Commit 6433014805f6f23050c4c4d0483b0241b3eaccb4
1 parent
623a930e
Add OMAP Shared GPIO module.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3473 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
3 changed files
with
186 additions
and
1 deletions
hw/omap.c
@@ -3065,6 +3065,179 @@ void omap_mpuio_key(struct omap_mpuio_s *s, int row, int col, int down) | @@ -3065,6 +3065,179 @@ void omap_mpuio_key(struct omap_mpuio_s *s, int row, int col, int down) | ||
3065 | omap_mpuio_kbd_update(s); | 3065 | omap_mpuio_kbd_update(s); |
3066 | } | 3066 | } |
3067 | 3067 | ||
3068 | +/* General-Purpose I/O */ | ||
3069 | +struct omap_gpio_s { | ||
3070 | + target_phys_addr_t base; | ||
3071 | + qemu_irq irq; | ||
3072 | + qemu_irq *in; | ||
3073 | + qemu_irq handler[16]; | ||
3074 | + | ||
3075 | + uint16_t inputs; | ||
3076 | + uint16_t outputs; | ||
3077 | + uint16_t dir; | ||
3078 | + uint16_t edge; | ||
3079 | + uint16_t mask; | ||
3080 | + uint16_t ints; | ||
3081 | +}; | ||
3082 | + | ||
3083 | +static void omap_gpio_set(void *opaque, int line, int level) | ||
3084 | +{ | ||
3085 | + struct omap_gpio_s *s = (struct omap_gpio_s *) opaque; | ||
3086 | + uint16_t prev = s->inputs; | ||
3087 | + | ||
3088 | + if (level) | ||
3089 | + s->inputs |= 1 << line; | ||
3090 | + else | ||
3091 | + s->inputs &= ~(1 << line); | ||
3092 | + | ||
3093 | + if (((s->edge & s->inputs & ~prev) | (~s->edge & ~s->inputs & prev)) & | ||
3094 | + (1 << line) & s->dir & ~s->mask) { | ||
3095 | + s->ints |= 1 << line; | ||
3096 | + qemu_irq_raise(s->irq); | ||
3097 | + } | ||
3098 | +} | ||
3099 | + | ||
3100 | +static uint32_t omap_gpio_read(void *opaque, target_phys_addr_t addr) | ||
3101 | +{ | ||
3102 | + struct omap_gpio_s *s = (struct omap_gpio_s *) opaque; | ||
3103 | + int offset = addr - s->base; | ||
3104 | + uint16_t ret; | ||
3105 | + | ||
3106 | + switch (offset) { | ||
3107 | + case 0x00: /* DATA_INPUT */ | ||
3108 | + return s->inputs; | ||
3109 | + | ||
3110 | + case 0x04: /* DATA_OUTPUT */ | ||
3111 | + return s->outputs; | ||
3112 | + | ||
3113 | + case 0x08: /* DIRECTION_CONTROL */ | ||
3114 | + return s->dir; | ||
3115 | + | ||
3116 | + case 0x0c: /* INTERRUPT_CONTROL */ | ||
3117 | + return s->edge; | ||
3118 | + | ||
3119 | + case 0x10: /* INTERRUPT_MASK */ | ||
3120 | + return s->mask; | ||
3121 | + | ||
3122 | + case 0x14: /* INTERRUPT_STATUS */ | ||
3123 | + return s->ints; | ||
3124 | + } | ||
3125 | + | ||
3126 | + OMAP_BAD_REG(addr); | ||
3127 | + return 0; | ||
3128 | +} | ||
3129 | + | ||
3130 | +static void omap_gpio_write(void *opaque, target_phys_addr_t addr, | ||
3131 | + uint32_t value) | ||
3132 | +{ | ||
3133 | + struct omap_gpio_s *s = (struct omap_gpio_s *) opaque; | ||
3134 | + int offset = addr - s->base; | ||
3135 | + uint16_t diff; | ||
3136 | + int ln; | ||
3137 | + | ||
3138 | + switch (offset) { | ||
3139 | + case 0x00: /* DATA_INPUT */ | ||
3140 | + OMAP_RO_REG(addr); | ||
3141 | + return; | ||
3142 | + | ||
3143 | + case 0x04: /* DATA_OUTPUT */ | ||
3144 | + diff = s->outputs ^ (value & ~s->dir); | ||
3145 | + s->outputs = value; | ||
3146 | + value &= ~s->dir; | ||
3147 | + while ((ln = ffs(diff))) { | ||
3148 | + ln --; | ||
3149 | + if (s->handler[ln]) | ||
3150 | + qemu_set_irq(s->handler[ln], (value >> ln) & 1); | ||
3151 | + diff &= ~(1 << ln); | ||
3152 | + } | ||
3153 | + break; | ||
3154 | + | ||
3155 | + case 0x08: /* DIRECTION_CONTROL */ | ||
3156 | + diff = s->outputs & (s->dir ^ value); | ||
3157 | + s->dir = value; | ||
3158 | + | ||
3159 | + value = s->outputs & ~s->dir; | ||
3160 | + while ((ln = ffs(diff))) { | ||
3161 | + ln --; | ||
3162 | + if (s->handler[ln]) | ||
3163 | + qemu_set_irq(s->handler[ln], (value >> ln) & 1); | ||
3164 | + diff &= ~(1 << ln); | ||
3165 | + } | ||
3166 | + break; | ||
3167 | + | ||
3168 | + case 0x0c: /* INTERRUPT_CONTROL */ | ||
3169 | + s->edge = value; | ||
3170 | + break; | ||
3171 | + | ||
3172 | + case 0x10: /* INTERRUPT_MASK */ | ||
3173 | + s->mask = value; | ||
3174 | + break; | ||
3175 | + | ||
3176 | + case 0x14: /* INTERRUPT_STATUS */ | ||
3177 | + s->ints &= ~value; | ||
3178 | + if (!s->ints) | ||
3179 | + qemu_irq_lower(s->irq); | ||
3180 | + break; | ||
3181 | + | ||
3182 | + default: | ||
3183 | + OMAP_BAD_REG(addr); | ||
3184 | + return; | ||
3185 | + } | ||
3186 | +} | ||
3187 | + | ||
3188 | +static CPUReadMemoryFunc *omap_gpio_readfn[] = { | ||
3189 | + omap_gpio_read, | ||
3190 | + omap_badwidth_read32, | ||
3191 | + omap_badwidth_read32, | ||
3192 | +}; | ||
3193 | + | ||
3194 | +static CPUWriteMemoryFunc *omap_gpio_writefn[] = { | ||
3195 | + omap_gpio_write, | ||
3196 | + omap_badwidth_write32, | ||
3197 | + omap_badwidth_write32, | ||
3198 | +}; | ||
3199 | + | ||
3200 | +void omap_gpio_reset(struct omap_gpio_s *s) | ||
3201 | +{ | ||
3202 | + s->inputs = 0; | ||
3203 | + s->outputs = ~0; | ||
3204 | + s->dir = ~0; | ||
3205 | + s->edge = ~0; | ||
3206 | + s->mask = ~0; | ||
3207 | + s->ints = 0; | ||
3208 | +} | ||
3209 | + | ||
3210 | +struct omap_gpio_s *omap_gpio_init(target_phys_addr_t base, | ||
3211 | + qemu_irq irq, omap_clk clk) | ||
3212 | +{ | ||
3213 | + int iomemtype; | ||
3214 | + struct omap_gpio_s *s = (struct omap_gpio_s *) | ||
3215 | + qemu_mallocz(sizeof(struct omap_gpio_s)); | ||
3216 | + | ||
3217 | + s->base = base; | ||
3218 | + s->irq = irq; | ||
3219 | + s->in = qemu_allocate_irqs(omap_gpio_set, s, 16); | ||
3220 | + omap_gpio_reset(s); | ||
3221 | + | ||
3222 | + iomemtype = cpu_register_io_memory(0, omap_gpio_readfn, | ||
3223 | + omap_gpio_writefn, s); | ||
3224 | + cpu_register_physical_memory(s->base, 0x1000, iomemtype); | ||
3225 | + | ||
3226 | + return s; | ||
3227 | +} | ||
3228 | + | ||
3229 | +qemu_irq *omap_gpio_in_get(struct omap_gpio_s *s) | ||
3230 | +{ | ||
3231 | + return s->in; | ||
3232 | +} | ||
3233 | + | ||
3234 | +void omap_gpio_out_set(struct omap_gpio_s *s, int line, qemu_irq handler) | ||
3235 | +{ | ||
3236 | + if (line >= 16 || line < 0) | ||
3237 | + cpu_abort(cpu_single_env, "%s: No GPIO line %i\n", __FUNCTION__, line); | ||
3238 | + s->handler[line] = handler; | ||
3239 | +} | ||
3240 | + | ||
3068 | /* General chip reset */ | 3241 | /* General chip reset */ |
3069 | static void omap_mpu_reset(void *opaque) | 3242 | static void omap_mpu_reset(void *opaque) |
3070 | { | 3243 | { |
@@ -3093,6 +3266,7 @@ static void omap_mpu_reset(void *opaque) | @@ -3093,6 +3266,7 @@ static void omap_mpu_reset(void *opaque) | ||
3093 | omap_uart_reset(mpu->uart3); | 3266 | omap_uart_reset(mpu->uart3); |
3094 | omap_mmc_reset(mpu->mmc); | 3267 | omap_mmc_reset(mpu->mmc); |
3095 | omap_mpuio_reset(mpu->mpuio); | 3268 | omap_mpuio_reset(mpu->mpuio); |
3269 | + omap_gpio_reset(mpu->gpio); | ||
3096 | cpu_reset(mpu->env); | 3270 | cpu_reset(mpu->env); |
3097 | } | 3271 | } |
3098 | 3272 | ||
@@ -3208,6 +3382,9 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, | @@ -3208,6 +3382,9 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, | ||
3208 | s->irq[1][OMAP_INT_KEYBOARD], s->irq[1][OMAP_INT_MPUIO], | 3382 | s->irq[1][OMAP_INT_KEYBOARD], s->irq[1][OMAP_INT_MPUIO], |
3209 | s->wakeup, omap_findclk(s, "clk32-kHz")); | 3383 | s->wakeup, omap_findclk(s, "clk32-kHz")); |
3210 | 3384 | ||
3385 | + s->gpio = omap_gpio_init(0xfffcf000, s->irq[1][OMAP_INT_KEYBOARD], | ||
3386 | + omap_findclk(s, "mpuper_ck")); | ||
3387 | + | ||
3211 | qemu_register_reset(omap_mpu_reset, s); | 3388 | qemu_register_reset(omap_mpu_reset, s); |
3212 | 3389 | ||
3213 | return s; | 3390 | return s; |
hw/omap.h
@@ -458,6 +458,12 @@ qemu_irq *omap_mpuio_in_get(struct omap_mpuio_s *s); | @@ -458,6 +458,12 @@ qemu_irq *omap_mpuio_in_get(struct omap_mpuio_s *s); | ||
458 | void omap_mpuio_out_set(struct omap_mpuio_s *s, int line, qemu_irq handler); | 458 | void omap_mpuio_out_set(struct omap_mpuio_s *s, int line, qemu_irq handler); |
459 | void omap_mpuio_key(struct omap_mpuio_s *s, int row, int col, int down); | 459 | void omap_mpuio_key(struct omap_mpuio_s *s, int row, int col, int down); |
460 | 460 | ||
461 | +struct omap_gpio_s; | ||
462 | +struct omap_gpio_s *omap_gpio_init(target_phys_addr_t base, | ||
463 | + qemu_irq irq, omap_clk clk); | ||
464 | +qemu_irq *omap_gpio_in_get(struct omap_gpio_s *s); | ||
465 | +void omap_gpio_out_set(struct omap_gpio_s *s, int line, qemu_irq handler); | ||
466 | + | ||
461 | /* omap_lcdc.c */ | 467 | /* omap_lcdc.c */ |
462 | struct omap_lcd_panel_s; | 468 | struct omap_lcd_panel_s; |
463 | void omap_lcdc_reset(struct omap_lcd_panel_s *s); | 469 | void omap_lcdc_reset(struct omap_lcd_panel_s *s); |
@@ -574,6 +580,7 @@ struct omap_mpu_state_s { | @@ -574,6 +580,7 @@ struct omap_mpu_state_s { | ||
574 | } clkm; | 580 | } clkm; |
575 | 581 | ||
576 | struct omap_mpuio_s *mpuio; | 582 | struct omap_mpuio_s *mpuio; |
583 | + struct omap_gpio_s *gpio; | ||
577 | } *omap310_mpu_init(unsigned long sdram_size, | 584 | } *omap310_mpu_init(unsigned long sdram_size, |
578 | DisplayState *ds, const char *core); | 585 | DisplayState *ds, const char *core); |
579 | 586 |
hw/palm.c
@@ -158,7 +158,8 @@ static void palmte_init(int ram_size, int vga_ram_size, int boot_device, | @@ -158,7 +158,8 @@ static void palmte_init(int ram_size, int vga_ram_size, int boot_device, | ||
158 | 158 | ||
159 | qemu_add_kbd_event_handler(palmte_button_event, cpu); | 159 | qemu_add_kbd_event_handler(palmte_button_event, cpu); |
160 | 160 | ||
161 | - omap_mmc_handlers(cpu->mmc, 0, | 161 | + omap_mmc_handlers(cpu->mmc, |
162 | + omap_gpio_in_get(cpu->gpio)[PALMTE_MMC_WP_GPIO], | ||
162 | qemu_allocate_irqs(palmte_mmc_cover, cpu, 1)[0]); | 163 | qemu_allocate_irqs(palmte_mmc_cover, cpu, 1)[0]); |
163 | 164 | ||
164 | /* Setup initial (reset) machine state */ | 165 | /* Setup initial (reset) machine state */ |