All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v3 00/13] Add support for the ZynqMP Generic QSPI
@ 2017-10-24 19:51 Francisco Iglesias
  2017-10-24 19:51 ` [Qemu-devel] [PATCH v3 01/13] m25p80: Add support for continuous read out of RDSR and READ_FSR Francisco Iglesias
                   ` (12 more replies)
  0 siblings, 13 replies; 19+ messages in thread
From: Francisco Iglesias @ 2017-10-24 19:51 UTC (permalink / raw)
  To: qemu-devel; +Cc: edgari, alistai, francisco.iglesias

Hi,

This patch series is an attempt to add support for the ZynqMP QSPI (consisting
of the Generic QSPI and the legacy QSPI) to the xlnx-zcu102 board and connect 
Numonyx n25q512a11 flashes to the QSPI. Also some functionality is added to
m25p80.

The series starts by adding support in m25p80 for continous read out of status
registers, SST flash READ ID commands, bank address register accesses, bulk
erase (0x60) and two Numonyx flashes (n25q512a11 and n25q512a13). Thereafter it
updates the striping behaviour to be bit big endiann in the Xilinx QSPI model
and adds support for RX discard, zero pumping according transfer register and 4
byte LQSPI addresses. Finally it adds support for the ZynqMP Generic QSPI and
adds the ZynqMP QSPI to the xlnx-zcu102 board.

Best regards,
Francisco Iglesias

Changelog:
v2 -> v3
  * Tweaked commit messages 
  * Corrected patch 08 'Make tx/rx_data_bytes more generic and reusable'
  * Reworked the patch adding the ZynqMP GQSPI and splitted out another QSPI
    related change into an own patch 'Don't set TX FIFO UNDERFLOW at cmd done'

v1 -> v2
  * Reset author on commits (due to mailing issues).


Francisco Iglesias (13):
  m25p80: Add support for continuous read out of RDSR and READ_FSR
  m25p80: Add support for SST READ ID 0x90/0xAB commands
  m25p80: Add support for BRRD/BRWR and BULK_ERASE (0x60)
  m25p80: Add support for n25q512a11 and n25q512a13
  xilinx_spips: Move FlashCMD, XilinxQSPIPS and XilinxSPIPSClass
  xilinx_spips: Update striping to be big-endian bit order
  xilinx_spips: Add support for RX discard and RX drain
  xilinx_spips: Make tx/rx_data_bytes more generic and reusable
  xilinx_spips: Add support for zero pumping
  xilinx_spips: Add support for 4 byte addresses in the LQSPI
  xilinx_spips: Don't set TX FIFO UNDERFLOW at cmd done
  xilinx_spips: Add support for the ZynqMP Generic QSPI
  xlnx-zcu102: Add support for the ZynqMP QSPI

 default-configs/arm-softmmu.mak |   1 +
 hw/arm/xlnx-zcu102.c            |  23 ++
 hw/arm/xlnx-zynqmp.c            |  24 ++
 hw/block/m25p80.c               |  50 ++-
 hw/ssi/xilinx_spips.c           | 775 +++++++++++++++++++++++++++++++++-------
 include/hw/arm/xlnx-zynqmp.h    |   5 +
 include/hw/ssi/xilinx_spips.h   |  71 +++-
 7 files changed, 809 insertions(+), 140 deletions(-)

-- 
2.9.3

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

* [Qemu-devel] [PATCH v3 01/13] m25p80: Add support for continuous read out of RDSR and READ_FSR
  2017-10-24 19:51 [Qemu-devel] [PATCH v3 00/13] Add support for the ZynqMP Generic QSPI Francisco Iglesias
@ 2017-10-24 19:51 ` Francisco Iglesias
  2017-10-25 18:03   ` mar.krzeminski
  2017-10-24 19:51 ` [Qemu-devel] [PATCH v3 02/13] m25p80: Add support for SST READ ID 0x90/0xAB commands Francisco Iglesias
                   ` (11 subsequent siblings)
  12 siblings, 1 reply; 19+ messages in thread
From: Francisco Iglesias @ 2017-10-24 19:51 UTC (permalink / raw)
  To: qemu-devel; +Cc: edgari, alistai, francisco.iglesias

Add support for continuous read out of the RDSR and READ_FSR status
registers until the chip select is deasserted. This feature is supported
by amongst others 1 or more flashtypes manufactured by Numonyx (Micron),
Windbond, SST, Gigadevice, Eon and Macronix.

Signed-off-by: Francisco Iglesias <frasse.iglesias@gmail.com>
---
 hw/block/m25p80.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
index a2438b9..2971519 100644
--- a/hw/block/m25p80.c
+++ b/hw/block/m25p80.c
@@ -423,6 +423,7 @@ typedef struct Flash {
     uint8_t data[M25P80_INTERNAL_DATA_BUFFER_SZ];
     uint32_t len;
     uint32_t pos;
+    bool data_read_loop;
     uint8_t needed_bytes;
     uint8_t cmd_in_progress;
     uint32_t cur_addr;
@@ -983,6 +984,7 @@ static void decode_new_cmd(Flash *s, uint32_t value)
         }
         s->pos = 0;
         s->len = 1;
+        s->data_read_loop = true;
         s->state = STATE_READING_DATA;
         break;
 
@@ -993,6 +995,7 @@ static void decode_new_cmd(Flash *s, uint32_t value)
         }
         s->pos = 0;
         s->len = 1;
+        s->data_read_loop = true;
         s->state = STATE_READING_DATA;
         break;
 
@@ -1133,6 +1136,7 @@ static int m25p80_cs(SSISlave *ss, bool select)
         s->pos = 0;
         s->state = STATE_IDLE;
         flash_sync_dirty(s, -1);
+        s->data_read_loop = false;
     }
 
     DB_PRINT_L(0, "%sselect\n", select ? "de" : "");
@@ -1198,7 +1202,9 @@ static uint32_t m25p80_transfer8(SSISlave *ss, uint32_t tx)
         s->pos++;
         if (s->pos == s->len) {
             s->pos = 0;
-            s->state = STATE_IDLE;
+            if (!s->data_read_loop) {
+                s->state = STATE_IDLE;
+            }
         }
         break;
 
-- 
2.9.3

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

