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;
|