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 */ | ... | ... |