* [Qemu-devel] [PATCH v3 02/13] m25p80: Add support for SST READ ID 0x90/0xAB commands
  2017-10-24 19:51 [Qemu-devel] [PATCH v3 00/13] Add support for the ZynqMP Generic QSPI Francisco Iglesias
  2017-10-24 19:51 ` [Qemu-devel] [PATCH v3 01/13] m25p80: Add support for continuous read out of RDSR and READ_FSR Francisco Iglesias
@ 2017-10-24 19:51 ` Francisco Iglesias
  2017-10-25 18:12   ` mar.krzeminski
  2017-10-24 19:51 ` [Qemu-devel] [PATCH v3 03/13] m25p80: Add support for BRRD/BRWR and BULK_ERASE (0x60) Francisco Iglesias
                   ` (10 subsequent siblings)
  12 siblings, 1 reply; 19+ messages in thread
From: Francisco Iglesias @ 2017-10-24 19:51 UTC (permalink / raw)
  To: qemu-devel; +Cc: edgari, alistai, francisco.iglesias

Add support for SST READ ID 0x90/0xAB commands for reading out the flash
manufacuter ID and device ID.

Signed-off-by: Francisco Iglesias <frasse.iglesias@gmail.com>
---
 hw/block/m25p80.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
index 2971519..c85e8fa 100644
--- a/hw/block/m25p80.c
+++ b/hw/block/m25p80.c
@@ -355,6 +355,8 @@ typedef enum {
     DPP = 0xa2,
     QPP = 0x32,
     QPP_4 = 0x34,
+    RDID_90 = 0x90,
+    RDID_AB = 0xab,
 
     ERASE_4K = 0x20,
     ERASE4_4K = 0x21,
@@ -405,6 +407,7 @@ typedef enum {
     MAN_MACRONIX,
     MAN_NUMONYX,
     MAN_WINBOND,
+    MAN_SST,
     MAN_GENERIC,
 } Manufacturer;
 
@@ -476,6 +479,8 @@ static inline Manufacturer get_man(Flash *s)
         return MAN_SPANSION;
     case 0xC2:
         return MAN_MACRONIX;
+    case 0xBF:
+        return MAN_SST;
     default:
         return MAN_GENERIC;
     }
@@ -1018,6 +1023,21 @@ static void decode_new_cmd(Flash *s, uint32_t value)
         s->state = STATE_READING_DATA;
         break;
 
+    case RDID_90:
+    case RDID_AB:
+        DB_PRINT_L(0, "populated manf/dev ID\n");
+        if (get_man(s) == MAN_SST) {
+            s->data[0] = s->pi->id[0];
+            s->data[1] = s->pi->id[2];
+            s->pos = 0;
+            s->len = 2;
+            s->data_read_loop = true;
+            s->state = STATE_READING_DATA;
+        } else {
+            qemu_log_mask(LOG_GUEST_ERROR, "M25P80: Unknown cmd %x\n", value);
+        }
+        break;
+
     case BULK_ERASE:
         if (s->write_enable) {
             DB_PRINT_L(0, "chip erase\n");
-- 
2.9.3

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

* [Qemu-devel] [PATCH v3 03/13] m25p80: Add support for BRRD/BRWR and BULK_ERASE (0x60)
  2017-10-24 19:51 [Qemu-devel] [PATCH v3 00/13] Add support for the ZynqMP Generic QSPI Francisco Iglesias
  2017-10-24 19:51 ` [Qemu-devel] [PATCH v3 01/13] m25p80: Add support for continuous read out of RDSR and READ_FSR Francisco Iglesias
  2017-10-24 19:51 ` [Qemu-devel] [PATCH v3 02/13] m25p80: Add support for SST READ ID 0x90/0xAB commands Francisco Iglesias
@ 2017-10-24 19:51 ` Francisco Iglesias
  2017-10-25 14:55   ` mar.krzeminski
  2017-10-24 19:51 ` [Qemu-devel] [PATCH v3 04/13] m25p80: Add support for n25q512a11 and n25q512a13 Francisco Iglesias
                   ` (9 subsequent siblings)
  12 siblings, 1 reply; 19+ messages in thread
From: Francisco Iglesias @ 2017-10-24 19:51 UTC (permalink / raw)
  To: qemu-devel; +Cc: edgari, alistai, francisco.iglesias

Add support for the bank address register access commands (BRRD/BRWR) and
the BULK_ERASE (0x60) command.

Signed-off-by: Francisco Iglesias <frasse.iglesias@gmail.com>
---
 hw/block/m25p80.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
index c85e8fa..3d2975c 100644
--- a/hw/block/m25p80.c
+++ b/hw/block/m25p80.c
@@ -331,6 +331,8 @@ typedef enum {
     WRDI = 0x4,
     RDSR = 0x5,
     WREN = 0x6,
+    BRRD = 0x16,
+    BRWR = 0x17,
     JEDEC_READ = 0x9f,
     BULK_ERASE = 0xc7,
     READ_FSR = 0x70,
@@ -368,6 +370,8 @@ typedef enum {
     EN_4BYTE_ADDR = 0xB7,
     EX_4BYTE_ADDR = 0xE9,
 
+    BULK_ERASE_60 = 0x60,
+
     EXTEND_ADDR_READ = 0xC8,
     EXTEND_ADDR_WRITE = 0xC5,
 
@@ -975,6 +979,15 @@ static void decode_new_cmd(Flash *s, uint32_t value)
         }
         break;
 
+    case BRWR:
+        if (s->write_enable) {
+            s->needed_bytes = 1;
+            s->pos = 0;
+            s->len = 0;
+            s->state = STATE_COLLECTING_DATA;
+        }
+        break;
+
     case WRDI:
         s->write_enable = false;
         break;
@@ -1004,6 +1017,12 @@ static void decode_new_cmd(Flash *s, uint32_t value)
         s->state = STATE_READING_DATA;
         break;
 
+    case BRRD:
+        s->pos = 0;
+        s->len = 1;
+        s->state = STATE_READING_DATA;
+        break;
+
     case JEDEC_READ:
         DB_PRINT_L(0, "populated jedec code\n");
         for (i = 0; i < s->pi->id_len; i++) {
@@ -1038,6 +1057,7 @@ static void decode_new_cmd(Flash *s, uint32_t value)
         }
         break;
 
+    case BULK_ERASE_60:
     case BULK_ERASE:
         if (s->write_enable) {
             DB_PRINT_L(0, "chip erase\n");
-- 
2.9.3

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

* [Qemu-devel] [PATCH v3 04/13] m25p80: Add support for n25q512a11 and n25q512a13
  2017-10-24 19:51 [Qemu-devel] [PATCH v3 00/13] Add support for the ZynqMP Generic QSPI Francisco Iglesias
                   ` (2 preceding siblings ...)
  2017-10-24 19:51 ` [Qemu-devel] [PATCH v3 03/13] m25p80: Add support for BRRD/BRWR and BULK_ERASE (0x60) Francisco Iglesias
@ 2017-10-24 19:51 ` Francisco Iglesias
  2017-10-25 18:02   ` mar.krzeminski
  2017-10-24 19:51 ` [Qemu-devel] [PATCH v3 05/13] xilinx_spips: Move FlashCMD, XilinxQSPIPS and XilinxSPIPSClass Francisco Iglesias
                   ` (8 subsequent siblings)
  12 siblings, 1 reply; 19+ messages in thread
From: Francisco Iglesias @ 2017-10-24 19:51 UTC (permalink / raw)
  To: qemu-devel; +Cc: edgari, alistai, francisco.iglesias

Add support for Micron (Numonyx) n25q512a11 and n25q512a13 flashes.

Signed-off-by: Francisco Iglesias <frasse.iglesias@gmail.com>
---
 hw/block/m25p80.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
index 3d2975c..7f3fcc4 100644
--- a/hw/block/m25p80.c
+++ b/hw/block/m25p80.c
@@ -240,6 +240,8 @@ static const FlashPartInfo known_devices[] = {
     { INFO("n25q128a13",  0x20ba18,      0,  64 << 10, 256, ER_4K) },
     { INFO("n25q256a11",  0x20bb19,      0,  64 << 10, 512, ER_4K) },
     { INFO("n25q256a13",  0x20ba19,      0,  64 << 10, 512, ER_4K) },
+    { INFO("n25q512a11",  0x20bb20,      0,  64 << 10, 1024, ER_4K) },
+    { INFO("n25q512a13",  0x20ba20,      0,  64 << 10, 1024, ER_4K) },
     { INFO("n25q128",     0x20ba18,      0,  64 << 10, 256, 0) },
     { INFO("n25q256a",    0x20ba19,      0,  64 << 10, 512, ER_4K) },
     { INFO("n25q512a",    0x20ba20,      0,  64 << 10, 1024, ER_4K) },
-- 
2.9.3

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

* [Qemu-devel] [PATCH v3 05/13] xilinx_spips: Move FlashCMD, XilinxQSPIPS and XilinxSPIPSClass
  2017-10-24 19:51 [Qemu-devel] [PATCH v3 00/13] Add support for the ZynqMP Generic QSPI Francisco Iglesias
                   ` (3 preceding siblings ...)
  2017-10-24 19:51 ` [Qemu-devel] [PATCH v3 04/13] m25p80: Add support for n25q512a11 and n25q512a13 Francisco Iglesias
@ 2017-10-24 19:51 ` Francisco Iglesias
  2017-10-24 19:51 ` [Qemu-devel] [PATCH v3 06/13] xilinx_spips: Update striping to be big-endian bit order Francisco Iglesias
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 19+ messages in thread
From: Francisco Iglesias @ 2017-10-24 19:51 UTC (permalink / raw)
  To: qemu-devel; +Cc: edgari, alistai, francisco.iglesias

Move the FlashCMD enum, XilinxQSPIPS and XilinxSPIPSClass structures to the
header for consistency. Also move out a define and remove two dubbel included
headers (while touching the code). Finally, add 4 byte address commands to the
FlashCMD enum.

Signed-off-by: Francisco Iglesias <frasse.iglesias@gmail.com>
---
 hw/ssi/xilinx_spips.c         | 35 -----------------------------------
 include/hw/ssi/xilinx_spips.h | 34 ++++++++++++++++++++++++++++++++++
 2 files changed, 34 insertions(+), 35 deletions(-)

diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
index ef56d35..559fa79 100644
--- a/hw/ssi/xilinx_spips.c
+++ b/hw/ssi/xilinx_spips.c
@@ -27,8 +27,6 @@
 #include "sysemu/sysemu.h"
 #include "hw/ptimer.h"
 #include "qemu/log.h"
-#include "qemu/fifo8.h"
-#include "hw/ssi/ssi.h"
 #include "qemu/bitops.h"
 #include "hw/ssi/xilinx_spips.h"
 #include "qapi/error.h"
@@ -116,44 +114,11 @@
 
 /* 16MB per linear region */
 #define LQSPI_ADDRESS_BITS 24
-/* Bite off 4k chunks at a time */
-#define LQSPI_CACHE_SIZE 1024
 
 #define SNOOP_CHECKING 0xFF
 #define SNOOP_NONE 0xFE
 #define SNOOP_STRIPING 0
 
-typedef enum {
-    READ = 0x3,
-    FAST_READ = 0xb,
-    DOR = 0x3b,
-    QOR = 0x6b,
-    DIOR = 0xbb,
-    QIOR = 0xeb,
-
-    PP = 0x2,
-    DPP = 0xa2,
-    QPP = 0x32,
-} FlashCMD;
-
-typedef struct {
-    XilinxSPIPS parent_obj;
-
-    uint8_t lqspi_buf[LQSPI_CACHE_SIZE];
-    hwaddr lqspi_cached_addr;
-    Error *migration_blocker;
-    bool mmio_execution_enabled;
-} XilinxQSPIPS;
-
-typedef struct XilinxSPIPSClass {
-    SysBusDeviceClass parent_class;
-
-    const MemoryRegionOps *reg_ops;
-
-    uint32_t rx_fifo_size;
-    uint32_t tx_fifo_size;
-} XilinxSPIPSClass;
-
 static inline int num_effective_busses(XilinxSPIPS *s)
 {
     return (s->regs[R_LQSPI_CFG] & LQSPI_CFG_SEP_BUS &&
diff --git a/include/hw/ssi/xilinx_spips.h b/include/hw/ssi/xilinx_spips.h
index 06aa096..7f9e2fc 100644
--- a/include/hw/ssi/xilinx_spips.h
+++ b/include/hw/ssi/xilinx_spips.h
@@ -32,6 +32,22 @@ typedef struct XilinxSPIPS XilinxSPIPS;
 
 #define XLNX_SPIPS_R_MAX        (0x100 / 4)
 
+/* Bite off 4k chunks at a time */
+#define LQSPI_CACHE_SIZE 1024
+
+typedef enum {
+    READ = 0x3,         READ_4 = 0x13,
+    FAST_READ = 0xb,    FAST_READ_4 = 0x0c,
+    DOR = 0x3b,         DOR_4 = 0x3c,
+    QOR = 0x6b,         QOR_4 = 0x6c,
+    DIOR = 0xbb,        DIOR_4 = 0xbc,
+    QIOR = 0xeb,        QIOR_4 = 0xec,
+
+    PP = 0x2,           PP_4 = 0x12,
+    DPP = 0xa2,
+    QPP = 0x32,         QPP_4 = 0x34,
+} FlashCMD;
+
 struct XilinxSPIPS {
     SysBusDevice parent_obj;
 
@@ -56,6 +72,24 @@ struct XilinxSPIPS {
     uint32_t regs[XLNX_SPIPS_R_MAX];
 };
 
+typedef struct {
+    XilinxSPIPS parent_obj;
+
+    uint8_t lqspi_buf[LQSPI_CACHE_SIZE];
+    hwaddr lqspi_cached_addr;
+    Error *migration_blocker;
+    bool mmio_execution_enabled;
+} XilinxQSPIPS;
+
+typedef struct XilinxSPIPSClass {
+    SysBusDeviceClass parent_class;
+
+    const MemoryRegionOps *reg_ops;
+
+    uint32_t rx_fifo_size;
+    uint32_t tx_fifo_size;
+} XilinxSPIPSClass;
+
 #define TYPE_XILINX_SPIPS "xlnx.ps7-spi"
 #define TYPE_XILINX_QSPIPS "xlnx.ps7-qspi"
 
-- 
2.9.3

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

* [Qemu-devel] [PATCH v3 06/13] xilinx_spips: Update striping to be big-endian bit order
  2017-10-24 19:51 [Qemu-devel] [PATCH v3 00/13] Add support for the ZynqMP Generic QSPI Francisco Iglesias
                   ` (4 preceding siblings ...)
  2017-10-24 19:51 ` [Qemu-devel] [PATCH v3 05/13] xilinx_spips: Move FlashCMD, XilinxQSPIPS and XilinxSPIPSClass Francisco Iglesias
@ 2017-10-24 19:51 ` Francisco Iglesias
  2017-10-24 19:51 ` [Qemu-devel] [PATCH v3 08/13] xilinx_spips: Make tx/rx_data_bytes more generic and reusable Francisco Iglesias
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 19+ messages in thread
From: Francisco Iglesias @ 2017-10-24 19:51 UTC (permalink / raw)
  To: qemu-devel; +Cc: edgari, alistai, francisco.iglesias

Update striping functionality to be big-endian bit order and output even
bits into flash memory connected to the lower QSPI bus and odd bits into
the flash memory connected to the upper QSPI bus.

Signed-off-by: Francisco Iglesias <frasse.iglesias@gmail.com>
---
 hw/ssi/xilinx_spips.c | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
index 559fa79..7accf5d 100644
--- a/hw/ssi/xilinx_spips.c
+++ b/hw/ssi/xilinx_spips.c
@@ -208,14 +208,14 @@ static void xilinx_spips_reset(DeviceState *d)
     xilinx_spips_update_cs_lines(s);
 }
 
-/* N way (num) in place bit striper. Lay out row wise bits (LSB to MSB)
+/* N way (num) in place bit striper. Lay out row wise bits (MSB to LSB)
  * column wise (from element 0 to N-1). num is the length of x, and dir
  * reverses the direction of the transform. Best illustrated by example:
  * Each digit in the below array is a single bit (num == 3):
  *
- * {{ 76543210, }  ----- stripe (dir == false) -----> {{ FCheb630, }
- *  { hgfedcba, }                                      { GDAfc741, }
- *  { HGFEDCBA, }} <---- upstripe (dir == true) -----  { HEBgda52, }}
+ * {{ 76543210, }  ----- stripe (dir == false) -----> {{ 741gdaFC, }
+ *  { hgfedcba, }                                      { 630fcHEB, }
+ *  { HGFEDCBA, }} <---- upstripe (dir == true) -----  { 52hebGDA, }}
  */
 
 static inline void stripe8(uint8_t *x, int num, bool dir)
@@ -223,15 +223,15 @@ static inline void stripe8(uint8_t *x, int num, bool dir)
     uint8_t r[num];
     memset(r, 0, sizeof(uint8_t) * num);
     int idx[2] = {0, 0};
-    int bit[2] = {0, 0};
+    int bit[2] = {0, 7};
     int d = dir;
 
     for (idx[0] = 0; idx[0] < num; ++idx[0]) {
-        for (bit[0] = 0; bit[0] < 8; ++bit[0]) {
-            r[idx[d]] |= x[idx[!d]] & 1 << bit[!d] ? 1 << bit[d] : 0;
+        for (bit[0] = 7; bit[0] != -1; bit[0] += -1) {
+            r[idx[!d]] |= x[idx[d]] & 1 << bit[d] ? 1 << bit[!d] : 0;
             idx[1] = (idx[1] + 1) % num;
             if (!idx[1]) {
-                bit[1]++;
+                bit[1] += -1;
             }
         }
     }
@@ -266,8 +266,9 @@ static void xilinx_spips_flush_txfifo(XilinxSPIPS *s)
         }
 
         for (i = 0; i < num_effective_busses(s); ++i) {
+            int bus = num_effective_busses(s) - 1 - i;
             DB_PRINT_L(debug_level, "tx = %02x\n", tx_rx[i]);
-            tx_rx[i] = ssi_transfer(s->spi[i], (uint32_t)tx_rx[i]);
+            tx_rx[i] = ssi_transfer(s->spi[bus], (uint32_t)tx_rx[i]);
             DB_PRINT_L(debug_level, "rx = %02x\n", tx_rx[i]);
         }
 
-- 
2.9.3

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

* [Qemu-devel] [PATCH v3 08/13] xilinx_spips: Make tx/rx_data_bytes more generic and reusable
  2017-10-24 19:51 [Qemu-devel] [PATCH v3 00/13] Add support for the ZynqMP Generic QSPI Francisco Iglesias
                   ` (5 preceding siblings ...)
  2017-10-24 19:51 ` [Qemu-devel] [PATCH v3 06/13] xilinx_spips: Update striping to be big-endian bit order Francisco Iglesias
@ 2017-10-24 19:51 ` Francisco Iglesias
  2017-10-24 19:51 ` [Qemu-devel] [PATCH v3 10/13] xilinx_spips: Add support for 4 byte addresses in the LQSPI Francisco Iglesias
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 19+ messages in thread
From: Francisco Iglesias @ 2017-10-24 19:51 UTC (permalink / raw)
  To: qemu-devel; +Cc: edgari, alistai, francisco.iglesias

Make tx/rx_data_bytes more generic so they can be reused (when adding
support for the Zynqmp Generic QSPI).

Signed-off-by: Francisco Iglesias <frasse.iglesias@gmail.com>
---
 hw/ssi/xilinx_spips.c | 64 +++++++++++++++++++++++++++++----------------------
 1 file changed, 37 insertions(+), 27 deletions(-)

diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
index 2ee70e9..ad9f1a0 100644
--- a/hw/ssi/xilinx_spips.c
+++ b/hw/ssi/xilinx_spips.c
@@ -47,7 +47,7 @@
 /* config register */
 #define R_CONFIG            (0x00 / 4)
 #define IFMODE              (1U << 31)
-#define ENDIAN              (1 << 26)
+#define R_CONFIG_ENDIAN     (1 << 26)
 #define MODEFAIL_GEN_EN     (1 << 17)
 #define MAN_START_COM       (1 << 16)
 #define MAN_START_EN        (1 << 15)
@@ -445,13 +445,28 @@ static void xilinx_spips_flush_txfifo(XilinxSPIPS *s)
     }
 }
 
-static inline void rx_data_bytes(XilinxSPIPS *s, uint8_t *value, int max)
+static inline void tx_data_bytes(Fifo8 *fifo, uint32_t value, int num, bool be)
 {
     int i;
+    for (i = 0; i < num && !fifo8_is_full(fifo); ++i) {
+        if (be) {
+            fifo8_push(fifo, (uint8_t)(value >> 24));
+            value <<= 8;
+        } else {
+            fifo8_push(fifo, (uint8_t)value);
+            value >>= 8;
+        }
+    }
+}
 
-    for (i = 0; i < max && !fifo8_is_empty(&s->rx_fifo); ++i) {
-        value[i] = fifo8_pop(&s->rx_fifo);
+static inline int rx_data_bytes(Fifo8 *fifo, uint8_t *value, int max)
+{
+    int i;
+
+    for (i = 0; i < max && !fifo8_is_empty(fifo); ++i) {
+        value[i] = fifo8_pop(fifo);
     }
+    return max - i;
 }
 
 static uint64_t xilinx_spips_read(void *opaque, hwaddr addr,
@@ -461,6 +476,7 @@ static uint64_t xilinx_spips_read(void *opaque, hwaddr addr,
     uint32_t mask = ~0;
     uint32_t ret;
     uint8_t rx_buf[4];
+    int shortfall;
 
     addr >>= 2;
     switch (addr) {
@@ -491,9 +507,13 @@ static uint64_t xilinx_spips_read(void *opaque, hwaddr addr,
         break;
     case R_RX_DATA:
         memset(rx_buf, 0, sizeof(rx_buf));
-        rx_data_bytes(s, rx_buf, s->num_txrx_bytes);
-        ret = s->regs[R_CONFIG] & ENDIAN ? cpu_to_be32(*(uint32_t *)rx_buf)
-                        : cpu_to_le32(*(uint32_t *)rx_buf);
+        shortfall = rx_data_bytes(&s->rx_fifo, rx_buf, s->num_txrx_bytes);
+        ret = s->regs[R_CONFIG] & R_CONFIG_ENDIAN ?
+                        cpu_to_be32(*(uint32_t *)rx_buf) :
+                        cpu_to_le32(*(uint32_t *)rx_buf);
+        if (!(s->regs[R_CONFIG] & R_CONFIG_ENDIAN)) {
+            ret <<= 8 * shortfall;
+        }
         DB_PRINT_L(0, "addr=" TARGET_FMT_plx " = %x\n", addr * 4, ret);
         xilinx_spips_update_ixr(s);
         return ret;
@@ -504,20 +524,6 @@ static uint64_t xilinx_spips_read(void *opaque, hwaddr addr,
 
 }
 
-static inline void tx_data_bytes(XilinxSPIPS *s, uint32_t value, int num)
-{
-    int i;
-    for (i = 0; i < num && !fifo8_is_full(&s->tx_fifo); ++i) {
-        if (s->regs[R_CONFIG] & ENDIAN) {
-            fifo8_push(&s->tx_fifo, (uint8_t)(value >> 24));
-            value <<= 8;
-        } else {
-            fifo8_push(&s->tx_fifo, (uint8_t)value);
-            value >>= 8;
-        }
-    }
-}
-
 static void xilinx_spips_write(void *opaque, hwaddr addr,
                                         uint64_t value, unsigned size)
 {
@@ -558,16 +564,20 @@ static void xilinx_spips_write(void *opaque, hwaddr addr,
         mask = 0;
         break;
     case R_TX_DATA:
-        tx_data_bytes(s, (uint32_t)value, s->num_txrx_bytes);
+        tx_data_bytes(&s->tx_fifo, (uint32_t)value, s->num_txrx_bytes,
+                      s->regs[R_CONFIG] & R_CONFIG_ENDIAN);
         goto no_reg_update;
     case R_TXD1:
-        tx_data_bytes(s, (uint32_t)value, 1);
+        tx_data_bytes(&s->tx_fifo, (uint32_t)value, 1,
+                      s->regs[R_CONFIG] & R_CONFIG_ENDIAN);
         goto no_reg_update;
     case R_TXD2:
-        tx_data_bytes(s, (uint32_t)value, 2);
+        tx_data_bytes(&s->tx_fifo, (uint32_t)value, 2,
+                      s->regs[R_CONFIG] & R_CONFIG_ENDIAN);
         goto no_reg_update;
     case R_TXD3:
-        tx_data_bytes(s, (uint32_t)value, 3);
+        tx_data_bytes(&s->tx_fifo, (uint32_t)value, 3,
+                      s->regs[R_CONFIG] & R_CONFIG_ENDIAN);
         goto no_reg_update;
     }
     s->regs[addr] = (s->regs[addr] & ~mask) | (value & mask);
@@ -677,11 +687,11 @@ static void lqspi_load_cache(void *opaque, hwaddr addr)
 
         while (cache_entry < LQSPI_CACHE_SIZE) {
             for (i = 0; i < 64; ++i) {
-                tx_data_bytes(s, 0, 1);
+                tx_data_bytes(&s->tx_fifo, 0, 1, false);
             }
             xilinx_spips_flush_txfifo(s);
             for (i = 0; i < 64; ++i) {
-                rx_data_bytes(s, &q->lqspi_buf[cache_entry++], 1);
+                rx_data_bytes(&s->rx_fifo, &q->lqspi_buf[cache_entry++], 1);
             }
         }
 
-- 
2.9.3

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

* [Qemu-devel] [PATCH v3 10/13] xilinx_spips: Add support for 4 byte addresses in the LQSPI
  2017-10-24 19:51 [Qemu-devel] [PATCH v3 00/13] Add support for the ZynqMP Generic QSPI Francisco Iglesias
                   ` (6 preceding siblings ...)
  2017-10-24 19:51 ` [Qemu-devel] [PATCH v3 08/13] xilinx_spips: Make tx/rx_data_bytes more generic and reusable Francisco Iglesias
@ 2017-10-24 19:51 ` Francisco Iglesias
  2017-10-24 19:51 ` [Qemu-devel] [PATCH v3 11/13] xilinx_spips: Don't set TX FIFO UNDERFLOW at cmd done Francisco Iglesias
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 19+ messages in thread
From: Francisco Iglesias @ 2017-10-24 19:51 UTC (permalink / raw)
  To: qemu-devel; +Cc: edgari, alistai, francisco.iglesias

Add support for 4 byte addresses in the LQSPI and correct LQSPI_CFG_SEP_BUS.

Signed-off-by: Francisco Iglesias <frasse.iglesias@gmail.com>
---
 hw/ssi/xilinx_spips.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
index df5d908..5e5e8cc 100644
--- a/hw/ssi/xilinx_spips.c
+++ b/hw/ssi/xilinx_spips.c
@@ -92,8 +92,9 @@
 #define R_LQSPI_CFG_RESET       0x03A002EB
 #define LQSPI_CFG_LQ_MODE       (1U << 31)
 #define LQSPI_CFG_TWO_MEM       (1 << 30)
-#define LQSPI_CFG_SEP_BUS       (1 << 30)
+#define LQSPI_CFG_SEP_BUS       (1 << 29)
 #define LQSPI_CFG_U_PAGE        (1 << 28)
+#define LQSPI_CFG_ADDR4         (1 << 27)
 #define LQSPI_CFG_MODE_EN       (1 << 25)
 #define LQSPI_CFG_MODE_WIDTH    8
 #define LQSPI_CFG_MODE_SHIFT    16
@@ -697,6 +698,9 @@ static void lqspi_load_cache(void *opaque, hwaddr addr)
         fifo8_push(&s->tx_fifo, s->regs[R_LQSPI_CFG] & LQSPI_CFG_INST_CODE);
         /* read address */
         DB_PRINT_L(0, "pushing read address %06x\n", flash_addr);
+        if (s->regs[R_LQSPI_CFG] & LQSPI_CFG_ADDR4) {
+            fifo8_push(&s->tx_fifo, (uint8_t)(flash_addr >> 24));
+        }
         fifo8_push(&s->tx_fifo, (uint8_t)(flash_addr >> 16));
         fifo8_push(&s->tx_fifo, (uint8_t)(flash_addr >> 8));
         fifo8_push(&s->tx_fifo, (uint8_t)flash_addr);
-- 
2.9.3

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

* [Qemu-devel] [PATCH v3 11/13] xilinx_spips: Don't set TX FIFO UNDERFLOW at cmd done
  2017-10-24 19:51 [Qemu-devel] [PATCH v3 00/13] Add support for the ZynqMP Generic QSPI Francisco Iglesias
                   ` (7 preceding siblings ...)
  2017-10-24 19:51 ` [Qemu-devel] [PATCH v3 10/13] xilinx_spips: Add support for 4 byte addresses in the LQSPI Francisco Iglesias
@ 2017-10-24 19:51 ` Francisco Iglesias
  2017-10-24 19:51 ` [Qemu-devel] [PATCH v3 12/13] xilinx_spips: Add support for the ZynqMP Generic QSPI Francisco Iglesias
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 19+ messages in thread
From: Francisco Iglesias @ 2017-10-24 19:51 UTC (permalink / raw)
  To: qemu-devel; +Cc: edgari, alistai, francisco.iglesias

Don't set TX FIFO UNDERFLOW interrupt after done transmiting the commands.
Also update interrupts after reading out the interrupt status.

Signed-off-by: Francisco Iglesias <frasse.iglesias@gmail.com>
---
 hw/ssi/xilinx_spips.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
index 5e5e8cc..ffed5ba 100644
--- a/hw/ssi/xilinx_spips.c
+++ b/hw/ssi/xilinx_spips.c
@@ -324,9 +324,6 @@ static void xilinx_spips_flush_txfifo(XilinxSPIPS *s)
         uint8_t addr_length;
 
         if (fifo8_is_empty(&s->tx_fifo)) {
-            if (!(s->regs[R_LQSPI_CFG] & LQSPI_CFG_LQ_MODE)) {
-                s->regs[R_INTR_STATUS] |= IXR_TX_FIFO_UNDERFLOW;
-            }
             xilinx_spips_update_ixr(s);
             return;
         } else if (s->snoop_state == SNOOP_STRIPING) {
@@ -525,6 +522,7 @@ static uint64_t xilinx_spips_read(void *opaque, hwaddr addr,
         ret = s->regs[addr] & IXR_ALL;
         s->regs[addr] = 0;
         DB_PRINT_L(0, "addr=" TARGET_FMT_plx " = %x\n", addr * 4, ret);
+        xilinx_spips_update_ixr(s);
         return ret;
     case R_INTR_MASK:
         mask = IXR_ALL;
-- 
2.9.3

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

* [Qemu-devel] [PATCH v3 12/13] xilinx_spips: Add support for the ZynqMP Generic QSPI
  2017-10-24 19:51 [Qemu-devel] [PATCH v3 00/13] Add support for the ZynqMP Generic QSPI Francisco Iglesias
                   ` (8 preceding siblings ...)
  2017-10-24 19:51 ` [Qemu-devel] [PATCH v3 11/13] xilinx_spips: Don't set TX FIFO UNDERFLOW at cmd done Francisco Iglesias
@ 2017-10-24 19:51 ` Francisco Iglesias
  2017-10-24 19:51 ` [Qemu-devel] [PATCH v3 13/13] xlnx-zcu102: Add support for the ZynqMP QSPI Francisco Iglesias
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 19+ messages in thread
From: Francisco Iglesias @ 2017-10-24 19:51 UTC (permalink / raw)
  To: qemu-devel; +Cc: edgari, alistai, francisco.iglesias

Add support for the Zynq Ultrascale MPSoc Generic QSPI.

Signed-off-by: Francisco Iglesias <frasse.iglesias@gmail.com>
---
 default-configs/arm-softmmu.mak |   1 +
 hw/ssi/xilinx_spips.c           | 451 ++++++++++++++++++++++++++++++++++++----
 include/hw/ssi/xilinx_spips.h   |  30 ++-
 3 files changed, 437 insertions(+), 45 deletions(-)

diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index 5059d13..d09fd34 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -130,3 +130,4 @@ CONFIG_SMBIOS=y
 CONFIG_ASPEED_SOC=y
 CONFIG_GPIO_KEY=y
 CONFIG_MSF2=y
+CONFIG_XILINX_AXI=y
diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
index ffed5ba..2a43fb8 100644
--- a/hw/ssi/xilinx_spips.c
+++ b/hw/ssi/xilinx_spips.c
@@ -31,6 +31,7 @@
 #include "hw/ssi/xilinx_spips.h"
 #include "qapi/error.h"
 #include "hw/register.h"
+#include "sysemu/dma.h"
 #include "migration/blocker.h"
 
 #ifndef XILINX_SPIPS_ERR_DEBUG
@@ -69,13 +70,30 @@
 #define R_INTR_DIS          (0x0C / 4)
 #define R_INTR_MASK         (0x10 / 4)
 #define IXR_TX_FIFO_UNDERFLOW   (1 << 6)
+/* Poll timeout not implemented */
+#define IXR_RX_FIFO_EMPTY       (1 << 11)
+#define IXR_GENERIC_FIFO_FULL   (1 << 10)
+#define IXR_GENERIC_FIFO_NOT_FULL (1 << 9)
+#define IXR_TX_FIFO_EMPTY       (1 << 8)
+#define IXR_GENERIC_FIFO_EMPTY  (1 << 7)
 #define IXR_RX_FIFO_FULL        (1 << 5)
 #define IXR_RX_FIFO_NOT_EMPTY   (1 << 4)
 #define IXR_TX_FIFO_FULL        (1 << 3)
 #define IXR_TX_FIFO_NOT_FULL    (1 << 2)
 #define IXR_TX_FIFO_MODE_FAIL   (1 << 1)
 #define IXR_RX_FIFO_OVERFLOW    (1 << 0)
-#define IXR_ALL                 ((IXR_TX_FIFO_UNDERFLOW<<1)-1)
+#define IXR_ALL                 ((1 << 13) - 1)
+#define GQSPI_IXR_MASK          0xFBE
+#define IXR_SELF_CLEAR \
+(IXR_GENERIC_FIFO_EMPTY \
+| IXR_GENERIC_FIFO_FULL  \
+| IXR_GENERIC_FIFO_NOT_FULL \
+| IXR_TX_FIFO_EMPTY \
+| IXR_TX_FIFO_FULL  \
+| IXR_TX_FIFO_NOT_FULL \
+| IXR_RX_FIFO_EMPTY \
+| IXR_RX_FIFO_FULL  \
+| IXR_RX_FIFO_NOT_EMPTY)
 
 #define R_EN                (0x14 / 4)
 #define R_DELAY             (0x18 / 4)
@@ -116,9 +134,54 @@
 
 #define R_MOD_ID            (0xFC / 4)
 
+#define R_GQSPI_SELECT          (0x144 / 4)
+    FIELD(GQSPI_SELECT, GENERIC_QSPI_EN, 0, 1)
+#define R_GQSPI_ISR         (0x104 / 4)
+#define R_GQSPI_IER         (0x108 / 4)
+#define R_GQSPI_IDR         (0x10c / 4)
+#define R_GQSPI_IMR         (0x110 / 4)
+#define R_GQSPI_TX_THRESH   (0x128 / 4)
+#define R_GQSPI_RX_THRESH   (0x12c / 4)
+#define R_GQSPI_CNFG        (0x100 / 4)
+    FIELD(GQSPI_CNFG, MODE_EN, 30, 2)
+    FIELD(GQSPI_CNFG, GEN_FIFO_START_MODE, 29, 1)
+    FIELD(GQSPI_CNFG, GEN_FIFO_START, 28, 1)
+    FIELD(GQSPI_CNFG, ENDIAN, 26, 1)
+    /* Poll timeout not implemented */
+    FIELD(GQSPI_CNFG, EN_POLL_TIMEOUT, 20, 1)
+    /* QEMU doesnt care about any of these last three */
+    FIELD(GQSPI_CNFG, BR, 3, 3)
+    FIELD(GQSPI_CNFG, CPH, 2, 1)
+    FIELD(GQSPI_CNFG, CPL, 1, 1)
+#define R_GQSPI_GEN_FIFO        (0x140 / 4)
+#define R_GQSPI_TXD             (0x11c / 4)
+#define R_GQSPI_RXD             (0x120 / 4)
+#define R_GQSPI_FIFO_CTRL       (0x14c / 4)
+    FIELD(GQSPI_FIFO_CTRL, RX_FIFO_RESET, 2, 1)
+    FIELD(GQSPI_FIFO_CTRL, TX_FIFO_RESET, 1, 1)
+    FIELD(GQSPI_FIFO_CTRL, GENERIC_FIFO_RESET, 0, 1)
+#define R_GQSPI_GFIFO_THRESH    (0x150 / 4)
+#define R_GQSPI_DATA_STS (0x15c / 4)
+/* We use the snapshot register to hold the core state for the currently
+ * or most recently executed command. So the generic fifo format is defined
+ * for the snapshot register
+ */
+#define R_GQSPI_GF_SNAPSHOT (0x160 / 4)
+    FIELD(GQSPI_GF_SNAPSHOT, POLL, 19, 1)
+    FIELD(GQSPI_GF_SNAPSHOT, STRIPE, 18, 1)
+    FIELD(GQSPI_GF_SNAPSHOT, RECIEVE, 17, 1)
+    FIELD(GQSPI_GF_SNAPSHOT, TRANSMIT, 16, 1)
+    FIELD(GQSPI_GF_SNAPSHOT, DATA_BUS_SELECT, 14, 2)
+    FIELD(GQSPI_GF_SNAPSHOT, CHIP_SELECT, 12, 2)
+    FIELD(GQSPI_GF_SNAPSHOT, SPI_MODE, 10, 2)
+    FIELD(GQSPI_GF_SNAPSHOT, EXPONENT, 9, 1)
+    FIELD(GQSPI_GF_SNAPSHOT, DATA_XFER, 8, 1)
+    FIELD(GQSPI_GF_SNAPSHOT, IMMEDIATE_DATA, 0, 8)
+#define R_GQSPI_MOD_ID        (0x168 / 4)
+#define R_GQSPI_MOD_ID_VALUE  0x010A0000
 /* size of TXRX FIFOs */
-#define RXFF_A          32
-#define TXFF_A          32
+#define RXFF_A          (128)
+#define TXFF_A          (128)
 
 #define RXFF_A_Q          (64 * 4)
 #define TXFF_A_Q          (64 * 4)
@@ -137,37 +200,54 @@ static inline int num_effective_busses(XilinxSPIPS *s)
             s->regs[R_LQSPI_CFG] & LQSPI_CFG_TWO_MEM) ? s->num_busses : 1;
 }
 
-static inline bool xilinx_spips_cs_is_set(XilinxSPIPS *s, int i, int field)
+static void xilinx_spips_update_cs_lines_legacy(XilinxSPIPS *s, int *field)
 {
-    return ~field & (1 << i) && (s->regs[R_CONFIG] & MANUAL_CS
-                    || !fifo8_is_empty(&s->tx_fifo));
+    *field = ~((s->regs[R_CONFIG] & CS) >> CS_SHIFT);
+    /* In dual parallel, mirror low CS to both */
+    if (num_effective_busses(s) == 2) {
+        /* Single bit chip-select for qspi */
+        *field &= 0x1;
+        *field |= *field << 1;
+    /* Dual stack U-Page */
+    } else if (s->regs[R_LQSPI_CFG] & LQSPI_CFG_TWO_MEM &&
+               s->regs[R_LQSPI_STS] & LQSPI_CFG_U_PAGE) {
+        /* Single bit chip-select for qspi */
+        *field &= 0x1;
+        /* change from CS0 to CS1 */
+        *field <<= 1;
+    }
+    /* Auto CS */
+    if (!(s->regs[R_CONFIG] & MANUAL_CS) &&
+        fifo8_is_empty(&s->tx_fifo)) {
+        *field = 0;
+    }
 }
 
 static void xilinx_spips_update_cs_lines(XilinxSPIPS *s)
 {
-    int i, j;
-    bool found = false;
-    int field = s->regs[R_CONFIG] >> CS_SHIFT;
+    int i;
+    int field = 0;
 
+    if (!ARRAY_FIELD_EX32(s->regs, GQSPI_SELECT, GENERIC_QSPI_EN)) {
+        xilinx_spips_update_cs_lines_legacy(s, &field);
+    } else if (s->regs[R_GQSPI_GF_SNAPSHOT]) {
+        field = ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, CHIP_SELECT);
+    } else {
+        /* Do nothing */
+        return;
+    }
     for (i = 0; i < s->num_cs; i++) {
-        for (j = 0; j < num_effective_busses(s); j++) {
-            int upage = !!(s->regs[R_LQSPI_STS] & LQSPI_CFG_U_PAGE);
-            int cs_to_set = (j * s->num_cs + i + upage) %
-                                (s->num_cs * s->num_busses);
-
-            if (xilinx_spips_cs_is_set(s, i, field) && !found) {
-                DB_PRINT_L(0, "selecting slave %d\n", i);
-                qemu_set_irq(s->cs_lines[cs_to_set], 0);
-            } else {
-                DB_PRINT_L(0, "deselecting slave %d\n", i);
-                qemu_set_irq(s->cs_lines[cs_to_set], 1);
-            }
-        }
-        if (xilinx_spips_cs_is_set(s, i, field)) {
-            found = true;
+        bool old_state = s->cs_lines_state[i];
+        bool new_state = field & (1 << i);
+
+        if (old_state != new_state) {
+            s->cs_lines_state[i] = new_state;
+            s->rx_discard = ARRAY_FIELD_EX32(s->regs, CMND, RX_DISCARD);
+            DB_PRINT_L(0, "%sselecting slave %d\n", new_state ? "" : "de", i);
         }
+        qemu_set_irq(s->cs_lines[i], !new_state);
     }
-    if (!found) {
+    if (!(field & ((1 << s->num_cs) - 1))) {
         s->snoop_state = SNOOP_CHECKING;
         s->cmd_dummies = 0;
         s->link_state = 1;
@@ -179,22 +259,48 @@ static void xilinx_spips_update_cs_lines(XilinxSPIPS *s)
 
 static void xilinx_spips_update_ixr(XilinxSPIPS *s)
 {
-    if (s->regs[R_LQSPI_CFG] & LQSPI_CFG_LQ_MODE) {
-        return;
+    int new_irqline;
+    uint32_t qspi_int, gqspi_int;
+
+    s->regs[R_GQSPI_ISR] &= ~IXR_SELF_CLEAR;
+    s->regs[R_GQSPI_ISR] |=
+        (fifo32_is_empty(&s->fifo_g) ? IXR_GENERIC_FIFO_EMPTY : 0) |
+        (fifo32_is_full(&s->fifo_g) ? IXR_GENERIC_FIFO_FULL : 0) |
+        (s->fifo_g.fifo.num < s->regs[R_GQSPI_GFIFO_THRESH] ?
+                                    IXR_GENERIC_FIFO_NOT_FULL : 0) |
+        (fifo8_is_empty(&s->rx_fifo_g) ? IXR_RX_FIFO_EMPTY : 0) |
+        (fifo8_is_full(&s->rx_fifo_g) ? IXR_RX_FIFO_FULL : 0) |
+        (s->rx_fifo_g.num >= s->regs[R_GQSPI_RX_THRESH] ?
+                                    IXR_RX_FIFO_NOT_EMPTY : 0) |
+        (fifo8_is_empty(&s->tx_fifo_g) ? IXR_TX_FIFO_EMPTY : 0) |
+        (fifo8_is_full(&s->tx_fifo_g) ? IXR_TX_FIFO_FULL : 0) |
+        (s->tx_fifo_g.num < s->regs[R_GQSPI_TX_THRESH] ?
+                                    IXR_TX_FIFO_NOT_FULL : 0);
+
+    if (!(s->regs[R_LQSPI_CFG] & LQSPI_CFG_LQ_MODE)) {
+        s->regs[R_INTR_STATUS] &= ~IXR_SELF_CLEAR;
+        s->regs[R_INTR_STATUS] |=
+            (fifo8_is_full(&s->rx_fifo) ? IXR_RX_FIFO_FULL : 0) |
+            (s->rx_fifo.num >= s->regs[R_RX_THRES] ?
+                                    IXR_RX_FIFO_NOT_EMPTY : 0) |
+            (fifo8_is_full(&s->tx_fifo) ? IXR_TX_FIFO_FULL : 0) |
+            (s->tx_fifo.num < s->regs[R_TX_THRES] ? IXR_TX_FIFO_NOT_FULL : 0);
+        if (object_dynamic_cast(OBJECT(s), TYPE_XLNX_ZYNQMP_QSPIPS)) {
+            s->regs[R_INTR_STATUS] = fifo8_is_empty(&s->tx_fifo) ?
+                                     IXR_TX_FIFO_EMPTY : 0;
+        }
     }
-    /* These are set/cleared as they occur */
-    s->regs[R_INTR_STATUS] &= (IXR_TX_FIFO_UNDERFLOW | IXR_RX_FIFO_OVERFLOW |
-                                IXR_TX_FIFO_MODE_FAIL);
-    /* these are pure functions of fifo state, set them here */
-    s->regs[R_INTR_STATUS] |=
-        (fifo8_is_full(&s->rx_fifo) ? IXR_RX_FIFO_FULL : 0) |
-        (s->rx_fifo.num >= s->regs[R_RX_THRES] ? IXR_RX_FIFO_NOT_EMPTY : 0) |
-        (fifo8_is_full(&s->tx_fifo) ? IXR_TX_FIFO_FULL : 0) |
-        (s->tx_fifo.num < s->regs[R_TX_THRES] ? IXR_TX_FIFO_NOT_FULL : 0);
+
+    /* QSPI/SPI Interrupt Trigger Status */
+    qspi_int = s->regs[R_INTR_MASK] & s->regs[R_INTR_STATUS];
+    /* GQSPI Interrupt Trigger Status */
+    gqspi_int = (~s->regs[R_GQSPI_IMR]) & s->regs[R_GQSPI_ISR] &
+                   GQSPI_IXR_MASK;
     /* drive external interrupt pin */
-    int new_irqline = !!(s->regs[R_INTR_MASK] & s->regs[R_INTR_STATUS] &
-                                                                IXR_ALL);
+    new_irqline = !!((qspi_int | gqspi_int) & IXR_ALL);
     if (new_irqline != s->irqline) {
+        DB_PRINT_L(0, "IRQ state is changing %" PRIx32 " -> %" PRIx32 "\n",
+                   s->irqline, new_irqline);
         s->irqline = new_irqline;
         qemu_set_irq(s->irq, s->irqline);
     }
@@ -211,11 +317,18 @@ static void xilinx_spips_reset(DeviceState *d)
 
     fifo8_reset(&s->rx_fifo);
     fifo8_reset(&s->rx_fifo);
+    fifo8_reset(&s->rx_fifo_g);
+    fifo8_reset(&s->rx_fifo_g);
+    fifo32_reset(&s->fifo_g);
     /* non zero resets */
     s->regs[R_CONFIG] |= MODEFAIL_GEN_EN;
     s->regs[R_SLAVE_IDLE_COUNT] = 0xFF;
     s->regs[R_TX_THRES] = 1;
     s->regs[R_RX_THRES] = 1;
+    s->regs[R_GQSPI_TX_THRESH] = 1;
+    s->regs[R_GQSPI_RX_THRESH] = 1;
+    s->regs[R_GQSPI_GFIFO_THRESH] = 1;
+    s->regs[R_GQSPI_IMR] = GQSPI_IXR_MASK;
     /* FIXME: move magic number definition somewhere sensible */
     s->regs[R_MOD_ID] = 0x01090106;
     s->regs[R_LQSPI_CFG] = R_LQSPI_CFG_RESET;
@@ -225,6 +338,7 @@ static void xilinx_spips_reset(DeviceState *d)
     s->snoop_state = SNOOP_CHECKING;
     s->cmd_dummies = 0;
     s->man_start_com = false;
+    s->man_start_com_g = false;
     xilinx_spips_update_ixr(s);
     xilinx_spips_update_cs_lines(s);
 }
@@ -259,6 +373,112 @@ static inline void stripe8(uint8_t *x, int num, bool dir)
     memcpy(x, r, sizeof(uint8_t) * num);
 }
 
+static void xilinx_spips_flush_fifo_g(XilinxSPIPS *s)
+{
+    while (s->regs[R_GQSPI_DATA_STS] || !fifo32_is_empty(&s->fifo_g)) {
+        uint8_t tx_rx[2] = { 0 };
+        int num_stripes = 1;
+        uint8_t busses;
+        int i;
+
+        if (!s->regs[R_GQSPI_DATA_STS]) {
+            uint8_t imm;
+
+            s->regs[R_GQSPI_GF_SNAPSHOT] = fifo32_pop(&s->fifo_g);
+            DB_PRINT_L(0, "Popped GQSPI command %" PRIx32 "\n",
+                       s->regs[R_GQSPI_GF_SNAPSHOT]);
+            if (!s->regs[R_GQSPI_GF_SNAPSHOT]) {
+                DB_PRINT_L(0, "Dummy GQSPI Delay Command Entry, Do nothing");
+                continue;
+            }
+            xilinx_spips_update_cs_lines(s);
+
+            imm = ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, IMMEDIATE_DATA);
+            if (!ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, DATA_XFER)) {
+                /* immedate transfer */
+                if (ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, TRANSMIT) ||
+                    ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, RECIEVE)) {
+                    s->regs[R_GQSPI_DATA_STS] = 1;
+                /* CS setup/hold - do nothing */
+                } else {
+                    s->regs[R_GQSPI_DATA_STS] = 0;
+                }
+            } else if (ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, EXPONENT)) {
+                if (imm > 31) {
+                    qemu_log_mask(LOG_UNIMP, "QSPI exponential transfer too"
+                                  " long - 2 ^ %" PRId8 " requested\n", imm);
+                }
+                s->regs[R_GQSPI_DATA_STS] = 1ul << imm;
+            } else {
+                s->regs[R_GQSPI_DATA_STS] = imm;
+            }
+        }
+        /* Zero length transfer check */
+        if (!s->regs[R_GQSPI_DATA_STS]) {
+            continue;
+        }
+        if (ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, RECIEVE) &&
+            fifo8_is_full(&s->rx_fifo_g)) {
+            /* No space in RX fifo for transfer - try again later */
+            return;
+        }
+        if (ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, STRIPE) &&
+            (ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, TRANSMIT) ||
+             ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, RECIEVE))) {
+            num_stripes = 2;
+        }
+        if (!ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, DATA_XFER)) {
+            tx_rx[0] = ARRAY_FIELD_EX32(s->regs,
+                                        GQSPI_GF_SNAPSHOT, IMMEDIATE_DATA);
+        } else if (ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, TRANSMIT)) {
+            for (i = 0; i < num_stripes; ++i) {
+                if (!fifo8_is_empty(&s->tx_fifo_g)) {
+                    tx_rx[i] = fifo8_pop(&s->tx_fifo_g);
+                    s->tx_fifo_g_align++;
+                } else {
+                    return;
+                }
+            }
+        }
+        if (num_stripes == 1) {
+            /* mirror */
+            tx_rx[1] = tx_rx[0];
+        }
+        busses = ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, DATA_BUS_SELECT);
+        for (i = 0; i < 2; ++i) {
+            DB_PRINT_L((busses & (1 << i)) ? 1 : 0,
+                        "bus %d tx = %02x\n", i, tx_rx[i]);
+            tx_rx[i] = ssi_transfer(s->spi[i], tx_rx[i]);
+            DB_PRINT_L((busses & (1 << i)) ? 1 : 0,
+                        "bus %d rx = %02x\n", i, tx_rx[i]);
+        }
+        if (s->regs[R_GQSPI_DATA_STS] > 1 &&
+            busses == 0x3 && num_stripes == 2) {
+            s->regs[R_GQSPI_DATA_STS] -= 2;
+        } else if (s->regs[R_GQSPI_DATA_STS] > 0) {
+            s->regs[R_GQSPI_DATA_STS]--;
+        }
+        if (ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, RECIEVE)) {
+            for (i = 0; i < 2; ++i) {
+                if (busses & (1 << i)) {
+                    DB_PRINT_L(1, "bus %d push_byte = %02x\n",
+                               i, tx_rx[i]);
+                   fifo8_push(&s->rx_fifo_g, tx_rx[i]);
+                   s->rx_fifo_g_align++;
+                }
+            }
+        }
+        if (!s->regs[R_GQSPI_DATA_STS]) {
+            for (; s->tx_fifo_g_align % 4; s->tx_fifo_g_align++) {
+                fifo8_pop(&s->tx_fifo_g);
+            }
+            for (; s->rx_fifo_g_align % 4; s->rx_fifo_g_align++) {
+                fifo8_push(&s->rx_fifo_g, 0);
+            }
+        }
+    }
+}
+
 static int xilinx_spips_num_dummies(XilinxQSPIPS *qs, uint8_t command)
 {
     if (!qs) {
@@ -482,15 +702,27 @@ static void xilinx_spips_check_zero_pump(XilinxSPIPS *s)
 
 static void xilinx_spips_check_flush(XilinxSPIPS *s)
 {
-    if (s->man_start_com ||
-        (!fifo8_is_empty(&s->tx_fifo) &&
-         !(s->regs[R_CONFIG] & MAN_START_EN))) {
-        xilinx_spips_check_zero_pump(s);
-        xilinx_spips_flush_txfifo(s);
+    bool gqspi_has_work = s->regs[R_GQSPI_DATA_STS] ||
+                          !fifo32_is_empty(&s->fifo_g);
+
+    if (ARRAY_FIELD_EX32(s->regs, GQSPI_SELECT, GENERIC_QSPI_EN)) {
+        if (s->man_start_com_g || (gqspi_has_work &&
+             !ARRAY_FIELD_EX32(s->regs, GQSPI_CNFG, GEN_FIFO_START_MODE))) {
+            xilinx_spips_flush_fifo_g(s);
+        }
+    } else {
+        if (s->man_start_com || (!fifo8_is_empty(&s->tx_fifo) &&
+             !(s->regs[R_CONFIG] & MAN_START_EN))) {
+            xilinx_spips_check_zero_pump(s);
+            xilinx_spips_flush_txfifo(s);
+        }
     }
     if (fifo8_is_empty(&s->tx_fifo) && !s->regs[R_TRANSFER_SIZE]) {
         s->man_start_com = false;
     }
+    if (!gqspi_has_work) {
+        s->man_start_com_g = false;
+    }
     xilinx_spips_update_ixr(s);
 }
 
@@ -504,6 +736,53 @@ static inline int rx_data_bytes(Fifo8 *fifo, uint8_t *value, int max)
     return max - i;
 }
 
+static const void *pop_buf(Fifo8 *fifo, uint32_t max, uint32_t *num)
+{
+    void *ret;
+
+    if (max == 0 || max > fifo->num) {
+        abort();
+    }
+    *num = MIN(fifo->capacity - fifo->head, max);
+    ret = &fifo->data[fifo->head];
+    fifo->head += *num;
+    fifo->head %= fifo->capacity;
+    fifo->num -= *num;
+    return ret;
+}
+
+static void xlnx_zynqmp_qspips_notify(void *opaque)
+{
+    XlnxZynqMPQSPIPS *rq = XLNX_ZYNQMP_QSPIPS(opaque);
+    XilinxSPIPS *s = XILINX_SPIPS(rq);
+    Fifo8 *recv_fifo;
+
+    if (ARRAY_FIELD_EX32(s->regs, GQSPI_SELECT, GENERIC_QSPI_EN)) {
+        if (!(ARRAY_FIELD_EX32(s->regs, GQSPI_CNFG, MODE_EN) == 2)) {
+            return;
+        }
+        recv_fifo = &s->rx_fifo_g;
+    } else {
+        if (!(s->regs[R_CMND] & R_CMND_DMA_EN)) {
+            return;
+        }
+        recv_fifo = &s->rx_fifo;
+    }
+    while (recv_fifo->num >= 4
+           && stream_can_push(rq->dma, xlnx_zynqmp_qspips_notify, rq))
+    {
+        size_t ret;
+        uint32_t num;
+        const void *rxd = pop_buf(recv_fifo, 4, &num);
+
+        memcpy(rq->dma_buf, rxd, num);
+
+        ret = stream_push(rq->dma, rq->dma_buf, 4);
+        assert(ret == 4);
+        xilinx_spips_check_flush(s);
+    }
+}
+
 static uint64_t xilinx_spips_read(void *opaque, hwaddr addr,
                                                         unsigned size)
 {
@@ -551,6 +830,23 @@ static uint64_t xilinx_spips_read(void *opaque, hwaddr addr,
             ret <<= 8 * shortfall;
         }
         DB_PRINT_L(0, "addr=" TARGET_FMT_plx " = %x\n", addr * 4, ret);
+        xilinx_spips_check_flush(s);
+        xilinx_spips_update_ixr(s);
+        return ret;
+    case R_GQSPI_RXD:
+        if (fifo8_is_empty(&s->rx_fifo_g)) {
+            qemu_log_mask(LOG_GUEST_ERROR, "Read from empty GQSPI RX FIFO\n");
+            return 0;
+        }
+        memset(rx_buf, 0, sizeof(rx_buf));
+        shortfall = rx_data_bytes(&s->rx_fifo_g, rx_buf, s->num_txrx_bytes);
+        ret = ARRAY_FIELD_EX32(s->regs, GQSPI_CNFG, ENDIAN) ?
+              cpu_to_be32(*(uint32_t *)rx_buf) :
+              cpu_to_le32(*(uint32_t *)rx_buf);
+        if (!ARRAY_FIELD_EX32(s->regs, GQSPI_CNFG, ENDIAN)) {
+            ret <<= 8 * shortfall;
+        }
+        xilinx_spips_check_flush(s);
         xilinx_spips_update_ixr(s);
         return ret;
     }
@@ -614,6 +910,49 @@ static void xilinx_spips_write(void *opaque, hwaddr addr,
         tx_data_bytes(&s->tx_fifo, (uint32_t)value, 3,
                       s->regs[R_CONFIG] & R_CONFIG_ENDIAN);
         goto no_reg_update;
+    case R_GQSPI_CNFG:
+        mask = ~(R_GQSPI_CNFG_GEN_FIFO_START_MASK);
+        if (FIELD_EX32(value, GQSPI_CNFG, GEN_FIFO_START) &&
+            ARRAY_FIELD_EX32(s->regs, GQSPI_CNFG, GEN_FIFO_START_MODE)) {
+            s->man_start_com_g = true;
+        }
+        break;
+    case R_GQSPI_GEN_FIFO:
+        if (!fifo32_is_full(&s->fifo_g)) {
+            fifo32_push(&s->fifo_g, value);
+        }
+        goto no_reg_update;
+    case R_GQSPI_TXD:
+        tx_data_bytes(&s->tx_fifo_g, (uint32_t)value, 4,
+                      ARRAY_FIELD_EX32(s->regs, GQSPI_CNFG, ENDIAN));
+        goto no_reg_update;
+    case R_GQSPI_FIFO_CTRL:
+        mask = 0;
+        if (FIELD_EX32(value, GQSPI_FIFO_CTRL, GENERIC_FIFO_RESET)) {
+            fifo32_reset(&s->fifo_g);
+        }
+        if (FIELD_EX32(value, GQSPI_FIFO_CTRL, TX_FIFO_RESET)) {
+            fifo8_reset(&s->tx_fifo_g);
+        }
+        if (FIELD_EX32(value, GQSPI_FIFO_CTRL, RX_FIFO_RESET)) {
+            fifo8_reset(&s->rx_fifo_g);
+        }
+        break;
+    case R_GQSPI_IDR:
+        s->regs[R_GQSPI_IMR] |= value;
+        goto no_reg_update;
+    case R_GQSPI_IER:
+        s->regs[R_GQSPI_IMR] &= ~value;
+        goto no_reg_update;
+    case R_GQSPI_ISR:
+        s->regs[R_GQSPI_ISR] &= ~value;
+        goto no_reg_update;
+    case R_GQSPI_IMR:
+    case R_GQSPI_RXD:
+    case R_GQSPI_GF_SNAPSHOT:
+    case R_GQSPI_MOD_ID:
+        mask = 0;
+        break;
     }
     s->regs[addr] = (s->regs[addr] & ~mask) | (value & mask);
 no_reg_update:
@@ -657,6 +996,9 @@ static void xilinx_qspips_write(void *opaque, hwaddr addr,
     if (s->regs[R_CMND] & R_CMND_RXFIFO_DRAIN) {
         fifo8_reset(&s->rx_fifo);
     }
+    if (object_dynamic_cast(OBJECT(s), TYPE_XLNX_ZYNQMP_QSPIPS)) {
+        xlnx_zynqmp_qspips_notify(s);
+    }
 }
 
 static const MemoryRegionOps qspips_ops = {
@@ -802,6 +1144,7 @@ static void xilinx_spips_realize(DeviceState *dev, Error **errp)
     }
 
     s->cs_lines = g_new0(qemu_irq, s->num_cs * s->num_busses);
+    s->cs_lines_state = g_new0(bool, s->num_cs * s->num_busses);
     for (i = 0, cs = s->cs_lines; i < s->num_busses; ++i, cs += s->num_cs) {
         ssi_auto_connect_slaves(DEVICE(s), cs, s->spi[i]);
     }
@@ -819,6 +1162,9 @@ static void xilinx_spips_realize(DeviceState *dev, Error **errp)
 
     fifo8_create(&s->rx_fifo, xsc->rx_fifo_size);
     fifo8_create(&s->tx_fifo, xsc->tx_fifo_size);
+    fifo8_create(&s->rx_fifo_g, xsc->rx_fifo_size);
+    fifo8_create(&s->tx_fifo_g, xsc->tx_fifo_size);
+    fifo32_create(&s->fifo_g, 32);
 }
 
 static void xilinx_qspips_realize(DeviceState *dev, Error **errp)
@@ -850,6 +1196,17 @@ static void xilinx_qspips_realize(DeviceState *dev, Error **errp)
     }
 }
 
+static void xlnx_zynqmp_qspips_init(Object *obj)
+{
+    XlnxZynqMPQSPIPS *rq = XLNX_ZYNQMP_QSPIPS(obj);
+
+    object_property_add_link(obj, "stream-connected-dma", TYPE_STREAM_SLAVE,
+                             (Object **)&rq->dma,
+                             object_property_allow_set_link,
+                             OBJ_PROP_LINK_UNREF_ON_RELEASE,
+                             NULL);
+}
+
 static int xilinx_spips_post_load(void *opaque, int version_id)
 {
     xilinx_spips_update_ixr((XilinxSPIPS *)opaque);
@@ -930,10 +1287,18 @@ static const TypeInfo xilinx_qspips_info = {
     .class_init = xilinx_qspips_class_init,
 };
 
+static const TypeInfo xlnx_zynqmp_qspips_info = {
+    .name  = TYPE_XLNX_ZYNQMP_QSPIPS,
+    .parent = TYPE_XILINX_QSPIPS,
+    .instance_size  = sizeof(XlnxZynqMPQSPIPS),
+    .instance_init = xlnx_zynqmp_qspips_init,
+};
+
 static void xilinx_spips_register_types(void)
 {
     type_register_static(&xilinx_spips_info);
     type_register_static(&xilinx_qspips_info);
+    type_register_static(&xlnx_zynqmp_qspips_info);
 }
 
 type_init(xilinx_spips_register_types)
diff --git a/include/hw/ssi/xilinx_spips.h b/include/hw/ssi/xilinx_spips.h
index df6e245..35f6a6f 100644
--- a/include/hw/ssi/xilinx_spips.h
+++ b/include/hw/ssi/xilinx_spips.h
@@ -26,11 +26,12 @@
 #define XILINX_SPIPS_H
 
 #include "hw/ssi/ssi.h"
-#include "qemu/fifo8.h"
+#include "qemu/fifo32.h"
+#include "hw/stream.h"
 
 typedef struct XilinxSPIPS XilinxSPIPS;
 
-#define XLNX_SPIPS_R_MAX        (0x100 / 4)
+#define XLNX_SPIPS_R_MAX        0x200
 
 /* Bite off 4k chunks at a time */
 #define LQSPI_CACHE_SIZE 1024
@@ -66,10 +67,23 @@ struct XilinxSPIPS {
     uint8_t link_state_next;
     uint8_t link_state_next_when;
     qemu_irq *cs_lines;
+    bool *cs_lines_state;
     SSIBus **spi;
 
     Fifo8 rx_fifo;
     Fifo8 tx_fifo;
+    /* GQSPI has seperate tx/rx fifos */
+    Fifo8 rx_fifo_g;
+    Fifo8 tx_fifo_g;
+    Fifo32 fifo_g;
+    /*
+     * at the end of each generic command, misaligned extra bytes are discard
+     * or padded to tx and rx respectively to round it out (and avoid need for
+     * individual byte access. Since we use byte fifos, keep track of the
+     * alignment WRT to word access.
+     */
+    uint8_t rx_fifo_g_align;
+    uint8_t tx_fifo_g_align;
 
     uint8_t num_txrx_bytes;
     uint32_t rx_discard;
@@ -77,6 +91,7 @@ struct XilinxSPIPS {
     uint32_t regs[XLNX_SPIPS_R_MAX];
 
     bool man_start_com;
+    bool man_start_com_g;
 };
 
 typedef struct {
@@ -88,6 +103,13 @@ typedef struct {
     bool mmio_execution_enabled;
 } XilinxQSPIPS;
 
+typedef struct {
+    XilinxQSPIPS parent_obj;
+
+    StreamSlave *dma;
+    uint8_t dma_buf[4];
+} XlnxZynqMPQSPIPS;
+
 typedef struct XilinxSPIPSClass {
     SysBusDeviceClass parent_class;
 
@@ -99,6 +121,7 @@ typedef struct XilinxSPIPSClass {
 
 #define TYPE_XILINX_SPIPS "xlnx.ps7-spi"
 #define TYPE_XILINX_QSPIPS "xlnx.ps7-qspi"
+#define TYPE_XLNX_ZYNQMP_QSPIPS "xlnx.usmp-gqspi"
 
 #define XILINX_SPIPS(obj) \
      OBJECT_CHECK(XilinxSPIPS, (obj), TYPE_XILINX_SPIPS)
@@ -110,4 +133,7 @@ typedef struct XilinxSPIPSClass {
 #define XILINX_QSPIPS(obj) \
      OBJECT_CHECK(XilinxQSPIPS, (obj), TYPE_XILINX_QSPIPS)
 
+#define XLNX_ZYNQMP_QSPIPS(obj) \
+     OBJECT_CHECK(XlnxZynqMPQSPIPS, (obj), TYPE_XLNX_ZYNQMP_QSPIPS)
+
 #endif /* XILINX_SPIPS_H */
-- 
2.9.3

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

* [Qemu-devel] [PATCH v3 13/13] xlnx-zcu102: Add support for the ZynqMP QSPI
  2017-10-24 19:51 [Qemu-devel] [PATCH v3 00/13] Add support for the ZynqMP Generic QSPI Francisco Iglesias
                   ` (9 preceding siblings ...)
  2017-10-24 19:51 ` [Qemu-devel] [PATCH v3 12/13] xilinx_spips: Add support for the ZynqMP Generic QSPI Francisco Iglesias
@ 2017-10-24 19:51 ` Francisco Iglesias
  2017-10-24 20:04 ` [Qemu-devel] [PATCH v3 09/13] xilinx_spips: Add support for zero pumping Francisco Iglesias
  2017-11-02 23:59 ` [Qemu-devel] [PATCH v7 " Francisco Iglesias
  12 siblings, 0 replies; 19+ messages in thread
From: Francisco Iglesias @ 2017-10-24 19:51 UTC (permalink / raw)
  To: qemu-devel; +Cc: edgari, alistai, francisco.iglesias

Add support for the ZynqMP QSPI (consisting of the Generic QSPI and Legacy
QSPI) and connect Numonyx n25q512a11 flashes to it.

Signed-off-by: Francisco Iglesias <frasse.iglesias@gmail.com>
---
 hw/arm/xlnx-zcu102.c         | 23 +++++++++++++++++++++++
 hw/arm/xlnx-zynqmp.c         | 24 ++++++++++++++++++++++++
 include/hw/arm/xlnx-zynqmp.h |  5 +++++
 3 files changed, 52 insertions(+)

diff --git a/hw/arm/xlnx-zcu102.c b/hw/arm/xlnx-zcu102.c
index 519a16e..7d61972 100644
--- a/hw/arm/xlnx-zcu102.c
+++ b/hw/arm/xlnx-zcu102.c
@@ -150,6 +150,29 @@ static void xlnx_zynqmp_init(XlnxZCU102 *s, MachineState *machine)
         sysbus_connect_irq(SYS_BUS_DEVICE(&s->soc.spi[i]), 1, cs_line);
     }
 
