diff options
Diffstat (limited to 'hw/pxa2xx_gpio.c')
-rw-r--r-- | hw/pxa2xx_gpio.c | 56 |
1 files changed, 34 insertions, 22 deletions
diff --git a/hw/pxa2xx_gpio.c b/hw/pxa2xx_gpio.c index 85aeb50cc..e3a30bc45 100644 --- a/hw/pxa2xx_gpio.c +++ b/hw/pxa2xx_gpio.c @@ -7,7 +7,8 @@ * This code is licensed under the GPL. */ -#include "vl.h" +#include "hw.h" +#include "pxa.h" #define PXA2XX_GPIO_BANKS 4 @@ -16,6 +17,7 @@ struct pxa2xx_gpio_info_s { qemu_irq *pic; int lines; CPUState *cpu_env; + qemu_irq *in; /* XXX: GNU C vectors are more suitable */ uint32_t ilevel[PXA2XX_GPIO_BANKS]; @@ -24,16 +26,12 @@ struct pxa2xx_gpio_info_s { uint32_t rising[PXA2XX_GPIO_BANKS]; uint32_t falling[PXA2XX_GPIO_BANKS]; uint32_t status[PXA2XX_GPIO_BANKS]; + uint32_t gpsr[PXA2XX_GPIO_BANKS]; uint32_t gafr[PXA2XX_GPIO_BANKS * 2]; uint32_t prev_level[PXA2XX_GPIO_BANKS]; - struct { - gpio_handler_t fn; - void *opaque; - } handler[PXA2XX_GPIO_BANKS * 32]; - - void (*read_notify)(void *opaque); - void *opaque; + qemu_irq handler[PXA2XX_GPIO_BANKS * 32]; + qemu_irq read_notify; }; static struct { @@ -85,12 +83,13 @@ static void pxa2xx_gpio_irq_update(struct pxa2xx_gpio_info_s *s) } /* Bitmap of pins used as standby and sleep wake-up sources. */ -const int pxa2xx_gpio_wake[PXA2XX_GPIO_BANKS] = { +static const int pxa2xx_gpio_wake[PXA2XX_GPIO_BANKS] = { 0x8003fe1b, 0x002001fc, 0xec080000, 0x0012007f, }; -void pxa2xx_gpio_set(struct pxa2xx_gpio_info_s *s, int line, int level) +static void pxa2xx_gpio_set(void *opaque, int line, int level) { + struct pxa2xx_gpio_info_s *s = (struct pxa2xx_gpio_info_s *) opaque; int bank; uint32_t mask; @@ -129,9 +128,7 @@ static void pxa2xx_gpio_handler_update(struct pxa2xx_gpio_info_s *s) { for (diff = s->prev_level[i] ^ level; diff; diff ^= 1 << bit) { bit = ffs(diff) - 1; line = bit + 32 * i; - if (s->handler[line].fn) - s->handler[line].fn(line, (level >> bit) & 1, - s->handler[line].opaque); + qemu_set_irq(s->handler[line], (level >> bit) & 1); } s->prev_level[i] = level; @@ -152,6 +149,16 @@ static uint32_t pxa2xx_gpio_read(void *opaque, target_phys_addr_t offset) case GPDR: /* GPIO Pin-Direction registers */ return s->dir[bank]; + case GPSR: /* GPIO Pin-Output Set registers */ + printf("%s: Read from a write-only register " REG_FMT "\n", + __FUNCTION__, offset); + return s->gpsr[bank]; /* Return last written value. */ + + case GPCR: /* GPIO Pin-Output Clear registers */ + printf("%s: Read from a write-only register " REG_FMT "\n", + __FUNCTION__, offset); + return 31337; /* Specified as unpredictable in the docs. */ + case GRER: /* GPIO Rising-Edge Detect Enable registers */ return s->rising[bank]; @@ -167,8 +174,7 @@ static uint32_t pxa2xx_gpio_read(void *opaque, target_phys_addr_t offset) case GPLR: /* GPIO Pin-Level registers */ ret = (s->olevel[bank] & s->dir[bank]) | (s->ilevel[bank] & ~s->dir[bank]); - if (s->read_notify) - s->read_notify(s->opaque); + qemu_irq_raise(s->read_notify); return ret; case GEDR: /* GPIO Edge Detect Status registers */ @@ -201,6 +207,7 @@ static void pxa2xx_gpio_write(void *opaque, case GPSR: /* GPIO Pin-Output Set registers */ s->olevel[bank] |= value; pxa2xx_gpio_handler_update(s); + s->gpsr[bank] = value; break; case GPCR: /* GPIO Pin-Output Clear registers */ @@ -305,6 +312,7 @@ struct pxa2xx_gpio_info_s *pxa2xx_gpio_init(target_phys_addr_t base, s->pic = pic; s->lines = lines; s->cpu_env = env; + s->in = qemu_allocate_irqs(pxa2xx_gpio_set, s, lines); iomemtype = cpu_register_io_memory(0, pxa2xx_gpio_readfn, pxa2xx_gpio_writefn, s); @@ -316,23 +324,27 @@ struct pxa2xx_gpio_info_s *pxa2xx_gpio_init(target_phys_addr_t base, return s; } -void pxa2xx_gpio_handler_set(struct pxa2xx_gpio_info_s *s, int line, - gpio_handler_t handler, void *opaque) { +qemu_irq *pxa2xx_gpio_in_get(struct pxa2xx_gpio_info_s *s) +{ + return s->in; +} + +void pxa2xx_gpio_out_set(struct pxa2xx_gpio_info_s *s, + int line, qemu_irq handler) +{ if (line >= s->lines) { printf("%s: No GPIO pin %i\n", __FUNCTION__, line); return; } - s->handler[line].fn = handler; - s->handler[line].opaque = opaque; + s->handler[line] = handler; } /* * Registers a callback to notify on GPLR reads. This normally * shouldn't be needed but it is used for the hack on Spitz machines. */ -void pxa2xx_gpio_read_notifier(struct pxa2xx_gpio_info_s *s, - void (*handler)(void *opaque), void *opaque) { +void pxa2xx_gpio_read_notifier(struct pxa2xx_gpio_info_s *s, qemu_irq handler) +{ s->read_notify = handler; - s->opaque = opaque; } |