This is an automated email from Gerrit.

"Andreas Bolsch <hyphen0br...@gmail.com>" just uploaded a new patch set to 
Gerrit, which you can find at https://review.openocd.org/c/openocd/+/7359

-- gerrit

commit c8fb583686358ce455f89f7aec87f11c25740b0e
Author: Andreas Bolsch <hyphen0br...@gmail.com>
Date:   Thu Nov 17 22:50:43 2022 +0100

    Extend SFDP parser in particular regarding octal devices
    
    Change-Id: I270835b782f9f94c9b1b9fe39ba0ddcf88483ed4
    Signed-off-by: Andreas Bolsch <hyphen0br...@gmail.com>

diff --git a/src/flash/nor/sfdp.c b/src/flash/nor/sfdp.c
index 5bfb541946..08533aef15 100644
--- a/src/flash/nor/sfdp.c
+++ b/src/flash/nor/sfdp.c
@@ -8,55 +8,172 @@
 #include "config.h"
 #endif
 
+#include "helper/bits.h"
 #include "imp.h"
 #include "spi.h"
 #include "sfdp.h"
 
-#define SFDP_MAGIC                     0x50444653
-#define SFDP_ACCESS_PROT       0xFF
-#define SFDP_BASIC_FLASH       0xFF00
-#define SFDP_4BYTE_ADDR                0xFF84
+#define SFDP_MAGIC                             0x50444653
+
+#define SFDP_ACCESS_OCT_3_8            0xFC
+#define SFDP_ACCESS_OCT_4_20   0xFD
+#define SFDP_ACCESS_OCT_4_8            0xFE
+#define SFDP_ACCESS_QUAD_3_8   0xFF
+
+#define SFDP_BASIC_FLASH               0xFF00
+#define        SFDP_XSPI_1_0                   0xFF05
+#define        SFDP_XSPI_2_0                   0xFF06
+#define SFDP_STAT_CTRL_CONF_2_0        0xFF09
+#define        SFDP_CMD_OCTAL_DTR              0xFF0A
+#define SFDP_X4_QUAD_IO                        0xFF0C
+#define SFDP_SECTOR_MAP                        0xFF81
+#define SFDP_4BYTE_ADDR                        0xFF84
+#define SFDP_STAT_CTRL_CONF            0xFF87
+#define        SFDP_CMD_QUAD_DTR               0xFF8D
 
 static const char *sfdp_name = "sfdp";
 
 struct sfdp_hdr {
-       uint32_t                        signature;
-       uint32_t                        revision;
+       uint32_t        signature;
+       uint32_t        revision;
 };
 
 struct sfdp_phdr {
-       uint32_t                        revision;
-       uint32_t                        ptr;
+       uint32_t        revision;
+       uint32_t        ptr;
 };
 
 struct sfdp_basic_flash_param {
-       uint32_t                        fast_addr;              /* 01: fast 
read and 3/4 address bytes */
-       uint32_t                        density;                /* 02: memory 
density */
-       uint32_t                        fast_1x4;               /* 03: 1-1-4 
and 1-4-4 fast read */
-       uint32_t                        fast_1x2;               /* 04: 1-2-2 
and 1-1-2 fast read */
-       uint32_t                        fast_444;               /* 05: 4-4-4 
and 2-2-2 fast read */
-       uint32_t                        read_222;               /* 06: 2-2-2 
fast read instr and dummy */
-       uint32_t                        read_444;               /* 07: 4-4-4 
fast read instr and dummy */
-       uint32_t                        erase_t12;              /* 08: erase 
types 1, 2 */
-       uint32_t                        erase_t34;              /* 09: erase 
types 3, 4 */
-       uint32_t                        erase_time;             /* 10: erase 
times for types 1 - 4 */
-       uint32_t                        chip_byte;              /* 11: chip 
erase time, byte prog time, page prog */
-       uint32_t                        susp_time;              /* 12: suspend 
and resume times */
-       uint32_t                        susp_instr;             /* 13: suspend 
and resume instr */
-       uint32_t                        pwrd_instr;             /* 14: 
powerdown instr */
-       uint32_t                        quad_req;               /* 15: quad 
enable requirements */
-       uint32_t                        addr_reset;             /* 16: 
3-/4-byte addressing and reset */
-       uint32_t                        read_1x8;               /* 17: 1-1-8 
and 1-8-8 fast read instr and dummy */
-       uint32_t                        dtr_drive;              /* 18: dtr 
modes and drive strength */
-       uint32_t                        octal_req;              /* 19: octal 
enable requirements */
-       uint32_t                        speed_888;              /* 20: speed in 
8-8-8 modes */
+       uint32_t        fast_addr;                      /* 01: fast read and 
3/4 address bytes */
+       uint32_t        density;                        /* 02: memory density */
+       uint32_t        fast_1x4;                       /* 03: 1-1-4 and 1-4-4 
fast read */
+       uint32_t        fast_1x2;                       /* 04: 1-2-2 and 1-1-2 
fast read */
+       uint32_t        fast_444;                       /* 05: 4-4-4 and 2-2-2 
fast read */
+       uint32_t        read_222;                       /* 06: 2-2-2 fast read 
instr and dummy */
+       uint32_t        read_444;                       /* 07: 4-4-4 fast read 
instr and dummy */
+       uint32_t        erase_t12;                      /* 08: erase types 1, 2 
*/
+       uint32_t        erase_t34;                      /* 09: erase types 3, 4 
*/
+       uint32_t        erase_time;                     /* 10: erase times for 
types 1 - 4 */
+       uint32_t        chip_byte;                      /* 11: chip erase time, 
byte prog time, page prog */
+       uint32_t        susp_time;                      /* 12: suspend and 
resume times */
+       uint32_t        susp_instr;                     /* 13: suspend and 
resume instr */
+       uint32_t        pwrd_instr;                     /* 14: powerdown instr 
*/
+       uint32_t        quad_req;                       /* 15: quad enable 
requirements */
+       uint32_t        addr_reset;                     /* 16: 3-/4-byte 
addressing and reset */
+       uint32_t        read_1x8;                       /* 17: 1-1-8 and 1-8-8 
fast read instr and dummy */
+       uint32_t        dtr_drive;                      /* 18: dtr modes and 
drive strength */
+       uint32_t        octal_req;                      /* 19: octal enable 
requirements */
+       uint32_t        speed_888;                      /* 20: speed in 8-8-8 
modes */
+};
+
+struct sfdp_xspi_1_0_param {
+       uint32_t        status_cmds;            /* 01: commands for status reg. 
in 8-8-8 mode */
+       uint32_t        reg_cmds;                       /* 02: commands for 
(non-) volatile registers in 8-8-8 mode */
+       uint32_t        mem_cmds;                       /* 03: commands for 
memory accesses in 8-8-8 mode */
+       uint32_t        dummy_200;                      /* 04: dummy cycles for 
200 MHz */
+       uint32_t        dummy_166_100;          /* 05: dummy cycles for 100 to 
166 MHz */
+};
+
+struct sfdp_xspi_2_0_param {
+       uint32_t        opi_cmds;                       /* 01: commands in 
8-8-8 mode */
+       uint32_t        dummy_200;                      /* 02: dummy cycles for 
200 MHz */
+       uint32_t        dummy_166_100;          /* 03: dummy cycles for 100 to 
166 MHz */
+};
+
+struct sfdp_sector_map {
+       uint32_t        conf_descr_1;           /* 01: conf descriptor 1 */
+       uint32_t        conf_descr_2;           /* 02: conf descriptor 1 */
 };
 
 struct sfdp_4byte_addr_param {
-       uint32_t                        flags;                  /* 01: various 
flags */
-       uint32_t                        erase_t1234;    /* 02: erase commands */
+       uint32_t        flags;                          /* 01: various flags */
+       uint32_t        erase_t1234;            /* 02: erase commands */
+};
+
+struct sfdp_stat_ctrl_conf_param {
+       uint32_t        addr_offs_vol;          /* 01: address offset for 
volatile register */
+       uint32_t        addr_offs_nvol;         /* 02: address offset for 
non-volatile register */
+       uint32_t        stat_ctrl_vol;          /* 03: volatile status/control 
registers */
+       uint32_t        stat_ctrl_nvol;         /* 04: non-volatile 
status/control registers */
+       uint32_t        wip_bit;                        /* 05: WIP bit */
+       uint32_t        wel_bit;                        /* 06: WIP bit */
+       uint32_t        pe_bit;                         /* 07: PE bit */
+       uint32_t        ee_bit;                         /* 08: EE bit */
+       uint32_t        dummy_vol;                      /* 09: volatile dummy 
cycles */
+       uint32_t        dummy_nvol;                     /* 10: non-volatile 
dummy cycles */
+       uint32_t        dummy_bit_30_22;        /* 11: bit patterns for 30 to 
22 dummy cycles */
+       uint32_t        dummy_bit_20_12;        /* 12: bit patterns for 20 to 
12 dummy cycles */
+       uint32_t        dummy_bit_10_02;        /* 13: bit patterns for 10 to 
02 dummy cycles */
+       uint32_t        qpi_vol;                        /* 14: volatile QPI 
mode enable */
+       uint32_t        qpi_nvol;                       /* 15: non-volatile QPI 
mode enable */
+       uint32_t        opi_vol;                        /* 16: volatile OPI 
mode enable */
+       uint32_t        opi_nvol;                       /* 17: non-volatile OPI 
mode enable */
+       uint32_t        str_dtr_vol;            /* 18: volatile STR/DTR select 
*/
+       uint32_t        str_dtr_nvol;           /* 19: non-volatile STR/DTR 
mode select */
+       uint32_t        str_octal_vol;          /* 20: volatile STR octal mode 
enable */
+       uint32_t        str_octal_nvol;         /* 21: non-volatile STR octal 
mode enable */
+       uint32_t        dtr_octal_vol;          /* 22: volatile DTR octal mode 
enable */
+       uint32_t        dtr_octal_nvol;         /* 23: non-volatile DTR octal 
mode enable */
+       uint32_t        dpd_status;                     /* 24: deep power-down 
status */
+       uint32_t        udpd_status;            /* 25: ultra-deep power-down 
status */
+       uint32_t        drv_str_vol;            /* 26: volatile output driver 
stregth */
+       uint32_t        drv_str_nvol;           /* 27: non-volatile output 
driver stregth */
+       uint32_t        drv_str_bit;            /* 28: bit patterns for output 
drive strength */
+};
+
+struct sfdp_stat_ctrl_conf_2_0_param {
+       uint32_t        addr_offs_vol;          /* 01: address offset for 
volatile register */
+       uint32_t        addr_offs_nvol;         /* 02: address offset for 
non-volatile register */
+       uint32_t        stat_ctrl;                      /* 03: generic 
status/control registers */
+       uint32_t        pgm_err;                        /* 04: program error */
+       uint32_t        erase_err;                      /* 05: erase error */
+       uint32_t        dummy_vol;                      /* 06: volatile dummy 
cycles */
+       uint32_t        dummy_nvol;                     /* 07: non-volatile 
dummy cycles */
+       uint32_t        dummy_bit_30_22;        /* 08: bit patterns for 30 to 
22 dummy cycles */
+       uint32_t        dummy_bit_20_12;        /* 09: bit patterns for 20 to 
12 dummy cycles */
+       uint32_t        dummy_bit_10_02;        /* 10: bit patterns for 10 to 
02 dummy cycles */
+       uint32_t        drv_str_vol;            /* 11: volatile output driver 
stregth */
+       uint32_t        drv_str_nvol;           /* 12: non-volatile output 
driver stregth */
+       uint32_t        drv_str_bit;            /* 13: bit patterns for output 
drive strength */
 };
 