+    for (i = 0; i < XLNX_ZYNQMP_NUM_QSPI_FLASH; i++) {
+        SSIBus *spi_bus;
+        DeviceState *flash_dev;
+        qemu_irq cs_line;
+        DriveInfo *dinfo = drive_get_next(IF_MTD);
+        int bus = i / XLNX_ZYNQMP_NUM_QSPI_BUS_CS;
+        gchar *bus_name = g_strdup_printf("qspi%d", bus);
+
+        spi_bus = (SSIBus *)qdev_get_child_bus(DEVICE(&s->soc), bus_name);
+        g_free(bus_name);
+
+        flash_dev = ssi_create_slave_no_init(spi_bus, "n25q512a11");
+        if (dinfo) {
+            qdev_prop_set_drive(flash_dev, "drive", blk_by_legacy_dinfo(dinfo),
+                                &error_fatal);
+        }
+        qdev_init_nofail(flash_dev);
+
+        cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0);
+
+        sysbus_connect_irq(SYS_BUS_DEVICE(&s->soc.qspi), i + 1, cs_line);
+    }
+
     /* TODO create and connect IDE devices for ide_drive_get() */
 
     xlnx_zcu102_binfo.ram_size = ram_size;
diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c
index d4b6560..f7c8b4b 100644
--- a/hw/arm/xlnx-zynqmp.c
+++ b/hw/arm/xlnx-zynqmp.c
@@ -40,6 +40,10 @@
 #define SATA_ADDR           0xFD0C0000
 #define SATA_NUM_PORTS      2
 
