diff mbox

[v2,06/10] m25p80: Introduce quad and equad modes.

Message ID 1466159314-28597-7-git-send-email-marcin.krzeminski@nokia.com
State New
Headers show

Commit Message

Krzeminski, Marcin (Nokia - PL/Wroclaw) June 17, 2016, 10:28 a.m. UTC
From: Marcin Krzeminski <marcin.krzeminski@nokia.com>

Quad and Equad modes for Spansion and Macronix flash devices.
This commit also includes modification and new command to manipulate
quad mode (status registers and dedicated commands).
This work is based on Pawel Lenkow work.

Signed-off-by: Marcin Krzeminski <marcin.krzeminski@nokia.com>
---
 hw/block/m25p80.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 65 insertions(+), 5 deletions(-)

Comments

Cédric Le Goater June 17, 2016, 12:33 p.m. UTC | #1
On 06/17/2016 12:28 PM, marcin.krzeminski@nokia.com wrote:
> From: Marcin Krzeminski <marcin.krzeminski@nokia.com>
> 
> Quad and Equad modes for Spansion and Macronix flash devices.
> This commit also includes modification and new command to manipulate
> quad mode (status registers and dedicated commands).
> This work is based on Pawel Lenkow work.
> 
> Signed-off-by: Marcin Krzeminski <marcin.krzeminski@nokia.com>

Reviewed-by: Cédric Le Goater <clg@kaod.org>

Thanks,

C.

