qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH V4 0/5] Ehnahced SSI bus support + M25P80 SPI flash + Xilinx SPI controller
@ 2012-06-04  8:08 Peter A. G. Crosthwaite
  2012-06-04  8:08 ` [Qemu-devel] [PATCH V4 1/5] SSI: Built in multiple device support Peter A. G. Crosthwaite
                   ` (5 more replies)
  0 siblings, 6 replies; 12+ messages in thread
From: Peter A. G. Crosthwaite @ 2012-06-04  8:08 UTC (permalink / raw)
  To: qemu-devel, paul, edgar.iglesias, peter.maydell, stefanha
  Cc: peter.crosthwaite, john.williams

Patch 1 Enhances SSI bus support to properly support multiple attached devices. An api is provided for SSI/SPI masters to select a particular device attached to the bus.

Patch 2 is a device model for the m25p80 style SPI flash chip.

Patch 3 is  the Xilinx XPS SPI contoller. Its a sysbus device that instantiates a ssi bus, and interfaces the two (as per the controllers functionality)

Patch 4 instantiates the XPS SPI controller in the petalogix ML605 reference platform and connects two m25p80s to it.

Patch 5 updates the stellaris machine model to use the multi slave SSI support

CHANGELOG:
changed from v3:
addressed reviewer comments from P Maydell and S Hajnoczi
added patch 5 (re Paul Brooks request)
changed from v2:
folded former SPI bus functionality into existing SSI infrastructure (suggested - Paul Brook) (all patches)
made m25p80 use async io (suggested - Stefan Hajnoczi) (2/4)
instantiated two spi flashes instead of one in ml605 ref design (4/4)
changed from v1:
minor sylistic changes (1/4)
converted spi api to modified txrx style (1-3/4)
heavily refactored m25p80 model (2/4)

Peter A. G. Crosthwaite (5):
  SSI: Built in multiple device support
  m25p80: initial verion
  xilinx_spi: initial version
  petalogix-ml605: added spi controller with m25p80
  stellaris: Updated spi bus implementation

 Makefile.target                          |    2 +
 default-configs/microblaze-softmmu.mak   |    1 +
 default-configs/microblazeel-softmmu.mak |    1 +
 hw/m25p80.c                              |  557 ++++++++++++++++++++++++++++++
 hw/petalogix_ml605_mmu.c                 |   23 ++
 hw/spitz.c                               |    8 +-
 hw/ssi.c                                 |  107 +++++-
 hw/ssi.h                                 |   28 ++-
 hw/stellaris.c                           |   21 +-
 hw/tosa.c                                |    2 +-
 hw/xilinx_spi.c                          |  481 ++++++++++++++++++++++++++
 hw/z2.c                                  |    2 +-
 12 files changed, 1196 insertions(+), 37 deletions(-)
 create mode 100644 hw/m25p80.c
 create mode 100644 hw/xilinx_spi.c

-- 
1.7.3.2

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [Qemu-devel] [PATCH V4 1/5] SSI: Built in multiple device support
  2012-06-04  8:08 [Qemu-devel] [PATCH V4 0/5] Ehnahced SSI bus support + M25P80 SPI flash + Xilinx SPI controller Peter A. G. Crosthwaite