+#define QSPI_ADDR           0xff0f0000
+#define LQSPI_ADDR          0xc0000000
+#define QSPI_IRQ            15
+
 #define DP_ADDR             0xfd4a0000
 #define DP_IRQ              113
 
@@ -169,6 +173,9 @@ static void xlnx_zynqmp_init(Object *obj)
         qdev_set_parent_bus(DEVICE(&s->spi[i]), sysbus_get_default());
     }
 
+    object_initialize(&s->qspi, sizeof(s->qspi), TYPE_XLNX_ZYNQMP_QSPIPS);
+    qdev_set_parent_bus(DEVICE(&s->qspi), sysbus_get_default());
+
     object_initialize(&s->dp, sizeof(s->dp), TYPE_XLNX_DP);
     qdev_set_parent_bus(DEVICE(&s->dp), sysbus_get_default());
 
@@ -405,6 +412,23 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
         g_free(bus_name);
     }
 
+    object_property_set_bool(OBJECT(&s->qspi), true, "realized", &err);
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->qspi), 0, QSPI_ADDR);
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->qspi), 1, LQSPI_ADDR);
+    sysbus_connect_irq(SYS_BUS_DEVICE(&s->qspi), 0, gic_spi[QSPI_IRQ]);
+    for (i = 0; i < XLNX_ZYNQMP_NUM_QSPI_BUS; i++) {
+        gchar *bus_name;
+        gchar *target_bus;
+        /* Alias controller SPI bus to the SoC itself */
+        bus_name = g_strdup_printf("qspi%d", i);
+        target_bus = g_strdup_printf("spi%d", i);
+        object_property_add_alias(OBJECT(s), bus_name,
+                                  OBJECT(&s->qspi), target_bus,
+                                  &error_abort);
+        g_free(bus_name);
+        g_free(target_bus);
+    }
+
     object_property_set_bool(OBJECT(&s->dp), true, "realized", &err);
     if (err) {
         error_propagate(errp, err);
diff --git a/include/hw/arm/xlnx-zynqmp.h b/include/hw/arm/xlnx-zynqmp.h
index 6eff81a..3e6fb9b 100644
--- a/include/hw/arm/xlnx-zynqmp.h
+++ b/include/hw/arm/xlnx-zynqmp.h
@@ -40,6 +40,10 @@
 #define XLNX_ZYNQMP_NUM_SDHCI 2
 #define XLNX_ZYNQMP_NUM_SPIS 2
 
+#define XLNX_ZYNQMP_NUM_QSPI_BUS 2
+#define XLNX_ZYNQMP_NUM_QSPI_BUS_CS 2
+#define XLNX_ZYNQMP_NUM_QSPI_FLASH 4
+
 #define XLNX_ZYNQMP_NUM_OCM_BANKS 4
 #define XLNX_ZYNQMP_OCM_RAM_0_ADDRESS 0xFFFC0000
 #define XLNX_ZYNQMP_OCM_RAM_SIZE 0x10000
@@ -83,6 +87,7 @@ typedef struct XlnxZynqMPState {
     SysbusAHCIState sata;
     SDHCIState sdhci[XLNX_ZYNQMP_NUM_SDHCI];
     XilinxSPIPS spi[XLNX_ZYNQMP_NUM_SPIS];
+    XlnxZynqMPQSPIPS qspi;
     XlnxDPState dp;
     XlnxDPDMAState dpdma;
 
-- 
2.9.3

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

* [Qemu-devel] [PATCH v3 09/13] xilinx_spips: Add support for zero pumping
  2017-10-24 19:51 [Qemu-devel] [PATCH v3 00/13] Add support for the ZynqMP Generic QSPI Francisco Iglesias
                   ` (10 preceding siblings ...)
  2017-10-24 19:51 ` [Qemu-devel] [PATCH v3 13/13] xlnx-zcu102: Add support for the ZynqMP QSPI Francisco Iglesias
@ 2017-10-24 20:04 ` Francisco Iglesias
  2017-11-02 23:59 ` [Qemu-devel] [PATCH v7 " Francisco Iglesias
  12 siblings, 0 replies; 19+ messages in thread
From: Francisco Iglesias @ 2017-10-24 20:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: edgari, alistai, francisco.iglesias

Add support for zero pumping according to the transfer size register.

Signed-off-by: Francisco Iglesias <frasse.iglesias@gmail.com>
---
 hw/ssi/xilinx_spips.c         | 47 ++++++++++++++++++++++++++++++++++++-------
 include/hw/ssi/xilinx_spips.h |  2 ++
 2 files changed, 42 insertions(+), 7 deletions(-)

diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
index ad9f1a0..df5d908 100644
--- a/hw/ssi/xilinx_spips.c
+++ b/hw/ssi/xilinx_spips.c
@@ -109,6 +109,7 @@
     FIELD(CMND, DUMMY_CYCLES, 2, 6)
 #define R_CMND_DMA_EN         (1 << 1)
 #define R_CMND_PUSH_WAIT      (1 << 0)
+#define R_TRANSFER_SIZE     (0xc4 / 4)
 #define R_LQSPI_STS         (0xA4 / 4)
 #define LQSPI_STS_WR_RECVD      (1 << 1)
 
@@ -222,6 +223,7 @@ static void xilinx_spips_reset(DeviceState *d)
     s->link_state_next_when = 0;
     s->snoop_state = SNOOP_CHECKING;
     s->cmd_dummies = 0;
+    s->man_start_com = false;
     xilinx_spips_update_ixr(s);
     xilinx_spips_update_cs_lines(s);
 }
@@ -459,6 +461,41 @@ static inline void tx_data_bytes(Fifo8 *fifo, uint32_t value, int num, bool be)
     }
 }
 
