aboutsummaryrefslogtreecommitdiff
path: root/hw/omap_gpio.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/omap_gpio.c')
-rw-r--r--hw/omap_gpio.c258
1 files changed, 151 insertions, 107 deletions
diff --git a/hw/omap_gpio.c b/hw/omap_gpio.c
index 478f7d9825..c23964c66d 100644
--- a/hw/omap_gpio.c
+++ b/hw/omap_gpio.c
@@ -20,10 +20,10 @@
#include "hw.h"
#include "omap.h"
-/* General-Purpose I/O */
+#include "sysbus.h"
+
struct omap_gpio_s {
qemu_irq irq;
- qemu_irq *in;
qemu_irq handler[16];
uint16_t inputs;
@@ -35,9 +35,17 @@ struct omap_gpio_s {
uint16_t pins;
};
+struct omap_gpif_s {
+ SysBusDevice busdev;
+ int mpu_model;
+ void *clk;
+ struct omap_gpio_s omap1;
+};
+
+/* General-Purpose I/O of OMAP1 */
static void omap_gpio_set(void *opaque, int line, int level)
{
- struct omap_gpio_s *s = (struct omap_gpio_s *) opaque;
+ struct omap_gpio_s *s = &((struct omap_gpif_s *) opaque)->omap1;
uint16_t prev = s->inputs;
if (level)
@@ -160,7 +168,7 @@ static CPUWriteMemoryFunc * const omap_gpio_writefn[] = {
omap_badwidth_write16,
};
-void omap_gpio_reset(struct omap_gpio_s *s)
+static void omap_gpio_reset(struct omap_gpio_s *s)
{
s->inputs = 0;
s->outputs = ~0;
@@ -171,43 +179,12 @@ void omap_gpio_reset(struct omap_gpio_s *s)
s->pins = ~0;
}
-struct omap_gpio_s *omap_gpio_init(target_phys_addr_t base,
- qemu_irq irq, omap_clk clk)
-{
- int iomemtype;
- struct omap_gpio_s *s = (struct omap_gpio_s *)
- qemu_mallocz(sizeof(struct omap_gpio_s));
-
- s->irq = irq;
- s->in = qemu_allocate_irqs(omap_gpio_set, s, 16);
- omap_gpio_reset(s);
-
- iomemtype = cpu_register_io_memory(omap_gpio_readfn,
- omap_gpio_writefn, s, DEVICE_NATIVE_ENDIAN);
- cpu_register_physical_memory(base, 0x1000, iomemtype);
-
- return s;
-}
-
-qemu_irq *omap_gpio_in_get(struct omap_gpio_s *s)
-{
- return s->in;
-}
-
-void omap_gpio_out_set(struct omap_gpio_s *s, int line, qemu_irq handler)
-{
- if (line >= 16 || line < 0)
- hw_error("%s: No GPIO line %i\n", __FUNCTION__, line);
- s->handler[line] = handler;
-}
-
-/* General-Purpose Interface of OMAP2 */
struct omap2_gpio_s {
qemu_irq irq[2];
qemu_irq wkup;
- qemu_irq *in;
- qemu_irq handler[32];
+ qemu_irq *handler;
+ uint8_t revision;
uint8_t config[2];
uint32_t inputs;
uint32_t outputs;
@@ -221,8 +198,21 @@ struct omap2_gpio_s {
uint8_t delay;
};
+struct omap2_gpif_s {
+ SysBusDevice busdev;
+ int mpu_model;
+ void *iclk;
+ void *fclk[6];
+ int modulecount;
+ struct omap2_gpio_s *modules;
+ qemu_irq *handler;
+ int autoidle;
+ int gpo;
+};
+
+/* General-Purpose Interface of OMAP2/3 */
static inline void omap2_gpio_module_int_update(struct omap2_gpio_s *s,
- int line)
+ int line)
{
qemu_set_irq(s->irq[line], s->ints[line] & s->mask[line]);
}
@@ -269,10 +259,12 @@ static inline void omap2_gpio_module_int(struct omap2_gpio_s *s, int line)
omap2_gpio_module_wake(s, line);
}
-static void omap2_gpio_module_set(void *opaque, int line, int level)
+static void omap2_gpio_set(void *opaque, int line, int level)
{
- struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque;
+ struct omap2_gpif_s *p = opaque;
+ struct omap2_gpio_s *s = &p->modules[line >> 5];
+ line &= 31;
if (level) {
if (s->dir & (1 << line) & ((~s->inputs & s->edge[0]) | s->level[1]))
omap2_gpio_module_int(s, line);
@@ -308,7 +300,7 @@ static uint32_t omap2_gpio_module_read(void *opaque, target_phys_addr_t addr)
switch (addr) {
case 0x00: /* GPIO_REVISION */
- return 0x18;
+ return s->revision;
case 0x10: /* GPIO_SYSCONFIG */
return s->config[0];
@@ -583,45 +575,28 @@ static CPUWriteMemoryFunc * const omap2_gpio_module_writefn[] = {
omap2_gpio_module_write,
};
-static void omap2_gpio_module_init(struct omap2_gpio_s *s,
- struct omap_target_agent_s *ta, int region,
- qemu_irq mpu, qemu_irq dsp, qemu_irq wkup,
- omap_clk fclk, omap_clk iclk)
+static void omap_gpif_reset(DeviceState *dev)
{
- int iomemtype;
-
- s->irq[0] = mpu;
- s->irq[1] = dsp;
- s->wkup = wkup;
- s->in = qemu_allocate_irqs(omap2_gpio_module_set, s, 32);
-
- iomemtype = l4_register_io_memory(omap2_gpio_module_readfn,
- omap2_gpio_module_writefn, s);
- omap_l4_attach(ta, region, iomemtype);
+ struct omap_gpif_s *s = FROM_SYSBUS(struct omap_gpif_s,
+ sysbus_from_qdev(dev));
+ omap_gpio_reset(&s->omap1);
}
-struct omap_gpif_s {
- struct omap2_gpio_s module[5];
- int modules;
-
- int autoidle;
- int gpo;
-};
-
-void omap_gpif_reset(struct omap_gpif_s *s)
+static void omap2_gpif_reset(DeviceState *dev)
{
int i;
-
- for (i = 0; i < s->modules; i ++)
- omap2_gpio_module_reset(s->module + i);
-
+ struct omap2_gpif_s *s = FROM_SYSBUS(struct omap2_gpif_s,
+ sysbus_from_qdev(dev));
+ for (i = 0; i < s->modulecount; i++) {
+ omap2_gpio_module_reset(&s->modules[i]);
+ }
s->autoidle = 0;
s->gpo = 0;
}
-static uint32_t omap_gpif_top_read(void *opaque, target_phys_addr_t addr)
+static uint32_t omap2_gpif_top_read(void *opaque, target_phys_addr_t addr)
{
- struct omap_gpif_s *s = (struct omap_gpif_s *) opaque;
+ struct omap2_gpif_s *s = (struct omap2_gpif_s *) opaque;
switch (addr) {
case 0x00: /* IPGENERICOCPSPL_REVISION */
@@ -647,10 +622,10 @@ static uint32_t omap_gpif_top_read(void *opaque, target_phys_addr_t addr)
return 0;
}
-static void omap_gpif_top_write(void *opaque, target_phys_addr_t addr,
+static void omap2_gpif_top_write(void *opaque, target_phys_addr_t addr,
uint32_t value)
{
- struct omap_gpif_s *s = (struct omap_gpif_s *) opaque;
+ struct omap2_gpif_s *s = (struct omap2_gpif_s *) opaque;
switch (addr) {
case 0x00: /* IPGENERICOCPSPL_REVISION */
@@ -662,7 +637,7 @@ static void omap_gpif_top_write(void *opaque, target_phys_addr_t addr,
case 0x10: /* IPGENERICOCPSPL_SYSCONFIG */
if (value & (1 << 1)) /* SOFTRESET */
- omap_gpif_reset(s);
+ omap2_gpif_reset(&s->busdev.qdev);
s->autoidle = value & 1;
break;
@@ -676,50 +651,119 @@ static void omap_gpif_top_write(void *opaque, target_phys_addr_t addr,
}
}
-static CPUReadMemoryFunc * const omap_gpif_top_readfn[] = {
- omap_gpif_top_read,
- omap_gpif_top_read,
- omap_gpif_top_read,
+static CPUReadMemoryFunc * const omap2_gpif_top_readfn[] = {
+ omap2_gpif_top_read,
+ omap2_gpif_top_read,
+ omap2_gpif_top_read,
};
-static CPUWriteMemoryFunc * const omap_gpif_top_writefn[] = {
- omap_gpif_top_write,
- omap_gpif_top_write,
- omap_gpif_top_write,
+static CPUWriteMemoryFunc * const omap2_gpif_top_writefn[] = {
+ omap2_gpif_top_write,
+ omap2_gpif_top_write,
+ omap2_gpif_top_write,
};
-struct omap_gpif_s *omap2_gpio_init(struct omap_target_agent_s *ta,
- qemu_irq *irq, omap_clk *fclk, omap_clk iclk, int modules)
+static int omap_gpio_init(SysBusDevice *dev)
{
- int iomemtype, i;
- struct omap_gpif_s *s = (struct omap_gpif_s *)
- qemu_mallocz(sizeof(struct omap_gpif_s));
- int region[4] = { 0, 2, 4, 5 };
+ struct omap_gpif_s *s = FROM_SYSBUS(struct omap_gpif_s, dev);
+ if (!s->clk) {
+ hw_error("omap-gpio: clk not connected\n");
+ }
+ qdev_init_gpio_in(&dev->qdev, omap_gpio_set, 16);
+ qdev_init_gpio_out(&dev->qdev, s->omap1.handler, 16);
+ sysbus_init_irq(dev, &s->omap1.irq);
+ sysbus_init_mmio(dev, 0x1000,
+ cpu_register_io_memory(omap_gpio_readfn,
+ omap_gpio_writefn,
+ &s->omap1,
+ DEVICE_NATIVE_ENDIAN));
+ return 0;
+}
- s->modules = modules;
- for (i = 0; i < modules; i ++)
- omap2_gpio_module_init(s->module + i, ta, region[i],
- irq[i], NULL, NULL, fclk[i], iclk);
+static int omap2_gpio_init(SysBusDevice *dev)
+{
+ int i;
+ struct omap2_gpif_s *s = FROM_SYSBUS(struct omap2_gpif_s, dev);
+ if (!s->iclk) {
+ hw_error("omap2-gpio: iclk not connected\n");
+ }
+ if (s->mpu_model < omap3430) {
+ s->modulecount = (s->mpu_model < omap2430) ? 4 : 5;
+ sysbus_init_mmio(dev, 0x1000,
+ cpu_register_io_memory(omap2_gpif_top_readfn,
+ omap2_gpif_top_writefn, s,
+ DEVICE_NATIVE_ENDIAN));
+ } else {
+ s->modulecount = 6;
+ }
+ s->modules = qemu_mallocz(s->modulecount * sizeof(struct omap2_gpio_s));
+ s->handler = qemu_mallocz(s->modulecount * 32 * sizeof(qemu_irq));
+ qdev_init_gpio_in(&dev->qdev, omap2_gpio_set, s->modulecount * 32);
+ qdev_init_gpio_out(&dev->qdev, s->handler, s->modulecount * 32);
+ for (i = 0; i < s->modulecount; i++) {
+ struct omap2_gpio_s *m = &s->modules[i];
+ if (!s->fclk[i]) {
+ hw_error("omap2-gpio: fclk%d not connected\n", i);
+ }
+ m->revision = (s->mpu_model < omap3430) ? 0x18 : 0x25;
+ m->handler = &s->handler[i * 32];
+ sysbus_init_irq(dev, &m->irq[0]); /* mpu irq */
+ sysbus_init_irq(dev, &m->irq[1]); /* dsp irq */
+ sysbus_init_irq(dev, &m->wkup);
+ sysbus_init_mmio(dev, 0x1000,
+ cpu_register_io_memory(omap2_gpio_module_readfn,
+ omap2_gpio_module_writefn,
+ m, DEVICE_NATIVE_ENDIAN));
+ }
+ return 0;
+}
- omap_gpif_reset(s);
+/* Using qdev pointer properties for the clocks is not ideal.
+ * qdev should support a generic means of defining a 'port' with
+ * an arbitrary interface for connecting two devices. Then we
+ * could reframe the omap clock API in terms of clock ports,
+ * and get some type safety. For now the best qdev provides is
+ * passing an arbitrary pointer.
+ * (It's not possible to pass in the string which is the clock
+ * name, because this device does not have the necessary information
+ * (ie the struct omap_mpu_state_s*) to do the clockname to pointer
+ * translation.)
+ */
- iomemtype = l4_register_io_memory(omap_gpif_top_readfn,
- omap_gpif_top_writefn, s);
- omap_l4_attach(ta, 1, iomemtype);
+static SysBusDeviceInfo omap_gpio_info = {
+ .init = omap_gpio_init,
+ .qdev.name = "omap-gpio",
+ .qdev.size = sizeof(struct omap_gpif_s),
+ .qdev.reset = omap_gpif_reset,
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_INT32("mpu_model", struct omap_gpif_s, mpu_model, 0),
+ DEFINE_PROP_PTR("clk", struct omap_gpif_s, clk),
+ DEFINE_PROP_END_OF_LIST()
+ }
+};
- return s;
-}
+static SysBusDeviceInfo omap2_gpio_info = {
+ .init = omap2_gpio_init,
+ .qdev.name = "omap2-gpio",
+ .qdev.size = sizeof(struct omap2_gpif_s),
+ .qdev.reset = omap2_gpif_reset,
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_INT32("mpu_model", struct omap2_gpif_s, mpu_model, 0),
+ DEFINE_PROP_PTR("iclk", struct omap2_gpif_s, iclk),
+ DEFINE_PROP_PTR("fclk0", struct omap2_gpif_s, fclk[0]),
+ DEFINE_PROP_PTR("fclk1", struct omap2_gpif_s, fclk[1]),
+ DEFINE_PROP_PTR("fclk2", struct omap2_gpif_s, fclk[2]),
+ DEFINE_PROP_PTR("fclk3", struct omap2_gpif_s, fclk[3]),
+ DEFINE_PROP_PTR("fclk4", struct omap2_gpif_s, fclk[4]),
+ DEFINE_PROP_PTR("fclk5", struct omap2_gpif_s, fclk[5]),
+ DEFINE_PROP_END_OF_LIST()
+ }
+};
-qemu_irq *omap2_gpio_in_get(struct omap_gpif_s *s, int start)
+static void omap_gpio_register_device(void)
{
- if (start >= s->modules * 32 || start < 0)
- hw_error("%s: No GPIO line %i\n", __FUNCTION__, start);
- return s->module[start >> 5].in + (start & 31);
+ sysbus_register_withprop(&omap_gpio_info);
+ sysbus_register_withprop(&omap2_gpio_info);
}
-void omap2_gpio_out_set(struct omap_gpif_s *s, int line, qemu_irq handler)
-{
- if (line >= s->modules * 32 || line < 0)
- hw_error("%s: No GPIO line %i\n", __FUNCTION__, line);
- s->module[line >> 5].handler[line & 31] = handler;
-}
+device_init(omap_gpio_register_device)