summaryrefslogtreecommitdiff
path: root/drivers/spi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/cadence_qspi.c16
-rw-r--r--drivers/spi/cadence_qspi_apb.c56
-rw-r--r--drivers/spi/npcm_fiu_spi.c72
-rw-r--r--drivers/spi/spi-mem.c8
-rw-r--r--drivers/spi/spi-sn-f-ospi.c2
-rw-r--r--drivers/spi/spi-synquacer.c4
6 files changed, 115 insertions, 43 deletions
diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c
index c7f10c50132..f931e4cf3e2 100644
--- a/drivers/spi/cadence_qspi.c
+++ b/drivers/spi/cadence_qspi.c
@@ -312,13 +312,12 @@ static int cadence_spi_mem_exec_op(struct spi_slave *spi,
* which is unsupported on some flash devices during register
* reads, prefer STIG mode for such small reads.
*/
- if (!op->addr.nbytes ||
- op->data.nbytes <= CQSPI_STIG_DATA_LEN_MAX)
+ if (op->data.nbytes <= CQSPI_STIG_DATA_LEN_MAX)
mode = CQSPI_STIG_READ;
else
mode = CQSPI_READ;
} else {
- if (!op->addr.nbytes || !op->data.buf.out)
+ if (op->data.nbytes <= CQSPI_STIG_DATA_LEN_MAX)
mode = CQSPI_STIG_WRITE;
else
mode = CQSPI_WRITE;
@@ -362,8 +361,15 @@ static bool cadence_spi_mem_supports_op(struct spi_slave *slave,
{
bool all_true, all_false;
- all_true = op->cmd.dtr && op->addr.dtr && op->dummy.dtr &&
- op->data.dtr;
+ /*
+ * op->dummy.dtr is required for converting nbytes into ncycles.
+ * Also, don't check the dtr field of the op phase having zero nbytes.
+ */
+ all_true = op->cmd.dtr &&
+ (!op->addr.nbytes || op->addr.dtr) &&
+ (!op->dummy.nbytes || op->dummy.dtr) &&
+ (!op->data.nbytes || op->data.dtr);
+
all_false = !op->cmd.dtr && !op->addr.dtr && !op->dummy.dtr &&
!op->data.dtr;
diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c
index 21fe2e655c5..9ce2c0f254f 100644
--- a/drivers/spi/cadence_qspi_apb.c
+++ b/drivers/spi/cadence_qspi_apb.c
@@ -120,7 +120,16 @@ static int cadence_qspi_set_protocol(struct cadence_spi_priv *priv,
{
int ret;
- priv->dtr = op->data.dtr && op->cmd.dtr && op->addr.dtr;
+ /*
+ * For an op to be DTR, cmd phase along with every other non-empty
+ * phase should have dtr field set to 1. If an op phase has zero
+ * nbytes, ignore its dtr field; otherwise, check its dtr field.
+ * Also, dummy checks not performed here Since supports_op()
+ * already checks that all or none of the fields are DTR.
+ */
+ priv->dtr = op->cmd.dtr &&
+ (!op->addr.nbytes || op->addr.dtr) &&
+ (!op->data.nbytes || op->data.dtr);
ret = cadence_qspi_buswidth_to_inst_type(op->cmd.buswidth);
if (ret < 0)
@@ -367,6 +376,9 @@ int cadence_qspi_apb_exec_flash_cmd(void *reg_base, unsigned int reg)
if (!cadence_qspi_wait_idle(reg_base))
return -EIO;
+ /* Flush the CMDCTRL reg after the execution */
+ writel(0, reg_base + CQSPI_REG_CMDCTRL);
+
return 0;
}
@@ -453,11 +465,6 @@ int cadence_qspi_apb_command_read(struct cadence_spi_priv *priv,
unsigned int dummy_clk;
u8 opcode;
- if (rxlen > CQSPI_STIG_DATA_LEN_MAX || !rxbuf) {
- printf("QSPI: Invalid input arguments rxlen %u\n", rxlen);
- return -EINVAL;
- }
-
if (priv->dtr)
opcode = op->cmd.opcode >> 8;
else
@@ -540,26 +547,12 @@ int cadence_qspi_apb_command_write(struct cadence_spi_priv *priv,
unsigned int reg = 0;
unsigned int wr_data;
unsigned int wr_len;
+ unsigned int dummy_clk;
unsigned int txlen = op->data.nbytes;
const void *txbuf = op->data.buf.out;
void *reg_base = priv->regbase;
- u32 addr;
u8 opcode;
- /* Reorder address to SPI bus order if only transferring address */
- if (!txlen) {
- addr = cpu_to_be32(op->addr.val);
- if (op->addr.nbytes == 3)
- addr >>= 8;
- txbuf = &addr;
- txlen = op->addr.nbytes;
- }
-
- if (txlen > CQSPI_STIG_DATA_LEN_MAX) {
- printf("QSPI: Invalid input arguments txlen %u\n", txlen);
- return -EINVAL;
- }
-
if (priv->dtr)
opcode = op->cmd.opcode >> 8;
else
@@ -567,6 +560,27 @@ int cadence_qspi_apb_command_write(struct cadence_spi_priv *priv,
reg |= opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB;
+ /* setup ADDR BIT field */
+ if (op->addr.nbytes) {
+ writel(op->addr.val, priv->regbase + CQSPI_REG_CMDADDRESS);
+ /*
+ * address bytes are zero indexed
+ */
+ reg |= (((op->addr.nbytes - 1) &
+ CQSPI_REG_CMDCTRL_ADD_BYTES_MASK) <<
+ CQSPI_REG_CMDCTRL_ADD_BYTES_LSB);
+ reg |= (0x1 << CQSPI_REG_CMDCTRL_ADDR_EN_LSB);
+ }
+
+ /* Set up dummy cycles. */
+ dummy_clk = cadence_qspi_calc_dummy(op, priv->dtr);
+ if (dummy_clk > CQSPI_DUMMY_CLKS_MAX)
+ return -EOPNOTSUPP;
+
+ if (dummy_clk)
+ reg |= (dummy_clk & CQSPI_REG_CMDCTRL_DUMMY_MASK)
+ << CQSPI_REG_CMDCTRL_DUMMY_LSB;
+
if (txlen) {
/* writing data = yes */
reg |= (0x1 << CQSPI_REG_CMDCTRL_WR_EN_LSB);
diff --git a/drivers/spi/npcm_fiu_spi.c b/drivers/spi/npcm_fiu_spi.c
index 7000fe5860d..73c506442ae 100644
--- a/drivers/spi/npcm_fiu_spi.c
+++ b/drivers/spi/npcm_fiu_spi.c
@@ -11,6 +11,7 @@
#include <linux/bitfield.h>
#include <linux/log2.h>
#include <linux/iopoll.h>
+#include <power/regulator.h>
#define DW_SIZE 4
#define CHUNK_SIZE 16
@@ -34,6 +35,34 @@
#define UMA_CTS_RDYST BIT(24)
#define UMA_CTS_DEV_NUM_MASK GENMASK(9, 8)
+/* Direct Write Configuration Register */
+#define DWR_CFG_WBURST_MASK GENMASK(25, 24)
+#define DWR_CFG_ADDSIZ_MASK GENMASK(17, 16)
+#define DWR_CFG_ABPCK_MASK GENMASK(11, 10)
+#define DRW_CFG_DBPCK_MASK GENMASK(9, 8)
+#define DRW_CFG_WRCMD 2
+enum {
+ DWR_WBURST_1_BYTE,
+ DWR_WBURST_16_BYTE = 3,
+};
+
+enum {
+ DWR_ADDSIZ_24_BIT,
+ DWR_ADDSIZ_32_BIT,
+};
+
+enum {
+ DWR_ABPCK_BIT_PER_CLK,
+ DWR_ABPCK_2_BIT_PER_CLK,
+ DWR_ABPCK_4_BIT_PER_CLK,
+};
+
+enum {
+ DWR_DBPCK_BIT_PER_CLK,
+ DWR_DBPCK_2_BIT_PER_CLK,
+ DWR_DBPCK_4_BIT_PER_CLK,
+};
+
struct npcm_fiu_regs {
unsigned int drd_cfg;
unsigned int dwr_cfg;
@@ -67,19 +96,10 @@ struct npcm_fiu_regs {
struct npcm_fiu_priv {
struct npcm_fiu_regs *regs;
- struct clk clk;
};
static int npcm_fiu_spi_set_speed(struct udevice *bus, uint speed)
{
- struct npcm_fiu_priv *priv = dev_get_priv(bus);
- int ret;
-
- debug("%s: set speed %u\n", bus->name, speed);
- ret = clk_set_rate(&priv->clk, speed);
- if (ret < 0)
- return ret;
-
return 0;
}
@@ -349,13 +369,38 @@ static int npcm_fiu_exec_op(struct spi_slave *slave,
static int npcm_fiu_spi_probe(struct udevice *bus)
{
struct npcm_fiu_priv *priv = dev_get_priv(bus);
- int ret;
+ struct udevice *vqspi_supply;
+ int vqspi_uv;
priv->regs = (struct npcm_fiu_regs *)dev_read_addr_ptr(bus);
- ret = clk_get_by_index(bus, 0, &priv->clk);
- if (ret < 0)
- return ret;
+ if (IS_ENABLED(CONFIG_DM_REGULATOR)) {
+ device_get_supply_regulator(bus, "vqspi-supply", &vqspi_supply);
+ vqspi_uv = dev_read_u32_default(bus, "vqspi-microvolt", 0);
+ /* Set IO voltage */
+ if (vqspi_supply && vqspi_uv)
+ regulator_set_value(vqspi_supply, vqspi_uv);
+ }
+
+ return 0;
+}
+
+static int npcm_fiu_spi_bind(struct udevice *bus)
+{
+ struct npcm_fiu_regs *regs;
+
+ if (dev_read_bool(bus, "nuvoton,spix-mode")) {
+ regs = dev_read_addr_ptr(bus);
+ if (!regs)
+ return -EINVAL;
+
+ /* Setup direct write cfg for SPIX */
+ writel(FIELD_PREP(DWR_CFG_WBURST_MASK, DWR_WBURST_16_BYTE) |
+ FIELD_PREP(DWR_CFG_ADDSIZ_MASK, DWR_ADDSIZ_24_BIT) |
+ FIELD_PREP(DWR_CFG_ABPCK_MASK, DWR_ABPCK_4_BIT_PER_CLK) |
+ FIELD_PREP(DRW_CFG_DBPCK_MASK, DWR_DBPCK_4_BIT_PER_CLK) |
+ DRW_CFG_WRCMD, &regs->dwr_cfg);
+ }
return 0;
}
@@ -384,4 +429,5 @@ U_BOOT_DRIVER(npcm_fiu_spi) = {
.ops = &npcm_fiu_spi_ops,
.priv_auto = sizeof(struct npcm_fiu_priv),
.probe = npcm_fiu_spi_probe,
+ .bind = npcm_fiu_spi_bind,
};
diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
index 8e8995fc537..b7eca583595 100644
--- a/drivers/spi/spi-mem.c
+++ b/drivers/spi/spi-mem.c
@@ -181,8 +181,12 @@ bool spi_mem_dtr_supports_op(struct spi_slave *slave,
if (op->dummy.nbytes && op->dummy.buswidth == 8 && op->dummy.nbytes % 2)
return false;
- if (op->data.dir != SPI_MEM_NO_DATA &&
- op->dummy.buswidth == 8 && op->data.nbytes % 2)
+ /*
+ * Transactions of odd length do not make sense for 8D-8D-8D mode
+ * because a byte is transferred in just half a cycle.
+ */
+ if (op->data.dir != SPI_MEM_NO_DATA && op->data.dir != SPI_MEM_DATA_IN &&
+ op->data.buswidth == 8 && op->data.nbytes % 2)
return false;
return spi_mem_check_buswidth(slave, op);
diff --git a/drivers/spi/spi-sn-f-ospi.c b/drivers/spi/spi-sn-f-ospi.c
index ebf2903d3ea..e3633a52608 100644
--- a/drivers/spi/spi-sn-f-ospi.c
+++ b/drivers/spi/spi-sn-f-ospi.c
@@ -556,7 +556,7 @@ static bool f_ospi_supports_op(struct spi_slave *slave,
if (!f_ospi_supports_op_width(op))
return false;
- return true;
+ return spi_mem_default_supports_op(slave, op);
}
static int f_ospi_adjust_op_size(struct spi_slave *slave, struct spi_mem_op *op)
diff --git a/drivers/spi/spi-synquacer.c b/drivers/spi/spi-synquacer.c
index 0cae3dfc778..0f5d0a30c39 100644
--- a/drivers/spi/spi-synquacer.c
+++ b/drivers/spi/spi-synquacer.c
@@ -186,7 +186,7 @@ static void synquacer_spi_config(struct udevice *dev, void *rx, const void *tx)
struct udevice *bus = dev->parent;
struct synquacer_spi_priv *priv = dev_get_priv(bus);
struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev);
- u32 val, div, bus_width;
+ u32 val, div, bus_width = 1;
int rwflag;
rwflag = (rx ? 1 : 0) | (tx ? 2 : 0);
@@ -211,6 +211,8 @@ static void synquacer_spi_config(struct udevice *dev, void *rx, const void *tx)
bus_width = 4;
else if (priv->mode & SPI_TX_OCTAL)
bus_width = 8;
+ else
+ log_warning("SPI mode not configured, setting to byte mode\n");
div = DIV_ROUND_UP(125000000, priv->speed);