162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) STMicroelectronics 2018 - All Rights Reserved 462306a36Sopenharmony_ci * Author: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include <linux/bitfield.h> 762306a36Sopenharmony_ci#include <linux/clk.h> 862306a36Sopenharmony_ci#include <linux/dmaengine.h> 962306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1062306a36Sopenharmony_ci#include <linux/errno.h> 1162306a36Sopenharmony_ci#include <linux/io.h> 1262306a36Sopenharmony_ci#include <linux/iopoll.h> 1362306a36Sopenharmony_ci#include <linux/interrupt.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/mutex.h> 1662306a36Sopenharmony_ci#include <linux/of.h> 1762306a36Sopenharmony_ci#include <linux/of_gpio.h> 1862306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h> 1962306a36Sopenharmony_ci#include <linux/pm_runtime.h> 2062306a36Sopenharmony_ci#include <linux/platform_device.h> 2162306a36Sopenharmony_ci#include <linux/reset.h> 2262306a36Sopenharmony_ci#include <linux/sizes.h> 2362306a36Sopenharmony_ci#include <linux/spi/spi-mem.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define QSPI_CR 0x00 2662306a36Sopenharmony_ci#define CR_EN BIT(0) 2762306a36Sopenharmony_ci#define CR_ABORT BIT(1) 2862306a36Sopenharmony_ci#define CR_DMAEN BIT(2) 2962306a36Sopenharmony_ci#define CR_TCEN BIT(3) 3062306a36Sopenharmony_ci#define CR_SSHIFT BIT(4) 3162306a36Sopenharmony_ci#define CR_DFM BIT(6) 3262306a36Sopenharmony_ci#define CR_FSEL BIT(7) 3362306a36Sopenharmony_ci#define CR_FTHRES_SHIFT 8 3462306a36Sopenharmony_ci#define CR_TEIE BIT(16) 3562306a36Sopenharmony_ci#define CR_TCIE BIT(17) 3662306a36Sopenharmony_ci#define CR_FTIE BIT(18) 3762306a36Sopenharmony_ci#define CR_SMIE BIT(19) 3862306a36Sopenharmony_ci#define CR_TOIE BIT(20) 3962306a36Sopenharmony_ci#define CR_APMS BIT(22) 4062306a36Sopenharmony_ci#define CR_PRESC_MASK GENMASK(31, 24) 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#define QSPI_DCR 0x04 4362306a36Sopenharmony_ci#define DCR_FSIZE_MASK GENMASK(20, 16) 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#define QSPI_SR 0x08 4662306a36Sopenharmony_ci#define SR_TEF BIT(0) 4762306a36Sopenharmony_ci#define SR_TCF BIT(1) 4862306a36Sopenharmony_ci#define SR_FTF BIT(2) 4962306a36Sopenharmony_ci#define SR_SMF BIT(3) 5062306a36Sopenharmony_ci#define SR_TOF BIT(4) 5162306a36Sopenharmony_ci#define SR_BUSY BIT(5) 5262306a36Sopenharmony_ci#define SR_FLEVEL_MASK GENMASK(13, 8) 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci#define QSPI_FCR 0x0c 5562306a36Sopenharmony_ci#define FCR_CTEF BIT(0) 5662306a36Sopenharmony_ci#define FCR_CTCF BIT(1) 5762306a36Sopenharmony_ci#define FCR_CSMF BIT(3) 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci#define QSPI_DLR 0x10 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci#define QSPI_CCR 0x14 6262306a36Sopenharmony_ci#define CCR_INST_MASK GENMASK(7, 0) 6362306a36Sopenharmony_ci#define CCR_IMODE_MASK GENMASK(9, 8) 6462306a36Sopenharmony_ci#define CCR_ADMODE_MASK GENMASK(11, 10) 6562306a36Sopenharmony_ci#define CCR_ADSIZE_MASK GENMASK(13, 12) 6662306a36Sopenharmony_ci#define CCR_DCYC_MASK GENMASK(22, 18) 6762306a36Sopenharmony_ci#define CCR_DMODE_MASK GENMASK(25, 24) 6862306a36Sopenharmony_ci#define CCR_FMODE_MASK GENMASK(27, 26) 6962306a36Sopenharmony_ci#define CCR_FMODE_INDW (0U << 26) 7062306a36Sopenharmony_ci#define CCR_FMODE_INDR (1U << 26) 7162306a36Sopenharmony_ci#define CCR_FMODE_APM (2U << 26) 7262306a36Sopenharmony_ci#define CCR_FMODE_MM (3U << 26) 7362306a36Sopenharmony_ci#define CCR_BUSWIDTH_0 0x0 7462306a36Sopenharmony_ci#define CCR_BUSWIDTH_1 0x1 7562306a36Sopenharmony_ci#define CCR_BUSWIDTH_2 0x2 7662306a36Sopenharmony_ci#define CCR_BUSWIDTH_4 0x3 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci#define QSPI_AR 0x18 7962306a36Sopenharmony_ci#define QSPI_ABR 0x1c 8062306a36Sopenharmony_ci#define QSPI_DR 0x20 8162306a36Sopenharmony_ci#define QSPI_PSMKR 0x24 8262306a36Sopenharmony_ci#define QSPI_PSMAR 0x28 8362306a36Sopenharmony_ci#define QSPI_PIR 0x2c 8462306a36Sopenharmony_ci#define QSPI_LPTR 0x30 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci#define STM32_QSPI_MAX_MMAP_SZ SZ_256M 8762306a36Sopenharmony_ci#define STM32_QSPI_MAX_NORCHIP 2 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci#define STM32_FIFO_TIMEOUT_US 30000 9062306a36Sopenharmony_ci#define STM32_BUSY_TIMEOUT_US 100000 9162306a36Sopenharmony_ci#define STM32_ABT_TIMEOUT_US 100000 9262306a36Sopenharmony_ci#define STM32_COMP_TIMEOUT_MS 1000 9362306a36Sopenharmony_ci#define STM32_AUTOSUSPEND_DELAY -1 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistruct stm32_qspi_flash { 9662306a36Sopenharmony_ci u32 cs; 9762306a36Sopenharmony_ci u32 presc; 9862306a36Sopenharmony_ci}; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistruct stm32_qspi { 10162306a36Sopenharmony_ci struct device *dev; 10262306a36Sopenharmony_ci struct spi_controller *ctrl; 10362306a36Sopenharmony_ci phys_addr_t phys_base; 10462306a36Sopenharmony_ci void __iomem *io_base; 10562306a36Sopenharmony_ci void __iomem *mm_base; 10662306a36Sopenharmony_ci resource_size_t mm_size; 10762306a36Sopenharmony_ci struct clk *clk; 10862306a36Sopenharmony_ci u32 clk_rate; 10962306a36Sopenharmony_ci struct stm32_qspi_flash flash[STM32_QSPI_MAX_NORCHIP]; 11062306a36Sopenharmony_ci struct completion data_completion; 11162306a36Sopenharmony_ci struct completion match_completion; 11262306a36Sopenharmony_ci u32 fmode; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci struct dma_chan *dma_chtx; 11562306a36Sopenharmony_ci struct dma_chan *dma_chrx; 11662306a36Sopenharmony_ci struct completion dma_completion; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci u32 cr_reg; 11962306a36Sopenharmony_ci u32 dcr_reg; 12062306a36Sopenharmony_ci unsigned long status_timeout; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci /* 12362306a36Sopenharmony_ci * to protect device configuration, could be different between 12462306a36Sopenharmony_ci * 2 flash access (bk1, bk2) 12562306a36Sopenharmony_ci */ 12662306a36Sopenharmony_ci struct mutex lock; 12762306a36Sopenharmony_ci}; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic irqreturn_t stm32_qspi_irq(int irq, void *dev_id) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci struct stm32_qspi *qspi = (struct stm32_qspi *)dev_id; 13262306a36Sopenharmony_ci u32 cr, sr; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci cr = readl_relaxed(qspi->io_base + QSPI_CR); 13562306a36Sopenharmony_ci sr = readl_relaxed(qspi->io_base + QSPI_SR); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci if (cr & CR_SMIE && sr & SR_SMF) { 13862306a36Sopenharmony_ci /* disable irq */ 13962306a36Sopenharmony_ci cr &= ~CR_SMIE; 14062306a36Sopenharmony_ci writel_relaxed(cr, qspi->io_base + QSPI_CR); 14162306a36Sopenharmony_ci complete(&qspi->match_completion); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci return IRQ_HANDLED; 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci if (sr & (SR_TEF | SR_TCF)) { 14762306a36Sopenharmony_ci /* disable irq */ 14862306a36Sopenharmony_ci cr &= ~CR_TCIE & ~CR_TEIE; 14962306a36Sopenharmony_ci writel_relaxed(cr, qspi->io_base + QSPI_CR); 15062306a36Sopenharmony_ci complete(&qspi->data_completion); 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci return IRQ_HANDLED; 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cistatic void stm32_qspi_read_fifo(u8 *val, void __iomem *addr) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci *val = readb_relaxed(addr); 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic void stm32_qspi_write_fifo(u8 *val, void __iomem *addr) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci writeb_relaxed(*val, addr); 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic int stm32_qspi_tx_poll(struct stm32_qspi *qspi, 16762306a36Sopenharmony_ci const struct spi_mem_op *op) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci void (*tx_fifo)(u8 *val, void __iomem *addr); 17062306a36Sopenharmony_ci u32 len = op->data.nbytes, sr; 17162306a36Sopenharmony_ci u8 *buf; 17262306a36Sopenharmony_ci int ret; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci if (op->data.dir == SPI_MEM_DATA_IN) { 17562306a36Sopenharmony_ci tx_fifo = stm32_qspi_read_fifo; 17662306a36Sopenharmony_ci buf = op->data.buf.in; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci } else { 17962306a36Sopenharmony_ci tx_fifo = stm32_qspi_write_fifo; 18062306a36Sopenharmony_ci buf = (u8 *)op->data.buf.out; 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci while (len--) { 18462306a36Sopenharmony_ci ret = readl_relaxed_poll_timeout_atomic(qspi->io_base + QSPI_SR, 18562306a36Sopenharmony_ci sr, (sr & SR_FTF), 1, 18662306a36Sopenharmony_ci STM32_FIFO_TIMEOUT_US); 18762306a36Sopenharmony_ci if (ret) { 18862306a36Sopenharmony_ci dev_err(qspi->dev, "fifo timeout (len:%d stat:%#x)\n", 18962306a36Sopenharmony_ci len, sr); 19062306a36Sopenharmony_ci return ret; 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci tx_fifo(buf++, qspi->io_base + QSPI_DR); 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci return 0; 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistatic int stm32_qspi_tx_mm(struct stm32_qspi *qspi, 19962306a36Sopenharmony_ci const struct spi_mem_op *op) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci memcpy_fromio(op->data.buf.in, qspi->mm_base + op->addr.val, 20262306a36Sopenharmony_ci op->data.nbytes); 20362306a36Sopenharmony_ci return 0; 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic void stm32_qspi_dma_callback(void *arg) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci struct completion *dma_completion = arg; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci complete(dma_completion); 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_cistatic int stm32_qspi_tx_dma(struct stm32_qspi *qspi, 21462306a36Sopenharmony_ci const struct spi_mem_op *op) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci struct dma_async_tx_descriptor *desc; 21762306a36Sopenharmony_ci enum dma_transfer_direction dma_dir; 21862306a36Sopenharmony_ci struct dma_chan *dma_ch; 21962306a36Sopenharmony_ci struct sg_table sgt; 22062306a36Sopenharmony_ci dma_cookie_t cookie; 22162306a36Sopenharmony_ci u32 cr, t_out; 22262306a36Sopenharmony_ci int err; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci if (op->data.dir == SPI_MEM_DATA_IN) { 22562306a36Sopenharmony_ci dma_dir = DMA_DEV_TO_MEM; 22662306a36Sopenharmony_ci dma_ch = qspi->dma_chrx; 22762306a36Sopenharmony_ci } else { 22862306a36Sopenharmony_ci dma_dir = DMA_MEM_TO_DEV; 22962306a36Sopenharmony_ci dma_ch = qspi->dma_chtx; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci /* 23362306a36Sopenharmony_ci * spi_map_buf return -EINVAL if the buffer is not DMA-able 23462306a36Sopenharmony_ci * (DMA-able: in vmalloc | kmap | virt_addr_valid) 23562306a36Sopenharmony_ci */ 23662306a36Sopenharmony_ci err = spi_controller_dma_map_mem_op_data(qspi->ctrl, op, &sgt); 23762306a36Sopenharmony_ci if (err) 23862306a36Sopenharmony_ci return err; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci desc = dmaengine_prep_slave_sg(dma_ch, sgt.sgl, sgt.nents, 24162306a36Sopenharmony_ci dma_dir, DMA_PREP_INTERRUPT); 24262306a36Sopenharmony_ci if (!desc) { 24362306a36Sopenharmony_ci err = -ENOMEM; 24462306a36Sopenharmony_ci goto out_unmap; 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci cr = readl_relaxed(qspi->io_base + QSPI_CR); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci reinit_completion(&qspi->dma_completion); 25062306a36Sopenharmony_ci desc->callback = stm32_qspi_dma_callback; 25162306a36Sopenharmony_ci desc->callback_param = &qspi->dma_completion; 25262306a36Sopenharmony_ci cookie = dmaengine_submit(desc); 25362306a36Sopenharmony_ci err = dma_submit_error(cookie); 25462306a36Sopenharmony_ci if (err) 25562306a36Sopenharmony_ci goto out; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci dma_async_issue_pending(dma_ch); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci writel_relaxed(cr | CR_DMAEN, qspi->io_base + QSPI_CR); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci t_out = sgt.nents * STM32_COMP_TIMEOUT_MS; 26262306a36Sopenharmony_ci if (!wait_for_completion_timeout(&qspi->dma_completion, 26362306a36Sopenharmony_ci msecs_to_jiffies(t_out))) 26462306a36Sopenharmony_ci err = -ETIMEDOUT; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci if (err) 26762306a36Sopenharmony_ci dmaengine_terminate_all(dma_ch); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ciout: 27062306a36Sopenharmony_ci writel_relaxed(cr & ~CR_DMAEN, qspi->io_base + QSPI_CR); 27162306a36Sopenharmony_ciout_unmap: 27262306a36Sopenharmony_ci spi_controller_dma_unmap_mem_op_data(qspi->ctrl, op, &sgt); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci return err; 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic int stm32_qspi_tx(struct stm32_qspi *qspi, const struct spi_mem_op *op) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci if (!op->data.nbytes) 28062306a36Sopenharmony_ci return 0; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci if (qspi->fmode == CCR_FMODE_MM) 28362306a36Sopenharmony_ci return stm32_qspi_tx_mm(qspi, op); 28462306a36Sopenharmony_ci else if (((op->data.dir == SPI_MEM_DATA_IN && qspi->dma_chrx) || 28562306a36Sopenharmony_ci (op->data.dir == SPI_MEM_DATA_OUT && qspi->dma_chtx)) && 28662306a36Sopenharmony_ci op->data.nbytes > 4) 28762306a36Sopenharmony_ci if (!stm32_qspi_tx_dma(qspi, op)) 28862306a36Sopenharmony_ci return 0; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci return stm32_qspi_tx_poll(qspi, op); 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic int stm32_qspi_wait_nobusy(struct stm32_qspi *qspi) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci u32 sr; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci return readl_relaxed_poll_timeout_atomic(qspi->io_base + QSPI_SR, sr, 29862306a36Sopenharmony_ci !(sr & SR_BUSY), 1, 29962306a36Sopenharmony_ci STM32_BUSY_TIMEOUT_US); 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_cistatic int stm32_qspi_wait_cmd(struct stm32_qspi *qspi) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci u32 cr, sr; 30562306a36Sopenharmony_ci int err = 0; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci if ((readl_relaxed(qspi->io_base + QSPI_SR) & SR_TCF) || 30862306a36Sopenharmony_ci qspi->fmode == CCR_FMODE_APM) 30962306a36Sopenharmony_ci goto out; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci reinit_completion(&qspi->data_completion); 31262306a36Sopenharmony_ci cr = readl_relaxed(qspi->io_base + QSPI_CR); 31362306a36Sopenharmony_ci writel_relaxed(cr | CR_TCIE | CR_TEIE, qspi->io_base + QSPI_CR); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci if (!wait_for_completion_timeout(&qspi->data_completion, 31662306a36Sopenharmony_ci msecs_to_jiffies(STM32_COMP_TIMEOUT_MS))) { 31762306a36Sopenharmony_ci err = -ETIMEDOUT; 31862306a36Sopenharmony_ci } else { 31962306a36Sopenharmony_ci sr = readl_relaxed(qspi->io_base + QSPI_SR); 32062306a36Sopenharmony_ci if (sr & SR_TEF) 32162306a36Sopenharmony_ci err = -EIO; 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ciout: 32562306a36Sopenharmony_ci /* clear flags */ 32662306a36Sopenharmony_ci writel_relaxed(FCR_CTCF | FCR_CTEF, qspi->io_base + QSPI_FCR); 32762306a36Sopenharmony_ci if (!err) 32862306a36Sopenharmony_ci err = stm32_qspi_wait_nobusy(qspi); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci return err; 33162306a36Sopenharmony_ci} 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistatic int stm32_qspi_wait_poll_status(struct stm32_qspi *qspi) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci u32 cr; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci reinit_completion(&qspi->match_completion); 33862306a36Sopenharmony_ci cr = readl_relaxed(qspi->io_base + QSPI_CR); 33962306a36Sopenharmony_ci writel_relaxed(cr | CR_SMIE, qspi->io_base + QSPI_CR); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci if (!wait_for_completion_timeout(&qspi->match_completion, 34262306a36Sopenharmony_ci msecs_to_jiffies(qspi->status_timeout))) 34362306a36Sopenharmony_ci return -ETIMEDOUT; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci writel_relaxed(FCR_CSMF, qspi->io_base + QSPI_FCR); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci return 0; 34862306a36Sopenharmony_ci} 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_cistatic int stm32_qspi_get_mode(u8 buswidth) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci if (buswidth == 4) 35362306a36Sopenharmony_ci return CCR_BUSWIDTH_4; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci return buswidth; 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic int stm32_qspi_send(struct spi_device *spi, const struct spi_mem_op *op) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci struct stm32_qspi *qspi = spi_controller_get_devdata(spi->master); 36162306a36Sopenharmony_ci struct stm32_qspi_flash *flash = &qspi->flash[spi_get_chipselect(spi, 0)]; 36262306a36Sopenharmony_ci u32 ccr, cr; 36362306a36Sopenharmony_ci int timeout, err = 0, err_poll_status = 0; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci dev_dbg(qspi->dev, "cmd:%#x mode:%d.%d.%d.%d addr:%#llx len:%#x\n", 36662306a36Sopenharmony_ci op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth, 36762306a36Sopenharmony_ci op->dummy.buswidth, op->data.buswidth, 36862306a36Sopenharmony_ci op->addr.val, op->data.nbytes); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci cr = readl_relaxed(qspi->io_base + QSPI_CR); 37162306a36Sopenharmony_ci cr &= ~CR_PRESC_MASK & ~CR_FSEL; 37262306a36Sopenharmony_ci cr |= FIELD_PREP(CR_PRESC_MASK, flash->presc); 37362306a36Sopenharmony_ci cr |= FIELD_PREP(CR_FSEL, flash->cs); 37462306a36Sopenharmony_ci writel_relaxed(cr, qspi->io_base + QSPI_CR); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci if (op->data.nbytes) 37762306a36Sopenharmony_ci writel_relaxed(op->data.nbytes - 1, 37862306a36Sopenharmony_ci qspi->io_base + QSPI_DLR); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci ccr = qspi->fmode; 38162306a36Sopenharmony_ci ccr |= FIELD_PREP(CCR_INST_MASK, op->cmd.opcode); 38262306a36Sopenharmony_ci ccr |= FIELD_PREP(CCR_IMODE_MASK, 38362306a36Sopenharmony_ci stm32_qspi_get_mode(op->cmd.buswidth)); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci if (op->addr.nbytes) { 38662306a36Sopenharmony_ci ccr |= FIELD_PREP(CCR_ADMODE_MASK, 38762306a36Sopenharmony_ci stm32_qspi_get_mode(op->addr.buswidth)); 38862306a36Sopenharmony_ci ccr |= FIELD_PREP(CCR_ADSIZE_MASK, op->addr.nbytes - 1); 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci if (op->dummy.nbytes) 39262306a36Sopenharmony_ci ccr |= FIELD_PREP(CCR_DCYC_MASK, 39362306a36Sopenharmony_ci op->dummy.nbytes * 8 / op->dummy.buswidth); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci if (op->data.nbytes) { 39662306a36Sopenharmony_ci ccr |= FIELD_PREP(CCR_DMODE_MASK, 39762306a36Sopenharmony_ci stm32_qspi_get_mode(op->data.buswidth)); 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci writel_relaxed(ccr, qspi->io_base + QSPI_CCR); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci if (op->addr.nbytes && qspi->fmode != CCR_FMODE_MM) 40362306a36Sopenharmony_ci writel_relaxed(op->addr.val, qspi->io_base + QSPI_AR); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci if (qspi->fmode == CCR_FMODE_APM) 40662306a36Sopenharmony_ci err_poll_status = stm32_qspi_wait_poll_status(qspi); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci err = stm32_qspi_tx(qspi, op); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci /* 41162306a36Sopenharmony_ci * Abort in: 41262306a36Sopenharmony_ci * -error case 41362306a36Sopenharmony_ci * -read memory map: prefetching must be stopped if we read the last 41462306a36Sopenharmony_ci * byte of device (device size - fifo size). like device size is not 41562306a36Sopenharmony_ci * knows, the prefetching is always stop. 41662306a36Sopenharmony_ci */ 41762306a36Sopenharmony_ci if (err || err_poll_status || qspi->fmode == CCR_FMODE_MM) 41862306a36Sopenharmony_ci goto abort; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci /* wait end of tx in indirect mode */ 42162306a36Sopenharmony_ci err = stm32_qspi_wait_cmd(qspi); 42262306a36Sopenharmony_ci if (err) 42362306a36Sopenharmony_ci goto abort; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci return 0; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ciabort: 42862306a36Sopenharmony_ci cr = readl_relaxed(qspi->io_base + QSPI_CR) | CR_ABORT; 42962306a36Sopenharmony_ci writel_relaxed(cr, qspi->io_base + QSPI_CR); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci /* wait clear of abort bit by hw */ 43262306a36Sopenharmony_ci timeout = readl_relaxed_poll_timeout_atomic(qspi->io_base + QSPI_CR, 43362306a36Sopenharmony_ci cr, !(cr & CR_ABORT), 1, 43462306a36Sopenharmony_ci STM32_ABT_TIMEOUT_US); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci writel_relaxed(FCR_CTCF | FCR_CSMF, qspi->io_base + QSPI_FCR); 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci if (err || err_poll_status || timeout) 43962306a36Sopenharmony_ci dev_err(qspi->dev, "%s err:%d err_poll_status:%d abort timeout:%d\n", 44062306a36Sopenharmony_ci __func__, err, err_poll_status, timeout); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci return err; 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_cistatic int stm32_qspi_poll_status(struct spi_mem *mem, const struct spi_mem_op *op, 44662306a36Sopenharmony_ci u16 mask, u16 match, 44762306a36Sopenharmony_ci unsigned long initial_delay_us, 44862306a36Sopenharmony_ci unsigned long polling_rate_us, 44962306a36Sopenharmony_ci unsigned long timeout_ms) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->master); 45262306a36Sopenharmony_ci int ret; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci if (!spi_mem_supports_op(mem, op)) 45562306a36Sopenharmony_ci return -EOPNOTSUPP; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(qspi->dev); 45862306a36Sopenharmony_ci if (ret < 0) 45962306a36Sopenharmony_ci return ret; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci mutex_lock(&qspi->lock); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci writel_relaxed(mask, qspi->io_base + QSPI_PSMKR); 46462306a36Sopenharmony_ci writel_relaxed(match, qspi->io_base + QSPI_PSMAR); 46562306a36Sopenharmony_ci qspi->fmode = CCR_FMODE_APM; 46662306a36Sopenharmony_ci qspi->status_timeout = timeout_ms; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci ret = stm32_qspi_send(mem->spi, op); 46962306a36Sopenharmony_ci mutex_unlock(&qspi->lock); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci pm_runtime_mark_last_busy(qspi->dev); 47262306a36Sopenharmony_ci pm_runtime_put_autosuspend(qspi->dev); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci return ret; 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_cistatic int stm32_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) 47862306a36Sopenharmony_ci{ 47962306a36Sopenharmony_ci struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->master); 48062306a36Sopenharmony_ci int ret; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(qspi->dev); 48362306a36Sopenharmony_ci if (ret < 0) 48462306a36Sopenharmony_ci return ret; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci mutex_lock(&qspi->lock); 48762306a36Sopenharmony_ci if (op->data.dir == SPI_MEM_DATA_IN && op->data.nbytes) 48862306a36Sopenharmony_ci qspi->fmode = CCR_FMODE_INDR; 48962306a36Sopenharmony_ci else 49062306a36Sopenharmony_ci qspi->fmode = CCR_FMODE_INDW; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci ret = stm32_qspi_send(mem->spi, op); 49362306a36Sopenharmony_ci mutex_unlock(&qspi->lock); 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci pm_runtime_mark_last_busy(qspi->dev); 49662306a36Sopenharmony_ci pm_runtime_put_autosuspend(qspi->dev); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci return ret; 49962306a36Sopenharmony_ci} 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_cistatic int stm32_qspi_dirmap_create(struct spi_mem_dirmap_desc *desc) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci struct stm32_qspi *qspi = spi_controller_get_devdata(desc->mem->spi->master); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_OUT) 50662306a36Sopenharmony_ci return -EOPNOTSUPP; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci /* should never happen, as mm_base == null is an error probe exit condition */ 50962306a36Sopenharmony_ci if (!qspi->mm_base && desc->info.op_tmpl.data.dir == SPI_MEM_DATA_IN) 51062306a36Sopenharmony_ci return -EOPNOTSUPP; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci if (!qspi->mm_size) 51362306a36Sopenharmony_ci return -EOPNOTSUPP; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci return 0; 51662306a36Sopenharmony_ci} 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_cistatic ssize_t stm32_qspi_dirmap_read(struct spi_mem_dirmap_desc *desc, 51962306a36Sopenharmony_ci u64 offs, size_t len, void *buf) 52062306a36Sopenharmony_ci{ 52162306a36Sopenharmony_ci struct stm32_qspi *qspi = spi_controller_get_devdata(desc->mem->spi->master); 52262306a36Sopenharmony_ci struct spi_mem_op op; 52362306a36Sopenharmony_ci u32 addr_max; 52462306a36Sopenharmony_ci int ret; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(qspi->dev); 52762306a36Sopenharmony_ci if (ret < 0) 52862306a36Sopenharmony_ci return ret; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci mutex_lock(&qspi->lock); 53162306a36Sopenharmony_ci /* make a local copy of desc op_tmpl and complete dirmap rdesc 53262306a36Sopenharmony_ci * spi_mem_op template with offs, len and *buf in order to get 53362306a36Sopenharmony_ci * all needed transfer information into struct spi_mem_op 53462306a36Sopenharmony_ci */ 53562306a36Sopenharmony_ci memcpy(&op, &desc->info.op_tmpl, sizeof(struct spi_mem_op)); 53662306a36Sopenharmony_ci dev_dbg(qspi->dev, "%s len = 0x%zx offs = 0x%llx buf = 0x%p\n", __func__, len, offs, buf); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci op.data.nbytes = len; 53962306a36Sopenharmony_ci op.addr.val = desc->info.offset + offs; 54062306a36Sopenharmony_ci op.data.buf.in = buf; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci addr_max = op.addr.val + op.data.nbytes + 1; 54362306a36Sopenharmony_ci if (addr_max < qspi->mm_size && op.addr.buswidth) 54462306a36Sopenharmony_ci qspi->fmode = CCR_FMODE_MM; 54562306a36Sopenharmony_ci else 54662306a36Sopenharmony_ci qspi->fmode = CCR_FMODE_INDR; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci ret = stm32_qspi_send(desc->mem->spi, &op); 54962306a36Sopenharmony_ci mutex_unlock(&qspi->lock); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci pm_runtime_mark_last_busy(qspi->dev); 55262306a36Sopenharmony_ci pm_runtime_put_autosuspend(qspi->dev); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci return ret ?: len; 55562306a36Sopenharmony_ci} 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_cistatic int stm32_qspi_transfer_one_message(struct spi_controller *ctrl, 55862306a36Sopenharmony_ci struct spi_message *msg) 55962306a36Sopenharmony_ci{ 56062306a36Sopenharmony_ci struct stm32_qspi *qspi = spi_controller_get_devdata(ctrl); 56162306a36Sopenharmony_ci struct spi_transfer *transfer; 56262306a36Sopenharmony_ci struct spi_device *spi = msg->spi; 56362306a36Sopenharmony_ci struct spi_mem_op op; 56462306a36Sopenharmony_ci int ret = 0; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci if (!spi_get_csgpiod(spi, 0)) 56762306a36Sopenharmony_ci return -EOPNOTSUPP; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(qspi->dev); 57062306a36Sopenharmony_ci if (ret < 0) 57162306a36Sopenharmony_ci return ret; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci mutex_lock(&qspi->lock); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci gpiod_set_value_cansleep(spi_get_csgpiod(spi, 0), true); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci list_for_each_entry(transfer, &msg->transfers, transfer_list) { 57862306a36Sopenharmony_ci u8 dummy_bytes = 0; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci memset(&op, 0, sizeof(op)); 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci dev_dbg(qspi->dev, "tx_buf:%p tx_nbits:%d rx_buf:%p rx_nbits:%d len:%d dummy_data:%d\n", 58362306a36Sopenharmony_ci transfer->tx_buf, transfer->tx_nbits, 58462306a36Sopenharmony_ci transfer->rx_buf, transfer->rx_nbits, 58562306a36Sopenharmony_ci transfer->len, transfer->dummy_data); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci /* 58862306a36Sopenharmony_ci * QSPI hardware supports dummy bytes transfer. 58962306a36Sopenharmony_ci * If current transfer is dummy byte, merge it with the next 59062306a36Sopenharmony_ci * transfer in order to take into account QSPI block constraint 59162306a36Sopenharmony_ci */ 59262306a36Sopenharmony_ci if (transfer->dummy_data) { 59362306a36Sopenharmony_ci op.dummy.buswidth = transfer->tx_nbits; 59462306a36Sopenharmony_ci op.dummy.nbytes = transfer->len; 59562306a36Sopenharmony_ci dummy_bytes = transfer->len; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci /* if happens, means that message is not correctly built */ 59862306a36Sopenharmony_ci if (list_is_last(&transfer->transfer_list, &msg->transfers)) { 59962306a36Sopenharmony_ci ret = -EINVAL; 60062306a36Sopenharmony_ci goto end_of_transfer; 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci transfer = list_next_entry(transfer, transfer_list); 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci op.data.nbytes = transfer->len; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci if (transfer->rx_buf) { 60962306a36Sopenharmony_ci qspi->fmode = CCR_FMODE_INDR; 61062306a36Sopenharmony_ci op.data.buswidth = transfer->rx_nbits; 61162306a36Sopenharmony_ci op.data.dir = SPI_MEM_DATA_IN; 61262306a36Sopenharmony_ci op.data.buf.in = transfer->rx_buf; 61362306a36Sopenharmony_ci } else { 61462306a36Sopenharmony_ci qspi->fmode = CCR_FMODE_INDW; 61562306a36Sopenharmony_ci op.data.buswidth = transfer->tx_nbits; 61662306a36Sopenharmony_ci op.data.dir = SPI_MEM_DATA_OUT; 61762306a36Sopenharmony_ci op.data.buf.out = transfer->tx_buf; 61862306a36Sopenharmony_ci } 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci ret = stm32_qspi_send(spi, &op); 62162306a36Sopenharmony_ci if (ret) 62262306a36Sopenharmony_ci goto end_of_transfer; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci msg->actual_length += transfer->len + dummy_bytes; 62562306a36Sopenharmony_ci } 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ciend_of_transfer: 62862306a36Sopenharmony_ci gpiod_set_value_cansleep(spi_get_csgpiod(spi, 0), false); 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci mutex_unlock(&qspi->lock); 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci msg->status = ret; 63362306a36Sopenharmony_ci spi_finalize_current_message(ctrl); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci pm_runtime_mark_last_busy(qspi->dev); 63662306a36Sopenharmony_ci pm_runtime_put_autosuspend(qspi->dev); 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci return ret; 63962306a36Sopenharmony_ci} 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_cistatic int stm32_qspi_setup(struct spi_device *spi) 64262306a36Sopenharmony_ci{ 64362306a36Sopenharmony_ci struct spi_controller *ctrl = spi->master; 64462306a36Sopenharmony_ci struct stm32_qspi *qspi = spi_controller_get_devdata(ctrl); 64562306a36Sopenharmony_ci struct stm32_qspi_flash *flash; 64662306a36Sopenharmony_ci u32 presc, mode; 64762306a36Sopenharmony_ci int ret; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci if (ctrl->busy) 65062306a36Sopenharmony_ci return -EBUSY; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci if (!spi->max_speed_hz) 65362306a36Sopenharmony_ci return -EINVAL; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci mode = spi->mode & (SPI_TX_OCTAL | SPI_RX_OCTAL); 65662306a36Sopenharmony_ci if ((mode == SPI_TX_OCTAL || mode == SPI_RX_OCTAL) || 65762306a36Sopenharmony_ci ((mode == (SPI_TX_OCTAL | SPI_RX_OCTAL)) && 65862306a36Sopenharmony_ci gpiod_count(qspi->dev, "cs") == -ENOENT)) { 65962306a36Sopenharmony_ci dev_err(qspi->dev, "spi-rx-bus-width\\/spi-tx-bus-width\\/cs-gpios\n"); 66062306a36Sopenharmony_ci dev_err(qspi->dev, "configuration not supported\n"); 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci return -EINVAL; 66362306a36Sopenharmony_ci } 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(qspi->dev); 66662306a36Sopenharmony_ci if (ret < 0) 66762306a36Sopenharmony_ci return ret; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci presc = DIV_ROUND_UP(qspi->clk_rate, spi->max_speed_hz) - 1; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci flash = &qspi->flash[spi_get_chipselect(spi, 0)]; 67262306a36Sopenharmony_ci flash->cs = spi_get_chipselect(spi, 0); 67362306a36Sopenharmony_ci flash->presc = presc; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci mutex_lock(&qspi->lock); 67662306a36Sopenharmony_ci qspi->cr_reg = CR_APMS | 3 << CR_FTHRES_SHIFT | CR_SSHIFT | CR_EN; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci /* 67962306a36Sopenharmony_ci * Dual flash mode is only enable in case SPI_TX_OCTAL and SPI_TX_OCTAL 68062306a36Sopenharmony_ci * are both set in spi->mode and "cs-gpios" properties is found in DT 68162306a36Sopenharmony_ci */ 68262306a36Sopenharmony_ci if (mode == (SPI_TX_OCTAL | SPI_RX_OCTAL)) { 68362306a36Sopenharmony_ci qspi->cr_reg |= CR_DFM; 68462306a36Sopenharmony_ci dev_dbg(qspi->dev, "Dual flash mode enable"); 68562306a36Sopenharmony_ci } 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci writel_relaxed(qspi->cr_reg, qspi->io_base + QSPI_CR); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci /* set dcr fsize to max address */ 69062306a36Sopenharmony_ci qspi->dcr_reg = DCR_FSIZE_MASK; 69162306a36Sopenharmony_ci writel_relaxed(qspi->dcr_reg, qspi->io_base + QSPI_DCR); 69262306a36Sopenharmony_ci mutex_unlock(&qspi->lock); 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci pm_runtime_mark_last_busy(qspi->dev); 69562306a36Sopenharmony_ci pm_runtime_put_autosuspend(qspi->dev); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci return 0; 69862306a36Sopenharmony_ci} 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_cistatic int stm32_qspi_dma_setup(struct stm32_qspi *qspi) 70162306a36Sopenharmony_ci{ 70262306a36Sopenharmony_ci struct dma_slave_config dma_cfg; 70362306a36Sopenharmony_ci struct device *dev = qspi->dev; 70462306a36Sopenharmony_ci int ret = 0; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci memset(&dma_cfg, 0, sizeof(dma_cfg)); 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci dma_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; 70962306a36Sopenharmony_ci dma_cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; 71062306a36Sopenharmony_ci dma_cfg.src_addr = qspi->phys_base + QSPI_DR; 71162306a36Sopenharmony_ci dma_cfg.dst_addr = qspi->phys_base + QSPI_DR; 71262306a36Sopenharmony_ci dma_cfg.src_maxburst = 4; 71362306a36Sopenharmony_ci dma_cfg.dst_maxburst = 4; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci qspi->dma_chrx = dma_request_chan(dev, "rx"); 71662306a36Sopenharmony_ci if (IS_ERR(qspi->dma_chrx)) { 71762306a36Sopenharmony_ci ret = PTR_ERR(qspi->dma_chrx); 71862306a36Sopenharmony_ci qspi->dma_chrx = NULL; 71962306a36Sopenharmony_ci if (ret == -EPROBE_DEFER) 72062306a36Sopenharmony_ci goto out; 72162306a36Sopenharmony_ci } else { 72262306a36Sopenharmony_ci if (dmaengine_slave_config(qspi->dma_chrx, &dma_cfg)) { 72362306a36Sopenharmony_ci dev_err(dev, "dma rx config failed\n"); 72462306a36Sopenharmony_ci dma_release_channel(qspi->dma_chrx); 72562306a36Sopenharmony_ci qspi->dma_chrx = NULL; 72662306a36Sopenharmony_ci } 72762306a36Sopenharmony_ci } 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci qspi->dma_chtx = dma_request_chan(dev, "tx"); 73062306a36Sopenharmony_ci if (IS_ERR(qspi->dma_chtx)) { 73162306a36Sopenharmony_ci ret = PTR_ERR(qspi->dma_chtx); 73262306a36Sopenharmony_ci qspi->dma_chtx = NULL; 73362306a36Sopenharmony_ci } else { 73462306a36Sopenharmony_ci if (dmaengine_slave_config(qspi->dma_chtx, &dma_cfg)) { 73562306a36Sopenharmony_ci dev_err(dev, "dma tx config failed\n"); 73662306a36Sopenharmony_ci dma_release_channel(qspi->dma_chtx); 73762306a36Sopenharmony_ci qspi->dma_chtx = NULL; 73862306a36Sopenharmony_ci } 73962306a36Sopenharmony_ci } 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ciout: 74262306a36Sopenharmony_ci init_completion(&qspi->dma_completion); 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci if (ret != -EPROBE_DEFER) 74562306a36Sopenharmony_ci ret = 0; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci return ret; 74862306a36Sopenharmony_ci} 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_cistatic void stm32_qspi_dma_free(struct stm32_qspi *qspi) 75162306a36Sopenharmony_ci{ 75262306a36Sopenharmony_ci if (qspi->dma_chtx) 75362306a36Sopenharmony_ci dma_release_channel(qspi->dma_chtx); 75462306a36Sopenharmony_ci if (qspi->dma_chrx) 75562306a36Sopenharmony_ci dma_release_channel(qspi->dma_chrx); 75662306a36Sopenharmony_ci} 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci/* 75962306a36Sopenharmony_ci * no special host constraint, so use default spi_mem_default_supports_op 76062306a36Sopenharmony_ci * to check supported mode. 76162306a36Sopenharmony_ci */ 76262306a36Sopenharmony_cistatic const struct spi_controller_mem_ops stm32_qspi_mem_ops = { 76362306a36Sopenharmony_ci .exec_op = stm32_qspi_exec_op, 76462306a36Sopenharmony_ci .dirmap_create = stm32_qspi_dirmap_create, 76562306a36Sopenharmony_ci .dirmap_read = stm32_qspi_dirmap_read, 76662306a36Sopenharmony_ci .poll_status = stm32_qspi_poll_status, 76762306a36Sopenharmony_ci}; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_cistatic int stm32_qspi_probe(struct platform_device *pdev) 77062306a36Sopenharmony_ci{ 77162306a36Sopenharmony_ci struct device *dev = &pdev->dev; 77262306a36Sopenharmony_ci struct spi_controller *ctrl; 77362306a36Sopenharmony_ci struct reset_control *rstc; 77462306a36Sopenharmony_ci struct stm32_qspi *qspi; 77562306a36Sopenharmony_ci struct resource *res; 77662306a36Sopenharmony_ci int ret, irq; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci ctrl = devm_spi_alloc_master(dev, sizeof(*qspi)); 77962306a36Sopenharmony_ci if (!ctrl) 78062306a36Sopenharmony_ci return -ENOMEM; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci qspi = spi_controller_get_devdata(ctrl); 78362306a36Sopenharmony_ci qspi->ctrl = ctrl; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi"); 78662306a36Sopenharmony_ci qspi->io_base = devm_ioremap_resource(dev, res); 78762306a36Sopenharmony_ci if (IS_ERR(qspi->io_base)) 78862306a36Sopenharmony_ci return PTR_ERR(qspi->io_base); 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci qspi->phys_base = res->start; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_mm"); 79362306a36Sopenharmony_ci qspi->mm_base = devm_ioremap_resource(dev, res); 79462306a36Sopenharmony_ci if (IS_ERR(qspi->mm_base)) 79562306a36Sopenharmony_ci return PTR_ERR(qspi->mm_base); 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci qspi->mm_size = resource_size(res); 79862306a36Sopenharmony_ci if (qspi->mm_size > STM32_QSPI_MAX_MMAP_SZ) 79962306a36Sopenharmony_ci return -EINVAL; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci irq = platform_get_irq(pdev, 0); 80262306a36Sopenharmony_ci if (irq < 0) 80362306a36Sopenharmony_ci return irq; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci ret = devm_request_irq(dev, irq, stm32_qspi_irq, 0, 80662306a36Sopenharmony_ci dev_name(dev), qspi); 80762306a36Sopenharmony_ci if (ret) { 80862306a36Sopenharmony_ci dev_err(dev, "failed to request irq\n"); 80962306a36Sopenharmony_ci return ret; 81062306a36Sopenharmony_ci } 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci init_completion(&qspi->data_completion); 81362306a36Sopenharmony_ci init_completion(&qspi->match_completion); 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci qspi->clk = devm_clk_get(dev, NULL); 81662306a36Sopenharmony_ci if (IS_ERR(qspi->clk)) 81762306a36Sopenharmony_ci return PTR_ERR(qspi->clk); 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci qspi->clk_rate = clk_get_rate(qspi->clk); 82062306a36Sopenharmony_ci if (!qspi->clk_rate) 82162306a36Sopenharmony_ci return -EINVAL; 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci ret = clk_prepare_enable(qspi->clk); 82462306a36Sopenharmony_ci if (ret) { 82562306a36Sopenharmony_ci dev_err(dev, "can not enable the clock\n"); 82662306a36Sopenharmony_ci return ret; 82762306a36Sopenharmony_ci } 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci rstc = devm_reset_control_get_exclusive(dev, NULL); 83062306a36Sopenharmony_ci if (IS_ERR(rstc)) { 83162306a36Sopenharmony_ci ret = PTR_ERR(rstc); 83262306a36Sopenharmony_ci if (ret == -EPROBE_DEFER) 83362306a36Sopenharmony_ci goto err_clk_disable; 83462306a36Sopenharmony_ci } else { 83562306a36Sopenharmony_ci reset_control_assert(rstc); 83662306a36Sopenharmony_ci udelay(2); 83762306a36Sopenharmony_ci reset_control_deassert(rstc); 83862306a36Sopenharmony_ci } 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci qspi->dev = dev; 84162306a36Sopenharmony_ci platform_set_drvdata(pdev, qspi); 84262306a36Sopenharmony_ci ret = stm32_qspi_dma_setup(qspi); 84362306a36Sopenharmony_ci if (ret) 84462306a36Sopenharmony_ci goto err_dma_free; 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci mutex_init(&qspi->lock); 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci ctrl->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD | SPI_TX_OCTAL 84962306a36Sopenharmony_ci | SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_OCTAL; 85062306a36Sopenharmony_ci ctrl->setup = stm32_qspi_setup; 85162306a36Sopenharmony_ci ctrl->bus_num = -1; 85262306a36Sopenharmony_ci ctrl->mem_ops = &stm32_qspi_mem_ops; 85362306a36Sopenharmony_ci ctrl->use_gpio_descriptors = true; 85462306a36Sopenharmony_ci ctrl->transfer_one_message = stm32_qspi_transfer_one_message; 85562306a36Sopenharmony_ci ctrl->num_chipselect = STM32_QSPI_MAX_NORCHIP; 85662306a36Sopenharmony_ci ctrl->dev.of_node = dev->of_node; 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci pm_runtime_set_autosuspend_delay(dev, STM32_AUTOSUSPEND_DELAY); 85962306a36Sopenharmony_ci pm_runtime_use_autosuspend(dev); 86062306a36Sopenharmony_ci pm_runtime_set_active(dev); 86162306a36Sopenharmony_ci pm_runtime_enable(dev); 86262306a36Sopenharmony_ci pm_runtime_get_noresume(dev); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci ret = spi_register_master(ctrl); 86562306a36Sopenharmony_ci if (ret) 86662306a36Sopenharmony_ci goto err_pm_runtime_free; 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci pm_runtime_mark_last_busy(dev); 86962306a36Sopenharmony_ci pm_runtime_put_autosuspend(dev); 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci return 0; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_cierr_pm_runtime_free: 87462306a36Sopenharmony_ci pm_runtime_get_sync(qspi->dev); 87562306a36Sopenharmony_ci /* disable qspi */ 87662306a36Sopenharmony_ci writel_relaxed(0, qspi->io_base + QSPI_CR); 87762306a36Sopenharmony_ci mutex_destroy(&qspi->lock); 87862306a36Sopenharmony_ci pm_runtime_put_noidle(qspi->dev); 87962306a36Sopenharmony_ci pm_runtime_disable(qspi->dev); 88062306a36Sopenharmony_ci pm_runtime_set_suspended(qspi->dev); 88162306a36Sopenharmony_ci pm_runtime_dont_use_autosuspend(qspi->dev); 88262306a36Sopenharmony_cierr_dma_free: 88362306a36Sopenharmony_ci stm32_qspi_dma_free(qspi); 88462306a36Sopenharmony_cierr_clk_disable: 88562306a36Sopenharmony_ci clk_disable_unprepare(qspi->clk); 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci return ret; 88862306a36Sopenharmony_ci} 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_cistatic void stm32_qspi_remove(struct platform_device *pdev) 89162306a36Sopenharmony_ci{ 89262306a36Sopenharmony_ci struct stm32_qspi *qspi = platform_get_drvdata(pdev); 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci pm_runtime_get_sync(qspi->dev); 89562306a36Sopenharmony_ci spi_unregister_master(qspi->ctrl); 89662306a36Sopenharmony_ci /* disable qspi */ 89762306a36Sopenharmony_ci writel_relaxed(0, qspi->io_base + QSPI_CR); 89862306a36Sopenharmony_ci stm32_qspi_dma_free(qspi); 89962306a36Sopenharmony_ci mutex_destroy(&qspi->lock); 90062306a36Sopenharmony_ci pm_runtime_put_noidle(qspi->dev); 90162306a36Sopenharmony_ci pm_runtime_disable(qspi->dev); 90262306a36Sopenharmony_ci pm_runtime_set_suspended(qspi->dev); 90362306a36Sopenharmony_ci pm_runtime_dont_use_autosuspend(qspi->dev); 90462306a36Sopenharmony_ci clk_disable_unprepare(qspi->clk); 90562306a36Sopenharmony_ci} 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_cistatic int __maybe_unused stm32_qspi_runtime_suspend(struct device *dev) 90862306a36Sopenharmony_ci{ 90962306a36Sopenharmony_ci struct stm32_qspi *qspi = dev_get_drvdata(dev); 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci clk_disable_unprepare(qspi->clk); 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci return 0; 91462306a36Sopenharmony_ci} 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_cistatic int __maybe_unused stm32_qspi_runtime_resume(struct device *dev) 91762306a36Sopenharmony_ci{ 91862306a36Sopenharmony_ci struct stm32_qspi *qspi = dev_get_drvdata(dev); 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci return clk_prepare_enable(qspi->clk); 92162306a36Sopenharmony_ci} 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_cistatic int __maybe_unused stm32_qspi_suspend(struct device *dev) 92462306a36Sopenharmony_ci{ 92562306a36Sopenharmony_ci pinctrl_pm_select_sleep_state(dev); 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci return pm_runtime_force_suspend(dev); 92862306a36Sopenharmony_ci} 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_cistatic int __maybe_unused stm32_qspi_resume(struct device *dev) 93162306a36Sopenharmony_ci{ 93262306a36Sopenharmony_ci struct stm32_qspi *qspi = dev_get_drvdata(dev); 93362306a36Sopenharmony_ci int ret; 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci ret = pm_runtime_force_resume(dev); 93662306a36Sopenharmony_ci if (ret < 0) 93762306a36Sopenharmony_ci return ret; 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci pinctrl_pm_select_default_state(dev); 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(dev); 94262306a36Sopenharmony_ci if (ret < 0) 94362306a36Sopenharmony_ci return ret; 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci writel_relaxed(qspi->cr_reg, qspi->io_base + QSPI_CR); 94662306a36Sopenharmony_ci writel_relaxed(qspi->dcr_reg, qspi->io_base + QSPI_DCR); 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci pm_runtime_mark_last_busy(dev); 94962306a36Sopenharmony_ci pm_runtime_put_autosuspend(dev); 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci return 0; 95262306a36Sopenharmony_ci} 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_cistatic const struct dev_pm_ops stm32_qspi_pm_ops = { 95562306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(stm32_qspi_runtime_suspend, 95662306a36Sopenharmony_ci stm32_qspi_runtime_resume, NULL) 95762306a36Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(stm32_qspi_suspend, stm32_qspi_resume) 95862306a36Sopenharmony_ci}; 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_cistatic const struct of_device_id stm32_qspi_match[] = { 96162306a36Sopenharmony_ci {.compatible = "st,stm32f469-qspi"}, 96262306a36Sopenharmony_ci {} 96362306a36Sopenharmony_ci}; 96462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, stm32_qspi_match); 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_cistatic struct platform_driver stm32_qspi_driver = { 96762306a36Sopenharmony_ci .probe = stm32_qspi_probe, 96862306a36Sopenharmony_ci .remove_new = stm32_qspi_remove, 96962306a36Sopenharmony_ci .driver = { 97062306a36Sopenharmony_ci .name = "stm32-qspi", 97162306a36Sopenharmony_ci .of_match_table = stm32_qspi_match, 97262306a36Sopenharmony_ci .pm = &stm32_qspi_pm_ops, 97362306a36Sopenharmony_ci }, 97462306a36Sopenharmony_ci}; 97562306a36Sopenharmony_cimodule_platform_driver(stm32_qspi_driver); 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ciMODULE_AUTHOR("Ludovic Barre <ludovic.barre@st.com>"); 97862306a36Sopenharmony_ciMODULE_DESCRIPTION("STMicroelectronics STM32 quad spi driver"); 97962306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 980