Revision 64330148 hw/omap.c
b/hw/omap.c | ||
---|---|---|
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 | 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 | 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; |
Also available in: Unified diff