+static void wip_wle_access(uint32_t offset, int addr_bytes, uint32_t word, 
const char *name)
+{
+       if (word & BIT(31)) {
+               if (word & BIT(28)) {
+                       uint32_t addr = (((word >> 16) & 0xFFU) << ((word >> 
27) & 0x1)) + offset;
+                       LOG_INFO("SFDP %s: %s, Write (%s) 0x%02" PRIx8 ", Read 
0x%02" PRIx8 ", addr 0x%0*" PRIx32
+                               ", bit %" PRIx8, name, (word & BIT(30)) ? "neg" 
: "pos", (word & BIT(29)) ? "direct" : "bit",
+                               word & 0xFFU, (word >> 8) & 0xFFU, addr_bytes 
<< 1, addr, (word >> 24) & 0x7U);
+               } else {
+                       LOG_INFO("SFDP %s: %s, Write (%s) 0x%02" PRIx8 ", Read 
0x%02" PRIx8 ", bit %" PRIx8 ", %" PRIx8
+                               " dummy cycles", name, (word & BIT(30)) ? "neg" 
: "pos", (word & BIT(29)) ? "direct" : "bit",
+                               word & 0xFFU, (word >> 8) & 0xFFU, (word >> 24) 
& 0x7U, (word >> 16) & 0xFU);
+               }
+       } else {
+               LOG_DEBUG("SFDP %s: not supported", name);
+       }
+}
+
+static void qpi_opi_access(uint32_t offset, int addr_bytes, uint32_t word, 
const char *name)
+{
+       if (word & BIT(31)) {
+               if (word & BIT(28)) {
+                       uint32_t addr = (((word >> 16) & 0xFFU) << ((word >> 
27) & 0x1)) + offset;
+                       LOG_INFO("SFDP %s: %s, Write %s0x%02" PRIx8 ", Read 
0x%02" PRIx8 ", addr 0x%0*" PRIx32
+                               ", bit %" PRIx8, name, (word & BIT(30)) ? "neg" 
: "pos", (word & BIT(29)) ? "(OTP) " : "",
+                               word & 0xFFU, (word >> 8) & 0xFFU, addr_bytes 
<< 1, addr,
+                               (word >> 24) & 0x7);
+               } else {
+                       LOG_INFO("SFDP %s: %s, Write %s0x%02" PRIx8 ", Read 
0x%02" PRIx8 ", bit %" PRIx8 ", %" PRIx8
+                               " dummy cycles", name, (word & BIT(30)) ? "neg" 
: "pos", (word & BIT(29)) ? "(OTP) " : "",
+                               word & 0xFFU, (word >> 8) & 0xFFU, (word >> 24) 
& 0x7, (word >> 16) & 0xFU);
+               }
+       } else {
+               LOG_DEBUG("SFDP %s: not supported", name);
+       }
+}
+
 /* Try to get parameters from flash via SFDP */
 int spi_sfdp(struct flash_bank *bank, struct flash_device *dev,
        read_sfdp_block_t read_sfdp_block)
