| 
									
										
										
										
											2010-05-31 23:54:13 +08:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * TI OMAP processors GPIO emulation. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (C) 2006-2008 Andrzej Zaborowski  <balrog@zabor.org> | 
					
						
							|  |  |  |  * Copyright (C) 2007-2009 Nokia Corporation | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software; you can redistribute it and/or | 
					
						
							|  |  |  |  * modify it under the terms of the GNU General Public License as | 
					
						
							|  |  |  |  * published by the Free Software Foundation; either version 2 or | 
					
						
							|  |  |  |  * (at your option) version 3 of the License. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |  * GNU General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU General Public License along | 
					
						
							|  |  |  |  * with this program; if not, see <http://www.gnu.org/licenses/>.
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-26 18:17:28 +00:00
										 |  |  | #include "qemu/osdep.h"
 | 
					
						
							| 
									
										
										
										
											2022-02-07 09:27:56 +01:00
										 |  |  | #include "qemu/log.h"
 | 
					
						
							| 
									
										
										
										
											2019-08-12 07:23:42 +02:00
										 |  |  | #include "hw/irq.h"
 | 
					
						
							| 
									
										
										
										
											2019-08-12 07:23:51 +02:00
										 |  |  | #include "hw/qdev-properties.h"
 | 
					
						
							| 
									
										
										
										
											2013-02-05 17:06:20 +01:00
										 |  |  | #include "hw/arm/omap.h"
 | 
					
						
							| 
									
										
										
										
											2013-02-04 15:40:22 +01:00
										 |  |  | #include "hw/sysbus.h"
 | 
					
						
							| 
									
										
										
										
											2015-12-17 17:35:10 +01:00
										 |  |  | #include "qemu/error-report.h"
 | 
					
						
							| 
									
										
										
										
											2019-05-23 16:35:07 +02:00
										 |  |  | #include "qemu/module.h"
 | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:13 +01:00
										 |  |  | #include "qapi/error.h"
 | 
					
						
							| 
									
										
										
										
											2011-07-29 16:35:17 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:13 +08:00
										 |  |  | struct omap_gpio_s { | 
					
						
							|  |  |  |     qemu_irq irq; | 
					
						
							|  |  |  |     qemu_irq handler[16]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     uint16_t inputs; | 
					
						
							|  |  |  |     uint16_t outputs; | 
					
						
							|  |  |  |     uint16_t dir; | 
					
						
							|  |  |  |     uint16_t edge; | 
					
						
							|  |  |  |     uint16_t mask; | 
					
						
							|  |  |  |     uint16_t ints; | 
					
						
							|  |  |  |     uint16_t pins; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-09 15:02:56 +01:00
										 |  |  | struct Omap1GpioState { | 
					
						
							| 
									
										
										
										
											2013-07-26 17:14:40 +02:00
										 |  |  |     SysBusDevice parent_obj; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-24 14:32:34 +02:00
										 |  |  |     MemoryRegion iomem; | 
					
						
							| 
									
										
										
										
											2011-07-29 16:35:17 +01:00
										 |  |  |     int mpu_model; | 
					
						
							|  |  |  |     void *clk; | 
					
						
							|  |  |  |     struct omap_gpio_s omap1; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* General-Purpose I/O of OMAP1 */ | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:13 +08:00
										 |  |  | static void omap_gpio_set(void *opaque, int line, int level) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-01-09 15:02:56 +01:00
										 |  |  |     Omap1GpioState *p = opaque; | 
					
						
							| 
									
										
										
										
											2023-01-09 15:02:54 +01:00
										 |  |  |     struct omap_gpio_s *s = &p->omap1; | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:13 +08:00
										 |  |  |     uint16_t prev = s->inputs; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (level) | 
					
						
							|  |  |  |         s->inputs |= 1 << line; | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         s->inputs &= ~(1 << line); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (((s->edge & s->inputs & ~prev) | (~s->edge & ~s->inputs & prev)) & | 
					
						
							|  |  |  |                     (1 << line) & s->dir & ~s->mask) { | 
					
						
							|  |  |  |         s->ints |= 1 << line; | 
					
						
							|  |  |  |         qemu_irq_raise(s->irq); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  | static uint64_t omap_gpio_read(void *opaque, hwaddr addr, | 
					
						
							| 
									
										
										
										
											2011-11-24 14:32:34 +02:00
										 |  |  |                                unsigned size) | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:13 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-01-09 15:02:55 +01:00
										 |  |  |     struct omap_gpio_s *s = opaque; | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:13 +08:00
										 |  |  |     int offset = addr & OMAP_MPUI_REG_MASK; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-24 14:32:34 +02:00
										 |  |  |     if (size != 2) { | 
					
						
							|  |  |  |         return omap_badwidth_read16(opaque, addr); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:13 +08:00
										 |  |  |     switch (offset) { | 
					
						
							|  |  |  |     case 0x00:	/* DATA_INPUT */ | 
					
						
							|  |  |  |         return s->inputs & s->pins; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x04:	/* DATA_OUTPUT */ | 
					
						
							|  |  |  |         return s->outputs; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x08:	/* DIRECTION_CONTROL */ | 
					
						
							|  |  |  |         return s->dir; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x0c:	/* INTERRUPT_CONTROL */ | 
					
						
							|  |  |  |         return s->edge; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x10:	/* INTERRUPT_MASK */ | 
					
						
							|  |  |  |         return s->mask; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x14:	/* INTERRUPT_STATUS */ | 
					
						
							|  |  |  |         return s->ints; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x18:	/* PIN_CONTROL (not in OMAP310) */ | 
					
						
							|  |  |  |         OMAP_BAD_REG(addr); | 
					
						
							|  |  |  |         return s->pins; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     OMAP_BAD_REG(addr); | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  | static void omap_gpio_write(void *opaque, hwaddr addr, | 
					
						
							| 
									
										
										
										
											2011-11-24 14:32:34 +02:00
										 |  |  |                             uint64_t value, unsigned size) | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:13 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-01-09 15:02:55 +01:00
										 |  |  |     struct omap_gpio_s *s = opaque; | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:13 +08:00
										 |  |  |     int offset = addr & OMAP_MPUI_REG_MASK; | 
					
						
							|  |  |  |     uint16_t diff; | 
					
						
							|  |  |  |     int ln; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-24 14:32:34 +02:00
										 |  |  |     if (size != 2) { | 
					
						
							| 
									
										
										
										
											2015-03-08 19:21:13 +01:00
										 |  |  |         omap_badwidth_write16(opaque, addr, value); | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2011-11-24 14:32:34 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:13 +08:00
										 |  |  |     switch (offset) { | 
					
						
							|  |  |  |     case 0x00:	/* DATA_INPUT */ | 
					
						
							|  |  |  |         OMAP_RO_REG(addr); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x04:	/* DATA_OUTPUT */ | 
					
						
							|  |  |  |         diff = (s->outputs ^ value) & ~s->dir; | 
					
						
							|  |  |  |         s->outputs = value; | 
					
						
							| 
									
										
										
										
											2015-03-23 15:29:27 +00:00
										 |  |  |         while ((ln = ctz32(diff)) != 32) { | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:13 +08:00
										 |  |  |             if (s->handler[ln]) | 
					
						
							|  |  |  |                 qemu_set_irq(s->handler[ln], (value >> ln) & 1); | 
					
						
							|  |  |  |             diff &= ~(1 << ln); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x08:	/* DIRECTION_CONTROL */ | 
					
						
							|  |  |  |         diff = s->outputs & (s->dir ^ value); | 
					
						
							|  |  |  |         s->dir = value; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         value = s->outputs & ~s->dir; | 
					
						
							| 
									
										
										
										
											2015-03-23 15:29:27 +00:00
										 |  |  |         while ((ln = ctz32(diff)) != 32) { | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:13 +08:00
										 |  |  |             if (s->handler[ln]) | 
					
						
							|  |  |  |                 qemu_set_irq(s->handler[ln], (value >> ln) & 1); | 
					
						
							|  |  |  |             diff &= ~(1 << ln); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x0c:	/* INTERRUPT_CONTROL */ | 
					
						
							|  |  |  |         s->edge = value; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x10:	/* INTERRUPT_MASK */ | 
					
						
							|  |  |  |         s->mask = value; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x14:	/* INTERRUPT_STATUS */ | 
					
						
							|  |  |  |         s->ints &= ~value; | 
					
						
							|  |  |  |         if (!s->ints) | 
					
						
							|  |  |  |             qemu_irq_lower(s->irq); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x18:	/* PIN_CONTROL (not in OMAP310 TRM) */ | 
					
						
							|  |  |  |         OMAP_BAD_REG(addr); | 
					
						
							|  |  |  |         s->pins = value; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         OMAP_BAD_REG(addr); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* *Some* sources say the memory region is 32-bit.  */ | 
					
						
							| 
									
										
										
										
											2011-11-24 14:32:34 +02:00
										 |  |  | static const MemoryRegionOps omap_gpio_ops = { | 
					
						
							|  |  |  |     .read = omap_gpio_read, | 
					
						
							|  |  |  |     .write = omap_gpio_write, | 
					
						
							|  |  |  |     .endianness = DEVICE_NATIVE_ENDIAN, | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:13 +08:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-29 16:35:17 +01:00
										 |  |  | static void omap_gpio_reset(struct omap_gpio_s *s) | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:13 +08:00
										 |  |  | { | 
					
						
							|  |  |  |     s->inputs = 0; | 
					
						
							|  |  |  |     s->outputs = ~0; | 
					
						
							|  |  |  |     s->dir = ~0; | 
					
						
							|  |  |  |     s->edge = ~0; | 
					
						
							|  |  |  |     s->mask = ~0; | 
					
						
							|  |  |  |     s->ints = 0; | 
					
						
							|  |  |  |     s->pins = ~0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  | struct omap2_gpio_s { | 
					
						
							|  |  |  |     qemu_irq irq[2]; | 
					
						
							|  |  |  |     qemu_irq wkup; | 
					
						
							| 
									
										
										
										
											2011-07-29 16:35:17 +01:00
										 |  |  |     qemu_irq *handler; | 
					
						
							| 
									
										
										
										
											2011-11-24 14:32:34 +02:00
										 |  |  |     MemoryRegion iomem; | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-29 16:35:17 +01:00
										 |  |  |     uint8_t revision; | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  |     uint8_t config[2]; | 
					
						
							|  |  |  |     uint32_t inputs; | 
					
						
							|  |  |  |     uint32_t outputs; | 
					
						
							|  |  |  |     uint32_t dir; | 
					
						
							|  |  |  |     uint32_t level[2]; | 
					
						
							|  |  |  |     uint32_t edge[2]; | 
					
						
							|  |  |  |     uint32_t mask[2]; | 
					
						
							|  |  |  |     uint32_t wumask; | 
					
						
							|  |  |  |     uint32_t ints[2]; | 
					
						
							|  |  |  |     uint32_t debounce; | 
					
						
							|  |  |  |     uint8_t delay; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-09 15:02:57 +01:00
										 |  |  | struct Omap2GpioState { | 
					
						
							| 
									
										
										
										
											2013-07-26 17:19:36 +02:00
										 |  |  |     SysBusDevice parent_obj; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-24 14:32:34 +02:00
										 |  |  |     MemoryRegion iomem; | 
					
						
							| 
									
										
										
										
											2011-07-29 16:35:17 +01:00
										 |  |  |     int mpu_model; | 
					
						
							|  |  |  |     void *iclk; | 
					
						
							|  |  |  |     void *fclk[6]; | 
					
						
							|  |  |  |     int modulecount; | 
					
						
							|  |  |  |     struct omap2_gpio_s *modules; | 
					
						
							|  |  |  |     qemu_irq *handler; | 
					
						
							|  |  |  |     int autoidle; | 
					
						
							|  |  |  |     int gpo; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* General-Purpose Interface of OMAP2/3 */ | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  | static inline void omap2_gpio_module_int_update(struct omap2_gpio_s *s, | 
					
						
							| 
									
										
										
										
											2011-07-29 16:35:17 +01:00
										 |  |  |                                                 int line) | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  | { | 
					
						
							|  |  |  |     qemu_set_irq(s->irq[line], s->ints[line] & s->mask[line]); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void omap2_gpio_module_wake(struct omap2_gpio_s *s, int line) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (!(s->config[0] & (1 << 2)))			/* ENAWAKEUP */ | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     if (!(s->config[0] & (3 << 3)))			/* Force Idle */ | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     if (!(s->wumask & (1 << line))) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     qemu_irq_raise(s->wkup); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline void omap2_gpio_module_out_update(struct omap2_gpio_s *s, | 
					
						
							|  |  |  |                 uint32_t diff) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int ln; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     s->outputs ^= diff; | 
					
						
							|  |  |  |     diff &= ~s->dir; | 
					
						
							| 
									
										
										
										
											2015-03-23 15:29:27 +00:00
										 |  |  |     while ((ln = ctz32(diff)) != 32) { | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  |         qemu_set_irq(s->handler[ln], (s->outputs >> ln) & 1); | 
					
						
							|  |  |  |         diff &= ~(1 << ln); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void omap2_gpio_module_level_update(struct omap2_gpio_s *s, int line) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     s->ints[line] |= s->dir & | 
					
						
							|  |  |  |             ((s->inputs & s->level[1]) | (~s->inputs & s->level[0])); | 
					
						
							|  |  |  |     omap2_gpio_module_int_update(s, line); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline void omap2_gpio_module_int(struct omap2_gpio_s *s, int line) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     s->ints[0] |= 1 << line; | 
					
						
							|  |  |  |     omap2_gpio_module_int_update(s, 0); | 
					
						
							|  |  |  |     s->ints[1] |= 1 << line; | 
					
						
							|  |  |  |     omap2_gpio_module_int_update(s, 1); | 
					
						
							|  |  |  |     omap2_gpio_module_wake(s, line); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-29 16:35:17 +01:00
										 |  |  | static void omap2_gpio_set(void *opaque, int line, int level) | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-01-09 15:02:57 +01:00
										 |  |  |     Omap2GpioState *p = opaque; | 
					
						
							| 
									
										
										
										
											2011-07-29 16:35:17 +01:00
										 |  |  |     struct omap2_gpio_s *s = &p->modules[line >> 5]; | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-29 16:35:17 +01:00
										 |  |  |     line &= 31; | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  |     if (level) { | 
					
						
							|  |  |  |         if (s->dir & (1 << line) & ((~s->inputs & s->edge[0]) | s->level[1])) | 
					
						
							|  |  |  |             omap2_gpio_module_int(s, line); | 
					
						
							|  |  |  |         s->inputs |= 1 << line; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         if (s->dir & (1 << line) & ((s->inputs & s->edge[1]) | s->level[0])) | 
					
						
							|  |  |  |             omap2_gpio_module_int(s, line); | 
					
						
							|  |  |  |         s->inputs &= ~(1 << line); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void omap2_gpio_module_reset(struct omap2_gpio_s *s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     s->config[0] = 0; | 
					
						
							|  |  |  |     s->config[1] = 2; | 
					
						
							|  |  |  |     s->ints[0] = 0; | 
					
						
							|  |  |  |     s->ints[1] = 0; | 
					
						
							|  |  |  |     s->mask[0] = 0; | 
					
						
							|  |  |  |     s->mask[1] = 0; | 
					
						
							|  |  |  |     s->wumask = 0; | 
					
						
							|  |  |  |     s->dir = ~0; | 
					
						
							|  |  |  |     s->level[0] = 0; | 
					
						
							|  |  |  |     s->level[1] = 0; | 
					
						
							|  |  |  |     s->edge[0] = 0; | 
					
						
							|  |  |  |     s->edge[1] = 0; | 
					
						
							|  |  |  |     s->debounce = 0; | 
					
						
							|  |  |  |     s->delay = 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  | static uint32_t omap2_gpio_module_read(void *opaque, hwaddr addr) | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-01-09 15:02:55 +01:00
										 |  |  |     struct omap2_gpio_s *s = opaque; | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     switch (addr) { | 
					
						
							|  |  |  |     case 0x00:	/* GPIO_REVISION */ | 
					
						
							| 
									
										
										
										
											2011-07-29 16:35:17 +01:00
										 |  |  |         return s->revision; | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     case 0x10:	/* GPIO_SYSCONFIG */ | 
					
						
							|  |  |  |         return s->config[0]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x14:	/* GPIO_SYSSTATUS */ | 
					
						
							|  |  |  |         return 0x01; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x18:	/* GPIO_IRQSTATUS1 */ | 
					
						
							|  |  |  |         return s->ints[0]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x1c:	/* GPIO_IRQENABLE1 */ | 
					
						
							|  |  |  |     case 0x60:	/* GPIO_CLEARIRQENABLE1 */ | 
					
						
							|  |  |  |     case 0x64:	/* GPIO_SETIRQENABLE1 */ | 
					
						
							|  |  |  |         return s->mask[0]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x20:	/* GPIO_WAKEUPENABLE */ | 
					
						
							|  |  |  |     case 0x80:	/* GPIO_CLEARWKUENA */ | 
					
						
							|  |  |  |     case 0x84:	/* GPIO_SETWKUENA */ | 
					
						
							|  |  |  |         return s->wumask; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x28:	/* GPIO_IRQSTATUS2 */ | 
					
						
							|  |  |  |         return s->ints[1]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x2c:	/* GPIO_IRQENABLE2 */ | 
					
						
							|  |  |  |     case 0x70:	/* GPIO_CLEARIRQENABLE2 */ | 
					
						
							|  |  |  |     case 0x74:	/* GPIO_SETIREQNEABLE2 */ | 
					
						
							|  |  |  |         return s->mask[1]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x30:	/* GPIO_CTRL */ | 
					
						
							|  |  |  |         return s->config[1]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x34:	/* GPIO_OE */ | 
					
						
							|  |  |  |         return s->dir; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x38:	/* GPIO_DATAIN */ | 
					
						
							|  |  |  |         return s->inputs; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x3c:	/* GPIO_DATAOUT */ | 
					
						
							|  |  |  |     case 0x90:	/* GPIO_CLEARDATAOUT */ | 
					
						
							|  |  |  |     case 0x94:	/* GPIO_SETDATAOUT */ | 
					
						
							|  |  |  |         return s->outputs; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x40:	/* GPIO_LEVELDETECT0 */ | 
					
						
							|  |  |  |         return s->level[0]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x44:	/* GPIO_LEVELDETECT1 */ | 
					
						
							|  |  |  |         return s->level[1]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x48:	/* GPIO_RISINGDETECT */ | 
					
						
							|  |  |  |         return s->edge[0]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x4c:	/* GPIO_FALLINGDETECT */ | 
					
						
							|  |  |  |         return s->edge[1]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x50:	/* GPIO_DEBOUNCENABLE */ | 
					
						
							|  |  |  |         return s->debounce; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x54:	/* GPIO_DEBOUNCINGTIME */ | 
					
						
							|  |  |  |         return s->delay; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     OMAP_BAD_REG(addr); | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  | static void omap2_gpio_module_write(void *opaque, hwaddr addr, | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  |                 uint32_t value) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-01-09 15:02:55 +01:00
										 |  |  |     struct omap2_gpio_s *s = opaque; | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  |     uint32_t diff; | 
					
						
							|  |  |  |     int ln; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch (addr) { | 
					
						
							|  |  |  |     case 0x00:	/* GPIO_REVISION */ | 
					
						
							|  |  |  |     case 0x14:	/* GPIO_SYSSTATUS */ | 
					
						
							|  |  |  |     case 0x38:	/* GPIO_DATAIN */ | 
					
						
							|  |  |  |         OMAP_RO_REG(addr); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x10:	/* GPIO_SYSCONFIG */ | 
					
						
							| 
									
										
										
										
											2020-09-01 12:42:33 +02:00
										 |  |  |         if (((value >> 3) & 3) == 3) { | 
					
						
							|  |  |  |             qemu_log_mask(LOG_GUEST_ERROR, | 
					
						
							|  |  |  |                           "%s: Illegal IDLEMODE value: 3\n", __func__); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  |         if (value & 2) | 
					
						
							|  |  |  |             omap2_gpio_module_reset(s); | 
					
						
							|  |  |  |         s->config[0] = value & 0x1d; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x18:	/* GPIO_IRQSTATUS1 */ | 
					
						
							|  |  |  |         if (s->ints[0] & value) { | 
					
						
							|  |  |  |             s->ints[0] &= ~value; | 
					
						
							|  |  |  |             omap2_gpio_module_level_update(s, 0); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x1c:	/* GPIO_IRQENABLE1 */ | 
					
						
							|  |  |  |         s->mask[0] = value; | 
					
						
							|  |  |  |         omap2_gpio_module_int_update(s, 0); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x20:	/* GPIO_WAKEUPENABLE */ | 
					
						
							|  |  |  |         s->wumask = value; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x28:	/* GPIO_IRQSTATUS2 */ | 
					
						
							|  |  |  |         if (s->ints[1] & value) { | 
					
						
							|  |  |  |             s->ints[1] &= ~value; | 
					
						
							|  |  |  |             omap2_gpio_module_level_update(s, 1); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x2c:	/* GPIO_IRQENABLE2 */ | 
					
						
							|  |  |  |         s->mask[1] = value; | 
					
						
							|  |  |  |         omap2_gpio_module_int_update(s, 1); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x30:	/* GPIO_CTRL */ | 
					
						
							|  |  |  |         s->config[1] = value & 7; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x34:	/* GPIO_OE */ | 
					
						
							|  |  |  |         diff = s->outputs & (s->dir ^ value); | 
					
						
							|  |  |  |         s->dir = value; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         value = s->outputs & ~s->dir; | 
					
						
							| 
									
										
										
										
											2015-03-23 15:29:27 +00:00
										 |  |  |         while ((ln = ctz32(diff)) != 32) { | 
					
						
							|  |  |  |             diff &= ~(1 << ln); | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  |             qemu_set_irq(s->handler[ln], (value >> ln) & 1); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         omap2_gpio_module_level_update(s, 0); | 
					
						
							|  |  |  |         omap2_gpio_module_level_update(s, 1); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x3c:	/* GPIO_DATAOUT */ | 
					
						
							|  |  |  |         omap2_gpio_module_out_update(s, s->outputs ^ value); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x40:	/* GPIO_LEVELDETECT0 */ | 
					
						
							|  |  |  |         s->level[0] = value; | 
					
						
							|  |  |  |         omap2_gpio_module_level_update(s, 0); | 
					
						
							|  |  |  |         omap2_gpio_module_level_update(s, 1); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x44:	/* GPIO_LEVELDETECT1 */ | 
					
						
							|  |  |  |         s->level[1] = value; | 
					
						
							|  |  |  |         omap2_gpio_module_level_update(s, 0); | 
					
						
							|  |  |  |         omap2_gpio_module_level_update(s, 1); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x48:	/* GPIO_RISINGDETECT */ | 
					
						
							|  |  |  |         s->edge[0] = value; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x4c:	/* GPIO_FALLINGDETECT */ | 
					
						
							|  |  |  |         s->edge[1] = value; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x50:	/* GPIO_DEBOUNCENABLE */ | 
					
						
							|  |  |  |         s->debounce = value; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x54:	/* GPIO_DEBOUNCINGTIME */ | 
					
						
							|  |  |  |         s->delay = value; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x60:	/* GPIO_CLEARIRQENABLE1 */ | 
					
						
							|  |  |  |         s->mask[0] &= ~value; | 
					
						
							|  |  |  |         omap2_gpio_module_int_update(s, 0); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x64:	/* GPIO_SETIRQENABLE1 */ | 
					
						
							|  |  |  |         s->mask[0] |= value; | 
					
						
							|  |  |  |         omap2_gpio_module_int_update(s, 0); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x70:	/* GPIO_CLEARIRQENABLE2 */ | 
					
						
							|  |  |  |         s->mask[1] &= ~value; | 
					
						
							|  |  |  |         omap2_gpio_module_int_update(s, 1); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x74:	/* GPIO_SETIREQNEABLE2 */ | 
					
						
							|  |  |  |         s->mask[1] |= value; | 
					
						
							|  |  |  |         omap2_gpio_module_int_update(s, 1); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x80:	/* GPIO_CLEARWKUENA */ | 
					
						
							|  |  |  |         s->wumask &= ~value; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x84:	/* GPIO_SETWKUENA */ | 
					
						
							|  |  |  |         s->wumask |= value; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x90:	/* GPIO_CLEARDATAOUT */ | 
					
						
							|  |  |  |         omap2_gpio_module_out_update(s, s->outputs & value); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x94:	/* GPIO_SETDATAOUT */ | 
					
						
							|  |  |  |         omap2_gpio_module_out_update(s, ~s->outputs & value); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         OMAP_BAD_REG(addr); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-16 17:46:14 +01:00
										 |  |  | static uint64_t omap2_gpio_module_readp(void *opaque, hwaddr addr, | 
					
						
							|  |  |  |                                         unsigned size) | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-11-07 13:25:45 +00:00
										 |  |  |     return omap2_gpio_module_read(opaque, addr & ~3) >> ((addr & 3) << 3); | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  | static void omap2_gpio_module_writep(void *opaque, hwaddr addr, | 
					
						
							| 
									
										
										
										
											2017-09-16 17:46:14 +01:00
										 |  |  |                                      uint64_t value, unsigned size) | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  | { | 
					
						
							|  |  |  |     uint32_t cur = 0; | 
					
						
							|  |  |  |     uint32_t mask = 0xffff; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-16 17:46:14 +01:00
										 |  |  |     if (size == 4) { | 
					
						
							|  |  |  |         omap2_gpio_module_write(opaque, addr, value); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  |     switch (addr & ~3) { | 
					
						
							|  |  |  |     case 0x00:	/* GPIO_REVISION */ | 
					
						
							|  |  |  |     case 0x14:	/* GPIO_SYSSTATUS */ | 
					
						
							|  |  |  |     case 0x38:	/* GPIO_DATAIN */ | 
					
						
							|  |  |  |         OMAP_RO_REG(addr); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x10:	/* GPIO_SYSCONFIG */ | 
					
						
							|  |  |  |     case 0x1c:	/* GPIO_IRQENABLE1 */ | 
					
						
							|  |  |  |     case 0x20:	/* GPIO_WAKEUPENABLE */ | 
					
						
							|  |  |  |     case 0x2c:	/* GPIO_IRQENABLE2 */ | 
					
						
							|  |  |  |     case 0x30:	/* GPIO_CTRL */ | 
					
						
							|  |  |  |     case 0x34:	/* GPIO_OE */ | 
					
						
							|  |  |  |     case 0x3c:	/* GPIO_DATAOUT */ | 
					
						
							|  |  |  |     case 0x40:	/* GPIO_LEVELDETECT0 */ | 
					
						
							|  |  |  |     case 0x44:	/* GPIO_LEVELDETECT1 */ | 
					
						
							|  |  |  |     case 0x48:	/* GPIO_RISINGDETECT */ | 
					
						
							|  |  |  |     case 0x4c:	/* GPIO_FALLINGDETECT */ | 
					
						
							|  |  |  |     case 0x50:	/* GPIO_DEBOUNCENABLE */ | 
					
						
							|  |  |  |     case 0x54:	/* GPIO_DEBOUNCINGTIME */ | 
					
						
							|  |  |  |         cur = omap2_gpio_module_read(opaque, addr & ~3) & | 
					
						
							|  |  |  |                 ~(mask << ((addr & 3) << 3)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* Fall through.  */ | 
					
						
							|  |  |  |     case 0x18:	/* GPIO_IRQSTATUS1 */ | 
					
						
							|  |  |  |     case 0x28:	/* GPIO_IRQSTATUS2 */ | 
					
						
							|  |  |  |     case 0x60:	/* GPIO_CLEARIRQENABLE1 */ | 
					
						
							|  |  |  |     case 0x64:	/* GPIO_SETIRQENABLE1 */ | 
					
						
							|  |  |  |     case 0x70:	/* GPIO_CLEARIRQENABLE2 */ | 
					
						
							|  |  |  |     case 0x74:	/* GPIO_SETIREQNEABLE2 */ | 
					
						
							|  |  |  |     case 0x80:	/* GPIO_CLEARWKUENA */ | 
					
						
							|  |  |  |     case 0x84:	/* GPIO_SETWKUENA */ | 
					
						
							|  |  |  |     case 0x90:	/* GPIO_CLEARDATAOUT */ | 
					
						
							|  |  |  |     case 0x94:	/* GPIO_SETDATAOUT */ | 
					
						
							|  |  |  |         value <<= (addr & 3) << 3; | 
					
						
							|  |  |  |         omap2_gpio_module_write(opaque, addr, cur | value); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         OMAP_BAD_REG(addr); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-24 14:32:34 +02:00
										 |  |  | static const MemoryRegionOps omap2_gpio_module_ops = { | 
					
						
							| 
									
										
										
										
											2017-09-16 17:46:14 +01:00
										 |  |  |     .read = omap2_gpio_module_readp, | 
					
						
							|  |  |  |     .write = omap2_gpio_module_writep, | 
					
						
							|  |  |  |     .valid.min_access_size = 1, | 
					
						
							|  |  |  |     .valid.max_access_size = 4, | 
					
						
							| 
									
										
										
										
											2011-11-24 14:32:34 +02:00
										 |  |  |     .endianness = DEVICE_NATIVE_ENDIAN, | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-29 16:35:17 +01:00
										 |  |  | static void omap_gpif_reset(DeviceState *dev) | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-01-09 15:02:56 +01:00
										 |  |  |     Omap1GpioState *s = OMAP1_GPIO(dev); | 
					
						
							| 
									
										
										
										
											2013-07-26 17:14:40 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-29 16:35:17 +01:00
										 |  |  |     omap_gpio_reset(&s->omap1); | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-29 16:35:17 +01:00
										 |  |  | static void omap2_gpif_reset(DeviceState *dev) | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-01-09 15:02:57 +01:00
										 |  |  |     Omap2GpioState *s = OMAP2_GPIO(dev); | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  |     int i; | 
					
						
							| 
									
										
										
										
											2013-07-26 17:19:36 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-29 16:35:17 +01:00
										 |  |  |     for (i = 0; i < s->modulecount; i++) { | 
					
						
							|  |  |  |         omap2_gpio_module_reset(&s->modules[i]); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  |     s->autoidle = 0; | 
					
						
							|  |  |  |     s->gpo = 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-09 15:02:55 +01:00
										 |  |  | static uint64_t omap2_gpif_top_read(void *opaque, hwaddr addr, unsigned size) | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-01-09 15:02:57 +01:00
										 |  |  |     Omap2GpioState *s = opaque; | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     switch (addr) { | 
					
						
							|  |  |  |     case 0x00:	/* IPGENERICOCPSPL_REVISION */ | 
					
						
							|  |  |  |         return 0x18; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x10:	/* IPGENERICOCPSPL_SYSCONFIG */ | 
					
						
							|  |  |  |         return s->autoidle; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x14:	/* IPGENERICOCPSPL_SYSSTATUS */ | 
					
						
							|  |  |  |         return 0x01; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x18:	/* IPGENERICOCPSPL_IRQSTATUS */ | 
					
						
							|  |  |  |         return 0x00; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x40:	/* IPGENERICOCPSPL_GPO */ | 
					
						
							|  |  |  |         return s->gpo; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x50:	/* IPGENERICOCPSPL_GPI */ | 
					
						
							|  |  |  |         return 0x00; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     OMAP_BAD_REG(addr); | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  | static void omap2_gpif_top_write(void *opaque, hwaddr addr, | 
					
						
							| 
									
										
										
										
											2011-11-24 14:32:34 +02:00
										 |  |  |                                  uint64_t value, unsigned size) | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-01-09 15:02:57 +01:00
										 |  |  |     Omap2GpioState *s = opaque; | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     switch (addr) { | 
					
						
							|  |  |  |     case 0x00:	/* IPGENERICOCPSPL_REVISION */ | 
					
						
							|  |  |  |     case 0x14:	/* IPGENERICOCPSPL_SYSSTATUS */ | 
					
						
							|  |  |  |     case 0x18:	/* IPGENERICOCPSPL_IRQSTATUS */ | 
					
						
							|  |  |  |     case 0x50:	/* IPGENERICOCPSPL_GPI */ | 
					
						
							|  |  |  |         OMAP_RO_REG(addr); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x10:	/* IPGENERICOCPSPL_SYSCONFIG */ | 
					
						
							|  |  |  |         if (value & (1 << 1))					/* SOFTRESET */ | 
					
						
							| 
									
										
										
										
											2013-07-26 17:19:36 +02:00
										 |  |  |             omap2_gpif_reset(DEVICE(s)); | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  |         s->autoidle = value & 1; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 0x40:	/* IPGENERICOCPSPL_GPO */ | 
					
						
							|  |  |  |         s->gpo = value & 1; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         OMAP_BAD_REG(addr); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-24 14:32:34 +02:00
										 |  |  | static const MemoryRegionOps omap2_gpif_top_ops = { | 
					
						
							|  |  |  |     .read = omap2_gpif_top_read, | 
					
						
							|  |  |  |     .write = omap2_gpif_top_write, | 
					
						
							|  |  |  |     .endianness = DEVICE_NATIVE_ENDIAN, | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:13 +01:00
										 |  |  | static void omap_gpio_init(Object *obj) | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:13 +01:00
										 |  |  |     DeviceState *dev = DEVICE(obj); | 
					
						
							| 
									
										
										
										
											2023-01-09 15:02:56 +01:00
										 |  |  |     Omap1GpioState *s = OMAP1_GPIO(obj); | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:13 +01:00
										 |  |  |     SysBusDevice *sbd = SYS_BUS_DEVICE(obj); | 
					
						
							| 
									
										
										
										
											2013-07-26 17:14:40 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     qdev_init_gpio_in(dev, omap_gpio_set, 16); | 
					
						
							|  |  |  |     qdev_init_gpio_out(dev, s->omap1.handler, 16); | 
					
						
							|  |  |  |     sysbus_init_irq(sbd, &s->omap1.irq); | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:13 +01:00
										 |  |  |     memory_region_init_io(&s->iomem, obj, &omap_gpio_ops, &s->omap1, | 
					
						
							| 
									
										
										
										
											2011-11-24 14:32:34 +02:00
										 |  |  |                           "omap.gpio", 0x1000); | 
					
						
							| 
									
										
										
										
											2013-07-26 17:14:40 +02:00
										 |  |  |     sysbus_init_mmio(sbd, &s->iomem); | 
					
						
							| 
									
										
										
										
											2011-07-29 16:35:17 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:13 +01:00
										 |  |  | static void omap_gpio_realize(DeviceState *dev, Error **errp) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-01-09 15:02:56 +01:00
										 |  |  |     Omap1GpioState *s = OMAP1_GPIO(dev); | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:13 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (!s->clk) { | 
					
						
							|  |  |  |         error_setg(errp, "omap-gpio: clk not connected"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void omap2_gpio_realize(DeviceState *dev, Error **errp) | 
					
						
							| 
									
										
										
										
											2011-07-29 16:35:17 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-01-09 15:02:57 +01:00
										 |  |  |     Omap2GpioState *s = OMAP2_GPIO(dev); | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:13 +01:00
										 |  |  |     SysBusDevice *sbd = SYS_BUS_DEVICE(dev); | 
					
						
							| 
									
										
										
										
											2011-07-29 16:35:17 +01:00
										 |  |  |     int i; | 
					
						
							| 
									
										
										
										
											2013-07-26 17:19:36 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-29 16:35:17 +01:00
										 |  |  |     if (!s->iclk) { | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:13 +01:00
										 |  |  |         error_setg(errp, "omap2-gpio: iclk not connected"); | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2011-07-29 16:35:17 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-12-17 17:35:10 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     s->modulecount = s->mpu_model < omap2430 ? 4 | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:13 +01:00
										 |  |  |         : s->mpu_model < omap3430 ? 5 | 
					
						
							|  |  |  |         : 6; | 
					
						
							| 
									
										
										
										
											2015-12-17 17:35:10 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-29 16:35:17 +01:00
										 |  |  |     if (s->mpu_model < omap3430) { | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:13 +01:00
										 |  |  |         memory_region_init_io(&s->iomem, OBJECT(dev), &omap2_gpif_top_ops, s, | 
					
						
							| 
									
										
										
										
											2011-11-24 14:32:34 +02:00
										 |  |  |                               "omap2.gpio", 0x1000); | 
					
						
							| 
									
										
										
										
											2013-07-26 17:19:36 +02:00
										 |  |  |         sysbus_init_mmio(sbd, &s->iomem); | 
					
						
							| 
									
										
										
										
											2011-07-29 16:35:17 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-12-17 17:35:10 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
											  
											
												arm: Use g_new() & friends where that makes obvious sense
g_new(T, n) is neater than g_malloc(sizeof(T) * n).  It's also safer,
for two reasons.  One, it catches multiplication overflowing size_t.
Two, it returns T * rather than void *, which lets the compiler catch
more type errors.
This commit only touches allocations with size arguments of the form
sizeof(T).
Coccinelle semantic patch:
    @@
    type T;
    @@
    -g_malloc(sizeof(T))
    +g_new(T, 1)
    @@
    type T;
    @@
    -g_try_malloc(sizeof(T))
    +g_try_new(T, 1)
    @@
    type T;
    @@
    -g_malloc0(sizeof(T))
    +g_new0(T, 1)
    @@
    type T;
    @@
    -g_try_malloc0(sizeof(T))
    +g_try_new0(T, 1)
    @@
    type T;
    expression n;
    @@
    -g_malloc(sizeof(T) * (n))
    +g_new(T, n)
    @@
    type T;
    expression n;
    @@
    -g_try_malloc(sizeof(T) * (n))
    +g_try_new(T, n)
    @@
    type T;
    expression n;
    @@
    -g_malloc0(sizeof(T) * (n))
    +g_new0(T, n)
    @@
    type T;
    expression n;
    @@
    -g_try_malloc0(sizeof(T) * (n))
    +g_try_new0(T, n)
    @@
    type T;
    expression p, n;
    @@
    -g_realloc(p, sizeof(T) * (n))
    +g_renew(T, p, n)
    @@
    type T;
    expression p, n;
    @@
    -g_try_realloc(p, sizeof(T) * (n))
    +g_try_renew(T, p, n)
    @@
    type T;
    expression n;
    @@
    -(T *)g_new(T, n)
    +g_new(T, n)
    @@
    type T;
    expression n;
    @@
    -(T *)g_new0(T, n)
    +g_new0(T, n)
    @@
    type T;
    expression p, n;
    @@
    -(T *)g_renew(T, p, n)
    +g_renew(T, p, n)
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-id: 1440524394-15640-1-git-send-email-armbru@redhat.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
											
										 
											2015-09-07 10:39:27 +01:00
										 |  |  |     s->modules = g_new0(struct omap2_gpio_s, s->modulecount); | 
					
						
							|  |  |  |     s->handler = g_new0(qemu_irq, s->modulecount * 32); | 
					
						
							| 
									
										
										
										
											2013-07-26 17:19:36 +02:00
										 |  |  |     qdev_init_gpio_in(dev, omap2_gpio_set, s->modulecount * 32); | 
					
						
							|  |  |  |     qdev_init_gpio_out(dev, s->handler, s->modulecount * 32); | 
					
						
							| 
									
										
										
										
											2015-12-17 17:35:10 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-29 16:35:17 +01:00
										 |  |  |     for (i = 0; i < s->modulecount; i++) { | 
					
						
							|  |  |  |         struct omap2_gpio_s *m = &s->modules[i]; | 
					
						
							| 
									
										
										
										
											2015-12-17 17:35:10 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:13 +01:00
										 |  |  |         if (!s->fclk[i]) { | 
					
						
							|  |  |  |             error_setg(errp, "omap2-gpio: fclk%d not connected", i); | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-29 16:35:17 +01:00
										 |  |  |         m->revision = (s->mpu_model < omap3430) ? 0x18 : 0x25; | 
					
						
							|  |  |  |         m->handler = &s->handler[i * 32]; | 
					
						
							| 
									
										
										
										
											2013-07-26 17:19:36 +02:00
										 |  |  |         sysbus_init_irq(sbd, &m->irq[0]); /* mpu irq */ | 
					
						
							|  |  |  |         sysbus_init_irq(sbd, &m->irq[1]); /* dsp irq */ | 
					
						
							|  |  |  |         sysbus_init_irq(sbd, &m->wkup); | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:13 +01:00
										 |  |  |         memory_region_init_io(&m->iomem, OBJECT(dev), &omap2_gpio_module_ops, m, | 
					
						
							| 
									
										
										
										
											2011-11-24 14:32:34 +02:00
										 |  |  |                               "omap.gpio-module", 0x1000); | 
					
						
							| 
									
										
										
										
											2013-07-26 17:19:36 +02:00
										 |  |  |         sysbus_init_mmio(sbd, &m->iomem); | 
					
						
							| 
									
										
										
										
											2011-07-29 16:35:17 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-09 15:02:56 +01:00
										 |  |  | void omap_gpio_set_clk(Omap1GpioState *gpio, omap_clk clk) | 
					
						
							| 
									
										
										
										
											2019-10-18 15:26:19 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     gpio->clk = clk; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-24 13:12:29 -06:00
										 |  |  | static Property omap_gpio_properties[] = { | 
					
						
							| 
									
										
										
										
											2023-01-09 15:02:56 +01:00
										 |  |  |     DEFINE_PROP_INT32("mpu_model", Omap1GpioState, mpu_model, 0), | 
					
						
							| 
									
										
										
										
											2012-01-24 13:12:29 -06:00
										 |  |  |     DEFINE_PROP_END_OF_LIST(), | 
					
						
							| 
									
										
										
										
											2011-07-29 16:35:17 +01:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-24 13:12:29 -06:00
										 |  |  | static void omap_gpio_class_init(ObjectClass *klass, void *data) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-12-07 21:34:16 -06:00
										 |  |  |     DeviceClass *dc = DEVICE_CLASS(klass); | 
					
						
							| 
									
										
										
										
											2012-01-24 13:12:29 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:13 +01:00
										 |  |  |     dc->realize = omap_gpio_realize; | 
					
						
							| 
									
										
										
										
											2011-12-07 21:34:16 -06:00
										 |  |  |     dc->reset = omap_gpif_reset; | 
					
						
							| 
									
										
										
										
											2020-01-10 19:30:32 +04:00
										 |  |  |     device_class_set_props(dc, omap_gpio_properties); | 
					
						
							| 
									
										
										
										
											2013-11-29 10:43:44 +01:00
										 |  |  |     /* Reason: pointer property "clk" */ | 
					
						
							| 
									
										
										
										
											2017-05-03 17:35:44 -03:00
										 |  |  |     dc->user_creatable = false; | 
					
						
							| 
									
										
										
										
											2012-01-24 13:12:29 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-10 16:19:07 +01:00
										 |  |  | static const TypeInfo omap_gpio_info = { | 
					
						
							| 
									
										
										
										
											2013-07-26 17:14:40 +02:00
										 |  |  |     .name          = TYPE_OMAP1_GPIO, | 
					
						
							| 
									
										
										
										
											2011-12-07 21:34:16 -06:00
										 |  |  |     .parent        = TYPE_SYS_BUS_DEVICE, | 
					
						
							| 
									
										
										
										
											2023-01-09 15:02:56 +01:00
										 |  |  |     .instance_size = sizeof(Omap1GpioState), | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:13 +01:00
										 |  |  |     .instance_init = omap_gpio_init, | 
					
						
							| 
									
										
										
										
											2011-12-07 21:34:16 -06:00
										 |  |  |     .class_init    = omap_gpio_class_init, | 
					
						
							| 
									
										
										
										
											2012-01-24 13:12:29 -06:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-09 15:02:57 +01:00
										 |  |  | void omap2_gpio_set_iclk(Omap2GpioState *gpio, omap_clk clk) | 
					
						
							| 
									
										
										
										
											2019-10-18 15:26:19 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     gpio->iclk = clk; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-09 15:02:57 +01:00
										 |  |  | void omap2_gpio_set_fclk(Omap2GpioState *gpio, uint8_t i, omap_clk clk) | 
					
						
							| 
									
										
										
										
											2019-10-18 15:26:19 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     assert(i <= 5); | 
					
						
							|  |  |  |     gpio->fclk[i] = clk; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-24 13:12:29 -06:00
										 |  |  | static Property omap2_gpio_properties[] = { | 
					
						
							| 
									
										
										
										
											2023-01-09 15:02:57 +01:00
										 |  |  |     DEFINE_PROP_INT32("mpu_model", Omap2GpioState, mpu_model, 0), | 
					
						
							| 
									
										
										
										
											2012-01-24 13:12:29 -06:00
										 |  |  |     DEFINE_PROP_END_OF_LIST(), | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void omap2_gpio_class_init(ObjectClass *klass, void *data) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-12-07 21:34:16 -06:00
										 |  |  |     DeviceClass *dc = DEVICE_CLASS(klass); | 
					
						
							| 
									
										
										
										
											2012-01-24 13:12:29 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-14 15:59:13 +01:00
										 |  |  |     dc->realize = omap2_gpio_realize; | 
					
						
							| 
									
										
										
										
											2011-12-07 21:34:16 -06:00
										 |  |  |     dc->reset = omap2_gpif_reset; | 
					
						
							| 
									
										
										
										
											2020-01-10 19:30:32 +04:00
										 |  |  |     device_class_set_props(dc, omap2_gpio_properties); | 
					
						
							| 
									
										
										
										
											2013-11-29 10:43:44 +01:00
										 |  |  |     /* Reason: pointer properties "iclk", "fclk0", ..., "fclk5" */ | 
					
						
							| 
									
										
										
										
											2017-05-03 17:35:44 -03:00
										 |  |  |     dc->user_creatable = false; | 
					
						
							| 
									
										
										
										
											2012-01-24 13:12:29 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-10 16:19:07 +01:00
										 |  |  | static const TypeInfo omap2_gpio_info = { | 
					
						
							| 
									
										
										
										
											2013-07-26 17:19:36 +02:00
										 |  |  |     .name          = TYPE_OMAP2_GPIO, | 
					
						
							| 
									
										
										
										
											2011-12-07 21:34:16 -06:00
										 |  |  |     .parent        = TYPE_SYS_BUS_DEVICE, | 
					
						
							| 
									
										
										
										
											2023-01-09 15:02:57 +01:00
										 |  |  |     .instance_size = sizeof(Omap2GpioState), | 
					
						
							| 
									
										
										
										
											2011-12-07 21:34:16 -06:00
										 |  |  |     .class_init    = omap2_gpio_class_init, | 
					
						
							| 
									
										
										
										
											2011-07-29 16:35:17 +01:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-02-09 15:20:55 +01:00
										 |  |  | static void omap_gpio_register_types(void) | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-12-07 21:34:16 -06:00
										 |  |  |     type_register_static(&omap_gpio_info); | 
					
						
							|  |  |  |     type_register_static(&omap2_gpio_info); | 
					
						
							| 
									
										
										
										
											2010-05-31 23:54:14 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-02-09 15:20:55 +01:00
										 |  |  | type_init(omap_gpio_register_types) |