// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) STMicroelectronics 2025 - All Rights Reserved
*/
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_reserved_mem.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <linux/sizes.h>
#include <linux/spi/spi-mem.h>
#include <linux/types.h>
#define OSPI_CR 0x00
#define CR_EN BIT(0)
#define CR_ABORT BIT(1)
#define CR_DMAEN BIT(2)
#define CR_FTHRES_SHIFT 8
#define CR_TEIE BIT(16)
#define CR_TCIE BIT(17)
#define CR_SMIE BIT(19)
#define CR_APMS BIT(22)
#define CR_CSSEL BIT(24)
#define CR_FMODE_MASK GENMASK(29, 28)
#define CR_FMODE_INDW (0U)
#define CR_FMODE_INDR (1U)
#define CR_FMODE_APM (2U)
#define CR_FMODE_MM (3U)
#define OSPI_DCR1 0x08
#define DCR1_DLYBYP BIT(3)
#define DCR1_DEVSIZE_MASK GENMASK(20, 16)
#define DCR1_MTYP_MASK GENMASK(26, 24)
#define DCR1_MTYP_MX_MODE 1
#define DCR1_MTYP_HP_MEMMODE 4
#define OSPI_DCR2 0x0c
#define DCR2_PRESC_MASK GENMASK(7, 0)
#define OSPI_SR 0x20
#define SR_TEF BIT(0)
#define SR_TCF BIT(1)
#define SR_FTF BIT(2)
#define SR_SMF BIT(3)
#define SR_BUSY BIT(5)
#define OSPI_FCR 0x24
#define FCR_CTEF BIT(0)
#define FCR_CTCF BIT(1)
#define FCR_CSMF BIT(3)
#define OSPI_DLR 0x40
#define OSPI_AR 0x48
#define OSPI_DR 0x50
#define OSPI_PSMKR 0x80
#define OSPI_PSMAR 0x88
#define OSPI_CCR 0x100
#define CCR_IMODE_MASK GENMASK(2, 0)
#define CCR_IDTR BIT(3)
#define CCR_ISIZE_MASK GENMASK(5, 4)
#define CCR_ADMODE_MASK GENMASK(10, 8)
#define CCR_ADMODE_8LINES 4
#define CCR_ADDTR BIT(11)
#define CCR_ADSIZE_MASK GENMASK(13, 12)
#define CCR_ADSIZE_32BITS 3
#define CCR_DMODE_MASK GENMASK(26, 24)
#define CCR_DMODE_8LINES 4
#define CCR_DQSE BIT(29)
#define CCR_DDTR BIT(27)
#define CCR_BUSWIDTH_0 0x0
#define CCR_BUSWIDTH_1 0x1
#define CCR_BUSWIDTH_2 0x2
#define CCR_BUSWIDTH_4 0x3
#define CCR_BUSWIDTH_8 0x4
#define OSPI_TCR 0x108
#define TCR_DCYC_MASK GENMASK(4, 0)
#define TCR_DHQC BIT(28)
#define TCR_SSHIFT BIT(30)
#define OSPI_IR 0x110
#define STM32_OSPI_MAX_MMAP_SZ SZ_256M
#define STM32_OSPI_MAX_NORCHIP 2
#define STM32_FIFO_TIMEOUT_US 30000
#define STM32_ABT_TIMEOUT_US 100000
#define STM32_COMP_TIMEOUT_MS 5000
#define STM32_BUSY_TIMEOUT_US 100000
#define STM32_AUTOSUSPEND_DELAY -1
struct stm32_ospi {
struct device *dev;
struct spi_controller *ctrl;
struct clk *clk;
struct reset_control *rstc;
struct completion data_completion;
struct completion match_completion;
struct dma_chan *dma_chtx;
struct dma_chan *dma_chrx;
struct completion dma_completion;
void __iomem *regs_base;
void __iomem *mm_base;
phys_addr_t regs_phys_base;
resource_size_t mm_size;
u32 clk_rate;
u32 fmode;
u32 cr_reg;
u32 dcr_reg;
u32 flash_presc[STM32_OSPI_MAX_NORCHIP];
int irq;
unsigned long status_timeout;
/*
* To protect device configuration, could be different between
* 2 flash access
*/
struct mutex lock;
};
static void stm32_ospi_read_fifo(u8 *val, void __iomem *addr)
{
*val = readb_relaxed(addr);
}
static void stm32_ospi_write_fifo(u8 *val, void __iomem *addr)
{
writeb_relaxed(*val, addr);
}
static int stm32_ospi_abort(struct stm32_ospi *ospi)
{
void __iomem *regs_base = ospi->regs_base;
u32 cr;
int timeout;
cr = readl_relaxed(regs_base + OSPI_CR) | CR_ABORT;
writel_relaxed(cr, regs_base + OSPI_CR);
/* wait clear of abort bit by hw */
timeout = readl_relaxed_poll_timeout_atomic(regs_base + OSPI_CR,
cr, !(cr & CR_ABORT), 1,
STM32_ABT_TIMEOUT_US);
if (timeout)
dev_err(ospi->dev, "%s abort timeout:%d\n", __func__, timeout);
return timeout;
}
static int stm32_ospi_poll(struct stm32_ospi *ospi, u8 *buf, u32 len, bool read)
{
void __iomem *regs_base = ospi->regs_base;
void (*fifo)(u8 *val, void __iomem *addr);
u32 sr;
int ret;
if (read)
fifo = stm32_ospi_read_fifo;
else
fifo = stm32_ospi_write_fifo;
while (len--) {
ret = readl_relaxed_poll_timeout_atomic(regs_base + OSPI_SR,
sr, sr & SR_FTF, 1,
STM32_FIFO_TIMEOUT_US);
if (ret) {
dev_err(ospi->dev, "fifo timeout (len:%d stat:%#x)\n",
len, sr);
return ret;
}
fifo(buf++, regs_base + OSPI_DR);
}
return 0;
}
static int stm32_ospi_wait_nobusy(struct stm32_ospi *ospi)
{
u32 sr;
return readl_relaxed_poll_timeout_atomic(ospi->regs_base + OSPI_SR,
sr, !(sr & SR_BUSY), 1,
STM32_BUSY_TIMEOUT_US);
}
static int stm32_ospi_wait_cmd(struct stm32_ospi *ospi)
{
void __iomem *regs_base = ospi->regs_base;
u32 cr, sr;
int err = 0;
if ((readl_relaxed(regs_base + OSPI_SR) & SR_TCF) ||
ospi->fmode == CR_FMODE_APM)
goto out;
reinit_completion(&ospi->data_completion);
cr = readl_relaxed(regs_base + OSPI_CR);
writel_relaxed(cr | CR_TCIE | CR_TEIE, regs_base + OSPI_CR);
if (!wait_for_completion_timeout(&ospi->data_completion,
msecs_to_jiffies(STM32_COMP_TIMEOUT_MS)))
err = -ETIMEDOUT;
sr = readl_relaxed(regs_base + OSPI_SR);
if (