]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
spi: cadence_qspi: Add support for page program using STIG write
authorSiva Durga Prasad Paladugu <siva.durga.paladugu@xilinx.com>
Sat, 11 Aug 2018 08:52:38 +0000 (14:22 +0530)
committerMichal Simek <michal.simek@xilinx.com>
Wed, 27 Feb 2019 07:50:42 +0000 (08:50 +0100)
This patch supports page programming using STIG write. This is needed
if controller support only STIG writes for page program instead of
regular indirect write support. So, this patch gets the controller
capability from dt using "cdns,is-stig-pgm" property. This patch also
modifies stig write routine to support for page programming.

Signed-off-by: Siva Durga Prasad Paladugu <siva.durga.paladugu@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
drivers/spi/cadence_qspi.c
drivers/spi/cadence_qspi.h
drivers/spi/cadence_qspi_apb.c

index 17b1932445e5a4ee5d122da8fc8e73b5af2bbfb1..7413d52ecfb5f11024ae157ca4ddf6ff323f8783 100644 (file)
@@ -228,7 +228,7 @@ static int cadence_spi_xfer(struct udevice *dev, unsigned int bitlen,
                                mode = CQSPI_INDIRECT_READ;
                } else if (dout && !(flags & SPI_XFER_BEGIN)) {
                        /* write */
-                       if (!CQSPI_IS_ADDR(priv->cmd_len))
+                       if (!CQSPI_IS_ADDR(priv->cmd_len) || plat->stg_pgm)
                                mode = CQSPI_STIG_WRITE;
                        else
                                mode = CQSPI_INDIRECT_WRITE;
@@ -242,9 +242,10 @@ static int cadence_spi_xfer(struct udevice *dev, unsigned int bitlen,
 
                break;
                case CQSPI_STIG_WRITE:
-                       err = cadence_qspi_apb_command_write(base,
-                               priv->cmd_len, cmd_buf,
-                               data_bytes, dout);
+                       err = cadence_qspi_apb_command_write(plat,
+                                                            priv->cmd_len,
+                                                            cmd_buf,
+                                                            data_bytes, dout);
                break;
                case CQSPI_INDIRECT_READ:
                        err = cadence_qspi_apb_indirect_read_setup(plat,
@@ -292,6 +293,7 @@ static int cadence_spi_ofdata_to_platdata(struct udevice *bus)
        plat->trigger_address = fdtdec_get_uint(blob, node,
                                                "cdns,trigger-address", 0);
        plat->is_dma = fdtdec_get_bool(blob, node, "cdns,is-dma");
+       plat->stg_pgm = fdtdec_get_bool(blob, node, "cdns,is-stig-pgm");
 
        /* All other paramters are embedded in the child node */
        subnode = fdt_first_subnode(blob, node);
index 233793d4dcee6e23bf9a5e10316b34a7cdc974e9..de57c7def8f1d166d32aa3d18a92f1eb84fe4f3b 100644 (file)
@@ -30,6 +30,7 @@ struct cadence_spi_platdata {
        u32             tchsh_ns;
        u32             tslch_ns;
        bool            is_dma;
+       bool            stg_pgm;
 };
 
 struct cadence_spi_priv {
@@ -52,9 +53,9 @@ void cadence_qspi_apb_controller_disable(void *reg_base_addr);
 
 int cadence_qspi_apb_command_read(void *reg_base_addr,
        unsigned int cmdlen, const u8 *cmdbuf, unsigned int rxlen, u8 *rxbuf);
-int cadence_qspi_apb_command_write(void *reg_base_addr,
-       unsigned int cmdlen, const u8 *cmdbuf,
-       unsigned int txlen,  const u8 *txbuf);
+int cadence_qspi_apb_command_write(struct cadence_spi_platdata *plat,
+                                  unsigned int cmdlen, const u8 *cmdbuf,
+                                  unsigned int txlen,  const u8 *txbuf);
 
 int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat,
        unsigned int cmdlen, unsigned int rx_width, const u8 *cmdbuf);
index e7b67c91bd355073e93c148d33b9854b46dd903d..c96476039b128e86f67fb7c2874efbbc83452ade 100644 (file)
@@ -493,20 +493,36 @@ int cadence_qspi_apb_command_read(void *reg_base,
 }
 
 /* For commands: WRSR, WREN, WRDI, CHIP_ERASE, BE, etc. */
-int cadence_qspi_apb_command_write(void *reg_base, unsigned int cmdlen,
-       const u8 *cmdbuf, unsigned int txlen,  const u8 *txbuf)
+int cadence_qspi_apb_command_write(struct cadence_spi_platdata *plat,
+                                  unsigned int cmdlen, const u8 *cmdbuf,
+                                  unsigned int txlen,  const u8 *txbuf)
 {
+       void *reg_base = plat->regbase;
        unsigned int reg = 0;
-       unsigned int addr_value;
+       unsigned int addr_value = 0;
        unsigned int wr_data;
        unsigned int wr_len;
+       bool pageprgm = false;
+       unsigned int pgmlen = 0;
+       int ret;
 
-       if (!cmdlen || cmdlen > 5 || txlen > 8 || cmdbuf == NULL) {
+       if (!cmdlen || cmdlen > 5 || cmdbuf == NULL) {
                printf("QSPI: Invalid input arguments cmdlen %d txlen %d\n",
                       cmdlen, txlen);
                return -EINVAL;
        }
 
+       if (txlen > 8) {
+               if (plat->stg_pgm) {
+                       pageprgm = true;
+                       pgmlen = txlen;
+                       txlen = 8;
+               } else {
+                       printf("%s Invalid txlen %d\n", __func__, txlen);
+                       return -EINVAL;
+               }
+       }
+
        reg |= cmdbuf[0] << CQSPI_REG_CMDCTRL_OPCODE_LSB;
 
        if (cmdlen == 4 || cmdlen == 5) {
@@ -540,10 +556,58 @@ int cadence_qspi_apb_command_write(void *reg_base, unsigned int cmdlen,
                        writel(wr_data, reg_base +
                                CQSPI_REG_CMDWRITEDATAUPPER);
                }
+
+               if (pageprgm) {
+                       pgmlen -= txlen;
+                       txbuf += wr_len;
+                       addr_value += txlen;
+               }
        }
 
        /* Execute the command */
-       return cadence_qspi_apb_exec_flash_cmd(reg_base, reg);
+       ret = cadence_qspi_apb_exec_flash_cmd(reg_base, reg);
+       if (ret)
+               return ret;
+
+       while (pgmlen) {
+               reg = 0x6 << CQSPI_REG_CMDCTRL_OPCODE_LSB;
+               ret = cadence_qspi_apb_exec_flash_cmd(reg_base, reg);
+               if (ret)
+                       return ret;
+
+               reg = cmdbuf[0] << CQSPI_REG_CMDCTRL_OPCODE_LSB;
+               reg |= (0x1 << CQSPI_REG_CMDCTRL_ADDR_EN_LSB);
+               reg |= ((cmdlen - 2) & CQSPI_REG_CMDCTRL_ADD_BYTES_MASK)
+                       << CQSPI_REG_CMDCTRL_ADD_BYTES_LSB;
+               writel(addr_value, reg_base + CQSPI_REG_CMDADDRESS);
+
+               reg |= (0x1 << CQSPI_REG_CMDCTRL_WR_EN_LSB);
+               reg |= ((txlen - 1) & CQSPI_REG_CMDCTRL_WR_BYTES_MASK)
+                       << CQSPI_REG_CMDCTRL_WR_BYTES_LSB;
+               wr_len = txlen > 4 ? 4 : txlen;
+               memcpy(&wr_data, txbuf, wr_len);
+               writel(wr_data, reg_base +
+                       CQSPI_REG_CMDWRITEDATALOWER);
+
+               if (txlen > 4) {
+                       txbuf += wr_len;
+                       wr_len = txlen - wr_len;
+                       memcpy(&wr_data, txbuf, wr_len);
+                       writel(wr_data, reg_base +
+                               CQSPI_REG_CMDWRITEDATAUPPER);
+               }
+
+               pgmlen -= txlen;
+               txbuf += wr_len;
+               addr_value += txlen;
+               txlen = pgmlen > 8 ? 8 : pgmlen;
+
+               ret =  cadence_qspi_apb_exec_flash_cmd(reg_base, reg);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
 }
 
 /* Opcode + Address (3/4 bytes) + dummy bytes (0-4 bytes) */