linux/drivers/spi/spi-nxp-fspi.c

// SPDX-License-Identifier: GPL-2.0+

/*
 * NXP FlexSPI(FSPI) controller driver.
 *
 * Copyright 2019-2020 NXP
 * Copyright 2020 Puresoftware Ltd.
 *
 * FlexSPI is a flexsible SPI host controller which supports two SPI
 * channels and up to 4 external devices. Each channel supports
 * Single/Dual/Quad/Octal mode data transfer (1/2/4/8 bidirectional
 * data lines).
 *
 * FlexSPI controller is driven by the LUT(Look-up Table) registers
 * LUT registers are a look-up-table for sequences of instructions.
 * A valid sequence consists of four LUT registers.
 * Maximum 32 LUT sequences can be programmed simultaneously.
 *
 * LUTs are being created at run-time based on the commands passed
 * from the spi-mem framework, thus using single LUT index.
 *
 * Software triggered Flash read/write access by IP Bus.
 *
 * Memory mapped read access by AHB Bus.
 *
 * Based on SPI MEM interface and spi-fsl-qspi.c driver.
 *
 * Author:
 *     Yogesh Narayan Gaur <[email protected]>
 *     Boris Brezillon <[email protected]>
 *     Frieder Schrempf <[email protected]>
 */

#include <linux/acpi.h>
#include <linux/bitops.h>
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_qos.h>
#include <linux/regmap.h>
#include <linux/sizes.h>
#include <linux/sys_soc.h>

#include <linux/mfd/syscon.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi-mem.h>

/*
 * The driver only uses one single LUT entry, that is updated on
 * each call of exec_op(). Index 0 is preset at boot with a basic
 * read operation, so let's use the last entry (31).
 */
#define SEQID_LUT

/* Registers used by the driver */
#define FSPI_MCR0
#define FSPI_MCR0_AHB_TIMEOUT(x)
#define FSPI_MCR0_IP_TIMEOUT(x)
#define FSPI_MCR0_LEARN_EN
#define FSPI_MCR0_SCRFRUN_EN
#define FSPI_MCR0_OCTCOMB_EN
#define FSPI_MCR0_DOZE_EN
#define FSPI_MCR0_HSEN
#define FSPI_MCR0_SERCLKDIV
#define FSPI_MCR0_ATDF_EN
#define FSPI_MCR0_ARDF_EN
#define FSPI_MCR0_RXCLKSRC(x)
#define FSPI_MCR0_END_CFG(x)
#define FSPI_MCR0_MDIS
#define FSPI_MCR0_SWRST

#define FSPI_MCR1
#define FSPI_MCR1_SEQ_TIMEOUT(x)
#define FSPI_MCR1_AHB_TIMEOUT(x)

#define FSPI_MCR2
#define FSPI_MCR2_IDLE_WAIT(x)
#define FSPI_MCR2_SAMEDEVICEEN
#define FSPI_MCR2_CLRLRPHS
#define FSPI_MCR2_ABRDATSZ
#define FSPI_MCR2_ABRLEARN
#define FSPI_MCR2_ABR_READ
#define FSPI_MCR2_ABRWRITE
#define FSPI_MCR2_ABRDUMMY
#define FSPI_MCR2_ABR_MODE
#define FSPI_MCR2_ABRCADDR
#define FSPI_MCR2_ABRRADDR
#define FSPI_MCR2_ABR_CMD

#define FSPI_AHBCR
#define FSPI_AHBCR_RDADDROPT
#define FSPI_AHBCR_PREF_EN
#define FSPI_AHBCR_BUFF_EN
#define FSPI_AHBCR_CACH_EN
#define FSPI_AHBCR_CLRTXBUF
#define FSPI_AHBCR_CLRRXBUF
#define FSPI_AHBCR_PAR_EN

#define FSPI_INTEN
#define FSPI_INTEN_SCLKSBWR
#define FSPI_INTEN_SCLKSBRD
#define FSPI_INTEN_DATALRNFL
#define FSPI_INTEN_IPTXWE
#define FSPI_INTEN_IPRXWA
#define FSPI_INTEN_AHBCMDERR
#define FSPI_INTEN_IPCMDERR
#define FSPI_INTEN_AHBCMDGE
#define FSPI_INTEN_IPCMDGE
#define FSPI_INTEN_IPCMDDONE