@ 2012-06-04  8:08 ` Peter A. G. Crosthwaite
  2012-06-04  8:08 ` [Qemu-devel] [PATCH V4 2/5] m25p80: initial verion Peter A. G. Crosthwaite
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 12+ messages in thread
From: Peter A. G. Crosthwaite @ 2012-06-04  8:08 UTC (permalink / raw)
  To: qemu-devel, paul, edgar.iglesias, peter.maydell, stefanha
  Cc: peter.crosthwaite, john.williams

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 <peter.crosthwaite@petalogix.com>
---
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 (peter.crosthwaite@petalogix.com)
+ * 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

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [Qemu-devel] [PATCH V4 2/5] m25p80: initial verion
  2012-06-04  8:08 [Qemu-devel] [PATCH V4 0/5] Ehnahced SSI bus support + M25P80 SPI flash + Xilinx SPI controller Peter A. G. Crosthwaite
  2012-06-04  8:08 ` [Qemu-devel] [PATCH V4 1/5] SSI: Built in multiple device support Peter A. G. Crosthwaite
@ 2012-06-04  8:08 ` Peter A. G. Crosthwaite
  2012-06-04  8:08 ` [Qemu-devel] [PATCH V4 3/5] xilinx_spi: initial version Peter A. G. Crosthwaite
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 12+ messages in thread
From: Peter A. G. Crosthwaite @ 2012-06-04  8:08 UTC (permalink / raw)
  To: qemu-devel, paul, edgar.iglesias, peter.maydell, stefanha
  Cc: peter.crosthwaite, john.williams

Added device model for m25p80 SPI flash

Signed-off-by: Peter A. G. Crosthwaite <peter.crosthwaite@petalogix.com>
---
changed from v3:
changed licence to v2 or later (PMM review)
generalised device model - rather than being fixed to the fl064k, it can handle a wide range of m25p80 devices
refactored erase commands (previously they were fl064k specific and used spansions broken terminology)
typdef'd strcuts and enums
fixed some camel casing
added comment to explain why bdrv_sync_complete is a nop (PMM review)
removed hardcoded "512" for BDRV_SECTOR_SIZE
flash_sync_area: use bdrv_aio_writev instead of bdrv_write 
flash_chip_erase/flash_block_erase32k/flash_sector_erase: consolidated to one function
decode_new_cmd: fixed multi-statement lines (PMM review)
CHIP_ERASE->BULK_ERASE
init: drive_get -> drive_get_next (PMM review)
changed from v2:
updated for SSI slave interface
used async io (suggested - Stefan Hajnoczi)
changed from v1:
converted spi api to modified txrx style
factored out lots of common code and inlined overly short single call functions.
undated for txrx style spi interface
 Makefile.target |    1 +
 hw/m25p80.c     |  557 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 558 insertions(+), 0 deletions(-)
 create mode 100644 hw/m25p80.c

diff --git a/Makefile.target b/Makefile.target
index 1582904..77feb83 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -292,6 +292,7 @@ obj-mips-$(CONFIG_FULONG) += bonito.o vt82c686.o mips_fulong2e.o
 obj-microblaze-y = petalogix_s3adsp1800_mmu.o
 obj-microblaze-y += petalogix_ml605_mmu.o
 obj-microblaze-y += microblaze_boot.o
+obj-microblaze-y += m25p80.o
 
 obj-microblaze-y += microblaze_pic_cpu.o
 obj-microblaze-y += xilinx_intc.o
diff --git a/hw/m25p80.c b/hw/m25p80.c
new file mode 100644
index 0000000..0edb67f
--- /dev/null
+++ b/hw/m25p80.c
@@ -0,0 +1,557 @@
+/*
+ * ST M25P80 emulator. Emulate all SPI flash devices based on the m25p80 command
+ * set. Known devices table current as of Jun/2012 and taked from linux.
+ * See drivers/mtd/devices/m25p80.c.
+ *
+ * Copyright (C) 2011 Edgar E. Iglesias <edgar.iglesias@gmail.com>
+ * Copyright (C) 2012 Peter A. G. Crosthwaite <peter.crosthwaite@petalogix.com>
+ * Copyright (C) 2012 PetaLogix
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) a later version of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw.h"
+#include "blockdev.h"
+#include "ssi.h"
+#include "devices.h"
+
+#ifdef M25P80_ERR_DEBUG
+#define DB_PRINT(...) do { \
+    fprintf(stderr,  ": %s: ", __func__); \
+    fprintf(stderr, ## __VA_ARGS__); \
+    } while (0);
+#else
+    #define DB_PRINT(...)
+#endif
+
+typedef struct FlashPartInfo {
+    const char *part_name;
+    /* jedec code. (jedec >> 16) & 0xff is the 1st byte, >> 8 the 2nd etc */
+    uint32_t jedec;
+    /* extended jedec code */
+    uint16_t ext_jedec;
+    /* there is confusion between manufacturers as to what a sector is. In this
+     * device model, a "sector" is the size that is erased by the ERASE_SECTOR
+     * command (opcode 0xd8).
+     */
+    uint32_t sector_size;
+    uint32_t n_sectors;
+    uint32_t page_size;
+    uint8_t flags;
+#define ER_4K 1
+#define ER_32K 2
+} FlashPartInfo;
+
+/* adapted from linux */
+
+#define INFO(_part_name, _jedec, _ext_jedec, _sector_size, _n_sectors, _flags)\
+    .part_name = (_part_name),\
+    .jedec = (_jedec),\
+    .ext_jedec = (_ext_jedec),\
+    .sector_size = (_sector_size),\
+    .n_sectors = (_n_sectors),\
+    .page_size = 256,\
+    .flags = (_flags),\
+
+static const FlashPartInfo known_devices[] = {
+    /* Atmel -- some are (confusingly) marketed as "DataFlash" */
+    { INFO("at25fs010",   0x1f6601,      0,  32 << 10,   4, ER_4K) },
+    { INFO("at25fs040",   0x1f6604,      0,  64 << 10,   8, ER_4K) },
+
+    { INFO("at25df041a",  0x1f4401,      0,  64 << 10,   8, ER_4K) },
+    { INFO("at25df321a",  0x1f4701,      0,  64 << 10,  64, ER_4K) },
+    { INFO("at25df641",   0x1f4800,      0,  64 << 10, 128, ER_4K) },
+
+    { INFO("at26f004",    0x1f0400,      0,  64 << 10,   8, ER_4K) },
+    { INFO("at26df081a",  0x1f4501,      0,  64 << 10,  16, ER_4K) },
+    { INFO("at26df161a",  0x1f4601,      0,  64 << 10,  32, ER_4K) },
+    { INFO("at26df321",   0x1f4700,      0,  64 << 10,  64, ER_4K) },
+
+    /* EON -- en25xxx */
+    { INFO("en25f32",     0x1c3116,      0,  64 << 10,  64, ER_4K) },
+    { INFO("en25p32",     0x1c2016,      0,  64 << 10,  64, 0) },
+    { INFO("en25q32b",    0x1c3016,      0,  64 << 10,  64, 0) },
+    { INFO("en25p64",     0x1c2017,      0,  64 << 10, 128, 0) },
+
+    /* Intel/Numonyx -- xxxs33b */
+    { INFO("160s33b",     0x898911,      0,  64 << 10,  32, 0) },
+    { INFO("320s33b",     0x898912,      0,  64 << 10,  64, 0) },
+    { INFO("640s33b",     0x898913,      0,  64 << 10, 128, 0) },
+
+    /* Macronix */
+    { INFO("mx25l4005a",  0xc22013,      0,  64 << 10,   8, ER_4K) },
+    { INFO("mx25l8005",   0xc22014,      0,  64 << 10,  16, 0) },
+    { INFO("mx25l1606e",  0xc22015,      0,  64 << 10,  32, ER_4K) },
+    { INFO("mx25l3205d",  0xc22016,      0,  64 << 10,  64, 0) },
+    { INFO("mx25l6405d",  0xc22017,      0,  64 << 10, 128, 0) },
+    { INFO("mx25l12805d", 0xc22018,      0,  64 << 10, 256, 0) },
+    { INFO("mx25l12855e", 0xc22618,      0,  64 << 10, 256, 0) },
+    { INFO("mx25l25635e", 0xc22019,      0,  64 << 10, 512, 0) },
+    { INFO("mx25l25655e", 0xc22619,      0,  64 << 10, 512, 0) },
+
+    /* Spansion -- single (large) sector size only, at least
+     * for the chips listed here (without boot sectors).
+     */
+    { INFO("s25sl004a",   0x010212,      0,  64 << 10,   8, 0) },
+    { INFO("s25sl008a",   0x010213,      0,  64 << 10,  16, 0) },
+    { INFO("s25sl016a",   0x010214,      0,  64 << 10,  32, 0) },
+    { INFO("s25sl032a",   0x010215,      0,  64 << 10,  64, 0) },
+    { INFO("s25sl032p",   0x010215, 0x4d00,  64 << 10,  64, ER_4K) },
+    { INFO("s25sl064a",   0x010216,      0,  64 << 10, 128, 0) },
+    { INFO("s25fl256s0",  0x010219, 0x4d00, 256 << 10, 128, 0) },
+    { INFO("s25fl256s1",  0x010219, 0x4d01,  64 << 10, 512, 0) },
+    { INFO("s25fl512s",   0x010220, 0x4d00, 256 << 10, 256, 0) },
+    { INFO("s70fl01gs",   0x010221, 0x4d00, 256 << 10, 256, 0) },
+    { INFO("s25sl12800",  0x012018, 0x0300, 256 << 10,  64, 0) },
+    { INFO("s25sl12801",  0x012018, 0x0301,  64 << 10, 256, 0) },
+    { INFO("s25fl129p0",  0x012018, 0x4d00, 256 << 10,  64, 0) },
+    { INFO("s25fl129p1",  0x012018, 0x4d01,  64 << 10, 256, 0) },
+    { INFO("s25fl016k",   0xef4015,      0,  64 << 10,  32, ER_4K | ER_32K) },
+    { INFO("s25fl064k",   0xef4017,      0,  64 << 10, 128, ER_4K | ER_32K) },
+
+    /* SST -- large erase sizes are "overlays", "sectors" are 4<< 10 */
+    { INFO("sst25vf040b", 0xbf258d,      0,  64 << 10,   8, ER_4K) },
+    { INFO("sst25vf080b", 0xbf258e,      0,  64 << 10,  16, ER_4K) },
+    { INFO("sst25vf016b", 0xbf2541,      0,  64 << 10,  32, ER_4K) },
+    { INFO("sst25vf032b", 0xbf254a,      0,  64 << 10,  64, ER_4K) },
+    { INFO("sst25wf512",  0xbf2501,      0,  64 << 10,   1, ER_4K) },
+    { INFO("sst25wf010",  0xbf2502,      0,  64 << 10,   2, ER_4K) },
+    { INFO("sst25wf020",  0xbf2503,      0,  64 << 10,   4, ER_4K) },
+    { INFO("sst25wf040",  0xbf2504,      0,  64 << 10,   8, ER_4K) },
+
+    /* ST Microelectronics -- newer production may have feature updates */
+    { INFO("m25p05",      0x202010,      0,  32 << 10,   2, 0) },
+    { INFO("m25p10",      0x202011,      0,  32 << 10,   4, 0) },
+    { INFO("m25p20",      0x202012,      0,  64 << 10,   4, 0) },
+    { INFO("m25p40",      0x202013,      0,  64 << 10,   8, 0) },
+    { INFO("m25p80",      0x202014,      0,  64 << 10,  16, 0) },
+    { INFO("m25p16",      0x202015,      0,  64 << 10,  32, 0) },
+    { INFO("m25p32",      0x202016,      0,  64 << 10,  64, 0) },
+    { INFO("m25p64",      0x202017,      0,  64 << 10, 128, 0) },
+    { INFO("m25p128",     0x202018,      0, 256 << 10,  64, 0) },
+
+    { INFO("m45pe10",     0x204011,      0,  64 << 10,   2, 0) },
+    { INFO("m45pe80",     0x204014,      0,  64 << 10,  16, 0) },
+    { INFO("m45pe16",     0x204015,      0,  64 << 10,  32, 0) },
+
+    { INFO("m25pe80",     0x208014,      0,  64 << 10,  16, 0) },
+    { INFO("m25pe16",     0x208015,      0,  64 << 10,  32, ER_4K) },
+
+    { INFO("m25px32",     0x207116,      0,  64 << 10,  64, ER_4K) },
+    { INFO("m25px32-s0",  0x207316,      0,  64 << 10,  64, ER_4K) },
+    { INFO("m25px32-s1",  0x206316,      0,  64 << 10,  64, ER_4K) },
+    { INFO("m25px64",     0x207117,      0,  64 << 10, 128, 0) },
+
+    /* Winbond -- w25x "blocks" are 64k, "sectors" are 4KiB */
+    { INFO("w25x10",      0xef3011,      0,  64 << 10,   2, ER_4K) },
+    { INFO("w25x20",      0xef3012,      0,  64 << 10,   4, ER_4K) },
+    { INFO("w25x40",      0xef3013,      0,  64 << 10,   8, ER_4K) },
+    { INFO("w25x80",      0xef3014,      0,  64 << 10,  16, ER_4K) },
+    { INFO("w25x16",      0xef3015,      0,  64 << 10,  32, ER_4K) },
+    { INFO("w25x32",      0xef3016,      0,  64 << 10,  64, ER_4K) },
+    { INFO("w25q32",      0xef4016,      0,  64 << 10,  64, ER_4K) },
+    { INFO("w25x64",      0xef3017,      0,  64 << 10, 128, ER_4K) },
+    { INFO("w25q64",      0xef4017,      0,  64 << 10, 128, ER_4K) },
+
+   /* Numonyx -- n25q128 */
+   { INFO("n25q128",      0x20ba18,      0,  64 << 10, 256, 0) },
+
+    { },
+};
+
+typedef enum {
+    NOP = 0,
+    PP = 0x2,
+    READ = 0x3,
+    WRDI = 0x4,
+    RDSR = 0x5,
+    WREN = 0x6,
+    FAST_READ = 0xb,
+    ERASE_4K = 0x20,
+    ERASE_32K = 0x52,
+    ERASE_SECTOR = 0xd8,
+    JEDEC_READ = 0x9f,
+    BULK_ERASE = 0xc7,
+} FlashCMD;
+
+typedef enum {
+    STATE_IDLE,
+    STATE_PAGE_PROGRAM,
+    STATE_READ,
+    STATE_COLLECTING_DATA,
+    STATE_READING_DATA,
+} CMDState;
+
+typedef struct Flash {
+    SSISlave ssidev;
+    uint32_t r;
+
+    BlockDriverState *bdrv;
+    CMDState state;
+
+    uint8_t *storage;
+    uint32_t size;
+    int page_size;
+
+    uint8_t data[16];
+    uint32_t len;
+    uint32_t pos;
+    uint8_t needed_bytes;
+    FlashCMD cmd_in_progress;
+
+    int64_t dirty_page;
+
+    uint64_t waddr;
+    int write_enable;
+
+    char *part_name;
+    const FlashPartInfo *pi;
+
+} Flash;
+
+static void bdrv_sync_complete(void *opaque, int ret)
+{
+    /* do nothing. Masters do not directly interact with the backing store,
+     * only the working copy so no mutexing required.
+     */
+}
+
+static void flash_sync_page(Flash *s, int page)
+{
+    if (s->bdrv) {
+        int bdrv_sector, nb_sectors;
+        QEMUIOVector iov;
+
+        bdrv_sector = (page * s->pi->page_size) / BDRV_SECTOR_SIZE;
+        nb_sectors = DIV_ROUND_UP(s->pi->page_size, BDRV_SECTOR_SIZE);
+        qemu_iovec_init(&iov, 1);
+        qemu_iovec_add(&iov, s->storage + bdrv_sector * BDRV_SECTOR_SIZE,
+                                                nb_sectors * BDRV_SECTOR_SIZE);
+        bdrv_aio_writev(s->bdrv, bdrv_sector, &iov, nb_sectors,
+                                                bdrv_sync_complete, NULL);
+    }
+}
+
+static inline void flash_sync_area(Flash *s, int64_t off, int64_t len)
+{
+    int64_t start, end;
+    int nb_sectors;
+    QEMUIOVector iov;
+
+    if (!s->bdrv) {
+        return;
+    }
+
+    assert(!(len % BDRV_SECTOR_SIZE));
+    start = off / BDRV_SECTOR_SIZE;
+    end = (off + len) / BDRV_SECTOR_SIZE;
+    nb_sectors = end - start;
+    qemu_iovec_init(&iov, 1);
+    qemu_iovec_add(&iov, s->storage + (start * BDRV_SECTOR_SIZE),
+                                        nb_sectors * BDRV_SECTOR_SIZE);
+    bdrv_aio_writev(s->bdrv, start, &iov, nb_sectors, bdrv_sync_complete, NULL);
+}
+
+static void flash_erase(Flash *s, int offset, FlashCMD cmd)
+{
+    uint32_t len;
+    uint8_t capa_to_assert = 0;
+
+    switch (cmd) {
+    case ERASE_4K:
+        len = 4 << 10;
+        capa_to_assert = ER_4K;
+        break;
+    case ERASE_32K:
+        len = 32 << 10;
+        capa_to_assert = ER_32K;
+        break;
+    case ERASE_SECTOR:
+        len = s->pi->sector_size;
+        break;
+    case BULK_ERASE:
+        len = s->size;
+    default:
+        assert(false);
+    }
+
+    DB_PRINT("offset = %#x, len = %d\n", offset, len);
+    if ((s->pi->flags & capa_to_assert) != capa_to_assert) {
+        hw_error("m25p80: %dk erase size not supported by device\n", len);
+    }
+
+    if (!s->write_enable) {
+        DB_PRINT("erase with write protect!\n");
+        return;
+    }
+    memset(s->storage + offset, 0xff, len);
+    flash_sync_area(s, offset, len);
+}
+
+static inline void flash_sync_dirty(Flash *s, int64_t newpage)
+{
+    if (s->dirty_page >= 0 && s->dirty_page != newpage) {
+        flash_sync_page(s, s->dirty_page);
+        s->dirty_page = newpage;
+    }
+}
+
+static inline
+void flash_write8(Flash *s, uint64_t addr, uint8_t data)
+{
+    int64_t page = addr / s->pi->page_size;
+    uint8_t prev = s->storage[s->waddr];
+
+    if (!s->write_enable) {
+        DB_PRINT("write with write protect!\n");
+    }
+
+    if ((prev ^ data) & data) {
+        DB_PRINT("programming zero to one! addr=%lx  %x -> %x\n",
+                  addr, prev, data);
+    }
+    s->storage[s->waddr] ^= ~data & s->storage[s->waddr];
+
+    flash_sync_dirty(s, page);
+    s->dirty_page = page;
+}
+
+static void complete_collecting_data(Flash *s)
+{
+    s->waddr = s->data[0] << 16;
+    s->waddr |= s->data[1] << 8;
+    s->waddr |= s->data[2];
+
+    switch (s->cmd_in_progress) {
+    case PP:
+        s->state = STATE_PAGE_PROGRAM;
+        break;
+    case READ:
+    case FAST_READ:
+        s->state = STATE_READ;
+        break;
+    case ERASE_4K:
+    case ERASE_32K:
+    case ERASE_SECTOR:
+        flash_erase(s, s->waddr, s->cmd_in_progress);
+        break;
+    default:
+        break;
+    }
+}
+
+static void decode_new_cmd(Flash *s, uint32_t value)
+{
+    s->cmd_in_progress = value;
+    DB_PRINT("decoded new command:%d\n", value);
+
+    switch (value) {
+
+    case ERASE_4K:
+    case ERASE_32K:
+    case ERASE_SECTOR:
+    case READ:
+    case PP:
+        s->needed_bytes = 3;
+        s->pos = 0;
+        s->len = 0;
+        s->state = STATE_COLLECTING_DATA;
+        break;
+
+    case FAST_READ:
+        s->needed_bytes = 4;
+        s->pos = 0;
+        s->len = 0;
+        s->state = STATE_COLLECTING_DATA;
+        break;
+
+    case WRDI:
+        s->write_enable = 0;
+        break;
+    case WREN:
+        s->write_enable = 1;
+        break;
+
+    case RDSR:
+        s->data[0] = (!!s->write_enable) << 1;
+        s->pos = 0;
+        s->len = 1;;
+        s->state = STATE_READING_DATA;
+        break;
+
+    case JEDEC_READ:
+        DB_PRINT("populated jedec code\n");
+        s->data[0] = (s->pi->jedec >> 16) & 0xff;
+        s->data[1] = (s->pi->jedec >> 8) & 0xff;
+        s->data[2] = s->pi->jedec & 0xff;
+        if (s->pi->ext_jedec) {
+            s->data[3] = (s->pi->ext_jedec >> 8) & 0xff;
+            s->data[4] = s->pi->ext_jedec & 0xff;
+            s->len = 5;
+        } else {
+            s->len = 3;
+        }
+        s->pos = 0;
+        s->state = STATE_READING_DATA;
+        break;
+
+    case BULK_ERASE:
+        if (s->write_enable) {
+            DB_PRINT("chip erase\n");
+            flash_erase(s, 0, BULK_ERASE);
+        } else {
+            DB_PRINT("chip erase with write protect!\n");
+        }
+        break;
+    case NOP:
+        break;
+    default:
+        DB_PRINT("Unknown cmd %x\n", value);
+        break;
+    }
+}
+
+static int m25p80_cs(SSISlave *ss, int select)
+{
+    Flash *s = FROM_SSI_SLAVE(Flash, ss);
+
+    if (!select) {
+        s->len = 0;
+        s->pos = 0;
+        s->state = STATE_IDLE;
+        flash_sync_dirty(s, -1);
+        DB_PRINT("deselect\n");
+    }
+
+    return 0;
+}
+
+static uint32_t m25p80_transfer8(SSISlave *ss, uint32_t tx)
+{
+    Flash *s = FROM_SSI_SLAVE(Flash, ss);
+    uint32_t r = 0;
+
+    switch (s->state) {
+
+    case STATE_PAGE_PROGRAM:
+        DB_PRINT("page program waddr=%lx data=%x\n", s->waddr, (uint8_t)tx);
+        flash_write8(s, s->waddr, (uint8_t)tx);
+        s->waddr++;
+        break;
+
+    case STATE_READ:
+        r = s->storage[s->waddr];
+        DB_PRINT("READ 0x%lx=%x\n", s->waddr, r);
+        s->waddr = (s->waddr + 1) % s->size;
+        break;
+
+    case STATE_COLLECTING_DATA:
+        s->data[s->len] = (uint8_t)tx;
+        s->len++;
+
+        if (s->len == s->needed_bytes) {
+            complete_collecting_data(s);
+        }
+        break;
+
+    case STATE_READING_DATA:
+        r = s->data[s->pos];
+        s->pos++;
+        if (s->pos == s->len) {
+            s->pos = 0;
+            s->state = STATE_IDLE;
+        }
+        break;
+
+    default:
+    case STATE_IDLE:
+        decode_new_cmd(s, (uint8_t)tx);
+        break;
+    }
+
+    return r;
+}
+
+static int m25p80_init(SSISlave *ss)
+{
+    DriveInfo *dinfo;
+    Flash *s = FROM_SSI_SLAVE(Flash, ss);
+    const FlashPartInfo *i;
+
+    dinfo = drive_get_next(IF_MTD);
+
+    if (!s->part_name) { /* default to actual m25p80 if no partname given */
+        s->part_name = (char *)"m25p80";
+    }
+
+    i = known_devices;
+    for (i = known_devices;; i++) {
+        assert(i);
+        if (!i->part_name) {
+            fprintf(stderr, "Unknown SPI flash part: \"%s\"\n", s->part_name);
+            return 1;
+        } else if (!strcmp(i->part_name, s->part_name)) {
+            s->pi = i;
+            break;
+        }
+    }
+
+    s->size = s->pi->sector_size * s->pi->n_sectors;
+    s->dirty_page = -1;
+    s->storage = qemu_blockalign(s->bdrv, s->size);
+
+    if (dinfo && dinfo->bdrv) {
+        int rsize;
+
+        s->bdrv = dinfo->bdrv;
+        rsize = MIN(bdrv_getlength(s->bdrv), s->size);
+        if (bdrv_read(s->bdrv, 0, s->storage, DIV_ROUND_UP(s->size,
+                                                    BDRV_SECTOR_SIZE))) {
+            fprintf(stderr, "Failed to initialize SPI flash!\n");
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+static Property m25p80_properties[] = {
+    DEFINE_PROP_STRING("partname", Flash, part_name),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void m25p80_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+    k->init = m25p80_init;
+    k->transfer = m25p80_transfer8;
+    k->set_cs = m25p80_cs;
+    dc->props = m25p80_properties;
+}
+
+static TypeInfo m25p80_info = {
+    .name           = "m25p80",
+    .parent         = TYPE_SSI_SLAVE,
+    .instance_size  = sizeof(Flash),
+    .class_init     = m25p80_class_init,
+};
+
+static void m25p80_register_types(void)
+{
+    type_register_static(&m25p80_info);
+}
+
+type_init(m25p80_register_types)
-- 
1.7.3.2

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [Qemu-devel] [PATCH V4 3/5] xilinx_spi: initial version
  2012-06-04  8:08 [Qemu-devel] [PATCH V4 0/5] Ehnahced SSI bus support + M25P80 SPI flash + Xilinx SPI controller Peter A. G. Crosthwaite
  2012-06-04  8:08 ` [Qemu-devel] [PATCH V4 1/5] SSI: Built in multiple device support Peter A. G. Crosthwaite
  2012-06-04  8:08 ` [Qemu-devel] [PATCH V4 2/5] m25p80: initial verion Peter A. G. Crosthwaite
@ 2012-06-04  8:08 ` Peter A. G. Crosthwaite
  2012-06-04  8:08 ` [Qemu-devel] [PATCH V4 4/5] petalogix-ml605: added spi controller with m25p80 Peter A. G. Crosthwaite
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 12+ messages in thread
From: Peter A. G. Crosthwaite @ 2012-06-04  8:08 UTC (permalink / raw)
  To: qemu-devel, paul, edgar.iglesias, peter.maydell, stefanha
  Cc: peter.crosthwaite, john.williams

device model for xilinx XPS SPI controller (v2.0)

Signed-off-by: Peter A. G. Crosthwaite <peter.crosthwaite@petalogix.com>
---
changed from v3:
typedef'd struct XilinxSPI
changed unsigned int -> uin32_t
removed unused vars (c_fifo_exist and cmd_ongoing)
txfifo_reset removed duplicate s->regs[R_SPISR] &= ~SR_TX_FULL (PMM review)
reset: changed to Device Class style reset
reset: stope the ptimer (pmm review)
xlx_spi_update_irq: dont -> don't (PMM review)
init: set irq_line to 1 (force refresh on vmsd load)
init: dropped call to reset
implemetned vmsd
changed from v2:
converted spi api to ssi api
changed from v1:
converted spi api to modified txrx style
 Makefile.target |    1 +
 hw/xilinx_spi.c |  481 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 482 insertions(+), 0 deletions(-)
 create mode 100644 hw/xilinx_spi.c

diff --git a/Makefile.target b/Makefile.target
index 77feb83..4471317 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -293,6 +293,7 @@ obj-microblaze-y = petalogix_s3adsp1800_mmu.o
 obj-microblaze-y += petalogix_ml605_mmu.o
 obj-microblaze-y += microblaze_boot.o
 obj-microblaze-y += m25p80.o
+obj-microblaze-y += xilinx_spi.o
 
 obj-microblaze-y += microblaze_pic_cpu.o
 obj-microblaze-y += xilinx_intc.o
diff --git a/hw/xilinx_spi.c b/hw/xilinx_spi.c
new file mode 100644
index 0000000..cae88ad
--- /dev/null
+++ b/hw/xilinx_spi.c
@@ -0,0 +1,481 @@
+/*
+ * QEMU model of the Xilinx SPI Controller
+ *
+ * Copyright (C) 2010 Edgar E. Iglesias.
+ * Copyright (C) 2012 Peter A. G. Crosthwaite <peter.crosthwaite@petalogix.com>
+ * Copyright (C) 2012 PetaLogix
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "sysbus.h"
+#include "sysemu.h"
+#include "ptimer.h"
+#include "qemu-log.h"
+
+#include "ssi.h"
+
+#ifdef XILINX_SPI_ERR_DEBUG
+#define DB_PRINT(...) do { \
+    fprintf(stderr,  ": %s: ", __func__); \
+    fprintf(stderr, ## __VA_ARGS__); \
+    } while (0);
+#else
+    #define DB_PRINT(...)
+#endif
+
+#define R_DGIER     (0x1c / 4)
+#define R_DGIER_IE  (1 << 31)
+
+#define R_IPISR     (0x20 / 4)
+#define IRQ_DRR_NOT_EMPTY    (1 << (31 - 23))
+#define IRQ_DRR_OVERRUN      (1 << (31 - 26))
+#define IRQ_DRR_FULL         (1 << (31 - 27))
+#define IRQ_TX_FF_HALF_EMPTY (1 << 6)
+#define IRQ_DTR_UNDERRUN     (1 << 3)
+#define IRQ_DTR_EMPTY        (1 << (31 - 29))
+
+#define R_IPIER     (0x28 / 4)
+#define R_SRR       (0x40 / 4)
+#define R_SPICR     (0x60 / 4)
+#define R_SPICR_TXFF_RST     (1 << 5)
+#define R_SPICR_RXFF_RST     (1 << 6)
+#define R_SPICR_MTI          (1 << 8)
+
+#define R_SPISR     (0x64 / 4)
+#define SR_TX_FULL    (1 << 3)
+#define SR_TX_EMPTY   (1 << 2)
+#define SR_RX_FULL    (1 << 1)
+#define SR_RX_EMPTY   (1 << 0)
+
+
+#define R_SPIDTR    (0x68 / 4)
+#define R_SPIDRR    (0x6C / 4)
+#define R_SPISSR    (0x70 / 4)
+#define R_TX_FF_OCY (0x74 / 4)
+#define R_RX_FF_OCY (0x78 / 4)
+#define R_MAX       (0x7C / 4)
+
+typedef struct XilinxSPI {
+    SysBusDevice busdev;
+    MemoryRegion mmio;
+    qemu_irq irq;
+    int irqline;
+
+    QEMUBH *bh;
+    ptimer_state *ptimer;
+
+    SSIBus *spi;
+
+    uint8_t rx_fifo[256];
+    uint32_t rx_fifo_pos;
+    uint32_t rx_fifo_len;
+
+    uint8_t tx_fifo[256];
+    uint32_t tx_fifo_pos;
+    uint32_t tx_fifo_len;
+
+    /* Slave select.  */
+    uint8_t num_cs;
+
+    uint32_t regs[R_MAX];
+} XilinxSPI;
+
+static void txfifo_reset(XilinxSPI *s)
+{
+    s->tx_fifo_pos = 0;
+    s->tx_fifo_len = 0;
+
+    s->regs[R_SPISR] &= ~SR_TX_FULL;
+    s->regs[R_SPISR] |= SR_TX_EMPTY;
+    s->regs[R_IPISR] |= IRQ_DTR_EMPTY;
+}
+
+static void rxfifo_reset(XilinxSPI *s)
+{
+    s->rx_fifo_pos = 0;
+    s->rx_fifo_len = 0;
+
+    s->regs[R_SPISR] |= SR_RX_EMPTY;
+    s->regs[R_SPISR] &= ~SR_RX_FULL;
+    s->regs[R_IPISR] &= ~IRQ_DRR_NOT_EMPTY;
+    s->regs[R_IPISR] &= ~IRQ_DRR_OVERRUN;
+}
+
+static void xlx_spi_do_reset(XilinxSPI *s)
+{
+    memset(s->regs, 0, sizeof s->regs);
+
+    rxfifo_reset(s);
+    txfifo_reset(s);
+
+    s->regs[R_SPISSR] = 1;
+    ptimer_stop(s->ptimer);
+    ssi_select_slave(s->spi, 0);
+}
+
+static void xlx_spi_reset(DeviceState *d)
+{
+    xlx_spi_do_reset(DO_UPCAST(XilinxSPI, busdev.qdev, d));
+}
+
+static void xlx_spi_update_irq(XilinxSPI *s)
+{
+    uint32_t pending;
+    pending = s->regs[R_IPISR] & s->regs[R_IPIER];
+
+    pending = pending && (s->regs[R_DGIER] & R_DGIER_IE);
+    pending = !!pending;
+
+    /* This call lies right in the data paths so don't call the
+       irq chain unless things really changed.  */
+    if (pending != s->irqline) {
+        s->irqline = pending;
+        DB_PRINT("irq_change_of of state %d\n", pending);
+        qemu_set_irq(s->irq, pending);
+    }
+}
+
+static inline int spi_master_enabled(XilinxSPI *s)
+{
+    return !(s->regs[R_SPICR] & R_SPICR_MTI);
+}
+
+static int spi_slave_select(XilinxSPI *s, uint32_t v)
+{
+    unsigned int ss;
+
+    ss = ffs(v) - 1;
+    return ss < s->num_cs ? ss : SSI_SLAVE_SELECT_NONE;
+}
+
+static inline int txfifo_empty(XilinxSPI *s)
+{
+    return s->tx_fifo_len == 0;
+}
+
+static inline int txfifo_full(XilinxSPI *s)
+{
+    return s->tx_fifo_len >= ARRAY_SIZE(s->tx_fifo);
+}
+
+static inline int rxfifo_empty(XilinxSPI *s)
+{
+    return s->rx_fifo_len == 0;
+}
+
+static inline int rxfifo_full(XilinxSPI *s)
+{
+    return s->rx_fifo_len >= ARRAY_SIZE(s->rx_fifo);
+}
+
+static inline void txfifo_put(XilinxSPI *s, uint8_t v)
+{
+    s->regs[R_SPISR] &= ~SR_TX_EMPTY;
+    s->regs[R_IPISR] &= ~IRQ_DTR_EMPTY;
+
+    s->tx_fifo[s->tx_fifo_pos] = v;
+    s->tx_fifo_pos++;
+    s->tx_fifo_pos &= ARRAY_SIZE(s->tx_fifo) - 1;
+    s->tx_fifo_len++;
+
+    s->regs[R_SPISR] &= ~SR_TX_FULL;
+    if (txfifo_full(s)) {
+        s->regs[R_SPISR] |= SR_TX_FULL;
+    }
+}
+
+static inline uint8_t txfifo_get(XilinxSPI *s)
+{
+    uint8_t r = 0;
+    assert(s->tx_fifo_len);
+
+    r = s->tx_fifo[(s->tx_fifo_pos - s->tx_fifo_len) &
+                                (ARRAY_SIZE(s->tx_fifo) - 1)];
+    s->tx_fifo_len--;
+
+    s->regs[R_SPISR] &= ~SR_TX_FULL;
+    if (txfifo_empty(s)) {
+        s->regs[R_SPISR] |= SR_TX_EMPTY;
+        s->regs[R_IPISR] |= IRQ_DTR_EMPTY;
+    }
+
+    return r;
+}
+
+static inline void rxfifo_put(XilinxSPI *s, uint8_t v)
+{
+    DB_PRINT("%x\n", v);
+    s->regs[R_SPISR] &= ~SR_RX_EMPTY;
+    s->regs[R_IPISR] |= IRQ_DRR_NOT_EMPTY;
+
+    s->rx_fifo[s->rx_fifo_pos] = v;
+    s->rx_fifo_pos++;
+    s->rx_fifo_pos &= ARRAY_SIZE(s->rx_fifo) - 1;
+    s->rx_fifo_len++;
+
+    s->regs[R_SPISR] &= ~SR_RX_FULL;
+    if (s->rx_fifo_len >= ARRAY_SIZE(s->rx_fifo)) {
+        s->regs[R_SPISR] |= SR_RX_FULL;
+        s->regs[R_IPISR] |= IRQ_DRR_OVERRUN;
+    }
+}
+
+static inline uint32_t rxfifo_get(XilinxSPI *s)
+{
+    uint32_t r = 0;
+    assert(s->rx_fifo_len);
+
+    r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) &
+                            (ARRAY_SIZE(s->rx_fifo) - 1)];
+    s->rx_fifo_len--;
+
+    s->regs[R_SPISR] &= ~SR_RX_FULL;
+    if (rxfifo_empty(s)) {
+        s->regs[R_SPISR] |= SR_RX_EMPTY;
+        s->regs[R_IPISR] &= ~IRQ_DRR_NOT_EMPTY;
+    }
+
+    return r;
+}
+
+static void spi_timer_run(XilinxSPI *s, int delay)
+{
+    ptimer_set_count(s->ptimer, delay);
+    ptimer_run(s->ptimer, 1);
+}
+
+static void
+spi_flush_txfifo(XilinxSPI *s)
+{
+    uint32_t tx;
+    uint32_t rx;
+
+    while (!txfifo_empty(s)) {
+        tx = (uint32_t)txfifo_get(s);
+        DB_PRINT("data transfer:%x\n", tx);
+        rx = ssi_transfer(s->spi, (uint32_t)tx);
+        rxfifo_put(s, rx);
+    }
+}
+
+static uint64_t
+spi_read(void *opaque, target_phys_addr_t addr, unsigned int size)
+{
+    XilinxSPI *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_SPIDRR:
+        if (rxfifo_empty(s)) {
+            DB_PRINT("Read from empty FIFO!\n");
+            return 0xdeadbeef;
+        }
+
+        r = rxfifo_get(s);
+        break;
+
+    case R_SPISR:
+        r = s->regs[addr];
+        if (rxfifo_empty(s)) {
+            spi_timer_run(s, 1);
+        }
+        break;
+
+    default:
+        if (addr < ARRAY_SIZE(s->regs)) {
+            r = s->regs[addr];
+        }
+        break;
+
+    }
+    DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr * 4, r);
+    xlx_spi_update_irq(s);
+    return r;
+}
+
+static void
+spi_write(void *opaque, target_phys_addr_t addr,
+            uint64_t val64, unsigned int size)
+{
+    XilinxSPI *s = opaque;
+    uint32_t value = val64;
+
+    DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr, value);
+    addr >>= 2;
+    switch (addr) {
+    case R_SRR:
+        if (value != 0xa) {
+            DB_PRINT("Invalid write to SRR %x\n", value);
+        } else {
+            xlx_spi_do_reset(s);
+        }
+        break;
+
+    case R_SPIDTR:
+        txfifo_put(s, value);
+
+        if (!spi_master_enabled(s)) {
+            goto done;
+        } else {
+            DB_PRINT("DTR and master enabled?\n");
+        }
+        spi_flush_txfifo(s);
+        break;
+
+    case R_SPISR:
+        DB_PRINT("Invalid write to SPISR %x\n", value);
+        break;
+
+    case R_IPISR:
+        /* Toggle the bits.  */
+        s->regs[addr] ^= value;
+        break;
+
+    /* Slave Select Register.  */
+    case R_SPISSR:
+        ssi_select_slave(s->spi, spi_slave_select(s, ~value));
+        s->regs[addr] = value;
+        break;
+
+    case R_SPICR:
+        /* FIXME: reset irq and sr state to empty queues.  */
+        if (value & R_SPICR_RXFF_RST) {
+            rxfifo_reset(s);
+        }
+
+        if (value & R_SPICR_TXFF_RST) {
+            txfifo_reset(s);
+        }
+        value &= ~(R_SPICR_RXFF_RST | R_SPICR_TXFF_RST);
+        s->regs[addr] = value;
+
+        if (!(value & R_SPICR_MTI)) {
+            /* When releasing the master disable, initiate a timer
+               that eventually will flush the txfifo.  */
+            spi_timer_run(s, 1);
+        }
+        break;
+
+    default:
+        if (addr < ARRAY_SIZE(s->regs)) {
+            s->regs[addr] = value;
+        }
+        break;
+    }
+
+done:
+    xlx_spi_update_irq(s);
+}
+
+static const MemoryRegionOps spi_ops = {
+    .read = spi_read,
+    .write = spi_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
+};
+
+static void timer_hit(void *opaque)
+{
+    XilinxSPI *s = opaque;
+
+    if (!txfifo_empty(s)) {
+        spi_flush_txfifo(s);
+    }
+    xlx_spi_update_irq(s);
+}
+
+static int xilinx_spi_init(SysBusDevice *dev)
+{
+    XilinxSPI *s = FROM_SYSBUS(typeof(*s), dev);
+
+    DB_PRINT("\n");
+    sysbus_init_irq(dev, &s->irq);
+
+    memory_region_init_io(&s->mmio, &spi_ops, s, "xilinx-spi", R_MAX * 4);
+    sysbus_init_mmio(dev, &s->mmio);
+
+    s->bh = qemu_bh_new(timer_hit, s);
+    s->ptimer = ptimer_init(s->bh);
+    s->irqline = -1;
+    ptimer_set_freq(s->ptimer, 10 * 1000 * 1000);
+
+    s->spi = ssi_create_bus(&dev->qdev, "spi");
+
+    return 0;
+}
+
+static int xilinx_spi_post_load(void *opaque, int version_id)
+{
+    xlx_spi_update_irq((XilinxSPI *)opaque);
+    return 0;
+}
+
+static const VMStateDescription vmstate_xilinx_spi = {
+    .name = "xilinx_spi",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = xilinx_spi_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_PTIMER(ptimer, XilinxSPI),
+        VMSTATE_UINT8_ARRAY(rx_fifo, XilinxSPI, 256),
+        VMSTATE_UINT32(rx_fifo_pos, XilinxSPI),
+        VMSTATE_UINT32(rx_fifo_len, XilinxSPI),
+        VMSTATE_UINT8_ARRAY(tx_fifo, XilinxSPI, 256),
+        VMSTATE_UINT32(tx_fifo_pos, XilinxSPI),
+        VMSTATE_UINT32(tx_fifo_len, XilinxSPI),
+        VMSTATE_UINT32_ARRAY(regs, XilinxSPI, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property xilinx_spi_properties[] = {
+    DEFINE_PROP_UINT8("num-cs", XilinxSPI, num_cs, 1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xilinx_spi_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = xilinx_spi_init;
+    dc->reset = xlx_spi_reset;
+    dc->props = xilinx_spi_properties;
+    dc->vmsd = &vmstate_xilinx_spi;
+}
+
+static TypeInfo xilinx_spi_info = {
+    .name           = "xilinx,spi",
+    .parent         = TYPE_SYS_BUS_DEVICE,
+    .instance_size  = sizeof(XilinxSPI),
+    .class_init     = xilinx_spi_class_init,
+};
+
+static void xilinx_spi_register_types(void)
+{
+    type_register_static(&xilinx_spi_info);
+}
+
+type_init(xilinx_spi_register_types)
-- 
1.7.3.2

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [Qemu-devel] [PATCH V4 4/5] petalogix-ml605: added spi controller with m25p80
  2012-06-04  8:08 [Qemu-devel] [PATCH V4 0/5] Ehnahced SSI bus support + M25P80 SPI flash + Xilinx SPI controller Peter A. G. Crosthwaite
                   ` (2 preceding siblings ...)
  2012-06-04  8:08 ` [Qemu-devel] [PATCH V4 3/5] xilinx_spi: initial version Peter A. G. Crosthwaite
@ 2012-06-04  8:08 ` Peter A. G. Crosthwaite
  2012-06-04  8:08 ` [Qemu-devel] [PATCH V4 5/5] stellaris: Updated spi bus implementation Peter A. G. Crosthwaite
  2012-06-05  1:34 ` [Qemu-devel] [PATCH V4 0/5] Ehnahced SSI bus support + M25P80 SPI flash + Xilinx SPI controller Paul Brook
  5 siblings, 0 replies; 12+ messages in thread
