162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * TI QSPI driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2013 Texas Instruments Incorporated - https://www.ti.com 662306a36Sopenharmony_ci * Author: Sourav Poddar <sourav.poddar@ti.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/kernel.h> 1062306a36Sopenharmony_ci#include <linux/init.h> 1162306a36Sopenharmony_ci#include <linux/interrupt.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/device.h> 1462306a36Sopenharmony_ci#include <linux/delay.h> 1562306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1662306a36Sopenharmony_ci#include <linux/dmaengine.h> 1762306a36Sopenharmony_ci#include <linux/omap-dma.h> 1862306a36Sopenharmony_ci#include <linux/platform_device.h> 1962306a36Sopenharmony_ci#include <linux/err.h> 2062306a36Sopenharmony_ci#include <linux/clk.h> 2162306a36Sopenharmony_ci#include <linux/io.h> 2262306a36Sopenharmony_ci#include <linux/slab.h> 2362306a36Sopenharmony_ci#include <linux/pm_runtime.h> 2462306a36Sopenharmony_ci#include <linux/of.h> 2562306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h> 2662306a36Sopenharmony_ci#include <linux/mfd/syscon.h> 2762306a36Sopenharmony_ci#include <linux/regmap.h> 2862306a36Sopenharmony_ci#include <linux/sizes.h> 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#include <linux/spi/spi.h> 3162306a36Sopenharmony_ci#include <linux/spi/spi-mem.h> 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistruct ti_qspi_regs { 3462306a36Sopenharmony_ci u32 clkctrl; 3562306a36Sopenharmony_ci}; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistruct ti_qspi { 3862306a36Sopenharmony_ci struct completion transfer_complete; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci /* list synchronization */ 4162306a36Sopenharmony_ci struct mutex list_lock; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci struct spi_master *master; 4462306a36Sopenharmony_ci void __iomem *base; 4562306a36Sopenharmony_ci void __iomem *mmap_base; 4662306a36Sopenharmony_ci size_t mmap_size; 4762306a36Sopenharmony_ci struct regmap *ctrl_base; 4862306a36Sopenharmony_ci unsigned int ctrl_reg; 4962306a36Sopenharmony_ci struct clk *fclk; 5062306a36Sopenharmony_ci struct device *dev; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci struct ti_qspi_regs ctx_reg; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci dma_addr_t mmap_phys_base; 5562306a36Sopenharmony_ci dma_addr_t rx_bb_dma_addr; 5662306a36Sopenharmony_ci void *rx_bb_addr; 5762306a36Sopenharmony_ci struct dma_chan *rx_chan; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci u32 cmd; 6062306a36Sopenharmony_ci u32 dc; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci bool mmap_enabled; 6362306a36Sopenharmony_ci int current_cs; 6462306a36Sopenharmony_ci}; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci#define QSPI_PID (0x0) 6762306a36Sopenharmony_ci#define QSPI_SYSCONFIG (0x10) 6862306a36Sopenharmony_ci#define QSPI_SPI_CLOCK_CNTRL_REG (0x40) 6962306a36Sopenharmony_ci#define QSPI_SPI_DC_REG (0x44) 7062306a36Sopenharmony_ci#define QSPI_SPI_CMD_REG (0x48) 7162306a36Sopenharmony_ci#define QSPI_SPI_STATUS_REG (0x4c) 7262306a36Sopenharmony_ci#define QSPI_SPI_DATA_REG (0x50) 7362306a36Sopenharmony_ci#define QSPI_SPI_SETUP_REG(n) ((0x54 + 4 * n)) 7462306a36Sopenharmony_ci#define QSPI_SPI_SWITCH_REG (0x64) 7562306a36Sopenharmony_ci#define QSPI_SPI_DATA_REG_1 (0x68) 7662306a36Sopenharmony_ci#define QSPI_SPI_DATA_REG_2 (0x6c) 7762306a36Sopenharmony_ci#define QSPI_SPI_DATA_REG_3 (0x70) 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci#define QSPI_COMPLETION_TIMEOUT msecs_to_jiffies(2000) 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci/* Clock Control */ 8262306a36Sopenharmony_ci#define QSPI_CLK_EN (1 << 31) 8362306a36Sopenharmony_ci#define QSPI_CLK_DIV_MAX 0xffff 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci/* Command */ 8662306a36Sopenharmony_ci#define QSPI_EN_CS(n) (n << 28) 8762306a36Sopenharmony_ci#define QSPI_WLEN(n) ((n - 1) << 19) 8862306a36Sopenharmony_ci#define QSPI_3_PIN (1 << 18) 8962306a36Sopenharmony_ci#define QSPI_RD_SNGL (1 << 16) 9062306a36Sopenharmony_ci#define QSPI_WR_SNGL (2 << 16) 9162306a36Sopenharmony_ci#define QSPI_RD_DUAL (3 << 16) 9262306a36Sopenharmony_ci#define QSPI_RD_QUAD (7 << 16) 9362306a36Sopenharmony_ci#define QSPI_INVAL (4 << 16) 9462306a36Sopenharmony_ci#define QSPI_FLEN(n) ((n - 1) << 0) 9562306a36Sopenharmony_ci#define QSPI_WLEN_MAX_BITS 128 9662306a36Sopenharmony_ci#define QSPI_WLEN_MAX_BYTES 16 9762306a36Sopenharmony_ci#define QSPI_WLEN_MASK QSPI_WLEN(QSPI_WLEN_MAX_BITS) 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci/* STATUS REGISTER */ 10062306a36Sopenharmony_ci#define BUSY 0x01 10162306a36Sopenharmony_ci#define WC 0x02 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci/* Device Control */ 10462306a36Sopenharmony_ci#define QSPI_DD(m, n) (m << (3 + n * 8)) 10562306a36Sopenharmony_ci#define QSPI_CKPHA(n) (1 << (2 + n * 8)) 10662306a36Sopenharmony_ci#define QSPI_CSPOL(n) (1 << (1 + n * 8)) 10762306a36Sopenharmony_ci#define QSPI_CKPOL(n) (1 << (n * 8)) 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci#define QSPI_FRAME 4096 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci#define QSPI_AUTOSUSPEND_TIMEOUT 2000 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci#define MEM_CS_EN(n) ((n + 1) << 8) 11462306a36Sopenharmony_ci#define MEM_CS_MASK (7 << 8) 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci#define MM_SWITCH 0x1 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci#define QSPI_SETUP_RD_NORMAL (0x0 << 12) 11962306a36Sopenharmony_ci#define QSPI_SETUP_RD_DUAL (0x1 << 12) 12062306a36Sopenharmony_ci#define QSPI_SETUP_RD_QUAD (0x3 << 12) 12162306a36Sopenharmony_ci#define QSPI_SETUP_ADDR_SHIFT 8 12262306a36Sopenharmony_ci#define QSPI_SETUP_DUMMY_SHIFT 10 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci#define QSPI_DMA_BUFFER_SIZE SZ_64K 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic inline unsigned long ti_qspi_read(struct ti_qspi *qspi, 12762306a36Sopenharmony_ci unsigned long reg) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci return readl(qspi->base + reg); 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic inline void ti_qspi_write(struct ti_qspi *qspi, 13362306a36Sopenharmony_ci unsigned long val, unsigned long reg) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci writel(val, qspi->base + reg); 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic int ti_qspi_setup(struct spi_device *spi) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci struct ti_qspi *qspi = spi_master_get_devdata(spi->master); 14162306a36Sopenharmony_ci int ret; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci if (spi->master->busy) { 14462306a36Sopenharmony_ci dev_dbg(qspi->dev, "master busy doing other transfers\n"); 14562306a36Sopenharmony_ci return -EBUSY; 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (!qspi->master->max_speed_hz) { 14962306a36Sopenharmony_ci dev_err(qspi->dev, "spi max frequency not defined\n"); 15062306a36Sopenharmony_ci return -EINVAL; 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci spi->max_speed_hz = min(spi->max_speed_hz, qspi->master->max_speed_hz); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(qspi->dev); 15662306a36Sopenharmony_ci if (ret < 0) { 15762306a36Sopenharmony_ci dev_err(qspi->dev, "pm_runtime_get_sync() failed\n"); 15862306a36Sopenharmony_ci return ret; 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci pm_runtime_mark_last_busy(qspi->dev); 16262306a36Sopenharmony_ci ret = pm_runtime_put_autosuspend(qspi->dev); 16362306a36Sopenharmony_ci if (ret < 0) { 16462306a36Sopenharmony_ci dev_err(qspi->dev, "pm_runtime_put_autosuspend() failed\n"); 16562306a36Sopenharmony_ci return ret; 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci return 0; 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic void ti_qspi_setup_clk(struct ti_qspi *qspi, u32 speed_hz) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci struct ti_qspi_regs *ctx_reg = &qspi->ctx_reg; 17462306a36Sopenharmony_ci int clk_div; 17562306a36Sopenharmony_ci u32 clk_ctrl_reg, clk_rate, clk_ctrl_new; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci clk_rate = clk_get_rate(qspi->fclk); 17862306a36Sopenharmony_ci clk_div = DIV_ROUND_UP(clk_rate, speed_hz) - 1; 17962306a36Sopenharmony_ci clk_div = clamp(clk_div, 0, QSPI_CLK_DIV_MAX); 18062306a36Sopenharmony_ci dev_dbg(qspi->dev, "hz: %d, clock divider %d\n", speed_hz, clk_div); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci pm_runtime_resume_and_get(qspi->dev); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci clk_ctrl_new = QSPI_CLK_EN | clk_div; 18562306a36Sopenharmony_ci if (ctx_reg->clkctrl != clk_ctrl_new) { 18662306a36Sopenharmony_ci clk_ctrl_reg = ti_qspi_read(qspi, QSPI_SPI_CLOCK_CNTRL_REG); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci clk_ctrl_reg &= ~QSPI_CLK_EN; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci /* disable SCLK */ 19162306a36Sopenharmony_ci ti_qspi_write(qspi, clk_ctrl_reg, QSPI_SPI_CLOCK_CNTRL_REG); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci /* enable SCLK */ 19462306a36Sopenharmony_ci ti_qspi_write(qspi, clk_ctrl_new, QSPI_SPI_CLOCK_CNTRL_REG); 19562306a36Sopenharmony_ci ctx_reg->clkctrl = clk_ctrl_new; 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci pm_runtime_mark_last_busy(qspi->dev); 19962306a36Sopenharmony_ci pm_runtime_put_autosuspend(qspi->dev); 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_cistatic void ti_qspi_restore_ctx(struct ti_qspi *qspi) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci struct ti_qspi_regs *ctx_reg = &qspi->ctx_reg; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci ti_qspi_write(qspi, ctx_reg->clkctrl, QSPI_SPI_CLOCK_CNTRL_REG); 20762306a36Sopenharmony_ci} 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic inline u32 qspi_is_busy(struct ti_qspi *qspi) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci u32 stat; 21262306a36Sopenharmony_ci unsigned long timeout = jiffies + QSPI_COMPLETION_TIMEOUT; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG); 21562306a36Sopenharmony_ci while ((stat & BUSY) && time_after(timeout, jiffies)) { 21662306a36Sopenharmony_ci cpu_relax(); 21762306a36Sopenharmony_ci stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG); 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci WARN(stat & BUSY, "qspi busy\n"); 22162306a36Sopenharmony_ci return stat & BUSY; 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistatic inline int ti_qspi_poll_wc(struct ti_qspi *qspi) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci u32 stat; 22762306a36Sopenharmony_ci unsigned long timeout = jiffies + QSPI_COMPLETION_TIMEOUT; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci do { 23062306a36Sopenharmony_ci stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG); 23162306a36Sopenharmony_ci if (stat & WC) 23262306a36Sopenharmony_ci return 0; 23362306a36Sopenharmony_ci cpu_relax(); 23462306a36Sopenharmony_ci } while (time_after(timeout, jiffies)); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG); 23762306a36Sopenharmony_ci if (stat & WC) 23862306a36Sopenharmony_ci return 0; 23962306a36Sopenharmony_ci return -ETIMEDOUT; 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t, 24362306a36Sopenharmony_ci int count) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci int wlen, xfer_len; 24662306a36Sopenharmony_ci unsigned int cmd; 24762306a36Sopenharmony_ci const u8 *txbuf; 24862306a36Sopenharmony_ci u32 data; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci txbuf = t->tx_buf; 25162306a36Sopenharmony_ci cmd = qspi->cmd | QSPI_WR_SNGL; 25262306a36Sopenharmony_ci wlen = t->bits_per_word >> 3; /* in bytes */ 25362306a36Sopenharmony_ci xfer_len = wlen; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci while (count) { 25662306a36Sopenharmony_ci if (qspi_is_busy(qspi)) 25762306a36Sopenharmony_ci return -EBUSY; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci switch (wlen) { 26062306a36Sopenharmony_ci case 1: 26162306a36Sopenharmony_ci dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %02x\n", 26262306a36Sopenharmony_ci cmd, qspi->dc, *txbuf); 26362306a36Sopenharmony_ci if (count >= QSPI_WLEN_MAX_BYTES) { 26462306a36Sopenharmony_ci u32 *txp = (u32 *)txbuf; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci data = cpu_to_be32(*txp++); 26762306a36Sopenharmony_ci writel(data, qspi->base + 26862306a36Sopenharmony_ci QSPI_SPI_DATA_REG_3); 26962306a36Sopenharmony_ci data = cpu_to_be32(*txp++); 27062306a36Sopenharmony_ci writel(data, qspi->base + 27162306a36Sopenharmony_ci QSPI_SPI_DATA_REG_2); 27262306a36Sopenharmony_ci data = cpu_to_be32(*txp++); 27362306a36Sopenharmony_ci writel(data, qspi->base + 27462306a36Sopenharmony_ci QSPI_SPI_DATA_REG_1); 27562306a36Sopenharmony_ci data = cpu_to_be32(*txp++); 27662306a36Sopenharmony_ci writel(data, qspi->base + 27762306a36Sopenharmony_ci QSPI_SPI_DATA_REG); 27862306a36Sopenharmony_ci xfer_len = QSPI_WLEN_MAX_BYTES; 27962306a36Sopenharmony_ci cmd |= QSPI_WLEN(QSPI_WLEN_MAX_BITS); 28062306a36Sopenharmony_ci } else { 28162306a36Sopenharmony_ci writeb(*txbuf, qspi->base + QSPI_SPI_DATA_REG); 28262306a36Sopenharmony_ci cmd = qspi->cmd | QSPI_WR_SNGL; 28362306a36Sopenharmony_ci xfer_len = wlen; 28462306a36Sopenharmony_ci cmd |= QSPI_WLEN(wlen); 28562306a36Sopenharmony_ci } 28662306a36Sopenharmony_ci break; 28762306a36Sopenharmony_ci case 2: 28862306a36Sopenharmony_ci dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %04x\n", 28962306a36Sopenharmony_ci cmd, qspi->dc, *txbuf); 29062306a36Sopenharmony_ci writew(*((u16 *)txbuf), qspi->base + QSPI_SPI_DATA_REG); 29162306a36Sopenharmony_ci break; 29262306a36Sopenharmony_ci case 4: 29362306a36Sopenharmony_ci dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %08x\n", 29462306a36Sopenharmony_ci cmd, qspi->dc, *txbuf); 29562306a36Sopenharmony_ci writel(*((u32 *)txbuf), qspi->base + QSPI_SPI_DATA_REG); 29662306a36Sopenharmony_ci break; 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG); 30062306a36Sopenharmony_ci if (ti_qspi_poll_wc(qspi)) { 30162306a36Sopenharmony_ci dev_err(qspi->dev, "write timed out\n"); 30262306a36Sopenharmony_ci return -ETIMEDOUT; 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci txbuf += xfer_len; 30562306a36Sopenharmony_ci count -= xfer_len; 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci return 0; 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_cistatic int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t, 31262306a36Sopenharmony_ci int count) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci int wlen; 31562306a36Sopenharmony_ci unsigned int cmd; 31662306a36Sopenharmony_ci u32 rx; 31762306a36Sopenharmony_ci u8 rxlen, rx_wlen; 31862306a36Sopenharmony_ci u8 *rxbuf; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci rxbuf = t->rx_buf; 32162306a36Sopenharmony_ci cmd = qspi->cmd; 32262306a36Sopenharmony_ci switch (t->rx_nbits) { 32362306a36Sopenharmony_ci case SPI_NBITS_DUAL: 32462306a36Sopenharmony_ci cmd |= QSPI_RD_DUAL; 32562306a36Sopenharmony_ci break; 32662306a36Sopenharmony_ci case SPI_NBITS_QUAD: 32762306a36Sopenharmony_ci cmd |= QSPI_RD_QUAD; 32862306a36Sopenharmony_ci break; 32962306a36Sopenharmony_ci default: 33062306a36Sopenharmony_ci cmd |= QSPI_RD_SNGL; 33162306a36Sopenharmony_ci break; 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci wlen = t->bits_per_word >> 3; /* in bytes */ 33462306a36Sopenharmony_ci rx_wlen = wlen; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci while (count) { 33762306a36Sopenharmony_ci dev_dbg(qspi->dev, "rx cmd %08x dc %08x\n", cmd, qspi->dc); 33862306a36Sopenharmony_ci if (qspi_is_busy(qspi)) 33962306a36Sopenharmony_ci return -EBUSY; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci switch (wlen) { 34262306a36Sopenharmony_ci case 1: 34362306a36Sopenharmony_ci /* 34462306a36Sopenharmony_ci * Optimize the 8-bit words transfers, as used by 34562306a36Sopenharmony_ci * the SPI flash devices. 34662306a36Sopenharmony_ci */ 34762306a36Sopenharmony_ci if (count >= QSPI_WLEN_MAX_BYTES) { 34862306a36Sopenharmony_ci rxlen = QSPI_WLEN_MAX_BYTES; 34962306a36Sopenharmony_ci } else { 35062306a36Sopenharmony_ci rxlen = min(count, 4); 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci rx_wlen = rxlen << 3; 35362306a36Sopenharmony_ci cmd &= ~QSPI_WLEN_MASK; 35462306a36Sopenharmony_ci cmd |= QSPI_WLEN(rx_wlen); 35562306a36Sopenharmony_ci break; 35662306a36Sopenharmony_ci default: 35762306a36Sopenharmony_ci rxlen = wlen; 35862306a36Sopenharmony_ci break; 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG); 36262306a36Sopenharmony_ci if (ti_qspi_poll_wc(qspi)) { 36362306a36Sopenharmony_ci dev_err(qspi->dev, "read timed out\n"); 36462306a36Sopenharmony_ci return -ETIMEDOUT; 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci switch (wlen) { 36862306a36Sopenharmony_ci case 1: 36962306a36Sopenharmony_ci /* 37062306a36Sopenharmony_ci * Optimize the 8-bit words transfers, as used by 37162306a36Sopenharmony_ci * the SPI flash devices. 37262306a36Sopenharmony_ci */ 37362306a36Sopenharmony_ci if (count >= QSPI_WLEN_MAX_BYTES) { 37462306a36Sopenharmony_ci u32 *rxp = (u32 *) rxbuf; 37562306a36Sopenharmony_ci rx = readl(qspi->base + QSPI_SPI_DATA_REG_3); 37662306a36Sopenharmony_ci *rxp++ = be32_to_cpu(rx); 37762306a36Sopenharmony_ci rx = readl(qspi->base + QSPI_SPI_DATA_REG_2); 37862306a36Sopenharmony_ci *rxp++ = be32_to_cpu(rx); 37962306a36Sopenharmony_ci rx = readl(qspi->base + QSPI_SPI_DATA_REG_1); 38062306a36Sopenharmony_ci *rxp++ = be32_to_cpu(rx); 38162306a36Sopenharmony_ci rx = readl(qspi->base + QSPI_SPI_DATA_REG); 38262306a36Sopenharmony_ci *rxp++ = be32_to_cpu(rx); 38362306a36Sopenharmony_ci } else { 38462306a36Sopenharmony_ci u8 *rxp = rxbuf; 38562306a36Sopenharmony_ci rx = readl(qspi->base + QSPI_SPI_DATA_REG); 38662306a36Sopenharmony_ci if (rx_wlen >= 8) 38762306a36Sopenharmony_ci *rxp++ = rx >> (rx_wlen - 8); 38862306a36Sopenharmony_ci if (rx_wlen >= 16) 38962306a36Sopenharmony_ci *rxp++ = rx >> (rx_wlen - 16); 39062306a36Sopenharmony_ci if (rx_wlen >= 24) 39162306a36Sopenharmony_ci *rxp++ = rx >> (rx_wlen - 24); 39262306a36Sopenharmony_ci if (rx_wlen >= 32) 39362306a36Sopenharmony_ci *rxp++ = rx; 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci break; 39662306a36Sopenharmony_ci case 2: 39762306a36Sopenharmony_ci *((u16 *)rxbuf) = readw(qspi->base + QSPI_SPI_DATA_REG); 39862306a36Sopenharmony_ci break; 39962306a36Sopenharmony_ci case 4: 40062306a36Sopenharmony_ci *((u32 *)rxbuf) = readl(qspi->base + QSPI_SPI_DATA_REG); 40162306a36Sopenharmony_ci break; 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci rxbuf += rxlen; 40462306a36Sopenharmony_ci count -= rxlen; 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci return 0; 40862306a36Sopenharmony_ci} 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_cistatic int qspi_transfer_msg(struct ti_qspi *qspi, struct spi_transfer *t, 41162306a36Sopenharmony_ci int count) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci int ret; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci if (t->tx_buf) { 41662306a36Sopenharmony_ci ret = qspi_write_msg(qspi, t, count); 41762306a36Sopenharmony_ci if (ret) { 41862306a36Sopenharmony_ci dev_dbg(qspi->dev, "Error while writing\n"); 41962306a36Sopenharmony_ci return ret; 42062306a36Sopenharmony_ci } 42162306a36Sopenharmony_ci } 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci if (t->rx_buf) { 42462306a36Sopenharmony_ci ret = qspi_read_msg(qspi, t, count); 42562306a36Sopenharmony_ci if (ret) { 42662306a36Sopenharmony_ci dev_dbg(qspi->dev, "Error while reading\n"); 42762306a36Sopenharmony_ci return ret; 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci return 0; 43262306a36Sopenharmony_ci} 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_cistatic void ti_qspi_dma_callback(void *param) 43562306a36Sopenharmony_ci{ 43662306a36Sopenharmony_ci struct ti_qspi *qspi = param; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci complete(&qspi->transfer_complete); 43962306a36Sopenharmony_ci} 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_cistatic int ti_qspi_dma_xfer(struct ti_qspi *qspi, dma_addr_t dma_dst, 44262306a36Sopenharmony_ci dma_addr_t dma_src, size_t len) 44362306a36Sopenharmony_ci{ 44462306a36Sopenharmony_ci struct dma_chan *chan = qspi->rx_chan; 44562306a36Sopenharmony_ci dma_cookie_t cookie; 44662306a36Sopenharmony_ci enum dma_ctrl_flags flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT; 44762306a36Sopenharmony_ci struct dma_async_tx_descriptor *tx; 44862306a36Sopenharmony_ci int ret; 44962306a36Sopenharmony_ci unsigned long time_left; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci tx = dmaengine_prep_dma_memcpy(chan, dma_dst, dma_src, len, flags); 45262306a36Sopenharmony_ci if (!tx) { 45362306a36Sopenharmony_ci dev_err(qspi->dev, "device_prep_dma_memcpy error\n"); 45462306a36Sopenharmony_ci return -EIO; 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci tx->callback = ti_qspi_dma_callback; 45862306a36Sopenharmony_ci tx->callback_param = qspi; 45962306a36Sopenharmony_ci cookie = tx->tx_submit(tx); 46062306a36Sopenharmony_ci reinit_completion(&qspi->transfer_complete); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci ret = dma_submit_error(cookie); 46362306a36Sopenharmony_ci if (ret) { 46462306a36Sopenharmony_ci dev_err(qspi->dev, "dma_submit_error %d\n", cookie); 46562306a36Sopenharmony_ci return -EIO; 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci dma_async_issue_pending(chan); 46962306a36Sopenharmony_ci time_left = wait_for_completion_timeout(&qspi->transfer_complete, 47062306a36Sopenharmony_ci msecs_to_jiffies(len)); 47162306a36Sopenharmony_ci if (time_left == 0) { 47262306a36Sopenharmony_ci dmaengine_terminate_sync(chan); 47362306a36Sopenharmony_ci dev_err(qspi->dev, "DMA wait_for_completion_timeout\n"); 47462306a36Sopenharmony_ci return -ETIMEDOUT; 47562306a36Sopenharmony_ci } 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci return 0; 47862306a36Sopenharmony_ci} 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_cistatic int ti_qspi_dma_bounce_buffer(struct ti_qspi *qspi, loff_t offs, 48162306a36Sopenharmony_ci void *to, size_t readsize) 48262306a36Sopenharmony_ci{ 48362306a36Sopenharmony_ci dma_addr_t dma_src = qspi->mmap_phys_base + offs; 48462306a36Sopenharmony_ci int ret = 0; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci /* 48762306a36Sopenharmony_ci * Use bounce buffer as FS like jffs2, ubifs may pass 48862306a36Sopenharmony_ci * buffers that does not belong to kernel lowmem region. 48962306a36Sopenharmony_ci */ 49062306a36Sopenharmony_ci while (readsize != 0) { 49162306a36Sopenharmony_ci size_t xfer_len = min_t(size_t, QSPI_DMA_BUFFER_SIZE, 49262306a36Sopenharmony_ci readsize); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci ret = ti_qspi_dma_xfer(qspi, qspi->rx_bb_dma_addr, 49562306a36Sopenharmony_ci dma_src, xfer_len); 49662306a36Sopenharmony_ci if (ret != 0) 49762306a36Sopenharmony_ci return ret; 49862306a36Sopenharmony_ci memcpy(to, qspi->rx_bb_addr, xfer_len); 49962306a36Sopenharmony_ci readsize -= xfer_len; 50062306a36Sopenharmony_ci dma_src += xfer_len; 50162306a36Sopenharmony_ci to += xfer_len; 50262306a36Sopenharmony_ci } 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci return ret; 50562306a36Sopenharmony_ci} 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_cistatic int ti_qspi_dma_xfer_sg(struct ti_qspi *qspi, struct sg_table rx_sg, 50862306a36Sopenharmony_ci loff_t from) 50962306a36Sopenharmony_ci{ 51062306a36Sopenharmony_ci struct scatterlist *sg; 51162306a36Sopenharmony_ci dma_addr_t dma_src = qspi->mmap_phys_base + from; 51262306a36Sopenharmony_ci dma_addr_t dma_dst; 51362306a36Sopenharmony_ci int i, len, ret; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci for_each_sg(rx_sg.sgl, sg, rx_sg.nents, i) { 51662306a36Sopenharmony_ci dma_dst = sg_dma_address(sg); 51762306a36Sopenharmony_ci len = sg_dma_len(sg); 51862306a36Sopenharmony_ci ret = ti_qspi_dma_xfer(qspi, dma_dst, dma_src, len); 51962306a36Sopenharmony_ci if (ret) 52062306a36Sopenharmony_ci return ret; 52162306a36Sopenharmony_ci dma_src += len; 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci return 0; 52562306a36Sopenharmony_ci} 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_cistatic void ti_qspi_enable_memory_map(struct spi_device *spi) 52862306a36Sopenharmony_ci{ 52962306a36Sopenharmony_ci struct ti_qspi *qspi = spi_master_get_devdata(spi->master); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci ti_qspi_write(qspi, MM_SWITCH, QSPI_SPI_SWITCH_REG); 53262306a36Sopenharmony_ci if (qspi->ctrl_base) { 53362306a36Sopenharmony_ci regmap_update_bits(qspi->ctrl_base, qspi->ctrl_reg, 53462306a36Sopenharmony_ci MEM_CS_MASK, 53562306a36Sopenharmony_ci MEM_CS_EN(spi_get_chipselect(spi, 0))); 53662306a36Sopenharmony_ci } 53762306a36Sopenharmony_ci qspi->mmap_enabled = true; 53862306a36Sopenharmony_ci qspi->current_cs = spi_get_chipselect(spi, 0); 53962306a36Sopenharmony_ci} 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_cistatic void ti_qspi_disable_memory_map(struct spi_device *spi) 54262306a36Sopenharmony_ci{ 54362306a36Sopenharmony_ci struct ti_qspi *qspi = spi_master_get_devdata(spi->master); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci ti_qspi_write(qspi, 0, QSPI_SPI_SWITCH_REG); 54662306a36Sopenharmony_ci if (qspi->ctrl_base) 54762306a36Sopenharmony_ci regmap_update_bits(qspi->ctrl_base, qspi->ctrl_reg, 54862306a36Sopenharmony_ci MEM_CS_MASK, 0); 54962306a36Sopenharmony_ci qspi->mmap_enabled = false; 55062306a36Sopenharmony_ci qspi->current_cs = -1; 55162306a36Sopenharmony_ci} 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_cistatic void ti_qspi_setup_mmap_read(struct spi_device *spi, u8 opcode, 55462306a36Sopenharmony_ci u8 data_nbits, u8 addr_width, 55562306a36Sopenharmony_ci u8 dummy_bytes) 55662306a36Sopenharmony_ci{ 55762306a36Sopenharmony_ci struct ti_qspi *qspi = spi_master_get_devdata(spi->master); 55862306a36Sopenharmony_ci u32 memval = opcode; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci switch (data_nbits) { 56162306a36Sopenharmony_ci case SPI_NBITS_QUAD: 56262306a36Sopenharmony_ci memval |= QSPI_SETUP_RD_QUAD; 56362306a36Sopenharmony_ci break; 56462306a36Sopenharmony_ci case SPI_NBITS_DUAL: 56562306a36Sopenharmony_ci memval |= QSPI_SETUP_RD_DUAL; 56662306a36Sopenharmony_ci break; 56762306a36Sopenharmony_ci default: 56862306a36Sopenharmony_ci memval |= QSPI_SETUP_RD_NORMAL; 56962306a36Sopenharmony_ci break; 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci memval |= ((addr_width - 1) << QSPI_SETUP_ADDR_SHIFT | 57262306a36Sopenharmony_ci dummy_bytes << QSPI_SETUP_DUMMY_SHIFT); 57362306a36Sopenharmony_ci ti_qspi_write(qspi, memval, 57462306a36Sopenharmony_ci QSPI_SPI_SETUP_REG(spi_get_chipselect(spi, 0))); 57562306a36Sopenharmony_ci} 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_cistatic int ti_qspi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op) 57862306a36Sopenharmony_ci{ 57962306a36Sopenharmony_ci struct ti_qspi *qspi = spi_controller_get_devdata(mem->spi->master); 58062306a36Sopenharmony_ci size_t max_len; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci if (op->data.dir == SPI_MEM_DATA_IN) { 58362306a36Sopenharmony_ci if (op->addr.val < qspi->mmap_size) { 58462306a36Sopenharmony_ci /* Limit MMIO to the mmaped region */ 58562306a36Sopenharmony_ci if (op->addr.val + op->data.nbytes > qspi->mmap_size) { 58662306a36Sopenharmony_ci max_len = qspi->mmap_size - op->addr.val; 58762306a36Sopenharmony_ci op->data.nbytes = min((size_t) op->data.nbytes, 58862306a36Sopenharmony_ci max_len); 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci } else { 59162306a36Sopenharmony_ci /* 59262306a36Sopenharmony_ci * Use fallback mode (SW generated transfers) above the 59362306a36Sopenharmony_ci * mmaped region. 59462306a36Sopenharmony_ci * Adjust size to comply with the QSPI max frame length. 59562306a36Sopenharmony_ci */ 59662306a36Sopenharmony_ci max_len = QSPI_FRAME; 59762306a36Sopenharmony_ci max_len -= 1 + op->addr.nbytes + op->dummy.nbytes; 59862306a36Sopenharmony_ci op->data.nbytes = min((size_t) op->data.nbytes, 59962306a36Sopenharmony_ci max_len); 60062306a36Sopenharmony_ci } 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci return 0; 60462306a36Sopenharmony_ci} 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_cistatic int ti_qspi_exec_mem_op(struct spi_mem *mem, 60762306a36Sopenharmony_ci const struct spi_mem_op *op) 60862306a36Sopenharmony_ci{ 60962306a36Sopenharmony_ci struct ti_qspi *qspi = spi_master_get_devdata(mem->spi->master); 61062306a36Sopenharmony_ci u32 from = 0; 61162306a36Sopenharmony_ci int ret = 0; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci /* Only optimize read path. */ 61462306a36Sopenharmony_ci if (!op->data.nbytes || op->data.dir != SPI_MEM_DATA_IN || 61562306a36Sopenharmony_ci !op->addr.nbytes || op->addr.nbytes > 4) 61662306a36Sopenharmony_ci return -ENOTSUPP; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci /* Address exceeds MMIO window size, fall back to regular mode. */ 61962306a36Sopenharmony_ci from = op->addr.val; 62062306a36Sopenharmony_ci if (from + op->data.nbytes > qspi->mmap_size) 62162306a36Sopenharmony_ci return -ENOTSUPP; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci mutex_lock(&qspi->list_lock); 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci if (!qspi->mmap_enabled || qspi->current_cs != spi_get_chipselect(mem->spi, 0)) { 62662306a36Sopenharmony_ci ti_qspi_setup_clk(qspi, mem->spi->max_speed_hz); 62762306a36Sopenharmony_ci ti_qspi_enable_memory_map(mem->spi); 62862306a36Sopenharmony_ci } 62962306a36Sopenharmony_ci ti_qspi_setup_mmap_read(mem->spi, op->cmd.opcode, op->data.buswidth, 63062306a36Sopenharmony_ci op->addr.nbytes, op->dummy.nbytes); 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci if (qspi->rx_chan) { 63362306a36Sopenharmony_ci struct sg_table sgt; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci if (virt_addr_valid(op->data.buf.in) && 63662306a36Sopenharmony_ci !spi_controller_dma_map_mem_op_data(mem->spi->master, op, 63762306a36Sopenharmony_ci &sgt)) { 63862306a36Sopenharmony_ci ret = ti_qspi_dma_xfer_sg(qspi, sgt, from); 63962306a36Sopenharmony_ci spi_controller_dma_unmap_mem_op_data(mem->spi->master, 64062306a36Sopenharmony_ci op, &sgt); 64162306a36Sopenharmony_ci } else { 64262306a36Sopenharmony_ci ret = ti_qspi_dma_bounce_buffer(qspi, from, 64362306a36Sopenharmony_ci op->data.buf.in, 64462306a36Sopenharmony_ci op->data.nbytes); 64562306a36Sopenharmony_ci } 64662306a36Sopenharmony_ci } else { 64762306a36Sopenharmony_ci memcpy_fromio(op->data.buf.in, qspi->mmap_base + from, 64862306a36Sopenharmony_ci op->data.nbytes); 64962306a36Sopenharmony_ci } 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci mutex_unlock(&qspi->list_lock); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci return ret; 65462306a36Sopenharmony_ci} 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_cistatic const struct spi_controller_mem_ops ti_qspi_mem_ops = { 65762306a36Sopenharmony_ci .exec_op = ti_qspi_exec_mem_op, 65862306a36Sopenharmony_ci .adjust_op_size = ti_qspi_adjust_op_size, 65962306a36Sopenharmony_ci}; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_cistatic int ti_qspi_start_transfer_one(struct spi_master *master, 66262306a36Sopenharmony_ci struct spi_message *m) 66362306a36Sopenharmony_ci{ 66462306a36Sopenharmony_ci struct ti_qspi *qspi = spi_master_get_devdata(master); 66562306a36Sopenharmony_ci struct spi_device *spi = m->spi; 66662306a36Sopenharmony_ci struct spi_transfer *t; 66762306a36Sopenharmony_ci int status = 0, ret; 66862306a36Sopenharmony_ci unsigned int frame_len_words, transfer_len_words; 66962306a36Sopenharmony_ci int wlen; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci /* setup device control reg */ 67262306a36Sopenharmony_ci qspi->dc = 0; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci if (spi->mode & SPI_CPHA) 67562306a36Sopenharmony_ci qspi->dc |= QSPI_CKPHA(spi_get_chipselect(spi, 0)); 67662306a36Sopenharmony_ci if (spi->mode & SPI_CPOL) 67762306a36Sopenharmony_ci qspi->dc |= QSPI_CKPOL(spi_get_chipselect(spi, 0)); 67862306a36Sopenharmony_ci if (spi->mode & SPI_CS_HIGH) 67962306a36Sopenharmony_ci qspi->dc |= QSPI_CSPOL(spi_get_chipselect(spi, 0)); 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci frame_len_words = 0; 68262306a36Sopenharmony_ci list_for_each_entry(t, &m->transfers, transfer_list) 68362306a36Sopenharmony_ci frame_len_words += t->len / (t->bits_per_word >> 3); 68462306a36Sopenharmony_ci frame_len_words = min_t(unsigned int, frame_len_words, QSPI_FRAME); 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci /* setup command reg */ 68762306a36Sopenharmony_ci qspi->cmd = 0; 68862306a36Sopenharmony_ci qspi->cmd |= QSPI_EN_CS(spi_get_chipselect(spi, 0)); 68962306a36Sopenharmony_ci qspi->cmd |= QSPI_FLEN(frame_len_words); 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci ti_qspi_write(qspi, qspi->dc, QSPI_SPI_DC_REG); 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci mutex_lock(&qspi->list_lock); 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci if (qspi->mmap_enabled) 69662306a36Sopenharmony_ci ti_qspi_disable_memory_map(spi); 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci list_for_each_entry(t, &m->transfers, transfer_list) { 69962306a36Sopenharmony_ci qspi->cmd = ((qspi->cmd & ~QSPI_WLEN_MASK) | 70062306a36Sopenharmony_ci QSPI_WLEN(t->bits_per_word)); 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci wlen = t->bits_per_word >> 3; 70362306a36Sopenharmony_ci transfer_len_words = min(t->len / wlen, frame_len_words); 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci ti_qspi_setup_clk(qspi, t->speed_hz); 70662306a36Sopenharmony_ci ret = qspi_transfer_msg(qspi, t, transfer_len_words * wlen); 70762306a36Sopenharmony_ci if (ret) { 70862306a36Sopenharmony_ci dev_dbg(qspi->dev, "transfer message failed\n"); 70962306a36Sopenharmony_ci mutex_unlock(&qspi->list_lock); 71062306a36Sopenharmony_ci return -EINVAL; 71162306a36Sopenharmony_ci } 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci m->actual_length += transfer_len_words * wlen; 71462306a36Sopenharmony_ci frame_len_words -= transfer_len_words; 71562306a36Sopenharmony_ci if (frame_len_words == 0) 71662306a36Sopenharmony_ci break; 71762306a36Sopenharmony_ci } 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci mutex_unlock(&qspi->list_lock); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci ti_qspi_write(qspi, qspi->cmd | QSPI_INVAL, QSPI_SPI_CMD_REG); 72262306a36Sopenharmony_ci m->status = status; 72362306a36Sopenharmony_ci spi_finalize_current_message(master); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci return status; 72662306a36Sopenharmony_ci} 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_cistatic int ti_qspi_runtime_resume(struct device *dev) 72962306a36Sopenharmony_ci{ 73062306a36Sopenharmony_ci struct ti_qspi *qspi; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci qspi = dev_get_drvdata(dev); 73362306a36Sopenharmony_ci ti_qspi_restore_ctx(qspi); 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci return 0; 73662306a36Sopenharmony_ci} 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_cistatic void ti_qspi_dma_cleanup(struct ti_qspi *qspi) 73962306a36Sopenharmony_ci{ 74062306a36Sopenharmony_ci if (qspi->rx_bb_addr) 74162306a36Sopenharmony_ci dma_free_coherent(qspi->dev, QSPI_DMA_BUFFER_SIZE, 74262306a36Sopenharmony_ci qspi->rx_bb_addr, 74362306a36Sopenharmony_ci qspi->rx_bb_dma_addr); 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci if (qspi->rx_chan) 74662306a36Sopenharmony_ci dma_release_channel(qspi->rx_chan); 74762306a36Sopenharmony_ci} 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_cistatic const struct of_device_id ti_qspi_match[] = { 75062306a36Sopenharmony_ci {.compatible = "ti,dra7xxx-qspi" }, 75162306a36Sopenharmony_ci {.compatible = "ti,am4372-qspi" }, 75262306a36Sopenharmony_ci {}, 75362306a36Sopenharmony_ci}; 75462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, ti_qspi_match); 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_cistatic int ti_qspi_probe(struct platform_device *pdev) 75762306a36Sopenharmony_ci{ 75862306a36Sopenharmony_ci struct ti_qspi *qspi; 75962306a36Sopenharmony_ci struct spi_master *master; 76062306a36Sopenharmony_ci struct resource *r, *res_mmap; 76162306a36Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 76262306a36Sopenharmony_ci u32 max_freq; 76362306a36Sopenharmony_ci int ret = 0, num_cs, irq; 76462306a36Sopenharmony_ci dma_cap_mask_t mask; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci master = spi_alloc_master(&pdev->dev, sizeof(*qspi)); 76762306a36Sopenharmony_ci if (!master) 76862306a36Sopenharmony_ci return -ENOMEM; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD; 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci master->flags = SPI_CONTROLLER_HALF_DUPLEX; 77362306a36Sopenharmony_ci master->setup = ti_qspi_setup; 77462306a36Sopenharmony_ci master->auto_runtime_pm = true; 77562306a36Sopenharmony_ci master->transfer_one_message = ti_qspi_start_transfer_one; 77662306a36Sopenharmony_ci master->dev.of_node = pdev->dev.of_node; 77762306a36Sopenharmony_ci master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) | 77862306a36Sopenharmony_ci SPI_BPW_MASK(8); 77962306a36Sopenharmony_ci master->mem_ops = &ti_qspi_mem_ops; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci if (!of_property_read_u32(np, "num-cs", &num_cs)) 78262306a36Sopenharmony_ci master->num_chipselect = num_cs; 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci qspi = spi_master_get_devdata(master); 78562306a36Sopenharmony_ci qspi->master = master; 78662306a36Sopenharmony_ci qspi->dev = &pdev->dev; 78762306a36Sopenharmony_ci platform_set_drvdata(pdev, qspi); 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_base"); 79062306a36Sopenharmony_ci if (r == NULL) { 79162306a36Sopenharmony_ci r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 79262306a36Sopenharmony_ci if (r == NULL) { 79362306a36Sopenharmony_ci dev_err(&pdev->dev, "missing platform data\n"); 79462306a36Sopenharmony_ci ret = -ENODEV; 79562306a36Sopenharmony_ci goto free_master; 79662306a36Sopenharmony_ci } 79762306a36Sopenharmony_ci } 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci res_mmap = platform_get_resource_byname(pdev, 80062306a36Sopenharmony_ci IORESOURCE_MEM, "qspi_mmap"); 80162306a36Sopenharmony_ci if (res_mmap == NULL) { 80262306a36Sopenharmony_ci res_mmap = platform_get_resource(pdev, IORESOURCE_MEM, 1); 80362306a36Sopenharmony_ci if (res_mmap == NULL) { 80462306a36Sopenharmony_ci dev_err(&pdev->dev, 80562306a36Sopenharmony_ci "memory mapped resource not required\n"); 80662306a36Sopenharmony_ci } 80762306a36Sopenharmony_ci } 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci if (res_mmap) 81062306a36Sopenharmony_ci qspi->mmap_size = resource_size(res_mmap); 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci irq = platform_get_irq(pdev, 0); 81362306a36Sopenharmony_ci if (irq < 0) { 81462306a36Sopenharmony_ci ret = irq; 81562306a36Sopenharmony_ci goto free_master; 81662306a36Sopenharmony_ci } 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci mutex_init(&qspi->list_lock); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci qspi->base = devm_ioremap_resource(&pdev->dev, r); 82162306a36Sopenharmony_ci if (IS_ERR(qspi->base)) { 82262306a36Sopenharmony_ci ret = PTR_ERR(qspi->base); 82362306a36Sopenharmony_ci goto free_master; 82462306a36Sopenharmony_ci } 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci if (of_property_read_bool(np, "syscon-chipselects")) { 82862306a36Sopenharmony_ci qspi->ctrl_base = 82962306a36Sopenharmony_ci syscon_regmap_lookup_by_phandle(np, 83062306a36Sopenharmony_ci "syscon-chipselects"); 83162306a36Sopenharmony_ci if (IS_ERR(qspi->ctrl_base)) { 83262306a36Sopenharmony_ci ret = PTR_ERR(qspi->ctrl_base); 83362306a36Sopenharmony_ci goto free_master; 83462306a36Sopenharmony_ci } 83562306a36Sopenharmony_ci ret = of_property_read_u32_index(np, 83662306a36Sopenharmony_ci "syscon-chipselects", 83762306a36Sopenharmony_ci 1, &qspi->ctrl_reg); 83862306a36Sopenharmony_ci if (ret) { 83962306a36Sopenharmony_ci dev_err(&pdev->dev, 84062306a36Sopenharmony_ci "couldn't get ctrl_mod reg index\n"); 84162306a36Sopenharmony_ci goto free_master; 84262306a36Sopenharmony_ci } 84362306a36Sopenharmony_ci } 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci qspi->fclk = devm_clk_get(&pdev->dev, "fck"); 84662306a36Sopenharmony_ci if (IS_ERR(qspi->fclk)) { 84762306a36Sopenharmony_ci ret = PTR_ERR(qspi->fclk); 84862306a36Sopenharmony_ci dev_err(&pdev->dev, "could not get clk: %d\n", ret); 84962306a36Sopenharmony_ci } 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci pm_runtime_use_autosuspend(&pdev->dev); 85262306a36Sopenharmony_ci pm_runtime_set_autosuspend_delay(&pdev->dev, QSPI_AUTOSUSPEND_TIMEOUT); 85362306a36Sopenharmony_ci pm_runtime_enable(&pdev->dev); 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci if (!of_property_read_u32(np, "spi-max-frequency", &max_freq)) 85662306a36Sopenharmony_ci master->max_speed_hz = max_freq; 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci dma_cap_zero(mask); 85962306a36Sopenharmony_ci dma_cap_set(DMA_MEMCPY, mask); 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci qspi->rx_chan = dma_request_chan_by_mask(&mask); 86262306a36Sopenharmony_ci if (IS_ERR(qspi->rx_chan)) { 86362306a36Sopenharmony_ci dev_err(qspi->dev, 86462306a36Sopenharmony_ci "No Rx DMA available, trying mmap mode\n"); 86562306a36Sopenharmony_ci qspi->rx_chan = NULL; 86662306a36Sopenharmony_ci ret = 0; 86762306a36Sopenharmony_ci goto no_dma; 86862306a36Sopenharmony_ci } 86962306a36Sopenharmony_ci qspi->rx_bb_addr = dma_alloc_coherent(qspi->dev, 87062306a36Sopenharmony_ci QSPI_DMA_BUFFER_SIZE, 87162306a36Sopenharmony_ci &qspi->rx_bb_dma_addr, 87262306a36Sopenharmony_ci GFP_KERNEL | GFP_DMA); 87362306a36Sopenharmony_ci if (!qspi->rx_bb_addr) { 87462306a36Sopenharmony_ci dev_err(qspi->dev, 87562306a36Sopenharmony_ci "dma_alloc_coherent failed, using PIO mode\n"); 87662306a36Sopenharmony_ci dma_release_channel(qspi->rx_chan); 87762306a36Sopenharmony_ci goto no_dma; 87862306a36Sopenharmony_ci } 87962306a36Sopenharmony_ci master->dma_rx = qspi->rx_chan; 88062306a36Sopenharmony_ci init_completion(&qspi->transfer_complete); 88162306a36Sopenharmony_ci if (res_mmap) 88262306a36Sopenharmony_ci qspi->mmap_phys_base = (dma_addr_t)res_mmap->start; 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_cino_dma: 88562306a36Sopenharmony_ci if (!qspi->rx_chan && res_mmap) { 88662306a36Sopenharmony_ci qspi->mmap_base = devm_ioremap_resource(&pdev->dev, res_mmap); 88762306a36Sopenharmony_ci if (IS_ERR(qspi->mmap_base)) { 88862306a36Sopenharmony_ci dev_info(&pdev->dev, 88962306a36Sopenharmony_ci "mmap failed with error %ld using PIO mode\n", 89062306a36Sopenharmony_ci PTR_ERR(qspi->mmap_base)); 89162306a36Sopenharmony_ci qspi->mmap_base = NULL; 89262306a36Sopenharmony_ci master->mem_ops = NULL; 89362306a36Sopenharmony_ci } 89462306a36Sopenharmony_ci } 89562306a36Sopenharmony_ci qspi->mmap_enabled = false; 89662306a36Sopenharmony_ci qspi->current_cs = -1; 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci ret = devm_spi_register_master(&pdev->dev, master); 89962306a36Sopenharmony_ci if (!ret) 90062306a36Sopenharmony_ci return 0; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci ti_qspi_dma_cleanup(qspi); 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 90562306a36Sopenharmony_cifree_master: 90662306a36Sopenharmony_ci spi_master_put(master); 90762306a36Sopenharmony_ci return ret; 90862306a36Sopenharmony_ci} 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_cistatic int ti_qspi_remove(struct platform_device *pdev) 91162306a36Sopenharmony_ci{ 91262306a36Sopenharmony_ci struct ti_qspi *qspi = platform_get_drvdata(pdev); 91362306a36Sopenharmony_ci int rc; 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci rc = spi_master_suspend(qspi->master); 91662306a36Sopenharmony_ci if (rc) 91762306a36Sopenharmony_ci return rc; 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci pm_runtime_put_sync(&pdev->dev); 92062306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci ti_qspi_dma_cleanup(qspi); 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci return 0; 92562306a36Sopenharmony_ci} 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_cistatic const struct dev_pm_ops ti_qspi_pm_ops = { 92862306a36Sopenharmony_ci .runtime_resume = ti_qspi_runtime_resume, 92962306a36Sopenharmony_ci}; 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_cistatic struct platform_driver ti_qspi_driver = { 93262306a36Sopenharmony_ci .probe = ti_qspi_probe, 93362306a36Sopenharmony_ci .remove = ti_qspi_remove, 93462306a36Sopenharmony_ci .driver = { 93562306a36Sopenharmony_ci .name = "ti-qspi", 93662306a36Sopenharmony_ci .pm = &ti_qspi_pm_ops, 93762306a36Sopenharmony_ci .of_match_table = ti_qspi_match, 93862306a36Sopenharmony_ci } 93962306a36Sopenharmony_ci}; 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_cimodule_platform_driver(ti_qspi_driver); 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ciMODULE_AUTHOR("Sourav Poddar <sourav.poddar@ti.com>"); 94462306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 94562306a36Sopenharmony_ciMODULE_DESCRIPTION("TI QSPI controller driver"); 94662306a36Sopenharmony_ciMODULE_ALIAS("platform:ti-qspi"); 947