#define FSPI_INTR
#define FSPI_INTR_SCLKSBWR
#define FSPI_INTR_SCLKSBRD
#define FSPI_INTR_DATALRNFL
#define FSPI_INTR_IPTXWE
#define FSPI_INTR_IPRXWA
#define FSPI_INTR_AHBCMDERR
#define FSPI_INTR_IPCMDERR
#define FSPI_INTR_AHBCMDGE
#define FSPI_INTR_IPCMDGE
#define FSPI_INTR_IPCMDDONE

#define FSPI_LUTKEY
#define FSPI_LUTKEY_VALUE

#define FSPI_LCKCR

#define FSPI_LCKER_LOCK
#define FSPI_LCKER_UNLOCK

#define FSPI_BUFXCR_INVALID_MSTRID
#define FSPI_AHBRX_BUF0CR0
#define FSPI_AHBRX_BUF1CR0
#define FSPI_AHBRX_BUF2CR0
#define FSPI_AHBRX_BUF3CR0
#define FSPI_AHBRX_BUF4CR0
#define FSPI_AHBRX_BUF5CR0
#define FSPI_AHBRX_BUF6CR0
#define FSPI_AHBRX_BUF7CR0
#define FSPI_AHBRXBUF0CR7_PREF

#define FSPI_AHBRX_BUF0CR1
#define FSPI_AHBRX_BUF1CR1
#define FSPI_AHBRX_BUF2CR1
#define FSPI_AHBRX_BUF3CR1
#define FSPI_AHBRX_BUF4CR1
#define FSPI_AHBRX_BUF5CR1
#define FSPI_AHBRX_BUF6CR1
#define FSPI_AHBRX_BUF7CR1

#define FSPI_FLSHA1CR0
#define FSPI_FLSHA2CR0
#define FSPI_FLSHB1CR0
#define FSPI_FLSHB2CR0
#define FSPI_FLSHXCR0_SZ_KB
#define FSPI_FLSHXCR0_SZ(x)

#define FSPI_FLSHA1CR1
#define FSPI_FLSHA2CR1
#define FSPI_FLSHB1CR1
#define FSPI_FLSHB2CR1
#define FSPI_FLSHXCR1_CSINTR(x)
#define FSPI_FLSHXCR1_CAS(x)
#define FSPI_FLSHXCR1_WA
#define FSPI_FLSHXCR1_TCSH(x)
#define FSPI_FLSHXCR1_TCSS(x)

#define FSPI_FLSHA1CR2
#define FSPI_FLSHA2CR2
#define FSPI_FLSHB1CR2
#define FSPI_FLSHB2CR2
#define FSPI_FLSHXCR2_CLRINSP
#define FSPI_FLSHXCR2_AWRWAIT
#define FSPI_FLSHXCR2_AWRSEQN_SHIFT
#define FSPI_FLSHXCR2_AWRSEQI_SHIFT
#define FSPI_FLSHXCR2_ARDSEQN_SHIFT
#define FSPI_FLSHXCR2_ARDSEQI_SHIFT

#define FSPI_IPCR0

#define FSPI_IPCR1
#define FSPI_IPCR1_IPAREN
#define FSPI_IPCR1_SEQNUM_SHIFT
#define FSPI_IPCR1_SEQID_SHIFT
#define FSPI_IPCR1_IDATSZ(x)

#define FSPI_IPCMD
#define FSPI_IPCMD_TRG

#define FSPI_DLPR

#define FSPI_IPRXFCR
#define FSPI_IPRXFCR_CLR
#define FSPI_IPRXFCR_DMA_EN
#define FSPI_IPRXFCR_WMRK(x)

#define FSPI_IPTXFCR
#define FSPI_IPTXFCR_CLR
#define FSPI_IPTXFCR_DMA_EN
#define FSPI_IPTXFCR_WMRK(x)

#define FSPI_DLLACR
#define FSPI_DLLACR_OVRDEN
#define FSPI_DLLACR_SLVDLY(x)
#define FSPI_DLLACR_DLLRESET
#define FSPI_DLLACR_DLLEN

#define FSPI_DLLBCR
#define FSPI_DLLBCR_OVRDEN
#define FSPI_DLLBCR_SLVDLY(x)
#define FSPI_DLLBCR_DLLRESET
#define FSPI_DLLBCR_DLLEN

#define FSPI_STS0
#define FSPI_STS0_DLPHB(x)
#define FSPI_STS0_DLPHA(x)
#define FSPI_STS0_CMD_SRC(x)
#define FSPI_STS0_ARB_IDLE
#define FSPI_STS0_SEQ_IDLE