From: Peter A. G. Crosthwaite @ 2012-06-04  8:08 UTC (permalink / raw)
  To: qemu-devel, paul, edgar.iglesias, peter.maydell, stefanha
  Cc: peter.crosthwaite, john.williams

Added spi controller to the reference design, with a single cs line and a
m25p80 style spi-flash connected

Signed-off-by: Peter A. G. Crosthwaite <peter.crosthwaite@petalogix.com>
---
changed from v3:
set spi flashes as being fl06k
changed from v2:
changed spi -> ssi
added two spi flashes to machine model instead of one

 default-configs/microblaze-softmmu.mak   |    1 +
 default-configs/microblazeel-softmmu.mak |    1 +
 hw/petalogix_ml605_mmu.c                 |   23 +++++++++++++++++++++++
 3 files changed, 25 insertions(+), 0 deletions(-)

diff --git a/default-configs/microblaze-softmmu.mak b/default-configs/microblaze-softmmu.mak
index 613edab..e9f2a29 100644
--- a/default-configs/microblaze-softmmu.mak
+++ b/default-configs/microblaze-softmmu.mak
@@ -3,3 +3,4 @@
 CONFIG_PTIMER=y
 CONFIG_PFLASH_CFI01=y
 CONFIG_SERIAL=y
+CONFIG_SSI=y
diff --git a/default-configs/microblazeel-softmmu.mak b/default-configs/microblazeel-softmmu.mak
index 4b40fb2..00c1a87 100644
--- a/default-configs/microblazeel-softmmu.mak
+++ b/default-configs/microblazeel-softmmu.mak
@@ -3,3 +3,4 @@
 CONFIG_PTIMER=y
 CONFIG_PFLASH_CFI01=y
 CONFIG_SERIAL=y
