18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci//
38c2ecf20Sopenharmony_ci// Driver for Cadence QSPI Controller
48c2ecf20Sopenharmony_ci//
58c2ecf20Sopenharmony_ci// Copyright Altera Corporation (C) 2012-2014. All rights reserved.
68c2ecf20Sopenharmony_ci// Copyright Intel Corporation (C) 2019-2020. All rights reserved.
78c2ecf20Sopenharmony_ci// Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/clk.h>
108c2ecf20Sopenharmony_ci#include <linux/completion.h>
118c2ecf20Sopenharmony_ci#include <linux/delay.h>
128c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
138c2ecf20Sopenharmony_ci#include <linux/dmaengine.h>
148c2ecf20Sopenharmony_ci#include <linux/err.h>
158c2ecf20Sopenharmony_ci#include <linux/errno.h>
168c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
178c2ecf20Sopenharmony_ci#include <linux/io.h>
188c2ecf20Sopenharmony_ci#include <linux/iopoll.h>
198c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
208c2ecf20Sopenharmony_ci#include <linux/kernel.h>
218c2ecf20Sopenharmony_ci#include <linux/module.h>
228c2ecf20Sopenharmony_ci#include <linux/of_device.h>
238c2ecf20Sopenharmony_ci#include <linux/of.h>
248c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
258c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
268c2ecf20Sopenharmony_ci#include <linux/reset.h>
278c2ecf20Sopenharmony_ci#include <linux/sched.h>
288c2ecf20Sopenharmony_ci#include <linux/spi/spi.h>
298c2ecf20Sopenharmony_ci#include <linux/spi/spi-mem.h>
308c2ecf20Sopenharmony_ci#include <linux/timer.h>
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#define CQSPI_NAME			"cadence-qspi"
338c2ecf20Sopenharmony_ci#define CQSPI_MAX_CHIPSELECT		16
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci/* Quirks */
368c2ecf20Sopenharmony_ci#define CQSPI_NEEDS_WR_DELAY		BIT(0)
378c2ecf20Sopenharmony_ci#define CQSPI_DISABLE_DAC_MODE		BIT(1)
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci/* Capabilities */
408c2ecf20Sopenharmony_ci#define CQSPI_SUPPORTS_OCTAL		BIT(0)
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistruct cqspi_st;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistruct cqspi_flash_pdata {
458c2ecf20Sopenharmony_ci	struct cqspi_st	*cqspi;
468c2ecf20Sopenharmony_ci	u32		clk_rate;
478c2ecf20Sopenharmony_ci	u32		read_delay;
488c2ecf20Sopenharmony_ci	u32		tshsl_ns;
498c2ecf20Sopenharmony_ci	u32		tsd2d_ns;
508c2ecf20Sopenharmony_ci	u32		tchsh_ns;
518c2ecf20Sopenharmony_ci	u32		tslch_ns;
528c2ecf20Sopenharmony_ci	u8		inst_width;
538c2ecf20Sopenharmony_ci	u8		addr_width;
548c2ecf20Sopenharmony_ci	u8		data_width;
558c2ecf20Sopenharmony_ci	u8		cs;
568c2ecf20Sopenharmony_ci};
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistruct cqspi_st {
598c2ecf20Sopenharmony_ci	struct platform_device	*pdev;
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	struct clk		*clk;
628c2ecf20Sopenharmony_ci	unsigned int		sclk;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	void __iomem		*iobase;
658c2ecf20Sopenharmony_ci	void __iomem		*ahb_base;
668c2ecf20Sopenharmony_ci	resource_size_t		ahb_size;
678c2ecf20Sopenharmony_ci	struct completion	transfer_complete;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	struct dma_chan		*rx_chan;
708c2ecf20Sopenharmony_ci	struct completion	rx_dma_complete;
718c2ecf20Sopenharmony_ci	dma_addr_t		mmap_phys_base;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	int			current_cs;
748c2ecf20Sopenharmony_ci	unsigned long		master_ref_clk_hz;
758c2ecf20Sopenharmony_ci	bool			is_decoded_cs;
768c2ecf20Sopenharmony_ci	u32			fifo_depth;
778c2ecf20Sopenharmony_ci	u32			fifo_width;
788c2ecf20Sopenharmony_ci	bool			rclk_en;
798c2ecf20Sopenharmony_ci	u32			trigger_address;
808c2ecf20Sopenharmony_ci	u32			wr_delay;
818c2ecf20Sopenharmony_ci	bool			use_direct_mode;
828c2ecf20Sopenharmony_ci	struct cqspi_flash_pdata f_pdata[CQSPI_MAX_CHIPSELECT];
838c2ecf20Sopenharmony_ci};
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_cistruct cqspi_driver_platdata {
868c2ecf20Sopenharmony_ci	u32 hwcaps_mask;
878c2ecf20Sopenharmony_ci	u8 quirks;
888c2ecf20Sopenharmony_ci};
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci/* Operation timeout value */
918c2ecf20Sopenharmony_ci#define CQSPI_TIMEOUT_MS			500
928c2ecf20Sopenharmony_ci#define CQSPI_READ_TIMEOUT_MS			10
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci/* Instruction type */
958c2ecf20Sopenharmony_ci#define CQSPI_INST_TYPE_SINGLE			0
968c2ecf20Sopenharmony_ci#define CQSPI_INST_TYPE_DUAL			1
978c2ecf20Sopenharmony_ci#define CQSPI_INST_TYPE_QUAD			2
988c2ecf20Sopenharmony_ci#define CQSPI_INST_TYPE_OCTAL			3
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci#define CQSPI_DUMMY_CLKS_PER_BYTE		8
1018c2ecf20Sopenharmony_ci#define CQSPI_DUMMY_BYTES_MAX			4
1028c2ecf20Sopenharmony_ci#define CQSPI_DUMMY_CLKS_MAX			31
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci#define CQSPI_STIG_DATA_LEN_MAX			8
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci/* Register map */
1078c2ecf20Sopenharmony_ci#define CQSPI_REG_CONFIG			0x00
1088c2ecf20Sopenharmony_ci#define CQSPI_REG_CONFIG_ENABLE_MASK		BIT(0)
1098c2ecf20Sopenharmony_ci#define CQSPI_REG_CONFIG_ENB_DIR_ACC_CTRL	BIT(7)
1108c2ecf20Sopenharmony_ci#define CQSPI_REG_CONFIG_DECODE_MASK		BIT(9)
1118c2ecf20Sopenharmony_ci#define CQSPI_REG_CONFIG_CHIPSELECT_LSB		10
1128c2ecf20Sopenharmony_ci#define CQSPI_REG_CONFIG_DMA_MASK		BIT(15)
1138c2ecf20Sopenharmony_ci#define CQSPI_REG_CONFIG_BAUD_LSB		19
1148c2ecf20Sopenharmony_ci#define CQSPI_REG_CONFIG_IDLE_LSB		31
1158c2ecf20Sopenharmony_ci#define CQSPI_REG_CONFIG_CHIPSELECT_MASK	0xF
1168c2ecf20Sopenharmony_ci#define CQSPI_REG_CONFIG_BAUD_MASK		0xF
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci#define CQSPI_REG_RD_INSTR			0x04
1198c2ecf20Sopenharmony_ci#define CQSPI_REG_RD_INSTR_OPCODE_LSB		0
1208c2ecf20Sopenharmony_ci#define CQSPI_REG_RD_INSTR_TYPE_INSTR_LSB	8
1218c2ecf20Sopenharmony_ci#define CQSPI_REG_RD_INSTR_TYPE_ADDR_LSB	12
1228c2ecf20Sopenharmony_ci#define CQSPI_REG_RD_INSTR_TYPE_DATA_LSB	16
1238c2ecf20Sopenharmony_ci#define CQSPI_REG_RD_INSTR_MODE_EN_LSB		20
1248c2ecf20Sopenharmony_ci#define CQSPI_REG_RD_INSTR_DUMMY_LSB		24
1258c2ecf20Sopenharmony_ci#define CQSPI_REG_RD_INSTR_TYPE_INSTR_MASK	0x3
1268c2ecf20Sopenharmony_ci#define CQSPI_REG_RD_INSTR_TYPE_ADDR_MASK	0x3
1278c2ecf20Sopenharmony_ci#define CQSPI_REG_RD_INSTR_TYPE_DATA_MASK	0x3
1288c2ecf20Sopenharmony_ci#define CQSPI_REG_RD_INSTR_DUMMY_MASK		0x1F
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci#define CQSPI_REG_WR_INSTR			0x08
1318c2ecf20Sopenharmony_ci#define CQSPI_REG_WR_INSTR_OPCODE_LSB		0
1328c2ecf20Sopenharmony_ci#define CQSPI_REG_WR_INSTR_TYPE_ADDR_LSB	12
1338c2ecf20Sopenharmony_ci#define CQSPI_REG_WR_INSTR_TYPE_DATA_LSB	16
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci#define CQSPI_REG_DELAY				0x0C
1368c2ecf20Sopenharmony_ci#define CQSPI_REG_DELAY_TSLCH_LSB		0
1378c2ecf20Sopenharmony_ci#define CQSPI_REG_DELAY_TCHSH_LSB		8
1388c2ecf20Sopenharmony_ci#define CQSPI_REG_DELAY_TSD2D_LSB		16
1398c2ecf20Sopenharmony_ci#define CQSPI_REG_DELAY_TSHSL_LSB		24
1408c2ecf20Sopenharmony_ci#define CQSPI_REG_DELAY_TSLCH_MASK		0xFF
1418c2ecf20Sopenharmony_ci#define CQSPI_REG_DELAY_TCHSH_MASK		0xFF
1428c2ecf20Sopenharmony_ci#define CQSPI_REG_DELAY_TSD2D_MASK		0xFF
1438c2ecf20Sopenharmony_ci#define CQSPI_REG_DELAY_TSHSL_MASK		0xFF
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci#define CQSPI_REG_READCAPTURE			0x10
1468c2ecf20Sopenharmony_ci#define CQSPI_REG_READCAPTURE_BYPASS_LSB	0
1478c2ecf20Sopenharmony_ci#define CQSPI_REG_READCAPTURE_DELAY_LSB		1
1488c2ecf20Sopenharmony_ci#define CQSPI_REG_READCAPTURE_DELAY_MASK	0xF
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci#define CQSPI_REG_SIZE				0x14
1518c2ecf20Sopenharmony_ci#define CQSPI_REG_SIZE_ADDRESS_LSB		0
1528c2ecf20Sopenharmony_ci#define CQSPI_REG_SIZE_PAGE_LSB			4
1538c2ecf20Sopenharmony_ci#define CQSPI_REG_SIZE_BLOCK_LSB		16
1548c2ecf20Sopenharmony_ci#define CQSPI_REG_SIZE_ADDRESS_MASK		0xF
1558c2ecf20Sopenharmony_ci#define CQSPI_REG_SIZE_PAGE_MASK		0xFFF
1568c2ecf20Sopenharmony_ci#define CQSPI_REG_SIZE_BLOCK_MASK		0x3F
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci#define CQSPI_REG_SRAMPARTITION			0x18
1598c2ecf20Sopenharmony_ci#define CQSPI_REG_INDIRECTTRIGGER		0x1C
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci#define CQSPI_REG_DMA				0x20
1628c2ecf20Sopenharmony_ci#define CQSPI_REG_DMA_SINGLE_LSB		0
1638c2ecf20Sopenharmony_ci#define CQSPI_REG_DMA_BURST_LSB			8
1648c2ecf20Sopenharmony_ci#define CQSPI_REG_DMA_SINGLE_MASK		0xFF
1658c2ecf20Sopenharmony_ci#define CQSPI_REG_DMA_BURST_MASK		0xFF
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci#define CQSPI_REG_REMAP				0x24
1688c2ecf20Sopenharmony_ci#define CQSPI_REG_MODE_BIT			0x28
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci#define CQSPI_REG_SDRAMLEVEL			0x2C
1718c2ecf20Sopenharmony_ci#define CQSPI_REG_SDRAMLEVEL_RD_LSB		0
1728c2ecf20Sopenharmony_ci#define CQSPI_REG_SDRAMLEVEL_WR_LSB		16
1738c2ecf20Sopenharmony_ci#define CQSPI_REG_SDRAMLEVEL_RD_MASK		0xFFFF
1748c2ecf20Sopenharmony_ci#define CQSPI_REG_SDRAMLEVEL_WR_MASK		0xFFFF
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci#define CQSPI_REG_IRQSTATUS			0x40
1778c2ecf20Sopenharmony_ci#define CQSPI_REG_IRQMASK			0x44
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci#define CQSPI_REG_INDIRECTRD			0x60
1808c2ecf20Sopenharmony_ci#define CQSPI_REG_INDIRECTRD_START_MASK		BIT(0)
1818c2ecf20Sopenharmony_ci#define CQSPI_REG_INDIRECTRD_CANCEL_MASK	BIT(1)
1828c2ecf20Sopenharmony_ci#define CQSPI_REG_INDIRECTRD_DONE_MASK		BIT(5)
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci#define CQSPI_REG_INDIRECTRDWATERMARK		0x64
1858c2ecf20Sopenharmony_ci#define CQSPI_REG_INDIRECTRDSTARTADDR		0x68
1868c2ecf20Sopenharmony_ci#define CQSPI_REG_INDIRECTRDBYTES		0x6C
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci#define CQSPI_REG_CMDCTRL			0x90
1898c2ecf20Sopenharmony_ci#define CQSPI_REG_CMDCTRL_EXECUTE_MASK		BIT(0)
1908c2ecf20Sopenharmony_ci#define CQSPI_REG_CMDCTRL_INPROGRESS_MASK	BIT(1)
1918c2ecf20Sopenharmony_ci#define CQSPI_REG_CMDCTRL_WR_BYTES_LSB		12
1928c2ecf20Sopenharmony_ci#define CQSPI_REG_CMDCTRL_WR_EN_LSB		15
1938c2ecf20Sopenharmony_ci#define CQSPI_REG_CMDCTRL_ADD_BYTES_LSB		16
1948c2ecf20Sopenharmony_ci#define CQSPI_REG_CMDCTRL_ADDR_EN_LSB		19
1958c2ecf20Sopenharmony_ci#define CQSPI_REG_CMDCTRL_RD_BYTES_LSB		20
1968c2ecf20Sopenharmony_ci#define CQSPI_REG_CMDCTRL_RD_EN_LSB		23
1978c2ecf20Sopenharmony_ci#define CQSPI_REG_CMDCTRL_OPCODE_LSB		24
1988c2ecf20Sopenharmony_ci#define CQSPI_REG_CMDCTRL_WR_BYTES_MASK		0x7
1998c2ecf20Sopenharmony_ci#define CQSPI_REG_CMDCTRL_ADD_BYTES_MASK	0x3
2008c2ecf20Sopenharmony_ci#define CQSPI_REG_CMDCTRL_RD_BYTES_MASK		0x7
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci#define CQSPI_REG_INDIRECTWR			0x70
2038c2ecf20Sopenharmony_ci#define CQSPI_REG_INDIRECTWR_START_MASK		BIT(0)
2048c2ecf20Sopenharmony_ci#define CQSPI_REG_INDIRECTWR_CANCEL_MASK	BIT(1)
2058c2ecf20Sopenharmony_ci#define CQSPI_REG_INDIRECTWR_DONE_MASK		BIT(5)
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci#define CQSPI_REG_INDIRECTWRWATERMARK		0x74
2088c2ecf20Sopenharmony_ci#define CQSPI_REG_INDIRECTWRSTARTADDR		0x78
2098c2ecf20Sopenharmony_ci#define CQSPI_REG_INDIRECTWRBYTES		0x7C
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci#define CQSPI_REG_CMDADDRESS			0x94
2128c2ecf20Sopenharmony_ci#define CQSPI_REG_CMDREADDATALOWER		0xA0
2138c2ecf20Sopenharmony_ci#define CQSPI_REG_CMDREADDATAUPPER		0xA4
2148c2ecf20Sopenharmony_ci#define CQSPI_REG_CMDWRITEDATALOWER		0xA8
2158c2ecf20Sopenharmony_ci#define CQSPI_REG_CMDWRITEDATAUPPER		0xAC
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci/* Interrupt status bits */
2188c2ecf20Sopenharmony_ci#define CQSPI_REG_IRQ_MODE_ERR			BIT(0)
2198c2ecf20Sopenharmony_ci#define CQSPI_REG_IRQ_UNDERFLOW			BIT(1)
2208c2ecf20Sopenharmony_ci#define CQSPI_REG_IRQ_IND_COMP			BIT(2)
2218c2ecf20Sopenharmony_ci#define CQSPI_REG_IRQ_IND_RD_REJECT		BIT(3)
2228c2ecf20Sopenharmony_ci#define CQSPI_REG_IRQ_WR_PROTECTED_ERR		BIT(4)
2238c2ecf20Sopenharmony_ci#define CQSPI_REG_IRQ_ILLEGAL_AHB_ERR		BIT(5)
2248c2ecf20Sopenharmony_ci#define CQSPI_REG_IRQ_WATERMARK			BIT(6)
2258c2ecf20Sopenharmony_ci#define CQSPI_REG_IRQ_IND_SRAM_FULL		BIT(12)
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci#define CQSPI_IRQ_MASK_RD		(CQSPI_REG_IRQ_WATERMARK	| \
2288c2ecf20Sopenharmony_ci					 CQSPI_REG_IRQ_IND_SRAM_FULL	| \
2298c2ecf20Sopenharmony_ci					 CQSPI_REG_IRQ_IND_COMP)
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci#define CQSPI_IRQ_MASK_WR		(CQSPI_REG_IRQ_IND_COMP		| \
2328c2ecf20Sopenharmony_ci					 CQSPI_REG_IRQ_WATERMARK	| \
2338c2ecf20Sopenharmony_ci					 CQSPI_REG_IRQ_UNDERFLOW)
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci#define CQSPI_IRQ_STATUS_MASK		0x1FFFF
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_cistatic int cqspi_wait_for_bit(void __iomem *reg, const u32 mask, bool clr)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	u32 val;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	return readl_relaxed_poll_timeout(reg, val,
2428c2ecf20Sopenharmony_ci					  (((clr ? ~val : val) & mask) == mask),
2438c2ecf20Sopenharmony_ci					  10, CQSPI_TIMEOUT_MS * 1000);
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_cistatic bool cqspi_is_idle(struct cqspi_st *cqspi)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	u32 reg = readl(cqspi->iobase + CQSPI_REG_CONFIG);
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	return reg & (1 << CQSPI_REG_CONFIG_IDLE_LSB);
2518c2ecf20Sopenharmony_ci}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_cistatic u32 cqspi_get_rd_sram_level(struct cqspi_st *cqspi)
2548c2ecf20Sopenharmony_ci{
2558c2ecf20Sopenharmony_ci	u32 reg = readl(cqspi->iobase + CQSPI_REG_SDRAMLEVEL);
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	reg >>= CQSPI_REG_SDRAMLEVEL_RD_LSB;
2588c2ecf20Sopenharmony_ci	return reg & CQSPI_REG_SDRAMLEVEL_RD_MASK;
2598c2ecf20Sopenharmony_ci}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_cistatic irqreturn_t cqspi_irq_handler(int this_irq, void *dev)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	struct cqspi_st *cqspi = dev;
2648c2ecf20Sopenharmony_ci	unsigned int irq_status;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	/* Read interrupt status */
2678c2ecf20Sopenharmony_ci	irq_status = readl(cqspi->iobase + CQSPI_REG_IRQSTATUS);
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	/* Clear interrupt */
2708c2ecf20Sopenharmony_ci	writel(irq_status, cqspi->iobase + CQSPI_REG_IRQSTATUS);
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	irq_status &= CQSPI_IRQ_MASK_RD | CQSPI_IRQ_MASK_WR;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	if (irq_status)
2758c2ecf20Sopenharmony_ci		complete(&cqspi->transfer_complete);
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
2788c2ecf20Sopenharmony_ci}
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_cistatic unsigned int cqspi_calc_rdreg(struct cqspi_flash_pdata *f_pdata)
2818c2ecf20Sopenharmony_ci{
2828c2ecf20Sopenharmony_ci	u32 rdreg = 0;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	rdreg |= f_pdata->inst_width << CQSPI_REG_RD_INSTR_TYPE_INSTR_LSB;
2858c2ecf20Sopenharmony_ci	rdreg |= f_pdata->addr_width << CQSPI_REG_RD_INSTR_TYPE_ADDR_LSB;
2868c2ecf20Sopenharmony_ci	rdreg |= f_pdata->data_width << CQSPI_REG_RD_INSTR_TYPE_DATA_LSB;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	return rdreg;
2898c2ecf20Sopenharmony_ci}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_cistatic int cqspi_wait_idle(struct cqspi_st *cqspi)
2928c2ecf20Sopenharmony_ci{
2938c2ecf20Sopenharmony_ci	const unsigned int poll_idle_retry = 3;
2948c2ecf20Sopenharmony_ci	unsigned int count = 0;
2958c2ecf20Sopenharmony_ci	unsigned long timeout;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	timeout = jiffies + msecs_to_jiffies(CQSPI_TIMEOUT_MS);
2988c2ecf20Sopenharmony_ci	while (1) {
2998c2ecf20Sopenharmony_ci		/*
3008c2ecf20Sopenharmony_ci		 * Read few times in succession to ensure the controller
3018c2ecf20Sopenharmony_ci		 * is indeed idle, that is, the bit does not transition
3028c2ecf20Sopenharmony_ci		 * low again.
3038c2ecf20Sopenharmony_ci		 */
3048c2ecf20Sopenharmony_ci		if (cqspi_is_idle(cqspi))
3058c2ecf20Sopenharmony_ci			count++;
3068c2ecf20Sopenharmony_ci		else
3078c2ecf20Sopenharmony_ci			count = 0;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci		if (count >= poll_idle_retry)
3108c2ecf20Sopenharmony_ci			return 0;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci		if (time_after(jiffies, timeout)) {
3138c2ecf20Sopenharmony_ci			/* Timeout, in busy mode. */
3148c2ecf20Sopenharmony_ci			dev_err(&cqspi->pdev->dev,
3158c2ecf20Sopenharmony_ci				"QSPI is still busy after %dms timeout.\n",
3168c2ecf20Sopenharmony_ci				CQSPI_TIMEOUT_MS);
3178c2ecf20Sopenharmony_ci			return -ETIMEDOUT;
3188c2ecf20Sopenharmony_ci		}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci		cpu_relax();
3218c2ecf20Sopenharmony_ci	}
3228c2ecf20Sopenharmony_ci}
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_cistatic int cqspi_exec_flash_cmd(struct cqspi_st *cqspi, unsigned int reg)
3258c2ecf20Sopenharmony_ci{
3268c2ecf20Sopenharmony_ci	void __iomem *reg_base = cqspi->iobase;
3278c2ecf20Sopenharmony_ci	int ret;
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	/* Write the CMDCTRL without start execution. */
3308c2ecf20Sopenharmony_ci	writel(reg, reg_base + CQSPI_REG_CMDCTRL);
3318c2ecf20Sopenharmony_ci	/* Start execute */
3328c2ecf20Sopenharmony_ci	reg |= CQSPI_REG_CMDCTRL_EXECUTE_MASK;
3338c2ecf20Sopenharmony_ci	writel(reg, reg_base + CQSPI_REG_CMDCTRL);
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	/* Polling for completion. */
3368c2ecf20Sopenharmony_ci	ret = cqspi_wait_for_bit(reg_base + CQSPI_REG_CMDCTRL,
3378c2ecf20Sopenharmony_ci				 CQSPI_REG_CMDCTRL_INPROGRESS_MASK, 1);
3388c2ecf20Sopenharmony_ci	if (ret) {
3398c2ecf20Sopenharmony_ci		dev_err(&cqspi->pdev->dev,
3408c2ecf20Sopenharmony_ci			"Flash command execution timed out.\n");
3418c2ecf20Sopenharmony_ci		return ret;
3428c2ecf20Sopenharmony_ci	}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	/* Polling QSPI idle status. */
3458c2ecf20Sopenharmony_ci	return cqspi_wait_idle(cqspi);
3468c2ecf20Sopenharmony_ci}
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_cistatic int cqspi_command_read(struct cqspi_flash_pdata *f_pdata,
3498c2ecf20Sopenharmony_ci			      const struct spi_mem_op *op)
3508c2ecf20Sopenharmony_ci{
3518c2ecf20Sopenharmony_ci	struct cqspi_st *cqspi = f_pdata->cqspi;
3528c2ecf20Sopenharmony_ci	void __iomem *reg_base = cqspi->iobase;
3538c2ecf20Sopenharmony_ci	u8 *rxbuf = op->data.buf.in;
3548c2ecf20Sopenharmony_ci	u8 opcode = op->cmd.opcode;
3558c2ecf20Sopenharmony_ci	size_t n_rx = op->data.nbytes;
3568c2ecf20Sopenharmony_ci	unsigned int rdreg;
3578c2ecf20Sopenharmony_ci	unsigned int reg;
3588c2ecf20Sopenharmony_ci	size_t read_len;
3598c2ecf20Sopenharmony_ci	int status;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	if (!n_rx || n_rx > CQSPI_STIG_DATA_LEN_MAX || !rxbuf) {
3628c2ecf20Sopenharmony_ci		dev_err(&cqspi->pdev->dev,
3638c2ecf20Sopenharmony_ci			"Invalid input argument, len %zu rxbuf 0x%p\n",
3648c2ecf20Sopenharmony_ci			n_rx, rxbuf);
3658c2ecf20Sopenharmony_ci		return -EINVAL;
3668c2ecf20Sopenharmony_ci	}
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	reg = opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	rdreg = cqspi_calc_rdreg(f_pdata);
3718c2ecf20Sopenharmony_ci	writel(rdreg, reg_base + CQSPI_REG_RD_INSTR);
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	reg |= (0x1 << CQSPI_REG_CMDCTRL_RD_EN_LSB);
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	/* 0 means 1 byte. */
3768c2ecf20Sopenharmony_ci	reg |= (((n_rx - 1) & CQSPI_REG_CMDCTRL_RD_BYTES_MASK)
3778c2ecf20Sopenharmony_ci		<< CQSPI_REG_CMDCTRL_RD_BYTES_LSB);
3788c2ecf20Sopenharmony_ci	status = cqspi_exec_flash_cmd(cqspi, reg);
3798c2ecf20Sopenharmony_ci	if (status)
3808c2ecf20Sopenharmony_ci		return status;
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	reg = readl(reg_base + CQSPI_REG_CMDREADDATALOWER);
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	/* Put the read value into rx_buf */
3858c2ecf20Sopenharmony_ci	read_len = (n_rx > 4) ? 4 : n_rx;
3868c2ecf20Sopenharmony_ci	memcpy(rxbuf, &reg, read_len);
3878c2ecf20Sopenharmony_ci	rxbuf += read_len;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	if (n_rx > 4) {
3908c2ecf20Sopenharmony_ci		reg = readl(reg_base + CQSPI_REG_CMDREADDATAUPPER);
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci		read_len = n_rx - read_len;
3938c2ecf20Sopenharmony_ci		memcpy(rxbuf, &reg, read_len);
3948c2ecf20Sopenharmony_ci	}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	return 0;
3978c2ecf20Sopenharmony_ci}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_cistatic int cqspi_command_write(struct cqspi_flash_pdata *f_pdata,
4008c2ecf20Sopenharmony_ci			       const struct spi_mem_op *op)
4018c2ecf20Sopenharmony_ci{
4028c2ecf20Sopenharmony_ci	struct cqspi_st *cqspi = f_pdata->cqspi;
4038c2ecf20Sopenharmony_ci	void __iomem *reg_base = cqspi->iobase;
4048c2ecf20Sopenharmony_ci	const u8 opcode = op->cmd.opcode;
4058c2ecf20Sopenharmony_ci	const u8 *txbuf = op->data.buf.out;
4068c2ecf20Sopenharmony_ci	size_t n_tx = op->data.nbytes;
4078c2ecf20Sopenharmony_ci	unsigned int reg;
4088c2ecf20Sopenharmony_ci	unsigned int data;
4098c2ecf20Sopenharmony_ci	size_t write_len;
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	if (n_tx > CQSPI_STIG_DATA_LEN_MAX || (n_tx && !txbuf)) {
4128c2ecf20Sopenharmony_ci		dev_err(&cqspi->pdev->dev,
4138c2ecf20Sopenharmony_ci			"Invalid input argument, cmdlen %zu txbuf 0x%p\n",
4148c2ecf20Sopenharmony_ci			n_tx, txbuf);
4158c2ecf20Sopenharmony_ci		return -EINVAL;
4168c2ecf20Sopenharmony_ci	}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	reg = opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB;
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	if (op->addr.nbytes) {
4218c2ecf20Sopenharmony_ci		reg |= (0x1 << CQSPI_REG_CMDCTRL_ADDR_EN_LSB);
4228c2ecf20Sopenharmony_ci		reg |= ((op->addr.nbytes - 1) &
4238c2ecf20Sopenharmony_ci			CQSPI_REG_CMDCTRL_ADD_BYTES_MASK)
4248c2ecf20Sopenharmony_ci			<< CQSPI_REG_CMDCTRL_ADD_BYTES_LSB;
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci		writel(op->addr.val, reg_base + CQSPI_REG_CMDADDRESS);
4278c2ecf20Sopenharmony_ci	}
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	if (n_tx) {
4308c2ecf20Sopenharmony_ci		reg |= (0x1 << CQSPI_REG_CMDCTRL_WR_EN_LSB);
4318c2ecf20Sopenharmony_ci		reg |= ((n_tx - 1) & CQSPI_REG_CMDCTRL_WR_BYTES_MASK)
4328c2ecf20Sopenharmony_ci			<< CQSPI_REG_CMDCTRL_WR_BYTES_LSB;
4338c2ecf20Sopenharmony_ci		data = 0;
4348c2ecf20Sopenharmony_ci		write_len = (n_tx > 4) ? 4 : n_tx;
4358c2ecf20Sopenharmony_ci		memcpy(&data, txbuf, write_len);
4368c2ecf20Sopenharmony_ci		txbuf += write_len;
4378c2ecf20Sopenharmony_ci		writel(data, reg_base + CQSPI_REG_CMDWRITEDATALOWER);
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci		if (n_tx > 4) {
4408c2ecf20Sopenharmony_ci			data = 0;
4418c2ecf20Sopenharmony_ci			write_len = n_tx - 4;
4428c2ecf20Sopenharmony_ci			memcpy(&data, txbuf, write_len);
4438c2ecf20Sopenharmony_ci			writel(data, reg_base + CQSPI_REG_CMDWRITEDATAUPPER);
4448c2ecf20Sopenharmony_ci		}
4458c2ecf20Sopenharmony_ci	}
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	return cqspi_exec_flash_cmd(cqspi, reg);
4488c2ecf20Sopenharmony_ci}
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_cistatic int cqspi_read_setup(struct cqspi_flash_pdata *f_pdata,
4518c2ecf20Sopenharmony_ci			    const struct spi_mem_op *op)
4528c2ecf20Sopenharmony_ci{
4538c2ecf20Sopenharmony_ci	struct cqspi_st *cqspi = f_pdata->cqspi;
4548c2ecf20Sopenharmony_ci	void __iomem *reg_base = cqspi->iobase;
4558c2ecf20Sopenharmony_ci	unsigned int dummy_clk = 0;
4568c2ecf20Sopenharmony_ci	unsigned int reg;
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	reg = op->cmd.opcode << CQSPI_REG_RD_INSTR_OPCODE_LSB;
4598c2ecf20Sopenharmony_ci	reg |= cqspi_calc_rdreg(f_pdata);
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	/* Setup dummy clock cycles */
4628c2ecf20Sopenharmony_ci	dummy_clk = op->dummy.nbytes * 8;
4638c2ecf20Sopenharmony_ci	if (dummy_clk > CQSPI_DUMMY_CLKS_MAX)
4648c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	if (dummy_clk)
4678c2ecf20Sopenharmony_ci		reg |= (dummy_clk & CQSPI_REG_RD_INSTR_DUMMY_MASK)
4688c2ecf20Sopenharmony_ci		       << CQSPI_REG_RD_INSTR_DUMMY_LSB;
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	writel(reg, reg_base + CQSPI_REG_RD_INSTR);
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	/* Set address width */
4738c2ecf20Sopenharmony_ci	reg = readl(reg_base + CQSPI_REG_SIZE);
4748c2ecf20Sopenharmony_ci	reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK;
4758c2ecf20Sopenharmony_ci	reg |= (op->addr.nbytes - 1);
4768c2ecf20Sopenharmony_ci	writel(reg, reg_base + CQSPI_REG_SIZE);
4778c2ecf20Sopenharmony_ci	return 0;
4788c2ecf20Sopenharmony_ci}
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_cistatic int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata,
4818c2ecf20Sopenharmony_ci				       u8 *rxbuf, loff_t from_addr,
4828c2ecf20Sopenharmony_ci				       const size_t n_rx)
4838c2ecf20Sopenharmony_ci{
4848c2ecf20Sopenharmony_ci	struct cqspi_st *cqspi = f_pdata->cqspi;
4858c2ecf20Sopenharmony_ci	struct device *dev = &cqspi->pdev->dev;
4868c2ecf20Sopenharmony_ci	void __iomem *reg_base = cqspi->iobase;
4878c2ecf20Sopenharmony_ci	void __iomem *ahb_base = cqspi->ahb_base;
4888c2ecf20Sopenharmony_ci	unsigned int remaining = n_rx;
4898c2ecf20Sopenharmony_ci	unsigned int mod_bytes = n_rx % 4;
4908c2ecf20Sopenharmony_ci	unsigned int bytes_to_read = 0;
4918c2ecf20Sopenharmony_ci	u8 *rxbuf_end = rxbuf + n_rx;
4928c2ecf20Sopenharmony_ci	int ret = 0;
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	writel(from_addr, reg_base + CQSPI_REG_INDIRECTRDSTARTADDR);
4958c2ecf20Sopenharmony_ci	writel(remaining, reg_base + CQSPI_REG_INDIRECTRDBYTES);
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	/* Clear all interrupts. */
4988c2ecf20Sopenharmony_ci	writel(CQSPI_IRQ_STATUS_MASK, reg_base + CQSPI_REG_IRQSTATUS);
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	writel(CQSPI_IRQ_MASK_RD, reg_base + CQSPI_REG_IRQMASK);
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	reinit_completion(&cqspi->transfer_complete);
5038c2ecf20Sopenharmony_ci	writel(CQSPI_REG_INDIRECTRD_START_MASK,
5048c2ecf20Sopenharmony_ci	       reg_base + CQSPI_REG_INDIRECTRD);
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	while (remaining > 0) {
5078c2ecf20Sopenharmony_ci		if (!wait_for_completion_timeout(&cqspi->transfer_complete,
5088c2ecf20Sopenharmony_ci						 msecs_to_jiffies(CQSPI_READ_TIMEOUT_MS)))
5098c2ecf20Sopenharmony_ci			ret = -ETIMEDOUT;
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci		bytes_to_read = cqspi_get_rd_sram_level(cqspi);
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci		if (ret && bytes_to_read == 0) {
5148c2ecf20Sopenharmony_ci			dev_err(dev, "Indirect read timeout, no bytes\n");
5158c2ecf20Sopenharmony_ci			goto failrd;
5168c2ecf20Sopenharmony_ci		}
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci		while (bytes_to_read != 0) {
5198c2ecf20Sopenharmony_ci			unsigned int word_remain = round_down(remaining, 4);
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci			bytes_to_read *= cqspi->fifo_width;
5228c2ecf20Sopenharmony_ci			bytes_to_read = bytes_to_read > remaining ?
5238c2ecf20Sopenharmony_ci					remaining : bytes_to_read;
5248c2ecf20Sopenharmony_ci			bytes_to_read = round_down(bytes_to_read, 4);
5258c2ecf20Sopenharmony_ci			/* Read 4 byte word chunks then single bytes */
5268c2ecf20Sopenharmony_ci			if (bytes_to_read) {
5278c2ecf20Sopenharmony_ci				ioread32_rep(ahb_base, rxbuf,
5288c2ecf20Sopenharmony_ci					     (bytes_to_read / 4));
5298c2ecf20Sopenharmony_ci			} else if (!word_remain && mod_bytes) {
5308c2ecf20Sopenharmony_ci				unsigned int temp = ioread32(ahb_base);
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci				bytes_to_read = mod_bytes;
5338c2ecf20Sopenharmony_ci				memcpy(rxbuf, &temp, min((unsigned int)
5348c2ecf20Sopenharmony_ci							 (rxbuf_end - rxbuf),
5358c2ecf20Sopenharmony_ci							 bytes_to_read));
5368c2ecf20Sopenharmony_ci			}
5378c2ecf20Sopenharmony_ci			rxbuf += bytes_to_read;
5388c2ecf20Sopenharmony_ci			remaining -= bytes_to_read;
5398c2ecf20Sopenharmony_ci			bytes_to_read = cqspi_get_rd_sram_level(cqspi);
5408c2ecf20Sopenharmony_ci		}
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci		if (remaining > 0)
5438c2ecf20Sopenharmony_ci			reinit_completion(&cqspi->transfer_complete);
5448c2ecf20Sopenharmony_ci	}
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	/* Check indirect done status */
5478c2ecf20Sopenharmony_ci	ret = cqspi_wait_for_bit(reg_base + CQSPI_REG_INDIRECTRD,
5488c2ecf20Sopenharmony_ci				 CQSPI_REG_INDIRECTRD_DONE_MASK, 0);
5498c2ecf20Sopenharmony_ci	if (ret) {
5508c2ecf20Sopenharmony_ci		dev_err(dev, "Indirect read completion error (%i)\n", ret);
5518c2ecf20Sopenharmony_ci		goto failrd;
5528c2ecf20Sopenharmony_ci	}
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	/* Disable interrupt */
5558c2ecf20Sopenharmony_ci	writel(0, reg_base + CQSPI_REG_IRQMASK);
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	/* Clear indirect completion status */
5588c2ecf20Sopenharmony_ci	writel(CQSPI_REG_INDIRECTRD_DONE_MASK, reg_base + CQSPI_REG_INDIRECTRD);
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	return 0;
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_cifailrd:
5638c2ecf20Sopenharmony_ci	/* Disable interrupt */
5648c2ecf20Sopenharmony_ci	writel(0, reg_base + CQSPI_REG_IRQMASK);
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	/* Cancel the indirect read */
5678c2ecf20Sopenharmony_ci	writel(CQSPI_REG_INDIRECTWR_CANCEL_MASK,
5688c2ecf20Sopenharmony_ci	       reg_base + CQSPI_REG_INDIRECTRD);
5698c2ecf20Sopenharmony_ci	return ret;
5708c2ecf20Sopenharmony_ci}
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_cistatic int cqspi_write_setup(struct cqspi_flash_pdata *f_pdata,
5738c2ecf20Sopenharmony_ci			     const struct spi_mem_op *op)
5748c2ecf20Sopenharmony_ci{
5758c2ecf20Sopenharmony_ci	unsigned int reg;
5768c2ecf20Sopenharmony_ci	struct cqspi_st *cqspi = f_pdata->cqspi;
5778c2ecf20Sopenharmony_ci	void __iomem *reg_base = cqspi->iobase;
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	/* Set opcode. */
5808c2ecf20Sopenharmony_ci	reg = op->cmd.opcode << CQSPI_REG_WR_INSTR_OPCODE_LSB;
5818c2ecf20Sopenharmony_ci	writel(reg, reg_base + CQSPI_REG_WR_INSTR);
5828c2ecf20Sopenharmony_ci	reg = cqspi_calc_rdreg(f_pdata);
5838c2ecf20Sopenharmony_ci	writel(reg, reg_base + CQSPI_REG_RD_INSTR);
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	reg = readl(reg_base + CQSPI_REG_SIZE);
5868c2ecf20Sopenharmony_ci	reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK;
5878c2ecf20Sopenharmony_ci	reg |= (op->addr.nbytes - 1);
5888c2ecf20Sopenharmony_ci	writel(reg, reg_base + CQSPI_REG_SIZE);
5898c2ecf20Sopenharmony_ci	return 0;
5908c2ecf20Sopenharmony_ci}
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_cistatic int cqspi_indirect_write_execute(struct cqspi_flash_pdata *f_pdata,
5938c2ecf20Sopenharmony_ci					loff_t to_addr, const u8 *txbuf,
5948c2ecf20Sopenharmony_ci					const size_t n_tx)
5958c2ecf20Sopenharmony_ci{
5968c2ecf20Sopenharmony_ci	struct cqspi_st *cqspi = f_pdata->cqspi;
5978c2ecf20Sopenharmony_ci	struct device *dev = &cqspi->pdev->dev;
5988c2ecf20Sopenharmony_ci	void __iomem *reg_base = cqspi->iobase;
5998c2ecf20Sopenharmony_ci	unsigned int remaining = n_tx;
6008c2ecf20Sopenharmony_ci	unsigned int write_bytes;
6018c2ecf20Sopenharmony_ci	int ret;
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	writel(to_addr, reg_base + CQSPI_REG_INDIRECTWRSTARTADDR);
6048c2ecf20Sopenharmony_ci	writel(remaining, reg_base + CQSPI_REG_INDIRECTWRBYTES);
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	/* Clear all interrupts. */
6078c2ecf20Sopenharmony_ci	writel(CQSPI_IRQ_STATUS_MASK, reg_base + CQSPI_REG_IRQSTATUS);
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	writel(CQSPI_IRQ_MASK_WR, reg_base + CQSPI_REG_IRQMASK);
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	reinit_completion(&cqspi->transfer_complete);
6128c2ecf20Sopenharmony_ci	writel(CQSPI_REG_INDIRECTWR_START_MASK,
6138c2ecf20Sopenharmony_ci	       reg_base + CQSPI_REG_INDIRECTWR);
6148c2ecf20Sopenharmony_ci	/*
6158c2ecf20Sopenharmony_ci	 * As per 66AK2G02 TRM SPRUHY8F section 11.15.5.3 Indirect Access
6168c2ecf20Sopenharmony_ci	 * Controller programming sequence, couple of cycles of
6178c2ecf20Sopenharmony_ci	 * QSPI_REF_CLK delay is required for the above bit to
6188c2ecf20Sopenharmony_ci	 * be internally synchronized by the QSPI module. Provide 5
6198c2ecf20Sopenharmony_ci	 * cycles of delay.
6208c2ecf20Sopenharmony_ci	 */
6218c2ecf20Sopenharmony_ci	if (cqspi->wr_delay)
6228c2ecf20Sopenharmony_ci		ndelay(cqspi->wr_delay);
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	while (remaining > 0) {
6258c2ecf20Sopenharmony_ci		size_t write_words, mod_bytes;
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci		write_bytes = remaining;
6288c2ecf20Sopenharmony_ci		write_words = write_bytes / 4;
6298c2ecf20Sopenharmony_ci		mod_bytes = write_bytes % 4;
6308c2ecf20Sopenharmony_ci		/* Write 4 bytes at a time then single bytes. */
6318c2ecf20Sopenharmony_ci		if (write_words) {
6328c2ecf20Sopenharmony_ci			iowrite32_rep(cqspi->ahb_base, txbuf, write_words);
6338c2ecf20Sopenharmony_ci			txbuf += (write_words * 4);
6348c2ecf20Sopenharmony_ci		}
6358c2ecf20Sopenharmony_ci		if (mod_bytes) {
6368c2ecf20Sopenharmony_ci			unsigned int temp = 0xFFFFFFFF;
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci			memcpy(&temp, txbuf, mod_bytes);
6398c2ecf20Sopenharmony_ci			iowrite32(temp, cqspi->ahb_base);
6408c2ecf20Sopenharmony_ci			txbuf += mod_bytes;
6418c2ecf20Sopenharmony_ci		}
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci		if (!wait_for_completion_timeout(&cqspi->transfer_complete,
6448c2ecf20Sopenharmony_ci						 msecs_to_jiffies(CQSPI_TIMEOUT_MS))) {
6458c2ecf20Sopenharmony_ci			dev_err(dev, "Indirect write timeout\n");
6468c2ecf20Sopenharmony_ci			ret = -ETIMEDOUT;
6478c2ecf20Sopenharmony_ci			goto failwr;
6488c2ecf20Sopenharmony_ci		}
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci		remaining -= write_bytes;
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci		if (remaining > 0)
6538c2ecf20Sopenharmony_ci			reinit_completion(&cqspi->transfer_complete);
6548c2ecf20Sopenharmony_ci	}
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	/* Check indirect done status */
6578c2ecf20Sopenharmony_ci	ret = cqspi_wait_for_bit(reg_base + CQSPI_REG_INDIRECTWR,
6588c2ecf20Sopenharmony_ci				 CQSPI_REG_INDIRECTWR_DONE_MASK, 0);
6598c2ecf20Sopenharmony_ci	if (ret) {
6608c2ecf20Sopenharmony_ci		dev_err(dev, "Indirect write completion error (%i)\n", ret);
6618c2ecf20Sopenharmony_ci		goto failwr;
6628c2ecf20Sopenharmony_ci	}
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci	/* Disable interrupt. */
6658c2ecf20Sopenharmony_ci	writel(0, reg_base + CQSPI_REG_IRQMASK);
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	/* Clear indirect completion status */
6688c2ecf20Sopenharmony_ci	writel(CQSPI_REG_INDIRECTWR_DONE_MASK, reg_base + CQSPI_REG_INDIRECTWR);
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	cqspi_wait_idle(cqspi);
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	return 0;
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_cifailwr:
6758c2ecf20Sopenharmony_ci	/* Disable interrupt. */
6768c2ecf20Sopenharmony_ci	writel(0, reg_base + CQSPI_REG_IRQMASK);
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci	/* Cancel the indirect write */
6798c2ecf20Sopenharmony_ci	writel(CQSPI_REG_INDIRECTWR_CANCEL_MASK,
6808c2ecf20Sopenharmony_ci	       reg_base + CQSPI_REG_INDIRECTWR);
6818c2ecf20Sopenharmony_ci	return ret;
6828c2ecf20Sopenharmony_ci}
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_cistatic void cqspi_chipselect(struct cqspi_flash_pdata *f_pdata)
6858c2ecf20Sopenharmony_ci{
6868c2ecf20Sopenharmony_ci	struct cqspi_st *cqspi = f_pdata->cqspi;
6878c2ecf20Sopenharmony_ci	void __iomem *reg_base = cqspi->iobase;
6888c2ecf20Sopenharmony_ci	unsigned int chip_select = f_pdata->cs;
6898c2ecf20Sopenharmony_ci	unsigned int reg;
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	reg = readl(reg_base + CQSPI_REG_CONFIG);
6928c2ecf20Sopenharmony_ci	if (cqspi->is_decoded_cs) {
6938c2ecf20Sopenharmony_ci		reg |= CQSPI_REG_CONFIG_DECODE_MASK;
6948c2ecf20Sopenharmony_ci	} else {
6958c2ecf20Sopenharmony_ci		reg &= ~CQSPI_REG_CONFIG_DECODE_MASK;
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci		/* Convert CS if without decoder.
6988c2ecf20Sopenharmony_ci		 * CS0 to 4b'1110
6998c2ecf20Sopenharmony_ci		 * CS1 to 4b'1101
7008c2ecf20Sopenharmony_ci		 * CS2 to 4b'1011
7018c2ecf20Sopenharmony_ci		 * CS3 to 4b'0111
7028c2ecf20Sopenharmony_ci		 */
7038c2ecf20Sopenharmony_ci		chip_select = 0xF & ~(1 << chip_select);
7048c2ecf20Sopenharmony_ci	}
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	reg &= ~(CQSPI_REG_CONFIG_CHIPSELECT_MASK
7078c2ecf20Sopenharmony_ci		 << CQSPI_REG_CONFIG_CHIPSELECT_LSB);
7088c2ecf20Sopenharmony_ci	reg |= (chip_select & CQSPI_REG_CONFIG_CHIPSELECT_MASK)
7098c2ecf20Sopenharmony_ci	    << CQSPI_REG_CONFIG_CHIPSELECT_LSB;
7108c2ecf20Sopenharmony_ci	writel(reg, reg_base + CQSPI_REG_CONFIG);
7118c2ecf20Sopenharmony_ci}
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_cistatic unsigned int calculate_ticks_for_ns(const unsigned int ref_clk_hz,
7148c2ecf20Sopenharmony_ci					   const unsigned int ns_val)
7158c2ecf20Sopenharmony_ci{
7168c2ecf20Sopenharmony_ci	unsigned int ticks;
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	ticks = ref_clk_hz / 1000;	/* kHz */
7198c2ecf20Sopenharmony_ci	ticks = DIV_ROUND_UP(ticks * ns_val, 1000000);
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	return ticks;
7228c2ecf20Sopenharmony_ci}
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_cistatic void cqspi_delay(struct cqspi_flash_pdata *f_pdata)
7258c2ecf20Sopenharmony_ci{
7268c2ecf20Sopenharmony_ci	struct cqspi_st *cqspi = f_pdata->cqspi;
7278c2ecf20Sopenharmony_ci	void __iomem *iobase = cqspi->iobase;
7288c2ecf20Sopenharmony_ci	const unsigned int ref_clk_hz = cqspi->master_ref_clk_hz;
7298c2ecf20Sopenharmony_ci	unsigned int tshsl, tchsh, tslch, tsd2d;
7308c2ecf20Sopenharmony_ci	unsigned int reg;
7318c2ecf20Sopenharmony_ci	unsigned int tsclk;
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci	/* calculate the number of ref ticks for one sclk tick */
7348c2ecf20Sopenharmony_ci	tsclk = DIV_ROUND_UP(ref_clk_hz, cqspi->sclk);
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	tshsl = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tshsl_ns);
7378c2ecf20Sopenharmony_ci	/* this particular value must be at least one sclk */
7388c2ecf20Sopenharmony_ci	if (tshsl < tsclk)
7398c2ecf20Sopenharmony_ci		tshsl = tsclk;
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci	tchsh = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tchsh_ns);
7428c2ecf20Sopenharmony_ci	tslch = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tslch_ns);
7438c2ecf20Sopenharmony_ci	tsd2d = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tsd2d_ns);
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci	reg = (tshsl & CQSPI_REG_DELAY_TSHSL_MASK)
7468c2ecf20Sopenharmony_ci	       << CQSPI_REG_DELAY_TSHSL_LSB;
7478c2ecf20Sopenharmony_ci	reg |= (tchsh & CQSPI_REG_DELAY_TCHSH_MASK)
7488c2ecf20Sopenharmony_ci		<< CQSPI_REG_DELAY_TCHSH_LSB;
7498c2ecf20Sopenharmony_ci	reg |= (tslch & CQSPI_REG_DELAY_TSLCH_MASK)
7508c2ecf20Sopenharmony_ci		<< CQSPI_REG_DELAY_TSLCH_LSB;
7518c2ecf20Sopenharmony_ci	reg |= (tsd2d & CQSPI_REG_DELAY_TSD2D_MASK)
7528c2ecf20Sopenharmony_ci		<< CQSPI_REG_DELAY_TSD2D_LSB;
7538c2ecf20Sopenharmony_ci	writel(reg, iobase + CQSPI_REG_DELAY);
7548c2ecf20Sopenharmony_ci}
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_cistatic void cqspi_config_baudrate_div(struct cqspi_st *cqspi)
7578c2ecf20Sopenharmony_ci{
7588c2ecf20Sopenharmony_ci	const unsigned int ref_clk_hz = cqspi->master_ref_clk_hz;
7598c2ecf20Sopenharmony_ci	void __iomem *reg_base = cqspi->iobase;
7608c2ecf20Sopenharmony_ci	u32 reg, div;
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	/* Recalculate the baudrate divisor based on QSPI specification. */
7638c2ecf20Sopenharmony_ci	div = DIV_ROUND_UP(ref_clk_hz, 2 * cqspi->sclk) - 1;
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci	reg = readl(reg_base + CQSPI_REG_CONFIG);
7668c2ecf20Sopenharmony_ci	reg &= ~(CQSPI_REG_CONFIG_BAUD_MASK << CQSPI_REG_CONFIG_BAUD_LSB);
7678c2ecf20Sopenharmony_ci	reg |= (div & CQSPI_REG_CONFIG_BAUD_MASK) << CQSPI_REG_CONFIG_BAUD_LSB;
7688c2ecf20Sopenharmony_ci	writel(reg, reg_base + CQSPI_REG_CONFIG);
7698c2ecf20Sopenharmony_ci}
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_cistatic void cqspi_readdata_capture(struct cqspi_st *cqspi,
7728c2ecf20Sopenharmony_ci				   const bool bypass,
7738c2ecf20Sopenharmony_ci				   const unsigned int delay)
7748c2ecf20Sopenharmony_ci{
7758c2ecf20Sopenharmony_ci	void __iomem *reg_base = cqspi->iobase;
7768c2ecf20Sopenharmony_ci	unsigned int reg;
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	reg = readl(reg_base + CQSPI_REG_READCAPTURE);
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	if (bypass)
7818c2ecf20Sopenharmony_ci		reg |= (1 << CQSPI_REG_READCAPTURE_BYPASS_LSB);
7828c2ecf20Sopenharmony_ci	else
7838c2ecf20Sopenharmony_ci		reg &= ~(1 << CQSPI_REG_READCAPTURE_BYPASS_LSB);
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ci	reg &= ~(CQSPI_REG_READCAPTURE_DELAY_MASK
7868c2ecf20Sopenharmony_ci		 << CQSPI_REG_READCAPTURE_DELAY_LSB);
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci	reg |= (delay & CQSPI_REG_READCAPTURE_DELAY_MASK)
7898c2ecf20Sopenharmony_ci		<< CQSPI_REG_READCAPTURE_DELAY_LSB;
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci	writel(reg, reg_base + CQSPI_REG_READCAPTURE);
7928c2ecf20Sopenharmony_ci}
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_cistatic void cqspi_controller_enable(struct cqspi_st *cqspi, bool enable)
7958c2ecf20Sopenharmony_ci{
7968c2ecf20Sopenharmony_ci	void __iomem *reg_base = cqspi->iobase;
7978c2ecf20Sopenharmony_ci	unsigned int reg;
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	reg = readl(reg_base + CQSPI_REG_CONFIG);
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci	if (enable)
8028c2ecf20Sopenharmony_ci		reg |= CQSPI_REG_CONFIG_ENABLE_MASK;
8038c2ecf20Sopenharmony_ci	else
8048c2ecf20Sopenharmony_ci		reg &= ~CQSPI_REG_CONFIG_ENABLE_MASK;
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	writel(reg, reg_base + CQSPI_REG_CONFIG);
8078c2ecf20Sopenharmony_ci}
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_cistatic void cqspi_configure(struct cqspi_flash_pdata *f_pdata,
8108c2ecf20Sopenharmony_ci			    unsigned long sclk)
8118c2ecf20Sopenharmony_ci{
8128c2ecf20Sopenharmony_ci	struct cqspi_st *cqspi = f_pdata->cqspi;
8138c2ecf20Sopenharmony_ci	int switch_cs = (cqspi->current_cs != f_pdata->cs);
8148c2ecf20Sopenharmony_ci	int switch_ck = (cqspi->sclk != sclk);
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci	if (switch_cs || switch_ck)
8178c2ecf20Sopenharmony_ci		cqspi_controller_enable(cqspi, 0);
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci	/* Switch chip select. */
8208c2ecf20Sopenharmony_ci	if (switch_cs) {
8218c2ecf20Sopenharmony_ci		cqspi->current_cs = f_pdata->cs;
8228c2ecf20Sopenharmony_ci		cqspi_chipselect(f_pdata);
8238c2ecf20Sopenharmony_ci	}
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	/* Setup baudrate divisor and delays */
8268c2ecf20Sopenharmony_ci	if (switch_ck) {
8278c2ecf20Sopenharmony_ci		cqspi->sclk = sclk;
8288c2ecf20Sopenharmony_ci		cqspi_config_baudrate_div(cqspi);
8298c2ecf20Sopenharmony_ci		cqspi_delay(f_pdata);
8308c2ecf20Sopenharmony_ci		cqspi_readdata_capture(cqspi, !cqspi->rclk_en,
8318c2ecf20Sopenharmony_ci				       f_pdata->read_delay);
8328c2ecf20Sopenharmony_ci	}
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	if (switch_cs || switch_ck)
8358c2ecf20Sopenharmony_ci		cqspi_controller_enable(cqspi, 1);
8368c2ecf20Sopenharmony_ci}
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_cistatic int cqspi_set_protocol(struct cqspi_flash_pdata *f_pdata,
8398c2ecf20Sopenharmony_ci			      const struct spi_mem_op *op)
8408c2ecf20Sopenharmony_ci{
8418c2ecf20Sopenharmony_ci	f_pdata->inst_width = CQSPI_INST_TYPE_SINGLE;
8428c2ecf20Sopenharmony_ci	f_pdata->addr_width = CQSPI_INST_TYPE_SINGLE;
8438c2ecf20Sopenharmony_ci	f_pdata->data_width = CQSPI_INST_TYPE_SINGLE;
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	if (op->data.dir == SPI_MEM_DATA_IN) {
8468c2ecf20Sopenharmony_ci		switch (op->data.buswidth) {
8478c2ecf20Sopenharmony_ci		case 1:
8488c2ecf20Sopenharmony_ci			f_pdata->data_width = CQSPI_INST_TYPE_SINGLE;
8498c2ecf20Sopenharmony_ci			break;
8508c2ecf20Sopenharmony_ci		case 2:
8518c2ecf20Sopenharmony_ci			f_pdata->data_width = CQSPI_INST_TYPE_DUAL;
8528c2ecf20Sopenharmony_ci			break;
8538c2ecf20Sopenharmony_ci		case 4:
8548c2ecf20Sopenharmony_ci			f_pdata->data_width = CQSPI_INST_TYPE_QUAD;
8558c2ecf20Sopenharmony_ci			break;
8568c2ecf20Sopenharmony_ci		case 8:
8578c2ecf20Sopenharmony_ci			f_pdata->data_width = CQSPI_INST_TYPE_OCTAL;
8588c2ecf20Sopenharmony_ci			break;
8598c2ecf20Sopenharmony_ci		default:
8608c2ecf20Sopenharmony_ci			return -EINVAL;
8618c2ecf20Sopenharmony_ci		}
8628c2ecf20Sopenharmony_ci	}
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	return 0;
8658c2ecf20Sopenharmony_ci}
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_cistatic ssize_t cqspi_write(struct cqspi_flash_pdata *f_pdata,
8688c2ecf20Sopenharmony_ci			   const struct spi_mem_op *op)
8698c2ecf20Sopenharmony_ci{
8708c2ecf20Sopenharmony_ci	struct cqspi_st *cqspi = f_pdata->cqspi;
8718c2ecf20Sopenharmony_ci	loff_t to = op->addr.val;
8728c2ecf20Sopenharmony_ci	size_t len = op->data.nbytes;
8738c2ecf20Sopenharmony_ci	const u_char *buf = op->data.buf.out;
8748c2ecf20Sopenharmony_ci	int ret;
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci	ret = cqspi_set_protocol(f_pdata, op);
8778c2ecf20Sopenharmony_ci	if (ret)
8788c2ecf20Sopenharmony_ci		return ret;
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci	ret = cqspi_write_setup(f_pdata, op);
8818c2ecf20Sopenharmony_ci	if (ret)
8828c2ecf20Sopenharmony_ci		return ret;
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci	if (cqspi->use_direct_mode && ((to + len) <= cqspi->ahb_size)) {
8858c2ecf20Sopenharmony_ci		memcpy_toio(cqspi->ahb_base + to, buf, len);
8868c2ecf20Sopenharmony_ci		return cqspi_wait_idle(cqspi);
8878c2ecf20Sopenharmony_ci	}
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	return cqspi_indirect_write_execute(f_pdata, to, buf, len);
8908c2ecf20Sopenharmony_ci}
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_cistatic void cqspi_rx_dma_callback(void *param)
8938c2ecf20Sopenharmony_ci{
8948c2ecf20Sopenharmony_ci	struct cqspi_st *cqspi = param;
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci	complete(&cqspi->rx_dma_complete);
8978c2ecf20Sopenharmony_ci}
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_cistatic int cqspi_direct_read_execute(struct cqspi_flash_pdata *f_pdata,
9008c2ecf20Sopenharmony_ci				     u_char *buf, loff_t from, size_t len)
9018c2ecf20Sopenharmony_ci{
9028c2ecf20Sopenharmony_ci	struct cqspi_st *cqspi = f_pdata->cqspi;
9038c2ecf20Sopenharmony_ci	struct device *dev = &cqspi->pdev->dev;
9048c2ecf20Sopenharmony_ci	enum dma_ctrl_flags flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
9058c2ecf20Sopenharmony_ci	dma_addr_t dma_src = (dma_addr_t)cqspi->mmap_phys_base + from;
9068c2ecf20Sopenharmony_ci	int ret = 0;
9078c2ecf20Sopenharmony_ci	struct dma_async_tx_descriptor *tx;
9088c2ecf20Sopenharmony_ci	dma_cookie_t cookie;
9098c2ecf20Sopenharmony_ci	dma_addr_t dma_dst;
9108c2ecf20Sopenharmony_ci	struct device *ddev;
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	if (!cqspi->rx_chan || !virt_addr_valid(buf)) {
9138c2ecf20Sopenharmony_ci		memcpy_fromio(buf, cqspi->ahb_base + from, len);
9148c2ecf20Sopenharmony_ci		return 0;
9158c2ecf20Sopenharmony_ci	}
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_ci	ddev = cqspi->rx_chan->device->dev;
9188c2ecf20Sopenharmony_ci	dma_dst = dma_map_single(ddev, buf, len, DMA_FROM_DEVICE);
9198c2ecf20Sopenharmony_ci	if (dma_mapping_error(ddev, dma_dst)) {
9208c2ecf20Sopenharmony_ci		dev_err(dev, "dma mapping failed\n");
9218c2ecf20Sopenharmony_ci		return -ENOMEM;
9228c2ecf20Sopenharmony_ci	}
9238c2ecf20Sopenharmony_ci	tx = dmaengine_prep_dma_memcpy(cqspi->rx_chan, dma_dst, dma_src,
9248c2ecf20Sopenharmony_ci				       len, flags);
9258c2ecf20Sopenharmony_ci	if (!tx) {
9268c2ecf20Sopenharmony_ci		dev_err(dev, "device_prep_dma_memcpy error\n");
9278c2ecf20Sopenharmony_ci		ret = -EIO;
9288c2ecf20Sopenharmony_ci		goto err_unmap;
9298c2ecf20Sopenharmony_ci	}
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci	tx->callback = cqspi_rx_dma_callback;
9328c2ecf20Sopenharmony_ci	tx->callback_param = cqspi;
9338c2ecf20Sopenharmony_ci	cookie = tx->tx_submit(tx);
9348c2ecf20Sopenharmony_ci	reinit_completion(&cqspi->rx_dma_complete);
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	ret = dma_submit_error(cookie);
9378c2ecf20Sopenharmony_ci	if (ret) {
9388c2ecf20Sopenharmony_ci		dev_err(dev, "dma_submit_error %d\n", cookie);
9398c2ecf20Sopenharmony_ci		ret = -EIO;
9408c2ecf20Sopenharmony_ci		goto err_unmap;
9418c2ecf20Sopenharmony_ci	}
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	dma_async_issue_pending(cqspi->rx_chan);
9448c2ecf20Sopenharmony_ci	if (!wait_for_completion_timeout(&cqspi->rx_dma_complete,
9458c2ecf20Sopenharmony_ci					 msecs_to_jiffies(len))) {
9468c2ecf20Sopenharmony_ci		dmaengine_terminate_sync(cqspi->rx_chan);
9478c2ecf20Sopenharmony_ci		dev_err(dev, "DMA wait_for_completion_timeout\n");
9488c2ecf20Sopenharmony_ci		ret = -ETIMEDOUT;
9498c2ecf20Sopenharmony_ci		goto err_unmap;
9508c2ecf20Sopenharmony_ci	}
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_cierr_unmap:
9538c2ecf20Sopenharmony_ci	dma_unmap_single(ddev, dma_dst, len, DMA_FROM_DEVICE);
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci	return ret;
9568c2ecf20Sopenharmony_ci}
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_cistatic ssize_t cqspi_read(struct cqspi_flash_pdata *f_pdata,
9598c2ecf20Sopenharmony_ci			  const struct spi_mem_op *op)
9608c2ecf20Sopenharmony_ci{
9618c2ecf20Sopenharmony_ci	struct cqspi_st *cqspi = f_pdata->cqspi;
9628c2ecf20Sopenharmony_ci	loff_t from = op->addr.val;
9638c2ecf20Sopenharmony_ci	size_t len = op->data.nbytes;
9648c2ecf20Sopenharmony_ci	u_char *buf = op->data.buf.in;
9658c2ecf20Sopenharmony_ci	int ret;
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci	ret = cqspi_set_protocol(f_pdata, op);
9688c2ecf20Sopenharmony_ci	if (ret)
9698c2ecf20Sopenharmony_ci		return ret;
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci	ret = cqspi_read_setup(f_pdata, op);
9728c2ecf20Sopenharmony_ci	if (ret)
9738c2ecf20Sopenharmony_ci		return ret;
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	if (cqspi->use_direct_mode && ((from + len) <= cqspi->ahb_size))
9768c2ecf20Sopenharmony_ci		return cqspi_direct_read_execute(f_pdata, buf, from, len);
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci	return cqspi_indirect_read_execute(f_pdata, buf, from, len);
9798c2ecf20Sopenharmony_ci}
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_cistatic int cqspi_mem_process(struct spi_mem *mem, const struct spi_mem_op *op)
9828c2ecf20Sopenharmony_ci{
9838c2ecf20Sopenharmony_ci	struct cqspi_st *cqspi = spi_master_get_devdata(mem->spi->master);
9848c2ecf20Sopenharmony_ci	struct cqspi_flash_pdata *f_pdata;
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci	f_pdata = &cqspi->f_pdata[mem->spi->chip_select];
9878c2ecf20Sopenharmony_ci	cqspi_configure(f_pdata, mem->spi->max_speed_hz);
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci	if (op->data.dir == SPI_MEM_DATA_IN && op->data.buf.in) {
9908c2ecf20Sopenharmony_ci		if (!op->addr.nbytes)
9918c2ecf20Sopenharmony_ci			return cqspi_command_read(f_pdata, op);
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci		return cqspi_read(f_pdata, op);
9948c2ecf20Sopenharmony_ci	}
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci	if (!op->addr.nbytes || !op->data.buf.out)
9978c2ecf20Sopenharmony_ci		return cqspi_command_write(f_pdata, op);
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci	return cqspi_write(f_pdata, op);
10008c2ecf20Sopenharmony_ci}
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_cistatic int cqspi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op)
10038c2ecf20Sopenharmony_ci{
10048c2ecf20Sopenharmony_ci	int ret;
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_ci	ret = cqspi_mem_process(mem, op);
10078c2ecf20Sopenharmony_ci	if (ret)
10088c2ecf20Sopenharmony_ci		dev_err(&mem->spi->dev, "operation failed with %d\n", ret);
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci	return ret;
10118c2ecf20Sopenharmony_ci}
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_cistatic int cqspi_of_get_flash_pdata(struct platform_device *pdev,
10148c2ecf20Sopenharmony_ci				    struct cqspi_flash_pdata *f_pdata,
10158c2ecf20Sopenharmony_ci				    struct device_node *np)
10168c2ecf20Sopenharmony_ci{
10178c2ecf20Sopenharmony_ci	if (of_property_read_u32(np, "cdns,read-delay", &f_pdata->read_delay)) {
10188c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "couldn't determine read-delay\n");
10198c2ecf20Sopenharmony_ci		return -ENXIO;
10208c2ecf20Sopenharmony_ci	}
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_ci	if (of_property_read_u32(np, "cdns,tshsl-ns", &f_pdata->tshsl_ns)) {
10238c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "couldn't determine tshsl-ns\n");
10248c2ecf20Sopenharmony_ci		return -ENXIO;
10258c2ecf20Sopenharmony_ci	}
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci	if (of_property_read_u32(np, "cdns,tsd2d-ns", &f_pdata->tsd2d_ns)) {
10288c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "couldn't determine tsd2d-ns\n");
10298c2ecf20Sopenharmony_ci		return -ENXIO;
10308c2ecf20Sopenharmony_ci	}
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci	if (of_property_read_u32(np, "cdns,tchsh-ns", &f_pdata->tchsh_ns)) {
10338c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "couldn't determine tchsh-ns\n");
10348c2ecf20Sopenharmony_ci		return -ENXIO;
10358c2ecf20Sopenharmony_ci	}
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_ci	if (of_property_read_u32(np, "cdns,tslch-ns", &f_pdata->tslch_ns)) {
10388c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "couldn't determine tslch-ns\n");
10398c2ecf20Sopenharmony_ci		return -ENXIO;
10408c2ecf20Sopenharmony_ci	}
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_ci	if (of_property_read_u32(np, "spi-max-frequency", &f_pdata->clk_rate)) {
10438c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "couldn't determine spi-max-frequency\n");
10448c2ecf20Sopenharmony_ci		return -ENXIO;
10458c2ecf20Sopenharmony_ci	}
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci	return 0;
10488c2ecf20Sopenharmony_ci}
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_cistatic int cqspi_of_get_pdata(struct cqspi_st *cqspi)
10518c2ecf20Sopenharmony_ci{
10528c2ecf20Sopenharmony_ci	struct device *dev = &cqspi->pdev->dev;
10538c2ecf20Sopenharmony_ci	struct device_node *np = dev->of_node;
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci	cqspi->is_decoded_cs = of_property_read_bool(np, "cdns,is-decoded-cs");
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_ci	if (of_property_read_u32(np, "cdns,fifo-depth", &cqspi->fifo_depth)) {
10588c2ecf20Sopenharmony_ci		dev_err(dev, "couldn't determine fifo-depth\n");
10598c2ecf20Sopenharmony_ci		return -ENXIO;
10608c2ecf20Sopenharmony_ci	}
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_ci	if (of_property_read_u32(np, "cdns,fifo-width", &cqspi->fifo_width)) {
10638c2ecf20Sopenharmony_ci		dev_err(dev, "couldn't determine fifo-width\n");
10648c2ecf20Sopenharmony_ci		return -ENXIO;
10658c2ecf20Sopenharmony_ci	}
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci	if (of_property_read_u32(np, "cdns,trigger-address",
10688c2ecf20Sopenharmony_ci				 &cqspi->trigger_address)) {
10698c2ecf20Sopenharmony_ci		dev_err(dev, "couldn't determine trigger-address\n");
10708c2ecf20Sopenharmony_ci		return -ENXIO;
10718c2ecf20Sopenharmony_ci	}
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_ci	cqspi->rclk_en = of_property_read_bool(np, "cdns,rclk-en");
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_ci	return 0;
10768c2ecf20Sopenharmony_ci}
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_cistatic void cqspi_controller_init(struct cqspi_st *cqspi)
10798c2ecf20Sopenharmony_ci{
10808c2ecf20Sopenharmony_ci	u32 reg;
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_ci	cqspi_controller_enable(cqspi, 0);
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_ci	/* Configure the remap address register, no remap */
10858c2ecf20Sopenharmony_ci	writel(0, cqspi->iobase + CQSPI_REG_REMAP);
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci	/* Disable all interrupts. */
10888c2ecf20Sopenharmony_ci	writel(0, cqspi->iobase + CQSPI_REG_IRQMASK);
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci	/* Configure the SRAM split to 1:1 . */
10918c2ecf20Sopenharmony_ci	writel(cqspi->fifo_depth / 2, cqspi->iobase + CQSPI_REG_SRAMPARTITION);
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_ci	/* Load indirect trigger address. */
10948c2ecf20Sopenharmony_ci	writel(cqspi->trigger_address,
10958c2ecf20Sopenharmony_ci	       cqspi->iobase + CQSPI_REG_INDIRECTTRIGGER);
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci	/* Program read watermark -- 1/2 of the FIFO. */
10988c2ecf20Sopenharmony_ci	writel(cqspi->fifo_depth * cqspi->fifo_width / 2,
10998c2ecf20Sopenharmony_ci	       cqspi->iobase + CQSPI_REG_INDIRECTRDWATERMARK);
11008c2ecf20Sopenharmony_ci	/* Program write watermark -- 1/8 of the FIFO. */
11018c2ecf20Sopenharmony_ci	writel(cqspi->fifo_depth * cqspi->fifo_width / 8,
11028c2ecf20Sopenharmony_ci	       cqspi->iobase + CQSPI_REG_INDIRECTWRWATERMARK);
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_ci	/* Enable Direct Access Controller */
11058c2ecf20Sopenharmony_ci	reg = readl(cqspi->iobase + CQSPI_REG_CONFIG);
11068c2ecf20Sopenharmony_ci	reg |= CQSPI_REG_CONFIG_ENB_DIR_ACC_CTRL;
11078c2ecf20Sopenharmony_ci	writel(reg, cqspi->iobase + CQSPI_REG_CONFIG);
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_ci	cqspi_controller_enable(cqspi, 1);
11108c2ecf20Sopenharmony_ci}
11118c2ecf20Sopenharmony_ci
11128c2ecf20Sopenharmony_cistatic int cqspi_request_mmap_dma(struct cqspi_st *cqspi)
11138c2ecf20Sopenharmony_ci{
11148c2ecf20Sopenharmony_ci	dma_cap_mask_t mask;
11158c2ecf20Sopenharmony_ci
11168c2ecf20Sopenharmony_ci	dma_cap_zero(mask);
11178c2ecf20Sopenharmony_ci	dma_cap_set(DMA_MEMCPY, mask);
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_ci	cqspi->rx_chan = dma_request_chan_by_mask(&mask);
11208c2ecf20Sopenharmony_ci	if (IS_ERR(cqspi->rx_chan)) {
11218c2ecf20Sopenharmony_ci		int ret = PTR_ERR(cqspi->rx_chan);
11228c2ecf20Sopenharmony_ci		cqspi->rx_chan = NULL;
11238c2ecf20Sopenharmony_ci		return dev_err_probe(&cqspi->pdev->dev, ret, "No Rx DMA available\n");
11248c2ecf20Sopenharmony_ci	}
11258c2ecf20Sopenharmony_ci	init_completion(&cqspi->rx_dma_complete);
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_ci	return 0;
11288c2ecf20Sopenharmony_ci}
11298c2ecf20Sopenharmony_ci
11308c2ecf20Sopenharmony_cistatic const char *cqspi_get_name(struct spi_mem *mem)
11318c2ecf20Sopenharmony_ci{
11328c2ecf20Sopenharmony_ci	struct cqspi_st *cqspi = spi_master_get_devdata(mem->spi->master);
11338c2ecf20Sopenharmony_ci	struct device *dev = &cqspi->pdev->dev;
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci	return devm_kasprintf(dev, GFP_KERNEL, "%s.%d", dev_name(dev), mem->spi->chip_select);
11368c2ecf20Sopenharmony_ci}
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_cistatic const struct spi_controller_mem_ops cqspi_mem_ops = {
11398c2ecf20Sopenharmony_ci	.exec_op = cqspi_exec_mem_op,
11408c2ecf20Sopenharmony_ci	.get_name = cqspi_get_name,
11418c2ecf20Sopenharmony_ci};
11428c2ecf20Sopenharmony_ci
11438c2ecf20Sopenharmony_cistatic int cqspi_setup_flash(struct cqspi_st *cqspi)
11448c2ecf20Sopenharmony_ci{
11458c2ecf20Sopenharmony_ci	struct platform_device *pdev = cqspi->pdev;
11468c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
11478c2ecf20Sopenharmony_ci	struct device_node *np = dev->of_node;
11488c2ecf20Sopenharmony_ci	struct cqspi_flash_pdata *f_pdata;
11498c2ecf20Sopenharmony_ci	unsigned int cs;
11508c2ecf20Sopenharmony_ci	int ret;
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci	/* Get flash device data */
11538c2ecf20Sopenharmony_ci	for_each_available_child_of_node(dev->of_node, np) {
11548c2ecf20Sopenharmony_ci		ret = of_property_read_u32(np, "reg", &cs);
11558c2ecf20Sopenharmony_ci		if (ret) {
11568c2ecf20Sopenharmony_ci			dev_err(dev, "Couldn't determine chip select.\n");
11578c2ecf20Sopenharmony_ci			return ret;
11588c2ecf20Sopenharmony_ci		}
11598c2ecf20Sopenharmony_ci
11608c2ecf20Sopenharmony_ci		if (cs >= CQSPI_MAX_CHIPSELECT) {
11618c2ecf20Sopenharmony_ci			dev_err(dev, "Chip select %d out of range.\n", cs);
11628c2ecf20Sopenharmony_ci			return -EINVAL;
11638c2ecf20Sopenharmony_ci		}
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci		f_pdata = &cqspi->f_pdata[cs];
11668c2ecf20Sopenharmony_ci		f_pdata->cqspi = cqspi;
11678c2ecf20Sopenharmony_ci		f_pdata->cs = cs;
11688c2ecf20Sopenharmony_ci
11698c2ecf20Sopenharmony_ci		ret = cqspi_of_get_flash_pdata(pdev, f_pdata, np);
11708c2ecf20Sopenharmony_ci		if (ret)
11718c2ecf20Sopenharmony_ci			return ret;
11728c2ecf20Sopenharmony_ci	}
11738c2ecf20Sopenharmony_ci
11748c2ecf20Sopenharmony_ci	return 0;
11758c2ecf20Sopenharmony_ci}
11768c2ecf20Sopenharmony_ci
11778c2ecf20Sopenharmony_cistatic int cqspi_probe(struct platform_device *pdev)
11788c2ecf20Sopenharmony_ci{
11798c2ecf20Sopenharmony_ci	const struct cqspi_driver_platdata *ddata;
11808c2ecf20Sopenharmony_ci	struct reset_control *rstc, *rstc_ocp;
11818c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
11828c2ecf20Sopenharmony_ci	struct spi_master *master;
11838c2ecf20Sopenharmony_ci	struct resource *res_ahb;
11848c2ecf20Sopenharmony_ci	struct cqspi_st *cqspi;
11858c2ecf20Sopenharmony_ci	struct resource *res;
11868c2ecf20Sopenharmony_ci	int ret;
11878c2ecf20Sopenharmony_ci	int irq;
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_ci	master = spi_alloc_master(&pdev->dev, sizeof(*cqspi));
11908c2ecf20Sopenharmony_ci	if (!master) {
11918c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "spi_alloc_master failed\n");
11928c2ecf20Sopenharmony_ci		return -ENOMEM;
11938c2ecf20Sopenharmony_ci	}
11948c2ecf20Sopenharmony_ci	master->mode_bits = SPI_RX_QUAD | SPI_RX_DUAL;
11958c2ecf20Sopenharmony_ci	master->mem_ops = &cqspi_mem_ops;
11968c2ecf20Sopenharmony_ci	master->dev.of_node = pdev->dev.of_node;
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci	cqspi = spi_master_get_devdata(master);
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_ci	cqspi->pdev = pdev;
12018c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, cqspi);
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_ci	/* Obtain configuration from OF. */
12048c2ecf20Sopenharmony_ci	ret = cqspi_of_get_pdata(cqspi);
12058c2ecf20Sopenharmony_ci	if (ret) {
12068c2ecf20Sopenharmony_ci		dev_err(dev, "Cannot get mandatory OF data.\n");
12078c2ecf20Sopenharmony_ci		ret = -ENODEV;
12088c2ecf20Sopenharmony_ci		goto probe_master_put;
12098c2ecf20Sopenharmony_ci	}
12108c2ecf20Sopenharmony_ci
12118c2ecf20Sopenharmony_ci	/* Obtain QSPI clock. */
12128c2ecf20Sopenharmony_ci	cqspi->clk = devm_clk_get(dev, NULL);
12138c2ecf20Sopenharmony_ci	if (IS_ERR(cqspi->clk)) {
12148c2ecf20Sopenharmony_ci		dev_err(dev, "Cannot claim QSPI clock.\n");
12158c2ecf20Sopenharmony_ci		ret = PTR_ERR(cqspi->clk);
12168c2ecf20Sopenharmony_ci		goto probe_master_put;
12178c2ecf20Sopenharmony_ci	}
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_ci	/* Obtain and remap controller address. */
12208c2ecf20Sopenharmony_ci	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
12218c2ecf20Sopenharmony_ci	cqspi->iobase = devm_ioremap_resource(dev, res);
12228c2ecf20Sopenharmony_ci	if (IS_ERR(cqspi->iobase)) {
12238c2ecf20Sopenharmony_ci		dev_err(dev, "Cannot remap controller address.\n");
12248c2ecf20Sopenharmony_ci		ret = PTR_ERR(cqspi->iobase);
12258c2ecf20Sopenharmony_ci		goto probe_master_put;
12268c2ecf20Sopenharmony_ci	}
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_ci	/* Obtain and remap AHB address. */
12298c2ecf20Sopenharmony_ci	res_ahb = platform_get_resource(pdev, IORESOURCE_MEM, 1);
12308c2ecf20Sopenharmony_ci	cqspi->ahb_base = devm_ioremap_resource(dev, res_ahb);
12318c2ecf20Sopenharmony_ci	if (IS_ERR(cqspi->ahb_base)) {
12328c2ecf20Sopenharmony_ci		dev_err(dev, "Cannot remap AHB address.\n");
12338c2ecf20Sopenharmony_ci		ret = PTR_ERR(cqspi->ahb_base);
12348c2ecf20Sopenharmony_ci		goto probe_master_put;
12358c2ecf20Sopenharmony_ci	}
12368c2ecf20Sopenharmony_ci	cqspi->mmap_phys_base = (dma_addr_t)res_ahb->start;
12378c2ecf20Sopenharmony_ci	cqspi->ahb_size = resource_size(res_ahb);
12388c2ecf20Sopenharmony_ci
12398c2ecf20Sopenharmony_ci	init_completion(&cqspi->transfer_complete);
12408c2ecf20Sopenharmony_ci
12418c2ecf20Sopenharmony_ci	/* Obtain IRQ line. */
12428c2ecf20Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
12438c2ecf20Sopenharmony_ci	if (irq < 0) {
12448c2ecf20Sopenharmony_ci		ret = -ENXIO;
12458c2ecf20Sopenharmony_ci		goto probe_master_put;
12468c2ecf20Sopenharmony_ci	}
12478c2ecf20Sopenharmony_ci
12488c2ecf20Sopenharmony_ci	pm_runtime_enable(dev);
12498c2ecf20Sopenharmony_ci	ret = pm_runtime_get_sync(dev);
12508c2ecf20Sopenharmony_ci	if (ret < 0) {
12518c2ecf20Sopenharmony_ci		pm_runtime_put_noidle(dev);
12528c2ecf20Sopenharmony_ci		goto probe_master_put;
12538c2ecf20Sopenharmony_ci	}
12548c2ecf20Sopenharmony_ci
12558c2ecf20Sopenharmony_ci	ret = clk_prepare_enable(cqspi->clk);
12568c2ecf20Sopenharmony_ci	if (ret) {
12578c2ecf20Sopenharmony_ci		dev_err(dev, "Cannot enable QSPI clock.\n");
12588c2ecf20Sopenharmony_ci		goto probe_clk_failed;
12598c2ecf20Sopenharmony_ci	}
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci	/* Obtain QSPI reset control */
12628c2ecf20Sopenharmony_ci	rstc = devm_reset_control_get_optional_exclusive(dev, "qspi");
12638c2ecf20Sopenharmony_ci	if (IS_ERR(rstc)) {
12648c2ecf20Sopenharmony_ci		ret = PTR_ERR(rstc);
12658c2ecf20Sopenharmony_ci		dev_err(dev, "Cannot get QSPI reset.\n");
12668c2ecf20Sopenharmony_ci		goto probe_reset_failed;
12678c2ecf20Sopenharmony_ci	}
12688c2ecf20Sopenharmony_ci
12698c2ecf20Sopenharmony_ci	rstc_ocp = devm_reset_control_get_optional_exclusive(dev, "qspi-ocp");
12708c2ecf20Sopenharmony_ci	if (IS_ERR(rstc_ocp)) {
12718c2ecf20Sopenharmony_ci		ret = PTR_ERR(rstc_ocp);
12728c2ecf20Sopenharmony_ci		dev_err(dev, "Cannot get QSPI OCP reset.\n");
12738c2ecf20Sopenharmony_ci		goto probe_reset_failed;
12748c2ecf20Sopenharmony_ci	}
12758c2ecf20Sopenharmony_ci
12768c2ecf20Sopenharmony_ci	reset_control_assert(rstc);
12778c2ecf20Sopenharmony_ci	reset_control_deassert(rstc);
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_ci	reset_control_assert(rstc_ocp);
12808c2ecf20Sopenharmony_ci	reset_control_deassert(rstc_ocp);
12818c2ecf20Sopenharmony_ci
12828c2ecf20Sopenharmony_ci	cqspi->master_ref_clk_hz = clk_get_rate(cqspi->clk);
12838c2ecf20Sopenharmony_ci	ddata  = of_device_get_match_data(dev);
12848c2ecf20Sopenharmony_ci	if (ddata) {
12858c2ecf20Sopenharmony_ci		if (ddata->quirks & CQSPI_NEEDS_WR_DELAY)
12868c2ecf20Sopenharmony_ci			cqspi->wr_delay = 5 * DIV_ROUND_UP(NSEC_PER_SEC,
12878c2ecf20Sopenharmony_ci						cqspi->master_ref_clk_hz);
12888c2ecf20Sopenharmony_ci		if (ddata->hwcaps_mask & CQSPI_SUPPORTS_OCTAL)
12898c2ecf20Sopenharmony_ci			master->mode_bits |= SPI_RX_OCTAL;
12908c2ecf20Sopenharmony_ci		if (!(ddata->quirks & CQSPI_DISABLE_DAC_MODE))
12918c2ecf20Sopenharmony_ci			cqspi->use_direct_mode = true;
12928c2ecf20Sopenharmony_ci	}
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_ci	ret = devm_request_irq(dev, irq, cqspi_irq_handler, 0,
12958c2ecf20Sopenharmony_ci			       pdev->name, cqspi);
12968c2ecf20Sopenharmony_ci	if (ret) {
12978c2ecf20Sopenharmony_ci		dev_err(dev, "Cannot request IRQ.\n");
12988c2ecf20Sopenharmony_ci		goto probe_reset_failed;
12998c2ecf20Sopenharmony_ci	}
13008c2ecf20Sopenharmony_ci
13018c2ecf20Sopenharmony_ci	cqspi_wait_idle(cqspi);
13028c2ecf20Sopenharmony_ci	cqspi_controller_init(cqspi);
13038c2ecf20Sopenharmony_ci	cqspi->current_cs = -1;
13048c2ecf20Sopenharmony_ci	cqspi->sclk = 0;
13058c2ecf20Sopenharmony_ci
13068c2ecf20Sopenharmony_ci	ret = cqspi_setup_flash(cqspi);
13078c2ecf20Sopenharmony_ci	if (ret) {
13088c2ecf20Sopenharmony_ci		dev_err(dev, "failed to setup flash parameters %d\n", ret);
13098c2ecf20Sopenharmony_ci		goto probe_setup_failed;
13108c2ecf20Sopenharmony_ci	}
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci	if (cqspi->use_direct_mode) {
13138c2ecf20Sopenharmony_ci		ret = cqspi_request_mmap_dma(cqspi);
13148c2ecf20Sopenharmony_ci		if (ret == -EPROBE_DEFER)
13158c2ecf20Sopenharmony_ci			goto probe_setup_failed;
13168c2ecf20Sopenharmony_ci	}
13178c2ecf20Sopenharmony_ci
13188c2ecf20Sopenharmony_ci	ret = devm_spi_register_master(dev, master);
13198c2ecf20Sopenharmony_ci	if (ret) {
13208c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "failed to register SPI ctlr %d\n", ret);
13218c2ecf20Sopenharmony_ci		goto probe_setup_failed;
13228c2ecf20Sopenharmony_ci	}
13238c2ecf20Sopenharmony_ci
13248c2ecf20Sopenharmony_ci	return 0;
13258c2ecf20Sopenharmony_ciprobe_setup_failed:
13268c2ecf20Sopenharmony_ci	cqspi_controller_enable(cqspi, 0);
13278c2ecf20Sopenharmony_ciprobe_reset_failed:
13288c2ecf20Sopenharmony_ci	clk_disable_unprepare(cqspi->clk);
13298c2ecf20Sopenharmony_ciprobe_clk_failed:
13308c2ecf20Sopenharmony_ci	pm_runtime_put_sync(dev);
13318c2ecf20Sopenharmony_ci	pm_runtime_disable(dev);
13328c2ecf20Sopenharmony_ciprobe_master_put:
13338c2ecf20Sopenharmony_ci	spi_master_put(master);
13348c2ecf20Sopenharmony_ci	return ret;
13358c2ecf20Sopenharmony_ci}
13368c2ecf20Sopenharmony_ci
13378c2ecf20Sopenharmony_cistatic int cqspi_remove(struct platform_device *pdev)
13388c2ecf20Sopenharmony_ci{
13398c2ecf20Sopenharmony_ci	struct cqspi_st *cqspi = platform_get_drvdata(pdev);
13408c2ecf20Sopenharmony_ci
13418c2ecf20Sopenharmony_ci	cqspi_controller_enable(cqspi, 0);
13428c2ecf20Sopenharmony_ci
13438c2ecf20Sopenharmony_ci	if (cqspi->rx_chan)
13448c2ecf20Sopenharmony_ci		dma_release_channel(cqspi->rx_chan);
13458c2ecf20Sopenharmony_ci
13468c2ecf20Sopenharmony_ci	clk_disable_unprepare(cqspi->clk);
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci	pm_runtime_put_sync(&pdev->dev);
13498c2ecf20Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci	return 0;
13528c2ecf20Sopenharmony_ci}
13538c2ecf20Sopenharmony_ci
13548c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
13558c2ecf20Sopenharmony_cistatic int cqspi_suspend(struct device *dev)
13568c2ecf20Sopenharmony_ci{
13578c2ecf20Sopenharmony_ci	struct cqspi_st *cqspi = dev_get_drvdata(dev);
13588c2ecf20Sopenharmony_ci	struct spi_master *master = dev_get_drvdata(dev);
13598c2ecf20Sopenharmony_ci	int ret;
13608c2ecf20Sopenharmony_ci
13618c2ecf20Sopenharmony_ci	ret = spi_master_suspend(master);
13628c2ecf20Sopenharmony_ci	cqspi_controller_enable(cqspi, 0);
13638c2ecf20Sopenharmony_ci
13648c2ecf20Sopenharmony_ci	clk_disable_unprepare(cqspi->clk);
13658c2ecf20Sopenharmony_ci
13668c2ecf20Sopenharmony_ci	return ret;
13678c2ecf20Sopenharmony_ci}
13688c2ecf20Sopenharmony_ci
13698c2ecf20Sopenharmony_cistatic int cqspi_resume(struct device *dev)
13708c2ecf20Sopenharmony_ci{
13718c2ecf20Sopenharmony_ci	struct cqspi_st *cqspi = dev_get_drvdata(dev);
13728c2ecf20Sopenharmony_ci	struct spi_master *master = dev_get_drvdata(dev);
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_ci	clk_prepare_enable(cqspi->clk);
13758c2ecf20Sopenharmony_ci	cqspi_wait_idle(cqspi);
13768c2ecf20Sopenharmony_ci	cqspi_controller_init(cqspi);
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci	cqspi->current_cs = -1;
13798c2ecf20Sopenharmony_ci	cqspi->sclk = 0;
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_ci	return spi_master_resume(master);
13828c2ecf20Sopenharmony_ci}
13838c2ecf20Sopenharmony_ci
13848c2ecf20Sopenharmony_cistatic const struct dev_pm_ops cqspi__dev_pm_ops = {
13858c2ecf20Sopenharmony_ci	.suspend = cqspi_suspend,
13868c2ecf20Sopenharmony_ci	.resume = cqspi_resume,
13878c2ecf20Sopenharmony_ci};
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci#define CQSPI_DEV_PM_OPS	(&cqspi__dev_pm_ops)
13908c2ecf20Sopenharmony_ci#else
13918c2ecf20Sopenharmony_ci#define CQSPI_DEV_PM_OPS	NULL
13928c2ecf20Sopenharmony_ci#endif
13938c2ecf20Sopenharmony_ci
13948c2ecf20Sopenharmony_cistatic const struct cqspi_driver_platdata cdns_qspi = {
13958c2ecf20Sopenharmony_ci	.quirks = CQSPI_DISABLE_DAC_MODE,
13968c2ecf20Sopenharmony_ci};
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_cistatic const struct cqspi_driver_platdata k2g_qspi = {
13998c2ecf20Sopenharmony_ci	.quirks = CQSPI_NEEDS_WR_DELAY,
14008c2ecf20Sopenharmony_ci};
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_cistatic const struct cqspi_driver_platdata am654_ospi = {
14038c2ecf20Sopenharmony_ci	.hwcaps_mask = CQSPI_SUPPORTS_OCTAL,
14048c2ecf20Sopenharmony_ci	.quirks = CQSPI_NEEDS_WR_DELAY,
14058c2ecf20Sopenharmony_ci};
14068c2ecf20Sopenharmony_ci
14078c2ecf20Sopenharmony_cistatic const struct of_device_id cqspi_dt_ids[] = {
14088c2ecf20Sopenharmony_ci	{
14098c2ecf20Sopenharmony_ci		.compatible = "cdns,qspi-nor",
14108c2ecf20Sopenharmony_ci		.data = &cdns_qspi,
14118c2ecf20Sopenharmony_ci	},
14128c2ecf20Sopenharmony_ci	{
14138c2ecf20Sopenharmony_ci		.compatible = "ti,k2g-qspi",
14148c2ecf20Sopenharmony_ci		.data = &k2g_qspi,
14158c2ecf20Sopenharmony_ci	},
14168c2ecf20Sopenharmony_ci	{
14178c2ecf20Sopenharmony_ci		.compatible = "ti,am654-ospi",
14188c2ecf20Sopenharmony_ci		.data = &am654_ospi,
14198c2ecf20Sopenharmony_ci	},
14208c2ecf20Sopenharmony_ci	{ /* end of table */ }
14218c2ecf20Sopenharmony_ci};
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, cqspi_dt_ids);
14248c2ecf20Sopenharmony_ci
14258c2ecf20Sopenharmony_cistatic struct platform_driver cqspi_platform_driver = {
14268c2ecf20Sopenharmony_ci	.probe = cqspi_probe,
14278c2ecf20Sopenharmony_ci	.remove = cqspi_remove,
14288c2ecf20Sopenharmony_ci	.driver = {
14298c2ecf20Sopenharmony_ci		.name = CQSPI_NAME,
14308c2ecf20Sopenharmony_ci		.pm = CQSPI_DEV_PM_OPS,
14318c2ecf20Sopenharmony_ci		.of_match_table = cqspi_dt_ids,
14328c2ecf20Sopenharmony_ci	},
14338c2ecf20Sopenharmony_ci};
14348c2ecf20Sopenharmony_ci
14358c2ecf20Sopenharmony_cimodule_platform_driver(cqspi_platform_driver);
14368c2ecf20Sopenharmony_ci
14378c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Cadence QSPI Controller Driver");
14388c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
14398c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:" CQSPI_NAME);
14408c2ecf20Sopenharmony_ciMODULE_AUTHOR("Ley Foon Tan <lftan@altera.com>");
14418c2ecf20Sopenharmony_ciMODULE_AUTHOR("Graham Moore <grmoore@opensource.altera.com>");
14428c2ecf20Sopenharmony_ciMODULE_AUTHOR("Vadivel Murugan R <vadivel.muruganx.ramuthevar@intel.com>");
14438c2ecf20Sopenharmony_ciMODULE_AUTHOR("Vignesh Raghavendra <vigneshr@ti.com>");
1444