@@ -1511,8 +1511,10 @@ static const struct flash_info *spi_nor_read_id(struct spi_nor *nor)
info = spi_nor_ids;
for (; info->name; info++) {
if (info->id_len) {
- if (!memcmp(info->id, id, info->id_len))
+ if ((!memcmp(info->id, id, info->id_len)) &&
+ memcpy(nor->spi->device_id, id, SPI_NOR_MAX_ID_LEN)) {
return info;
+ }
}
}
@@ -3944,7 +3946,7 @@ static struct spi_nor_fixups s28hx_t_fixups = {
static int spi_nor_micron_octal_dtr_enable(struct spi_nor *nor)
{
struct spi_mem_op op;
- u8 buf;
+ u8 *buf = nor->cmd_buf;
u8 addr_width = 3;
int ret;
@@ -3953,12 +3955,12 @@ static int spi_nor_micron_octal_dtr_enable(struct spi_nor *nor)
if (ret)
return ret;
- buf = 20;
+ *buf = 20;
op = (struct spi_mem_op)
SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_MT_WR_ANY_REG, 1),
SPI_MEM_OP_ADDR(addr_width, SPINOR_REG_MT_CFR1V, 1),
SPI_MEM_OP_NO_DUMMY,
- SPI_MEM_OP_DATA_OUT(1, &buf, 1));
+ SPI_MEM_OP_DATA_OUT(1, buf, 1));
ret = spi_mem_exec_op(nor->spi, &op);
if (ret)
return ret;
@@ -3973,18 +3975,33 @@ static int spi_nor_micron_octal_dtr_enable(struct spi_nor *nor)
if (ret)
return ret;
- buf = SPINOR_MT_OCT_DTR;
+ *buf = SPINOR_MT_OCT_DTR;
op = (struct spi_mem_op)
SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_MT_WR_ANY_REG, 1),
SPI_MEM_OP_ADDR(addr_width, SPINOR_REG_MT_CFR0V, 1),
SPI_MEM_OP_NO_DUMMY,
- SPI_MEM_OP_DATA_OUT(1, &buf, 1));
+ SPI_MEM_OP_DATA_OUT(1, buf, 1));
ret = spi_mem_exec_op(nor->spi, &op);
if (ret) {
dev_err(nor->dev, "Failed to enable octal DTR mode\n");
return ret;
}
+ /* Read flash ID to make sure the switch was successful. */
+ op = (struct spi_mem_op)
+ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDID, 0),
+ SPI_MEM_OP_ADDR(0, 0, 0),
+ SPI_MEM_OP_DUMMY(8, 0),
+ SPI_MEM_OP_DATA_IN(SPI_NOR_MAX_ID_LEN, buf, 0));
+
+ spi_nor_setup_op(nor, &op, SNOR_PROTO_8_8_8_DTR);
+
+ ret = spi_mem_exec_op(nor->spi, &op);
+ if (ret)
+ return ret;
+
+ nor->reg_proto = SNOR_PROTO_8_8_8_DTR;
+
return 0;
}
@@ -3996,18 +4013,19 @@ static void mt35xu512aba_default_init(struct spi_nor *nor)
static void mt35xu512aba_post_sfdp_fixup(struct spi_nor *nor,
struct spi_nor_flash_parameter *params)
{
- /* Set the Fast Read settings. */
- params->hwcaps.mask |= SNOR_HWCAPS_READ_8_8_8_DTR;
- spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_8_8_8_DTR],
- 0, 20, SPINOR_OP_MT_DTR_RD,
- SNOR_PROTO_8_8_8_DTR);
-
- params->hwcaps.mask |= SNOR_HWCAPS_PP_8_8_8_DTR;
+ if (params->hwcaps.mask & SNOR_HWCAPS_READ_8_8_8_DTR) {
+ /* Set the Fast Read settings. */
+ params->hwcaps.mask |= SNOR_HWCAPS_READ_8_8_8_DTR;
+ spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_8_8_8_DTR],
+ 0, 20, SPINOR_OP_MT_DTR_RD,
+ SNOR_PROTO_8_8_8_DTR);
- nor->cmd_ext_type = SPI_NOR_EXT_REPEAT;
- params->rdsr_dummy = 8;
- params->rdsr_addr_nbytes = 0;
+ params->hwcaps.mask |= SNOR_HWCAPS_PP_8_8_8_DTR;
+ nor->cmd_ext_type = SPI_NOR_EXT_REPEAT;
+ params->rdsr_dummy = 8;
+ params->rdsr_addr_nbytes = 0;
+ }
/*
* The BFPT quad enable field is set to a reserved value so the quad
* enable function is ignored by spi_nor_parse_bfpt(). Make sure we
@@ -15,6 +15,7 @@
#include <cpu_func.h>
#include <zynqmp_firmware.h>
#include <asm/arch/hardware.h>
+#include <soc.h>
#include "cadence_qspi.h"
#include <dt-bindings/power/xlnx-versal-power.h>
@@ -126,6 +127,30 @@ int cadence_qspi_apb_wait_for_dma_cmplt(struct cadence_spi_priv *priv)
return 0;
}
+static const struct soc_attr matches[] = {
+ { .family = "Versal", .revision = "v2" },
+ { }
+};
+
+/*
+ * cadence_qspi_versal_set_dll_mode checks for silicon version
+ * and set the DLL mode.
+ * Returns 0 in case of success, -ENOTSUPP in case of failure.
+ */
+int cadence_qspi_versal_set_dll_mode(struct udevice *dev)
+{
+ struct cadence_spi_priv *priv = dev_get_priv(dev);
+ const struct soc_attr *attr;
+
+ attr = soc_device_match(matches);
+ if (attr) {
+ priv->dll_mode = CQSPI_DLL_MODE_MASTER;
+ return 0;
+ }
+
+ return -ENOTSUPP;
+}
+
#if defined(CONFIG_DM_GPIO)
int cadence_qspi_versal_flash_reset(struct udevice *dev)
{
@@ -194,6 +194,20 @@ static int cadence_spi_set_speed(struct udevice *bus, uint hz)
return 0;
}
+static int cadence_spi_child_pre_probe(struct udevice *bus)
+{
+ struct spi_slave *slave = dev_get_parent_priv(bus);
+
+ slave->bytemode = SPI_4BYTE_MODE;
+
+ return 0;
+}
+
+__weak int cadence_qspi_versal_set_dll_mode(struct udevice *dev)
+{
+ return -ENOTSUPP;
+}
+
static int cadence_spi_probe(struct udevice *bus)
{
struct cadence_spi_plat *plat = dev_get_plat(bus);
@@ -250,6 +264,14 @@ static int cadence_spi_probe(struct udevice *bus)
priv->qspi_is_init = 1;
}
+ priv->edge_mode = CQSPI_EDGE_MODE_SDR;
+ priv->dll_mode = CQSPI_DLL_MODE_BYPASS;
+
+ /* Select dll mode */
+ ret = cadence_qspi_versal_set_dll_mode(bus);
+ if (ret == -ENOTSUPP)
+ debug("DLL mode set to bypass mode : %x\n", ret);
+
priv->wr_delay = 50 * DIV_ROUND_UP(NSEC_PER_SEC, priv->ref_clk_hz);
/* Versal and Versal-NET use spi calibration to set read delay */
@@ -293,6 +315,280 @@ static int cadence_spi_set_mode(struct udevice *bus, uint mode)
return 0;
}
+static int cadence_qspi_rx_dll_tuning(struct spi_slave *spi, const struct spi_mem_op *op,
+ u32 txtap, u8 extra_dummy)
+{
+ struct udevice *bus = spi->dev->parent;
+ struct cadence_spi_priv *priv = dev_get_priv(bus);
+ void *regbase = priv->regbase;
+ int ret, i, j;
+ u8 *id = op->data.buf.in;
+ u8 min_rxtap = 0, max_rxtap = 0, avg_rxtap,
+ max_tap, windowsize, dummy_flag = 0, max_index = 0, min_index = 0;
+ unsigned int reg;
+ s8 max_windowsize = -1;
+ bool id_matched, rxtapfound = false;
+
+ /* Return if octal-spi disabled */
+ reg = readl(regbase + CQSPI_REG_CONFIG);
+ reg &= CQSPI_REG_CONFIG_ENABLE;
+ if (!reg)
+ return 0;
+
+ max_tap = CQSPI_MAX_DLL_TAPS;
+ /*
+ * Rx dll tuning is done by setting tx delay and increment rx
+ * delay and check for correct flash id's by reading from flash.
+ */
+ for (i = 0; i <= max_tap; i++) {
+ /* Set DLL reset bit */
+ writel((txtap | i | CQSPI_REG_PHY_CONFIG_RESET_FLD_MASK),
+ regbase + CQSPI_REG_PHY_CONFIG);
+ /*
+ * Re-synchronisation delay lines to update them
+ * with values from TX DLL Delay and RX DLL Delay fields
+ */
+ writel((CQSPI_REG_PHY_CONFIG_RESYNC_FLD_MASK | txtap | i |
+ CQSPI_REG_PHY_CONFIG_RESET_FLD_MASK),
+ regbase + CQSPI_REG_PHY_CONFIG);
+ /* Check lock of loopback */
+ if (priv->dll_mode == CQSPI_DLL_MODE_MASTER) {
+ ret = wait_for_bit_le32
+ (regbase + CQSPI_REG_DLL_LOWER,
+ CQSPI_REG_DLL_LOWER_LPBK_LOCK_MASK, 1,
+ CQSPI_TIMEOUT_MS, 0);
+ if (ret) {
+ printf("LOWER_DLL_LOCK bit err: %i\n", ret);
+ return ret;
+ }
+ }
+
+ ret = cadence_qspi_apb_command_read_setup(priv, op);
+ if (!ret) {
+ ret = cadence_qspi_apb_command_read(priv, op);
+ if (ret < 0) {
+ printf("error %d reading JEDEC ID\n", ret);
+ return ret;
+ }
+ }
+
+ id_matched = true;
+ for (j = 0; j < op->data.nbytes; j++) {
+ if (spi->device_id[j] != id[j]) {
+ id_matched = false;
+ break;
+ }
+ }
+
+ if (id_matched && !rxtapfound) {
+ if (priv->dll_mode == CQSPI_DLL_MODE_MASTER) {
+ min_rxtap =
+ readl(regbase + CQSPI_REG_DLL_OBSVBLE_UPPER) &
+ CQSPI_REG_DLL_UPPER_RX_FLD_MASK;
+ max_rxtap = min_rxtap;
+ max_index = i;
+ min_index = i;
+ } else {
+ min_rxtap = i;
+ max_rxtap = i;
+ }
+ rxtapfound = true;
+ }
+
+ if (id_matched && rxtapfound) {
+ if (priv->dll_mode == CQSPI_DLL_MODE_MASTER) {
+ max_rxtap =
+ readl(regbase +
+ CQSPI_REG_DLL_OBSVBLE_UPPER) &
+ CQSPI_REG_DLL_UPPER_RX_FLD_MASK;
+ max_index = i;
+ } else {
+ max_rxtap = i;
+ }
+ }
+
+ if ((!id_matched || i == max_tap) && rxtapfound) {
+ windowsize = max_rxtap - min_rxtap + 1;
+ if (windowsize > max_windowsize) {
+ dummy_flag = extra_dummy;
+ max_windowsize = windowsize;
+ if (priv->dll_mode == CQSPI_DLL_MODE_MASTER)
+ avg_rxtap = (max_index + min_index);
+ else
+ avg_rxtap = (max_rxtap + min_rxtap);
+ avg_rxtap /= 2;
+ }
+
+ if (windowsize >= 3)
+ i = max_tap;
+
+ rxtapfound = false;
+ }
+ }
+
+ if (!extra_dummy) {
+ rxtapfound = false;
+ min_rxtap = 0;
+ max_rxtap = 0;
+ }
+
+ if (!dummy_flag)
+ priv->extra_dummy = false;
+
+ if (max_windowsize < 3)
+ return -EINVAL;
+
+ return avg_rxtap;
+}
+
+static int cadence_spi_setdlldelay(struct spi_slave *spi, const struct spi_mem_op *op)
+{
+ struct udevice *bus = spi->dev->parent;
+ struct cadence_spi_priv *priv = dev_get_priv(bus);
+ void *regbase = priv->regbase;
+ u32 txtap;
+ int ret, rxtap;
+ u8 extra_dummy;
+
+ ret = wait_for_bit_le32(regbase + CQSPI_REG_CONFIG,
+ 1 << CQSPI_REG_CONFIG_IDLE_LSB,
+ 1, CQSPI_TIMEOUT_MS, 0);
+ if (ret) {
+ printf("spi_wait_idle error : 0x%x\n", ret);
+ return ret;
+ }
+
+ if (priv->dll_mode == CQSPI_DLL_MODE_MASTER) {
+ /* Drive DLL reset bit to low */
+ writel(0, regbase + CQSPI_REG_PHY_CONFIG);
+
+ /* Set initial delay value */
+ writel(CQSPI_REG_PHY_INITIAL_DLY,
+ regbase + CQSPI_REG_PHY_MASTER_CTRL);
+ /* Set DLL reset bit */
+ writel(CQSPI_REG_PHY_CONFIG_RESET_FLD_MASK,
+ regbase + CQSPI_REG_PHY_CONFIG);
+
+ /* Check for loopback lock */
+ ret = wait_for_bit_le32(regbase + CQSPI_REG_DLL_LOWER,
+ CQSPI_REG_DLL_LOWER_LPBK_LOCK_MASK,
+ 1, CQSPI_TIMEOUT_MS, 0);
+ if (ret) {
+ printf("Loopback lock bit error (%i)\n", ret);
+ return ret;
+ }
+
+ /* Re-synchronize slave DLLs */
+ writel(CQSPI_REG_PHY_CONFIG_RESET_FLD_MASK,
+ regbase + CQSPI_REG_PHY_CONFIG);
+ writel(CQSPI_REG_PHY_CONFIG_RESET_FLD_MASK |
+ CQSPI_REG_PHY_CONFIG_RESYNC_FLD_MASK,
+ regbase + CQSPI_REG_PHY_CONFIG);
+
+ txtap = CQSPI_TX_TAP_MASTER <<
+ CQSPI_REG_PHY_CONFIG_TX_DLL_DLY_LSB;
+ }
+
+ priv->extra_dummy = false;
+ for (extra_dummy = 0; extra_dummy <= 1; extra_dummy++) {
+ if (extra_dummy)
+ priv->extra_dummy = true;
+
+ rxtap = cadence_qspi_rx_dll_tuning(spi, op, txtap, extra_dummy);
+ if (extra_dummy && rxtap < 0) {
+ printf("Failed RX dll tuning\n");
+ return rxtap;
+ }
+ }
+ debug("RXTAP: %d\n", rxtap);
+
+ writel((txtap | rxtap | CQSPI_REG_PHY_CONFIG_RESET_FLD_MASK),
+ regbase + CQSPI_REG_PHY_CONFIG);
+ writel((CQSPI_REG_PHY_CONFIG_RESYNC_FLD_MASK | txtap | rxtap |
+ CQSPI_REG_PHY_CONFIG_RESET_FLD_MASK),
+ regbase + CQSPI_REG_PHY_CONFIG);
+
+ if (priv->dll_mode == CQSPI_DLL_MODE_MASTER) {
+ ret = wait_for_bit_le32(regbase + CQSPI_REG_DLL_LOWER,
+ CQSPI_REG_DLL_LOWER_LPBK_LOCK_MASK,
+ 1, CQSPI_TIMEOUT_MS, 0);
+ if (ret) {
+ printf("LOWER_DLL_LOCK bit err: %i\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int priv_setup_ddrmode(struct udevice *bus)
+{
+ struct cadence_spi_priv *priv = dev_get_priv(bus);
+ void *regbase = priv->regbase;
+ int ret;
+
+ ret = wait_for_bit_le32(regbase + CQSPI_REG_CONFIG,
+ 1 << CQSPI_REG_CONFIG_IDLE_LSB,
+ 1, CQSPI_TIMEOUT_MS, 0);
+ if (ret) {
+ printf("spi_wait_idle error : 0x%x\n", ret);
+ return ret;
+ }
+
+ /* Disable QSPI */
+ cadence_qspi_apb_controller_disable(regbase);
+
+ /* Disable DAC mode */
+ if (priv->use_dac_mode) {
+ clrbits_le32(regbase + CQSPI_REG_CONFIG,
+ CQSPI_REG_CONFIG_DIRECT);
+ priv->use_dac_mode = false;
+ }
+
+ setbits_le32(regbase + CQSPI_REG_CONFIG,
+ CQSPI_REG_CONFIG_PHY_ENABLE_MASK);
+
+ /* Program POLL_CNT */
+ clrsetbits_le32(regbase + CQSPI_REG_WRCOMPLETION,
+ CQSPI_REG_WRCOMPLETION_POLLCNT_MASK,
+ CQSPI_REG_WRCOMPLETION_POLLCNT <<
+ CQSPI_REG_WRCOMPLETION_POLLCNY_LSB);
+
+ setbits_le32(regbase + CQSPI_REG_CONFIG,
+ CQSPI_REG_CONFIG_DTR_PROT_EN_MASK);
+
+ clrsetbits_le32(regbase + CQSPI_REG_RD_DATA_CAPTURE,
+ (CQSPI_REG_RD_DATA_CAPTURE_DELAY_MASK <<
+ CQSPI_REG_RD_DATA_CAPTURE_DELAY_LSB),
+ CQSPI_REG_READCAPTURE_DQS_ENABLE);
+
+ /* Enable QSPI */
+ cadence_qspi_apb_controller_enable(regbase);
+
+ return 0;
+}
+
+static int cadence_spi_setup_ddrmode(struct spi_slave *spi, const struct spi_mem_op *op)
+{
+ struct udevice *bus = spi->dev->parent;
+ struct cadence_spi_priv *priv = dev_get_priv(bus);
+ int ret;
+
+ ret = priv_setup_ddrmode(bus);
+ if (ret)
+ return ret;
+
+ priv->edge_mode = CQSPI_EDGE_MODE_DDR;
+ ret = cadence_spi_setdlldelay(spi, op);
+ if (ret) {
+ printf("DDR tuning failed with error %d\n", ret);
+ return ret;
+ }
+ priv->ddr_init = 1;
+
+ return 0;
+}
+
static int cadence_spi_mem_exec_op(struct spi_slave *spi,
const struct spi_mem_op *op)
{
@@ -353,6 +649,9 @@ static int cadence_spi_mem_exec_op(struct spi_slave *spi,
break;
}
+ if (op->cmd.dtr)
+ err = cadence_spi_setup_ddrmode(spi, op);
+
return err;
}
@@ -469,6 +768,7 @@ U_BOOT_DRIVER(cadence_spi) = {
.plat_auto = sizeof(struct cadence_spi_plat),
.priv_auto = sizeof(struct cadence_spi_priv),
.probe = cadence_spi_probe,
+ .child_pre_probe = cadence_spi_child_pre_probe,
.remove = cadence_spi_remove,
.flags = DM_FLAG_OS_PREPARE,
};
@@ -10,6 +10,7 @@
#include <reset.h>
#include <linux/mtd/spi-nor.h>
#include <spi-mem.h>
+#include <wait_bit.h>
#define CQSPI_IS_ADDR(cmd_len) (cmd_len > 1 ? 1 : 0)
@@ -21,6 +22,8 @@
#define CQSPI_REG_RETRY 10000
#define CQSPI_POLL_IDLE_RETRY 3
+#define CQSPI_TIMEOUT_MS 1000
+
/* Transfer mode */
#define CQSPI_INST_TYPE_SINGLE 0
#define CQSPI_INST_TYPE_DUAL 1
@@ -37,6 +40,22 @@
#define CMD_4BYTE_OCTAL_READ 0x7c
#define CMD_4BYTE_READ 0x13
+#define CQSPI_TX_TAP_MASTER 0x1E
+#define CQSPI_MAX_DLL_TAPS 127
+
+#define CQSPI_DLL_MODE_MASTER 0
+#define CQSPI_DLL_MODE_BYPASS 1
+
+#define CQSPI_EDGE_MODE_SDR 0
+#define CQSPI_EDGE_MODE_DDR 1
+
+#define SILICON_VER_MASK 0xFF
+#define SILICON_VER_1 0x10
+
+#define CQSPI_READ_ID 0x9F
+#define CQSPI_READID_LOOP_MAX 10
+#define TERA_MACRO 1000000000000l
+
/****************************************************************************
* Controller's configuration and status register (offset from QSPI_BASE)
****************************************************************************/
@@ -69,6 +88,7 @@
#define CQSPI_REG_RD_INSTR_TYPE_ADDR_MASK 0x3
#define CQSPI_REG_RD_INSTR_TYPE_DATA_MASK 0x3
#define CQSPI_REG_RD_INSTR_DUMMY_MASK 0x1F
+#define CQSPI_REG_RD_INSTR_DDR_ENABLE BIT(10)
#define CQSPI_REG_WR_INSTR 0x08
#define CQSPI_REG_WR_INSTR_OPCODE_LSB 0
@@ -113,9 +133,14 @@
#define CQSPI_REG_WR_COMPLETION_CTRL 0x38
#define CQSPI_REG_WR_DISABLE_AUTO_POLL BIT(14)
+#define CQSPI_REG_WRCOMPLETION 0x38
+#define CQSPI_REG_WRCOMPLETION_POLLCNT_MASK 0xFF0000
+#define CQSPI_REG_WRCOMPLETION_POLLCNY_LSB 16
+#define CQSPI_REG_WRCOMPLETION_POLLCNT 3
#define CQSPI_REG_IRQSTATUS 0x40
#define CQSPI_REG_IRQMASK 0x44
+#define CQSPI_REG_ECO 0x48
#define CQSPI_REG_INDIRECTRD 0x60
#define CQSPI_REG_INDIRECTRD_START BIT(0)
@@ -166,7 +191,31 @@
#define CQSPI_REG_OP_EXT_STIG_LSB 0
#define CQSPI_REG_PHY_CONFIG 0xB4
+#define CQSPI_REG_PHY_CONFIG_RESYNC_FLD_MASK 0x80000000
#define CQSPI_REG_PHY_CONFIG_RESET_FLD_MASK 0x40000000
+#define CQSPI_REG_PHY_CONFIG_TX_DLL_DLY_LSB 16
+
+#define CQSPI_REG_PHY_MASTER_CTRL 0xB8
+#define CQSPI_REG_PHY_INITIAL_DLY 0x4
+#define CQSPI_REG_DLL_LOWER 0xBC
+#define CQSPI_REG_DLL_LOWER_LPBK_LOCK_MASK 0x8000
+#define CQSPI_REG_DLL_LOWER_DLL_LOCK_MASK 0x1
+
+#define CQSPI_REG_DLL_OBSVBLE_UPPER 0xC0
+#define CQSPI_REG_DLL_UPPER_RX_FLD_MASK 0x7F
+
+#define CQSPI_REG_EXT_OP_LOWER 0xE0
+#define CQSPI_REG_EXT_STIG_OP_MASK 0xFF
+#define CQSPI_REG_EXT_READ_OP_MASK 0xFF000000
+#define CQSPI_REG_EXT_READ_OP_SHIFT 24
+#define CQSPI_REG_EXT_WRITE_OP_MASK 0xFF0000
+#define CQSPI_REG_EXT_WRITE_OP_SHIFT 16
+#define CQSPI_REG_DMA_SRC_ADDR 0x1000
+#define CQSPI_REG_DMA_DST_ADDR 0x1800
+#define CQSPI_REG_DMA_DST_SIZE 0x1804
+#define CQSPI_REG_DMA_DST_STS 0x1808
+#define CQSPI_REG_DMA_DST_CTRL 0x180C
+#define CQSPI_REG_DMA_DST_CTRL_VAL 0xF43FFA00
#define CQSPI_DMA_DST_ADDR_REG 0x1800
#define CQSPI_DMA_DST_SIZE_REG 0x1804
@@ -309,6 +358,7 @@ int cadence_qspi_apb_wait_for_dma_cmplt(struct cadence_spi_priv *priv);
int cadence_qspi_apb_exec_flash_cmd(void *reg_base, unsigned int reg);
int cadence_qspi_versal_flash_reset(struct udevice *dev);
ofnode cadence_qspi_get_subnode(struct udevice *dev);
+int cadence_qspi_versal_set_dll_mode(struct udevice *dev);
void cadence_qspi_apb_enable_linear_mode(bool enable);
#endif /* __CADENCE_QSPI_H__ */
@@ -464,6 +464,9 @@ int cadence_qspi_apb_command_read(struct cadence_spi_priv *priv,
unsigned int dummy_clk;
u8 opcode;
+ if (priv->dtr)
+ rxlen = ((rxlen % 2) != 0) ? (rxlen + 1) : rxlen;
+
if (priv->dtr)
opcode = op->cmd.opcode >> 8;
else
@@ -479,6 +482,9 @@ int cadence_qspi_apb_command_read(struct cadence_spi_priv *priv,
if (dummy_clk > CQSPI_DUMMY_CLKS_MAX)
return -ENOTSUPP;
+ if (priv->extra_dummy)
+ dummy_clk++;
+
if (dummy_clk)
reg |= (dummy_clk & CQSPI_REG_CMDCTRL_DUMMY_MASK)
<< CQSPI_REG_CMDCTRL_DUMMY_LSB;
@@ -555,6 +561,9 @@ int cadence_qspi_apb_command_write(struct cadence_spi_priv *priv,
void *reg_base = priv->regbase;
u8 opcode;
+ if (priv->dtr)
+ txlen = ((txlen % 2) != 0) ? (txlen + 1) : txlen;
+
if (priv->dtr)
opcode = op->cmd.opcode >> 8;
else
@@ -611,7 +620,6 @@ int cadence_qspi_apb_command_write(struct cadence_spi_priv *priv,
int cadence_qspi_apb_read_setup(struct cadence_spi_priv *priv,
const struct spi_mem_op *op)
{
- unsigned int reg;
unsigned int rd_reg;
unsigned int dummy_clk;
unsigned int dummy_bytes = op->dummy.nbytes;
@@ -649,6 +657,9 @@ int cadence_qspi_apb_read_setup(struct cadence_spi_priv *priv,
if (dummy_clk > CQSPI_DUMMY_CLKS_MAX)
return -ENOTSUPP;
+ if (priv->extra_dummy)
+ dummy_clk++;
+
if (dummy_clk)
rd_reg |= (dummy_clk & CQSPI_REG_RD_INSTR_DUMMY_MASK)
<< CQSPI_REG_RD_INSTR_DUMMY_LSB;
@@ -657,10 +668,10 @@ int cadence_qspi_apb_read_setup(struct cadence_spi_priv *priv,
writel(rd_reg, priv->regbase + CQSPI_REG_RD_INSTR);
/* set device size */
- reg = readl(priv->regbase + CQSPI_REG_SIZE);
- reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK;
- reg |= (op->addr.nbytes - 1);
- writel(reg, priv->regbase + CQSPI_REG_SIZE);
+ clrsetbits_le32(priv->regbase + CQSPI_REG_SIZE,
+ CQSPI_REG_SIZE_ADDRESS_MASK,
+ op->addr.nbytes - 1);
+
return 0;
}
@@ -830,10 +841,10 @@ int cadence_qspi_apb_write_setup(struct cadence_spi_priv *priv,
writel(reg, priv->regbase + CQSPI_REG_WR_COMPLETION_CTRL);
}
- reg = readl(priv->regbase + CQSPI_REG_SIZE);
- reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK;
- reg |= (op->addr.nbytes - 1);
- writel(reg, priv->regbase + CQSPI_REG_SIZE);
+ clrsetbits_le32(priv->regbase + CQSPI_REG_SIZE,
+ CQSPI_REG_SIZE_ADDRESS_MASK,
+ op->addr.nbytes - 1);
+
return 0;
}
@@ -848,6 +859,10 @@ cadence_qspi_apb_indirect_write_execute(struct cadence_spi_priv *priv,
unsigned int write_bytes;
int ret;
+ if (priv->edge_mode == CQSPI_EDGE_MODE_DDR && (n_tx % 2) != 0)
+ n_tx++;
+ remaining = n_tx;
+
/*
* Use bounce buffer for non 32 bit aligned txbuf to avoid data
* aborts
@@ -50,6 +50,8 @@
/* Max no. of CS supported per spi device */
#define SPI_CS_CNT_MAX 2
+#define SPI_MEM_DEV_MAX_ID_LEN 6
+
/**
* struct dm_spi_bus - SPI bus info
*
@@ -157,6 +159,7 @@ struct spi_slave {
unsigned int bus;
unsigned int cs;
#endif
+ u8 device_id[SPI_MEM_DEV_MAX_ID_LEN];
uint mode;
unsigned int wordlen;
unsigned int max_read_size;