// SPDX-License-Identifier: GPL-2.0-or-later /* * Xilinx Zynq UltraScale+ MPSoC Quad-SPI (QSPI) controller driver * (host mode only) * * Copyright (C) 2009 - 2015 Xilinx, Inc. */ #include <linux/clk.h> #include <linux/delay.h> #include <linux/dma-mapping.h> #include <linux/dmaengine.h> #include <linux/firmware/xlnx-zynqmp.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/spi/spi.h> #include <linux/spinlock.h> #include <linux/workqueue.h> #include <linux/spi/spi-mem.h> /* Generic QSPI register offsets */ #define GQSPI_CONFIG_OFST … #define GQSPI_ISR_OFST … #define GQSPI_IDR_OFST … #define GQSPI_IER_OFST … #define GQSPI_IMASK_OFST … #define GQSPI_EN_OFST … #define GQSPI_TXD_OFST … #define GQSPI_RXD_OFST … #define GQSPI_TX_THRESHOLD_OFST … #define GQSPI_RX_THRESHOLD_OFST … #define IOU_TAPDLY_BYPASS_OFST … #define GQSPI_LPBK_DLY_ADJ_OFST … #define GQSPI_GEN_FIFO_OFST … #define GQSPI_SEL_OFST … #define GQSPI_GF_THRESHOLD_OFST … #define GQSPI_FIFO_CTRL_OFST … #define GQSPI_QSPIDMA_DST_CTRL_OFST … #define GQSPI_QSPIDMA_DST_SIZE_OFST … #define GQSPI_QSPIDMA_DST_STS_OFST … #define GQSPI_QSPIDMA_DST_I_STS_OFST … #define GQSPI_QSPIDMA_DST_I_EN_OFST … #define GQSPI_QSPIDMA_DST_I_DIS_OFST … #define GQSPI_QSPIDMA_DST_I_MASK_OFST … #define GQSPI_QSPIDMA_DST_ADDR_OFST … #define GQSPI_QSPIDMA_DST_ADDR_MSB_OFST … #define GQSPI_DATA_DLY_ADJ_OFST … /* GQSPI register bit masks */ #define GQSPI_SEL_MASK … #define GQSPI_EN_MASK … #define GQSPI_LPBK_DLY_ADJ_USE_LPBK_MASK … #define GQSPI_ISR_WR_TO_CLR_MASK … #define GQSPI_IDR_ALL_MASK … #define GQSPI_CFG_MODE_EN_MASK … #define GQSPI_CFG_GEN_FIFO_START_MODE_MASK … #define GQSPI_CFG_ENDIAN_MASK … #define GQSPI_CFG_EN_POLL_TO_MASK … #define GQSPI_CFG_WP_HOLD_MASK … #define GQSPI_CFG_BAUD_RATE_DIV_MASK … #define GQSPI_CFG_CLK_PHA_MASK … #define GQSPI_CFG_CLK_POL_MASK … #define GQSPI_CFG_START_GEN_FIFO_MASK … #define GQSPI_GENFIFO_IMM_DATA_MASK … #define GQSPI_GENFIFO_DATA_XFER … #define GQSPI_GENFIFO_EXP … #define GQSPI_GENFIFO_MODE_SPI … #define GQSPI_GENFIFO_MODE_DUALSPI … #define GQSPI_GENFIFO_MODE_QUADSPI … #define GQSPI_GENFIFO_MODE_MASK … #define GQSPI_GENFIFO_CS_LOWER … #define GQSPI_GENFIFO_CS_UPPER … #define GQSPI_GENFIFO_BUS_LOWER … #define GQSPI_GENFIFO_BUS_UPPER … #define GQSPI_GENFIFO_BUS_BOTH … #define GQSPI_GENFIFO_BUS_MASK … #define GQSPI_GENFIFO_TX … #define GQSPI_GENFIFO_RX … #define GQSPI_GENFIFO_STRIPE … #define GQSPI_GENFIFO_POLL … #define GQSPI_GENFIFO_EXP_START … #define GQSPI_FIFO_CTRL_RST_RX_FIFO_MASK … #define GQSPI_FIFO_CTRL_RST_TX_FIFO_MASK … #define GQSPI_FIFO_CTRL_RST_GEN_FIFO_MASK … #define GQSPI_ISR_RXEMPTY_MASK … #define GQSPI_ISR_GENFIFOFULL_MASK … #define GQSPI_ISR_GENFIFONOT_FULL_MASK … #define GQSPI_ISR_TXEMPTY_MASK … #define GQSPI_ISR_GENFIFOEMPTY_MASK … #define GQSPI_ISR_RXFULL_MASK … #define GQSPI_ISR_RXNEMPTY_MASK … #define GQSPI_ISR_TXFULL_MASK … #define GQSPI_ISR_TXNOT_FULL_MASK … #define GQSPI_ISR_POLL_TIME_EXPIRE_MASK … #define GQSPI_IER_TXNOT_FULL_MASK … #define GQSPI_IER_RXEMPTY_MASK … #define GQSPI_IER_POLL_TIME_EXPIRE_MASK … #define GQSPI_IER_RXNEMPTY_MASK … #define GQSPI_IER_GENFIFOEMPTY_MASK … #define GQSPI_IER_TXEMPTY_MASK … #define GQSPI_QSPIDMA_DST_INTR_ALL_MASK … #define GQSPI_QSPIDMA_DST_STS_WTC … #define GQSPI_CFG_MODE_EN_DMA_MASK … #define GQSPI_ISR_IDR_MASK … #define GQSPI_QSPIDMA_DST_I_EN_DONE_MASK … #define GQSPI_QSPIDMA_DST_I_STS_DONE_MASK … #define GQSPI_IRQ_MASK … #define GQSPI_CFG_BAUD_RATE_DIV_SHIFT … #define GQSPI_GENFIFO_CS_SETUP … #define GQSPI_GENFIFO_CS_HOLD … #define GQSPI_TXD_DEPTH … #define GQSPI_RX_FIFO_THRESHOLD … #define GQSPI_RX_FIFO_FILL … #define GQSPI_TX_FIFO_THRESHOLD_RESET_VAL … #define GQSPI_TX_FIFO_FILL … #define GQSPI_GEN_FIFO_THRESHOLD_RESET_VAL … #define GQSPI_QSPIDMA_DST_CTRL_RESET_VAL … #define GQSPI_SELECT_FLASH_CS_LOWER … #define GQSPI_SELECT_FLASH_CS_UPPER … #define GQSPI_SELECT_FLASH_CS_BOTH … #define GQSPI_SELECT_FLASH_BUS_LOWER … #define GQSPI_SELECT_FLASH_BUS_UPPER … #define GQSPI_SELECT_FLASH_BUS_BOTH … #define GQSPI_BAUD_DIV_MAX … #define GQSPI_BAUD_DIV_SHIFT … #define GQSPI_SELECT_MODE_SPI … #define GQSPI_SELECT_MODE_DUALSPI … #define GQSPI_SELECT_MODE_QUADSPI … #define GQSPI_DMA_UNALIGN … #define GQSPI_DEFAULT_NUM_CS … #define GQSPI_MAX_NUM_CS … #define GQSPI_USE_DATA_DLY … #define GQSPI_USE_DATA_DLY_SHIFT … #define GQSPI_DATA_DLY_ADJ_VALUE … #define GQSPI_DATA_DLY_ADJ_SHIFT … #define GQSPI_LPBK_DLY_ADJ_DLY_1 … #define GQSPI_LPBK_DLY_ADJ_DLY_1_SHIFT … #define TAP_DLY_BYPASS_LQSPI_RX_VALUE … #define TAP_DLY_BYPASS_LQSPI_RX_SHIFT … /* set to differentiate versal from zynqmp, 1=versal, 0=zynqmp */ #define QSPI_QUIRK_HAS_TAPDELAY … #define GQSPI_FREQ_37_5MHZ … #define GQSPI_FREQ_40MHZ … #define GQSPI_FREQ_100MHZ … #define GQSPI_FREQ_150MHZ … #define SPI_AUTOSUSPEND_TIMEOUT … enum mode_type { … }; /** * struct qspi_platform_data - zynqmp qspi platform data structure * @quirks: Flags is used to identify the platform */ struct qspi_platform_data { … }; /** * struct zynqmp_qspi - Defines qspi driver instance * @ctlr: Pointer to the spi controller information * @regs: Virtual address of the QSPI controller registers * @refclk: Pointer to the peripheral clock * @pclk: Pointer to the APB clock * @irq: IRQ number * @dev: Pointer to struct device * @txbuf: Pointer to the TX buffer * @rxbuf: Pointer to the RX buffer * @bytes_to_transfer: Number of bytes left to transfer * @bytes_to_receive: Number of bytes left to receive * @genfifocs: Used for chip select * @genfifobus: Used to select the upper or lower bus * @dma_rx_bytes: Remaining bytes to receive by DMA mode * @dma_addr: DMA address after mapping the kernel buffer * @genfifoentry: Used for storing the genfifoentry instruction. * @mode: Defines the mode in which QSPI is operating * @data_completion: completion structure * @op_lock: Operational lock * @speed_hz: Current SPI bus clock speed in hz * @has_tapdelay: Used for tapdelay register available in qspi */ struct zynqmp_qspi { … }; /** * zynqmp_gqspi_read - For GQSPI controller read operation * @xqspi: Pointer to the zynqmp_qspi structure * @offset: Offset from where to read * Return: Value at the offset */ static u32 zynqmp_gqspi_read(struct zynqmp_qspi *xqspi, u32 offset) { … } /** * zynqmp_gqspi_write - For GQSPI controller write operation * @xqspi: Pointer to the zynqmp_qspi structure * @offset: Offset where to write * @val: Value to be written */ static inline void zynqmp_gqspi_write(struct zynqmp_qspi *xqspi, u32 offset, u32 val) { … } /** * zynqmp_gqspi_selecttarget - For selection of target device * @instanceptr: Pointer to the zynqmp_qspi structure * @targetcs: For chip select * @targetbus: To check which bus is selected- upper or lower */ static void zynqmp_gqspi_selecttarget(struct zynqmp_qspi *instanceptr, u8 targetcs, u8 targetbus) { … } /** * zynqmp_qspi_set_tapdelay: To configure qspi tap delays * @xqspi: Pointer to the zynqmp_qspi structure * @baudrateval: Buadrate to configure */ static void zynqmp_qspi_set_tapdelay(struct zynqmp_qspi *xqspi, u32 baudrateval) { … } /** * zynqmp_qspi_init_hw - Initialize the hardware * @xqspi: Pointer to the zynqmp_qspi structure * * The default settings of the QSPI controller's configurable parameters on * reset are * - Host mode * - TX threshold set to 1 * - RX threshold set to 1 * - Flash memory interface mode enabled * This function performs the following actions * - Disable and clear all the interrupts * - Enable manual target select * - Enable manual start * - Deselect all the chip select lines * - Set the little endian mode of TX FIFO * - Set clock phase * - Set clock polarity and * - Enable the QSPI controller */ static void zynqmp_qspi_init_hw(struct zynqmp_qspi *xqspi) { … } /** * zynqmp_qspi_copy_read_data - Copy data to RX buffer * @xqspi: Pointer to the zynqmp_qspi structure * @data: The variable where data is stored * @size: Number of bytes to be copied from data to RX buffer */ static void zynqmp_qspi_copy_read_data(struct zynqmp_qspi *xqspi, ulong data, u8 size) { … } /** * zynqmp_qspi_chipselect - Select or deselect the chip select line * @qspi: Pointer to the spi_device structure * @is_high: Select(0) or deselect (1) the chip select line */ static void zynqmp_qspi_chipselect(struct spi_device *qspi, bool is_high) { … } /** * zynqmp_qspi_selectspimode - Selects SPI mode - x1 or x2 or x4. * @xqspi: xqspi is a pointer to the GQSPI instance * @spimode: spimode - SPI or DUAL or QUAD. * Return: Mask to set desired SPI mode in GENFIFO entry. */ static inline u32 zynqmp_qspi_selectspimode(struct zynqmp_qspi *xqspi, u8 spimode) { … } /** * zynqmp_qspi_config_op - Configure QSPI controller for specified * transfer * @xqspi: Pointer to the zynqmp_qspi structure * @qspi: Pointer to the spi_device structure * * Sets the operational mode of QSPI controller for the next QSPI transfer and * sets the requested clock frequency. * * Return: Always 0 * * Note: * If the requested frequency is not an exact match with what can be * obtained using the pre-scalar value, the driver sets the clock * frequency which is lower than the requested frequency (maximum lower) * for the transfer. * * If the requested frequency is higher or lower than that is supported * by the QSPI controller the driver will set the highest or lowest * frequency supported by controller. */ static int zynqmp_qspi_config_op(struct zynqmp_qspi *xqspi, struct spi_device *qspi) { … } /** * zynqmp_qspi_setup_op - Configure the QSPI controller * @qspi: Pointer to the spi_device structure * * Sets the operational mode of QSPI controller for the next QSPI transfer, * baud rate and divisor value to setup the requested qspi clock. * * Return: 0 on success; error value otherwise. */ static int zynqmp_qspi_setup_op(struct spi_device *qspi) { … } /** * zynqmp_qspi_filltxfifo - Fills the TX FIFO as long as there is room in * the FIFO or the bytes required to be * transmitted. * @xqspi: Pointer to the zynqmp_qspi structure * @size: Number of bytes to be copied from TX buffer to TX FIFO */ static void zynqmp_qspi_filltxfifo(struct zynqmp_qspi *xqspi, int size) { … } /** * zynqmp_qspi_readrxfifo - Fills the RX FIFO as long as there is room in * the FIFO. * @xqspi: Pointer to the zynqmp_qspi structure * @size: Number of bytes to be copied from RX buffer to RX FIFO */ static void zynqmp_qspi_readrxfifo(struct zynqmp_qspi *xqspi, u32 size) { … } /** * zynqmp_qspi_fillgenfifo - Fills the GENFIFO. * @xqspi: Pointer to the zynqmp_qspi structure * @nbits: Transfer/Receive buswidth. * @genfifoentry: Variable in which GENFIFO mask is saved */ static void zynqmp_qspi_fillgenfifo(struct zynqmp_qspi *xqspi, u8 nbits, u32 genfifoentry) { … } /** * zynqmp_process_dma_irq - Handler for DMA done interrupt of QSPI * controller * @xqspi: zynqmp_qspi instance pointer * * This function handles DMA interrupt only. */ static void zynqmp_process_dma_irq(struct zynqmp_qspi *xqspi) { … } /** * zynqmp_qspi_irq - Interrupt service routine of the QSPI controller * @irq: IRQ number * @dev_id: Pointer to the xqspi structure * * This function handles TX empty only. * On TX empty interrupt this function reads the received data from RX FIFO * and fills the TX FIFO if there is any data remaining to be transferred. * * Return: IRQ_HANDLED when interrupt is handled * IRQ_NONE otherwise. */ static irqreturn_t zynqmp_qspi_irq(int irq, void *dev_id) { … } /** * zynqmp_qspi_setuprxdma - This function sets up the RX DMA operation * @xqspi: xqspi is a pointer to the GQSPI instance. * * Return: 0 on success; error value otherwise. */ static int zynqmp_qspi_setuprxdma(struct zynqmp_qspi *xqspi) { … } /** * zynqmp_qspi_write_op - This function sets up the GENFIFO entries, * TX FIFO, and fills the TX FIFO with as many * bytes as possible. * @xqspi: Pointer to the GQSPI instance. * @tx_nbits: Transfer buswidth. * @genfifoentry: Variable in which GENFIFO mask is returned * to calling function */ static void zynqmp_qspi_write_op(struct zynqmp_qspi *xqspi, u8 tx_nbits, u32 genfifoentry) { … } /** * zynqmp_qspi_read_op - This function sets up the GENFIFO entries and * RX DMA operation. * @xqspi: xqspi is a pointer to the GQSPI instance. * @rx_nbits: Receive buswidth. * @genfifoentry: genfifoentry is pointer to the variable in which * GENFIFO mask is returned to calling function * * Return: 0 on success; error value otherwise. */ static int zynqmp_qspi_read_op(struct zynqmp_qspi *xqspi, u8 rx_nbits, u32 genfifoentry) { … } /** * zynqmp_qspi_suspend - Suspend method for the QSPI driver * @dev: Address of the platform_device structure * * This function stops the QSPI driver queue and disables the QSPI controller * * Return: Always 0 */ static int __maybe_unused zynqmp_qspi_suspend(struct device *dev) { … } /** * zynqmp_qspi_resume - Resume method for the QSPI driver * @dev: Address of the platform_device structure * * The function starts the QSPI driver queue and initializes the QSPI * controller * * Return: 0 on success; error value otherwise */ static int __maybe_unused zynqmp_qspi_resume(struct device *dev) { … } /** * zynqmp_runtime_suspend - Runtime suspend method for the SPI driver * @dev: Address of the platform_device structure * * This function disables the clocks * * Return: Always 0 */ static int __maybe_unused zynqmp_runtime_suspend(struct device *dev) { … } /** * zynqmp_runtime_resume - Runtime resume method for the SPI driver * @dev: Address of the platform_device structure * * This function enables the clocks * * Return: 0 on success and error value on error */ static int __maybe_unused zynqmp_runtime_resume(struct device *dev) { … } /** * zynqmp_qspi_exec_op() - Initiates the QSPI transfer * @mem: The SPI memory * @op: The memory operation to execute * * Executes a memory operation. * * This function first selects the chip and starts the memory operation. * * Return: 0 in case of success, a negative error code otherwise. */ static int zynqmp_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) { … } static const struct dev_pm_ops zynqmp_qspi_dev_pm_ops = …; static const struct qspi_platform_data versal_qspi_def = …; static const struct of_device_id zynqmp_qspi_of_match[] = …; static const struct spi_controller_mem_ops zynqmp_qspi_mem_ops = …; /** * zynqmp_qspi_probe - Probe method for the QSPI driver * @pdev: Pointer to the platform_device structure * * This function initializes the driver data structures and the hardware. * * Return: 0 on success; error value otherwise */ static int zynqmp_qspi_probe(struct platform_device *pdev) { … } /** * zynqmp_qspi_remove - Remove method for the QSPI driver * @pdev: Pointer to the platform_device structure * * This function is called if a device is physically removed from the system or * if the driver module is being unloaded. It frees all resources allocated to * the device. * * Return: 0 Always */ static void zynqmp_qspi_remove(struct platform_device *pdev) { … } MODULE_DEVICE_TABLE(of, zynqmp_qspi_of_match); static struct platform_driver zynqmp_qspi_driver = …; module_platform_driver(…) …; MODULE_AUTHOR(…) …; MODULE_DESCRIPTION(…) …; MODULE_LICENSE(…) …;