#define FSPI_STS1
#define FSPI_STS1_IP_ERRCD(x)
#define FSPI_STS1_IP_ERRID(x)
#define FSPI_STS1_AHB_ERRCD(x)
#define FSPI_STS1_AHB_ERRID(x)

#define FSPI_STS2
#define FSPI_STS2_BREFLOCK
#define FSPI_STS2_BSLVLOCK
#define FSPI_STS2_AREFLOCK
#define FSPI_STS2_ASLVLOCK
#define FSPI_STS2_AB_LOCK

#define FSPI_AHBSPNST
#define FSPI_AHBSPNST_DATLFT(x)
#define FSPI_AHBSPNST_BUFID(x)
#define FSPI_AHBSPNST_ACTIVE

#define FSPI_IPRXFSTS
#define FSPI_IPRXFSTS_RDCNTR(x)
#define FSPI_IPRXFSTS_FILL(x)

#define FSPI_IPTXFSTS
#define FSPI_IPTXFSTS_WRCNTR(x)
#define FSPI_IPTXFSTS_FILL(x)

#define FSPI_RFDR
#define FSPI_TFDR

#define FSPI_LUT_BASE
#define FSPI_LUT_OFFSET
#define FSPI_LUT_REG(idx)

/* register map end */

/* Instruction set for the LUT register. */
#define LUT_STOP
#define LUT_CMD
#define LUT_ADDR
#define LUT_CADDR_SDR
#define LUT_MODE
#define LUT_MODE2
#define LUT_MODE4
#define LUT_MODE8
#define LUT_NXP_WRITE
#define LUT_NXP_READ
#define LUT_LEARN_SDR
#define LUT_DATSZ_SDR
#define LUT_DUMMY
#define LUT_DUMMY_RWDS_SDR
#define LUT_JMP_ON_CS
#define LUT_CMD_DDR
#define LUT_ADDR_DDR
#define LUT_CADDR_DDR
#define LUT_MODE_DDR
#define LUT_MODE2_DDR
#define LUT_MODE4_DDR
#define LUT_MODE8_DDR
#define LUT_WRITE_DDR
#define LUT_READ_DDR
#define LUT_LEARN_DDR
#define LUT_DATSZ_DDR
#define LUT_DUMMY_DDR
#define LUT_DUMMY_RWDS_DDR

/*
 * Calculate number of required PAD bits for LUT register.
 *
 * The pad stands for the number of IO lines [0:7].
 * For example, the octal read needs eight IO lines,
 * so you should use LUT_PAD(8). This macro
 * returns 3 i.e. use eight (2^3) IP lines for read.
 */
#define LUT_PAD(x)

/*
 * Macro for constructing the LUT entries with the following
 * register layout:
 *
 *  ---------------------------------------------------
 *  | INSTR1 | PAD1 | OPRND1 | INSTR0 | PAD0 | OPRND0 |
 *  ---------------------------------------------------
 */
#define PAD_SHIFT
#define INSTR_SHIFT
#define OPRND_SHIFT

/* Macros for constructing the LUT register. */
#define LUT_DEF(idx, ins, pad, opr)

#define POLL_TOUT
#define NXP_FSPI_MAX_CHIPSELECT
#define NXP_FSPI_MIN_IOMAP

#define DCFG_RCWSR1
#define SYS_PLL_RAT

/* Access flash memory using IP bus only */
#define FSPI_QUIRK_USE_IP_ONLY

struct nxp_fspi_devtype_data {};

static struct nxp_fspi_devtype_data lx2160a_data =;

static struct nxp_fspi_devtype_data imx8mm_data =;

static struct nxp_fspi_devtype_data imx8qxp_data =;

static struct nxp_fspi_devtype_data imx8dxl_data =;

struct nxp_fspi {};

static inline int needs_ip_only(struct nxp_fspi *f)
{}

/*
 * R/W functions for big- or little-endian registers:
 * The FSPI controller's endianness is independent of
 * the CPU core's endianness. So far, although the CPU
 * core is little-endian the FSPI controller can use
 * big-endian or little-endian.
 */
static void fspi_writel(struct nxp_fspi *f, u32 val, void __iomem *addr)
{}

static u32 fspi_readl(struct nxp_fspi *f, void __iomem *addr)
{}

static irqreturn_t nxp_fspi_irq_handler(int irq, void *dev_id)
{}

