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:
committed by
Michal Simek
parent
075605d57e
commit
f8e0279def
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) */
|
||||
|
||||
Reference in New Issue
Block a user