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 | 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 | 3241 | /* General chip reset */ |
3069 | 3242 | static void omap_mpu_reset(void *opaque) |
3070 | 3243 | { |
... | ... | @@ -3093,6 +3266,7 @@ static void omap_mpu_reset(void *opaque) |
3093 | 3266 | omap_uart_reset(mpu->uart3); |
3094 | 3267 | omap_mmc_reset(mpu->mmc); |
3095 | 3268 | omap_mpuio_reset(mpu->mpuio); |
3269 | + omap_gpio_reset(mpu->gpio); | |
3096 | 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 | 3382 | s->irq[1][OMAP_INT_KEYBOARD], s->irq[1][OMAP_INT_MPUIO], |
3209 | 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 | 3388 | qemu_register_reset(omap_mpu_reset, s); |
3212 | 3389 | |
3213 | 3390 | return s; | ... | ... |
hw/omap.h
... | ... | @@ -458,6 +458,12 @@ qemu_irq *omap_mpuio_in_get(struct omap_mpuio_s *s); |
458 | 458 | void omap_mpuio_out_set(struct omap_mpuio_s *s, int line, qemu_irq handler); |
459 | 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 | 467 | /* omap_lcdc.c */ |
462 | 468 | struct omap_lcd_panel_s; |
463 | 469 | void omap_lcdc_reset(struct omap_lcd_panel_s *s); |
... | ... | @@ -574,6 +580,7 @@ struct omap_mpu_state_s { |
574 | 580 | } clkm; |
575 | 581 | |
576 | 582 | struct omap_mpuio_s *mpuio; |
583 | + struct omap_gpio_s *gpio; | |
577 | 584 | } *omap310_mpu_init(unsigned long sdram_size, |
578 | 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 | 158 | |
159 | 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 | 163 | qemu_allocate_irqs(palmte_mmc_cover, cpu, 1)[0]); |
163 | 164 | |
164 | 165 | /* Setup initial (reset) machine state */ | ... | ... |