xref: /openbmc/linux/drivers/spi/spi-bcm-qspi.c (revision 26e85f7b)
1cb849fc5SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2fa236a7eSKamal Dasu /*
3fa236a7eSKamal Dasu  * Driver for Broadcom BRCMSTB, NSP,  NS2, Cygnus SPI Controllers
4fa236a7eSKamal Dasu  *
5fa236a7eSKamal Dasu  * Copyright 2016 Broadcom
6fa236a7eSKamal Dasu  */
7fa236a7eSKamal Dasu 
8fa236a7eSKamal Dasu #include <linux/clk.h>
9fa236a7eSKamal Dasu #include <linux/delay.h>
10fa236a7eSKamal Dasu #include <linux/device.h>
11fa236a7eSKamal Dasu #include <linux/init.h>
12fa236a7eSKamal Dasu #include <linux/interrupt.h>
13fa236a7eSKamal Dasu #include <linux/io.h>
14fa236a7eSKamal Dasu #include <linux/ioport.h>
15fa236a7eSKamal Dasu #include <linux/kernel.h>
16fa236a7eSKamal Dasu #include <linux/module.h>
17fa236a7eSKamal Dasu #include <linux/of.h>
18fa236a7eSKamal Dasu #include <linux/of_irq.h>
19fa236a7eSKamal Dasu #include <linux/platform_device.h>
20fa236a7eSKamal Dasu #include <linux/slab.h>
21fa236a7eSKamal Dasu #include <linux/spi/spi.h>
22*26e85f7bSKamal Dasu #include <linux/mtd/spi-nor.h>
23fa236a7eSKamal Dasu #include <linux/sysfs.h>
24fa236a7eSKamal Dasu #include <linux/types.h>
25fa236a7eSKamal Dasu #include "spi-bcm-qspi.h"
26fa236a7eSKamal Dasu 
27fa236a7eSKamal Dasu #define DRIVER_NAME "bcm_qspi"
28fa236a7eSKamal Dasu 
294e3b2d23SKamal Dasu 
304e3b2d23SKamal Dasu /* BSPI register offsets */
314e3b2d23SKamal Dasu #define BSPI_REVISION_ID			0x000
324e3b2d23SKamal Dasu #define BSPI_SCRATCH				0x004
334e3b2d23SKamal Dasu #define BSPI_MAST_N_BOOT_CTRL			0x008
344e3b2d23SKamal Dasu #define BSPI_BUSY_STATUS			0x00c
354e3b2d23SKamal Dasu #define BSPI_INTR_STATUS			0x010
364e3b2d23SKamal Dasu #define BSPI_B0_STATUS				0x014
374e3b2d23SKamal Dasu #define BSPI_B0_CTRL				0x018
384e3b2d23SKamal Dasu #define BSPI_B1_STATUS				0x01c
394e3b2d23SKamal Dasu #define BSPI_B1_CTRL				0x020
404e3b2d23SKamal Dasu #define BSPI_STRAP_OVERRIDE_CTRL		0x024
414e3b2d23SKamal Dasu #define BSPI_FLEX_MODE_ENABLE			0x028
424e3b2d23SKamal Dasu #define BSPI_BITS_PER_CYCLE			0x02c
434e3b2d23SKamal Dasu #define BSPI_BITS_PER_PHASE			0x030
444e3b2d23SKamal Dasu #define BSPI_CMD_AND_MODE_BYTE			0x034
454e3b2d23SKamal Dasu #define BSPI_BSPI_FLASH_UPPER_ADDR_BYTE	0x038
464e3b2d23SKamal Dasu #define BSPI_BSPI_XOR_VALUE			0x03c
474e3b2d23SKamal Dasu #define BSPI_BSPI_XOR_ENABLE			0x040
484e3b2d23SKamal Dasu #define BSPI_BSPI_PIO_MODE_ENABLE		0x044
494e3b2d23SKamal Dasu #define BSPI_BSPI_PIO_IODIR			0x048
504e3b2d23SKamal Dasu #define BSPI_BSPI_PIO_DATA			0x04c
514e3b2d23SKamal Dasu 
524e3b2d23SKamal Dasu /* RAF register offsets */
534e3b2d23SKamal Dasu #define BSPI_RAF_START_ADDR			0x100
544e3b2d23SKamal Dasu #define BSPI_RAF_NUM_WORDS			0x104
554e3b2d23SKamal Dasu #define BSPI_RAF_CTRL				0x108
564e3b2d23SKamal Dasu #define BSPI_RAF_FULLNESS			0x10c
574e3b2d23SKamal Dasu #define BSPI_RAF_WATERMARK			0x110
584e3b2d23SKamal Dasu #define BSPI_RAF_STATUS			0x114
594e3b2d23SKamal Dasu #define BSPI_RAF_READ_DATA			0x118
604e3b2d23SKamal Dasu #define BSPI_RAF_WORD_CNT			0x11c
614e3b2d23SKamal Dasu #define BSPI_RAF_CURR_ADDR			0x120
624e3b2d23SKamal Dasu 
634e3b2d23SKamal Dasu /* Override mode masks */
644e3b2d23SKamal Dasu #define BSPI_STRAP_OVERRIDE_CTRL_OVERRIDE	BIT(0)
654e3b2d23SKamal Dasu #define BSPI_STRAP_OVERRIDE_CTRL_DATA_DUAL	BIT(1)
664e3b2d23SKamal Dasu #define BSPI_STRAP_OVERRIDE_CTRL_ADDR_4BYTE	BIT(2)
674e3b2d23SKamal Dasu #define BSPI_STRAP_OVERRIDE_CTRL_DATA_QUAD	BIT(3)
684e3b2d23SKamal Dasu #define BSPI_STRAP_OVERRIDE_CTRL_ENDAIN_MODE	BIT(4)
694e3b2d23SKamal Dasu 
704e3b2d23SKamal Dasu #define BSPI_ADDRLEN_3BYTES			3
714e3b2d23SKamal Dasu #define BSPI_ADDRLEN_4BYTES			4
724e3b2d23SKamal Dasu 
734e3b2d23SKamal Dasu #define BSPI_RAF_STATUS_FIFO_EMPTY_MASK	BIT(1)
744e3b2d23SKamal Dasu 
754e3b2d23SKamal Dasu #define BSPI_RAF_CTRL_START_MASK		BIT(0)
764e3b2d23SKamal Dasu #define BSPI_RAF_CTRL_CLEAR_MASK		BIT(1)
774e3b2d23SKamal Dasu 
784e3b2d23SKamal Dasu #define BSPI_BPP_MODE_SELECT_MASK		BIT(8)
794e3b2d23SKamal Dasu #define BSPI_BPP_ADDR_SELECT_MASK		BIT(16)
804e3b2d23SKamal Dasu 
81940ec770SRafał Miłecki #define BSPI_READ_LENGTH			256
824e3b2d23SKamal Dasu 
83fa236a7eSKamal Dasu /* MSPI register offsets */
84fa236a7eSKamal Dasu #define MSPI_SPCR0_LSB				0x000
85fa236a7eSKamal Dasu #define MSPI_SPCR0_MSB				0x004
86ee4d62c4SKamal Dasu #define MSPI_SPCR0_MSB_CPHA			BIT(0)
87ee4d62c4SKamal Dasu #define MSPI_SPCR0_MSB_CPOL			BIT(1)
88ee4d62c4SKamal Dasu #define MSPI_SPCR0_MSB_BITS_SHIFT		0x2
89fa236a7eSKamal Dasu #define MSPI_SPCR1_LSB				0x008
90fa236a7eSKamal Dasu #define MSPI_SPCR1_MSB				0x00c
91fa236a7eSKamal Dasu #define MSPI_NEWQP				0x010
92fa236a7eSKamal Dasu #define MSPI_ENDQP				0x014
93fa236a7eSKamal Dasu #define MSPI_SPCR2				0x018
94fa236a7eSKamal Dasu #define MSPI_MSPI_STATUS			0x020
95fa236a7eSKamal Dasu #define MSPI_CPTQP				0x024
96fa236a7eSKamal Dasu #define MSPI_SPCR3				0x028
973a01f04dSFlorian Fainelli #define MSPI_REV				0x02c
98fa236a7eSKamal Dasu #define MSPI_TXRAM				0x040
99fa236a7eSKamal Dasu #define MSPI_RXRAM				0x0c0
100fa236a7eSKamal Dasu #define MSPI_CDRAM				0x140
101fa236a7eSKamal Dasu #define MSPI_WRITE_LOCK			0x180
102fa236a7eSKamal Dasu 
103fa236a7eSKamal Dasu #define MSPI_MASTER_BIT			BIT(7)
104fa236a7eSKamal Dasu 
105fa236a7eSKamal Dasu #define MSPI_NUM_CDRAM				16
106e81cd07dSKamal Dasu #define MSPI_CDRAM_OUTP				BIT(8)
107fa236a7eSKamal Dasu #define MSPI_CDRAM_CONT_BIT			BIT(7)
108fa236a7eSKamal Dasu #define MSPI_CDRAM_BITSE_BIT			BIT(6)
109ee4d62c4SKamal Dasu #define MSPI_CDRAM_DT_BIT			BIT(5)
110fa236a7eSKamal Dasu #define MSPI_CDRAM_PCS				0xf
111fa236a7eSKamal Dasu 
112fa236a7eSKamal Dasu #define MSPI_SPCR2_SPE				BIT(6)
113fa236a7eSKamal Dasu #define MSPI_SPCR2_CONT_AFTER_CMD		BIT(7)
114fa236a7eSKamal Dasu 
115d9576ae5SKamal Dasu #define MSPI_SPCR3_FASTBR			BIT(0)
116d9576ae5SKamal Dasu #define MSPI_SPCR3_FASTDT			BIT(1)
11743613a77SKamal Dasu #define MSPI_SPCR3_SYSCLKSEL_MASK		GENMASK(11, 10)
11843613a77SKamal Dasu #define MSPI_SPCR3_SYSCLKSEL_27			(MSPI_SPCR3_SYSCLKSEL_MASK & \
11943613a77SKamal Dasu 						 ~(BIT(10) | BIT(11)))
12043613a77SKamal Dasu #define MSPI_SPCR3_SYSCLKSEL_108		(MSPI_SPCR3_SYSCLKSEL_MASK & \
12143613a77SKamal Dasu 						 BIT(11))
122ee4d62c4SKamal Dasu #define MSPI_SPCR3_TXRXDAM_MASK			GENMASK(4, 2)
123ee4d62c4SKamal Dasu #define MSPI_SPCR3_DAM_8BYTE			0
124ee4d62c4SKamal Dasu #define MSPI_SPCR3_DAM_16BYTE			(BIT(2) | BIT(4))
125ee4d62c4SKamal Dasu #define MSPI_SPCR3_DAM_32BYTE			(BIT(3) | BIT(5))
126e81cd07dSKamal Dasu #define MSPI_SPCR3_HALFDUPLEX			BIT(6)
127e81cd07dSKamal Dasu #define MSPI_SPCR3_HDOUTTYPE			BIT(7)
128ee4d62c4SKamal Dasu #define MSPI_SPCR3_DATA_REG_SZ			BIT(8)
129ee4d62c4SKamal Dasu #define MSPI_SPCR3_CPHARX			BIT(9)
130d9576ae5SKamal Dasu 
131fa236a7eSKamal Dasu #define MSPI_MSPI_STATUS_SPIF			BIT(0)
132fa236a7eSKamal Dasu 
133fa236a7eSKamal Dasu #define INTR_BASE_BIT_SHIFT			0x02
134fa236a7eSKamal Dasu #define INTR_COUNT				0x07
135fa236a7eSKamal Dasu 
136fa236a7eSKamal Dasu #define NUM_CHIPSELECT				4
137fa236a7eSKamal Dasu #define QSPI_SPBR_MAX				255U
13843613a77SKamal Dasu #define MSPI_BASE_FREQ				27000000UL
139fa236a7eSKamal Dasu 
140fa236a7eSKamal Dasu #define OPCODE_DIOR				0xBB
141fa236a7eSKamal Dasu #define OPCODE_QIOR				0xEB
142fa236a7eSKamal Dasu #define OPCODE_DIOR_4B				0xBC
143fa236a7eSKamal Dasu #define OPCODE_QIOR_4B				0xEC
144fa236a7eSKamal Dasu 
145fa236a7eSKamal Dasu #define MAX_CMD_SIZE				6
146fa236a7eSKamal Dasu 
147fa236a7eSKamal Dasu #define ADDR_4MB_MASK				GENMASK(22, 0)
148fa236a7eSKamal Dasu 
149fa236a7eSKamal Dasu /* stop at end of transfer, no other reason */
150fa236a7eSKamal Dasu #define TRANS_STATUS_BREAK_NONE		0
151fa236a7eSKamal Dasu /* stop at end of spi_message */
152fa236a7eSKamal Dasu #define TRANS_STATUS_BREAK_EOM			1
153fa236a7eSKamal Dasu /* stop at end of spi_transfer if delay */
154fa236a7eSKamal Dasu #define TRANS_STATUS_BREAK_DELAY		2
155fa236a7eSKamal Dasu /* stop at end of spi_transfer if cs_change */
156fa236a7eSKamal Dasu #define TRANS_STATUS_BREAK_CS_CHANGE		4
157fa236a7eSKamal Dasu /* stop if we run out of bytes */
158fa236a7eSKamal Dasu #define TRANS_STATUS_BREAK_NO_BYTES		8
159fa236a7eSKamal Dasu 
160fa236a7eSKamal Dasu /* events that make us stop filling TX slots */
161fa236a7eSKamal Dasu #define TRANS_STATUS_BREAK_TX (TRANS_STATUS_BREAK_EOM |		\
162fa236a7eSKamal Dasu 			       TRANS_STATUS_BREAK_DELAY |		\
163fa236a7eSKamal Dasu 			       TRANS_STATUS_BREAK_CS_CHANGE)
164fa236a7eSKamal Dasu 
165fa236a7eSKamal Dasu /* events that make us deassert CS */
166fa236a7eSKamal Dasu #define TRANS_STATUS_BREAK_DESELECT (TRANS_STATUS_BREAK_EOM |		\
167fa236a7eSKamal Dasu 				     TRANS_STATUS_BREAK_CS_CHANGE)
168fa236a7eSKamal Dasu 
169ee4d62c4SKamal Dasu /*
170ee4d62c4SKamal Dasu  * Used for writing and reading data in the right order
171ee4d62c4SKamal Dasu  * to TXRAM and RXRAM when used as 32-bit registers respectively
172ee4d62c4SKamal Dasu  */
173ee4d62c4SKamal Dasu #define swap4bytes(__val) \
174ee4d62c4SKamal Dasu 	((((__val) >> 24) & 0x000000FF) | (((__val) >>  8) & 0x0000FF00) | \
175ee4d62c4SKamal Dasu 	 (((__val) <<  8) & 0x00FF0000) | (((__val) << 24) & 0xFF000000))
176ee4d62c4SKamal Dasu 
177fa236a7eSKamal Dasu struct bcm_qspi_parms {
178fa236a7eSKamal Dasu 	u32 speed_hz;
179fa236a7eSKamal Dasu 	u8 mode;
180fa236a7eSKamal Dasu 	u8 bits_per_word;
181fa236a7eSKamal Dasu };
182fa236a7eSKamal Dasu 
1834e3b2d23SKamal Dasu struct bcm_xfer_mode {
1844e3b2d23SKamal Dasu 	bool flex_mode;
1854e3b2d23SKamal Dasu 	unsigned int width;
1864e3b2d23SKamal Dasu 	unsigned int addrlen;
1874e3b2d23SKamal Dasu 	unsigned int hp;
1884e3b2d23SKamal Dasu };
1894e3b2d23SKamal Dasu 
190fa236a7eSKamal Dasu enum base_type {
191fa236a7eSKamal Dasu 	MSPI,
1924e3b2d23SKamal Dasu 	BSPI,
193fa236a7eSKamal Dasu 	CHIP_SELECT,
194fa236a7eSKamal Dasu 	BASEMAX,
195fa236a7eSKamal Dasu };
196fa236a7eSKamal Dasu 
197cc20a386SKamal Dasu enum irq_source {
198cc20a386SKamal Dasu 	SINGLE_L2,
199cc20a386SKamal Dasu 	MUXED_L1,
200cc20a386SKamal Dasu };
201cc20a386SKamal Dasu 
202fa236a7eSKamal Dasu struct bcm_qspi_irq {
203fa236a7eSKamal Dasu 	const char *irq_name;
204fa236a7eSKamal Dasu 	const irq_handler_t irq_handler;
205cc20a386SKamal Dasu 	int irq_source;
206fa236a7eSKamal Dasu 	u32 mask;
207fa236a7eSKamal Dasu };
208fa236a7eSKamal Dasu 
209fa236a7eSKamal Dasu struct bcm_qspi_dev_id {
210fa236a7eSKamal Dasu 	const struct bcm_qspi_irq *irqp;
211fa236a7eSKamal Dasu 	void *dev;
212fa236a7eSKamal Dasu };
213fa236a7eSKamal Dasu 
21481ab52fdSKamal Dasu 
215fa236a7eSKamal Dasu struct qspi_trans {
216fa236a7eSKamal Dasu 	struct spi_transfer *trans;
217fa236a7eSKamal Dasu 	int byte;
21881ab52fdSKamal Dasu 	bool mspi_last_trans;
219fa236a7eSKamal Dasu };
220fa236a7eSKamal Dasu 
221fa236a7eSKamal Dasu struct bcm_qspi {
222fa236a7eSKamal Dasu 	struct platform_device *pdev;
223ec271c04SYang Yingliang 	struct spi_controller *host;
224fa236a7eSKamal Dasu 	struct clk *clk;
225fa236a7eSKamal Dasu 	u32 base_clk;
226fa236a7eSKamal Dasu 	u32 max_speed_hz;
227fa236a7eSKamal Dasu 	void __iomem *base[BASEMAX];
228cc20a386SKamal Dasu 
229cc20a386SKamal Dasu 	/* Some SoCs provide custom interrupt status register(s) */
230cc20a386SKamal Dasu 	struct bcm_qspi_soc_intc	*soc_intc;
231cc20a386SKamal Dasu 
232fa236a7eSKamal Dasu 	struct bcm_qspi_parms last_parms;
233fa236a7eSKamal Dasu 	struct qspi_trans  trans_pos;
234fa236a7eSKamal Dasu 	int curr_cs;
2354e3b2d23SKamal Dasu 	int bspi_maj_rev;
2364e3b2d23SKamal Dasu 	int bspi_min_rev;
2374e3b2d23SKamal Dasu 	int bspi_enabled;
2385f195ee7SBoris Brezillon 	const struct spi_mem_op *bspi_rf_op;
2395f195ee7SBoris Brezillon 	u32 bspi_rf_op_idx;
2405f195ee7SBoris Brezillon 	u32 bspi_rf_op_len;
2415f195ee7SBoris Brezillon 	u32 bspi_rf_op_status;
2424e3b2d23SKamal Dasu 	struct bcm_xfer_mode xfer_mode;
243fa236a7eSKamal Dasu 	u32 s3_strap_override_ctrl;
2444e3b2d23SKamal Dasu 	bool bspi_mode;
245fa236a7eSKamal Dasu 	bool big_endian;
246fa236a7eSKamal Dasu 	int num_irqs;
247fa236a7eSKamal Dasu 	struct bcm_qspi_dev_id *dev_ids;
248fa236a7eSKamal Dasu 	struct completion mspi_done;
2494e3b2d23SKamal Dasu 	struct completion bspi_done;
2503a01f04dSFlorian Fainelli 	u8 mspi_maj_rev;
2513a01f04dSFlorian Fainelli 	u8 mspi_min_rev;
25243613a77SKamal Dasu 	bool mspi_spcr3_sysclk;
253fa236a7eSKamal Dasu };
254fa236a7eSKamal Dasu 
has_bspi(struct bcm_qspi * qspi)2554e3b2d23SKamal Dasu static inline bool has_bspi(struct bcm_qspi *qspi)
2564e3b2d23SKamal Dasu {
2574e3b2d23SKamal Dasu 	return qspi->bspi_mode;
2584e3b2d23SKamal Dasu }
2594e3b2d23SKamal Dasu 
260d9576ae5SKamal Dasu /* hardware supports spcr3 and fast baud-rate  */
bcm_qspi_has_fastbr(struct bcm_qspi * qspi)261d9576ae5SKamal Dasu static inline bool bcm_qspi_has_fastbr(struct bcm_qspi *qspi)
262d9576ae5SKamal Dasu {
263d9576ae5SKamal Dasu 	if (!has_bspi(qspi) &&
264d9576ae5SKamal Dasu 	    ((qspi->mspi_maj_rev >= 1) &&
265d9576ae5SKamal Dasu 	     (qspi->mspi_min_rev >= 5)))
266d9576ae5SKamal Dasu 		return true;
267d9576ae5SKamal Dasu 
268d9576ae5SKamal Dasu 	return false;
269d9576ae5SKamal Dasu }
270d9576ae5SKamal Dasu 
27143613a77SKamal Dasu /* hardware supports sys clk 108Mhz  */
bcm_qspi_has_sysclk_108(struct bcm_qspi * qspi)27243613a77SKamal Dasu static inline bool bcm_qspi_has_sysclk_108(struct bcm_qspi *qspi)
27343613a77SKamal Dasu {
27443613a77SKamal Dasu 	if (!has_bspi(qspi) && (qspi->mspi_spcr3_sysclk ||
27543613a77SKamal Dasu 	    ((qspi->mspi_maj_rev >= 1) &&
27643613a77SKamal Dasu 	     (qspi->mspi_min_rev >= 6))))
27743613a77SKamal Dasu 		return true;
27843613a77SKamal Dasu 
27943613a77SKamal Dasu 	return false;
28043613a77SKamal Dasu }
28143613a77SKamal Dasu 
bcm_qspi_spbr_min(struct bcm_qspi * qspi)282d9576ae5SKamal Dasu static inline int bcm_qspi_spbr_min(struct bcm_qspi *qspi)
283d9576ae5SKamal Dasu {
284d9576ae5SKamal Dasu 	if (bcm_qspi_has_fastbr(qspi))
285ee4d62c4SKamal Dasu 		return (bcm_qspi_has_sysclk_108(qspi) ? 4 : 1);
286d9576ae5SKamal Dasu 	else
287d9576ae5SKamal Dasu 		return 8;
288d9576ae5SKamal Dasu }
289d9576ae5SKamal Dasu 
bcm_qspi_calc_spbr(u32 clk_speed_hz,const struct bcm_qspi_parms * xp)290c74526f9SKamal Dasu static u32 bcm_qspi_calc_spbr(u32 clk_speed_hz,
291c74526f9SKamal Dasu 			      const struct bcm_qspi_parms *xp)
292c74526f9SKamal Dasu {
293c74526f9SKamal Dasu 	u32 spbr = 0;
294c74526f9SKamal Dasu 
295c74526f9SKamal Dasu 	/* SPBR = System Clock/(2 * SCK Baud Rate) */
296c74526f9SKamal Dasu 	if (xp->speed_hz)
297c74526f9SKamal Dasu 		spbr = clk_speed_hz / (xp->speed_hz * 2);
298c74526f9SKamal Dasu 
299c74526f9SKamal Dasu 	return spbr;
300c74526f9SKamal Dasu }
301c74526f9SKamal Dasu 
302fa236a7eSKamal Dasu /* Read qspi controller register*/
bcm_qspi_read(struct bcm_qspi * qspi,enum base_type type,unsigned int offset)303fa236a7eSKamal Dasu static inline u32 bcm_qspi_read(struct bcm_qspi *qspi, enum base_type type,
304fa236a7eSKamal Dasu 				unsigned int offset)
305fa236a7eSKamal Dasu {
306fa236a7eSKamal Dasu 	return bcm_qspi_readl(qspi->big_endian, qspi->base[type] + offset);
307fa236a7eSKamal Dasu }
308fa236a7eSKamal Dasu 
309fa236a7eSKamal Dasu /* Write qspi controller register*/
bcm_qspi_write(struct bcm_qspi * qspi,enum base_type type,unsigned int offset,unsigned int data)310fa236a7eSKamal Dasu static inline void bcm_qspi_write(struct bcm_qspi *qspi, enum base_type type,
311fa236a7eSKamal Dasu 				  unsigned int offset, unsigned int data)
312fa236a7eSKamal Dasu {
313fa236a7eSKamal Dasu 	bcm_qspi_writel(qspi->big_endian, data, qspi->base[type] + offset);
314fa236a7eSKamal Dasu }
315fa236a7eSKamal Dasu 
3164e3b2d23SKamal Dasu /* BSPI helpers */
bcm_qspi_bspi_busy_poll(struct bcm_qspi * qspi)3174e3b2d23SKamal Dasu static int bcm_qspi_bspi_busy_poll(struct bcm_qspi *qspi)
3184e3b2d23SKamal Dasu {
3194e3b2d23SKamal Dasu 	int i;
3204e3b2d23SKamal Dasu 
3214e3b2d23SKamal Dasu 	/* this should normally finish within 10us */
3224e3b2d23SKamal Dasu 	for (i = 0; i < 1000; i++) {
3234e3b2d23SKamal Dasu 		if (!(bcm_qspi_read(qspi, BSPI, BSPI_BUSY_STATUS) & 1))
3244e3b2d23SKamal Dasu 			return 0;
3254e3b2d23SKamal Dasu 		udelay(1);
3264e3b2d23SKamal Dasu 	}
3274e3b2d23SKamal Dasu 	dev_warn(&qspi->pdev->dev, "timeout waiting for !busy_status\n");
3284e3b2d23SKamal Dasu 	return -EIO;
3294e3b2d23SKamal Dasu }
3304e3b2d23SKamal Dasu 
bcm_qspi_bspi_ver_three(struct bcm_qspi * qspi)3314e3b2d23SKamal Dasu static inline bool bcm_qspi_bspi_ver_three(struct bcm_qspi *qspi)
3324e3b2d23SKamal Dasu {
3334e3b2d23SKamal Dasu 	if (qspi->bspi_maj_rev < 4)
3344e3b2d23SKamal Dasu 		return true;
3354e3b2d23SKamal Dasu 	return false;
3364e3b2d23SKamal Dasu }
3374e3b2d23SKamal Dasu 
bcm_qspi_bspi_flush_prefetch_buffers(struct bcm_qspi * qspi)3384e3b2d23SKamal Dasu static void bcm_qspi_bspi_flush_prefetch_buffers(struct bcm_qspi *qspi)
3394e3b2d23SKamal Dasu {
3404e3b2d23SKamal Dasu 	bcm_qspi_bspi_busy_poll(qspi);
3414e3b2d23SKamal Dasu 	/* Force rising edge for the b0/b1 'flush' field */
3424e3b2d23SKamal Dasu 	bcm_qspi_write(qspi, BSPI, BSPI_B0_CTRL, 1);
3434e3b2d23SKamal Dasu 	bcm_qspi_write(qspi, BSPI, BSPI_B1_CTRL, 1);
3444e3b2d23SKamal Dasu 	bcm_qspi_write(qspi, BSPI, BSPI_B0_CTRL, 0);
3454e3b2d23SKamal Dasu 	bcm_qspi_write(qspi, BSPI, BSPI_B1_CTRL, 0);
3464e3b2d23SKamal Dasu }
3474e3b2d23SKamal Dasu 
bcm_qspi_bspi_lr_is_fifo_empty(struct bcm_qspi * qspi)3484e3b2d23SKamal Dasu static int bcm_qspi_bspi_lr_is_fifo_empty(struct bcm_qspi *qspi)
3494e3b2d23SKamal Dasu {
3504e3b2d23SKamal Dasu 	return (bcm_qspi_read(qspi, BSPI, BSPI_RAF_STATUS) &
3514e3b2d23SKamal Dasu 				BSPI_RAF_STATUS_FIFO_EMPTY_MASK);
3524e3b2d23SKamal Dasu }
3534e3b2d23SKamal Dasu 
bcm_qspi_bspi_lr_read_fifo(struct bcm_qspi * qspi)3544e3b2d23SKamal Dasu static inline u32 bcm_qspi_bspi_lr_read_fifo(struct bcm_qspi *qspi)
3554e3b2d23SKamal Dasu {
3564e3b2d23SKamal Dasu 	u32 data = bcm_qspi_read(qspi, BSPI, BSPI_RAF_READ_DATA);
3574e3b2d23SKamal Dasu 
3584e3b2d23SKamal Dasu 	/* BSPI v3 LR is LE only, convert data to host endianness */
3594e3b2d23SKamal Dasu 	if (bcm_qspi_bspi_ver_three(qspi))
3604e3b2d23SKamal Dasu 		data = le32_to_cpu(data);
3614e3b2d23SKamal Dasu 
3624e3b2d23SKamal Dasu 	return data;
3634e3b2d23SKamal Dasu }
3644e3b2d23SKamal Dasu 
bcm_qspi_bspi_lr_start(struct bcm_qspi * qspi)3654e3b2d23SKamal Dasu static inline void bcm_qspi_bspi_lr_start(struct bcm_qspi *qspi)
3664e3b2d23SKamal Dasu {
3674e3b2d23SKamal Dasu 	bcm_qspi_bspi_busy_poll(qspi);
3684e3b2d23SKamal Dasu 	bcm_qspi_write(qspi, BSPI, BSPI_RAF_CTRL,
3694e3b2d23SKamal Dasu 		       BSPI_RAF_CTRL_START_MASK);
3704e3b2d23SKamal Dasu }
3714e3b2d23SKamal Dasu 
bcm_qspi_bspi_lr_clear(struct bcm_qspi * qspi)3724e3b2d23SKamal Dasu static inline void bcm_qspi_bspi_lr_clear(struct bcm_qspi *qspi)
3734e3b2d23SKamal Dasu {
3744e3b2d23SKamal Dasu 	bcm_qspi_write(qspi, BSPI, BSPI_RAF_CTRL,
3754e3b2d23SKamal Dasu 		       BSPI_RAF_CTRL_CLEAR_MASK);
3764e3b2d23SKamal Dasu 	bcm_qspi_bspi_flush_prefetch_buffers(qspi);
3774e3b2d23SKamal Dasu }
3784e3b2d23SKamal Dasu 
bcm_qspi_bspi_lr_data_read(struct bcm_qspi * qspi)3794e3b2d23SKamal Dasu static void bcm_qspi_bspi_lr_data_read(struct bcm_qspi *qspi)
3804e3b2d23SKamal Dasu {
3815f195ee7SBoris Brezillon 	u32 *buf = (u32 *)qspi->bspi_rf_op->data.buf.in;
3824e3b2d23SKamal Dasu 	u32 data = 0;
3834e3b2d23SKamal Dasu 
3845f195ee7SBoris Brezillon 	dev_dbg(&qspi->pdev->dev, "xfer %p rx %p rxlen %d\n", qspi->bspi_rf_op,
3855f195ee7SBoris Brezillon 		qspi->bspi_rf_op->data.buf.in, qspi->bspi_rf_op_len);
3864e3b2d23SKamal Dasu 	while (!bcm_qspi_bspi_lr_is_fifo_empty(qspi)) {
3874e3b2d23SKamal Dasu 		data = bcm_qspi_bspi_lr_read_fifo(qspi);
3885f195ee7SBoris Brezillon 		if (likely(qspi->bspi_rf_op_len >= 4) &&
3894e3b2d23SKamal Dasu 		    IS_ALIGNED((uintptr_t)buf, 4)) {
3905f195ee7SBoris Brezillon 			buf[qspi->bspi_rf_op_idx++] = data;
3915f195ee7SBoris Brezillon 			qspi->bspi_rf_op_len -= 4;
3924e3b2d23SKamal Dasu 		} else {
3934e3b2d23SKamal Dasu 			/* Read out remaining bytes, make sure*/
3945f195ee7SBoris Brezillon 			u8 *cbuf = (u8 *)&buf[qspi->bspi_rf_op_idx];
3954e3b2d23SKamal Dasu 
3964e3b2d23SKamal Dasu 			data = cpu_to_le32(data);
3975f195ee7SBoris Brezillon 			while (qspi->bspi_rf_op_len) {
3984e3b2d23SKamal Dasu 				*cbuf++ = (u8)data;
3994e3b2d23SKamal Dasu 				data >>= 8;
4005f195ee7SBoris Brezillon 				qspi->bspi_rf_op_len--;
4014e3b2d23SKamal Dasu 			}
4024e3b2d23SKamal Dasu 		}
4034e3b2d23SKamal Dasu 	}
4044e3b2d23SKamal Dasu }
4054e3b2d23SKamal Dasu 
bcm_qspi_bspi_set_xfer_params(struct bcm_qspi * qspi,u8 cmd_byte,int bpp,int bpc,int flex_mode)4064e3b2d23SKamal Dasu static void bcm_qspi_bspi_set_xfer_params(struct bcm_qspi *qspi, u8 cmd_byte,
4074e3b2d23SKamal Dasu 					  int bpp, int bpc, int flex_mode)
4084e3b2d23SKamal Dasu {
4094e3b2d23SKamal Dasu 	bcm_qspi_write(qspi, BSPI, BSPI_FLEX_MODE_ENABLE, 0);
4104e3b2d23SKamal Dasu 	bcm_qspi_write(qspi, BSPI, BSPI_BITS_PER_CYCLE, bpc);
4114e3b2d23SKamal Dasu 	bcm_qspi_write(qspi, BSPI, BSPI_BITS_PER_PHASE, bpp);
4124e3b2d23SKamal Dasu 	bcm_qspi_write(qspi, BSPI, BSPI_CMD_AND_MODE_BYTE, cmd_byte);
4134e3b2d23SKamal Dasu 	bcm_qspi_write(qspi, BSPI, BSPI_FLEX_MODE_ENABLE, flex_mode);
4144e3b2d23SKamal Dasu }
4154e3b2d23SKamal Dasu 
bcm_qspi_bspi_set_flex_mode(struct bcm_qspi * qspi,const struct spi_mem_op * op,int hp)416054e532fSKamal Dasu static int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi,
4175f195ee7SBoris Brezillon 				       const struct spi_mem_op *op, int hp)
4184e3b2d23SKamal Dasu {
4194e3b2d23SKamal Dasu 	int bpc = 0, bpp = 0;
4205f195ee7SBoris Brezillon 	u8 command = op->cmd.opcode;
42179629d0fSRayagonda Kokatanur 	int width = op->data.buswidth ? op->data.buswidth : SPI_NBITS_SINGLE;
4220976eda7SRafał Miłecki 	int addrlen = op->addr.nbytes;
423054e532fSKamal Dasu 	int flex_mode = 1;
4244e3b2d23SKamal Dasu 
4254e3b2d23SKamal Dasu 	dev_dbg(&qspi->pdev->dev, "set flex mode w %x addrlen %x hp %d\n",
4264e3b2d23SKamal Dasu 		width, addrlen, hp);
4274e3b2d23SKamal Dasu 
428054e532fSKamal Dasu 	if (addrlen == BSPI_ADDRLEN_4BYTES)
4294e3b2d23SKamal Dasu 		bpp = BSPI_BPP_ADDR_SELECT_MASK;
4304e3b2d23SKamal Dasu 
43109134c53SYoshitaka Ikeda 	if (op->dummy.nbytes)
4325f195ee7SBoris Brezillon 		bpp |= (op->dummy.nbytes * 8) / op->dummy.buswidth;
4334e3b2d23SKamal Dasu 
4344e3b2d23SKamal Dasu 	switch (width) {
4354e3b2d23SKamal Dasu 	case SPI_NBITS_SINGLE:
4364e3b2d23SKamal Dasu 		if (addrlen == BSPI_ADDRLEN_3BYTES)
4374e3b2d23SKamal Dasu 			/* default mode, does not need flex_cmd */
4384e3b2d23SKamal Dasu 			flex_mode = 0;
4394e3b2d23SKamal Dasu 		break;
4404e3b2d23SKamal Dasu 	case SPI_NBITS_DUAL:
4414e3b2d23SKamal Dasu 		bpc = 0x00000001;
4424e3b2d23SKamal Dasu 		if (hp) {
4434e3b2d23SKamal Dasu 			bpc |= 0x00010100; /* address and mode are 2-bit */
4444e3b2d23SKamal Dasu 			bpp = BSPI_BPP_MODE_SELECT_MASK;
4454e3b2d23SKamal Dasu 		}
4464e3b2d23SKamal Dasu 		break;
4474e3b2d23SKamal Dasu 	case SPI_NBITS_QUAD:
4484e3b2d23SKamal Dasu 		bpc = 0x00000002;
4494e3b2d23SKamal Dasu 		if (hp) {
4504e3b2d23SKamal Dasu 			bpc |= 0x00020200; /* address and mode are 4-bit */
451054e532fSKamal Dasu 			bpp |= BSPI_BPP_MODE_SELECT_MASK;
4524e3b2d23SKamal Dasu 		}
4534e3b2d23SKamal Dasu 		break;
4544e3b2d23SKamal Dasu 	default:
455054e532fSKamal Dasu 		return -EINVAL;
4564e3b2d23SKamal Dasu 	}
4574e3b2d23SKamal Dasu 
458054e532fSKamal Dasu 	bcm_qspi_bspi_set_xfer_params(qspi, command, bpp, bpc, flex_mode);
4594e3b2d23SKamal Dasu 
460054e532fSKamal Dasu 	return 0;
4614e3b2d23SKamal Dasu }
4624e3b2d23SKamal Dasu 
bcm_qspi_bspi_set_override(struct bcm_qspi * qspi,const struct spi_mem_op * op,int hp)463054e532fSKamal Dasu static int bcm_qspi_bspi_set_override(struct bcm_qspi *qspi,
4645f195ee7SBoris Brezillon 				      const struct spi_mem_op *op, int hp)
4654e3b2d23SKamal Dasu {
4665f195ee7SBoris Brezillon 	int width = op->data.buswidth ? op->data.buswidth : SPI_NBITS_SINGLE;
4675f195ee7SBoris Brezillon 	int addrlen = op->addr.nbytes;
4684e3b2d23SKamal Dasu 	u32 data = bcm_qspi_read(qspi, BSPI, BSPI_STRAP_OVERRIDE_CTRL);
4694e3b2d23SKamal Dasu 
4704e3b2d23SKamal Dasu 	dev_dbg(&qspi->pdev->dev, "set override mode w %x addrlen %x hp %d\n",
4714e3b2d23SKamal Dasu 		width, addrlen, hp);
4724e3b2d23SKamal Dasu 
4734e3b2d23SKamal Dasu 	switch (width) {
4744e3b2d23SKamal Dasu 	case SPI_NBITS_SINGLE:
4754e3b2d23SKamal Dasu 		/* clear quad/dual mode */
4764e3b2d23SKamal Dasu 		data &= ~(BSPI_STRAP_OVERRIDE_CTRL_DATA_QUAD |
4774e3b2d23SKamal Dasu 			  BSPI_STRAP_OVERRIDE_CTRL_DATA_DUAL);
4784e3b2d23SKamal Dasu 		break;
4794e3b2d23SKamal Dasu 	case SPI_NBITS_QUAD:
4804e3b2d23SKamal Dasu 		/* clear dual mode and set quad mode */
4814e3b2d23SKamal Dasu 		data &= ~BSPI_STRAP_OVERRIDE_CTRL_DATA_DUAL;
4824e3b2d23SKamal Dasu 		data |= BSPI_STRAP_OVERRIDE_CTRL_DATA_QUAD;
4834e3b2d23SKamal Dasu 		break;
4844e3b2d23SKamal Dasu 	case SPI_NBITS_DUAL:
4854e3b2d23SKamal Dasu 		/* clear quad mode set dual mode */
4864e3b2d23SKamal Dasu 		data &= ~BSPI_STRAP_OVERRIDE_CTRL_DATA_QUAD;
4874e3b2d23SKamal Dasu 		data |= BSPI_STRAP_OVERRIDE_CTRL_DATA_DUAL;
4884e3b2d23SKamal Dasu 		break;
4894e3b2d23SKamal Dasu 	default:
4904e3b2d23SKamal Dasu 		return -EINVAL;
4914e3b2d23SKamal Dasu 	}
4924e3b2d23SKamal Dasu 
4934e3b2d23SKamal Dasu 	if (addrlen == BSPI_ADDRLEN_4BYTES)
4944e3b2d23SKamal Dasu 		/* set 4byte mode*/
4954e3b2d23SKamal Dasu 		data |= BSPI_STRAP_OVERRIDE_CTRL_ADDR_4BYTE;
4964e3b2d23SKamal Dasu 	else
4974e3b2d23SKamal Dasu 		/* clear 4 byte mode */
4984e3b2d23SKamal Dasu 		data &= ~BSPI_STRAP_OVERRIDE_CTRL_ADDR_4BYTE;
4994e3b2d23SKamal Dasu 
5004e3b2d23SKamal Dasu 	/* set the override mode */
5014e3b2d23SKamal Dasu 	data |=	BSPI_STRAP_OVERRIDE_CTRL_OVERRIDE;
5024e3b2d23SKamal Dasu 	bcm_qspi_write(qspi, BSPI, BSPI_STRAP_OVERRIDE_CTRL, data);
5035f195ee7SBoris Brezillon 	bcm_qspi_bspi_set_xfer_params(qspi, op->cmd.opcode, 0, 0, 0);
5044e3b2d23SKamal Dasu 
5054e3b2d23SKamal Dasu 	return 0;
5064e3b2d23SKamal Dasu }
5074e3b2d23SKamal Dasu 
bcm_qspi_bspi_set_mode(struct bcm_qspi * qspi,const struct spi_mem_op * op,int hp)5084e3b2d23SKamal Dasu static int bcm_qspi_bspi_set_mode(struct bcm_qspi *qspi,
5095f195ee7SBoris Brezillon 				  const struct spi_mem_op *op, int hp)
5104e3b2d23SKamal Dasu {
5114e3b2d23SKamal Dasu 	int error = 0;
5125f195ee7SBoris Brezillon 	int width = op->data.buswidth ? op->data.buswidth : SPI_NBITS_SINGLE;
5135f195ee7SBoris Brezillon 	int addrlen = op->addr.nbytes;
5144e3b2d23SKamal Dasu 
5154e3b2d23SKamal Dasu 	/* default mode */
5164e3b2d23SKamal Dasu 	qspi->xfer_mode.flex_mode = true;
5174e3b2d23SKamal Dasu 
5184e3b2d23SKamal Dasu 	if (!bcm_qspi_bspi_ver_three(qspi)) {
5194e3b2d23SKamal Dasu 		u32 val, mask;
5204e3b2d23SKamal Dasu 
5214e3b2d23SKamal Dasu 		val = bcm_qspi_read(qspi, BSPI, BSPI_STRAP_OVERRIDE_CTRL);
5224e3b2d23SKamal Dasu 		mask = BSPI_STRAP_OVERRIDE_CTRL_OVERRIDE;
5234e3b2d23SKamal Dasu 		if (val & mask || qspi->s3_strap_override_ctrl & mask) {
5244e3b2d23SKamal Dasu 			qspi->xfer_mode.flex_mode = false;
525054e532fSKamal Dasu 			bcm_qspi_write(qspi, BSPI, BSPI_FLEX_MODE_ENABLE, 0);
5265f195ee7SBoris Brezillon 			error = bcm_qspi_bspi_set_override(qspi, op, hp);
5274e3b2d23SKamal Dasu 		}
5284e3b2d23SKamal Dasu 	}
5294e3b2d23SKamal Dasu 
5304e3b2d23SKamal Dasu 	if (qspi->xfer_mode.flex_mode)
5315f195ee7SBoris Brezillon 		error = bcm_qspi_bspi_set_flex_mode(qspi, op, hp);
5324e3b2d23SKamal Dasu 
5334e3b2d23SKamal Dasu 	if (error) {
5344e3b2d23SKamal Dasu 		dev_warn(&qspi->pdev->dev,
5354e3b2d23SKamal Dasu 			 "INVALID COMBINATION: width=%d addrlen=%d hp=%d\n",
5364e3b2d23SKamal Dasu 			 width, addrlen, hp);
5374e3b2d23SKamal Dasu 	} else if (qspi->xfer_mode.width != width ||
5384e3b2d23SKamal Dasu 		   qspi->xfer_mode.addrlen != addrlen ||
5394e3b2d23SKamal Dasu 		   qspi->xfer_mode.hp != hp) {
5404e3b2d23SKamal Dasu 		qspi->xfer_mode.width = width;
5414e3b2d23SKamal Dasu 		qspi->xfer_mode.addrlen = addrlen;
5424e3b2d23SKamal Dasu 		qspi->xfer_mode.hp = hp;
5434e3b2d23SKamal Dasu 		dev_dbg(&qspi->pdev->dev,
5444e3b2d23SKamal Dasu 			"cs:%d %d-lane output, %d-byte address%s\n",
5454e3b2d23SKamal Dasu 			qspi->curr_cs,
5464e3b2d23SKamal Dasu 			qspi->xfer_mode.width,
5474e3b2d23SKamal Dasu 			qspi->xfer_mode.addrlen,
5484e3b2d23SKamal Dasu 			qspi->xfer_mode.hp != -1 ? ", hp mode" : "");
5494e3b2d23SKamal Dasu 	}
5504e3b2d23SKamal Dasu 
5514e3b2d23SKamal Dasu 	return error;
5524e3b2d23SKamal Dasu }
5534e3b2d23SKamal Dasu 
bcm_qspi_enable_bspi(struct bcm_qspi * qspi)5544e3b2d23SKamal Dasu static void bcm_qspi_enable_bspi(struct bcm_qspi *qspi)
5554e3b2d23SKamal Dasu {
556602805fbSKamal Dasu 	if (!has_bspi(qspi))
5574e3b2d23SKamal Dasu 		return;
5584e3b2d23SKamal Dasu 
5594e3b2d23SKamal Dasu 	qspi->bspi_enabled = 1;
5604e3b2d23SKamal Dasu 	if ((bcm_qspi_read(qspi, BSPI, BSPI_MAST_N_BOOT_CTRL) & 1) == 0)
5614e3b2d23SKamal Dasu 		return;
5624e3b2d23SKamal Dasu 
5634e3b2d23SKamal Dasu 	bcm_qspi_bspi_flush_prefetch_buffers(qspi);
5644e3b2d23SKamal Dasu 	udelay(1);
5654e3b2d23SKamal Dasu 	bcm_qspi_write(qspi, BSPI, BSPI_MAST_N_BOOT_CTRL, 0);
5664e3b2d23SKamal Dasu 	udelay(1);
5674e3b2d23SKamal Dasu }
5684e3b2d23SKamal Dasu 
bcm_qspi_disable_bspi(struct bcm_qspi * qspi)5694e3b2d23SKamal Dasu static void bcm_qspi_disable_bspi(struct bcm_qspi *qspi)
5704e3b2d23SKamal Dasu {
571602805fbSKamal Dasu 	if (!has_bspi(qspi))
5724e3b2d23SKamal Dasu 		return;
5734e3b2d23SKamal Dasu 
5744e3b2d23SKamal Dasu 	qspi->bspi_enabled = 0;
5754e3b2d23SKamal Dasu 	if ((bcm_qspi_read(qspi, BSPI, BSPI_MAST_N_BOOT_CTRL) & 1))
5764e3b2d23SKamal Dasu 		return;
5774e3b2d23SKamal Dasu 
5784e3b2d23SKamal Dasu 	bcm_qspi_bspi_busy_poll(qspi);
5794e3b2d23SKamal Dasu 	bcm_qspi_write(qspi, BSPI, BSPI_MAST_N_BOOT_CTRL, 1);
5804e3b2d23SKamal Dasu 	udelay(1);
5814e3b2d23SKamal Dasu }
5824e3b2d23SKamal Dasu 
bcm_qspi_chip_select(struct bcm_qspi * qspi,int cs)583fa236a7eSKamal Dasu static void bcm_qspi_chip_select(struct bcm_qspi *qspi, int cs)
584fa236a7eSKamal Dasu {
5855eb9a07aSKamal Dasu 	u32 rd = 0;
5865eb9a07aSKamal Dasu 	u32 wr = 0;
587fa236a7eSKamal Dasu 
5882cbd2726SKamal Dasu 	if (cs >= 0 && qspi->base[CHIP_SELECT]) {
5895eb9a07aSKamal Dasu 		rd = bcm_qspi_read(qspi, CHIP_SELECT, 0);
5905eb9a07aSKamal Dasu 		wr = (rd & ~0xff) | (1 << cs);
5915eb9a07aSKamal Dasu 		if (rd == wr)
5925eb9a07aSKamal Dasu 			return;
5935eb9a07aSKamal Dasu 		bcm_qspi_write(qspi, CHIP_SELECT, 0, wr);
594fa236a7eSKamal Dasu 		usleep_range(10, 20);
595fa236a7eSKamal Dasu 	}
5965eb9a07aSKamal Dasu 
5975eb9a07aSKamal Dasu 	dev_dbg(&qspi->pdev->dev, "using cs:%d\n", cs);
598fa236a7eSKamal Dasu 	qspi->curr_cs = cs;
599fa236a7eSKamal Dasu }
600fa236a7eSKamal Dasu 
bcmspi_parms_did_change(const struct bcm_qspi_parms * const cur,const struct bcm_qspi_parms * const prev)601e10a6bb5SKamal Dasu static bool bcmspi_parms_did_change(const struct bcm_qspi_parms * const cur,
602e10a6bb5SKamal Dasu 				    const struct bcm_qspi_parms * const prev)
603e10a6bb5SKamal Dasu {
604e10a6bb5SKamal Dasu 	return (cur->speed_hz != prev->speed_hz) ||
605e10a6bb5SKamal Dasu 		(cur->mode != prev->mode) ||
606e10a6bb5SKamal Dasu 		(cur->bits_per_word != prev->bits_per_word);
607e10a6bb5SKamal Dasu }
608e10a6bb5SKamal Dasu 
609e10a6bb5SKamal Dasu 
610fa236a7eSKamal Dasu /* MSPI helpers */
bcm_qspi_hw_set_parms(struct bcm_qspi * qspi,const struct bcm_qspi_parms * xp)611fa236a7eSKamal Dasu static void bcm_qspi_hw_set_parms(struct bcm_qspi *qspi,
612fa236a7eSKamal Dasu 				  const struct bcm_qspi_parms *xp)
613fa236a7eSKamal Dasu {
614fa236a7eSKamal Dasu 	u32 spcr, spbr = 0;
615fa236a7eSKamal Dasu 
616e10a6bb5SKamal Dasu 	if (!bcmspi_parms_did_change(xp, &qspi->last_parms))
617e10a6bb5SKamal Dasu 		return;
618e10a6bb5SKamal Dasu 
6192f5f5302SKamal Dasu 	if (!qspi->mspi_maj_rev)
6202f5f5302SKamal Dasu 		/* legacy controller */
621fa236a7eSKamal Dasu 		spcr = MSPI_MASTER_BIT;
6222f5f5302SKamal Dasu 	else
6232f5f5302SKamal Dasu 		spcr = 0;
6242f5f5302SKamal Dasu 
625ee4d62c4SKamal Dasu 	/*
626ee4d62c4SKamal Dasu 	 * Bits per transfer.  BITS determines the number of data bits
627ee4d62c4SKamal Dasu 	 * transferred if the command control bit (BITSE of a
628ee4d62c4SKamal Dasu 	 * CDRAM Register) is equal to 1.
629ee4d62c4SKamal Dasu 	 * If CDRAM BITSE is equal to 0, 8 data bits are transferred
630ee4d62c4SKamal Dasu 	 * regardless
631ee4d62c4SKamal Dasu 	 */
632ee4d62c4SKamal Dasu 	if (xp->bits_per_word != 16 && xp->bits_per_word != 64)
633ee4d62c4SKamal Dasu 		spcr |= xp->bits_per_word << MSPI_SPCR0_MSB_BITS_SHIFT;
6342f5f5302SKamal Dasu 
635ee4d62c4SKamal Dasu 	spcr |= xp->mode & (MSPI_SPCR0_MSB_CPHA | MSPI_SPCR0_MSB_CPOL);
636fa236a7eSKamal Dasu 	bcm_qspi_write(qspi, MSPI, MSPI_SPCR0_MSB, spcr);
637fa236a7eSKamal Dasu 
638d9576ae5SKamal Dasu 	if (bcm_qspi_has_fastbr(qspi)) {
639d9576ae5SKamal Dasu 		spcr = 0;
640d9576ae5SKamal Dasu 
641d9576ae5SKamal Dasu 		/* enable fastbr */
642d9576ae5SKamal Dasu 		spcr |=	MSPI_SPCR3_FASTBR;
64343613a77SKamal Dasu 
644e81cd07dSKamal Dasu 		if (xp->mode & SPI_3WIRE)
645e81cd07dSKamal Dasu 			spcr |= MSPI_SPCR3_HALFDUPLEX |  MSPI_SPCR3_HDOUTTYPE;
646e81cd07dSKamal Dasu 
64743613a77SKamal Dasu 		if (bcm_qspi_has_sysclk_108(qspi)) {
648c74526f9SKamal Dasu 			/* check requested baud rate before moving to 108Mhz */
649c74526f9SKamal Dasu 			spbr = bcm_qspi_calc_spbr(MSPI_BASE_FREQ * 4, xp);
650c74526f9SKamal Dasu 			if (spbr > QSPI_SPBR_MAX) {
651c74526f9SKamal Dasu 				/* use SYSCLK_27Mhz for slower baud rates */
652c74526f9SKamal Dasu 				spcr &= ~MSPI_SPCR3_SYSCLKSEL_MASK;
653c74526f9SKamal Dasu 				qspi->base_clk = MSPI_BASE_FREQ;
654c74526f9SKamal Dasu 			} else {
655c74526f9SKamal Dasu 				/* SYSCLK_108Mhz */
65643613a77SKamal Dasu 				spcr |= MSPI_SPCR3_SYSCLKSEL_108;
65743613a77SKamal Dasu 				qspi->base_clk = MSPI_BASE_FREQ * 4;
65843613a77SKamal Dasu 			}
659c74526f9SKamal Dasu 		}
66043613a77SKamal Dasu 
661ee4d62c4SKamal Dasu 		if (xp->bits_per_word > 16) {
662ee4d62c4SKamal Dasu 			/* data_reg_size 1 (64bit) */
663ee4d62c4SKamal Dasu 			spcr |=	MSPI_SPCR3_DATA_REG_SZ;
664ee4d62c4SKamal Dasu 			/* TxRx RAM data access mode 2 for 32B and set fastdt */
665ee4d62c4SKamal Dasu 			spcr |=	MSPI_SPCR3_DAM_32BYTE  | MSPI_SPCR3_FASTDT;
666ee4d62c4SKamal Dasu 			/*
667ee4d62c4SKamal Dasu 			 *  Set length of delay after transfer
668ee4d62c4SKamal Dasu 			 *  DTL from 0(256) to 1
669ee4d62c4SKamal Dasu 			 */
670ee4d62c4SKamal Dasu 			bcm_qspi_write(qspi, MSPI, MSPI_SPCR1_LSB, 1);
671ee4d62c4SKamal Dasu 		} else {
672ee4d62c4SKamal Dasu 			/* data_reg_size[8] = 0 */
673ee4d62c4SKamal Dasu 			spcr &=	~(MSPI_SPCR3_DATA_REG_SZ);
674ee4d62c4SKamal Dasu 
675ee4d62c4SKamal Dasu 			/*
676ee4d62c4SKamal Dasu 			 * TxRx RAM access mode 8B
677ee4d62c4SKamal Dasu 			 * and disable fastdt
678ee4d62c4SKamal Dasu 			 */
679ee4d62c4SKamal Dasu 			spcr &= ~(MSPI_SPCR3_DAM_32BYTE);
680ee4d62c4SKamal Dasu 		}
681d9576ae5SKamal Dasu 		bcm_qspi_write(qspi, MSPI, MSPI_SPCR3, spcr);
682d9576ae5SKamal Dasu 	}
683d9576ae5SKamal Dasu 
684c74526f9SKamal Dasu 	/* SCK Baud Rate = System Clock/(2 * SPBR) */
685c74526f9SKamal Dasu 	qspi->max_speed_hz = qspi->base_clk / (bcm_qspi_spbr_min(qspi) * 2);
686c74526f9SKamal Dasu 	spbr = bcm_qspi_calc_spbr(qspi->base_clk, xp);
687ee4d62c4SKamal Dasu 	spbr = clamp_val(spbr, bcm_qspi_spbr_min(qspi), QSPI_SPBR_MAX);
688ee4d62c4SKamal Dasu 	bcm_qspi_write(qspi, MSPI, MSPI_SPCR0_LSB, spbr);
689ee4d62c4SKamal Dasu 
690fa236a7eSKamal Dasu 	qspi->last_parms = *xp;
691fa236a7eSKamal Dasu }
692fa236a7eSKamal Dasu 
bcm_qspi_update_parms(struct bcm_qspi * qspi,struct spi_device * spi,struct spi_transfer * trans)693fa236a7eSKamal Dasu static void bcm_qspi_update_parms(struct bcm_qspi *qspi,
694fa236a7eSKamal Dasu 				  struct spi_device *spi,
695fa236a7eSKamal Dasu 				  struct spi_transfer *trans)
696fa236a7eSKamal Dasu {
697fa236a7eSKamal Dasu 	struct bcm_qspi_parms xp;
698fa236a7eSKamal Dasu 
699fa236a7eSKamal Dasu 	xp.speed_hz = trans->speed_hz;
700fa236a7eSKamal Dasu 	xp.bits_per_word = trans->bits_per_word;
701fa236a7eSKamal Dasu 	xp.mode = spi->mode;
702fa236a7eSKamal Dasu 
703fa236a7eSKamal Dasu 	bcm_qspi_hw_set_parms(qspi, &xp);
704fa236a7eSKamal Dasu }
705fa236a7eSKamal Dasu 
bcm_qspi_setup(struct spi_device * spi)706fa236a7eSKamal Dasu static int bcm_qspi_setup(struct spi_device *spi)
707fa236a7eSKamal Dasu {
708fa236a7eSKamal Dasu 	struct bcm_qspi_parms *xp;
709fa236a7eSKamal Dasu 
710ee4d62c4SKamal Dasu 	if (spi->bits_per_word > 64)
711fa236a7eSKamal Dasu 		return -EINVAL;
712fa236a7eSKamal Dasu 
713fa236a7eSKamal Dasu 	xp = spi_get_ctldata(spi);
714fa236a7eSKamal Dasu 	if (!xp) {
715fa236a7eSKamal Dasu 		xp = kzalloc(sizeof(*xp), GFP_KERNEL);
716fa236a7eSKamal Dasu 		if (!xp)
717fa236a7eSKamal Dasu 			return -ENOMEM;
718fa236a7eSKamal Dasu 		spi_set_ctldata(spi, xp);
719fa236a7eSKamal Dasu 	}
720fa236a7eSKamal Dasu 	xp->speed_hz = spi->max_speed_hz;
721fa236a7eSKamal Dasu 	xp->mode = spi->mode;
722fa236a7eSKamal Dasu 
723fa236a7eSKamal Dasu 	if (spi->bits_per_word)
724fa236a7eSKamal Dasu 		xp->bits_per_word = spi->bits_per_word;
725fa236a7eSKamal Dasu 	else
726fa236a7eSKamal Dasu 		xp->bits_per_word = 8;
727fa236a7eSKamal Dasu 
728fa236a7eSKamal Dasu 	return 0;
729fa236a7eSKamal Dasu }
730fa236a7eSKamal Dasu 
bcm_qspi_mspi_transfer_is_last(struct bcm_qspi * qspi,struct qspi_trans * qt)73181ab52fdSKamal Dasu static bool bcm_qspi_mspi_transfer_is_last(struct bcm_qspi *qspi,
73281ab52fdSKamal Dasu 					   struct qspi_trans *qt)
73381ab52fdSKamal Dasu {
73481ab52fdSKamal Dasu 	if (qt->mspi_last_trans &&
735ec271c04SYang Yingliang 	    spi_transfer_is_last(qspi->host, qt->trans))
73681ab52fdSKamal Dasu 		return true;
73781ab52fdSKamal Dasu 	else
73881ab52fdSKamal Dasu 		return false;
73981ab52fdSKamal Dasu }
74081ab52fdSKamal Dasu 
update_qspi_trans_byte_count(struct bcm_qspi * qspi,struct qspi_trans * qt,int flags)741fa236a7eSKamal Dasu static int update_qspi_trans_byte_count(struct bcm_qspi *qspi,
742fa236a7eSKamal Dasu 					struct qspi_trans *qt, int flags)
743fa236a7eSKamal Dasu {
744fa236a7eSKamal Dasu 	int ret = TRANS_STATUS_BREAK_NONE;
745fa236a7eSKamal Dasu 
746fa236a7eSKamal Dasu 	/* count the last transferred bytes */
747fa236a7eSKamal Dasu 	if (qt->trans->bits_per_word <= 8)
748fa236a7eSKamal Dasu 		qt->byte++;
749ee4d62c4SKamal Dasu 	else if (qt->trans->bits_per_word <= 16)
750fa236a7eSKamal Dasu 		qt->byte += 2;
751ee4d62c4SKamal Dasu 	else if (qt->trans->bits_per_word <= 32)
752ee4d62c4SKamal Dasu 		qt->byte += 4;
753ee4d62c4SKamal Dasu 	else if (qt->trans->bits_per_word <= 64)
754ee4d62c4SKamal Dasu 		qt->byte += 8;
755fa236a7eSKamal Dasu 
756fa236a7eSKamal Dasu 	if (qt->byte >= qt->trans->len) {
757fa236a7eSKamal Dasu 		/* we're at the end of the spi_transfer */
758fa236a7eSKamal Dasu 		/* in TX mode, need to pause for a delay or CS change */
75966a3aadeSAlexandru Ardelean 		if (qt->trans->delay.value &&
760fa236a7eSKamal Dasu 		    (flags & TRANS_STATUS_BREAK_DELAY))
761fa236a7eSKamal Dasu 			ret |= TRANS_STATUS_BREAK_DELAY;
762fa236a7eSKamal Dasu 		if (qt->trans->cs_change &&
763fa236a7eSKamal Dasu 		    (flags & TRANS_STATUS_BREAK_CS_CHANGE))
764fa236a7eSKamal Dasu 			ret |= TRANS_STATUS_BREAK_CS_CHANGE;
765fa236a7eSKamal Dasu 
76681ab52fdSKamal Dasu 		if (bcm_qspi_mspi_transfer_is_last(qspi, qt))
767742d5958SKamal Dasu 			ret |= TRANS_STATUS_BREAK_EOM;
768fa236a7eSKamal Dasu 		else
769742d5958SKamal Dasu 			ret |= TRANS_STATUS_BREAK_NO_BYTES;
770fa236a7eSKamal Dasu 
771fa236a7eSKamal Dasu 		qt->trans = NULL;
772fa236a7eSKamal Dasu 	}
773fa236a7eSKamal Dasu 
774fa236a7eSKamal Dasu 	dev_dbg(&qspi->pdev->dev, "trans %p len %d byte %d ret %x\n",
775fa236a7eSKamal Dasu 		qt->trans, qt->trans ? qt->trans->len : 0, qt->byte, ret);
776fa236a7eSKamal Dasu 	return ret;
777fa236a7eSKamal Dasu }
778fa236a7eSKamal Dasu 
read_rxram_slot_u8(struct bcm_qspi * qspi,int slot)779fa236a7eSKamal Dasu static inline u8 read_rxram_slot_u8(struct bcm_qspi *qspi, int slot)
780fa236a7eSKamal Dasu {
781fa236a7eSKamal Dasu 	u32 slot_offset = MSPI_RXRAM + (slot << 3) + 0x4;
782fa236a7eSKamal Dasu 
783fa236a7eSKamal Dasu 	/* mask out reserved bits */
784fa236a7eSKamal Dasu 	return bcm_qspi_read(qspi, MSPI, slot_offset) & 0xff;
785fa236a7eSKamal Dasu }
786fa236a7eSKamal Dasu 
read_rxram_slot_u16(struct bcm_qspi * qspi,int slot)787fa236a7eSKamal Dasu static inline u16 read_rxram_slot_u16(struct bcm_qspi *qspi, int slot)
788fa236a7eSKamal Dasu {
789fa236a7eSKamal Dasu 	u32 reg_offset = MSPI_RXRAM;
790fa236a7eSKamal Dasu 	u32 lsb_offset = reg_offset + (slot << 3) + 0x4;
791fa236a7eSKamal Dasu 	u32 msb_offset = reg_offset + (slot << 3);
792fa236a7eSKamal Dasu 
793fa236a7eSKamal Dasu 	return (bcm_qspi_read(qspi, MSPI, lsb_offset) & 0xff) |
794fa236a7eSKamal Dasu 		((bcm_qspi_read(qspi, MSPI, msb_offset) & 0xff) << 8);
795fa236a7eSKamal Dasu }
796fa236a7eSKamal Dasu 
read_rxram_slot_u32(struct bcm_qspi * qspi,int slot)797ee4d62c4SKamal Dasu static inline u32 read_rxram_slot_u32(struct bcm_qspi *qspi, int slot)
798ee4d62c4SKamal Dasu {
799ee4d62c4SKamal Dasu 	u32 reg_offset = MSPI_RXRAM;
800ee4d62c4SKamal Dasu 	u32 offset = reg_offset + (slot << 3);
801ee4d62c4SKamal Dasu 	u32 val;
802ee4d62c4SKamal Dasu 
803ee4d62c4SKamal Dasu 	val = bcm_qspi_read(qspi, MSPI, offset);
804ee4d62c4SKamal Dasu 	val = swap4bytes(val);
805ee4d62c4SKamal Dasu 
806ee4d62c4SKamal Dasu 	return val;
807ee4d62c4SKamal Dasu }
808ee4d62c4SKamal Dasu 
read_rxram_slot_u64(struct bcm_qspi * qspi,int slot)809ee4d62c4SKamal Dasu static inline u64 read_rxram_slot_u64(struct bcm_qspi *qspi, int slot)
810ee4d62c4SKamal Dasu {
811ee4d62c4SKamal Dasu 	u32 reg_offset = MSPI_RXRAM;
812ee4d62c4SKamal Dasu 	u32 lsb_offset = reg_offset + (slot << 3) + 0x4;
813ee4d62c4SKamal Dasu 	u32 msb_offset = reg_offset + (slot << 3);
814ee4d62c4SKamal Dasu 	u32 msb, lsb;
815ee4d62c4SKamal Dasu 
816ee4d62c4SKamal Dasu 	msb = bcm_qspi_read(qspi, MSPI, msb_offset);
817ee4d62c4SKamal Dasu 	msb = swap4bytes(msb);
818ee4d62c4SKamal Dasu 	lsb = bcm_qspi_read(qspi, MSPI, lsb_offset);
819ee4d62c4SKamal Dasu 	lsb = swap4bytes(lsb);
820ee4d62c4SKamal Dasu 
821ee4d62c4SKamal Dasu 	return ((u64)msb << 32 | lsb);
822ee4d62c4SKamal Dasu }
823ee4d62c4SKamal Dasu 
read_from_hw(struct bcm_qspi * qspi,int slots)824fa236a7eSKamal Dasu static void read_from_hw(struct bcm_qspi *qspi, int slots)
825fa236a7eSKamal Dasu {
826fa236a7eSKamal Dasu 	struct qspi_trans tp;
827fa236a7eSKamal Dasu 	int slot;
828fa236a7eSKamal Dasu 
8294e3b2d23SKamal Dasu 	bcm_qspi_disable_bspi(qspi);
8304e3b2d23SKamal Dasu 
831fa236a7eSKamal Dasu 	if (slots > MSPI_NUM_CDRAM) {
832fa236a7eSKamal Dasu 		/* should never happen */
833fa236a7eSKamal Dasu 		dev_err(&qspi->pdev->dev, "%s: too many slots!\n", __func__);
834fa236a7eSKamal Dasu 		return;
835fa236a7eSKamal Dasu 	}
836fa236a7eSKamal Dasu 
837fa236a7eSKamal Dasu 	tp = qspi->trans_pos;
838fa236a7eSKamal Dasu 
839fa236a7eSKamal Dasu 	for (slot = 0; slot < slots; slot++) {
840fa236a7eSKamal Dasu 		if (tp.trans->bits_per_word <= 8) {
841fa236a7eSKamal Dasu 			u8 *buf = tp.trans->rx_buf;
842fa236a7eSKamal Dasu 
843fa236a7eSKamal Dasu 			if (buf)
844fa236a7eSKamal Dasu 				buf[tp.byte] = read_rxram_slot_u8(qspi, slot);
845fa236a7eSKamal Dasu 			dev_dbg(&qspi->pdev->dev, "RD %02x\n",
8464df3bea7SJustin Chen 				buf ? buf[tp.byte] : 0x0);
847ee4d62c4SKamal Dasu 		} else if (tp.trans->bits_per_word <= 16) {
848fa236a7eSKamal Dasu 			u16 *buf = tp.trans->rx_buf;
849fa236a7eSKamal Dasu 
850fa236a7eSKamal Dasu 			if (buf)
851fa236a7eSKamal Dasu 				buf[tp.byte / 2] = read_rxram_slot_u16(qspi,
852fa236a7eSKamal Dasu 								      slot);
853fa236a7eSKamal Dasu 			dev_dbg(&qspi->pdev->dev, "RD %04x\n",
8544df3bea7SJustin Chen 				buf ? buf[tp.byte / 2] : 0x0);
855ee4d62c4SKamal Dasu 		} else if (tp.trans->bits_per_word <= 32) {
856ee4d62c4SKamal Dasu 			u32 *buf = tp.trans->rx_buf;
857ee4d62c4SKamal Dasu 
858ee4d62c4SKamal Dasu 			if (buf)
859ee4d62c4SKamal Dasu 				buf[tp.byte / 4] = read_rxram_slot_u32(qspi,
860ee4d62c4SKamal Dasu 								      slot);
861ee4d62c4SKamal Dasu 			dev_dbg(&qspi->pdev->dev, "RD %08x\n",
862ee4d62c4SKamal Dasu 				buf ? buf[tp.byte / 4] : 0x0);
863ee4d62c4SKamal Dasu 
864ee4d62c4SKamal Dasu 		} else if (tp.trans->bits_per_word <= 64) {
865ee4d62c4SKamal Dasu 			u64 *buf = tp.trans->rx_buf;
866ee4d62c4SKamal Dasu 
867ee4d62c4SKamal Dasu 			if (buf)
868ee4d62c4SKamal Dasu 				buf[tp.byte / 8] = read_rxram_slot_u64(qspi,
869ee4d62c4SKamal Dasu 								      slot);
870ee4d62c4SKamal Dasu 			dev_dbg(&qspi->pdev->dev, "RD %llx\n",
871ee4d62c4SKamal Dasu 				buf ? buf[tp.byte / 8] : 0x0);
872ee4d62c4SKamal Dasu 
873ee4d62c4SKamal Dasu 
874fa236a7eSKamal Dasu 		}
875fa236a7eSKamal Dasu 
876fa236a7eSKamal Dasu 		update_qspi_trans_byte_count(qspi, &tp,
877fa236a7eSKamal Dasu 					     TRANS_STATUS_BREAK_NONE);
878fa236a7eSKamal Dasu 	}
879fa236a7eSKamal Dasu 
880fa236a7eSKamal Dasu 	qspi->trans_pos = tp;
881fa236a7eSKamal Dasu }
882fa236a7eSKamal Dasu 
write_txram_slot_u8(struct bcm_qspi * qspi,int slot,u8 val)883fa236a7eSKamal Dasu static inline void write_txram_slot_u8(struct bcm_qspi *qspi, int slot,
884fa236a7eSKamal Dasu 				       u8 val)
885fa236a7eSKamal Dasu {
886fa236a7eSKamal Dasu 	u32 reg_offset = MSPI_TXRAM + (slot << 3);
887fa236a7eSKamal Dasu 
888fa236a7eSKamal Dasu 	/* mask out reserved bits */
889fa236a7eSKamal Dasu 	bcm_qspi_write(qspi, MSPI, reg_offset, val);
890fa236a7eSKamal Dasu }
891fa236a7eSKamal Dasu 
write_txram_slot_u16(struct bcm_qspi * qspi,int slot,u16 val)892fa236a7eSKamal Dasu static inline void write_txram_slot_u16(struct bcm_qspi *qspi, int slot,
893fa236a7eSKamal Dasu 					u16 val)
894fa236a7eSKamal Dasu {
895fa236a7eSKamal Dasu 	u32 reg_offset = MSPI_TXRAM;
896fa236a7eSKamal Dasu 	u32 msb_offset = reg_offset + (slot << 3);
897fa236a7eSKamal Dasu 	u32 lsb_offset = reg_offset + (slot << 3) + 0x4;
898fa236a7eSKamal Dasu 
899fa236a7eSKamal Dasu 	bcm_qspi_write(qspi, MSPI, msb_offset, (val >> 8));
900fa236a7eSKamal Dasu 	bcm_qspi_write(qspi, MSPI, lsb_offset, (val & 0xff));
901fa236a7eSKamal Dasu }
902fa236a7eSKamal Dasu 
write_txram_slot_u32(struct bcm_qspi * qspi,int slot,u32 val)903ee4d62c4SKamal Dasu static inline void write_txram_slot_u32(struct bcm_qspi *qspi, int slot,
904ee4d62c4SKamal Dasu 					u32 val)
905ee4d62c4SKamal Dasu {
906ee4d62c4SKamal Dasu 	u32 reg_offset = MSPI_TXRAM;
907ee4d62c4SKamal Dasu 	u32 msb_offset = reg_offset + (slot << 3);
908ee4d62c4SKamal Dasu 
909ee4d62c4SKamal Dasu 	bcm_qspi_write(qspi, MSPI, msb_offset, swap4bytes(val));
910ee4d62c4SKamal Dasu }
911ee4d62c4SKamal Dasu 
write_txram_slot_u64(struct bcm_qspi * qspi,int slot,u64 val)912ee4d62c4SKamal Dasu static inline void write_txram_slot_u64(struct bcm_qspi *qspi, int slot,
913ee4d62c4SKamal Dasu 					u64 val)
914ee4d62c4SKamal Dasu {
915ee4d62c4SKamal Dasu 	u32 reg_offset = MSPI_TXRAM;
916ee4d62c4SKamal Dasu 	u32 msb_offset = reg_offset + (slot << 3);
917ee4d62c4SKamal Dasu 	u32 lsb_offset = reg_offset + (slot << 3) + 0x4;
918ee4d62c4SKamal Dasu 	u32 msb = upper_32_bits(val);
919ee4d62c4SKamal Dasu 	u32 lsb = lower_32_bits(val);
920ee4d62c4SKamal Dasu 
921ee4d62c4SKamal Dasu 	bcm_qspi_write(qspi, MSPI, msb_offset, swap4bytes(msb));
922ee4d62c4SKamal Dasu 	bcm_qspi_write(qspi, MSPI, lsb_offset, swap4bytes(lsb));
923ee4d62c4SKamal Dasu }
924ee4d62c4SKamal Dasu 
read_cdram_slot(struct bcm_qspi * qspi,int slot)925fa236a7eSKamal Dasu static inline u32 read_cdram_slot(struct bcm_qspi *qspi, int slot)
926fa236a7eSKamal Dasu {
927fa236a7eSKamal Dasu 	return bcm_qspi_read(qspi, MSPI, MSPI_CDRAM + (slot << 2));
928fa236a7eSKamal Dasu }
929fa236a7eSKamal Dasu 
write_cdram_slot(struct bcm_qspi * qspi,int slot,u32 val)930fa236a7eSKamal Dasu static inline void write_cdram_slot(struct bcm_qspi *qspi, int slot, u32 val)
931fa236a7eSKamal Dasu {
932fa236a7eSKamal Dasu 	bcm_qspi_write(qspi, MSPI, (MSPI_CDRAM + (slot << 2)), val);
933fa236a7eSKamal Dasu }
934fa236a7eSKamal Dasu 
935fa236a7eSKamal Dasu /* Return number of slots written */
write_to_hw(struct bcm_qspi * qspi,struct spi_device * spi)936fa236a7eSKamal Dasu static int write_to_hw(struct bcm_qspi *qspi, struct spi_device *spi)
937fa236a7eSKamal Dasu {
938fa236a7eSKamal Dasu 	struct qspi_trans tp;
939fa236a7eSKamal Dasu 	int slot = 0, tstatus = 0;
940fa236a7eSKamal Dasu 	u32 mspi_cdram = 0;
941fa236a7eSKamal Dasu 
9424e3b2d23SKamal Dasu 	bcm_qspi_disable_bspi(qspi);
943fa236a7eSKamal Dasu 	tp = qspi->trans_pos;
944fa236a7eSKamal Dasu 	bcm_qspi_update_parms(qspi, spi, tp.trans);
945fa236a7eSKamal Dasu 
946fa236a7eSKamal Dasu 	/* Run until end of transfer or reached the max data */
947fa236a7eSKamal Dasu 	while (!tstatus && slot < MSPI_NUM_CDRAM) {
948ee4d62c4SKamal Dasu 		mspi_cdram = MSPI_CDRAM_CONT_BIT;
949fa236a7eSKamal Dasu 		if (tp.trans->bits_per_word <= 8) {
950fa236a7eSKamal Dasu 			const u8 *buf = tp.trans->tx_buf;
9514df3bea7SJustin Chen 			u8 val = buf ? buf[tp.byte] : 0x00;
952fa236a7eSKamal Dasu 
953fa236a7eSKamal Dasu 			write_txram_slot_u8(qspi, slot, val);
954fa236a7eSKamal Dasu 			dev_dbg(&qspi->pdev->dev, "WR %02x\n", val);
955ee4d62c4SKamal Dasu 		} else if (tp.trans->bits_per_word <= 16) {
956fa236a7eSKamal Dasu 			const u16 *buf = tp.trans->tx_buf;
9574df3bea7SJustin Chen 			u16 val = buf ? buf[tp.byte / 2] : 0x0000;
958fa236a7eSKamal Dasu 
959fa236a7eSKamal Dasu 			write_txram_slot_u16(qspi, slot, val);
960fa236a7eSKamal Dasu 			dev_dbg(&qspi->pdev->dev, "WR %04x\n", val);
961ee4d62c4SKamal Dasu 		} else if (tp.trans->bits_per_word <= 32) {
962ee4d62c4SKamal Dasu 			const u32 *buf = tp.trans->tx_buf;
963ee4d62c4SKamal Dasu 			u32 val = buf ? buf[tp.byte/4] : 0x0;
964ee4d62c4SKamal Dasu 
965ee4d62c4SKamal Dasu 			write_txram_slot_u32(qspi, slot, val);
966ee4d62c4SKamal Dasu 			dev_dbg(&qspi->pdev->dev, "WR %08x\n", val);
967ee4d62c4SKamal Dasu 		} else if (tp.trans->bits_per_word <= 64) {
968ee4d62c4SKamal Dasu 			const u64 *buf = tp.trans->tx_buf;
969ee4d62c4SKamal Dasu 			u64 val = (buf ? buf[tp.byte/8] : 0x0);
970ee4d62c4SKamal Dasu 
971ee4d62c4SKamal Dasu 			/* use the length of delay from SPCR1_LSB */
972ee4d62c4SKamal Dasu 			if (bcm_qspi_has_fastbr(qspi))
973ee4d62c4SKamal Dasu 				mspi_cdram |= MSPI_CDRAM_DT_BIT;
974ee4d62c4SKamal Dasu 
975ee4d62c4SKamal Dasu 			write_txram_slot_u64(qspi, slot, val);
976ee4d62c4SKamal Dasu 			dev_dbg(&qspi->pdev->dev, "WR %llx\n", val);
977fa236a7eSKamal Dasu 		}
978ee4d62c4SKamal Dasu 
979ee4d62c4SKamal Dasu 		mspi_cdram |= ((tp.trans->bits_per_word <= 8) ? 0 :
980ee4d62c4SKamal Dasu 			       MSPI_CDRAM_BITSE_BIT);
9815eb9a07aSKamal Dasu 
982ec271c04SYang Yingliang 		/* set 3wrire halfduplex mode data from host to target */
983e81cd07dSKamal Dasu 		if ((spi->mode & SPI_3WIRE) && tp.trans->tx_buf)
984e81cd07dSKamal Dasu 			mspi_cdram |= MSPI_CDRAM_OUTP;
9855eb9a07aSKamal Dasu 
9865eb9a07aSKamal Dasu 		if (has_bspi(qspi))
9875eb9a07aSKamal Dasu 			mspi_cdram &= ~1;
9885eb9a07aSKamal Dasu 		else
9899e264f3fSAmit Kumar Mahapatra via Alsa-devel 			mspi_cdram |= (~(1 << spi_get_chipselect(spi, 0)) &
990fa236a7eSKamal Dasu 				       MSPI_CDRAM_PCS);
9915eb9a07aSKamal Dasu 
992fa236a7eSKamal Dasu 		write_cdram_slot(qspi, slot, mspi_cdram);
993fa236a7eSKamal Dasu 
994fa236a7eSKamal Dasu 		tstatus = update_qspi_trans_byte_count(qspi, &tp,
995fa236a7eSKamal Dasu 						       TRANS_STATUS_BREAK_TX);
996fa236a7eSKamal Dasu 		slot++;
997fa236a7eSKamal Dasu 	}
998fa236a7eSKamal Dasu 
999fa236a7eSKamal Dasu 	if (!slot) {
1000fa236a7eSKamal Dasu 		dev_err(&qspi->pdev->dev, "%s: no data to send?", __func__);
1001fa236a7eSKamal Dasu 		goto done;
1002fa236a7eSKamal Dasu 	}
1003fa236a7eSKamal Dasu 
1004fa236a7eSKamal Dasu 	dev_dbg(&qspi->pdev->dev, "submitting %d slots\n", slot);
1005fa236a7eSKamal Dasu 	bcm_qspi_write(qspi, MSPI, MSPI_NEWQP, 0);
1006fa236a7eSKamal Dasu 	bcm_qspi_write(qspi, MSPI, MSPI_ENDQP, slot - 1);
1007fa236a7eSKamal Dasu 
1008742d5958SKamal Dasu 	/*
1009742d5958SKamal Dasu 	 *  case 1) EOM =1, cs_change =0: SSb inactive
1010742d5958SKamal Dasu 	 *  case 2) EOM =1, cs_change =1: SSb stay active
1011742d5958SKamal Dasu 	 *  case 3) EOM =0, cs_change =0: SSb stay active
1012742d5958SKamal Dasu 	 *  case 4) EOM =0, cs_change =1: SSb inactive
1013742d5958SKamal Dasu 	 */
1014742d5958SKamal Dasu 	if (((tstatus & TRANS_STATUS_BREAK_DESELECT)
1015742d5958SKamal Dasu 	     == TRANS_STATUS_BREAK_CS_CHANGE) ||
1016742d5958SKamal Dasu 	    ((tstatus & TRANS_STATUS_BREAK_DESELECT)
1017742d5958SKamal Dasu 	     == TRANS_STATUS_BREAK_EOM)) {
1018fa236a7eSKamal Dasu 		mspi_cdram = read_cdram_slot(qspi, slot - 1) &
1019fa236a7eSKamal Dasu 			~MSPI_CDRAM_CONT_BIT;
1020fa236a7eSKamal Dasu 		write_cdram_slot(qspi, slot - 1, mspi_cdram);
1021fa236a7eSKamal Dasu 	}
1022fa236a7eSKamal Dasu 
10234e3b2d23SKamal Dasu 	if (has_bspi(qspi))
10244e3b2d23SKamal Dasu 		bcm_qspi_write(qspi, MSPI, MSPI_WRITE_LOCK, 1);
10254e3b2d23SKamal Dasu 
1026fa236a7eSKamal Dasu 	/* Must flush previous writes before starting MSPI operation */
1027fa236a7eSKamal Dasu 	mb();
1028fa236a7eSKamal Dasu 	/* Set cont | spe | spifie */
1029fa236a7eSKamal Dasu 	bcm_qspi_write(qspi, MSPI, MSPI_SPCR2, 0xe0);
1030fa236a7eSKamal Dasu 
1031fa236a7eSKamal Dasu done:
1032fa236a7eSKamal Dasu 	return slot;
1033fa236a7eSKamal Dasu }
1034fa236a7eSKamal Dasu 
bcm_qspi_bspi_exec_mem_op(struct spi_device * spi,const struct spi_mem_op * op)10355f195ee7SBoris Brezillon static int bcm_qspi_bspi_exec_mem_op(struct spi_device *spi,
10365f195ee7SBoris Brezillon 				     const struct spi_mem_op *op)
10374e3b2d23SKamal Dasu {
1038ec271c04SYang Yingliang 	struct bcm_qspi *qspi = spi_controller_get_devdata(spi->controller);
10395f195ee7SBoris Brezillon 	u32 addr = 0, len, rdlen, len_words, from = 0;
10404e3b2d23SKamal Dasu 	int ret = 0;
10414e3b2d23SKamal Dasu 	unsigned long timeo = msecs_to_jiffies(100);
1042cc20a386SKamal Dasu 	struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc;
10434e3b2d23SKamal Dasu 
10444e3b2d23SKamal Dasu 	if (bcm_qspi_bspi_ver_three(qspi))
10455f195ee7SBoris Brezillon 		if (op->addr.nbytes == BSPI_ADDRLEN_4BYTES)
10464e3b2d23SKamal Dasu 			return -EIO;
10474e3b2d23SKamal Dasu 
10485f195ee7SBoris Brezillon 	from = op->addr.val;
10499e264f3fSAmit Kumar Mahapatra via Alsa-devel 	if (!spi_get_csgpiod(spi, 0))
10509e264f3fSAmit Kumar Mahapatra via Alsa-devel 		bcm_qspi_chip_select(qspi, spi_get_chipselect(spi, 0));
10514e3b2d23SKamal Dasu 	bcm_qspi_write(qspi, MSPI, MSPI_WRITE_LOCK, 0);
10524e3b2d23SKamal Dasu 
10534e3b2d23SKamal Dasu 	/*
1054345309faSKamal Dasu 	 * when using flex mode we need to send
10554e3b2d23SKamal Dasu 	 * the upper address byte to bspi
10564e3b2d23SKamal Dasu 	 */
10576650ab2aSYANG LI 	if (!bcm_qspi_bspi_ver_three(qspi)) {
10585f195ee7SBoris Brezillon 		addr = from & 0xff000000;
10594e3b2d23SKamal Dasu 		bcm_qspi_write(qspi, BSPI,
10604e3b2d23SKamal Dasu 			       BSPI_BSPI_FLASH_UPPER_ADDR_BYTE, addr);
10614e3b2d23SKamal Dasu 	}
10624e3b2d23SKamal Dasu 
10634e3b2d23SKamal Dasu 	if (!qspi->xfer_mode.flex_mode)
10645f195ee7SBoris Brezillon 		addr = from;
10654e3b2d23SKamal Dasu 	else
10665f195ee7SBoris Brezillon 		addr = from & 0x00ffffff;
10674e3b2d23SKamal Dasu 
10684e3b2d23SKamal Dasu 	if (bcm_qspi_bspi_ver_three(qspi) == true)
10694e3b2d23SKamal Dasu 		addr = (addr + 0xc00000) & 0xffffff;
10704e3b2d23SKamal Dasu 
1071345309faSKamal Dasu 	/*
1072345309faSKamal Dasu 	 * read into the entire buffer by breaking the reads
1073345309faSKamal Dasu 	 * into RAF buffer read lengths
1074345309faSKamal Dasu 	 */
10755f195ee7SBoris Brezillon 	len = op->data.nbytes;
10765f195ee7SBoris Brezillon 	qspi->bspi_rf_op_idx = 0;
1077345309faSKamal Dasu 
1078345309faSKamal Dasu 	do {
1079345309faSKamal Dasu 		if (len > BSPI_READ_LENGTH)
1080345309faSKamal Dasu 			rdlen = BSPI_READ_LENGTH;
1081345309faSKamal Dasu 		else
1082345309faSKamal Dasu 			rdlen = len;
1083345309faSKamal Dasu 
10844e3b2d23SKamal Dasu 		reinit_completion(&qspi->bspi_done);
10854e3b2d23SKamal Dasu 		bcm_qspi_enable_bspi(qspi);
1086345309faSKamal Dasu 		len_words = (rdlen + 3) >> 2;
10875f195ee7SBoris Brezillon 		qspi->bspi_rf_op = op;
10885f195ee7SBoris Brezillon 		qspi->bspi_rf_op_status = 0;
10895f195ee7SBoris Brezillon 		qspi->bspi_rf_op_len = rdlen;
1090345309faSKamal Dasu 		dev_dbg(&qspi->pdev->dev,
1091345309faSKamal Dasu 			"bspi xfr addr 0x%x len 0x%x", addr, rdlen);
10924e3b2d23SKamal Dasu 		bcm_qspi_write(qspi, BSPI, BSPI_RAF_START_ADDR, addr);
10934e3b2d23SKamal Dasu 		bcm_qspi_write(qspi, BSPI, BSPI_RAF_NUM_WORDS, len_words);
10944e3b2d23SKamal Dasu 		bcm_qspi_write(qspi, BSPI, BSPI_RAF_WATERMARK, 0);
1095cc20a386SKamal Dasu 		if (qspi->soc_intc) {
1096cc20a386SKamal Dasu 			/*
1097cc20a386SKamal Dasu 			 * clear soc MSPI and BSPI interrupts and enable
1098cc20a386SKamal Dasu 			 * BSPI interrupts.
1099cc20a386SKamal Dasu 			 */
1100cc20a386SKamal Dasu 			soc_intc->bcm_qspi_int_ack(soc_intc, MSPI_BSPI_DONE);
1101cc20a386SKamal Dasu 			soc_intc->bcm_qspi_int_set(soc_intc, BSPI_DONE, true);
1102cc20a386SKamal Dasu 		}
1103cc20a386SKamal Dasu 
11044e3b2d23SKamal Dasu 		/* Must flush previous writes before starting BSPI operation */
11054e3b2d23SKamal Dasu 		mb();
11064e3b2d23SKamal Dasu 		bcm_qspi_bspi_lr_start(qspi);
11074e3b2d23SKamal Dasu 		if (!wait_for_completion_timeout(&qspi->bspi_done, timeo)) {
11084e3b2d23SKamal Dasu 			dev_err(&qspi->pdev->dev, "timeout waiting for BSPI\n");
11094e3b2d23SKamal Dasu 			ret = -ETIMEDOUT;
1110345309faSKamal Dasu 			break;
11114e3b2d23SKamal Dasu 		}
11124e3b2d23SKamal Dasu 
1113345309faSKamal Dasu 		/* set msg return length */
1114345309faSKamal Dasu 		addr += rdlen;
1115345309faSKamal Dasu 		len -= rdlen;
1116345309faSKamal Dasu 	} while (len);
1117345309faSKamal Dasu 
11184e3b2d23SKamal Dasu 	return ret;
11194e3b2d23SKamal Dasu }
11204e3b2d23SKamal Dasu 
bcm_qspi_transfer_one(struct spi_controller * host,struct spi_device * spi,struct spi_transfer * trans)1121ec271c04SYang Yingliang static int bcm_qspi_transfer_one(struct spi_controller *host,
112281ab52fdSKamal Dasu 				 struct spi_device *spi,
112381ab52fdSKamal Dasu 				 struct spi_transfer *trans)
112481ab52fdSKamal Dasu {
1125ec271c04SYang Yingliang 	struct bcm_qspi *qspi = spi_controller_get_devdata(host);
112681ab52fdSKamal Dasu 	int slots;
112781ab52fdSKamal Dasu 	unsigned long timeo = msecs_to_jiffies(100);
112881ab52fdSKamal Dasu 
11299e264f3fSAmit Kumar Mahapatra via Alsa-devel 	if (!spi_get_csgpiod(spi, 0))
11309e264f3fSAmit Kumar Mahapatra via Alsa-devel 		bcm_qspi_chip_select(qspi, spi_get_chipselect(spi, 0));
113181ab52fdSKamal Dasu 	qspi->trans_pos.trans = trans;
113281ab52fdSKamal Dasu 	qspi->trans_pos.byte = 0;
113381ab52fdSKamal Dasu 
113481ab52fdSKamal Dasu 	while (qspi->trans_pos.byte < trans->len) {
113581ab52fdSKamal Dasu 		reinit_completion(&qspi->mspi_done);
113681ab52fdSKamal Dasu 
113781ab52fdSKamal Dasu 		slots = write_to_hw(qspi, spi);
113881ab52fdSKamal Dasu 		if (!wait_for_completion_timeout(&qspi->mspi_done, timeo)) {
113981ab52fdSKamal Dasu 			dev_err(&qspi->pdev->dev, "timeout waiting for MSPI\n");
114081ab52fdSKamal Dasu 			return -ETIMEDOUT;
114181ab52fdSKamal Dasu 		}
114281ab52fdSKamal Dasu 
114381ab52fdSKamal Dasu 		read_from_hw(qspi, slots);
114481ab52fdSKamal Dasu 	}
1145ca105398SRayagonda Kokatanur 	bcm_qspi_enable_bspi(qspi);
114681ab52fdSKamal Dasu 
114781ab52fdSKamal Dasu 	return 0;
114881ab52fdSKamal Dasu }
114981ab52fdSKamal Dasu 
bcm_qspi_mspi_exec_mem_op(struct spi_device * spi,const struct spi_mem_op * op)11505f195ee7SBoris Brezillon static int bcm_qspi_mspi_exec_mem_op(struct spi_device *spi,
11515f195ee7SBoris Brezillon 				     const struct spi_mem_op *op)
115281ab52fdSKamal Dasu {
1153ec271c04SYang Yingliang 	struct spi_controller *host = spi->controller;
1154ec271c04SYang Yingliang 	struct bcm_qspi *qspi = spi_controller_get_devdata(host);
115581ab52fdSKamal Dasu 	struct spi_transfer t[2];
11565f195ee7SBoris Brezillon 	u8 cmd[6] = { };
11575f195ee7SBoris Brezillon 	int ret, i;
115881ab52fdSKamal Dasu 
115981ab52fdSKamal Dasu 	memset(cmd, 0, sizeof(cmd));
116081ab52fdSKamal Dasu 	memset(t, 0, sizeof(t));
116181ab52fdSKamal Dasu 
116281ab52fdSKamal Dasu 	/* tx */
116381ab52fdSKamal Dasu 	/* opcode is in cmd[0] */
11645f195ee7SBoris Brezillon 	cmd[0] = op->cmd.opcode;
11655f195ee7SBoris Brezillon 	for (i = 0; i < op->addr.nbytes; i++)
11665f195ee7SBoris Brezillon 		cmd[1 + i] = op->addr.val >> (8 * (op->addr.nbytes - i - 1));
11675f195ee7SBoris Brezillon 
116881ab52fdSKamal Dasu 	t[0].tx_buf = cmd;
11695f195ee7SBoris Brezillon 	t[0].len = op->addr.nbytes + op->dummy.nbytes + 1;
117081ab52fdSKamal Dasu 	t[0].bits_per_word = spi->bits_per_word;
11715f195ee7SBoris Brezillon 	t[0].tx_nbits = op->cmd.buswidth;
117281ab52fdSKamal Dasu 	/* lets mspi know that this is not last transfer */
117381ab52fdSKamal Dasu 	qspi->trans_pos.mspi_last_trans = false;
1174ec271c04SYang Yingliang 	ret = bcm_qspi_transfer_one(host, spi, &t[0]);
117581ab52fdSKamal Dasu 
117681ab52fdSKamal Dasu 	/* rx */
117781ab52fdSKamal Dasu 	qspi->trans_pos.mspi_last_trans = true;
117881ab52fdSKamal Dasu 	if (!ret) {
117981ab52fdSKamal Dasu 		/* rx */
11805f195ee7SBoris Brezillon 		t[1].rx_buf = op->data.buf.in;
11815f195ee7SBoris Brezillon 		t[1].len = op->data.nbytes;
11825f195ee7SBoris Brezillon 		t[1].rx_nbits =  op->data.buswidth;
118381ab52fdSKamal Dasu 		t[1].bits_per_word = spi->bits_per_word;
1184ec271c04SYang Yingliang 		ret = bcm_qspi_transfer_one(host, spi, &t[1]);
118581ab52fdSKamal Dasu 	}
118681ab52fdSKamal Dasu 
11874e3b2d23SKamal Dasu 	return ret;
11884e3b2d23SKamal Dasu }
11894e3b2d23SKamal Dasu 
bcm_qspi_exec_mem_op(struct spi_mem * mem,const struct spi_mem_op * op)1190b6456057SBoris Brezillon static int bcm_qspi_exec_mem_op(struct spi_mem *mem,
11915f195ee7SBoris Brezillon 				const struct spi_mem_op *op)
11924e3b2d23SKamal Dasu {
1193b6456057SBoris Brezillon 	struct spi_device *spi = mem->spi;
1194ec271c04SYang Yingliang 	struct bcm_qspi *qspi = spi_controller_get_devdata(spi->controller);
11954e3b2d23SKamal Dasu 	int ret = 0;
11964e3b2d23SKamal Dasu 	bool mspi_read = false;
11975f195ee7SBoris Brezillon 	u32 addr = 0, len;
11984e3b2d23SKamal Dasu 	u_char *buf;
11994e3b2d23SKamal Dasu 
12005f195ee7SBoris Brezillon 	if (!op->data.nbytes || !op->addr.nbytes || op->addr.nbytes > 4 ||
12015f195ee7SBoris Brezillon 	    op->data.dir != SPI_MEM_DATA_IN)
12025f195ee7SBoris Brezillon 		return -ENOTSUPP;
12035f195ee7SBoris Brezillon 
12045f195ee7SBoris Brezillon 	buf = op->data.buf.in;
12055f195ee7SBoris Brezillon 	addr = op->addr.val;
12065f195ee7SBoris Brezillon 	len = op->data.nbytes;
12074e3b2d23SKamal Dasu 
12082c7d1b28SKamal Dasu 	if (has_bspi(qspi) && bcm_qspi_bspi_ver_three(qspi) == true) {
12094e3b2d23SKamal Dasu 		/*
12104e3b2d23SKamal Dasu 		 * The address coming into this function is a raw flash offset.
12114e3b2d23SKamal Dasu 		 * But for BSPI <= V3, we need to convert it to a remapped BSPI
12124e3b2d23SKamal Dasu 		 * address. If it crosses a 4MB boundary, just revert back to
12134e3b2d23SKamal Dasu 		 * using MSPI.
12144e3b2d23SKamal Dasu 		 */
12154e3b2d23SKamal Dasu 		addr = (addr + 0xc00000) & 0xffffff;
12164e3b2d23SKamal Dasu 
12174e3b2d23SKamal Dasu 		if ((~ADDR_4MB_MASK & addr) ^
12184e3b2d23SKamal Dasu 		    (~ADDR_4MB_MASK & (addr + len - 1)))
12194e3b2d23SKamal Dasu 			mspi_read = true;
12204e3b2d23SKamal Dasu 	}
12214e3b2d23SKamal Dasu 
12224e3b2d23SKamal Dasu 	/* non-aligned and very short transfers are handled by MSPI */
12234e3b2d23SKamal Dasu 	if (!IS_ALIGNED((uintptr_t)addr, 4) || !IS_ALIGNED((uintptr_t)buf, 4) ||
1224*26e85f7bSKamal Dasu 	    len < 4 || op->cmd.opcode == SPINOR_OP_RDSFDP)
12254e3b2d23SKamal Dasu 		mspi_read = true;
12264e3b2d23SKamal Dasu 
12272c7d1b28SKamal Dasu 	if (!has_bspi(qspi) || mspi_read)
12285f195ee7SBoris Brezillon 		return bcm_qspi_mspi_exec_mem_op(spi, op);
12294e3b2d23SKamal Dasu 
123079629d0fSRayagonda Kokatanur 	ret = bcm_qspi_bspi_set_mode(qspi, op, 0);
12314e3b2d23SKamal Dasu 
12324e3b2d23SKamal Dasu 	if (!ret)
12335f195ee7SBoris Brezillon 		ret = bcm_qspi_bspi_exec_mem_op(spi, op);
12345f195ee7SBoris Brezillon 
12355f195ee7SBoris Brezillon 	return ret;
12365f195ee7SBoris Brezillon }
12375f195ee7SBoris Brezillon 
bcm_qspi_cleanup(struct spi_device * spi)1238fa236a7eSKamal Dasu static void bcm_qspi_cleanup(struct spi_device *spi)
1239fa236a7eSKamal Dasu {
1240fa236a7eSKamal Dasu 	struct bcm_qspi_parms *xp = spi_get_ctldata(spi);
1241fa236a7eSKamal Dasu 
1242fa236a7eSKamal Dasu 	kfree(xp);
1243fa236a7eSKamal Dasu }
1244fa236a7eSKamal Dasu 
bcm_qspi_mspi_l2_isr(int irq,void * dev_id)1245fa236a7eSKamal Dasu static irqreturn_t bcm_qspi_mspi_l2_isr(int irq, void *dev_id)
1246fa236a7eSKamal Dasu {
1247fa236a7eSKamal Dasu 	struct bcm_qspi_dev_id *qspi_dev_id = dev_id;
1248fa236a7eSKamal Dasu 	struct bcm_qspi *qspi = qspi_dev_id->dev;
1249fa236a7eSKamal Dasu 	u32 status = bcm_qspi_read(qspi, MSPI, MSPI_MSPI_STATUS);
1250fa236a7eSKamal Dasu 
1251fa236a7eSKamal Dasu 	if (status & MSPI_MSPI_STATUS_SPIF) {
1252cc20a386SKamal Dasu 		struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc;
1253fa236a7eSKamal Dasu 		/* clear interrupt */
1254fa236a7eSKamal Dasu 		status &= ~MSPI_MSPI_STATUS_SPIF;
1255fa236a7eSKamal Dasu 		bcm_qspi_write(qspi, MSPI, MSPI_MSPI_STATUS, status);
1256cc20a386SKamal Dasu 		if (qspi->soc_intc)
1257cc20a386SKamal Dasu 			soc_intc->bcm_qspi_int_ack(soc_intc, MSPI_DONE);
1258fa236a7eSKamal Dasu 		complete(&qspi->mspi_done);
1259fa236a7eSKamal Dasu 		return IRQ_HANDLED;
12604e3b2d23SKamal Dasu 	}
12614e3b2d23SKamal Dasu 
1262fa236a7eSKamal Dasu 	return IRQ_NONE;
1263fa236a7eSKamal Dasu }
12644e3b2d23SKamal Dasu 
bcm_qspi_bspi_lr_l2_isr(int irq,void * dev_id)12654e3b2d23SKamal Dasu static irqreturn_t bcm_qspi_bspi_lr_l2_isr(int irq, void *dev_id)
12664e3b2d23SKamal Dasu {
12674e3b2d23SKamal Dasu 	struct bcm_qspi_dev_id *qspi_dev_id = dev_id;
12684e3b2d23SKamal Dasu 	struct bcm_qspi *qspi = qspi_dev_id->dev;
1269cc20a386SKamal Dasu 	struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc;
1270cc20a386SKamal Dasu 	u32 status = qspi_dev_id->irqp->mask;
12714e3b2d23SKamal Dasu 
12725f195ee7SBoris Brezillon 	if (qspi->bspi_enabled && qspi->bspi_rf_op) {
12734e3b2d23SKamal Dasu 		bcm_qspi_bspi_lr_data_read(qspi);
12745f195ee7SBoris Brezillon 		if (qspi->bspi_rf_op_len == 0) {
12755f195ee7SBoris Brezillon 			qspi->bspi_rf_op = NULL;
1276cc20a386SKamal Dasu 			if (qspi->soc_intc) {
1277cc20a386SKamal Dasu 				/* disable soc BSPI interrupt */
1278cc20a386SKamal Dasu 				soc_intc->bcm_qspi_int_set(soc_intc, BSPI_DONE,
1279cc20a386SKamal Dasu 							   false);
1280cc20a386SKamal Dasu 				/* indicate done */
1281cc20a386SKamal Dasu 				status = INTR_BSPI_LR_SESSION_DONE_MASK;
1282cc20a386SKamal Dasu 			}
1283cc20a386SKamal Dasu 
12845f195ee7SBoris Brezillon 			if (qspi->bspi_rf_op_status)
12854e3b2d23SKamal Dasu 				bcm_qspi_bspi_lr_clear(qspi);
12864e3b2d23SKamal Dasu 			else
12874e3b2d23SKamal Dasu 				bcm_qspi_bspi_flush_prefetch_buffers(qspi);
12884e3b2d23SKamal Dasu 		}
1289cc20a386SKamal Dasu 
1290cc20a386SKamal Dasu 		if (qspi->soc_intc)
1291cc20a386SKamal Dasu 			/* clear soc BSPI interrupt */
1292cc20a386SKamal Dasu 			soc_intc->bcm_qspi_int_ack(soc_intc, BSPI_DONE);
1293fa236a7eSKamal Dasu 	}
1294fa236a7eSKamal Dasu 
1295cc20a386SKamal Dasu 	status &= INTR_BSPI_LR_SESSION_DONE_MASK;
12965f195ee7SBoris Brezillon 	if (qspi->bspi_enabled && status && qspi->bspi_rf_op_len == 0)
12974e3b2d23SKamal Dasu 		complete(&qspi->bspi_done);
12984e3b2d23SKamal Dasu 
12994e3b2d23SKamal Dasu 	return IRQ_HANDLED;
13004e3b2d23SKamal Dasu }
13014e3b2d23SKamal Dasu 
bcm_qspi_bspi_lr_err_l2_isr(int irq,void * dev_id)13024e3b2d23SKamal Dasu static irqreturn_t bcm_qspi_bspi_lr_err_l2_isr(int irq, void *dev_id)
13034e3b2d23SKamal Dasu {
13044e3b2d23SKamal Dasu 	struct bcm_qspi_dev_id *qspi_dev_id = dev_id;
13054e3b2d23SKamal Dasu 	struct bcm_qspi *qspi = qspi_dev_id->dev;
1306cc20a386SKamal Dasu 	struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc;
13074e3b2d23SKamal Dasu 
13084e3b2d23SKamal Dasu 	dev_err(&qspi->pdev->dev, "BSPI INT error\n");
13095f195ee7SBoris Brezillon 	qspi->bspi_rf_op_status = -EIO;
1310cc20a386SKamal Dasu 	if (qspi->soc_intc)
1311cc20a386SKamal Dasu 		/* clear soc interrupt */
1312cc20a386SKamal Dasu 		soc_intc->bcm_qspi_int_ack(soc_intc, BSPI_ERR);
1313cc20a386SKamal Dasu 
13144e3b2d23SKamal Dasu 	complete(&qspi->bspi_done);
13154e3b2d23SKamal Dasu 	return IRQ_HANDLED;
13164e3b2d23SKamal Dasu }
13174e3b2d23SKamal Dasu 
bcm_qspi_l1_isr(int irq,void * dev_id)1318cc20a386SKamal Dasu static irqreturn_t bcm_qspi_l1_isr(int irq, void *dev_id)
1319cc20a386SKamal Dasu {
1320cc20a386SKamal Dasu 	struct bcm_qspi_dev_id *qspi_dev_id = dev_id;
1321cc20a386SKamal Dasu 	struct bcm_qspi *qspi = qspi_dev_id->dev;
1322cc20a386SKamal Dasu 	struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc;
1323cc20a386SKamal Dasu 	irqreturn_t ret = IRQ_NONE;
1324cc20a386SKamal Dasu 
1325cc20a386SKamal Dasu 	if (soc_intc) {
1326cc20a386SKamal Dasu 		u32 status = soc_intc->bcm_qspi_get_int_status(soc_intc);
1327cc20a386SKamal Dasu 
1328cc20a386SKamal Dasu 		if (status & MSPI_DONE)
1329cc20a386SKamal Dasu 			ret = bcm_qspi_mspi_l2_isr(irq, dev_id);
1330cc20a386SKamal Dasu 		else if (status & BSPI_DONE)
1331cc20a386SKamal Dasu 			ret = bcm_qspi_bspi_lr_l2_isr(irq, dev_id);
1332cc20a386SKamal Dasu 		else if (status & BSPI_ERR)
1333cc20a386SKamal Dasu 			ret = bcm_qspi_bspi_lr_err_l2_isr(irq, dev_id);
1334cc20a386SKamal Dasu 	}
1335cc20a386SKamal Dasu 
1336cc20a386SKamal Dasu 	return ret;
1337cc20a386SKamal Dasu }
1338cc20a386SKamal Dasu 
1339fa236a7eSKamal Dasu static const struct bcm_qspi_irq qspi_irq_tab[] = {
1340fa236a7eSKamal Dasu 	{
13414e3b2d23SKamal Dasu 		.irq_name = "spi_lr_fullness_reached",
13424e3b2d23SKamal Dasu 		.irq_handler = bcm_qspi_bspi_lr_l2_isr,
13434e3b2d23SKamal Dasu 		.mask = INTR_BSPI_LR_FULLNESS_REACHED_MASK,
13444e3b2d23SKamal Dasu 	},
13454e3b2d23SKamal Dasu 	{
13464e3b2d23SKamal Dasu 		.irq_name = "spi_lr_session_aborted",
13474e3b2d23SKamal Dasu 		.irq_handler = bcm_qspi_bspi_lr_err_l2_isr,
13484e3b2d23SKamal Dasu 		.mask = INTR_BSPI_LR_SESSION_ABORTED_MASK,
13494e3b2d23SKamal Dasu 	},
13504e3b2d23SKamal Dasu 	{
13514e3b2d23SKamal Dasu 		.irq_name = "spi_lr_impatient",
13524e3b2d23SKamal Dasu 		.irq_handler = bcm_qspi_bspi_lr_err_l2_isr,
13534e3b2d23SKamal Dasu 		.mask = INTR_BSPI_LR_IMPATIENT_MASK,
13544e3b2d23SKamal Dasu 	},
13554e3b2d23SKamal Dasu 	{
13564e3b2d23SKamal Dasu 		.irq_name = "spi_lr_session_done",
13574e3b2d23SKamal Dasu 		.irq_handler = bcm_qspi_bspi_lr_l2_isr,
13584e3b2d23SKamal Dasu 		.mask = INTR_BSPI_LR_SESSION_DONE_MASK,
13594e3b2d23SKamal Dasu 	},
13604e3b2d23SKamal Dasu #ifdef QSPI_INT_DEBUG
13614e3b2d23SKamal Dasu 	/* this interrupt is for debug purposes only, dont request irq */
13624e3b2d23SKamal Dasu 	{
13634e3b2d23SKamal Dasu 		.irq_name = "spi_lr_overread",
13644e3b2d23SKamal Dasu 		.irq_handler = bcm_qspi_bspi_lr_err_l2_isr,
13654e3b2d23SKamal Dasu 		.mask = INTR_BSPI_LR_OVERREAD_MASK,
13664e3b2d23SKamal Dasu 	},
13674e3b2d23SKamal Dasu #endif
13684e3b2d23SKamal Dasu 	{
1369fa236a7eSKamal Dasu 		.irq_name = "mspi_done",
1370fa236a7eSKamal Dasu 		.irq_handler = bcm_qspi_mspi_l2_isr,
1371fa236a7eSKamal Dasu 		.mask = INTR_MSPI_DONE_MASK,
1372fa236a7eSKamal Dasu 	},
1373fa236a7eSKamal Dasu 	{
1374fa236a7eSKamal Dasu 		.irq_name = "mspi_halted",
1375fa236a7eSKamal Dasu 		.irq_handler = bcm_qspi_mspi_l2_isr,
1376fa236a7eSKamal Dasu 		.mask = INTR_MSPI_HALTED_MASK,
1377fa236a7eSKamal Dasu 	},
1378cc20a386SKamal Dasu 	{
1379cc20a386SKamal Dasu 		/* single muxed L1 interrupt source */
1380cc20a386SKamal Dasu 		.irq_name = "spi_l1_intr",
1381cc20a386SKamal Dasu 		.irq_handler = bcm_qspi_l1_isr,
1382cc20a386SKamal Dasu 		.irq_source = MUXED_L1,
1383cc20a386SKamal Dasu 		.mask = QSPI_INTERRUPTS_ALL,
1384cc20a386SKamal Dasu 	},
1385fa236a7eSKamal Dasu };
1386fa236a7eSKamal Dasu 
bcm_qspi_bspi_init(struct bcm_qspi * qspi)13874e3b2d23SKamal Dasu static void bcm_qspi_bspi_init(struct bcm_qspi *qspi)
13884e3b2d23SKamal Dasu {
13894e3b2d23SKamal Dasu 	u32 val = 0;
13904e3b2d23SKamal Dasu 
13914e3b2d23SKamal Dasu 	val = bcm_qspi_read(qspi, BSPI, BSPI_REVISION_ID);
13924e3b2d23SKamal Dasu 	qspi->bspi_maj_rev = (val >> 8) & 0xff;
13934e3b2d23SKamal Dasu 	qspi->bspi_min_rev = val & 0xff;
13944e3b2d23SKamal Dasu 	if (!(bcm_qspi_bspi_ver_three(qspi))) {
13954e3b2d23SKamal Dasu 		/* Force mapping of BSPI address -> flash offset */
13964e3b2d23SKamal Dasu 		bcm_qspi_write(qspi, BSPI, BSPI_BSPI_XOR_VALUE, 0);
13974e3b2d23SKamal Dasu 		bcm_qspi_write(qspi, BSPI, BSPI_BSPI_XOR_ENABLE, 1);
13984e3b2d23SKamal Dasu 	}
13994e3b2d23SKamal Dasu 	qspi->bspi_enabled = 1;
14004e3b2d23SKamal Dasu 	bcm_qspi_disable_bspi(qspi);
14014e3b2d23SKamal Dasu 	bcm_qspi_write(qspi, BSPI, BSPI_B0_CTRL, 0);
14024e3b2d23SKamal Dasu 	bcm_qspi_write(qspi, BSPI, BSPI_B1_CTRL, 0);
14034e3b2d23SKamal Dasu }
14044e3b2d23SKamal Dasu 
bcm_qspi_hw_init(struct bcm_qspi * qspi)1405fa236a7eSKamal Dasu static void bcm_qspi_hw_init(struct bcm_qspi *qspi)
1406fa236a7eSKamal Dasu {
1407fa236a7eSKamal Dasu 	struct bcm_qspi_parms parms;
1408fa236a7eSKamal Dasu 
1409fa236a7eSKamal Dasu 	bcm_qspi_write(qspi, MSPI, MSPI_SPCR1_LSB, 0);
1410fa236a7eSKamal Dasu 	bcm_qspi_write(qspi, MSPI, MSPI_SPCR1_MSB, 0);
1411fa236a7eSKamal Dasu 	bcm_qspi_write(qspi, MSPI, MSPI_NEWQP, 0);
1412fa236a7eSKamal Dasu 	bcm_qspi_write(qspi, MSPI, MSPI_ENDQP, 0);
1413fa236a7eSKamal Dasu 	bcm_qspi_write(qspi, MSPI, MSPI_SPCR2, 0x20);
1414fa236a7eSKamal Dasu 
1415fa236a7eSKamal Dasu 	parms.mode = SPI_MODE_3;
1416fa236a7eSKamal Dasu 	parms.bits_per_word = 8;
1417fa236a7eSKamal Dasu 	parms.speed_hz = qspi->max_speed_hz;
1418fa236a7eSKamal Dasu 	bcm_qspi_hw_set_parms(qspi, &parms);
14194e3b2d23SKamal Dasu 
14204e3b2d23SKamal Dasu 	if (has_bspi(qspi))
14214e3b2d23SKamal Dasu 		bcm_qspi_bspi_init(qspi);
1422fa236a7eSKamal Dasu }
1423fa236a7eSKamal Dasu 
bcm_qspi_hw_uninit(struct bcm_qspi * qspi)1424fa236a7eSKamal Dasu static void bcm_qspi_hw_uninit(struct bcm_qspi *qspi)
1425fa236a7eSKamal Dasu {
142675b3cb97SKamal Dasu 	u32 status = bcm_qspi_read(qspi, MSPI, MSPI_MSPI_STATUS);
142775b3cb97SKamal Dasu 
1428fa236a7eSKamal Dasu 	bcm_qspi_write(qspi, MSPI, MSPI_SPCR2, 0);
14294e3b2d23SKamal Dasu 	if (has_bspi(qspi))
14304e3b2d23SKamal Dasu 		bcm_qspi_write(qspi, MSPI, MSPI_WRITE_LOCK, 0);
14314e3b2d23SKamal Dasu 
143275b3cb97SKamal Dasu 	/* clear interrupt */
143375b3cb97SKamal Dasu 	bcm_qspi_write(qspi, MSPI, MSPI_MSPI_STATUS, status & ~1);
1434fa236a7eSKamal Dasu }
1435fa236a7eSKamal Dasu 
14365f195ee7SBoris Brezillon static const struct spi_controller_mem_ops bcm_qspi_mem_ops = {
1437b6456057SBoris Brezillon 	.exec_op = bcm_qspi_exec_mem_op,
14385f195ee7SBoris Brezillon };
14395f195ee7SBoris Brezillon 
14403a01f04dSFlorian Fainelli struct bcm_qspi_data {
14413a01f04dSFlorian Fainelli 	bool	has_mspi_rev;
144243613a77SKamal Dasu 	bool	has_spcr3_sysclk;
14433a01f04dSFlorian Fainelli };
14443a01f04dSFlorian Fainelli 
14453a01f04dSFlorian Fainelli static const struct bcm_qspi_data bcm_qspi_no_rev_data = {
14463a01f04dSFlorian Fainelli 	.has_mspi_rev	= false,
144743613a77SKamal Dasu 	.has_spcr3_sysclk = false,
14483a01f04dSFlorian Fainelli };
14493a01f04dSFlorian Fainelli 
14503a01f04dSFlorian Fainelli static const struct bcm_qspi_data bcm_qspi_rev_data = {
14513a01f04dSFlorian Fainelli 	.has_mspi_rev	= true,
145243613a77SKamal Dasu 	.has_spcr3_sysclk = false,
145343613a77SKamal Dasu };
145443613a77SKamal Dasu 
145543613a77SKamal Dasu static const struct bcm_qspi_data bcm_qspi_spcr3_data = {
145643613a77SKamal Dasu 	.has_mspi_rev	= true,
145743613a77SKamal Dasu 	.has_spcr3_sysclk = true,
14583a01f04dSFlorian Fainelli };
14593a01f04dSFlorian Fainelli 
14606340fdf2SKrzysztof Kozlowski static const struct of_device_id bcm_qspi_of_match[] __maybe_unused = {
14613a01f04dSFlorian Fainelli 	{
1462e0eeb76bSRay Jui 		.compatible = "brcm,spi-bcm7445-qspi",
1463e0eeb76bSRay Jui 		.data = &bcm_qspi_rev_data,
1464e0eeb76bSRay Jui 
1465e0eeb76bSRay Jui 	},
1466e0eeb76bSRay Jui 	{
14673a01f04dSFlorian Fainelli 		.compatible = "brcm,spi-bcm-qspi",
14689a852d44SRay Jui 		.data = &bcm_qspi_no_rev_data,
14693a01f04dSFlorian Fainelli 	},
147043613a77SKamal Dasu 	{
147143613a77SKamal Dasu 		.compatible = "brcm,spi-bcm7216-qspi",
147243613a77SKamal Dasu 		.data = &bcm_qspi_spcr3_data,
147343613a77SKamal Dasu 	},
147443613a77SKamal Dasu 	{
147543613a77SKamal Dasu 		.compatible = "brcm,spi-bcm7278-qspi",
147643613a77SKamal Dasu 		.data = &bcm_qspi_spcr3_data,
147743613a77SKamal Dasu 	},
1478fa236a7eSKamal Dasu 	{},
1479fa236a7eSKamal Dasu };
1480fa236a7eSKamal Dasu MODULE_DEVICE_TABLE(of, bcm_qspi_of_match);
1481fa236a7eSKamal Dasu 
bcm_qspi_probe(struct platform_device * pdev,struct bcm_qspi_soc_intc * soc_intc)1482fa236a7eSKamal Dasu int bcm_qspi_probe(struct platform_device *pdev,
14834e3b2d23SKamal Dasu 		   struct bcm_qspi_soc_intc *soc_intc)
1484fa236a7eSKamal Dasu {
14853a01f04dSFlorian Fainelli 	const struct of_device_id *of_id = NULL;
14863a01f04dSFlorian Fainelli 	const struct bcm_qspi_data *data;
1487fa236a7eSKamal Dasu 	struct device *dev = &pdev->dev;
1488fa236a7eSKamal Dasu 	struct bcm_qspi *qspi;
1489ec271c04SYang Yingliang 	struct spi_controller *host;
1490fa236a7eSKamal Dasu 	struct resource *res;
1491fa236a7eSKamal Dasu 	int irq, ret = 0, num_ints = 0;
1492fa236a7eSKamal Dasu 	u32 val;
14933a01f04dSFlorian Fainelli 	u32 rev = 0;
1494fa236a7eSKamal Dasu 	const char *name = NULL;
1495fa236a7eSKamal Dasu 	int num_irqs = ARRAY_SIZE(qspi_irq_tab);
1496fa236a7eSKamal Dasu 
1497fa236a7eSKamal Dasu 	/* We only support device-tree instantiation */
1498fa236a7eSKamal Dasu 	if (!dev->of_node)
1499fa236a7eSKamal Dasu 		return -ENODEV;
1500fa236a7eSKamal Dasu 
15013a01f04dSFlorian Fainelli 	of_id = of_match_node(bcm_qspi_of_match, dev->of_node);
15023a01f04dSFlorian Fainelli 	if (!of_id)
1503fa236a7eSKamal Dasu 		return -ENODEV;
1504fa236a7eSKamal Dasu 
15053a01f04dSFlorian Fainelli 	data = of_id->data;
15063a01f04dSFlorian Fainelli 
1507ec271c04SYang Yingliang 	host = devm_spi_alloc_host(dev, sizeof(struct bcm_qspi));
1508ec271c04SYang Yingliang 	if (!host) {
1509ec271c04SYang Yingliang 		dev_err(dev, "error allocating spi_controller\n");
1510fa236a7eSKamal Dasu 		return -ENOMEM;
1511fa236a7eSKamal Dasu 	}
1512fa236a7eSKamal Dasu 
1513ec271c04SYang Yingliang 	qspi = spi_controller_get_devdata(host);
15140392727cSFlorian Fainelli 
15150392727cSFlorian Fainelli 	qspi->clk = devm_clk_get_optional(&pdev->dev, NULL);
15160392727cSFlorian Fainelli 	if (IS_ERR(qspi->clk))
15170392727cSFlorian Fainelli 		return PTR_ERR(qspi->clk);
15180392727cSFlorian Fainelli 
1519fa236a7eSKamal Dasu 	qspi->pdev = pdev;
1520fa236a7eSKamal Dasu 	qspi->trans_pos.trans = NULL;
1521fa236a7eSKamal Dasu 	qspi->trans_pos.byte = 0;
152281ab52fdSKamal Dasu 	qspi->trans_pos.mspi_last_trans = true;
1523ec271c04SYang Yingliang 	qspi->host = host;
1524fa236a7eSKamal Dasu 
1525ec271c04SYang Yingliang 	host->bus_num = -1;
1526ec271c04SYang Yingliang 	host->mode_bits = SPI_CPHA | SPI_CPOL | SPI_RX_DUAL | SPI_RX_QUAD |
1527e81cd07dSKamal Dasu 				SPI_3WIRE;
1528ec271c04SYang Yingliang 	host->setup = bcm_qspi_setup;
1529ec271c04SYang Yingliang 	host->transfer_one = bcm_qspi_transfer_one;
1530ec271c04SYang Yingliang 	host->mem_ops = &bcm_qspi_mem_ops;
1531ec271c04SYang Yingliang 	host->cleanup = bcm_qspi_cleanup;
1532ec271c04SYang Yingliang 	host->dev.of_node = dev->of_node;
1533ec271c04SYang Yingliang 	host->num_chipselect = NUM_CHIPSELECT;
1534ec271c04SYang Yingliang 	host->use_gpio_descriptors = true;
1535fa236a7eSKamal Dasu 
1536fa236a7eSKamal Dasu 	qspi->big_endian = of_device_is_big_endian(dev->of_node);
1537fa236a7eSKamal Dasu 
1538fa236a7eSKamal Dasu 	if (!of_property_read_u32(dev->of_node, "num-cs", &val))
1539ec271c04SYang Yingliang 		host->num_chipselect = val;
1540fa236a7eSKamal Dasu 
1541fa236a7eSKamal Dasu 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hif_mspi");
1542fa236a7eSKamal Dasu 	if (!res)
1543fa236a7eSKamal Dasu 		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1544fa236a7eSKamal Dasu 						   "mspi");
1545fa236a7eSKamal Dasu 
1546fa236a7eSKamal Dasu 	qspi->base[MSPI]  = devm_ioremap_resource(dev, res);
154763c5395bSLukas Wunner 	if (IS_ERR(qspi->base[MSPI]))
154863c5395bSLukas Wunner 		return PTR_ERR(qspi->base[MSPI]);
1549fa236a7eSKamal Dasu 
15504e3b2d23SKamal Dasu 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "bspi");
15514e3b2d23SKamal Dasu 	if (res) {
15524e3b2d23SKamal Dasu 		qspi->base[BSPI]  = devm_ioremap_resource(dev, res);
155363c5395bSLukas Wunner 		if (IS_ERR(qspi->base[BSPI]))
155463c5395bSLukas Wunner 			return PTR_ERR(qspi->base[BSPI]);
15554e3b2d23SKamal Dasu 		qspi->bspi_mode = true;
15564e3b2d23SKamal Dasu 	} else {
15574e3b2d23SKamal Dasu 		qspi->bspi_mode = false;
15584e3b2d23SKamal Dasu 	}
15594e3b2d23SKamal Dasu 
15604e3b2d23SKamal Dasu 	dev_info(dev, "using %smspi mode\n", qspi->bspi_mode ? "bspi-" : "");
15614e3b2d23SKamal Dasu 
1562fa236a7eSKamal Dasu 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cs_reg");
1563fa236a7eSKamal Dasu 	if (res) {
1564fa236a7eSKamal Dasu 		qspi->base[CHIP_SELECT]  = devm_ioremap_resource(dev, res);
156563c5395bSLukas Wunner 		if (IS_ERR(qspi->base[CHIP_SELECT]))
156663c5395bSLukas Wunner 			return PTR_ERR(qspi->base[CHIP_SELECT]);
1567fa236a7eSKamal Dasu 	}
1568fa236a7eSKamal Dasu 
1569fa236a7eSKamal Dasu 	qspi->dev_ids = kcalloc(num_irqs, sizeof(struct bcm_qspi_dev_id),
1570fa236a7eSKamal Dasu 				GFP_KERNEL);
157163c5395bSLukas Wunner 	if (!qspi->dev_ids)
157263c5395bSLukas Wunner 		return -ENOMEM;
1573fa236a7eSKamal Dasu 
157475b3cb97SKamal Dasu 	/*
157575b3cb97SKamal Dasu 	 * Some SoCs integrate spi controller (e.g., its interrupt bits)
157675b3cb97SKamal Dasu 	 * in specific ways
157775b3cb97SKamal Dasu 	 */
157875b3cb97SKamal Dasu 	if (soc_intc) {
157975b3cb97SKamal Dasu 		qspi->soc_intc = soc_intc;
158075b3cb97SKamal Dasu 		soc_intc->bcm_qspi_int_set(soc_intc, MSPI_DONE, true);
158175b3cb97SKamal Dasu 	} else {
158275b3cb97SKamal Dasu 		qspi->soc_intc = NULL;
158375b3cb97SKamal Dasu 	}
158475b3cb97SKamal Dasu 
158575b3cb97SKamal Dasu 	if (qspi->clk) {
158675b3cb97SKamal Dasu 		ret = clk_prepare_enable(qspi->clk);
158775b3cb97SKamal Dasu 		if (ret) {
158875b3cb97SKamal Dasu 			dev_err(dev, "failed to prepare clock\n");
158975b3cb97SKamal Dasu 			goto qspi_probe_err;
159075b3cb97SKamal Dasu 		}
159175b3cb97SKamal Dasu 		qspi->base_clk = clk_get_rate(qspi->clk);
159275b3cb97SKamal Dasu 	} else {
159375b3cb97SKamal Dasu 		qspi->base_clk = MSPI_BASE_FREQ;
159475b3cb97SKamal Dasu 	}
159575b3cb97SKamal Dasu 
159675b3cb97SKamal Dasu 	if (data->has_mspi_rev) {
159775b3cb97SKamal Dasu 		rev = bcm_qspi_read(qspi, MSPI, MSPI_REV);
159875b3cb97SKamal Dasu 		/* some older revs do not have a MSPI_REV register */
159975b3cb97SKamal Dasu 		if ((rev & 0xff) == 0xff)
160075b3cb97SKamal Dasu 			rev = 0;
160175b3cb97SKamal Dasu 	}
160275b3cb97SKamal Dasu 
160375b3cb97SKamal Dasu 	qspi->mspi_maj_rev = (rev >> 4) & 0xf;
160475b3cb97SKamal Dasu 	qspi->mspi_min_rev = rev & 0xf;
160575b3cb97SKamal Dasu 	qspi->mspi_spcr3_sysclk = data->has_spcr3_sysclk;
160675b3cb97SKamal Dasu 
160775b3cb97SKamal Dasu 	qspi->max_speed_hz = qspi->base_clk / (bcm_qspi_spbr_min(qspi) * 2);
160875b3cb97SKamal Dasu 
160975b3cb97SKamal Dasu 	/*
161075b3cb97SKamal Dasu 	 * On SW resets it is possible to have the mask still enabled
161175b3cb97SKamal Dasu 	 * Need to disable the mask and clear the status while we init
161275b3cb97SKamal Dasu 	 */
161375b3cb97SKamal Dasu 	bcm_qspi_hw_uninit(qspi);
161475b3cb97SKamal Dasu 
1615fa236a7eSKamal Dasu 	for (val = 0; val < num_irqs; val++) {
1616fa236a7eSKamal Dasu 		irq = -1;
1617fa236a7eSKamal Dasu 		name = qspi_irq_tab[val].irq_name;
1618cc20a386SKamal Dasu 		if (qspi_irq_tab[val].irq_source == SINGLE_L2) {
1619cc20a386SKamal Dasu 			/* get the l2 interrupts */
1620e9aa3b85SRayagonda Kokatanur 			irq = platform_get_irq_byname_optional(pdev, name);
1621cc20a386SKamal Dasu 		} else if (!num_ints && soc_intc) {
1622cc20a386SKamal Dasu 			/* all mspi, bspi intrs muxed to one L1 intr */
1623cc20a386SKamal Dasu 			irq = platform_get_irq(pdev, 0);
1624cc20a386SKamal Dasu 		}
1625fa236a7eSKamal Dasu 
1626fa236a7eSKamal Dasu 		if (irq  >= 0) {
1627fa236a7eSKamal Dasu 			ret = devm_request_irq(&pdev->dev, irq,
1628fa236a7eSKamal Dasu 					       qspi_irq_tab[val].irq_handler, 0,
1629fa236a7eSKamal Dasu 					       name,
1630fa236a7eSKamal Dasu 					       &qspi->dev_ids[val]);
1631fa236a7eSKamal Dasu 			if (ret < 0) {
1632fa236a7eSKamal Dasu 				dev_err(&pdev->dev, "IRQ %s not found\n", name);
1633ca9b8f56SYang Yingliang 				goto qspi_unprepare_err;
1634fa236a7eSKamal Dasu 			}
1635fa236a7eSKamal Dasu 
1636fa236a7eSKamal Dasu 			qspi->dev_ids[val].dev = qspi;
1637fa236a7eSKamal Dasu 			qspi->dev_ids[val].irqp = &qspi_irq_tab[val];
1638fa236a7eSKamal Dasu 			num_ints++;
1639fa236a7eSKamal Dasu 			dev_dbg(&pdev->dev, "registered IRQ %s %d\n",
1640fa236a7eSKamal Dasu 				qspi_irq_tab[val].irq_name,
1641fa236a7eSKamal Dasu 				irq);
1642fa236a7eSKamal Dasu 		}
1643fa236a7eSKamal Dasu 	}
1644fa236a7eSKamal Dasu 
1645fa236a7eSKamal Dasu 	if (!num_ints) {
1646fa236a7eSKamal Dasu 		dev_err(&pdev->dev, "no IRQs registered, cannot init driver\n");
164771b8f350SWei Yongjun 		ret = -EINVAL;
1648ca9b8f56SYang Yingliang 		goto qspi_unprepare_err;
1649fa236a7eSKamal Dasu 	}
1650fa236a7eSKamal Dasu 
1651fa236a7eSKamal Dasu 	bcm_qspi_hw_init(qspi);
1652fa236a7eSKamal Dasu 	init_completion(&qspi->mspi_done);
16534e3b2d23SKamal Dasu 	init_completion(&qspi->bspi_done);
1654fa236a7eSKamal Dasu 	qspi->curr_cs = -1;
1655fa236a7eSKamal Dasu 
1656fa236a7eSKamal Dasu 	platform_set_drvdata(pdev, qspi);
16574e3b2d23SKamal Dasu 
16584e3b2d23SKamal Dasu 	qspi->xfer_mode.width = -1;
16594e3b2d23SKamal Dasu 	qspi->xfer_mode.addrlen = -1;
16604e3b2d23SKamal Dasu 	qspi->xfer_mode.hp = -1;
16614e3b2d23SKamal Dasu 
1662ec271c04SYang Yingliang 	ret = spi_register_controller(host);
1663fa236a7eSKamal Dasu 	if (ret < 0) {
1664ec271c04SYang Yingliang 		dev_err(dev, "can't register host\n");
1665fa236a7eSKamal Dasu 		goto qspi_reg_err;
1666fa236a7eSKamal Dasu 	}
1667fa236a7eSKamal Dasu 
1668fa236a7eSKamal Dasu 	return 0;
1669fa236a7eSKamal Dasu 
1670fa236a7eSKamal Dasu qspi_reg_err:
1671fa236a7eSKamal Dasu 	bcm_qspi_hw_uninit(qspi);
1672ca9b8f56SYang Yingliang qspi_unprepare_err:
1673fa236a7eSKamal Dasu 	clk_disable_unprepare(qspi->clk);
1674fa236a7eSKamal Dasu qspi_probe_err:
1675fa236a7eSKamal Dasu 	kfree(qspi->dev_ids);
1676fa236a7eSKamal Dasu 	return ret;
1677fa236a7eSKamal Dasu }
1678fa236a7eSKamal Dasu /* probe function to be called by SoC specific platform driver probe */
1679fa236a7eSKamal Dasu EXPORT_SYMBOL_GPL(bcm_qspi_probe);
1680fa236a7eSKamal Dasu 
bcm_qspi_remove(struct platform_device * pdev)1681666ea0adSUwe Kleine-König void bcm_qspi_remove(struct platform_device *pdev)
1682fa236a7eSKamal Dasu {
1683fa236a7eSKamal Dasu 	struct bcm_qspi *qspi = platform_get_drvdata(pdev);
1684fa236a7eSKamal Dasu 
1685ec271c04SYang Yingliang 	spi_unregister_controller(qspi->host);
1686fa236a7eSKamal Dasu 	bcm_qspi_hw_uninit(qspi);
1687fa236a7eSKamal Dasu 	clk_disable_unprepare(qspi->clk);
1688fa236a7eSKamal Dasu 	kfree(qspi->dev_ids);
1689fa236a7eSKamal Dasu }
1690666ea0adSUwe Kleine-König 
1691fa236a7eSKamal Dasu /* function to be called by SoC specific platform driver remove() */
1692fa236a7eSKamal Dasu EXPORT_SYMBOL_GPL(bcm_qspi_remove);
1693fa236a7eSKamal Dasu 
bcm_qspi_suspend(struct device * dev)1694a0319f8bSArnd Bergmann static int __maybe_unused bcm_qspi_suspend(struct device *dev)
1695fa236a7eSKamal Dasu {
1696fa236a7eSKamal Dasu 	struct bcm_qspi *qspi = dev_get_drvdata(dev);
1697fa236a7eSKamal Dasu 
1698054e532fSKamal Dasu 	/* store the override strap value */
1699054e532fSKamal Dasu 	if (!bcm_qspi_bspi_ver_three(qspi))
1700054e532fSKamal Dasu 		qspi->s3_strap_override_ctrl =
1701054e532fSKamal Dasu 			bcm_qspi_read(qspi, BSPI, BSPI_STRAP_OVERRIDE_CTRL);
1702054e532fSKamal Dasu 
1703ec271c04SYang Yingliang 	spi_controller_suspend(qspi->host);
17041b7ad8c4SKamal Dasu 	clk_disable_unprepare(qspi->clk);
1705fa236a7eSKamal Dasu 	bcm_qspi_hw_uninit(qspi);
1706fa236a7eSKamal Dasu 
1707fa236a7eSKamal Dasu 	return 0;
1708fa236a7eSKamal Dasu };
1709fa236a7eSKamal Dasu 
bcm_qspi_resume(struct device * dev)1710a0319f8bSArnd Bergmann static int __maybe_unused bcm_qspi_resume(struct device *dev)
1711fa236a7eSKamal Dasu {
1712fa236a7eSKamal Dasu 	struct bcm_qspi *qspi = dev_get_drvdata(dev);
1713fa236a7eSKamal Dasu 	int ret = 0;
1714fa236a7eSKamal Dasu 
1715fa236a7eSKamal Dasu 	bcm_qspi_hw_init(qspi);
1716fa236a7eSKamal Dasu 	bcm_qspi_chip_select(qspi, qspi->curr_cs);
1717cc20a386SKamal Dasu 	if (qspi->soc_intc)
1718cc20a386SKamal Dasu 		/* enable MSPI interrupt */
1719cc20a386SKamal Dasu 		qspi->soc_intc->bcm_qspi_int_set(qspi->soc_intc, MSPI_DONE,
1720cc20a386SKamal Dasu 						 true);
1721cc20a386SKamal Dasu 
17221b7ad8c4SKamal Dasu 	ret = clk_prepare_enable(qspi->clk);
1723fa236a7eSKamal Dasu 	if (!ret)
1724ec271c04SYang Yingliang 		spi_controller_resume(qspi->host);
1725fa236a7eSKamal Dasu 
1726fa236a7eSKamal Dasu 	return ret;
1727fa236a7eSKamal Dasu }
1728fa236a7eSKamal Dasu 
1729a0319f8bSArnd Bergmann SIMPLE_DEV_PM_OPS(bcm_qspi_pm_ops, bcm_qspi_suspend, bcm_qspi_resume);
1730a0319f8bSArnd Bergmann 
1731fa236a7eSKamal Dasu /* pm_ops to be called by SoC specific platform driver */
1732fa236a7eSKamal Dasu EXPORT_SYMBOL_GPL(bcm_qspi_pm_ops);
1733fa236a7eSKamal Dasu 
1734fa236a7eSKamal Dasu MODULE_AUTHOR("Kamal Dasu");
1735fa236a7eSKamal Dasu MODULE_DESCRIPTION("Broadcom QSPI driver");
1736fa236a7eSKamal Dasu MODULE_LICENSE("GPL v2");
1737fa236a7eSKamal Dasu MODULE_ALIAS("platform:" DRIVER_NAME);
1738