> ---
>  hw/block/m25p80.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++----
>  1 file changed, 65 insertions(+), 5 deletions(-)
> 
> diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
> index 55b4377..d1c4d46 100644
> --- a/hw/block/m25p80.c
> +++ b/hw/block/m25p80.c
> @@ -281,6 +281,7 @@ typedef enum {
>      JEDEC_READ = 0x9f,
>      BULK_ERASE = 0xc7,
>      READ_FSR = 0x70,
> +    RDCR = 0x15,
>  
>      READ = 0x03,
>      READ4 = 0x13,
> @@ -317,6 +318,13 @@ typedef enum {
>      RESET_ENABLE = 0x66,
>      RESET_MEMORY = 0x99,
>  
> +    /*
> +     * Micron: 0x35 - enable QPI
> +     * Spansion: 0x35 - read control register
> +     */
> +    RDCR_EQIO = 0x35,
> +    RSTQIO = 0xf5,
> +
>      RNVCR = 0xB5,
>      WNVCR = 0xB1,
>  
> @@ -366,6 +374,7 @@ typedef struct Flash {
>      bool write_enable;
>      bool four_bytes_address_mode;
>      bool reset_enable;
> +    bool quad_enable;
>      uint8_t ear;
>  
>      int64_t dirty_page;
> @@ -586,6 +595,16 @@ static void complete_collecting_data(Flash *s)
>          flash_erase(s, s->cur_addr, s->cmd_in_progress);
>          break;
>      case WRSR:
> +        switch (get_man(s)) {
> +        case MAN_SPANSION:
> +            s->quad_enable = !!(s->data[1] & 0x02);
> +            break;
> +        case MAN_MACRONIX:
> +            s->quad_enable = extract32(s->data[0], 6, 1);
> +            break;
> +        default:
> +            break;
> +        }
>          if (s->write_enable) {
>              s->write_enable = false;
>          }
> @@ -619,6 +638,7 @@ static void reset_memory(Flash *s)
>      s->state = STATE_IDLE;
>      s->write_enable = false;
>      s->reset_enable = false;
> +    s->quad_enable = false;
>  
>      switch (get_man(s)) {
>      case MAN_NUMONYX:
> @@ -747,10 +767,20 @@ static void decode_new_cmd(Flash *s, uint32_t value)
>  
>      case WRSR:
>          if (s->write_enable) {
> -            s->needed_bytes = 1;
> +            switch (get_man(s)) {
> +            case MAN_SPANSION:
> +                s->needed_bytes = 2;
> +                s->state = STATE_COLLECTING_DATA;
> +                break;
> +            case MAN_MACRONIX:
> +                s->needed_bytes = 2;
> +                s->state = STATE_COLLECTING_VAR_LEN_DATA;
> +                break;
> +            default:
> +                s->needed_bytes = 1;
> +                s->state = STATE_COLLECTING_DATA;
> +            }
>              s->pos = 0;
> -            s->len = 0;
> -            s->state = STATE_COLLECTING_DATA;
>          }
>          break;
>  
> @@ -763,6 +793,9 @@ static void decode_new_cmd(Flash *s, uint32_t value)
>  
>      case RDSR:
>          s->data[0] = (!!s->write_enable) << 1;
> +        if (get_man(s) == MAN_MACRONIX) {
> +            s->data[0] |= (!!s->quad_enable) << 6;
> +        }
>          s->pos = 0;
>          s->len = 1;
>          s->state = STATE_READING_DATA;
> @@ -789,6 +822,14 @@ static void decode_new_cmd(Flash *s, uint32_t value)
>          s->state = STATE_READING_DATA;
>          break;
>  
> +    case RDCR:
> +        s->data[0] = s->volatile_cfg & 0xFF;
> +        s->data[0] |= (!!s->four_bytes_address_mode) << 5;
> +        s->pos = 0;
> +        s->len = 1;
> +        s->state = STATE_READING_DATA;
> +        break;
> +
>      case BULK_ERASE:
>          if (s->write_enable) {
>              DB_PRINT_L(0, "chip erase\n");
> @@ -828,7 +869,7 @@ static void decode_new_cmd(Flash *s, uint32_t value)
>          s->state = STATE_READING_DATA;
>          break;
>      case WNVCR:
> -        if (s->write_enable) {
> +        if (s->write_enable && get_man(s) == MAN_NUMONYX) {
>              s->needed_bytes = 2;
>              s->pos = 0;
>              s->len = 0;
> @@ -871,6 +912,24 @@ static void decode_new_cmd(Flash *s, uint32_t value)
>              reset_memory(s);
>          }
>          break;
> +    case RDCR_EQIO:
> +        switch (get_man(s)) {
> +        case MAN_SPANSION:
> +            s->data[0] = (!!s->quad_enable) << 1;
> +            s->pos = 0;
> +            s->len = 1;
> +            s->state = STATE_READING_DATA;
> +            break;
> +        case MAN_MACRONIX:
> +            s->quad_enable = true;
> +            break;
> +        default:
> +            break;
> +        }
> +        break;
> +    case RSTQIO:
> +        s->quad_enable = false;
> +        break;
>      default:
>          qemu_log_mask(LOG_GUEST_ERROR, "M25P80: Unknown cmd %x\n", value);
>          break;
> @@ -999,7 +1058,7 @@ static Property m25p80_properties[] = {
>  
>  static const VMStateDescription vmstate_m25p80 = {
>      .name = "xilinx_spi",
> -    .version_id = 2,
> +    .version_id = 3,
>      .minimum_version_id = 1,
>      .pre_save = m25p80_pre_save,
>      .fields = (VMStateField[]) {
> @@ -1017,6 +1076,7 @@ static const VMStateDescription vmstate_m25p80 = {
>          VMSTATE_UINT32_V(nonvolatile_cfg, Flash, 2),
>          VMSTATE_UINT32_V(volatile_cfg, Flash, 2),
>          VMSTATE_UINT32_V(enh_volatile_cfg, Flash, 2),
> +        VMSTATE_BOOL_V(quad_enable, Flash, 3),
>          VMSTATE_END_OF_LIST()
>      }
>  };
>
diff mbox

Patch

diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
index 55b4377..d1c4d46 100644
--- a/hw/block/m25p80.c
+++ b/hw/block/m25p80.c
@@ -281,6 +281,7 @@  typedef enum {
     JEDEC_READ = 0x9f,
     BULK_ERASE = 0xc7,
     READ_FSR = 0x70,
+    RDCR = 0x15,
 
     READ = 0x03,
     READ4 = 0x13,
@@ -317,6 +318,13 @@  typedef enum {
     RESET_ENABLE = 0x66,
     RESET_MEMORY = 0x99,
 
+    /*
+     * Micron: 0x35 - enable QPI
+     * Spansion: 0x35 - read control register
+     */
+    RDCR_EQIO = 0x35,
+    RSTQIO = 0xf5,
+
     RNVCR = 0xB5,
     WNVCR = 0xB1,
 
@@ -366,6 +374,7 @@  typedef struct Flash {
     bool write_enable;
     bool four_bytes_address_mode;
     bool reset_enable;
+    bool quad_enable;
     uint8_t ear;
 
     int64_t dirty_page;
@@ -586,6 +595,16 @@  static void complete_collecting_data(Flash *s)
         flash_erase(s, s->cur_addr, s->cmd_in_progress);
         break;
     case WRSR:
+        switch (get_man(s)) {
+        case MAN_SPANSION:
+            s->quad_enable = !!(s->data[1] & 0x02);
+            break;
+        case MAN_MACRONIX:
+            s->quad_enable = extract32(s->data[0], 6, 1);
+            break;
+        default:
+            break;
+        }
         if (s->write_enable) {
             s->write_enable = false;
         }
@@ -619,6 +638,7 @@  static void reset_memory(Flash *s)
     s->state = STATE_IDLE;
     s->write_enable = false;
     s->reset_enable = false;
+    s->quad_enable = false;
 
     switch (get_man(s)) {
     case MAN_NUMONYX:
@@ -747,10 +767,20 @@  static void decode_new_cmd(Flash *s, uint32_t value)
 
     case WRSR:
         if (s->write_enable) {
-            s->needed_bytes = 1;
+            switch (get_man(s)) {
+            case MAN_SPANSION:
+                s->needed_bytes = 2;
+                s->state = STATE_COLLECTING_DATA;
+                break;
+            case MAN_MACRONIX:
+                s->needed_bytes = 2;
+                s->state = STATE_COLLECTING_VAR_LEN_DATA;
+                break;
+            default:
+                s->needed_bytes = 1;
+                s->state = STATE_COLLECTING_DATA;
+            }
             s->pos = 0;
-            s->len = 0;
-            s->state = STATE_COLLECTING_DATA;
         }
         break;
 
@@ -763,6 +793,9 @@  static void decode_new_cmd(Flash *s, uint32_t value)
 
     case RDSR:
         s->data[0] = (!!s->write_enable) << 1;
+        if (get_man(s) == MAN_MACRONIX) {
+            s->data[0] |= (!!s->quad_enable) << 6;
+        }
         s->pos = 0;
         s->len = 1;
         s->state = STATE_READING_DATA;
@@ -789,6 +822,14 @@  static void decode_new_cmd(Flash *s, uint32_t value)
         s->state = STATE_READING_DATA;
         break;
 
+    case RDCR:
+        s->data[0] = s->volatile_cfg & 0xFF;
+        s->data[0] |= (!!s->four_bytes_address_mode) << 5;
+        s->pos = 0;
+        s->len = 1;
+        s->state = STATE_READING_DATA;
+        break;
+
     case BULK_ERASE:
         if (s->write_enable) {
             DB_PRINT_L(0, "chip erase\n");
@@ -828,7 +869,7 @@  static void decode_new_cmd(Flash *s, uint32_t value)
         s->state = STATE_READING_DATA;
         break;
     case WNVCR:
-        if (s->write_enable) {
+        if (s->write_enable && get_man(s) == MAN_NUMONYX) {
             s->needed_bytes = 2;
             s->pos = 0;
             s->len = 0;
@@ -871,6 +912,24 @@  static void decode_new_cmd(Flash *s, uint32_t value)
             reset_memory(s);
         }
         break;
+    case RDCR_EQIO:
+        switch (get_man(s)) {
+        case MAN_SPANSION:
+            s->data[0] = (!!s->quad_enable) << 1;
+            s->pos = 0;
+            s->len = 1;
+            s->state = STATE_READING_DATA;
+            break;
+        case MAN_MACRONIX:
+            s->quad_enable = true;
+            break;
+        default:
+            break;
+        }
+        break;
+    case RSTQIO:
+        s->quad_enable = false;
+        break;
     default:
         qemu_log_mask(LOG_GUEST_ERROR, "M25P80: Unknown cmd %x\n", value);
         break;
@@ -999,7 +1058,7 @@  static Property m25p80_properties[] = {
 
 static const VMStateDescription vmstate_m25p80 = {
     .name = "xilinx_spi",
-    .version_id = 2,
+    .version_id = 3,
     .minimum_version_id = 1,
     .pre_save = m25p80_pre_save,
     .fields = (VMStateField[]) {
@@ -1017,6 +1076,7 @@  static const VMStateDescription vmstate_m25p80 = {
         VMSTATE_UINT32_V(nonvolatile_cfg, Flash, 2),
         VMSTATE_UINT32_V(volatile_cfg, Flash, 2),
         VMSTATE_UINT32_V(enh_volatile_cfg, Flash, 2),
+        VMSTATE_BOOL_V(quad_enable, Flash, 3),
         VMSTATE_END_OF_LIST()
     }
 };