diff options
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/cadence_qspi.c | 16 | ||||
-rw-r--r-- | drivers/spi/cadence_qspi_apb.c | 56 | ||||
-rw-r--r-- | drivers/spi/mpc8xxx_spi.c | 13 | ||||
-rw-r--r-- | drivers/spi/npcm_fiu_spi.c | 72 | ||||
-rw-r--r-- | drivers/spi/spi-mem.c | 8 | ||||
-rw-r--r-- | drivers/spi/spi-sn-f-ospi.c | 2 | ||||
-rw-r--r-- | drivers/spi/spi-synquacer.c | 4 |
7 files changed, 128 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/mpc8xxx_spi.c b/drivers/spi/mpc8xxx_spi.c index 6869d60d97b..78892173dc1 100644 --- a/drivers/spi/mpc8xxx_spi.c +++ b/drivers/spi/mpc8xxx_spi.c @@ -16,6 +16,7 @@ #include <dm/device_compat.h> #include <linux/bitops.h> #include <linux/delay.h> +#include <asm/arch/soc.h> enum { SPI_EV_NE = BIT(31 - 22), /* Receiver Not Empty */ @@ -30,6 +31,7 @@ enum { SPI_MODE_REV = BIT(31 - 5), /* Reverse mode - MSB first */ SPI_MODE_MS = BIT(31 - 6), /* Always master */ SPI_MODE_EN = BIT(31 - 7), /* Enable interface */ + SPI_MODE_OP = BIT(31 - 17), /* CPU Mode, QE otherwise */ SPI_MODE_LEN_MASK = 0xf00000, SPI_MODE_LEN_SHIFT = 20, @@ -89,6 +91,9 @@ static int mpc8xxx_spi_probe(struct udevice *dev) */ out_be32(&priv->spi->mode, SPI_MODE_REV | SPI_MODE_MS); + if (dev_get_driver_data(dev) == SOC_MPC832X) + setbits_be32(&priv->spi->mode, SPI_MODE_OP); + /* set len to 8 bits */ setbits_be32(&spi->mode, (8 - 1) << SPI_MODE_LEN_SHIFT); @@ -130,6 +135,7 @@ static int mpc8xxx_spi_xfer(struct udevice *dev, uint bitlen, u32 tmpdin = 0, tmpdout = 0, n; const u8 *cout = dout; u8 *cin = din; + ulong type = dev_get_driver_data(bus); debug("%s: slave %s:%u dout %08X din %08X bitlen %u\n", __func__, bus->name, plat->cs, (uint)dout, (uint)din, bitlen); @@ -157,6 +163,9 @@ static int mpc8xxx_spi_xfer(struct udevice *dev, uint bitlen, if (cout) tmpdout = *cout++; + if (type == SOC_MPC832X) + tmpdout <<= 24; + /* Write the data out */ out_be32(&spi->tx, tmpdout); @@ -179,6 +188,9 @@ static int mpc8xxx_spi_xfer(struct udevice *dev, uint bitlen, tmpdin = in_be32(&spi->rx); setbits_be32(&spi->event, SPI_EV_NE); + if (type == SOC_MPC832X) + tmpdin >>= 16; + if (cin) *cin++ = tmpdin; @@ -271,6 +283,7 @@ static const struct dm_spi_ops mpc8xxx_spi_ops = { static const struct udevice_id mpc8xxx_spi_ids[] = { { .compatible = "fsl,spi" }, + { .compatible = "fsl,mpc832x-spi", .data = SOC_MPC832X }, { } }; 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, ®s->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); |