[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH V4 1/5] SSI: Built in multiple device support
From: |
Peter A. G. Crosthwaite |
Subject: |
[Qemu-devel] [PATCH V4 1/5] SSI: Built in multiple device support |
Date: |
Mon, 4 Jun 2012 18:08:20 +1000 |
Added support for multiple devices attached to a single SSI bus (Previously
SSI masters with multiple slaves were emulated as multiple point to point SSI
busses)
Signed-off-by: Peter A. G. Crosthwaite <address@hidden>
---
changed from v3:
added ssi_create_slave_noinit
changed from v2:
This patch is new (totally rewitten replacement of (1/4) from v2)
hw/spitz.c | 8 ++--
hw/ssi.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++++--------
hw/ssi.h | 28 ++++++++++++--
hw/stellaris.c | 6 ++--
hw/tosa.c | 2 +-
hw/z2.c | 2 +-
6 files changed, 125 insertions(+), 28 deletions(-)
diff --git a/hw/spitz.c b/hw/spitz.c
index 1d6d2b0..f63a9bf 100644
--- a/hw/spitz.c
+++ b/hw/spitz.c
@@ -669,18 +669,18 @@ static void spitz_ssp_attach(PXA2xxState *cpu)
DeviceState *dev;
void *bus;
- mux = ssi_create_slave(cpu->ssp[CORGI_SSP_PORT - 1], "corgi-ssp");
+ mux = ssi_create_slave(cpu->ssp[CORGI_SSP_PORT - 1], "corgi-ssp", 0);
bus = qdev_get_child_bus(mux, "ssi0");
- ssi_create_slave(bus, "spitz-lcdtg");
+ ssi_create_slave(bus, "spitz-lcdtg", 0);
bus = qdev_get_child_bus(mux, "ssi1");
- dev = ssi_create_slave(bus, "ads7846");
+ dev = ssi_create_slave(bus, "ads7846", 0);
qdev_connect_gpio_out(dev, 0,
qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_TP_INT));
bus = qdev_get_child_bus(mux, "ssi2");
- max1111 = ssi_create_slave(bus, "max1111");
+ max1111 = ssi_create_slave(bus, "max1111", 0);
max111x_set_input(max1111, MAX1111_BATT_VOLT, SPITZ_BATTERY_VOLT);
max111x_set_input(max1111, MAX1111_BATT_TEMP, 0);
max111x_set_input(max1111, MAX1111_ACIN_VOLT, SPITZ_CHARGEON_ACIN);
diff --git a/hw/ssi.c b/hw/ssi.c
index 8f2d9bc..af7e887 100644
--- a/hw/ssi.c
+++ b/hw/ssi.c
@@ -2,6 +2,8 @@
* QEMU Synchronous Serial Interface support
*
* Copyright (c) 2009 CodeSourcery.
+ * Copyright (c) 2012 Peter A.G. Crosthwaite (address@hidden)
+ * Copyright (c) 2012 PetaLogix Pty Ltd.
* Written by Paul Brook
*
* This code is licensed under the GNU GPL v2.
@@ -14,24 +16,33 @@
struct SSIBus {
BusState qbus;
+ int32_t selected_slave;
};
static struct BusInfo ssi_bus_info = {
.name = "SSI",
.size = sizeof(SSIBus),
+ .props = (Property[]) {
+ DEFINE_PROP_INT32("slave_select", struct SSISlave, slave_select, 0),
+ DEFINE_PROP_END_OF_LIST(),
+ }
+};
+
+static const VMStateDescription vmstate_ssi_bus = {
+ .name = "ssi_bus",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_INT32(selected_slave, SSIBus),
+ VMSTATE_END_OF_LIST()
+ }
};
static int ssi_slave_init(DeviceState *dev)
{
SSISlave *s = SSI_SLAVE(dev);
SSISlaveClass *ssc = SSI_SLAVE_GET_CLASS(s);
- SSIBus *bus;
-
- bus = FROM_QBUS(SSIBus, qdev_get_parent_bus(dev));
- if (QTAILQ_FIRST(&bus->qbus.children) != dev
- || QTAILQ_NEXT(dev, sibling) != NULL) {
- hw_error("Too many devices on SSI bus");
- }
return ssc->init(s);
}
@@ -46,40 +57,106 @@ static void ssi_slave_class_init(ObjectClass *klass, void
*data)
static TypeInfo ssi_slave_info = {
.name = TYPE_SSI_SLAVE,
.parent = TYPE_DEVICE,
+ .instance_size = sizeof(struct SSISlave),
.class_init = ssi_slave_class_init,
.class_size = sizeof(SSISlaveClass),
.abstract = true,
};
-DeviceState *ssi_create_slave(SSIBus *bus, const char *name)
+DeviceState *ssi_create_slave_no_init(SSIBus *bus, const char *name,
+ int32_t slave_select)
{
DeviceState *dev;
dev = qdev_create(&bus->qbus, name);
+ qdev_prop_set_int32(dev, "slave_select", slave_select);
+ return dev;
+}
+
+DeviceState *ssi_create_slave(SSIBus *bus, const char *name,
+ int32_t slave_select)
+{
+ DeviceState *dev;
+ dev = ssi_create_slave_no_init(bus, name, slave_select);
qdev_init_nofail(dev);
return dev;
+
}
SSIBus *ssi_create_bus(DeviceState *parent, const char *name)
{
- BusState *bus;
- bus = qbus_create(&ssi_bus_info, parent, name);
- return FROM_QBUS(SSIBus, bus);
+ SSIBus *bus;
+
+ bus = FROM_QBUS(SSIBus, qbus_create(&ssi_bus_info, parent, name));
+ vmstate_register(NULL, -1, &vmstate_ssi_bus, bus);
+ return bus;
+}
+
+static SSISlave *get_current_slave(SSIBus *bus)
+{
+ DeviceState *qdev;
+
+ QTAILQ_FOREACH(qdev, &bus->qbus.children, sibling) {
+ SSISlave *candidate = SSI_SLAVE_FROM_QDEV(qdev);
+ if (candidate->slave_select == bus->selected_slave) {
+ return candidate;
+ }
+ }
+
+ return NULL;
+}
+
+void ssi_select_slave(SSIBus *bus, int32_t selected_slave)
+{
+ SSISlave *slave;
+ SSISlaveClass *ssc;
+
+ if (bus->selected_slave == selected_slave) {
+ return;
+ }
+
+ slave = get_current_slave(bus);
+ if (slave) {
+ ssc = SSI_SLAVE_GET_CLASS(slave);
+ if (ssc->set_cs) {
+ ssc->set_cs(slave, 0);
+ }
+ }
+ bus->selected_slave = selected_slave;
+
+ slave = get_current_slave(bus);
+ if (slave) {
+ ssc = SSI_SLAVE_GET_CLASS(slave);
+ if (ssc->set_cs) {
+ ssc->set_cs(slave, 1);
+ }
+ }
+
}
uint32_t ssi_transfer(SSIBus *bus, uint32_t val)
{
- DeviceState *dev;
SSISlave *slave;
SSISlaveClass *ssc;
- dev = QTAILQ_FIRST(&bus->qbus.children);
- if (!dev) {
+
+ slave = get_current_slave(bus);
+ if (!slave) {
return 0;
}
- slave = SSI_SLAVE(dev);
ssc = SSI_SLAVE_GET_CLASS(slave);
return ssc->transfer(slave, val);
}
+const VMStateDescription vmstate_ssi_slave = {
+ .name = "SSISlave",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_INT32(slave_select, SSISlave),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static void ssi_slave_register_types(void)
{
type_register_static(&ssi_slave_info);
diff --git a/hw/ssi.h b/hw/ssi.h
index 06657d7..7f0ea36 100644
--- a/hw/ssi.h
+++ b/hw/ssi.h
@@ -1,10 +1,10 @@
/* QEMU Synchronous Serial Interface support. */
-/* In principle SSI is a point-point interface. As such the qemu
- implementation has a single slave device on a "bus".
+/* In principle SSI is a point-point interface.
However it is fairly common for boards to have multiple slaves
connected to a single master, and select devices with an external
- chip select. This is implemented in qemu by having an explicit mux device.
+ chip select. SSI busses can therefore have any number of slaves,
+ of which a master can select using ssi_select_slave().
It is assumed that master and slave are both using the same transfer width.
*/
@@ -29,22 +29,42 @@ typedef struct SSISlaveClass {
int (*init)(SSISlave *dev);
uint32_t (*transfer)(SSISlave *dev, uint32_t val);
+ int (*set_cs)(SSISlave *dev, int state);
} SSISlaveClass;
struct SSISlave {
DeviceState qdev;
+
+ int32_t slave_select;
};
#define SSI_SLAVE_FROM_QDEV(dev) DO_UPCAST(SSISlave, qdev, dev)
#define FROM_SSI_SLAVE(type, dev) DO_UPCAST(type, ssidev, dev)
-DeviceState *ssi_create_slave(SSIBus *bus, const char *name);
+DeviceState *ssi_create_slave(SSIBus *bus, const char *name,
+ int32_t slave_select);
+DeviceState *ssi_create_slave_no_init(SSIBus *bus, const char *name,
+ int32_t slave_select);
/* Master interface. */
SSIBus *ssi_create_bus(DeviceState *parent, const char *name);
+#define SSI_SLAVE_SELECT_NONE (-1)
+
+void ssi_select_slave(SSIBus *bus, int32_t selected_slave);
+
uint32_t ssi_transfer(SSIBus *bus, uint32_t val);
+extern const VMStateDescription vmstate_ssi_slave;
+
+#define VMSTATE_SSI_SLAVE(_field, _state) { \
+ .name = (stringify(_field)), \
+ .size = sizeof(SSISlave), \
+ .vmsd = &vmstate_ssi_slave, \
+ .flags = VMS_STRUCT, \
+ .offset = vmstate_offset_value(_state, _field, SSISlave), \
+}
+
/* max111x.c */
void max111x_set_input(DeviceState *dev, int line, uint8_t value);
diff --git a/hw/stellaris.c b/hw/stellaris.c
index 562fbbf..e0600a1 100644
--- a/hw/stellaris.c
+++ b/hw/stellaris.c
@@ -1309,14 +1309,14 @@ static void stellaris_init(const char *kernel_filename,
const char *cpu_model,
void *bus;
bus = qdev_get_child_bus(dev, "ssi");
- mux = ssi_create_slave(bus, "evb6965-ssi");
+ mux = ssi_create_slave(bus, "evb6965-ssi", 0);
gpio_out[GPIO_D][0] = qdev_get_gpio_in(mux, 0);
bus = qdev_get_child_bus(mux, "ssi0");
- ssi_create_slave(bus, "ssi-sd");
+ ssi_create_slave(bus, "ssi-sd", 0);
bus = qdev_get_child_bus(mux, "ssi1");
- dev = ssi_create_slave(bus, "ssd0323");
+ dev = ssi_create_slave(bus, "ssd0323", 0);
gpio_out[GPIO_C][7] = qdev_get_gpio_in(dev, 0);
/* Make sure the select pin is high. */
diff --git a/hw/tosa.c b/hw/tosa.c
index 6baa17d..3986810 100644
--- a/hw/tosa.c
+++ b/hw/tosa.c
@@ -196,7 +196,7 @@ static void tosa_tg_init(PXA2xxState *cpu)
{
i2c_bus *bus = pxa2xx_i2c_bus(cpu->i2c[0]);
i2c_create_slave(bus, "tosa_dac", DAC_BASE);
- ssi_create_slave(cpu->ssp[1], "tosa-ssp");
+ ssi_create_slave(cpu->ssp[1], "tosa-ssp", 0);
}
diff --git a/hw/z2.c b/hw/z2.c
index 654ac55..2a0ecf5 100644
--- a/hw/z2.c
+++ b/hw/z2.c
@@ -346,7 +346,7 @@ static void z2_init(ram_addr_t ram_size,
type_register_static(&zipit_lcd_info);
type_register_static(&aer915_info);
- z2_lcd = ssi_create_slave(cpu->ssp[1], "zipit-lcd");
+ z2_lcd = ssi_create_slave(cpu->ssp[1], "zipit-lcd", 0);
bus = pxa2xx_i2c_bus(cpu->i2c[0]);
i2c_create_slave(bus, "aer915", 0x55);
wm = i2c_create_slave(bus, "wm8750", 0x1b);
--
1.7.3.2
- [Qemu-devel] [PATCH V4 0/5] Ehnahced SSI bus support + M25P80 SPI flash + Xilinx SPI controller, Peter A. G. Crosthwaite, 2012/06/04
- [Qemu-devel] [PATCH V4 1/5] SSI: Built in multiple device support,
Peter A. G. Crosthwaite <=
- [Qemu-devel] [PATCH V4 2/5] m25p80: initial verion, Peter A. G. Crosthwaite, 2012/06/04
- [Qemu-devel] [PATCH V4 4/5] petalogix-ml605: added spi controller with m25p80, Peter A. G. Crosthwaite, 2012/06/04
- [Qemu-devel] [PATCH V4 3/5] xilinx_spi: initial version, Peter A. G. Crosthwaite, 2012/06/04
- [Qemu-devel] [PATCH V4 5/5] stellaris: Updated spi bus implementation, Peter A. G. Crosthwaite, 2012/06/04
- Re: [Qemu-devel] [PATCH V4 0/5] Ehnahced SSI bus support + M25P80 SPI flash + Xilinx SPI controller, Paul Brook, 2012/06/04