+CONFIG_SSI=y
diff --git a/hw/petalogix_ml605_mmu.c b/hw/petalogix_ml605_mmu.c
index 31a4348..01af0da 100644
--- a/hw/petalogix_ml605_mmu.c
+++ b/hw/petalogix_ml605_mmu.c
@@ -36,6 +36,7 @@
 #include "blockdev.h"
 #include "pc.h"
 #include "exec-memory.h"
+#include "ssi.h"
 
 #include "microblaze_boot.h"
 #include "microblaze_pic_cpu.h"
@@ -54,6 +55,8 @@
 #define AXIENET_BASEADDR 0x82780000
 #define AXIDMA_BASEADDR 0x84600000
 
+#define NUM_SPI_FLASHES 2
+
 static void machine_cpu_reset(CPUMBState *env)
 {
     env->pvr.regs[10] = 0x0e000000; /* virtex 6 */
@@ -75,6 +78,7 @@ petalogix_ml605_init(ram_addr_t ram_size,
 {
     MemoryRegion *address_space_mem = get_system_memory();
     DeviceState *dev;
+    SysBusDevice *busdev;
     CPUMBState *env;
     DriveInfo *dinfo;
     int i;
@@ -131,6 +135,25 @@ petalogix_ml605_init(ram_addr_t ram_size,
                                      irq[1], irq[0], 100 * 1000000);
     }
 
+    {
+        void *spi;
+
+        dev = qdev_create(NULL, "xilinx,spi");
+        qdev_prop_set_uint8(dev, "num-cs", NUM_SPI_FLASHES);
+        qdev_init_nofail(dev);
+        busdev = sysbus_from_qdev(dev);
+        sysbus_mmio_map(busdev, 0, 0x40a00000);
+        sysbus_connect_irq(busdev, 0, irq[4]);
+
+        spi = qdev_get_child_bus(dev, "spi");
+
+        for (i = 0; i < NUM_SPI_FLASHES; i++) {
+            dev = ssi_create_slave_no_init(spi, "m25p80", i);
+            qdev_prop_set_string(dev, "partname", (char *)"s25fl064k");
+            qdev_init_nofail(dev);
+        }
+    }
+
     microblaze_load_kernel(env, ddr_base, ram_size, BINARY_DEVICE_TREE_FILE,
                                                             machine_cpu_reset);
 
-- 
1.7.3.2

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [Qemu-devel] [PATCH V4 5/5] stellaris: Updated spi bus implementation
  2012-06-04  8:08 [Qemu-devel] [PATCH V4 0/5] Ehnahced SSI bus support + M25P80 SPI flash + Xilinx SPI controller Peter A. G. Crosthwaite
                   ` (3 preceding siblings ...)
  2012-06-04  8:08 ` [Qemu-devel] [PATCH V4 4/5] petalogix-ml605: added spi controller with m25p80 Peter A. G. Crosthwaite
@ 2012-06-04  8:08 ` Peter A. G. Crosthwaite
  2012-06-04  8:14   ` Peter Crosthwaite
  2012-06-05  1:34 ` [Qemu-devel] [PATCH V4 0/5] Ehnahced SSI bus support + M25P80 SPI flash + Xilinx SPI controller Paul Brook
  5 siblings, 1 reply; 12+ messages in thread
From: Peter A. G. Crosthwaite @ 2012-06-04  8:08 UTC (permalink / raw)
  To: qemu-devel, paul, edgar.iglesias, peter.maydell, stefanha
  Cc: peter.crosthwaite, john.williams

Setup the stellaris_ssi_bus device to use a single multi-slave ssi bus instead
of two busses.

Signed-off-by: Peter A. G. Crosthwaite <peter.crosthwaite@petalogix.com>
---
changed from v3:
This patch is new

 hw/stellaris.c |   17 +++++++----------
 1 files changed, 7 insertions(+), 10 deletions(-)

diff --git a/hw/stellaris.c b/hw/stellaris.c
index e0600a1..07a4187 100644
--- a/hw/stellaris.c
+++ b/hw/stellaris.c
@@ -1164,22 +1164,21 @@ static int stellaris_adc_init(SysBusDevice *dev)
 typedef struct {
     SSISlave ssidev;
     qemu_irq irq;
-    int current_dev;
-    SSIBus *bus[2];
+    SSIBus *bus;
 } stellaris_ssi_bus_state;
 
 static void stellaris_ssi_bus_select(void *opaque, int irq, int level)
 {
     stellaris_ssi_bus_state *s = (stellaris_ssi_bus_state *)opaque;
 
-    s->current_dev = level;
+    ssi_select_slave(s->bus, (uint32_t)level);
 }
 
 static uint32_t stellaris_ssi_bus_transfer(SSISlave *dev, uint32_t val)
 {
     stellaris_ssi_bus_state *s = FROM_SSI_SLAVE(stellaris_ssi_bus_state, dev);
 
-    return ssi_transfer(s->bus[s->current_dev], val);
+    return ssi_transfer(s->bus, val);
 }
 
 static const VMStateDescription vmstate_stellaris_ssi_bus = {
@@ -1188,7 +1187,6 @@ static const VMStateDescription vmstate_stellaris_ssi_bus = {
     .minimum_version_id = 1,
     .minimum_version_id_old = 1,
     .fields      = (VMStateField[]) {
-        VMSTATE_INT32(current_dev, stellaris_ssi_bus_state),
         VMSTATE_END_OF_LIST()
     }
 };
@@ -1197,8 +1195,7 @@ static int stellaris_ssi_bus_init(SSISlave *dev)
 {
     stellaris_ssi_bus_state *s = FROM_SSI_SLAVE(stellaris_ssi_bus_state, dev);
 
-    s->bus[0] = ssi_create_bus(&dev->qdev, "ssi0");
-    s->bus[1] = ssi_create_bus(&dev->qdev, "ssi1");
+    s->bus = ssi_create_bus(&dev->qdev, "ssi");
     qdev_init_gpio_in(&dev->qdev, stellaris_ssi_bus_select, 1);
 
     vmstate_register(&dev->qdev, -1, &vmstate_stellaris_ssi_bus, s);
@@ -1312,11 +1309,11 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model,
             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");
+            bus = qdev_get_child_bus(mux, "ssi");
+
             ssi_create_slave(bus, "ssi-sd", 0);
 
-            bus = qdev_get_child_bus(mux, "ssi1");
-            dev = ssi_create_slave(bus, "ssd0323", 0);
+            dev = ssi_create_slave(bus, "ssd0323", 1);
             gpio_out[GPIO_C][7] = qdev_get_gpio_in(dev, 0);
 
             /* Make sure the select pin is high.  */
-- 
1.7.3.2

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [Qemu-devel] [PATCH V4 5/5] stellaris: Updated spi bus implementation
  2012-06-04  8:08 ` [Qemu-devel] [PATCH V4 5/5] stellaris: Updated spi bus implementation Peter A. G. Crosthwaite
@ 2012-06-04  8:14   ` Peter Crosthwaite
  0 siblings, 0 replies; 12+ messages in thread
From: Peter Crosthwaite @ 2012-06-04  8:14 UTC (permalink / raw)
  To: qemu-devel, paul, edgar.iglesias, peter.maydell, stefanha

Regression tested using Paul Brooks test vector:

peterc@PetaLogix-ws2:~/Petalogix/Internal/plgx_install/qemu-upstream-regression/third-party/stellaris-test$
qemu-system-arm -M lm3s6965evb -serial stdio -kernel sd_card.bin -sd
sdcard.img
VNC server running on `127.0.0.1:5900'


SD Card Example Program
Type 'help' for help.

/> ls
Open
SD: Unknown CMD8
listing

----A 2012/04/25 17:44        12  README.TXT

   1 File(s),        12 bytes total
   0 Dir(s),      61182K bytes free

/> cat README.TXT
Hello World

Gui based test works as well.

On Mon, Jun 4, 2012 at 6:08 PM, Peter A. G. Crosthwaite
<peter.crosthwaite@petalogix.com> wrote:
> Setup the stellaris_ssi_bus device to use a single multi-slave ssi bus instead
> of two busses.
>
> Signed-off-by: Peter A. G. Crosthwaite <peter.crosthwaite@petalogix.com>
> ---
> changed from v3:
> This patch is new
>
>  hw/stellaris.c |   17 +++++++----------
>  1 files changed, 7 insertions(+), 10 deletions(-)
>
> diff --git a/hw/stellaris.c b/hw/stellaris.c
> index e0600a1..07a4187 100644
> --- a/hw/stellaris.c
> +++ b/hw/stellaris.c
> @@ -1164,22 +1164,21 @@ static int stellaris_adc_init(SysBusDevice *dev)
>  typedef struct {
>     SSISlave ssidev;
>     qemu_irq irq;

Just curiously, AFAICT, this irq is completely dead. Paul can it be
removed in a trivial patch or is there some GPIO related black magic
occurring here?

> -    int current_dev;
> -    SSIBus *bus[2];
> +    SSIBus *bus;
>  } stellaris_ssi_bus_state;
>
>  static void stellaris_ssi_bus_select(void *opaque, int irq, int level)
>  {
>     stellaris_ssi_bus_state *s = (stellaris_ssi_bus_state *)opaque;
>
> -    s->current_dev = level;
> +    ssi_select_slave(s->bus, (uint32_t)level);
>  }
>
>  static uint32_t stellaris_ssi_bus_transfer(SSISlave *dev, uint32_t val)
>  {
>     stellaris_ssi_bus_state *s = FROM_SSI_SLAVE(stellaris_ssi_bus_state, dev);
>
> -    return ssi_transfer(s->bus[s->current_dev], val);
> +    return ssi_transfer(s->bus, val);
>  }
>
>  static const VMStateDescription vmstate_stellaris_ssi_bus = {
> @@ -1188,7 +1187,6 @@ static const VMStateDescription vmstate_stellaris_ssi_bus = {
>     .minimum_version_id = 1,
>     .minimum_version_id_old = 1,
>     .fields      = (VMStateField[]) {
> -        VMSTATE_INT32(current_dev, stellaris_ssi_bus_state),
>         VMSTATE_END_OF_LIST()
>     }
>  };
> @@ -1197,8 +1195,7 @@ static int stellaris_ssi_bus_init(SSISlave *dev)
>  {
>     stellaris_ssi_bus_state *s = FROM_SSI_SLAVE(stellaris_ssi_bus_state, dev);
>
> -    s->bus[0] = ssi_create_bus(&dev->qdev, "ssi0");
> -    s->bus[1] = ssi_create_bus(&dev->qdev, "ssi1");
> +    s->bus = ssi_create_bus(&dev->qdev, "ssi");
>     qdev_init_gpio_in(&dev->qdev, stellaris_ssi_bus_select, 1);
>
>     vmstate_register(&dev->qdev, -1, &vmstate_stellaris_ssi_bus, s);
> @@ -1312,11 +1309,11 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model,
>             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");
> +            bus = qdev_get_child_bus(mux, "ssi");
> +
>             ssi_create_slave(bus, "ssi-sd", 0);
>
> -            bus = qdev_get_child_bus(mux, "ssi1");
> -            dev = ssi_create_slave(bus, "ssd0323", 0);
> +            dev = ssi_create_slave(bus, "ssd0323", 1);
>             gpio_out[GPIO_C][7] = qdev_get_gpio_in(dev, 0);
>
>             /* Make sure the select pin is high.  */
> --
> 1.7.3.2
>

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Qemu-devel] [PATCH V4 0/5] Ehnahced SSI bus support + M25P80 SPI flash + Xilinx SPI controller
  2012-06-04  8:08 [Qemu-devel] [PATCH V4 0/5] Ehnahced SSI bus support + M25P80 SPI flash + Xilinx SPI controller Peter A. G. Crosthwaite
                   ` (4 preceding siblings ...)
  2012-06-04  8:08 ` [Qemu-devel] [PATCH V4 5/5] stellaris: Updated spi bus implementation Peter A. G. Crosthwaite
@ 2012-06-05  1:34 ` Paul Brook
  2012-06-05  1:54   ` Peter Crosthwaite
  2012-06-05  2:51   ` John Williams
  5 siblings, 2 replies; 12+ messages in thread
From: Paul Brook @ 2012-06-05  1:34 UTC (permalink / raw)
  To: Peter A. G. Crosthwaite
  Cc: stefanha, edgar.iglesias, qemu-devel, john.williams,
	peter.maydell

> Patch 1 Enhances SSI bus support to properly support multiple attached
> devices. An api is provided for SSI/SPI masters to select a particular
> device attached to the bus.
> 
> Patch 2 is a device model for the m25p80 style SPI flash chip.
> 
> Patch 3 is  the Xilinx XPS SPI contoller. Its a sysbus device that
> instantiates a ssi bus, and interfaces the two (as per the controllers
> functionality)
> 
> Patch 4 instantiates the XPS SPI controller in the petalogix ML605
> reference platform and connects two m25p80s to it.
> 
> Patch 5 updates the stellaris machine model to use the multi slave SSI
> support

I'm still not convinced modelling this as a multipoint bus is a good idea.  If 
nothing else you've failed to model the case where multiple slaves are 
selected simultanously.  Given the chip selects are actual wires, not part of 
the bus itself, I think multiple point-point busses are a better fit.

For the stellaris device we still have the synthetic mux device and 
intermediate bus.


Paul

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Qemu-devel] [PATCH V4 0/5] Ehnahced SSI bus support + M25P80 SPI flash + Xilinx SPI controller
  2012-06-05  1:34 ` [Qemu-devel] [PATCH V4 0/5] Ehnahced SSI bus support + M25P80 SPI flash + Xilinx SPI controller Paul Brook
@ 2012-06-05  1:54   ` Peter Crosthwaite
  2012-06-06 13:37     ` Paul Brook
  2012-06-05  2:51   ` John Williams
  1 sibling, 1 reply; 12+ messages in thread
From: Peter Crosthwaite @ 2012-06-05  1:54 UTC (permalink / raw)
  To: Paul Brook
  Cc: stefanha, edgar.iglesias, qemu-devel, john.williams,
	peter.maydell

Hi Paul,

Responses inline below.

On Tue, Jun 5, 2012 at 11:34 AM, Paul Brook <paul@codesourcery.com> wrote:
>> Patch 1 Enhances SSI bus support to properly support multiple attached
>> devices. An api is provided for SSI/SPI masters to select a particular
>> device attached to the bus.
>>
>> Patch 2 is a device model for the m25p80 style SPI flash chip.
>>
>> Patch 3 is  the Xilinx XPS SPI contoller. Its a sysbus device that
>> instantiates a ssi bus, and interfaces the two (as per the controllers
>> functionality)
>>
>> Patch 4 instantiates the XPS SPI controller in the petalogix ML605
>> reference platform and connects two m25p80s to it.
>>
>> Patch 5 updates the stellaris machine model to use the multi slave SSI
>> support
>
> I'm still not convinced modelling this as a multipoint bus is a good idea.  If
> nothing else you've failed to model the case where multiple slaves are
> selected simultanously.

The bus can easily be changed such that multiple devices are
selectable at once to get your desired multi device behaviour. AFAICT
though nothing in QEMU behaves like this ATM.

  Given the chip selects are actual wires, not part of
> the bus itself, I think multiple point-point busses are a better fit.
>
> For the stellaris device we still have the synthetic mux device and
> intermediate bus.
>

Yes, because in your stellaris architecture, the SSI controller
(pl022) is point to point so that exactly matches the hardware.

In the microblaze controller in this series, the controller has
inbuilt muxing with one-hot CS behavior. To implement with point to
point, I would have to dynamically create a number of sub-busses
(driven by a qdev property). I would also have to have a device within
a device to model the internal mux which increases my code volume
significantly. Also you end up with this little piece of ugliness in
your machine model and device model:

diff --git a/hw/petalogix_ml605_mmu.c b/hw/petalogix_ml605_mmu.c
index 01af0da..394a80e 100644
--- a/hw/petalogix_ml605_mmu.c
+++ b/hw/petalogix_ml605_mmu.c
@@ -145,10 +145,11 @@ petalogix_ml605_init(ram_addr_t ram_size,
         sysbus_mmio_map(busdev, 0, 0x40a00000);
         sysbus_connect_irq(busdev, 0, irq[4]);

-        spi = qdev_get_child_bus(dev, "spi");

         for (i = 0; i < NUM_SPI_FLASHES; i++) {
-            dev = ssi_create_slave_no_init(spi, "m25p80", i);
+            sprintf(sub_bus_name, "spi%d", i);
+            spi = qdev_get_child_bus(dev, sub_bus_name);
+            dev = ssi_create_slave_no_init(spi, "m25p80");
             qdev_prop_set_string(dev, "partname", (char *)"s25fl064k");
             qdev_init_nofail(dev);
         }
diff --git a/hw/xilinx_spi.c b/hw/xilinx_spi.c
index cae88ad..6c81f70 100644
--- a/hw/xilinx_spi.c
+++ b/hw/xilinx_spi.c
@@ -420,8 +420,11 @@ static int xilinx_spi_init(SysBusDevice *dev)
     s->irqline = -1;
     ptimer_set_freq(s->ptimer, 10 * 1000 * 1000);

-    s->spi = ssi_create_bus(&dev->qdev, "spi");
-
+    char sub_bus_name;
+    for (i = 0; i < num_cs; i++) {
+        sprintf(sub_bus_name, "spi%d", i);
+        s->spi[i] = ssi_create_bus(&dev->qdev, sub_bus_name);
+    }
     return 0;
 }

The multi-slave bus is a direct superset on point-to-point. There is
nothing stopping anyone from using it as p2p. Its just things are very
ugly for SPI controllers with integrated muxes to treat everything as
point to point.

Regards,
Peter
>
> Paul

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [Qemu-devel] [PATCH V4 0/5] Ehnahced SSI bus support + M25P80 SPI flash + Xilinx SPI controller
  2012-06-05  1:34 ` [Qemu-devel] [PATCH V4 0/5] Ehnahced SSI bus support + M25P80 SPI flash + Xilinx SPI controller Paul Brook
  2012-06-05  1:54   ` Peter Crosthwaite
@ 2012-06-05  2:51   ` John Williams
  2012-06-06 13:18     ` Paul Brook
  1 sibling, 1 reply; 12+ messages in thread
From: John Williams @ 2012-06-05  2:51 UTC (permalink / raw)
  To: Paul Brook
  Cc: Peter A. G. Crosthwaite, edgar.iglesias, stefanha, qemu-devel,
	peter.maydell

Hi Paul,

On Tue, Jun 5, 2012 at 11:34 AM, Paul Brook <paul@codesourcery.com> wrote:
>> Patch 1 Enhances SSI bus support to properly support multiple attached
>> devices. An api is provided for SSI/SPI masters to select a particular
>> device attached to the bus.
>>
>> Patch 2 is a device model for the m25p80 style SPI flash chip.
>>
>> Patch 3 is  the Xilinx XPS SPI contoller. Its a sysbus device that
>> instantiates a ssi bus, and interfaces the two (as per the controllers
>> functionality)
>>
>> Patch 4 instantiates the XPS SPI controller in the petalogix ML605
>> reference platform and connects two m25p80s to it.
>>
>> Patch 5 updates the stellaris machine model to use the multi slave SSI
>> support
>
> I'm still not convinced modelling this as a multipoint bus is a good idea.  If
> nothing else you've failed to model the case where multiple slaves are
> selected simultanously.  Given the chip selects are actual wires, not part of
> the bus itself, I think multiple point-point busses are a better fit.
>

On 5th April, when we first RFC'd our SPI layer support, you said to Peter:

==
I don't believe there is any difference between SSI and SPI.  It's the exact
same thing - the same way that many devices support a "two-wire interface"
that is actually just I2C with a different name.

The behavior of the CS pin varies between devices.  It sounds like you need a
bit of extra logic not present in the current ssi code.  You should fix that,
not invent a whole new bus.
==

He's gone and done exactly that, indeed generalised it with the
proposed changes to SSI.

If you don't like how he's done the Stellaris change then feel free to
NACK that specific patch, but otherwise it seems this generic SSI set
should be good to go now?

Thanks,

John
--
John Williams, PhD, B. Eng, B. IT
PetaLogix - Linux Solutions for a Reconfigurable World
w: www.petalogix.com  p: +61-7-30090663  f: +61-7-30090663

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Qemu-devel] [PATCH V4 0/5] Ehnahced SSI bus support + M25P80 SPI flash + Xilinx SPI controller
  2012-06-05  2:51   ` John Williams
@ 2012-06-06 13:18     ` Paul Brook
  0 siblings, 0 replies; 12+ messages in thread
From: Paul Brook @ 2012-06-06 13:18 UTC (permalink / raw)
  To: John Williams
  Cc: Peter A. G. Crosthwaite, edgar.iglesias, stefanha, qemu-devel,
	peter.maydell

> On 5th April, when we first RFC'd our SPI layer support, you said to Peter:
> 
> ==
> I don't believe there is any difference between SSI and SPI.  It's the
> exact same thing - the same way that many devices support a "two-wire
> interface" that is actually just I2C with a different name.
> 
> The behavior of the CS pin varies between devices.  It sounds like you need
> a bit of extra logic not present in the current ssi code.  You should fix
> that, not invent a whole new bus.
> ==
> 
> He's gone and done exactly that, indeed generalised it with the
> proposed changes to SSI.

No.  There are two changes.  Modelling the CS line in the SPI bus, and having 
SSI be a multipoint bus rather than point-point.

Paul

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Qemu-devel] [PATCH V4 0/5] Ehnahced SSI bus support + M25P80 SPI flash + Xilinx SPI controller
  2012-06-05  1:54   ` Peter Crosthwaite
@ 2012-06-06 13:37     ` Paul Brook
  0 siblings, 0 replies; 12+ messages in thread
From: Paul Brook @ 2012-06-06 13:37 UTC (permalink / raw)
  To: Peter Crosthwaite
  Cc: stefanha, edgar.iglesias, qemu-devel, john.williams,
	peter.maydell

> > I'm still not convinced modelling this as a multipoint bus is a good
> > idea.  If nothing else you've failed to model the case where multiple
> > slaves are selected simultanously.
> 
> The bus can easily be changed such that multiple devices are
> selectable at once to get your desired multi device behaviour. AFAICT
> though nothing in QEMU behaves like this ATM.

By my reading your xilinx device *should* behave like this.
 
> >  Given the chip selects are actual wires, not part of
> > the bus itself, I think multiple point-point busses are a better fit.
> > 
> > For the stellaris device we still have the synthetic mux device and
> > intermediate bus.
> 
> Yes, because in your stellaris architecture, the SSI controller
> (pl022) is point to point so that exactly matches the hardware.
> 
> In the microblaze controller in this series, the controller has
> inbuilt muxing with one-hot CS behavior. To implement with point to
> point, I would have to dynamically create a number of sub-busses
> (driven by a qdev property). I would also have to have a device within
> a device to model the internal mux which increases my code volume
> significantly. Also you end up with this little piece of ugliness in
> your machine model and device model:

I don't see why would would need a separate mux device.

One of my issues is that you've made this a device property.  A SPI device has 
no concept of address.  This really is a property of the controller.

> The multi-slave bus is a direct superset on point-to-point. There is
> nothing stopping anyone from using it as p2p. Its just things are very
> ugly for SPI controllers with integrated muxes to treat everything as
> point to point.

IMHO the resulting tree device is better with multiple point-point links.  I'm 
hoping the hardcoded board descriptions (i.e. everything using 
ssi_create_slave) will go away sooner rather than later.  Having two m25p80 
devices that are indistinguishable apart from one minor property seems 
undesirable.

Paul

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2012-06-06 13:37 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-06-04  8:08 [Qemu-devel] [PATCH V4 0/5] Ehnahced SSI bus support + M25P80 SPI flash + Xilinx SPI controller Peter A. G. Crosthwaite
2012-06-04  8:08 ` [Qemu-devel] [PATCH V4 1/5] SSI: Built in multiple device support Peter A. G. Crosthwaite
2012-06-04  8:08 ` [Qemu-devel] [PATCH V4 2/5] m25p80: initial verion Peter A. G. Crosthwaite
2012-06-04  8:08 ` [Qemu-devel] [PATCH V4 3/5] xilinx_spi: initial version Peter A. G. Crosthwaite
2012-06-04  8:08 ` [Qemu-devel] [PATCH V4 4/5] petalogix-ml605: added spi controller with m25p80 Peter A. G. Crosthwaite
2012-06-04  8:08 ` [Qemu-devel] [PATCH V4 5/5] stellaris: Updated spi bus implementation Peter A. G. Crosthwaite
2012-06-04  8:14   ` Peter Crosthwaite
2012-06-05  1:34 ` [Qemu-devel] [PATCH V4 0/5] Ehnahced SSI bus support + M25P80 SPI flash + Xilinx SPI controller Paul Brook
2012-06-05  1:54   ` Peter Crosthwaite
2012-06-06 13:37     ` Paul Brook
2012-06-05  2:51   ` John Williams
2012-06-06 13:18     ` Paul Brook

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).