+static void xilinx_spips_check_zero_pump(XilinxSPIPS *s)
+{
+    if (!s->regs[R_TRANSFER_SIZE]) {
+        return;
+    }
+    if (!fifo8_is_empty(&s->tx_fifo) && s->regs[R_CMND] & R_CMND_PUSH_WAIT) {
+        return;
+    }
+    /*
+     * The zero pump must never fill tx fifo such that rx overflow is
+     * possible
+     */
+    while (s->regs[R_TRANSFER_SIZE] &&
+           s->rx_fifo.num + s->tx_fifo.num < RXFF_A_Q - 3) {
+        /* endianess just doesn't matter when zero pumping */
+        tx_data_bytes(&s->tx_fifo, 0, 4, false);
+        s->regs[R_TRANSFER_SIZE] &= ~0x03ull;
+        s->regs[R_TRANSFER_SIZE] -= 4;
+    }
+}
+
+static void xilinx_spips_check_flush(XilinxSPIPS *s)
+{
+    if (s->man_start_com ||
+        (!fifo8_is_empty(&s->tx_fifo) &&
+         !(s->regs[R_CONFIG] & MAN_START_EN))) {
+        xilinx_spips_check_zero_pump(s);
+        xilinx_spips_flush_txfifo(s);
+    }
+    if (fifo8_is_empty(&s->tx_fifo) && !s->regs[R_TRANSFER_SIZE]) {
+        s->man_start_com = false;
+    }
+    xilinx_spips_update_ixr(s);
+}
+
 static inline int rx_data_bytes(Fifo8 *fifo, uint8_t *value, int max)
 {
     int i;
@@ -528,7 +565,6 @@ static void xilinx_spips_write(void *opaque, hwaddr addr,
                                         uint64_t value, unsigned size)
 {
     int mask = ~0;
-    int man_start_com = 0;
     XilinxSPIPS *s = opaque;
 
     DB_PRINT_L(0, "addr=" TARGET_FMT_plx " = %x\n", addr, (unsigned)value);
@@ -536,8 +572,8 @@ static void xilinx_spips_write(void *opaque, hwaddr addr,
     switch (addr) {
     case R_CONFIG:
         mask = ~(R_CONFIG_RSVD | MAN_START_COM);
-        if (value & MAN_START_COM) {
-            man_start_com = 1;
+        if ((value & MAN_START_COM) && (s->regs[R_CONFIG] & MAN_START_EN)) {
+            s->man_start_com = true;
         }
         break;
     case R_INTR_STATUS:
@@ -583,10 +619,7 @@ static void xilinx_spips_write(void *opaque, hwaddr addr,
     s->regs[addr] = (s->regs[addr] & ~mask) | (value & mask);
 no_reg_update:
     xilinx_spips_update_cs_lines(s);
-    if ((man_start_com && s->regs[R_CONFIG] & MAN_START_EN) ||
-            (fifo8_is_empty(&s->tx_fifo) && s->regs[R_CONFIG] & MAN_START_EN)) {
-        xilinx_spips_flush_txfifo(s);
-    }
+    xilinx_spips_check_flush(s);
     xilinx_spips_update_cs_lines(s);
     xilinx_spips_update_ixr(s);
 }
diff --git a/include/hw/ssi/xilinx_spips.h b/include/hw/ssi/xilinx_spips.h
index 036f86f..df6e245 100644
--- a/include/hw/ssi/xilinx_spips.h
+++ b/include/hw/ssi/xilinx_spips.h
@@ -75,6 +75,8 @@ struct XilinxSPIPS {
     uint32_t rx_discard;
 
     uint32_t regs[XLNX_SPIPS_R_MAX];
+
+    bool man_start_com;
 };
 
 typedef struct {
-- 
2.9.3

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

* Re: [Qemu-devel] [PATCH v3 03/13] m25p80: Add support for BRRD/BRWR and BULK_ERASE (0x60)
  2017-10-24 19:51 ` [Qemu-devel] [PATCH v3 03/13] m25p80: Add support for BRRD/BRWR and BULK_ERASE (0x60) Francisco Iglesias
@ 2017-10-25 14:55   ` mar.krzeminski
  0 siblings, 0 replies; 19+ messages in thread
From: mar.krzeminski @ 2017-10-25 14:55 UTC (permalink / raw)
  To: Francisco Iglesias, qemu-devel; +Cc: edgari, alistai, francisco.iglesias



W dniu 24.10.2017 o 21:51, Francisco Iglesias pisze:
> Add support for the bank address register access commands (BRRD/BRWR) and
> the BULK_ERASE (0x60) command.
>
> Signed-off-by: Francisco Iglesias <frasse.iglesias@gmail.com>
> ---
>   hw/block/m25p80.c | 20 ++++++++++++++++++++
>   1 file changed, 20 insertions(+)
>
> diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
> index c85e8fa..3d2975c 100644
> --- a/hw/block/m25p80.c
> +++ b/hw/block/m25p80.c
> @@ -331,6 +331,8 @@ typedef enum {
>       WRDI = 0x4,
>       RDSR = 0x5,
>       WREN = 0x6,
> +    BRRD = 0x16,
> +    BRWR = 0x17,
Above commands look to be equivalent to 
EXTEND_ADDR_READ/EXTEND_ADDR_WRITE from Micron.
IMO both could fall in the same case block.

>       JEDEC_READ = 0x9f,
>       BULK_ERASE = 0xc7,
>       READ_FSR = 0x70,
> @@ -368,6 +370,8 @@ typedef enum {
>       EN_4BYTE_ADDR = 0xB7,
>       EX_4BYTE_ADDR = 0xE9,
>   
> +    BULK_ERASE_60 = 0x60,
> +
>       EXTEND_ADDR_READ = 0xC8,
>       EXTEND_ADDR_WRITE = 0xC5,
>   
> @@ -975,6 +979,15 @@ static void decode_new_cmd(Flash *s, uint32_t value)
>           }
>           break;
>   
> +    case BRWR:
> +        if (s->write_enable) {
> +            s->needed_bytes = 1;
> +            s->pos = 0;
> +            s->len = 0;
> +            s->state = STATE_COLLECTING_DATA;
> +        }
> +        break;
> +
>       case WRDI:
>           s->write_enable = false;
>           break;
> @@ -1004,6 +1017,12 @@ static void decode_new_cmd(Flash *s, uint32_t value)
>           s->state = STATE_READING_DATA;
>           break;
>   
> +    case BRRD:
> +        s->pos = 0;
> +        s->len = 1;
> +        s->state = STATE_READING_DATA;
> +        break;
> +
I can not see any code where you are actually filling the register 
value. s->ear could be used for that as well.
>       case JEDEC_READ:
>           DB_PRINT_L(0, "populated jedec code\n");
>           for (i = 0; i < s->pi->id_len; i++) {
> @@ -1038,6 +1057,7 @@ static void decode_new_cmd(Flash *s, uint32_t value)
>           }
>           break;
>   
> +    case BULK_ERASE_60:
>       case BULK_ERASE:
>           if (s->write_enable) {
>               DB_PRINT_L(0, "chip erase\n");
Regards,
Marcin

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

* Re: [Qemu-devel] [PATCH v3 04/13] m25p80: Add support for n25q512a11 and n25q512a13
  2017-10-24 19:51 ` [Qemu-devel] [PATCH v3 04/13] m25p80: Add support for n25q512a11 and n25q512a13 Francisco Iglesias
@ 2017-10-25 18:02   ` mar.krzeminski
  0 siblings, 0 replies; 19+ messages in thread
From: mar.krzeminski @ 2017-10-25 18:02 UTC (permalink / raw)
  To: Francisco Iglesias, qemu-devel; +Cc: edgari, alistai, francisco.iglesias



W dniu 24.10.2017 o 21:51, Francisco Iglesias pisze:
> Add support for Micron (Numonyx) n25q512a11 and n25q512a13 flashes.
>
> Signed-off-by: Francisco Iglesias <frasse.iglesias@gmail.com>
Acked-by: Marcin Krzemiński <mar.krzeminski@gmail.com>
> ---
>   hw/block/m25p80.c | 2 ++
>   1 file changed, 2 insertions(+)
>
> diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
> index 3d2975c..7f3fcc4 100644
> --- a/hw/block/m25p80.c
> +++ b/hw/block/m25p80.c
> @@ -240,6 +240,8 @@ static const FlashPartInfo known_devices[] = {
>       { INFO("n25q128a13",  0x20ba18,      0,  64 << 10, 256, ER_4K) },
>       { INFO("n25q256a11",  0x20bb19,      0,  64 << 10, 512, ER_4K) },
>       { INFO("n25q256a13",  0x20ba19,      0,  64 << 10, 512, ER_4K) },
> +    { INFO("n25q512a11",  0x20bb20,      0,  64 << 10, 1024, ER_4K) },
> +    { INFO("n25q512a13",  0x20ba20,      0,  64 << 10, 1024, ER_4K) },
>       { INFO("n25q128",     0x20ba18,      0,  64 << 10, 256, 0) },
>       { INFO("n25q256a",    0x20ba19,      0,  64 << 10, 512, ER_4K) },
>       { INFO("n25q512a",    0x20ba20,      0,  64 << 10, 1024, ER_4K) },

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

* Re: [Qemu-devel] [PATCH v3 01/13] m25p80: Add support for continuous read out of RDSR and READ_FSR
  2017-10-24 19:51 ` [Qemu-devel] [PATCH v3 01/13] m25p80: Add support for continuous read out of RDSR and READ_FSR Francisco Iglesias
@ 2017-10-25 18:03   ` mar.krzeminski
  0 siblings, 0 replies; 19+ messages in thread
From: mar.krzeminski @ 2017-10-25 18:03 UTC (permalink / raw)
  To: Francisco Iglesias, qemu-devel; +Cc: edgari, alistai, francisco.iglesias



W dniu 24.10.2017 o 21:51, Francisco Iglesias pisze:
> Add support for continuous read out of the RDSR and READ_FSR status
> registers until the chip select is deasserted. This feature is supported
> by amongst others 1 or more flashtypes manufactured by Numonyx (Micron),
> Windbond, SST, Gigadevice, Eon and Macronix.
>
> Signed-off-by: Francisco Iglesias <frasse.iglesias@gmail.com>
Acked-by: Marcin Krzemiński <mar.krzeminski@gmail.com>
> ---
>   hw/block/m25p80.c | 8 +++++++-
>   1 file changed, 7 insertions(+), 1 deletion(-)
>
> diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
> index a2438b9..2971519 100644
> --- a/hw/block/m25p80.c
> +++ b/hw/block/m25p80.c
> @@ -423,6 +423,7 @@ typedef struct Flash {
>       uint8_t data[M25P80_INTERNAL_DATA_BUFFER_SZ];
>       uint32_t len;
>       uint32_t pos;
> +    bool data_read_loop;
>       uint8_t needed_bytes;
>       uint8_t cmd_in_progress;
>       uint32_t cur_addr;
> @@ -983,6 +984,7 @@ static void decode_new_cmd(Flash *s, uint32_t value)
>           }
>           s->pos = 0;
>           s->len = 1;
> +        s->data_read_loop = true;
>           s->state = STATE_READING_DATA;
>           break;
>   
> @@ -993,6 +995,7 @@ static void decode_new_cmd(Flash *s, uint32_t value)
>           }
>           s->pos = 0;
>           s->len = 1;
> +        s->data_read_loop = true;
>           s->state = STATE_READING_DATA;
>           break;
>   
> @@ -1133,6 +1136,7 @@ static int m25p80_cs(SSISlave *ss, bool select)
>           s->pos = 0;
>           s->state = STATE_IDLE;
>           flash_sync_dirty(s, -1);
> +        s->data_read_loop = false;
>       }
>   
>       DB_PRINT_L(0, "%sselect\n", select ? "de" : "");
> @@ -1198,7 +1202,9 @@ static uint32_t m25p80_transfer8(SSISlave *ss, uint32_t tx)
>           s->pos++;
>           if (s->pos == s->len) {
>               s->pos = 0;
> -            s->state = STATE_IDLE;
> +            if (!s->data_read_loop) {
> +                s->state = STATE_IDLE;
> +            }
>           }
>           break;
>   

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

* Re: [Qemu-devel] [PATCH v3 02/13] m25p80: Add support for SST READ ID 0x90/0xAB commands
  2017-10-24 19:51 ` [Qemu-devel] [PATCH v3 02/13] m25p80: Add support for SST READ ID 0x90/0xAB commands Francisco Iglesias
@ 2017-10-25 18:12   ` mar.krzeminski
  2017-10-25 21:03     ` francisco iglesias
  0 siblings, 1 reply; 19+ messages in thread
From: mar.krzeminski @ 2017-10-25 18:12 UTC (permalink / raw)
  To: Francisco Iglesias, qemu-devel; +Cc: edgari, alistai, francisco.iglesias



W dniu 24.10.2017 o 21:51, Francisco Iglesias pisze:
> Add support for SST READ ID 0x90/0xAB commands for reading out the flash
> manufacuter ID and device ID.
>
> Signed-off-by: Francisco Iglesias <frasse.iglesias@gmail.com>
> ---
>   hw/block/m25p80.c | 20 ++++++++++++++++++++
>   1 file changed, 20 insertions(+)
>
> diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
> index 2971519..c85e8fa 100644
> --- a/hw/block/m25p80.c
> +++ b/hw/block/m25p80.c
> @@ -355,6 +355,8 @@ typedef enum {
>       DPP = 0xa2,
>       QPP = 0x32,
>       QPP_4 = 0x34,
> +    RDID_90 = 0x90,
> +    RDID_AB = 0xab,
>   
>       ERASE_4K = 0x20,
>       ERASE4_4K = 0x21,
> @@ -405,6 +407,7 @@ typedef enum {
>       MAN_MACRONIX,
>       MAN_NUMONYX,
>       MAN_WINBOND,
> +    MAN_SST,
>       MAN_GENERIC,
>   } Manufacturer;
>   
> @@ -476,6 +479,8 @@ static inline Manufacturer get_man(Flash *s)
>           return MAN_SPANSION;
>       case 0xC2:
>           return MAN_MACRONIX;
> +    case 0xBF:
> +        return MAN_SST;
>       default:
>           return MAN_GENERIC;
>       }
> @@ -1018,6 +1023,21 @@ static void decode_new_cmd(Flash *s, uint32_t value)
>           s->state = STATE_READING_DATA;
>           break;
>   
> +    case RDID_90:
> +    case RDID_AB:
> +        DB_PRINT_L(0, "populated manf/dev ID\n");
> +        if (get_man(s) == MAN_SST) {
> +            s->data[0] = s->pi->id[0];
> +            s->data[1] = s->pi->id[2];
> +            s->pos = 0;
> +            s->len = 2;
> +            s->data_read_loop = true;
> +            s->state = STATE_READING_DATA;
I am not sure about this. I am looking at SST25WF080 datasheet, and it 
seem that those commands
also expect address, and based on that returns manufacturer id or device id.
> +        } else {
> +            qemu_log_mask(LOG_GUEST_ERROR, "M25P80: Unknown cmd %x\n", value);
> +        }
> +        break;
> +
>       case BULK_ERASE:
>           if (s->write_enable) {
>               DB_PRINT_L(0, "chip erase\n");
Regard,
Marcin

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

* Re: [Qemu-devel] [PATCH v3 02/13] m25p80: Add support for SST READ ID 0x90/0xAB commands
  2017-10-25 18:12   ` mar.krzeminski
@ 2017-10-25 21:03     ` francisco iglesias
  0 siblings, 0 replies; 19+ messages in thread
From: francisco iglesias @ 2017-10-25 21:03 UTC (permalink / raw)
  To: mar.krzeminski; +Cc: qemu-devel, edgari, alistai, Francisco Iglesias

Good day Marcin,

Thank you for your excellent review comments! I will correct the patches in
the next version of the patch series (v4).

Best regards,
Francisco Iglesias


On 25 October 2017 at 20:12, mar.krzeminski <mar.krzeminski@gmail.com>
wrote:

>
>
> W dniu 24.10.2017 o 21:51, Francisco Iglesias pisze:
>
> Add support for SST READ ID 0x90/0xAB commands for reading out the flash
>> manufacuter ID and device ID.
>>
>> Signed-off-by: Francisco Iglesias <frasse.iglesias@gmail.com>
>> ---
>>   hw/block/m25p80.c | 20 ++++++++++++++++++++
>>   1 file changed, 20 insertions(+)
>>
>> diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
>> index 2971519..c85e8fa 100644
>> --- a/hw/block/m25p80.c
>> +++ b/hw/block/m25p80.c
>> @@ -355,6 +355,8 @@ typedef enum {
>>       DPP = 0xa2,
>>       QPP = 0x32,
>>       QPP_4 = 0x34,
>> +    RDID_90 = 0x90,
>> +    RDID_AB = 0xab,
>>         ERASE_4K = 0x20,
>>       ERASE4_4K = 0x21,
>> @@ -405,6 +407,7 @@ typedef enum {
>>       MAN_MACRONIX,
>>       MAN_NUMONYX,
>>       MAN_WINBOND,
>> +    MAN_SST,
>>       MAN_GENERIC,
>>   } Manufacturer;
>>   @@ -476,6 +479,8 @@ static inline Manufacturer get_man(Flash *s)
>>           return MAN_SPANSION;
>>       case 0xC2:
>>           return MAN_MACRONIX;
>> +    case 0xBF:
>> +        return MAN_SST;
>>       default:
>>           return MAN_GENERIC;
>>       }
>> @@ -1018,6 +1023,21 @@ static void decode_new_cmd(Flash *s, uint32_t
>> value)
>>           s->state = STATE_READING_DATA;
>>           break;
>>   +    case RDID_90:
>> +    case RDID_AB:
>> +        DB_PRINT_L(0, "populated manf/dev ID\n");
>> +        if (get_man(s) == MAN_SST) {
>> +            s->data[0] = s->pi->id[0];
>> +            s->data[1] = s->pi->id[2];
>> +            s->pos = 0;
>> +            s->len = 2;
>> +            s->data_read_loop = true;
>> +            s->state = STATE_READING_DATA;
>>
> I am not sure about this. I am looking at SST25WF080 datasheet, and it
> seem that those commands
> also expect address, and based on that returns manufacturer id or device
> id.
>
>> +        } else {
>> +            qemu_log_mask(LOG_GUEST_ERROR, "M25P80: Unknown cmd %x\n",
>> value);
>> +        }
>> +        break;
>> +
>>       case BULK_ERASE:
>>           if (s->write_enable) {
>>               DB_PRINT_L(0, "chip erase\n");
>>
> Regard,
> Marcin
>

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

* [Qemu-devel] [PATCH v7 09/13] xilinx_spips: Add support for zero pumping
  2017-10-24 19:51 [Qemu-devel] [PATCH v3 00/13] Add support for the ZynqMP Generic QSPI Francisco Iglesias
                   ` (11 preceding siblings ...)
  2017-10-24 20:04 ` [Qemu-devel] [PATCH v3 09/13] xilinx_spips: Add support for zero pumping Francisco Iglesias
@ 2017-11-02 23:59 ` Francisco Iglesias
  12 siblings, 0 replies; 19+ messages in thread
From: Francisco Iglesias @ 2017-11-02 23:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: edgari, alistai, francisco.iglesias, mar.krzeminski, peter.maydell

Add support for zero pumping according to the transfer size register.

Signed-off-by: Francisco Iglesias <frasse.iglesias@gmail.com>
---
 hw/ssi/xilinx_spips.c         | 47 ++++++++++++++++++++++++++++++++++++-------
 include/hw/ssi/xilinx_spips.h |  2 ++
 2 files changed, 42 insertions(+), 7 deletions(-)

diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
index e37d005..3a98799 100644
--- a/hw/ssi/xilinx_spips.c
+++ b/hw/ssi/xilinx_spips.c
@@ -109,6 +109,7 @@
     FIELD(CMND, DUMMY_CYCLES, 2, 6)
 #define R_CMND_DMA_EN         (1 << 1)
 #define R_CMND_PUSH_WAIT      (1 << 0)
+#define R_TRANSFER_SIZE     (0xc4 / 4)
 #define R_LQSPI_STS         (0xA4 / 4)
 #define LQSPI_STS_WR_RECVD      (1 << 1)
 
@@ -227,6 +228,7 @@ static void xilinx_spips_reset(DeviceState *d)
     s->link_state_next_when = 0;
     s->snoop_state = SNOOP_CHECKING;
     s->cmd_dummies = 0;
+    s->man_start_com = false;
     xilinx_spips_update_ixr(s);
     xilinx_spips_update_cs_lines(s);
 }
@@ -464,6 +466,41 @@ static inline void tx_data_bytes(Fifo8 *fifo, uint32_t value, int num, bool be)
     }
 }
 
+static void xilinx_spips_check_zero_pump(XilinxSPIPS *s)
+{
+    if (!s->regs[R_TRANSFER_SIZE]) {
+        return;
+    }
+    if (!fifo8_is_empty(&s->tx_fifo) && s->regs[R_CMND] & R_CMND_PUSH_WAIT) {
+        return;
+    }
+    /*
+     * The zero pump must never fill tx fifo such that rx overflow is
+     * possible
+     */
+    while (s->regs[R_TRANSFER_SIZE] &&
+           s->rx_fifo.num + s->tx_fifo.num < RXFF_A_Q - 3) {
+        /* endianess just doesn't matter when zero pumping */
+        tx_data_bytes(&s->tx_fifo, 0, 4, false);
+        s->regs[R_TRANSFER_SIZE] &= ~0x03ull;
+        s->regs[R_TRANSFER_SIZE] -= 4;
+    }
+}
+
+static void xilinx_spips_check_flush(XilinxSPIPS *s)
+{
+    if (s->man_start_com ||
+        (!fifo8_is_empty(&s->tx_fifo) &&
+         !(s->regs[R_CONFIG] & MAN_START_EN))) {
+        xilinx_spips_check_zero_pump(s);
+        xilinx_spips_flush_txfifo(s);
+    }
+    if (fifo8_is_empty(&s->tx_fifo) && !s->regs[R_TRANSFER_SIZE]) {
+        s->man_start_com = false;
+    }
+    xilinx_spips_update_ixr(s);
+}
+
 static inline int rx_data_bytes(Fifo8 *fifo, uint8_t *value, int max)
 {
     int i;
@@ -533,7 +570,6 @@ static void xilinx_spips_write(void *opaque, hwaddr addr,
                                         uint64_t value, unsigned size)
 {
     int mask = ~0;
-    int man_start_com = 0;
     XilinxSPIPS *s = opaque;
 
     DB_PRINT_L(0, "addr=" TARGET_FMT_plx " = %x\n", addr, (unsigned)value);
@@ -541,8 +577,8 @@ static void xilinx_spips_write(void *opaque, hwaddr addr,
     switch (addr) {
     case R_CONFIG:
         mask = ~(R_CONFIG_RSVD | MAN_START_COM);
-        if (value & MAN_START_COM) {
-            man_start_com = 1;
+        if ((value & MAN_START_COM) && (s->regs[R_CONFIG] & MAN_START_EN)) {
+            s->man_start_com = true;
         }
         break;
     case R_INTR_STATUS:
@@ -588,10 +624,7 @@ static void xilinx_spips_write(void *opaque, hwaddr addr,
     s->regs[addr] = (s->regs[addr] & ~mask) | (value & mask);
 no_reg_update:
     xilinx_spips_update_cs_lines(s);
-    if ((man_start_com && s->regs[R_CONFIG] & MAN_START_EN) ||
-            (fifo8_is_empty(&s->tx_fifo) && s->regs[R_CONFIG] & MAN_START_EN)) {
-        xilinx_spips_flush_txfifo(s);
-    }
+    xilinx_spips_check_flush(s);
     xilinx_spips_update_cs_lines(s);
     xilinx_spips_update_ixr(s);
 }
diff --git a/include/hw/ssi/xilinx_spips.h b/include/hw/ssi/xilinx_spips.h
index bac90a5..ad2175a 100644
--- a/include/hw/ssi/xilinx_spips.h
+++ b/include/hw/ssi/xilinx_spips.h
@@ -76,6 +76,8 @@ struct XilinxSPIPS {
     uint32_t rx_discard;
 
     uint32_t regs[XLNX_SPIPS_R_MAX];
+
+    bool man_start_com;
 };
 
 typedef struct {
-- 
2.9.3

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

end of thread, other threads:[~2017-11-03  0:00 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-10-24 19:51 [Qemu-devel] [PATCH v3 00/13] Add support for the ZynqMP Generic QSPI Francisco Iglesias
2017-10-24 19:51 ` [Qemu-devel] [PATCH v3 01/13] m25p80: Add support for continuous read out of RDSR and READ_FSR Francisco Iglesias
2017-10-25 18:03   ` mar.krzeminski
2017-10-24 19:51 ` [Qemu-devel] [PATCH v3 02/13] m25p80: Add support for SST READ ID 0x90/0xAB commands Francisco Iglesias
2017-10-25 18:12   ` mar.krzeminski
2017-10-25 21:03     ` francisco iglesias
2017-10-24 19:51 ` [Qemu-devel] [PATCH v3 03/13] m25p80: Add support for BRRD/BRWR and BULK_ERASE (0x60) Francisco Iglesias
2017-10-25 14:55   ` mar.krzeminski
2017-10-24 19:51 ` [Qemu-devel] [PATCH v3 04/13] m25p80: Add support for n25q512a11 and n25q512a13 Francisco Iglesias
2017-10-25 18:02   ` mar.krzeminski
2017-10-24 19:51 ` [Qemu-devel] [PATCH v3 05/13] xilinx_spips: Move FlashCMD, XilinxQSPIPS and XilinxSPIPSClass Francisco Iglesias
2017-10-24 19:51 ` [Qemu-devel] [PATCH v3 06/13] xilinx_spips: Update striping to be big-endian bit order Francisco Iglesias
2017-10-24 19:51 ` [Qemu-devel] [PATCH v3 08/13] xilinx_spips: Make tx/rx_data_bytes more generic and reusable Francisco Iglesias
2017-10-24 19:51 ` [Qemu-devel] [PATCH v3 10/13] xilinx_spips: Add support for 4 byte addresses in the LQSPI Francisco Iglesias
2017-10-24 19:51 ` [Qemu-devel] [PATCH v3 11/13] xilinx_spips: Don't set TX FIFO UNDERFLOW at cmd done Francisco Iglesias
2017-10-24 19:51 ` [Qemu-devel] [PATCH v3 12/13] xilinx_spips: Add support for the ZynqMP Generic QSPI Francisco Iglesias
2017-10-24 19:51 ` [Qemu-devel] [PATCH v3 13/13] xlnx-zcu102: Add support for the ZynqMP QSPI Francisco Iglesias
2017-10-24 20:04 ` [Qemu-devel] [PATCH v3 09/13] xilinx_spips: Add support for zero pumping Francisco Iglesias
2017-11-02 23:59 ` [Qemu-devel] [PATCH v7 " Francisco Iglesias

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.