diff mbox series

[RFC,v1,2/3] hw: block: m25p80: Support dummy byte accuracy

Message ID 20210119130155.30194-3-frasse.iglesias@gmail.com (mailing list archive)
State New, archived
Headers show
Series Introduce ssi_txfifo_transfer | expand

Commit Message

Francisco Iglesias Jan. 19, 2021, 1:01 p.m. UTC
This patch adds support to toggle the accuracy in m25p80 between dummy
clock cycle to dummy byte. By being able to do this the SPI controllers
transfering through a txfifo will be able to support commands with dummy
clock cycles.

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

Patch

diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
index 1b3f2405a1..c9342e1842 100644
--- a/hw/block/m25p80.c
+++ b/hw/block/m25p80.c
@@ -462,6 +462,7 @@  struct Flash {
 
     const FlashPartInfo *pi;
 
+    bool dummy_byte_accuracy;
 };
 
 struct M25P80Class {
@@ -862,26 +863,59 @@  static uint8_t numonyx_extract_cfg_num_dummies(Flash *s)
     return num_dummies;
 }
 
+static uint8_t to_dummy_bytes(Flash *s, uint8_t dummy_clk_cycles)
+{
+    uint8_t lines = 1;
+
+    switch (s->cmd_in_progress) {
+    case DOR:
+    case DOR4:
+    case DIOR:
+    case DIOR4:
+        lines = 2;
+        break;
+    case QOR:
+    case QOR4:
+    case QIOR:
+    case QIOR4:
+        lines = 4;
+        break;
+    default:
+        break;
+    }
+
+    if ((dummy_clk_cycles * lines) % 8) {
+        qemu_log_mask(LOG_UNIMP, "M25P80: Non multiple of 8 number of dummy"
+                     " clock cycles while operating with dummy byte"
+                     " accuracy\n");
+    }
+
+    return (dummy_clk_cycles * lines) / 8;
+}
+
 static void decode_fast_read_cmd(Flash *s)
 {
+    uint8_t dummy_clk_cycles = 0;
+    uint8_t extra_bytes;
+
     s->needed_bytes = get_addr_length(s);
     switch (get_man(s)) {
     /* Dummy cycles - modeled with bytes writes instead of bits */
     case MAN_WINBOND:
-        s->needed_bytes += 8;
+        dummy_clk_cycles = 8;
         break;
     case MAN_NUMONYX:
-        s->needed_bytes += numonyx_extract_cfg_num_dummies(s);
+        dummy_clk_cycles = numonyx_extract_cfg_num_dummies(s);
         break;
     case MAN_MACRONIX:
         if (extract32(s->volatile_cfg, 6, 2) == 1) {
-            s->needed_bytes += 6;
+            dummy_clk_cycles = 6;
         } else {
-            s->needed_bytes += 8;
+            dummy_clk_cycles = 8;
         }
         break;
     case MAN_SPANSION:
-        s->needed_bytes += extract32(s->spansion_cr2v,
+        dummy_clk_cycles = extract32(s->spansion_cr2v,
                                     SPANSION_DUMMY_CLK_POS,
                                     SPANSION_DUMMY_CLK_LEN
                                     );
@@ -889,6 +923,14 @@  static void decode_fast_read_cmd(Flash *s)
     default:
         break;
     }
+
+    if (s->dummy_byte_accuracy) {
+        extra_bytes = to_dummy_bytes(s, dummy_clk_cycles);
+    } else {
+        extra_bytes = dummy_clk_cycles;
+    }
+
+    s->needed_bytes += extra_bytes;
     s->pos = 0;
     s->len = 0;
     s->state = STATE_COLLECTING_DATA;
@@ -896,38 +938,49 @@  static void decode_fast_read_cmd(Flash *s)
 
 static void decode_dio_read_cmd(Flash *s)
 {
+    uint8_t dummy_clk_cycles = 0;
+    uint8_t extra_bytes;
+
     s->needed_bytes = get_addr_length(s);
     /* Dummy cycles modeled with bytes writes instead of bits */
     switch (get_man(s)) {
     case MAN_WINBOND:
-        s->needed_bytes += WINBOND_CONTINUOUS_READ_MODE_CMD_LEN;
+        dummy_clk_cycles = WINBOND_CONTINUOUS_READ_MODE_CMD_LEN;
         break;
     case MAN_SPANSION:
-        s->needed_bytes += SPANSION_CONTINUOUS_READ_MODE_CMD_LEN;
-        s->needed_bytes += extract32(s->spansion_cr2v,
+        dummy_clk_cycles = SPANSION_CONTINUOUS_READ_MODE_CMD_LEN;
+        dummy_clk_cycles = extract32(s->spansion_cr2v,
                                     SPANSION_DUMMY_CLK_POS,
                                     SPANSION_DUMMY_CLK_LEN
                                     );
         break;
     case MAN_NUMONYX:
-        s->needed_bytes += numonyx_extract_cfg_num_dummies(s);
+        dummy_clk_cycles = numonyx_extract_cfg_num_dummies(s);
         break;
     case MAN_MACRONIX:
         switch (extract32(s->volatile_cfg, 6, 2)) {
         case 1:
-            s->needed_bytes += 6;
+            dummy_clk_cycles = 6;
             break;
         case 2:
-            s->needed_bytes += 8;
+            dummy_clk_cycles = 8;
             break;
         default:
-            s->needed_bytes += 4;
+            dummy_clk_cycles = 4;
             break;
         }
         break;
     default:
         break;
     }
+
+    if (s->dummy_byte_accuracy) {
+        extra_bytes = to_dummy_bytes(s, dummy_clk_cycles);
+    } else {
+        extra_bytes = dummy_clk_cycles;
+    }
+
+    s->needed_bytes += extra_bytes;
     s->pos = 0;
     s->len = 0;
     s->state = STATE_COLLECTING_DATA;
@@ -935,39 +988,50 @@  static void decode_dio_read_cmd(Flash *s)
 
 static void decode_qio_read_cmd(Flash *s)
 {
+    uint8_t dummy_clk_cycles = 0;
+    uint8_t extra_bytes;
+
     s->needed_bytes = get_addr_length(s);
     /* Dummy cycles modeled with bytes writes instead of bits */
     switch (get_man(s)) {
     case MAN_WINBOND:
-        s->needed_bytes += WINBOND_CONTINUOUS_READ_MODE_CMD_LEN;
-        s->needed_bytes += 4;
+        dummy_clk_cycles = WINBOND_CONTINUOUS_READ_MODE_CMD_LEN;
+        dummy_clk_cycles += 4;
         break;
     case MAN_SPANSION:
-        s->needed_bytes += SPANSION_CONTINUOUS_READ_MODE_CMD_LEN;
-        s->needed_bytes += extract32(s->spansion_cr2v,
+        dummy_clk_cycles = SPANSION_CONTINUOUS_READ_MODE_CMD_LEN;
+        dummy_clk_cycles += extract32(s->spansion_cr2v,
                                     SPANSION_DUMMY_CLK_POS,
                                     SPANSION_DUMMY_CLK_LEN
                                     );
         break;
     case MAN_NUMONYX:
-        s->needed_bytes += numonyx_extract_cfg_num_dummies(s);
+        dummy_clk_cycles = numonyx_extract_cfg_num_dummies(s);
         break;
     case MAN_MACRONIX:
         switch (extract32(s->volatile_cfg, 6, 2)) {
         case 1:
-            s->needed_bytes += 4;
+            dummy_clk_cycles = 4;
             break;
         case 2:
-            s->needed_bytes += 8;
+            dummy_clk_cycles = 8;
             break;
         default:
-            s->needed_bytes += 6;
+            dummy_clk_cycles = 6;
             break;
         }
         break;
     default:
         break;
     }
+
+    if (s->dummy_byte_accuracy) {
+        extra_bytes = to_dummy_bytes(s, dummy_clk_cycles);
+    } else {
+        extra_bytes = dummy_clk_cycles;
+    }
+
+    s->needed_bytes += extra_bytes;
     s->pos = 0;
     s->len = 0;
     s->state = STATE_COLLECTING_DATA;
@@ -1291,6 +1355,13 @@  static int m25p80_cs(SSIPeripheral *ss, bool select)
     return 0;
 }
 
+static void m25p80_dummy_byte_accuracy(SSIPeripheral *ss, bool val)
+{
+    Flash *s = M25P80(ss);
+
+    s->dummy_byte_accuracy = val;
+}
+
 static uint32_t m25p80_transfer8(SSIPeripheral *ss, uint32_t tx)
 {
     Flash *s = M25P80(ss);
@@ -1494,6 +1565,7 @@  static void m25p80_class_init(ObjectClass *klass, void *data)
     k->transfer = m25p80_transfer8;
     k->set_cs = m25p80_cs;
     k->cs_polarity = SSI_CS_LOW;
+    k->set_dummy_byte_accuracy = m25p80_dummy_byte_accuracy;
     dc->vmsd = &vmstate_m25p80;
     device_class_set_props(dc, m25p80_properties);
     dc->reset = m25p80_reset;