@@ -66,6 +183,7 @@ int spi_sfdp(struct flash_bank *bank, struct flash_device 
*dev,
        uint32_t *ptable = NULL;
        unsigned int j, k, nph;
        int retval, erase_type = 0;
+       uint8_t opi_read_fast_cmd = 0;
 
        memset(dev, 0, sizeof(struct flash_device));
 
@@ -76,11 +194,22 @@ int spi_sfdp(struct flash_bank *bank, struct flash_device 
*dev,
                return retval;
        LOG_DEBUG("header 0x%08" PRIx32 " 0x%08" PRIx32, header.signature, 
header.revision);
        if (header.signature != SFDP_MAGIC) {
-               LOG_INFO("no SDFP found");
+               LOG_INFO("Read SFDP: no header found");
                return ERROR_FLASH_BANK_NOT_PROBED;
        }
-       if (((header.revision >> 24) & 0xFF) != SFDP_ACCESS_PROT) {
-               LOG_ERROR("access protocol 0x%02x not implemented",
+
+       uint8_t sfdp_access = (header.revision >> 24) & 0xFFU;
+
+       if (sfdp_access == SFDP_ACCESS_QUAD_3_8) {
+               LOG_INFO("SFDP access protocol S/D/Q, 3-byte, 8 dummy");
+       } else if (sfdp_access == SFDP_ACCESS_OCT_3_8) {
+               LOG_INFO("SFDP access protocol Octal, 3-byte, 8 dummy");
+       } else if (sfdp_access == SFDP_ACCESS_OCT_4_20) {
+               LOG_INFO("SFDP access protocol Octal, 4-byte, 20 dummy");
+       } else if (sfdp_access == SFDP_ACCESS_OCT_4_8) {
+               LOG_INFO("SFDP access protocol Octal, 4-byte, 8 dummy");
+       } else {
+               LOG_ERROR("SFDP access protocol 0x%02" PRIx8 " unknown",
                        (header.revision >> 24) & 0xFFU);
                return ERROR_FLASH_BANK_NOT_PROBED;
        }
@@ -100,9 +229,9 @@ int spi_sfdp(struct flash_bank *bank, struct flash_device 
*dev,
                goto err;
 
        for (k = 0; k < nph; k++) {
-               uint8_t words = (pheaders[k].revision >> 24) & 0xFF;
-               uint16_t id = (((pheaders[k].ptr) >> 16) & 0xFF00) | 
(pheaders[k].revision & 0xFF);
-               uint32_t ptr = pheaders[k].ptr & 0xFFFFFF;
+               uint8_t words = (pheaders[k].revision >> 24) & 0xFFU;
+               uint16_t id = (((pheaders[k].ptr) >> 16) & 0xFF00U) | 
(pheaders[k].revision & 0xFFU);
+               uint32_t ptr = pheaders[k].ptr & 0xFFFFFFU;
 
                LOG_DEBUG("pheader %d len=0x%02" PRIx8 " id=0x%04" PRIx16
                        " ptr=0x%06" PRIx32, k, words, id, ptr);
@@ -119,19 +248,26 @@ int spi_sfdp(struct flash_bank *bank, struct flash_device 
*dev,
                        goto err;
 
                for (j = 0; j < words; j++)
-                       LOG_DEBUG("word %02d 0x%08X", j + 1, ptable[j]);
+                       LOG_DEBUG("word %02d 0x%08" PRIx32, j + 1, ptable[j]);
 
                if (id == SFDP_BASIC_FLASH) {
                        struct sfdp_basic_flash_param *table = (struct 
sfdp_basic_flash_param *)ptable;
                        uint16_t erase;
 
                        if (words < 9) {
-                               LOG_ERROR("id=0x%04" PRIx16 " invalid length 
%d", id, words);
+                               LOG_ERROR("id=0x%04" PRIx16 " invalid length %" 
PRIu8, id, words);
                                retval = ERROR_FLASH_BANK_NOT_PROBED;
                                goto err;
                        }
 
-                       LOG_DEBUG("basic flash parameter table");
+                       LOG_DEBUG("SFDP basic flash parameter table, length %" 
PRIu8, words);
+                       if (((offsetof(struct sfdp_basic_flash_param, 
chip_byte) >> 2) < words) &&
+                               (table->chip_byte == ~0U)) {
+                               /* ATXP032 indicates length 20 DWORDS but last 
10 apparently empty */
+                               LOG_WARNING("SFDP basic flash 11th word 
invalid, ignoring this and all following info");
+                               words = (offsetof(struct 
sfdp_basic_flash_param, chip_byte) >> 2) - 1;
+                       }
+
                        /* dummy device name */
                        dev->name = sfdp_name;
 
@@ -146,35 +282,47 @@ int spi_sfdp(struct flash_bank *bank, struct flash_device 
*dev,
                        else
                                dev->size_in_bytes = (table->density + 1) >> 3;
 
-                       /* 2-2-2 read instruction, not used */
-                       if (table->fast_444 & (1UL << 0))
-                               dev->qread_cmd = (table->read_222 >> 24) & 0xFF;
-
-                       /* 4-4-4 read instruction */
-                       if (table->fast_444 & (1UL << 4))
-                               dev->qread_cmd = (table->read_444 >> 24) & 0xFF;
+                       if ((table->fast_444 & (1UL << 4)) &&
+                               ((table->read_444 & 0xFFFFU) == 0xFFFFU)) {
+                               /* 4-4-4 read instruction */
+                               /* ATXP032 contains bogus data, check for bits 
15 to 0 all '1' */
+                               dev->qread_cmd = (table->read_444 >> 24) & 
0xFFU;
+                       } else if ((table->fast_444 & (1UL << 0)) &&
+                               ((table->read_222 & 0xFFFFU) == 0xFFFFU)) {
+                               /* fallback: 2-2-2 read instruction */
+                               dev->qread_cmd = (table->read_222 >> 24) & 
0xFFU;
+                       } else if ((offsetof(struct sfdp_basic_flash_param, 
read_1x8) >> 2) < words) {
+                               /* if no fast read so far, try the octal 
variants */
+                               if ((table->read_1x8 >> 8) & 0xFFU) {
+                                       /* fallback: 1-8-8 read instruction */
+                                       dev->qread_cmd = (table->read_1x8 >> 8) 
& 0xFFU;
+                               } else if ((table->read_1x8 >> 24) & 0xFFU) {
+                                       /* fallback: 1-1-8 read instruction */
+                                       dev->qread_cmd = (table->read_1x8 >> 
24) & 0xFFU;
+                               }
+                       }
 
                        /* find the largest erase block size and instruction */
-                       erase = (table->erase_t12 >> 0) & 0xFFFF;
+                       erase = (table->erase_t12 >> 0) & 0xFFFFU;
                        erase_type = 1;
-                       if (((table->erase_t12 >> 16) & 0xFF) > (erase & 0xFF)) 
{
-                               erase = (table->erase_t12 >> 16) & 0xFFFF;
+                       if (((table->erase_t12 >> 16) & 0xFFU) > (erase & 
0xFFU)) {
+                               erase = (table->erase_t12 >> 16) & 0xFFFFU;
                                erase_type = 2;
                        }
-                       if (((table->erase_t34 >> 0) & 0xFF) > (erase & 0xFF)) {
-                               erase = (table->erase_t34 >> 0) & 0xFFFF;
+                       if (((table->erase_t34 >> 0) & 0xFFU) > (erase & 
0xFFU)) {
+                               erase = (table->erase_t34 >> 0) & 0xFFFFU;
                                erase_type = 3;
                        }
-                       if (((table->erase_t34 >> 16) & 0xFF) > (erase & 0xFF)) 
{
-                               erase = (table->erase_t34 >> 16) & 0xFFFF;
+                       if (((table->erase_t34 >> 16) & 0xFFU) > (erase & 
0xFFU)) {
+                               erase = (table->erase_t34 >> 16) & 0xFFFFU;
                                erase_type = 4;
                        }
-                       dev->erase_cmd = (erase >> 8) & 0xFF;
-                       dev->sectorsize = 1UL << (erase & 0xFF);
+                       dev->erase_cmd = (erase >> 8) & 0xFFU;
+                       dev->sectorsize = 1UL << (erase & 0xFFU);
 
                        if ((offsetof(struct sfdp_basic_flash_param, chip_byte) 
>> 2) < words) {
                                /* get Program Page Size, if chip_byte present, 
that's optional */
-                               dev->pagesize = 1UL << ((table->chip_byte >> 4) 
& 0x0F);
+                               dev->pagesize = 1UL << ((table->chip_byte >> 4) 
& 0xFU);
                        } else {
                                /* no explicit page size specified ... */
                                if (table->fast_addr & (1UL << 2)) {
@@ -187,8 +335,8 @@ int spi_sfdp(struct flash_bank *bank, struct flash_device 
*dev,
                        }
 
                        if (dev->size_in_bytes > (1UL << 24)) {
-                               if (((table->fast_addr >> 17) & 0x3) == 0x0)
-                                       LOG_ERROR("device needs paging - not 
implemented");
+                               if (((table->fast_addr >> 17) & 0x3U) == 0x0U)
+                                       LOG_ERROR("SFDP device needs paging - 
not implemented");
 
                                /* 4-byte addresses needed if more than 16 
MBytes */
                                if (((offsetof(struct sfdp_basic_flash_param, 
addr_reset) >> 2) < words) &&
@@ -199,44 +347,368 @@ int spi_sfdp(struct flash_bank *bank, struct 
flash_device *dev,
                                        dev->read_cmd = 0x13;
                                        dev->pprog_cmd = 0x12;
                                        dev->erase_cmd = 0xDC;
-                                       if (dev->qread_cmd != 0)
+                                       if (dev->qread_cmd == 0xEB)
                                                dev->qread_cmd = 0xEC;
-                               } else if (((table->fast_addr >> 17) & 0x3) == 
0x1)
-                                       LOG_INFO("device has to be switched to 
4-byte addresses");
+                               } else if (((table->fast_addr >> 17) & 0x3) == 
0x1U)
+                                       LOG_INFO("SFDP device has to be 
switched to 4-byte addresses");
+                       }
+
+                       if ((offsetof(struct sfdp_basic_flash_param, quad_req) 
>> 2) < words) {
+                               switch ((table->quad_req >> 20) & 0x7U) {
+                                       case 0:
+                                               LOG_INFO("SFDP QER: none");
+                                               break;
+
+                                       case 1:
+                                               LOG_INFO("SFDP QER: Write 
Status Reg., QE is *second* data byte bit 1 "
+                                                       "(one data byte only 
implies second 0x00");
+                                               break;
+
+                                       case 2:
+                                               LOG_INFO("SFDP QER: Write 
Status Reg., QE is bit 6");
+                                               break;
+
+                                       case 3:
+                                               LOG_INFO("SFDP QER: Write 
Status Reg. 2, 0x3E, QE is bit 7");
+                                               break;
+
+                                       case 4:
+                                               LOG_INFO("SFDP QER: Write 
Status Reg., QE is *second* data byte bit 1 "
+                                                       "(one data byte only 
has no effect on second");
+                                               break;
+
+                                       case 5:
+                                               LOG_INFO("SFDP QER: Write 
Status, 0x01, QE is *second* data byte bit 1 "
+                                                       "(second byte read with 
0x35");
+                                               break;
+
+                                       case 6:
+                                               LOG_INFO("SFDP QER: Write 
Status Reg. 2, 0x31, QE is bit 1, (read with 0x35");
+                                               break;
+
+                                       case 7:
+                                               LOG_INFO("SFDP QER: reserved");
+                                               break;
+                               }
+
+                               if (table->quad_req & BIT(4))
+                                       LOG_INFO("SFDP QPI enter: set QE, then 
0x38");
+                               if (table->quad_req & BIT(5))
+                                       LOG_INFO("SFDP QPI enter: 0x38");
+                               if (table->quad_req & BIT(6))
+                                       LOG_INFO("SFDP QPI enter: 0x35");
+                               if (table->quad_req & BIT(7))
+                                       LOG_INFO("SFDP QPI enter: read by 0x65, 
addr 0x800003, set bit 6, write by 0x71, addr 0x800003");
+                               if (table->quad_req & BIT(8))
+                                       LOG_INFO("SFDP QPI enter/exit: read by 
0x65, clear/set bit 7, write by 0x61");
+                               if (table->quad_req & BIT(0))
+                                       LOG_INFO("SFDP QPI exit: 0xFF");
+                               if (table->quad_req & BIT(1))
+                                       LOG_INFO("SFDP QPI exit: 0xF5");
+                               if (table->quad_req & BIT(2))
+                                       LOG_INFO("SFDP QPI exit: read by 0x65, 
addr 0x800003, clear bit 6, write by 0x71, addr 0x800003");
+                               if (table->quad_req & BIT(3))
+                                       LOG_INFO("SFDP QPI exit: 0x66, 0x99");
+                       }
+
+                       if ((offsetof(struct sfdp_basic_flash_param, 
addr_reset) >> 2) < words) {
+                               if (table->addr_reset & BIT(24))
+                                       LOG_INFO("SFDP 4-byte enter: 0xB7");
+                               if (table->addr_reset & BIT(25))
+                                       LOG_INFO("SFDP 4-byte enter: 0x06, 
0xB7");
+                               if (table->addr_reset & BIT(26))
+                                       LOG_INFO("SFDP 4-byte: read address 
extension by 0xC8, write by 0xC5");
+                               if (table->addr_reset & BIT(27))
+                                       LOG_INFO("SFDP 4-byte enter/exit: read 
address extension by 0x16, "
+                                               "write by 0x17, bit 7 is 4-byte 
mode");
+                               if (table->addr_reset & BIT(28))
+                                       LOG_INFO("SFDP 4-byte enter/exit: read 
16-bit non-vol. reg. by 0xB5, write by 0xB1, 4-byte mode"
+                                               " is bit 0 in *second* data 
byte");
+                               if (table->addr_reset & BIT(29))
+                                       LOG_INFO("SFDP 4-byte: dedicated 4-byte 
instructions");
+                               if (table->addr_reset & BIT(30))
+                                       LOG_INFO("SFDP 4-byte: always");
+
+                               if (table->addr_reset & BIT(14))
+                                       LOG_INFO("SFDP 4-byte enter: 0xE9");
+                               if (table->addr_reset & BIT(15))
+                                       LOG_INFO("SFDP 4-byte enter: 0x06, 
0xE9");
+                               if (table->addr_reset & BIT(16))
+                                       LOG_INFO("SFDP 4-byte: read address 
extension by 0xC8, write by 0xC5");
+                               if (table->addr_reset & BIT(17))
+                                       LOG_INFO("SFDP 4-byte enter/exit: read 
address extension by 0x16, "
+                                               "write by 0x17, bit 7 is 4-byte 
mode");
+                               if (table->addr_reset & BIT(18))
+                                       LOG_INFO("SFDP 4-byte enter/exit: read 
16-bit non-vol. reg. by 0xB5, write by 0xB1, 4-byte mode"
+                                               " is bit 0 in *second* data 
byte");
+                               if (table->addr_reset & BIT(19))
+                                       LOG_INFO("SFDP 4-byte exit: hardware 
reset");
+                               if (table->addr_reset & BIT(20))
+                                       LOG_INFO("SFDP 4-byte exit: software 
reset");
+                               if (table->addr_reset & BIT(21))
+                                       LOG_INFO("SFDP 4-byte exit: power 
cycle");
+                       }
+
+                       if ((offsetof(struct sfdp_basic_flash_param, octal_req) 
>> 2) < words) {
+                               switch ((table->octal_req >> 20) & 0x7U) {
+                                       case 0:
+                                               LOG_INFO("SFDP OER: none");
+                                               break;
+
+                                       case 1:
+                                               LOG_INFO("SFDP OER: set by 
0x31, one data byte, OE is bit 3, clear by 0x3E, "
+                                                       "one data byte, read by 
0x65, addr 0x02, one dummy");
+                                               break;
+
+                                       default:
+                                               LOG_INFO("SFDP OER: reserved");
+                                               break;
+                               }
+
+                               if (table->octal_req & BIT(5))
+                                       LOG_INFO("SFDP OPI enter: 0x06, 0xE8");
+                               if (table->octal_req & BIT(6))
+                                       LOG_INFO("SFDP OPI enter: 0x06, 0x72, 
addr 0x000000, data 0x01 (STR) or data 0x02 (DTR)");
+                               if (table->octal_req & BIT(0))
+                                       LOG_INFO("SFDP OPI exit: 0x06, 0xFF");
+                               if (table->octal_req & BIT(3))
+                                       LOG_INFO("SFDP OPI exit: 0x66, 0x99");
+                       }
+
+               } else if ((id == SFDP_XSPI_1_0) || (id == SFDP_X4_QUAD_IO)) {
+                       struct sfdp_xspi_1_0_param *table = (struct 
sfdp_xspi_1_0_param *)ptable;
+
+                       if (words < sizeof(struct sfdp_xspi_1_0_param) / 
sizeof(uint32_t)) {
+                               LOG_ERROR("id=0x%04" PRIx16 " invalid length %" 
PRIu8, id, words);
+                               retval = ERROR_FLASH_BANK_NOT_PROBED;
+                               goto err;
+                       }
+
+                       const char *mode = (id == SFDP_XSPI_1_0) ? "OPI" : 
"QPI";
+                       if (id == SFDP_XSPI_1_0)
+                               LOG_DEBUG("xSPI profile 1.0 parameter table, 
length %" PRIu8, words);
+                       else
+                               LOG_DEBUG("x4 Quad IO parameter table, length 
%" PRIu8, words);
+
+                       if (table->status_cmds == ~0U) {
+                               /* ATXP032 has all 0xFFFFFFFF ... */
+                               LOG_WARNING("SFDP %s 1st word invalid, ignoring 
this table",
+                                       (id == SFDP_XSPI_1_0) ? "xSPI profile 
1.0" : "x4 Quad IO");
+                               goto skip;
+                       }
+
+                       LOG_INFO("%s: %d-byte address and %d dummy cycles for 
SFDP", mode,
+                               (table->status_cmds & BIT(31)) ? 3 : 4,
+                               (table->status_cmds & BIT(30)) ? 20 : 8);
+                       LOG_INFO("%s: latency %d, modifier %d for RDSR", mode,
+                               (table->status_cmds & BIT(28)) ? 8 : 4,
+                               (table->status_cmds & BIT(29)) ? 4 : 0);
+                       LOG_INFO("%s: latency %d, modifier %d for Read Vol. 
Reg.", mode,
+                               (table->status_cmds & BIT(26)) ? 8 : 4,
+                               (table->status_cmds & BIT(27)) ? 4 : 1);
+                       LOG_INFO("%s: latency %d, modifier %d for Read Non-Vol. 
Reg.", mode,
+                               (table->status_cmds & BIT(25)) ? 8 : 4,
+                               (table->status_cmds & BIT(27)) ? 4 : 1);
+                       LOG_INFO("%s: modifier bytes %d for WRSR, %d for Write 
Reg. "
+                               "with %d data bytes", mode, (table->status_cmds 
& BIT(24)) ? 4 : 0,
+                               (table->status_cmds & BIT(23)) ? 4 : 1,
+                               (table->status_cmds & BIT(22)) ? 2 : 1);
+                       opi_read_fast_cmd = (table->status_cmds >> 8) & 0xFFU;
+                       LOG_INFO("%s: Read Fast 0x%02" PRIx8 ", Read Fast 
Wrapped 0x%02" PRIx8, mode,
+                               opi_read_fast_cmd, (table->status_cmds >> 0) & 
0xFFU);
+                       if (table->mem_cmds & BIT(22))
+                               LOG_INFO("%s: Read Vol. Reg. 0x%02" PRIx8, mode,
+                                       (table->reg_cmds >> 24) & 0xFFU);
+                       if (table->mem_cmds & BIT(21))
+                               LOG_INFO("%s: Read Non-Vol. Reg. 0x%02" PRIx8, 
mode,
+                                       (table->reg_cmds >> 16) & 0xFFU);
+                       if (table->mem_cmds & BIT(17))
+                               LOG_INFO("%s: Write Vol. Reg. 0x%02" PRIx8, 
mode,
+                                       (table->reg_cmds >>  8) & 0xFFU);
+                       if (table->mem_cmds & BIT(16))
+                               LOG_INFO("%s: Write Non-Vol. Reg. 0x%02" PRIx8, 
mode,
+                                       (table->reg_cmds >>  0) & 0xFFU);
+                       LOG_INFO("%s: %sRead SFDP, %sErase 4KBytes, %sErase 
32kBytes, %sErase Chip", mode,
+                               (table->mem_cmds & BIT(31)) ? "" : "*NO* ",
+                               (table->mem_cmds & BIT(28)) ? "" : "*NO* ",
+                               (table->mem_cmds & BIT(27)) ? "" : "*NO* ",
+                               (table->mem_cmds & BIT(26)) ? "" : "*NO* ");
+                       LOG_INFO("%s: %sRead Conf. Reg., %sRead Reg., %sWrite 
Conf. Reg., %sWrite Reg.", mode,
+                               (table->mem_cmds & BIT(25)) ? "" : "*NO* ",
+                               (table->mem_cmds & BIT(23)) ? "" : "*NO* ",
+                               (table->mem_cmds & BIT(20)) ? "" : "*NO* ",
+                               (table->mem_cmds & BIT(18)) ? "" : "*NO* ");
+               } else if (id == SFDP_XSPI_2_0) {
+                       struct sfdp_xspi_2_0_param *table = (struct 
sfdp_xspi_2_0_param *)ptable;
+
+                       if (words < sizeof(struct sfdp_xspi_2_0_param) / 
sizeof(uint32_t)) {
+                               LOG_ERROR("id=0x%04" PRIx16 " invalid length %" 
PRIu8, id, words);
+                               retval = ERROR_FLASH_BANK_NOT_PROBED;
+                               goto err;
                        }
+
+                       LOG_DEBUG("xSPI profile 2.0 parameter table, length %" 
PRIu8, words);
+
+                       if (table->opi_cmds & BIT(31)) {
+                               if (table->opi_cmds & BIT(19))
+                                       LOG_INFO("OPI: Status Reg. Read");
+                               if (table->opi_cmds & BIT(13))
+                                       LOG_INFO("OPI: Sector Erase");
+                               if (table->opi_cmds & BIT(12))
+                                       LOG_INFO("OPI: Chip Erase");
+                               if (table->opi_cmds & BIT(5))
+                                       LOG_INFO("OPI: Enter SPI");
+                       } else {
+                               LOG_DEBUG("OPI DTR profile not implemented");
+                       }
+               } else if (id == SFDP_SECTOR_MAP) {
+                       struct sfdp_sector_map *table = (struct sfdp_sector_map 
*)ptable;
+
+                       if (words < sizeof(struct sfdp_sector_map) / 
sizeof(uint32_t)) {
+                               LOG_ERROR("id=0x%04" PRIx16 " invalid length %" 
PRIu8, id, words);
+                               goto skip;
+                       }
+
+                       LOG_DEBUG("sector map table, length %" PRIu8, words);
+                       (void)table->conf_descr_1;
                } else if (id == SFDP_4BYTE_ADDR) {
                        struct sfdp_4byte_addr_param *table = (struct 
sfdp_4byte_addr_param *)ptable;
 
                        if (words >= (offsetof(struct sfdp_4byte_addr_param, 
erase_t1234)
                                + sizeof(table->erase_t1234)) >> 2) {
-                               LOG_INFO("4-byte address parameter table");
+                               LOG_INFO("SFDP 4-byte address parameter table");
 
                                /* read and page program instructions */
                                if (table->flags & (1UL << 0))
                                        dev->read_cmd = 0x13;
+
                                if (table->flags & (1UL << 5))
                                        dev->qread_cmd = 0xEC;
+                               else if (table->flags & (1UL << 1))
+                                       dev->qread_cmd = 0x0C;
+                               else if (table->flags & (1UL << 2))
+                                       dev->qread_cmd = 0x3C;
+                               else if (table->flags & (1UL << 3))
+                                       dev->qread_cmd = 0xBC;
+                               else if (table->flags & (1UL << 4))
+                                       dev->qread_cmd = 0x6C;
+                               else if (table->flags & (1UL << 5))
+                                       dev->qread_cmd = 0xEC;
+
                                if (table->flags & (1UL << 6))
                                        dev->pprog_cmd = 0x12;
+                               else if (table->flags & (1UL << 7))
+                                       dev->pprog_cmd = 0x34;
+                               else if (table->flags & (1UL << 8))
+                                       dev->pprog_cmd = 0x3E;
 
                                /* erase instructions */
                                if ((erase_type == 1) && (table->flags & (1UL 
<< 9)))
-                                       dev->erase_cmd = (table->erase_t1234 >> 
0) & 0xFF;
+                                       dev->erase_cmd = (table->erase_t1234 >> 
0) & 0xFFU;
                                else if ((erase_type == 2) && (table->flags & 
(1UL << 10)))
-                                       dev->erase_cmd = (table->erase_t1234 >> 
8) & 0xFF;
+                                       dev->erase_cmd = (table->erase_t1234 >> 
8) & 0xFFU;
                                else if ((erase_type == 3) && (table->flags & 
(1UL << 11)))
-                                       dev->erase_cmd = (table->erase_t1234 >> 
16) & 0xFF;
+                                       dev->erase_cmd = (table->erase_t1234 >> 
16) & 0xFFU;
                                else if ((erase_type == 4) && (table->flags & 
(1UL << 12)))
-                                       dev->erase_cmd = (table->erase_t1234 >> 
24) & 0xFF;
+                                       dev->erase_cmd = (table->erase_t1234 >> 
24) & 0xFFU;
                        } else
-                               LOG_ERROR("parameter table id=0x%04" PRIx16 " 
invalid length %d", id, words);
+                               LOG_ERROR("parameter table id=0x%04" PRIx16 " 
invalid length %" PRIu8, id, words);
+               } else if (id == SFDP_STAT_CTRL_CONF) {
+                       struct sfdp_stat_ctrl_conf_param *table = (struct 
sfdp_stat_ctrl_conf_param *)ptable;
+
+                       if ((offsetof(struct sfdp_stat_ctrl_conf_param, 
wel_bit) >> 2) >= words) {
+                               LOG_ERROR("id=0x%04" PRIx16 " invalid length %" 
PRIu8, id, words);
+                               goto skip;
+                       }
+
+                       LOG_DEBUG("status, control and configuration register 
map table, length %" PRIu8, words);
+
+                       if (table->wip_bit == ~0U) {
+                               /* ATXP032 has all 0xFFFFFFFF ... */
+                               LOG_WARNING("SFDP Status, Control and 
Configuration Register Map "
+                                       "5th word invalid, ignoring this 
table");
+                               goto skip;
+                       }
+
+                       const unsigned int vol_addr = ((table->stat_ctrl_vol >> 
28) & 0x3U) + 1;
+                       LOG_INFO("SFDP: %d-byte addr for volatile", vol_addr);
+
+                       const unsigned int nvol_addr = ((table->stat_ctrl_nvol 
>> 28) & 0x3U) + 1;
+                       LOG_INFO("SFDP: %d-byte addr for non-volatile", 
nvol_addr);
+
+                       wip_wle_access(table->addr_offs_vol, vol_addr, 
table->wip_bit, "WIP");
+                       wip_wle_access(table->addr_offs_vol, vol_addr, 
table->wel_bit, "WEL");
+                       if ((offsetof(struct sfdp_stat_ctrl_conf_param, 
qpi_nvol) >> 2) < words) {
+                               qpi_opi_access(table->addr_offs_vol, vol_addr, 
table->qpi_vol, "vol. QPI");
+                               qpi_opi_access(table->addr_offs_nvol, 
nvol_addr, table->qpi_nvol, "non-vol. QPI");
+                       }
+                       if ((offsetof(struct sfdp_stat_ctrl_conf_param, 
opi_nvol) >> 2) < words) {
+                               qpi_opi_access(table->addr_offs_vol, vol_addr, 
table->opi_vol, "vol. OPI");
+                               qpi_opi_access(table->addr_offs_nvol, 
nvol_addr, table->opi_nvol, "non-vol. OPI");
+                       }
+                       if ((offsetof(struct sfdp_stat_ctrl_conf_param, 
str_dtr_nvol) >> 2) < words) {
+                               qpi_opi_access(table->addr_offs_vol, vol_addr, 
table->str_dtr_vol, "vol. STR/DTR");
+                               qpi_opi_access(table->addr_offs_nvol, 
nvol_addr, table->str_dtr_nvol, "non-vol. STR/DTR");
+                       }
+                       if ((offsetof(struct sfdp_stat_ctrl_conf_param, 
str_octal_nvol) >> 2) < words) {
+                               qpi_opi_access(table->addr_offs_vol, vol_addr, 
table->str_octal_vol, "vol. STR Octal");
+                               qpi_opi_access(table->addr_offs_nvol, 
nvol_addr, table->str_octal_nvol, "non-vol. STR Octal");
+                       }
+                       if ((offsetof(struct sfdp_stat_ctrl_conf_param, 
dtr_octal_nvol) >> 2) < words) {
+                               qpi_opi_access(table->addr_offs_vol, vol_addr, 
table->dtr_octal_vol, "vol. DTR Octal");
+                               qpi_opi_access(table->addr_offs_nvol, 
nvol_addr, table->dtr_octal_nvol, "non-vol. DTR Octal");
+                       }
+               } else if (id == SFDP_STAT_CTRL_CONF_2_0) {
+                       struct sfdp_stat_ctrl_conf_2_0_param *table = (struct 
sfdp_stat_ctrl_conf_2_0_param *)ptable;
+
+                       if ((offsetof(struct sfdp_stat_ctrl_conf_2_0_param, 
stat_ctrl) >> 2) >= words) {
+                               LOG_ERROR("id=0x%04" PRIx16 " invalid length %" 
PRIu8, id, words);
+                               goto skip;
+                       }
+
+                       LOG_DEBUG("status, control and configuration register 
map 2.0 table, length %" PRIu8, words);
+
+                       if (((table->stat_ctrl >> 28) & 0x3U) != 0x0) {
+                               LOG_ERROR("SFDP: reserved number of address 
bytes");
+                               goto skip;
+                       }
+
+                       LOG_INFO("SFDP: addr offset for volatile %0x08" PRIx32, 
table->addr_offs_vol);
+                       LOG_INFO("SFDP: addr offset for non-volatile %0x08" 
PRIx32, table->addr_offs_nvol);
+
+                       if (table->stat_ctrl & BIT(31))
+                               LOG_INFO("SFDP: generic addressable read for 
all registers, %d bytes", 6);
+                       if (table->stat_ctrl & BIT(30))
+                               LOG_INFO("SFDP: generic addressable write for 
all registers, %d bytes", 6);
+                       LOG_INFO("SFDP: %" PRIu8 " dummy for vol. registers, %" 
PRIu8 " dummy for non-vol. registers",
+                               (table->stat_ctrl >> 23) & 0x1FU, 
(table->stat_ctrl >> 18) & 0x1FU);
+                       if (table->stat_ctrl & BIT(17)) {
+                               uint32_t addr = (((table->stat_ctrl >> 3) & 
0xFFU) << ((table->stat_ctrl >> 15) & 0x1))
+                                       + table->addr_offs_vol;
+                               LOG_INFO("SFDP WIP: Read 0x%02" PRIx8 ", addr 
0x%0*" PRIx32 ", bit %" PRIu8,
+                                       0, 8, addr, (table->stat_ctrl >> 11) & 
0xFU);
+                       }
                } else
-                       LOG_DEBUG("unimplemented parameter table id=0x%04" 
PRIx16, id);
+                       if (((id >> 8) >= 0x1U) && (id >> 8) <= 0x7FU) {
+                               /* vendor owned */
+                               LOG_DEBUG("unimplemented vendor owned parameter 
table id=0x%04" PRIx16, id);
+                       } else {
+                               /* function specific */
+                               LOG_DEBUG("unimplemented function specific 
parameter table id=0x%04" PRIx16, id);
+                       }
 
+skip:
                free(ptable);
                ptable = NULL;
        }
 
+       if (opi_read_fast_cmd != 0 && dev->qread_cmd != opi_read_fast_cmd) {
+               /* OPI Read Fast takes precedence for octal-capable devices */
+               LOG_WARNING("OPI: Read Fast 0x%02" PRIx8 " overrides default 
Read Fast 0x%02" PRIx8,
+               opi_read_fast_cmd, dev->qread_cmd);
+               dev->qread_cmd = opi_read_fast_cmd;
+       }
+
        if (erase_type != 0) {
                LOG_INFO("valid SFDP detected");
                retval = ERROR_OK;

-- 

Reply via email to