Commit 6433014805f6f23050c4c4d0483b0241b3eaccb4

Authored by balrog
1 parent 623a930e

Add OMAP Shared GPIO module.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3473 c046a42c-6fe2-441c-8c8c-71466251a162
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 */
... ...