static int nxp_fspi_check_buswidth(struct nxp_fspi *f, u8 width)
{}

static bool nxp_fspi_supports_op(struct spi_mem *mem,
				 const struct spi_mem_op *op)
{}

/* Instead of busy looping invoke readl_poll_timeout functionality. */
static int fspi_readl_poll_tout(struct nxp_fspi *f, void __iomem *base,
				u32 mask, u32 delay_us,
				u32 timeout_us, bool c)
{}

/*
 * If the target device content being changed by Write/Erase, need to
 * invalidate the AHB buffer. This can be achieved by doing the reset
 * of controller after setting MCR0[SWRESET] bit.
 */
static inline void nxp_fspi_invalid(struct nxp_fspi *f)
{}

static void nxp_fspi_prepare_lut(struct nxp_fspi *f,
				 const struct spi_mem_op *op)
{}

static int nxp_fspi_clk_prep_enable(struct nxp_fspi *f)
{}

static int nxp_fspi_clk_disable_unprep(struct nxp_fspi *f)
{}

static void nxp_fspi_dll_calibration(struct nxp_fspi *f)
{}

/*
 * In FlexSPI controller, flash access is based on value of FSPI_FLSHXXCR0
 * register and start base address of the target device.
 *
 *							    (Higher address)
 *				--------    <-- FLSHB2CR0
 *				|  B2  |
 *				|      |
 *	B2 start address -->	--------    <-- FLSHB1CR0
 *				|  B1  |
 *				|      |
 *	B1 start address -->	--------    <-- FLSHA2CR0
 *				|  A2  |
 *				|      |
 *	A2 start address -->	--------    <-- FLSHA1CR0
 *				|  A1  |
 *				|      |
 *	A1 start address -->	--------		    (Lower address)
 *
 *
 * Start base address defines the starting address range for given CS and
 * FSPI_FLSHXXCR0 defines the size of the target device connected at given CS.
 *
 * But, different targets are having different combinations of number of CS,
 * some targets only have single CS or two CS covering controller's full
 * memory mapped space area.
 * Thus, implementation is being done as independent of the size and number
 * of the connected target device.
 * Assign controller memory mapped space size as the size to the connected
 * target device.
 * Mark FLSHxxCR0 as zero initially and then assign value only to the selected
 * chip-select Flash configuration register.
 *
 * For e.g. to access CS2 (B1), FLSHB1CR0 register would be equal to the
 * memory mapped size of the controller.
 * Value for rest of the CS FLSHxxCR0 register would be zero.
 *
 */
static void nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi)
{}

static int nxp_fspi_read_ahb(struct nxp_fspi *f, const struct spi_mem_op *op)
{}

static void nxp_fspi_fill_txfifo(struct nxp_fspi *f,
				 const struct spi_mem_op *op)
{}

static void nxp_fspi_read_rxfifo(struct nxp_fspi *f,
			  const struct spi_mem_op *op)
{}

static int nxp_fspi_do_op(struct nxp_fspi *f, const struct spi_mem_op *op)
{}

static int nxp_fspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
{}

static int nxp_fspi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
{}

static void erratum_err050568(struct nxp_fspi *f)
{}

static int nxp_fspi_default_setup(struct nxp_fspi *f)
{}

static const char *nxp_fspi_get_name(struct spi_mem *mem)
{}

static const struct spi_controller_mem_ops nxp_fspi_mem_ops =;

static int nxp_fspi_probe(struct platform_device *pdev)
{}

static void nxp_fspi_remove(struct platform_device *pdev)
{}

static int nxp_fspi_suspend(struct device *dev)
{}

static int nxp_fspi_resume(struct device *dev)
{}

static const struct of_device_id nxp_fspi_dt_ids[] =;
MODULE_DEVICE_TABLE(of, nxp_fspi_dt_ids);

#ifdef CONFIG_ACPI
static const struct acpi_device_id nxp_fspi_acpi_ids[] =;
MODULE_DEVICE_TABLE(acpi, nxp_fspi_acpi_ids);
#endif

static const struct dev_pm_ops nxp_fspi_pm_ops =;

static struct platform_driver nxp_fspi_driver =;
module_platform_driver();

MODULE_DESCRIPTION();
MODULE_AUTHOR();
MODULE_AUTHOR();
MODULE_AUTHOR();
MODULE_AUTHOR();
MODULE_LICENSE();