spi: cadence_qspi: Add support for page program using STIG write

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>
This commit is contained in:
Siva Durga Prasad Paladugu
2018-08-11 14:22:38 +05:30
committed by Michal Simek
parent 075605d57e
commit f8e0279def
3 changed files with 79 additions and 12 deletions

View 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);

View 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);

View 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) */