diff options
| -rw-r--r-- | Documentation/devicetree/bindings/spi/spi-mt65xx.txt | 1 | ||||
| -rw-r--r-- | Documentation/devicetree/bindings/spi/spi-nxp-fspi.txt | 1 | ||||
| -rw-r--r-- | drivers/spi/spi-atmel.c | 4 | ||||
| -rw-r--r-- | drivers/spi/spi-cadence-quadspi.c | 6 | ||||
| -rw-r--r-- | drivers/spi/spi-nxp-fspi.c | 114 | ||||
| -rw-r--r-- | drivers/spi/spi-omap2-mcspi.c | 24 | ||||
| -rw-r--r-- | drivers/spi/spi-rockchip.c | 13 |
7 files changed, 138 insertions, 25 deletions
diff --git a/Documentation/devicetree/bindings/spi/spi-mt65xx.txt b/Documentation/devicetree/bindings/spi/spi-mt65xx.txt index 9e43721fa7d6..7bae7eef26c7 100644 --- a/Documentation/devicetree/bindings/spi/spi-mt65xx.txt +++ b/Documentation/devicetree/bindings/spi/spi-mt65xx.txt @@ -13,6 +13,7 @@ Required properties: - mediatek,mt8183-spi: for mt8183 platforms - "mediatek,mt8192-spi", "mediatek,mt6765-spi": for mt8192 platforms - "mediatek,mt8516-spi", "mediatek,mt2712-spi": for mt8516 platforms + - "mediatek,mt6779-spi", "mediatek,mt6765-spi": for mt6779 platforms - #address-cells: should be 1. diff --git a/Documentation/devicetree/bindings/spi/spi-nxp-fspi.txt b/Documentation/devicetree/bindings/spi/spi-nxp-fspi.txt index 7ac60d9fe357..df178d1b62e6 100644 --- a/Documentation/devicetree/bindings/spi/spi-nxp-fspi.txt +++ b/Documentation/devicetree/bindings/spi/spi-nxp-fspi.txt @@ -4,6 +4,7 @@ Required properties: - compatible : Should be "nxp,lx2160a-fspi" "nxp,imx8qxp-fspi" "nxp,imx8mm-fspi" + "nxp,imx8dxl-fspi" - reg : First contains the register location and length, Second contains the memory mapping address and length diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index f429436082af..7cd5fe00dfc1 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -506,10 +506,6 @@ static int atmel_spi_configure_dma(struct spi_master *master, struct device *dev = &as->pdev->dev; int err; - dma_cap_mask_t mask; - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - master->dma_tx = dma_request_chan(dev, "tx"); if (IS_ERR(master->dma_tx)) { err = PTR_ERR(master->dma_tx); diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c index 442cc7c53a47..14a712058fac 100644 --- a/drivers/spi/spi-cadence-quadspi.c +++ b/drivers/spi/spi-cadence-quadspi.c @@ -1389,11 +1389,13 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi) ret = of_property_read_u32(np, "reg", &cs); if (ret) { dev_err(dev, "Couldn't determine chip select.\n"); + of_node_put(np); return ret; } if (cs >= CQSPI_MAX_CHIPSELECT) { dev_err(dev, "Chip select %d out of range.\n", cs); + of_node_put(np); return -EINVAL; } @@ -1402,8 +1404,10 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi) f_pdata->cs = cs; ret = cqspi_of_get_flash_pdata(pdev, f_pdata, np); - if (ret) + if (ret) { + of_node_put(np); return ret; + } } return 0; diff --git a/drivers/spi/spi-nxp-fspi.c b/drivers/spi/spi-nxp-fspi.c index ab9035662717..ed1e888c7ece 100644 --- a/drivers/spi/spi-nxp-fspi.c +++ b/drivers/spi/spi-nxp-fspi.c @@ -49,8 +49,11 @@ #include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/pm_qos.h> +#include <linux/regmap.h> #include <linux/sizes.h> +#include <linux/sys_soc.h> +#include <linux/mfd/syscon.h> #include <linux/spi/spi.h> #include <linux/spi/spi-mem.h> @@ -311,6 +314,11 @@ #define NXP_FSPI_MAX_CHIPSELECT 4 #define NXP_FSPI_MIN_IOMAP SZ_4M +#define DCFG_RCWSR1 0x100 + +/* Access flash memory using IP bus only */ +#define FSPI_QUIRK_USE_IP_ONLY BIT(0) + struct nxp_fspi_devtype_data { unsigned int rxfifo; unsigned int txfifo; @@ -319,7 +327,7 @@ struct nxp_fspi_devtype_data { bool little_endian; }; -static const struct nxp_fspi_devtype_data lx2160a_data = { +static struct nxp_fspi_devtype_data lx2160a_data = { .rxfifo = SZ_512, /* (64 * 64 bits) */ .txfifo = SZ_1K, /* (128 * 64 bits) */ .ahb_buf_size = SZ_2K, /* (256 * 64 bits) */ @@ -327,7 +335,7 @@ static const struct nxp_fspi_devtype_data lx2160a_data = { .little_endian = true, /* little-endian */ }; -static const struct nxp_fspi_devtype_data imx8mm_data = { +static struct nxp_fspi_devtype_data imx8mm_data = { .rxfifo = SZ_512, /* (64 * 64 bits) */ .txfifo = SZ_1K, /* (128 * 64 bits) */ .ahb_buf_size = SZ_2K, /* (256 * 64 bits) */ @@ -335,7 +343,7 @@ static const struct nxp_fspi_devtype_data imx8mm_data = { .little_endian = true, /* little-endian */ }; -static const struct nxp_fspi_devtype_data imx8qxp_data = { +static struct nxp_fspi_devtype_data imx8qxp_data = { .rxfifo = SZ_512, /* (64 * 64 bits) */ .txfifo = SZ_1K, /* (128 * 64 bits) */ .ahb_buf_size = SZ_2K, /* (256 * 64 bits) */ @@ -343,6 +351,14 @@ static const struct nxp_fspi_devtype_data imx8qxp_data = { .little_endian = true, /* little-endian */ }; +static struct nxp_fspi_devtype_data imx8dxl_data = { + .rxfifo = SZ_512, /* (64 * 64 bits) */ + .txfifo = SZ_1K, /* (128 * 64 bits) */ + .ahb_buf_size = SZ_2K, /* (256 * 64 bits) */ + .quirks = FSPI_QUIRK_USE_IP_ONLY, + .little_endian = true, /* little-endian */ +}; + struct nxp_fspi { void __iomem *iobase; void __iomem *ahb_addr; @@ -353,12 +369,17 @@ struct nxp_fspi { struct clk *clk, *clk_en; struct device *dev; struct completion c; - const struct nxp_fspi_devtype_data *devtype_data; + struct nxp_fspi_devtype_data *devtype_data; struct mutex lock; struct pm_qos_request pm_qos_req; int selected; }; +static inline int needs_ip_only(struct nxp_fspi *f) +{ + return f->devtype_data->quirks & FSPI_QUIRK_USE_IP_ONLY; +} + /* * R/W functions for big- or little-endian registers: * The FSPI controller's endianness is independent of @@ -553,8 +574,8 @@ static void nxp_fspi_prepare_lut(struct nxp_fspi *f, for (i = 0; i < ARRAY_SIZE(lutval); i++) fspi_writel(f, lutval[i], base + FSPI_LUT_REG(i)); - dev_dbg(f->dev, "CMD[%x] lutval[0:%x \t 1:%x \t 2:%x \t 3:%x]\n", - op->cmd.opcode, lutval[0], lutval[1], lutval[2], lutval[3]); + dev_dbg(f->dev, "CMD[%x] lutval[0:%x \t 1:%x \t 2:%x \t 3:%x], size: 0x%08x\n", + op->cmd.opcode, lutval[0], lutval[1], lutval[2], lutval[3], op->data.nbytes); /* lock LUT */ fspi_writel(f, FSPI_LUTKEY_VALUE, f->iobase + FSPI_LUTKEY); @@ -852,12 +873,14 @@ static int nxp_fspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) nxp_fspi_prepare_lut(f, op); /* - * If we have large chunks of data, we read them through the AHB bus - * by accessing the mapped memory. In all other cases we use - * IP commands to access the flash. + * If we have large chunks of data, we read them through the AHB bus by + * accessing the mapped memory. In all other cases we use IP commands + * to access the flash. Read via AHB bus may be corrupted due to + * existence of an errata and therefore discard AHB read in such cases. */ if (op->data.nbytes > (f->devtype_data->rxfifo - 4) && - op->data.dir == SPI_MEM_DATA_IN) { + op->data.dir == SPI_MEM_DATA_IN && + !needs_ip_only(f)) { err = nxp_fspi_read_ahb(f, op); } else { if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_OUT) @@ -888,9 +911,68 @@ static int nxp_fspi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op) op->data.nbytes = ALIGN_DOWN(op->data.nbytes, 8); } + /* Limit data bytes to RX FIFO in case of IP read only */ + if (op->data.dir == SPI_MEM_DATA_IN && + needs_ip_only(f) && + op->data.nbytes > f->devtype_data->rxfifo) + op->data.nbytes = f->devtype_data->rxfifo; + return 0; } +static void erratum_err050568(struct nxp_fspi *f) +{ + const struct soc_device_attribute ls1028a_soc_attr[] = { + { .family = "QorIQ LS1028A" }, + { /* sentinel */ } + }; + struct device_node *np; + struct regmap *map; + u32 val = 0, sysclk = 0; + int ret; + + /* Check for LS1028A family */ + if (!soc_device_match(ls1028a_soc_attr)) { + dev_dbg(f->dev, "Errata applicable only for LS1028A\n"); + return; + } + + /* Compute system clock frequency multiplier ratio */ + map = syscon_regmap_lookup_by_compatible("fsl,ls1028a-dcfg"); + if (IS_ERR(map)) { + dev_err(f->dev, "No syscon regmap\n"); + goto err; + } + + ret = regmap_read(map, DCFG_RCWSR1, &val); + if (ret < 0) + goto err; + + /* Strap bits 6:2 define SYS_PLL_RAT i.e frequency multiplier ratio */ + val = (val >> 2) & 0x1F; + WARN(val == 0, "Strapping is zero: Cannot determine ratio"); + + /* Compute system clock frequency */ + np = of_find_node_by_name(NULL, "clock-sysclk"); + if (!np) + goto err; + + if (of_property_read_u32(np, "clock-frequency", &sysclk)) + goto err; + + sysclk = (sysclk * val) / 1000000; /* Convert sysclk to Mhz */ + dev_dbg(f->dev, "val: 0x%08x, sysclk: %dMhz\n", val, sysclk); + + /* Use IP bus only if PLL is 300MHz */ + if (sysclk == 300) + f->devtype_data->quirks |= FSPI_QUIRK_USE_IP_ONLY; + + return; + +err: + dev_err(f->dev, "Errata cannot be executed. Read via IP bus may not work\n"); +} + static int nxp_fspi_default_setup(struct nxp_fspi *f) { void __iomem *base = f->iobase; @@ -909,6 +991,15 @@ static int nxp_fspi_default_setup(struct nxp_fspi *f) if (ret) return ret; + /* + * ERR050568: Flash access by FlexSPI AHB command may not work with + * platform frequency equal to 300 MHz on LS1028A. + * LS1028A reuses LX2160A compatible entry. Make errata applicable for + * Layerscape LS1028A platform. + */ + if (of_device_is_compatible(f->dev->of_node, "nxp,lx2160a-fspi")) + erratum_err050568(f); + /* Reset the module */ /* w1c register, wait unit clear */ ret = fspi_readl_poll_tout(f, f->iobase + FSPI_MCR0, @@ -1012,7 +1103,7 @@ static int nxp_fspi_probe(struct platform_device *pdev) f = spi_controller_get_devdata(ctlr); f->dev = dev; - f->devtype_data = device_get_match_data(dev); + f->devtype_data = (struct nxp_fspi_devtype_data *)device_get_match_data(dev); if (!f->devtype_data) { ret = -ENODEV; goto err_put_ctrl; @@ -1152,6 +1243,7 @@ static const struct of_device_id nxp_fspi_dt_ids[] = { { .compatible = "nxp,lx2160a-fspi", .data = (void *)&lx2160a_data, }, { .compatible = "nxp,imx8mm-fspi", .data = (void *)&imx8mm_data, }, { .compatible = "nxp,imx8qxp-fspi", .data = (void *)&imx8qxp_data, }, + { .compatible = "nxp,imx8dxl-fspi", .data = (void *)&imx8dxl_data, }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, nxp_fspi_dt_ids); diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index d4c9510af393..999c22736416 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -1327,6 +1327,17 @@ static int omap2_mcspi_controller_setup(struct omap2_mcspi *mcspi) return 0; } +static int omap_mcspi_runtime_suspend(struct device *dev) +{ + int error; + + error = pinctrl_pm_select_idle_state(dev); + if (error) + dev_warn(dev, "%s: failed to set pins: %i\n", __func__, error); + + return 0; +} + /* * When SPI wake up from off-mode, CS is in activate state. If it was in * inactive state when driver was suspend, then force it to inactive state at @@ -1338,6 +1349,11 @@ static int omap_mcspi_runtime_resume(struct device *dev) struct omap2_mcspi *mcspi = spi_master_get_devdata(master); struct omap2_mcspi_regs *ctx = &mcspi->ctx; struct omap2_mcspi_cs *cs; + int error; + + error = pinctrl_pm_select_default_state(dev); + if (error) + dev_warn(dev, "%s: failed to set pins: %i\n", __func__, error); /* McSPI: context restore */ mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, ctx->modulctrl); @@ -1566,11 +1582,6 @@ static int __maybe_unused omap2_mcspi_resume(struct device *dev) struct omap2_mcspi *mcspi = spi_master_get_devdata(master); int error; - error = pinctrl_pm_select_default_state(dev); - if (error) - dev_warn(mcspi->dev, "%s: failed to set pins: %i\n", - __func__, error); - error = spi_master_resume(master); if (error) dev_warn(mcspi->dev, "%s: master resume failed: %i\n", @@ -1582,7 +1593,8 @@ static int __maybe_unused omap2_mcspi_resume(struct device *dev) static const struct dev_pm_ops omap2_mcspi_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(omap2_mcspi_suspend, omap2_mcspi_resume) - .runtime_resume = omap_mcspi_runtime_resume, + .runtime_suspend = omap_mcspi_runtime_suspend, + .runtime_resume = omap_mcspi_runtime_resume, }; static struct platform_driver omap2_mcspi_driver = { diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index 936ef54e0903..0d75080da648 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -476,7 +476,7 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs, return 1; } -static void rockchip_spi_config(struct rockchip_spi *rs, +static int rockchip_spi_config(struct rockchip_spi *rs, struct spi_device *spi, struct spi_transfer *xfer, bool use_dma, bool slave_mode) { @@ -521,7 +521,9 @@ static void rockchip_spi_config(struct rockchip_spi *rs, * ctlr->bits_per_word_mask, so this shouldn't * happen */ - unreachable(); + dev_err(rs->dev, "unknown bits per word: %d\n", + xfer->bits_per_word); + return -EINVAL; } if (use_dma) { @@ -554,6 +556,8 @@ static void rockchip_spi_config(struct rockchip_spi *rs, */ writel_relaxed(2 * DIV_ROUND_UP(rs->freq, 2 * xfer->speed_hz), rs->regs + ROCKCHIP_SPI_BAUDR); + + return 0; } static size_t rockchip_spi_max_transfer_size(struct spi_device *spi) @@ -577,6 +581,7 @@ static int rockchip_spi_transfer_one( struct spi_transfer *xfer) { struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); + int ret; bool use_dma; WARN_ON(readl_relaxed(rs->regs + ROCKCHIP_SPI_SSIENR) && @@ -596,7 +601,9 @@ static int rockchip_spi_transfer_one( use_dma = ctlr->can_dma ? ctlr->can_dma(ctlr, spi, xfer) : false; - rockchip_spi_config(rs, spi, xfer, use_dma, ctlr->slave); + ret = rockchip_spi_config(rs, spi, xfer, use_dma, ctlr->slave); + if (ret) + return ret; if (use_dma) return rockchip_spi_prepare_dma(rs, ctlr, xfer); |
