xref: /rk3399_rockchip-uboot/drivers/spi/fsl_qspi.c (revision 4e14741833607f49eaccdfd4add9cb39e103c2db)
16b57ff6fSAlison Wang /*
25bc48308SHaikun.Wang@freescale.com  * Copyright 2013-2015 Freescale Semiconductor, Inc.
36b57ff6fSAlison Wang  *
46b57ff6fSAlison Wang  * Freescale Quad Serial Peripheral Interface (QSPI) driver
56b57ff6fSAlison Wang  *
66b57ff6fSAlison Wang  * SPDX-License-Identifier:	GPL-2.0+
76b57ff6fSAlison Wang  */
86b57ff6fSAlison Wang 
96b57ff6fSAlison Wang #include <common.h>
106b57ff6fSAlison Wang #include <malloc.h>
116b57ff6fSAlison Wang #include <spi.h>
126b57ff6fSAlison Wang #include <asm/io.h>
136b57ff6fSAlison Wang #include <linux/sizes.h>
145bc48308SHaikun.Wang@freescale.com #include <dm.h>
155bc48308SHaikun.Wang@freescale.com #include <errno.h>
16beedbc2eSAlexander Stein #include <watchdog.h>
176b57ff6fSAlison Wang #include "fsl_qspi.h"
186b57ff6fSAlison Wang 
195bc48308SHaikun.Wang@freescale.com DECLARE_GLOBAL_DATA_PTR;
205bc48308SHaikun.Wang@freescale.com 
216b57ff6fSAlison Wang #define RX_BUFFER_SIZE		0x80
22b93ab2eeSPeng Fan #ifdef CONFIG_MX6SX
23b93ab2eeSPeng Fan #define TX_BUFFER_SIZE		0x200
24b93ab2eeSPeng Fan #else
256b57ff6fSAlison Wang #define TX_BUFFER_SIZE		0x40
26b93ab2eeSPeng Fan #endif
276b57ff6fSAlison Wang 
288770413fSGong Qianyu #define OFFSET_BITS_MASK	GENMASK(23, 0)
296b57ff6fSAlison Wang 
306b57ff6fSAlison Wang #define FLASH_STATUS_WEL	0x02
316b57ff6fSAlison Wang 
326b57ff6fSAlison Wang /* SEQID */
336b57ff6fSAlison Wang #define SEQID_WREN		1
346b57ff6fSAlison Wang #define SEQID_FAST_READ		2
356b57ff6fSAlison Wang #define SEQID_RDSR		3
366b57ff6fSAlison Wang #define SEQID_SE		4
376b57ff6fSAlison Wang #define SEQID_CHIP_ERASE	5
386b57ff6fSAlison Wang #define SEQID_PP		6
396b57ff6fSAlison Wang #define SEQID_RDID		7
40ba4dc8abSPeng Fan #define SEQID_BE_4K		8
41a2358783SPeng Fan #ifdef CONFIG_SPI_FLASH_BAR
42a2358783SPeng Fan #define SEQID_BRRD		9
43a2358783SPeng Fan #define SEQID_BRWR		10
44a2358783SPeng Fan #define SEQID_RDEAR		11
45a2358783SPeng Fan #define SEQID_WREAR		12
46a2358783SPeng Fan #endif
476b57ff6fSAlison Wang 
4853e3db7fSPeng Fan /* QSPI CMD */
4953e3db7fSPeng Fan #define QSPI_CMD_PP		0x02	/* Page program (up to 256 bytes) */
5053e3db7fSPeng Fan #define QSPI_CMD_RDSR		0x05	/* Read status register */
5153e3db7fSPeng Fan #define QSPI_CMD_WREN		0x06	/* Write enable */
5253e3db7fSPeng Fan #define QSPI_CMD_FAST_READ	0x0b	/* Read data bytes (high frequency) */
53ba4dc8abSPeng Fan #define QSPI_CMD_BE_4K		0x20    /* 4K erase */
5453e3db7fSPeng Fan #define QSPI_CMD_CHIP_ERASE	0xc7	/* Erase whole flash chip */
5553e3db7fSPeng Fan #define QSPI_CMD_SE		0xd8	/* Sector erase (usually 64KiB) */
5653e3db7fSPeng Fan #define QSPI_CMD_RDID		0x9f	/* Read JEDEC ID */
576b57ff6fSAlison Wang 
58a2358783SPeng Fan /* Used for Micron, winbond and Macronix flashes */
59a2358783SPeng Fan #define	QSPI_CMD_WREAR		0xc5	/* EAR register write */
60a2358783SPeng Fan #define	QSPI_CMD_RDEAR		0xc8	/* EAR reigster read */
61a2358783SPeng Fan 
62a2358783SPeng Fan /* Used for Spansion flashes only. */
63a2358783SPeng Fan #define	QSPI_CMD_BRRD		0x16	/* Bank register read */
64a2358783SPeng Fan #define	QSPI_CMD_BRWR		0x17	/* Bank register write */
65a2358783SPeng Fan 
6653e3db7fSPeng Fan /* 4-byte address QSPI CMD - used on Spansion and some Macronix flashes */
6753e3db7fSPeng Fan #define QSPI_CMD_FAST_READ_4B	0x0c    /* Read data bytes (high frequency) */
6853e3db7fSPeng Fan #define QSPI_CMD_PP_4B		0x12    /* Page program (up to 256 bytes) */
6953e3db7fSPeng Fan #define QSPI_CMD_SE_4B		0xdc    /* Sector erase (usually 64KiB) */
706b57ff6fSAlison Wang 
715bc48308SHaikun.Wang@freescale.com /* fsl_qspi_platdata flags */
7229e6abd9SJagan Teki #define QSPI_FLAG_REGMAP_ENDIAN_BIG	BIT(0)
735bc48308SHaikun.Wang@freescale.com 
745bc48308SHaikun.Wang@freescale.com /* default SCK frequency, unit: HZ */
755bc48308SHaikun.Wang@freescale.com #define FSL_QSPI_DEFAULT_SCK_FREQ	50000000
765bc48308SHaikun.Wang@freescale.com 
775bc48308SHaikun.Wang@freescale.com /* QSPI max chipselect signals number */
785bc48308SHaikun.Wang@freescale.com #define FSL_QSPI_MAX_CHIPSELECT_NUM     4
795bc48308SHaikun.Wang@freescale.com 
805bc48308SHaikun.Wang@freescale.com #ifdef CONFIG_DM_SPI
815bc48308SHaikun.Wang@freescale.com /**
825bc48308SHaikun.Wang@freescale.com  * struct fsl_qspi_platdata - platform data for Freescale QSPI
835bc48308SHaikun.Wang@freescale.com  *
845bc48308SHaikun.Wang@freescale.com  * @flags: Flags for QSPI QSPI_FLAG_...
855bc48308SHaikun.Wang@freescale.com  * @speed_hz: Default SCK frequency
865bc48308SHaikun.Wang@freescale.com  * @reg_base: Base address of QSPI registers
875bc48308SHaikun.Wang@freescale.com  * @amba_base: Base address of QSPI memory mapping
885bc48308SHaikun.Wang@freescale.com  * @amba_total_size: size of QSPI memory mapping
895bc48308SHaikun.Wang@freescale.com  * @flash_num: Number of active slave devices
905bc48308SHaikun.Wang@freescale.com  * @num_chipselect: Number of QSPI chipselect signals
915bc48308SHaikun.Wang@freescale.com  */
925bc48308SHaikun.Wang@freescale.com struct fsl_qspi_platdata {
935bc48308SHaikun.Wang@freescale.com 	u32 flags;
945bc48308SHaikun.Wang@freescale.com 	u32 speed_hz;
95bf9bffa9SYuan Yao 	fdt_addr_t reg_base;
96bf9bffa9SYuan Yao 	fdt_addr_t amba_base;
97bf9bffa9SYuan Yao 	fdt_size_t amba_total_size;
985bc48308SHaikun.Wang@freescale.com 	u32 flash_num;
995bc48308SHaikun.Wang@freescale.com 	u32 num_chipselect;
1005bc48308SHaikun.Wang@freescale.com };
1016b57ff6fSAlison Wang #endif
1026b57ff6fSAlison Wang 
1035bc48308SHaikun.Wang@freescale.com /**
1045bc48308SHaikun.Wang@freescale.com  * struct fsl_qspi_priv - private data for Freescale QSPI
1055bc48308SHaikun.Wang@freescale.com  *
1065bc48308SHaikun.Wang@freescale.com  * @flags: Flags for QSPI QSPI_FLAG_...
1075bc48308SHaikun.Wang@freescale.com  * @bus_clk: QSPI input clk frequency
1085bc48308SHaikun.Wang@freescale.com  * @speed_hz: Default SCK frequency
1095bc48308SHaikun.Wang@freescale.com  * @cur_seqid: current LUT table sequence id
1105bc48308SHaikun.Wang@freescale.com  * @sf_addr: flash access offset
1115bc48308SHaikun.Wang@freescale.com  * @amba_base: Base address of QSPI memory mapping of every CS
1125bc48308SHaikun.Wang@freescale.com  * @amba_total_size: size of QSPI memory mapping
1135bc48308SHaikun.Wang@freescale.com  * @cur_amba_base: Base address of QSPI memory mapping of current CS
1145bc48308SHaikun.Wang@freescale.com  * @flash_num: Number of active slave devices
1155bc48308SHaikun.Wang@freescale.com  * @num_chipselect: Number of QSPI chipselect signals
1165bc48308SHaikun.Wang@freescale.com  * @regs: Point to QSPI register structure for I/O access
1175bc48308SHaikun.Wang@freescale.com  */
1185bc48308SHaikun.Wang@freescale.com struct fsl_qspi_priv {
1195bc48308SHaikun.Wang@freescale.com 	u32 flags;
1205bc48308SHaikun.Wang@freescale.com 	u32 bus_clk;
1215bc48308SHaikun.Wang@freescale.com 	u32 speed_hz;
1225bc48308SHaikun.Wang@freescale.com 	u32 cur_seqid;
1235bc48308SHaikun.Wang@freescale.com 	u32 sf_addr;
1245bc48308SHaikun.Wang@freescale.com 	u32 amba_base[FSL_QSPI_MAX_CHIPSELECT_NUM];
1255bc48308SHaikun.Wang@freescale.com 	u32 amba_total_size;
1265bc48308SHaikun.Wang@freescale.com 	u32 cur_amba_base;
1275bc48308SHaikun.Wang@freescale.com 	u32 flash_num;
1285bc48308SHaikun.Wang@freescale.com 	u32 num_chipselect;
1295bc48308SHaikun.Wang@freescale.com 	struct fsl_qspi_regs *regs;
1306b57ff6fSAlison Wang };
1316b57ff6fSAlison Wang 
1325bc48308SHaikun.Wang@freescale.com #ifndef CONFIG_DM_SPI
1336b57ff6fSAlison Wang struct fsl_qspi {
1346b57ff6fSAlison Wang 	struct spi_slave slave;
1355bc48308SHaikun.Wang@freescale.com 	struct fsl_qspi_priv priv;
1366b57ff6fSAlison Wang };
1375bc48308SHaikun.Wang@freescale.com #endif
1385bc48308SHaikun.Wang@freescale.com 
1395bc48308SHaikun.Wang@freescale.com static u32 qspi_read32(u32 flags, u32 *addr)
1405bc48308SHaikun.Wang@freescale.com {
1415bc48308SHaikun.Wang@freescale.com 	return flags & QSPI_FLAG_REGMAP_ENDIAN_BIG ?
1425bc48308SHaikun.Wang@freescale.com 		in_be32(addr) : in_le32(addr);
1435bc48308SHaikun.Wang@freescale.com }
1445bc48308SHaikun.Wang@freescale.com 
1455bc48308SHaikun.Wang@freescale.com static void qspi_write32(u32 flags, u32 *addr, u32 val)
1465bc48308SHaikun.Wang@freescale.com {
1475bc48308SHaikun.Wang@freescale.com 	flags & QSPI_FLAG_REGMAP_ENDIAN_BIG ?
1485bc48308SHaikun.Wang@freescale.com 		out_be32(addr, val) : out_le32(addr, val);
1495bc48308SHaikun.Wang@freescale.com }
1506b57ff6fSAlison Wang 
1516b57ff6fSAlison Wang /* QSPI support swapping the flash read/write data
1526b57ff6fSAlison Wang  * in hardware for LS102xA, but not for VF610 */
1536b57ff6fSAlison Wang static inline u32 qspi_endian_xchg(u32 data)
1546b57ff6fSAlison Wang {
1556b57ff6fSAlison Wang #ifdef CONFIG_VF610
1566b57ff6fSAlison Wang 	return swab32(data);
1576b57ff6fSAlison Wang #else
1586b57ff6fSAlison Wang 	return data;
1596b57ff6fSAlison Wang #endif
1606b57ff6fSAlison Wang }
1616b57ff6fSAlison Wang 
1625bc48308SHaikun.Wang@freescale.com static void qspi_set_lut(struct fsl_qspi_priv *priv)
1636b57ff6fSAlison Wang {
1645bc48308SHaikun.Wang@freescale.com 	struct fsl_qspi_regs *regs = priv->regs;
1656b57ff6fSAlison Wang 	u32 lut_base;
1666b57ff6fSAlison Wang 
1676b57ff6fSAlison Wang 	/* Unlock the LUT */
1685bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->lutkey, LUT_KEY_VALUE);
1695bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->lckcr, QSPI_LCKCR_UNLOCK);
1706b57ff6fSAlison Wang 
1716b57ff6fSAlison Wang 	/* Write Enable */
1726b57ff6fSAlison Wang 	lut_base = SEQID_WREN * 4;
1735bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_WREN) |
1746b57ff6fSAlison Wang 		PAD0(LUT_PAD1) | INSTR0(LUT_CMD));
1755bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->lut[lut_base + 1], 0);
1765bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
1775bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);
1786b57ff6fSAlison Wang 
1796b57ff6fSAlison Wang 	/* Fast Read */
1806b57ff6fSAlison Wang 	lut_base = SEQID_FAST_READ * 4;
181a2358783SPeng Fan #ifdef CONFIG_SPI_FLASH_BAR
1825bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->lut[lut_base],
1835bc48308SHaikun.Wang@freescale.com 		     OPRND0(QSPI_CMD_FAST_READ) | PAD0(LUT_PAD1) |
1845bc48308SHaikun.Wang@freescale.com 		     INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
185a2358783SPeng Fan 		     PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
186a2358783SPeng Fan #else
1876b57ff6fSAlison Wang 	if (FSL_QSPI_FLASH_SIZE  <= SZ_16M)
1885bc48308SHaikun.Wang@freescale.com 		qspi_write32(priv->flags, &regs->lut[lut_base],
1895bc48308SHaikun.Wang@freescale.com 			     OPRND0(QSPI_CMD_FAST_READ) | PAD0(LUT_PAD1) |
1905bc48308SHaikun.Wang@freescale.com 			     INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
1916b57ff6fSAlison Wang 			     PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
1926b57ff6fSAlison Wang 	else
1935bc48308SHaikun.Wang@freescale.com 		qspi_write32(priv->flags, &regs->lut[lut_base],
19453e3db7fSPeng Fan 			     OPRND0(QSPI_CMD_FAST_READ_4B) |
19553e3db7fSPeng Fan 			     PAD0(LUT_PAD1) | INSTR0(LUT_CMD) |
19653e3db7fSPeng Fan 			     OPRND1(ADDR32BIT) | PAD1(LUT_PAD1) |
19753e3db7fSPeng Fan 			     INSTR1(LUT_ADDR));
198a2358783SPeng Fan #endif
1995bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->lut[lut_base + 1],
2005bc48308SHaikun.Wang@freescale.com 		     OPRND0(8) | PAD0(LUT_PAD1) | INSTR0(LUT_DUMMY) |
2015bc48308SHaikun.Wang@freescale.com 		     OPRND1(RX_BUFFER_SIZE) | PAD1(LUT_PAD1) |
2026b57ff6fSAlison Wang 		     INSTR1(LUT_READ));
2035bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
2045bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);
2056b57ff6fSAlison Wang 
2066b57ff6fSAlison Wang 	/* Read Status */
2076b57ff6fSAlison Wang 	lut_base = SEQID_RDSR * 4;
2085bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_RDSR) |
2096b57ff6fSAlison Wang 		PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) |
2106b57ff6fSAlison Wang 		PAD1(LUT_PAD1) | INSTR1(LUT_READ));
2115bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->lut[lut_base + 1], 0);
2125bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
2135bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);
2146b57ff6fSAlison Wang 
2156b57ff6fSAlison Wang 	/* Erase a sector */
2166b57ff6fSAlison Wang 	lut_base = SEQID_SE * 4;
217a2358783SPeng Fan #ifdef CONFIG_SPI_FLASH_BAR
2185bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_SE) |
219a2358783SPeng Fan 		     PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
220a2358783SPeng Fan 		     PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
221a2358783SPeng Fan #else
2226b57ff6fSAlison Wang 	if (FSL_QSPI_FLASH_SIZE  <= SZ_16M)
2235bc48308SHaikun.Wang@freescale.com 		qspi_write32(priv->flags, &regs->lut[lut_base],
2245bc48308SHaikun.Wang@freescale.com 			     OPRND0(QSPI_CMD_SE) | PAD0(LUT_PAD1) |
2255bc48308SHaikun.Wang@freescale.com 			     INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
2266b57ff6fSAlison Wang 			     PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
2276b57ff6fSAlison Wang 	else
2285bc48308SHaikun.Wang@freescale.com 		qspi_write32(priv->flags, &regs->lut[lut_base],
2295bc48308SHaikun.Wang@freescale.com 			     OPRND0(QSPI_CMD_SE_4B) | PAD0(LUT_PAD1) |
2305bc48308SHaikun.Wang@freescale.com 			     INSTR0(LUT_CMD) | OPRND1(ADDR32BIT) |
2316b57ff6fSAlison Wang 			     PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
232a2358783SPeng Fan #endif
2335bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->lut[lut_base + 1], 0);
2345bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
2355bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);
2366b57ff6fSAlison Wang 
2376b57ff6fSAlison Wang 	/* Erase the whole chip */
2386b57ff6fSAlison Wang 	lut_base = SEQID_CHIP_ERASE * 4;
2395bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->lut[lut_base],
2405bc48308SHaikun.Wang@freescale.com 		     OPRND0(QSPI_CMD_CHIP_ERASE) |
2416b57ff6fSAlison Wang 		     PAD0(LUT_PAD1) | INSTR0(LUT_CMD));
2425bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->lut[lut_base + 1], 0);
2435bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
2445bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);
2456b57ff6fSAlison Wang 
2466b57ff6fSAlison Wang 	/* Page Program */
2476b57ff6fSAlison Wang 	lut_base = SEQID_PP * 4;
248a2358783SPeng Fan #ifdef CONFIG_SPI_FLASH_BAR
2495bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_PP) |
250a2358783SPeng Fan 		     PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
251a2358783SPeng Fan 		     PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
252a2358783SPeng Fan #else
2536b57ff6fSAlison Wang 	if (FSL_QSPI_FLASH_SIZE  <= SZ_16M)
2545bc48308SHaikun.Wang@freescale.com 		qspi_write32(priv->flags, &regs->lut[lut_base],
2555bc48308SHaikun.Wang@freescale.com 			     OPRND0(QSPI_CMD_PP) | PAD0(LUT_PAD1) |
2565bc48308SHaikun.Wang@freescale.com 			     INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
2576b57ff6fSAlison Wang 			     PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
2586b57ff6fSAlison Wang 	else
2595bc48308SHaikun.Wang@freescale.com 		qspi_write32(priv->flags, &regs->lut[lut_base],
2605bc48308SHaikun.Wang@freescale.com 			     OPRND0(QSPI_CMD_PP_4B) | PAD0(LUT_PAD1) |
2615bc48308SHaikun.Wang@freescale.com 			     INSTR0(LUT_CMD) | OPRND1(ADDR32BIT) |
2626b57ff6fSAlison Wang 			     PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
263a2358783SPeng Fan #endif
264b93ab2eeSPeng Fan #ifdef CONFIG_MX6SX
265b93ab2eeSPeng Fan 	/*
266b93ab2eeSPeng Fan 	 * To MX6SX, OPRND0(TX_BUFFER_SIZE) can not work correctly.
267b93ab2eeSPeng Fan 	 * So, Use IDATSZ in IPCR to determine the size and here set 0.
268b93ab2eeSPeng Fan 	 */
2695bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->lut[lut_base + 1], OPRND0(0) |
270b93ab2eeSPeng Fan 		     PAD0(LUT_PAD1) | INSTR0(LUT_WRITE));
271b93ab2eeSPeng Fan #else
2725bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->lut[lut_base + 1],
2735bc48308SHaikun.Wang@freescale.com 		     OPRND0(TX_BUFFER_SIZE) |
2746b57ff6fSAlison Wang 		     PAD0(LUT_PAD1) | INSTR0(LUT_WRITE));
275b93ab2eeSPeng Fan #endif
2765bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
2775bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);
2786b57ff6fSAlison Wang 
2796b57ff6fSAlison Wang 	/* READ ID */
2806b57ff6fSAlison Wang 	lut_base = SEQID_RDID * 4;
2815bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_RDID) |
2826b57ff6fSAlison Wang 		PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(8) |
2836b57ff6fSAlison Wang 		PAD1(LUT_PAD1) | INSTR1(LUT_READ));
2845bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->lut[lut_base + 1], 0);
2855bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
2865bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);
2876b57ff6fSAlison Wang 
288ba4dc8abSPeng Fan 	/* SUB SECTOR 4K ERASE */
289ba4dc8abSPeng Fan 	lut_base = SEQID_BE_4K * 4;
2905bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_BE_4K) |
291ba4dc8abSPeng Fan 		     PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
292ba4dc8abSPeng Fan 		     PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
293ba4dc8abSPeng Fan 
294a2358783SPeng Fan #ifdef CONFIG_SPI_FLASH_BAR
295a2358783SPeng Fan 	/*
296a2358783SPeng Fan 	 * BRRD BRWR RDEAR WREAR are all supported, because it is hard to
297a2358783SPeng Fan 	 * dynamically check whether to set BRRD BRWR or RDEAR WREAR during
298a2358783SPeng Fan 	 * initialization.
299a2358783SPeng Fan 	 */
300a2358783SPeng Fan 	lut_base = SEQID_BRRD * 4;
3015bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_BRRD) |
302a2358783SPeng Fan 		     PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) |
303a2358783SPeng Fan 		     PAD1(LUT_PAD1) | INSTR1(LUT_READ));
304a2358783SPeng Fan 
305a2358783SPeng Fan 	lut_base = SEQID_BRWR * 4;
3065bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_BRWR) |
307a2358783SPeng Fan 		     PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) |
308a2358783SPeng Fan 		     PAD1(LUT_PAD1) | INSTR1(LUT_WRITE));
309a2358783SPeng Fan 
310a2358783SPeng Fan 	lut_base = SEQID_RDEAR * 4;
3115bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_RDEAR) |
312a2358783SPeng Fan 		     PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) |
313a2358783SPeng Fan 		     PAD1(LUT_PAD1) | INSTR1(LUT_READ));
314a2358783SPeng Fan 
315a2358783SPeng Fan 	lut_base = SEQID_WREAR * 4;
3165bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_WREAR) |
317a2358783SPeng Fan 		     PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) |
318a2358783SPeng Fan 		     PAD1(LUT_PAD1) | INSTR1(LUT_WRITE));
319a2358783SPeng Fan #endif
3206b57ff6fSAlison Wang 	/* Lock the LUT */
3215bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->lutkey, LUT_KEY_VALUE);
3225bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->lckcr, QSPI_LCKCR_LOCK);
3236b57ff6fSAlison Wang }
3246b57ff6fSAlison Wang 
3255f7f70c1SPeng Fan #if defined(CONFIG_SYS_FSL_QSPI_AHB)
3265f7f70c1SPeng Fan /*
3275f7f70c1SPeng Fan  * If we have changed the content of the flash by writing or erasing,
3285f7f70c1SPeng Fan  * we need to invalidate the AHB buffer. If we do not do so, we may read out
3295f7f70c1SPeng Fan  * the wrong data. The spec tells us reset the AHB domain and Serial Flash
3305f7f70c1SPeng Fan  * domain at the same time.
3315f7f70c1SPeng Fan  */
3325bc48308SHaikun.Wang@freescale.com static inline void qspi_ahb_invalid(struct fsl_qspi_priv *priv)
3335f7f70c1SPeng Fan {
3345bc48308SHaikun.Wang@freescale.com 	struct fsl_qspi_regs *regs = priv->regs;
3355f7f70c1SPeng Fan 	u32 reg;
3365f7f70c1SPeng Fan 
3375bc48308SHaikun.Wang@freescale.com 	reg = qspi_read32(priv->flags, &regs->mcr);
3385f7f70c1SPeng Fan 	reg |= QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK;
3395bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->mcr, reg);
3405f7f70c1SPeng Fan 
3415f7f70c1SPeng Fan 	/*
3425f7f70c1SPeng Fan 	 * The minimum delay : 1 AHB + 2 SFCK clocks.
3435f7f70c1SPeng Fan 	 * Delay 1 us is enough.
3445f7f70c1SPeng Fan 	 */
3455f7f70c1SPeng Fan 	udelay(1);
3465f7f70c1SPeng Fan 
3475f7f70c1SPeng Fan 	reg &= ~(QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK);
3485bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->mcr, reg);
3495f7f70c1SPeng Fan }
3505f7f70c1SPeng Fan 
3515f7f70c1SPeng Fan /* Read out the data from the AHB buffer. */
3525bc48308SHaikun.Wang@freescale.com static inline void qspi_ahb_read(struct fsl_qspi_priv *priv, u8 *rxbuf, int len)
3535f7f70c1SPeng Fan {
3545bc48308SHaikun.Wang@freescale.com 	struct fsl_qspi_regs *regs = priv->regs;
3555f7f70c1SPeng Fan 	u32 mcr_reg;
3565f7f70c1SPeng Fan 
3575bc48308SHaikun.Wang@freescale.com 	mcr_reg = qspi_read32(priv->flags, &regs->mcr);
3585f7f70c1SPeng Fan 
3595bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->mcr,
3605bc48308SHaikun.Wang@freescale.com 		     QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
3615f7f70c1SPeng Fan 		     QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
3625f7f70c1SPeng Fan 
3635f7f70c1SPeng Fan 	/* Read out the data directly from the AHB buffer. */
3645bc48308SHaikun.Wang@freescale.com 	memcpy(rxbuf, (u8 *)(priv->cur_amba_base + priv->sf_addr), len);
3655f7f70c1SPeng Fan 
3665bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->mcr, mcr_reg);
3675f7f70c1SPeng Fan }
3685f7f70c1SPeng Fan 
3695bc48308SHaikun.Wang@freescale.com static void qspi_enable_ddr_mode(struct fsl_qspi_priv *priv)
3705f7f70c1SPeng Fan {
3715f7f70c1SPeng Fan 	u32 reg, reg2;
3725bc48308SHaikun.Wang@freescale.com 	struct fsl_qspi_regs *regs = priv->regs;
3735f7f70c1SPeng Fan 
3745bc48308SHaikun.Wang@freescale.com 	reg = qspi_read32(priv->flags, &regs->mcr);
3755f7f70c1SPeng Fan 	/* Disable the module */
3765bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->mcr, reg | QSPI_MCR_MDIS_MASK);
3775f7f70c1SPeng Fan 
3785f7f70c1SPeng Fan 	/* Set the Sampling Register for DDR */
3795bc48308SHaikun.Wang@freescale.com 	reg2 = qspi_read32(priv->flags, &regs->smpr);
3805f7f70c1SPeng Fan 	reg2 &= ~QSPI_SMPR_DDRSMP_MASK;
3815f7f70c1SPeng Fan 	reg2 |= (2 << QSPI_SMPR_DDRSMP_SHIFT);
3825bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->smpr, reg2);
3835f7f70c1SPeng Fan 
3845f7f70c1SPeng Fan 	/* Enable the module again (enable the DDR too) */
3855f7f70c1SPeng Fan 	reg |= QSPI_MCR_DDR_EN_MASK;
3865f7f70c1SPeng Fan 	/* Enable bit 29 for imx6sx */
38729e6abd9SJagan Teki 	reg |= BIT(29);
3885f7f70c1SPeng Fan 
3895bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->mcr, reg);
3905f7f70c1SPeng Fan }
3915f7f70c1SPeng Fan 
3925f7f70c1SPeng Fan /*
3935f7f70c1SPeng Fan  * There are two different ways to read out the data from the flash:
3945f7f70c1SPeng Fan  *  the "IP Command Read" and the "AHB Command Read".
3955f7f70c1SPeng Fan  *
3965f7f70c1SPeng Fan  * The IC guy suggests we use the "AHB Command Read" which is faster
3975f7f70c1SPeng Fan  * then the "IP Command Read". (What's more is that there is a bug in
3985f7f70c1SPeng Fan  * the "IP Command Read" in the Vybrid.)
3995f7f70c1SPeng Fan  *
4005f7f70c1SPeng Fan  * After we set up the registers for the "AHB Command Read", we can use
4015f7f70c1SPeng Fan  * the memcpy to read the data directly. A "missed" access to the buffer
4025f7f70c1SPeng Fan  * causes the controller to clear the buffer, and use the sequence pointed
4035f7f70c1SPeng Fan  * by the QUADSPI_BFGENCR[SEQID] to initiate a read from the flash.
4045f7f70c1SPeng Fan  */
4055bc48308SHaikun.Wang@freescale.com static void qspi_init_ahb_read(struct fsl_qspi_priv *priv)
4065f7f70c1SPeng Fan {
4075bc48308SHaikun.Wang@freescale.com 	struct fsl_qspi_regs *regs = priv->regs;
4085bc48308SHaikun.Wang@freescale.com 
4095f7f70c1SPeng Fan 	/* AHB configuration for access buffer 0/1/2 .*/
4105bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->buf0cr, QSPI_BUFXCR_INVALID_MSTRID);
4115bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->buf1cr, QSPI_BUFXCR_INVALID_MSTRID);
4125bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->buf2cr, QSPI_BUFXCR_INVALID_MSTRID);
4135bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->buf3cr, QSPI_BUF3CR_ALLMST_MASK |
4145f7f70c1SPeng Fan 		     (0x80 << QSPI_BUF3CR_ADATSZ_SHIFT));
4155f7f70c1SPeng Fan 
4165f7f70c1SPeng Fan 	/* We only use the buffer3 */
4175bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->buf0ind, 0);
4185bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->buf1ind, 0);
4195bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->buf2ind, 0);
4205f7f70c1SPeng Fan 
4215f7f70c1SPeng Fan 	/*
4225f7f70c1SPeng Fan 	 * Set the default lut sequence for AHB Read.
4235f7f70c1SPeng Fan 	 * Parallel mode is disabled.
4245f7f70c1SPeng Fan 	 */
4255bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->bfgencr,
4265f7f70c1SPeng Fan 		     SEQID_FAST_READ << QSPI_BFGENCR_SEQID_SHIFT);
4275f7f70c1SPeng Fan 
4285f7f70c1SPeng Fan 	/*Enable DDR Mode*/
4295bc48308SHaikun.Wang@freescale.com 	qspi_enable_ddr_mode(priv);
4305f7f70c1SPeng Fan }
4315f7f70c1SPeng Fan #endif
4325f7f70c1SPeng Fan 
4335bc48308SHaikun.Wang@freescale.com #ifdef CONFIG_SPI_FLASH_BAR
4345bc48308SHaikun.Wang@freescale.com /* Bank register read/write, EAR register read/write */
4355bc48308SHaikun.Wang@freescale.com static void qspi_op_rdbank(struct fsl_qspi_priv *priv, u8 *rxbuf, u32 len)
4366b57ff6fSAlison Wang {
4375bc48308SHaikun.Wang@freescale.com 	struct fsl_qspi_regs *regs = priv->regs;
4385bc48308SHaikun.Wang@freescale.com 	u32 reg, mcr_reg, data, seqid;
4395bc48308SHaikun.Wang@freescale.com 
4405bc48308SHaikun.Wang@freescale.com 	mcr_reg = qspi_read32(priv->flags, &regs->mcr);
4415bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->mcr,
4425bc48308SHaikun.Wang@freescale.com 		     QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
4435bc48308SHaikun.Wang@freescale.com 		     QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
4445bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
4455bc48308SHaikun.Wang@freescale.com 
4465bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->sfar, priv->cur_amba_base);
4475bc48308SHaikun.Wang@freescale.com 
4485bc48308SHaikun.Wang@freescale.com 	if (priv->cur_seqid == QSPI_CMD_BRRD)
4495bc48308SHaikun.Wang@freescale.com 		seqid = SEQID_BRRD;
4505bc48308SHaikun.Wang@freescale.com 	else
4515bc48308SHaikun.Wang@freescale.com 		seqid = SEQID_RDEAR;
4525bc48308SHaikun.Wang@freescale.com 
4535bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->ipcr,
4545bc48308SHaikun.Wang@freescale.com 		     (seqid << QSPI_IPCR_SEQID_SHIFT) | len);
4555bc48308SHaikun.Wang@freescale.com 
4565bc48308SHaikun.Wang@freescale.com 	/* Wait previous command complete */
4575bc48308SHaikun.Wang@freescale.com 	while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
4585bc48308SHaikun.Wang@freescale.com 		;
4595bc48308SHaikun.Wang@freescale.com 
4605bc48308SHaikun.Wang@freescale.com 	while (1) {
4615bc48308SHaikun.Wang@freescale.com 		reg = qspi_read32(priv->flags, &regs->rbsr);
4625bc48308SHaikun.Wang@freescale.com 		if (reg & QSPI_RBSR_RDBFL_MASK) {
4635bc48308SHaikun.Wang@freescale.com 			data = qspi_read32(priv->flags, &regs->rbdr[0]);
4645bc48308SHaikun.Wang@freescale.com 			data = qspi_endian_xchg(data);
4655bc48308SHaikun.Wang@freescale.com 			memcpy(rxbuf, &data, len);
4665bc48308SHaikun.Wang@freescale.com 			qspi_write32(priv->flags, &regs->mcr,
4675bc48308SHaikun.Wang@freescale.com 				     qspi_read32(priv->flags, &regs->mcr) |
4685bc48308SHaikun.Wang@freescale.com 				     QSPI_MCR_CLR_RXF_MASK);
4695bc48308SHaikun.Wang@freescale.com 			break;
4705bc48308SHaikun.Wang@freescale.com 		}
4715bc48308SHaikun.Wang@freescale.com 	}
4725bc48308SHaikun.Wang@freescale.com 
4735bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->mcr, mcr_reg);
4745bc48308SHaikun.Wang@freescale.com }
4755bc48308SHaikun.Wang@freescale.com #endif
4765bc48308SHaikun.Wang@freescale.com 
4775bc48308SHaikun.Wang@freescale.com static void qspi_op_rdid(struct fsl_qspi_priv *priv, u32 *rxbuf, u32 len)
4785bc48308SHaikun.Wang@freescale.com {
4795bc48308SHaikun.Wang@freescale.com 	struct fsl_qspi_regs *regs = priv->regs;
4805207014dSGong Qianyu 	u32 mcr_reg, rbsr_reg, data, size;
4815207014dSGong Qianyu 	int i;
4825bc48308SHaikun.Wang@freescale.com 
4835bc48308SHaikun.Wang@freescale.com 	mcr_reg = qspi_read32(priv->flags, &regs->mcr);
4845bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->mcr,
4855bc48308SHaikun.Wang@freescale.com 		     QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
4865bc48308SHaikun.Wang@freescale.com 		     QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
4875bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
4885bc48308SHaikun.Wang@freescale.com 
4895bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->sfar, priv->cur_amba_base);
4905bc48308SHaikun.Wang@freescale.com 
4915bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->ipcr,
4925bc48308SHaikun.Wang@freescale.com 		     (SEQID_RDID << QSPI_IPCR_SEQID_SHIFT) | 0);
4935bc48308SHaikun.Wang@freescale.com 	while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
4945bc48308SHaikun.Wang@freescale.com 		;
4955bc48308SHaikun.Wang@freescale.com 
4965bc48308SHaikun.Wang@freescale.com 	i = 0;
4975207014dSGong Qianyu 	while ((RX_BUFFER_SIZE >= len) && (len > 0)) {
4985bc48308SHaikun.Wang@freescale.com 		rbsr_reg = qspi_read32(priv->flags, &regs->rbsr);
4995bc48308SHaikun.Wang@freescale.com 		if (rbsr_reg & QSPI_RBSR_RDBFL_MASK) {
5005bc48308SHaikun.Wang@freescale.com 			data = qspi_read32(priv->flags, &regs->rbdr[i]);
5015bc48308SHaikun.Wang@freescale.com 			data = qspi_endian_xchg(data);
5025207014dSGong Qianyu 			size = (len < 4) ? len : 4;
5035207014dSGong Qianyu 			memcpy(rxbuf, &data, size);
5045207014dSGong Qianyu 			len -= size;
5055bc48308SHaikun.Wang@freescale.com 			rxbuf++;
5065bc48308SHaikun.Wang@freescale.com 			i++;
5075bc48308SHaikun.Wang@freescale.com 		}
5085bc48308SHaikun.Wang@freescale.com 	}
5095bc48308SHaikun.Wang@freescale.com 
5105bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->mcr, mcr_reg);
5115bc48308SHaikun.Wang@freescale.com }
5125bc48308SHaikun.Wang@freescale.com 
5135bc48308SHaikun.Wang@freescale.com #ifndef CONFIG_SYS_FSL_QSPI_AHB
5145bc48308SHaikun.Wang@freescale.com /* If not use AHB read, read data from ip interface */
5155bc48308SHaikun.Wang@freescale.com static void qspi_op_read(struct fsl_qspi_priv *priv, u32 *rxbuf, u32 len)
5165bc48308SHaikun.Wang@freescale.com {
5175bc48308SHaikun.Wang@freescale.com 	struct fsl_qspi_regs *regs = priv->regs;
5185bc48308SHaikun.Wang@freescale.com 	u32 mcr_reg, data;
5195bc48308SHaikun.Wang@freescale.com 	int i, size;
5205bc48308SHaikun.Wang@freescale.com 	u32 to_or_from;
5215bc48308SHaikun.Wang@freescale.com 
5225bc48308SHaikun.Wang@freescale.com 	mcr_reg = qspi_read32(priv->flags, &regs->mcr);
5235bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->mcr,
5245bc48308SHaikun.Wang@freescale.com 		     QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
5255bc48308SHaikun.Wang@freescale.com 		     QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
5265bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
5275bc48308SHaikun.Wang@freescale.com 
5285bc48308SHaikun.Wang@freescale.com 	to_or_from = priv->sf_addr + priv->cur_amba_base;
5295bc48308SHaikun.Wang@freescale.com 
5305bc48308SHaikun.Wang@freescale.com 	while (len > 0) {
531beedbc2eSAlexander Stein 		WATCHDOG_RESET();
532beedbc2eSAlexander Stein 
5335bc48308SHaikun.Wang@freescale.com 		qspi_write32(priv->flags, &regs->sfar, to_or_from);
5345bc48308SHaikun.Wang@freescale.com 
5355bc48308SHaikun.Wang@freescale.com 		size = (len > RX_BUFFER_SIZE) ?
5365bc48308SHaikun.Wang@freescale.com 			RX_BUFFER_SIZE : len;
5375bc48308SHaikun.Wang@freescale.com 
5385bc48308SHaikun.Wang@freescale.com 		qspi_write32(priv->flags, &regs->ipcr,
5395bc48308SHaikun.Wang@freescale.com 			     (SEQID_FAST_READ << QSPI_IPCR_SEQID_SHIFT) |
5405bc48308SHaikun.Wang@freescale.com 			     size);
5415bc48308SHaikun.Wang@freescale.com 		while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
5425bc48308SHaikun.Wang@freescale.com 			;
5435bc48308SHaikun.Wang@freescale.com 
5445bc48308SHaikun.Wang@freescale.com 		to_or_from += size;
5455bc48308SHaikun.Wang@freescale.com 		len -= size;
5465bc48308SHaikun.Wang@freescale.com 
5475bc48308SHaikun.Wang@freescale.com 		i = 0;
5485bc48308SHaikun.Wang@freescale.com 		while ((RX_BUFFER_SIZE >= size) && (size > 0)) {
5495bc48308SHaikun.Wang@freescale.com 			data = qspi_read32(priv->flags, &regs->rbdr[i]);
5505bc48308SHaikun.Wang@freescale.com 			data = qspi_endian_xchg(data);
5515bc48308SHaikun.Wang@freescale.com 			memcpy(rxbuf, &data, 4);
5525bc48308SHaikun.Wang@freescale.com 			rxbuf++;
5535bc48308SHaikun.Wang@freescale.com 			size -= 4;
5545bc48308SHaikun.Wang@freescale.com 			i++;
5555bc48308SHaikun.Wang@freescale.com 		}
5565bc48308SHaikun.Wang@freescale.com 		qspi_write32(priv->flags, &regs->mcr,
5575bc48308SHaikun.Wang@freescale.com 			     qspi_read32(priv->flags, &regs->mcr) |
5585bc48308SHaikun.Wang@freescale.com 			     QSPI_MCR_CLR_RXF_MASK);
5595bc48308SHaikun.Wang@freescale.com 	}
5605bc48308SHaikun.Wang@freescale.com 
5615bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->mcr, mcr_reg);
5625bc48308SHaikun.Wang@freescale.com }
5635bc48308SHaikun.Wang@freescale.com #endif
5645bc48308SHaikun.Wang@freescale.com 
5655bc48308SHaikun.Wang@freescale.com static void qspi_op_write(struct fsl_qspi_priv *priv, u8 *txbuf, u32 len)
5665bc48308SHaikun.Wang@freescale.com {
5675bc48308SHaikun.Wang@freescale.com 	struct fsl_qspi_regs *regs = priv->regs;
5685bc48308SHaikun.Wang@freescale.com 	u32 mcr_reg, data, reg, status_reg, seqid;
5695bc48308SHaikun.Wang@freescale.com 	int i, size, tx_size;
5705bc48308SHaikun.Wang@freescale.com 	u32 to_or_from = 0;
5715bc48308SHaikun.Wang@freescale.com 
5725bc48308SHaikun.Wang@freescale.com 	mcr_reg = qspi_read32(priv->flags, &regs->mcr);
5735bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->mcr,
5745bc48308SHaikun.Wang@freescale.com 		     QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
5755bc48308SHaikun.Wang@freescale.com 		     QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
5765bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
5775bc48308SHaikun.Wang@freescale.com 
5785bc48308SHaikun.Wang@freescale.com 	status_reg = 0;
5795bc48308SHaikun.Wang@freescale.com 	while ((status_reg & FLASH_STATUS_WEL) != FLASH_STATUS_WEL) {
580beedbc2eSAlexander Stein 		WATCHDOG_RESET();
581beedbc2eSAlexander Stein 
5825bc48308SHaikun.Wang@freescale.com 		qspi_write32(priv->flags, &regs->ipcr,
5835bc48308SHaikun.Wang@freescale.com 			     (SEQID_WREN << QSPI_IPCR_SEQID_SHIFT) | 0);
5845bc48308SHaikun.Wang@freescale.com 		while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
5855bc48308SHaikun.Wang@freescale.com 			;
5865bc48308SHaikun.Wang@freescale.com 
5875bc48308SHaikun.Wang@freescale.com 		qspi_write32(priv->flags, &regs->ipcr,
5885bc48308SHaikun.Wang@freescale.com 			     (SEQID_RDSR << QSPI_IPCR_SEQID_SHIFT) | 1);
5895bc48308SHaikun.Wang@freescale.com 		while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
5905bc48308SHaikun.Wang@freescale.com 			;
5915bc48308SHaikun.Wang@freescale.com 
5925bc48308SHaikun.Wang@freescale.com 		reg = qspi_read32(priv->flags, &regs->rbsr);
5935bc48308SHaikun.Wang@freescale.com 		if (reg & QSPI_RBSR_RDBFL_MASK) {
5945bc48308SHaikun.Wang@freescale.com 			status_reg = qspi_read32(priv->flags, &regs->rbdr[0]);
5955bc48308SHaikun.Wang@freescale.com 			status_reg = qspi_endian_xchg(status_reg);
5965bc48308SHaikun.Wang@freescale.com 		}
5975bc48308SHaikun.Wang@freescale.com 		qspi_write32(priv->flags, &regs->mcr,
5985bc48308SHaikun.Wang@freescale.com 			     qspi_read32(priv->flags, &regs->mcr) |
5995bc48308SHaikun.Wang@freescale.com 			     QSPI_MCR_CLR_RXF_MASK);
6005bc48308SHaikun.Wang@freescale.com 	}
6015bc48308SHaikun.Wang@freescale.com 
6025bc48308SHaikun.Wang@freescale.com 	/* Default is page programming */
6035bc48308SHaikun.Wang@freescale.com 	seqid = SEQID_PP;
6045bc48308SHaikun.Wang@freescale.com #ifdef CONFIG_SPI_FLASH_BAR
6055bc48308SHaikun.Wang@freescale.com 	if (priv->cur_seqid == QSPI_CMD_BRWR)
6065bc48308SHaikun.Wang@freescale.com 		seqid = SEQID_BRWR;
6075bc48308SHaikun.Wang@freescale.com 	else if (priv->cur_seqid == QSPI_CMD_WREAR)
6085bc48308SHaikun.Wang@freescale.com 		seqid = SEQID_WREAR;
6095bc48308SHaikun.Wang@freescale.com #endif
6105bc48308SHaikun.Wang@freescale.com 
6115bc48308SHaikun.Wang@freescale.com 	to_or_from = priv->sf_addr + priv->cur_amba_base;
6125bc48308SHaikun.Wang@freescale.com 
6135bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->sfar, to_or_from);
6145bc48308SHaikun.Wang@freescale.com 
6155bc48308SHaikun.Wang@freescale.com 	tx_size = (len > TX_BUFFER_SIZE) ?
6165bc48308SHaikun.Wang@freescale.com 		TX_BUFFER_SIZE : len;
6175bc48308SHaikun.Wang@freescale.com 
6185bc48308SHaikun.Wang@freescale.com 	size = tx_size / 4;
6195bc48308SHaikun.Wang@freescale.com 	for (i = 0; i < size; i++) {
6205bc48308SHaikun.Wang@freescale.com 		memcpy(&data, txbuf, 4);
6215bc48308SHaikun.Wang@freescale.com 		data = qspi_endian_xchg(data);
6225bc48308SHaikun.Wang@freescale.com 		qspi_write32(priv->flags, &regs->tbdr, data);
6235bc48308SHaikun.Wang@freescale.com 		txbuf += 4;
6245bc48308SHaikun.Wang@freescale.com 	}
6255bc48308SHaikun.Wang@freescale.com 
6265bc48308SHaikun.Wang@freescale.com 	size = tx_size % 4;
6275bc48308SHaikun.Wang@freescale.com 	if (size) {
6285bc48308SHaikun.Wang@freescale.com 		data = 0;
6295bc48308SHaikun.Wang@freescale.com 		memcpy(&data, txbuf, size);
6305bc48308SHaikun.Wang@freescale.com 		data = qspi_endian_xchg(data);
6315bc48308SHaikun.Wang@freescale.com 		qspi_write32(priv->flags, &regs->tbdr, data);
6325bc48308SHaikun.Wang@freescale.com 	}
6335bc48308SHaikun.Wang@freescale.com 
6345bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->ipcr,
6355bc48308SHaikun.Wang@freescale.com 		     (seqid << QSPI_IPCR_SEQID_SHIFT) | tx_size);
6365bc48308SHaikun.Wang@freescale.com 	while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
6375bc48308SHaikun.Wang@freescale.com 		;
6385bc48308SHaikun.Wang@freescale.com 
6395bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->mcr, mcr_reg);
6405bc48308SHaikun.Wang@freescale.com }
6415bc48308SHaikun.Wang@freescale.com 
642940d2b89SGong Qianyu static void qspi_op_rdsr(struct fsl_qspi_priv *priv, void *rxbuf, u32 len)
6435bc48308SHaikun.Wang@freescale.com {
6445bc48308SHaikun.Wang@freescale.com 	struct fsl_qspi_regs *regs = priv->regs;
6455bc48308SHaikun.Wang@freescale.com 	u32 mcr_reg, reg, data;
6465bc48308SHaikun.Wang@freescale.com 
6475bc48308SHaikun.Wang@freescale.com 	mcr_reg = qspi_read32(priv->flags, &regs->mcr);
6485bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->mcr,
6495bc48308SHaikun.Wang@freescale.com 		     QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
6505bc48308SHaikun.Wang@freescale.com 		     QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
6515bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
6525bc48308SHaikun.Wang@freescale.com 
6535bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->sfar, priv->cur_amba_base);
6545bc48308SHaikun.Wang@freescale.com 
6555bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->ipcr,
6565bc48308SHaikun.Wang@freescale.com 		     (SEQID_RDSR << QSPI_IPCR_SEQID_SHIFT) | 0);
6575bc48308SHaikun.Wang@freescale.com 	while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
6585bc48308SHaikun.Wang@freescale.com 		;
6595bc48308SHaikun.Wang@freescale.com 
6605bc48308SHaikun.Wang@freescale.com 	while (1) {
6615bc48308SHaikun.Wang@freescale.com 		reg = qspi_read32(priv->flags, &regs->rbsr);
6625bc48308SHaikun.Wang@freescale.com 		if (reg & QSPI_RBSR_RDBFL_MASK) {
6635bc48308SHaikun.Wang@freescale.com 			data = qspi_read32(priv->flags, &regs->rbdr[0]);
6645bc48308SHaikun.Wang@freescale.com 			data = qspi_endian_xchg(data);
665940d2b89SGong Qianyu 			memcpy(rxbuf, &data, len);
6665bc48308SHaikun.Wang@freescale.com 			qspi_write32(priv->flags, &regs->mcr,
6675bc48308SHaikun.Wang@freescale.com 				     qspi_read32(priv->flags, &regs->mcr) |
6685bc48308SHaikun.Wang@freescale.com 				     QSPI_MCR_CLR_RXF_MASK);
6695bc48308SHaikun.Wang@freescale.com 			break;
6705bc48308SHaikun.Wang@freescale.com 		}
6715bc48308SHaikun.Wang@freescale.com 	}
6725bc48308SHaikun.Wang@freescale.com 
6735bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->mcr, mcr_reg);
6745bc48308SHaikun.Wang@freescale.com }
6755bc48308SHaikun.Wang@freescale.com 
6765bc48308SHaikun.Wang@freescale.com static void qspi_op_erase(struct fsl_qspi_priv *priv)
6775bc48308SHaikun.Wang@freescale.com {
6785bc48308SHaikun.Wang@freescale.com 	struct fsl_qspi_regs *regs = priv->regs;
6795bc48308SHaikun.Wang@freescale.com 	u32 mcr_reg;
6805bc48308SHaikun.Wang@freescale.com 	u32 to_or_from = 0;
6815bc48308SHaikun.Wang@freescale.com 
6825bc48308SHaikun.Wang@freescale.com 	mcr_reg = qspi_read32(priv->flags, &regs->mcr);
6835bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->mcr,
6845bc48308SHaikun.Wang@freescale.com 		     QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
6855bc48308SHaikun.Wang@freescale.com 		     QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
6865bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
6875bc48308SHaikun.Wang@freescale.com 
6885bc48308SHaikun.Wang@freescale.com 	to_or_from = priv->sf_addr + priv->cur_amba_base;
6895bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->sfar, to_or_from);
6905bc48308SHaikun.Wang@freescale.com 
6915bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->ipcr,
6925bc48308SHaikun.Wang@freescale.com 		     (SEQID_WREN << QSPI_IPCR_SEQID_SHIFT) | 0);
6935bc48308SHaikun.Wang@freescale.com 	while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
6945bc48308SHaikun.Wang@freescale.com 		;
6955bc48308SHaikun.Wang@freescale.com 
6965bc48308SHaikun.Wang@freescale.com 	if (priv->cur_seqid == QSPI_CMD_SE) {
6975bc48308SHaikun.Wang@freescale.com 		qspi_write32(priv->flags, &regs->ipcr,
6985bc48308SHaikun.Wang@freescale.com 			     (SEQID_SE << QSPI_IPCR_SEQID_SHIFT) | 0);
6995bc48308SHaikun.Wang@freescale.com 	} else if (priv->cur_seqid == QSPI_CMD_BE_4K) {
7005bc48308SHaikun.Wang@freescale.com 		qspi_write32(priv->flags, &regs->ipcr,
7015bc48308SHaikun.Wang@freescale.com 			     (SEQID_BE_4K << QSPI_IPCR_SEQID_SHIFT) | 0);
7025bc48308SHaikun.Wang@freescale.com 	}
7035bc48308SHaikun.Wang@freescale.com 	while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
7045bc48308SHaikun.Wang@freescale.com 		;
7055bc48308SHaikun.Wang@freescale.com 
7065bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &regs->mcr, mcr_reg);
7075bc48308SHaikun.Wang@freescale.com }
7085bc48308SHaikun.Wang@freescale.com 
7095bc48308SHaikun.Wang@freescale.com int qspi_xfer(struct fsl_qspi_priv *priv, unsigned int bitlen,
7105bc48308SHaikun.Wang@freescale.com 		const void *dout, void *din, unsigned long flags)
7115bc48308SHaikun.Wang@freescale.com {
7125bc48308SHaikun.Wang@freescale.com 	u32 bytes = DIV_ROUND_UP(bitlen, 8);
7135bc48308SHaikun.Wang@freescale.com 	static u32 wr_sfaddr;
7145bc48308SHaikun.Wang@freescale.com 	u32 txbuf;
7155bc48308SHaikun.Wang@freescale.com 
7165bc48308SHaikun.Wang@freescale.com 	if (dout) {
7175bc48308SHaikun.Wang@freescale.com 		if (flags & SPI_XFER_BEGIN) {
7185bc48308SHaikun.Wang@freescale.com 			priv->cur_seqid = *(u8 *)dout;
7195bc48308SHaikun.Wang@freescale.com 			memcpy(&txbuf, dout, 4);
7205bc48308SHaikun.Wang@freescale.com 		}
7215bc48308SHaikun.Wang@freescale.com 
7225bc48308SHaikun.Wang@freescale.com 		if (flags == SPI_XFER_END) {
7235bc48308SHaikun.Wang@freescale.com 			priv->sf_addr = wr_sfaddr;
7245bc48308SHaikun.Wang@freescale.com 			qspi_op_write(priv, (u8 *)dout, bytes);
7255bc48308SHaikun.Wang@freescale.com 			return 0;
7265bc48308SHaikun.Wang@freescale.com 		}
7275bc48308SHaikun.Wang@freescale.com 
7285bc48308SHaikun.Wang@freescale.com 		if (priv->cur_seqid == QSPI_CMD_FAST_READ) {
7295bc48308SHaikun.Wang@freescale.com 			priv->sf_addr = swab32(txbuf) & OFFSET_BITS_MASK;
7305bc48308SHaikun.Wang@freescale.com 		} else if ((priv->cur_seqid == QSPI_CMD_SE) ||
7315bc48308SHaikun.Wang@freescale.com 			   (priv->cur_seqid == QSPI_CMD_BE_4K)) {
7325bc48308SHaikun.Wang@freescale.com 			priv->sf_addr = swab32(txbuf) & OFFSET_BITS_MASK;
7335bc48308SHaikun.Wang@freescale.com 			qspi_op_erase(priv);
7345bc48308SHaikun.Wang@freescale.com 		} else if (priv->cur_seqid == QSPI_CMD_PP) {
7355bc48308SHaikun.Wang@freescale.com 			wr_sfaddr = swab32(txbuf) & OFFSET_BITS_MASK;
7365bc48308SHaikun.Wang@freescale.com 		} else if ((priv->cur_seqid == QSPI_CMD_BRWR) ||
7375bc48308SHaikun.Wang@freescale.com 			 (priv->cur_seqid == QSPI_CMD_WREAR)) {
7385bc48308SHaikun.Wang@freescale.com #ifdef CONFIG_SPI_FLASH_BAR
7395bc48308SHaikun.Wang@freescale.com 			wr_sfaddr = 0;
7405bc48308SHaikun.Wang@freescale.com #endif
7415bc48308SHaikun.Wang@freescale.com 		}
7425bc48308SHaikun.Wang@freescale.com 	}
7435bc48308SHaikun.Wang@freescale.com 
7445bc48308SHaikun.Wang@freescale.com 	if (din) {
7455bc48308SHaikun.Wang@freescale.com 		if (priv->cur_seqid == QSPI_CMD_FAST_READ) {
7465bc48308SHaikun.Wang@freescale.com #ifdef CONFIG_SYS_FSL_QSPI_AHB
7475bc48308SHaikun.Wang@freescale.com 			qspi_ahb_read(priv, din, bytes);
7485bc48308SHaikun.Wang@freescale.com #else
7495bc48308SHaikun.Wang@freescale.com 			qspi_op_read(priv, din, bytes);
7505bc48308SHaikun.Wang@freescale.com #endif
7515bc48308SHaikun.Wang@freescale.com 		} else if (priv->cur_seqid == QSPI_CMD_RDID)
7525bc48308SHaikun.Wang@freescale.com 			qspi_op_rdid(priv, din, bytes);
7535bc48308SHaikun.Wang@freescale.com 		else if (priv->cur_seqid == QSPI_CMD_RDSR)
754940d2b89SGong Qianyu 			qspi_op_rdsr(priv, din, bytes);
7555bc48308SHaikun.Wang@freescale.com #ifdef CONFIG_SPI_FLASH_BAR
7565bc48308SHaikun.Wang@freescale.com 		else if ((priv->cur_seqid == QSPI_CMD_BRRD) ||
7575bc48308SHaikun.Wang@freescale.com 			 (priv->cur_seqid == QSPI_CMD_RDEAR)) {
7585bc48308SHaikun.Wang@freescale.com 			priv->sf_addr = 0;
7595bc48308SHaikun.Wang@freescale.com 			qspi_op_rdbank(priv, din, bytes);
7605bc48308SHaikun.Wang@freescale.com 		}
7615bc48308SHaikun.Wang@freescale.com #endif
7625bc48308SHaikun.Wang@freescale.com 	}
7635bc48308SHaikun.Wang@freescale.com 
7645bc48308SHaikun.Wang@freescale.com #ifdef CONFIG_SYS_FSL_QSPI_AHB
7655bc48308SHaikun.Wang@freescale.com 	if ((priv->cur_seqid == QSPI_CMD_SE) ||
7665bc48308SHaikun.Wang@freescale.com 	    (priv->cur_seqid == QSPI_CMD_PP) ||
7675bc48308SHaikun.Wang@freescale.com 	    (priv->cur_seqid == QSPI_CMD_BE_4K) ||
7685bc48308SHaikun.Wang@freescale.com 	    (priv->cur_seqid == QSPI_CMD_WREAR) ||
7695bc48308SHaikun.Wang@freescale.com 	    (priv->cur_seqid == QSPI_CMD_BRWR))
7705bc48308SHaikun.Wang@freescale.com 		qspi_ahb_invalid(priv);
7715bc48308SHaikun.Wang@freescale.com #endif
7725bc48308SHaikun.Wang@freescale.com 
7735bc48308SHaikun.Wang@freescale.com 	return 0;
7745bc48308SHaikun.Wang@freescale.com }
7755bc48308SHaikun.Wang@freescale.com 
7765bc48308SHaikun.Wang@freescale.com void qspi_module_disable(struct fsl_qspi_priv *priv, u8 disable)
7775bc48308SHaikun.Wang@freescale.com {
7785bc48308SHaikun.Wang@freescale.com 	u32 mcr_val;
7795bc48308SHaikun.Wang@freescale.com 
7805bc48308SHaikun.Wang@freescale.com 	mcr_val = qspi_read32(priv->flags, &priv->regs->mcr);
7815bc48308SHaikun.Wang@freescale.com 	if (disable)
7825bc48308SHaikun.Wang@freescale.com 		mcr_val |= QSPI_MCR_MDIS_MASK;
7835bc48308SHaikun.Wang@freescale.com 	else
7845bc48308SHaikun.Wang@freescale.com 		mcr_val &= ~QSPI_MCR_MDIS_MASK;
7855bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &priv->regs->mcr, mcr_val);
7865bc48308SHaikun.Wang@freescale.com }
7875bc48308SHaikun.Wang@freescale.com 
7885bc48308SHaikun.Wang@freescale.com void qspi_cfg_smpr(struct fsl_qspi_priv *priv, u32 clear_bits, u32 set_bits)
7895bc48308SHaikun.Wang@freescale.com {
7905bc48308SHaikun.Wang@freescale.com 	u32 smpr_val;
7915bc48308SHaikun.Wang@freescale.com 
7925bc48308SHaikun.Wang@freescale.com 	smpr_val = qspi_read32(priv->flags, &priv->regs->smpr);
7935bc48308SHaikun.Wang@freescale.com 	smpr_val &= ~clear_bits;
7945bc48308SHaikun.Wang@freescale.com 	smpr_val |= set_bits;
7955bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &priv->regs->smpr, smpr_val);
7965bc48308SHaikun.Wang@freescale.com }
7975bc48308SHaikun.Wang@freescale.com #ifndef CONFIG_DM_SPI
7985bc48308SHaikun.Wang@freescale.com static unsigned long spi_bases[] = {
7995bc48308SHaikun.Wang@freescale.com 	QSPI0_BASE_ADDR,
8005bc48308SHaikun.Wang@freescale.com #ifdef CONFIG_MX6SX
8015bc48308SHaikun.Wang@freescale.com 	QSPI1_BASE_ADDR,
8025bc48308SHaikun.Wang@freescale.com #endif
8035bc48308SHaikun.Wang@freescale.com };
8045bc48308SHaikun.Wang@freescale.com 
8055bc48308SHaikun.Wang@freescale.com static unsigned long amba_bases[] = {
8065bc48308SHaikun.Wang@freescale.com 	QSPI0_AMBA_BASE,
8075bc48308SHaikun.Wang@freescale.com #ifdef CONFIG_MX6SX
8085bc48308SHaikun.Wang@freescale.com 	QSPI1_AMBA_BASE,
8095bc48308SHaikun.Wang@freescale.com #endif
8105bc48308SHaikun.Wang@freescale.com };
8115bc48308SHaikun.Wang@freescale.com 
8125bc48308SHaikun.Wang@freescale.com static inline struct fsl_qspi *to_qspi_spi(struct spi_slave *slave)
8135bc48308SHaikun.Wang@freescale.com {
8145bc48308SHaikun.Wang@freescale.com 	return container_of(slave, struct fsl_qspi, slave);
8156b57ff6fSAlison Wang }
8166b57ff6fSAlison Wang 
8176b57ff6fSAlison Wang struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
8186b57ff6fSAlison Wang 		unsigned int max_hz, unsigned int mode)
8196b57ff6fSAlison Wang {
8206b57ff6fSAlison Wang 	struct fsl_qspi *qspi;
8216b57ff6fSAlison Wang 	struct fsl_qspi_regs *regs;
8225f7f70c1SPeng Fan 	u32 total_size;
8236b57ff6fSAlison Wang 
8246b57ff6fSAlison Wang 	if (bus >= ARRAY_SIZE(spi_bases))
8256b57ff6fSAlison Wang 		return NULL;
8266b57ff6fSAlison Wang 
827ed0c81c6SPeng Fan 	if (cs >= FSL_QSPI_FLASH_NUM)
828ed0c81c6SPeng Fan 		return NULL;
829ed0c81c6SPeng Fan 
8306b57ff6fSAlison Wang 	qspi = spi_alloc_slave(struct fsl_qspi, bus, cs);
8316b57ff6fSAlison Wang 	if (!qspi)
8326b57ff6fSAlison Wang 		return NULL;
8336b57ff6fSAlison Wang 
8345bc48308SHaikun.Wang@freescale.com #ifdef CONFIG_SYS_FSL_QSPI_BE
8355bc48308SHaikun.Wang@freescale.com 	qspi->priv.flags |= QSPI_FLAG_REGMAP_ENDIAN_BIG;
8365bc48308SHaikun.Wang@freescale.com #endif
8375bc48308SHaikun.Wang@freescale.com 
8385bc48308SHaikun.Wang@freescale.com 	regs = (struct fsl_qspi_regs *)spi_bases[bus];
8395bc48308SHaikun.Wang@freescale.com 	qspi->priv.regs = regs;
840ed0c81c6SPeng Fan 	/*
841ed0c81c6SPeng Fan 	 * According cs, use different amba_base to choose the
842ed0c81c6SPeng Fan 	 * corresponding flash devices.
843ed0c81c6SPeng Fan 	 *
844ed0c81c6SPeng Fan 	 * If not, only one flash device is used even if passing
845ed0c81c6SPeng Fan 	 * different cs using `sf probe`
846ed0c81c6SPeng Fan 	 */
8475bc48308SHaikun.Wang@freescale.com 	qspi->priv.cur_amba_base = amba_bases[bus] + cs * FSL_QSPI_FLASH_SIZE;
8486b57ff6fSAlison Wang 
8496b57ff6fSAlison Wang 	qspi->slave.max_write_size = TX_BUFFER_SIZE;
8506b57ff6fSAlison Wang 
8515bc48308SHaikun.Wang@freescale.com 	qspi_write32(qspi->priv.flags, &regs->mcr,
8525bc48308SHaikun.Wang@freescale.com 		     QSPI_MCR_RESERVED_MASK | QSPI_MCR_MDIS_MASK);
8536b57ff6fSAlison Wang 
8545bc48308SHaikun.Wang@freescale.com 	qspi_cfg_smpr(&qspi->priv,
8555bc48308SHaikun.Wang@freescale.com 		      ~(QSPI_SMPR_FSDLY_MASK | QSPI_SMPR_DDRSMP_MASK |
8565bc48308SHaikun.Wang@freescale.com 		      QSPI_SMPR_FSPHS_MASK | QSPI_SMPR_HSENA_MASK), 0);
8576b57ff6fSAlison Wang 
8586b57ff6fSAlison Wang 	total_size = FSL_QSPI_FLASH_SIZE * FSL_QSPI_FLASH_NUM;
859ed0c81c6SPeng Fan 	/*
860ed0c81c6SPeng Fan 	 * Any read access to non-implemented addresses will provide
861ed0c81c6SPeng Fan 	 * undefined results.
862ed0c81c6SPeng Fan 	 *
863ed0c81c6SPeng Fan 	 * In case single die flash devices, TOP_ADDR_MEMA2 and
864ed0c81c6SPeng Fan 	 * TOP_ADDR_MEMB2 should be initialized/programmed to
865ed0c81c6SPeng Fan 	 * TOP_ADDR_MEMA1 and TOP_ADDR_MEMB1 respectively - in effect,
866ed0c81c6SPeng Fan 	 * setting the size of these devices to 0.  This would ensure
867ed0c81c6SPeng Fan 	 * that the complete memory map is assigned to only one flash device.
868ed0c81c6SPeng Fan 	 */
8695bc48308SHaikun.Wang@freescale.com 	qspi_write32(qspi->priv.flags, &regs->sfa1ad,
8705bc48308SHaikun.Wang@freescale.com 		     FSL_QSPI_FLASH_SIZE | amba_bases[bus]);
8715bc48308SHaikun.Wang@freescale.com 	qspi_write32(qspi->priv.flags, &regs->sfa2ad,
8725bc48308SHaikun.Wang@freescale.com 		     FSL_QSPI_FLASH_SIZE | amba_bases[bus]);
8735bc48308SHaikun.Wang@freescale.com 	qspi_write32(qspi->priv.flags, &regs->sfb1ad,
8745bc48308SHaikun.Wang@freescale.com 		     total_size | amba_bases[bus]);
8755bc48308SHaikun.Wang@freescale.com 	qspi_write32(qspi->priv.flags, &regs->sfb2ad,
8765bc48308SHaikun.Wang@freescale.com 		     total_size | amba_bases[bus]);
8776b57ff6fSAlison Wang 
8785bc48308SHaikun.Wang@freescale.com 	qspi_set_lut(&qspi->priv);
8796b57ff6fSAlison Wang 
8805f7f70c1SPeng Fan #ifdef CONFIG_SYS_FSL_QSPI_AHB
8815bc48308SHaikun.Wang@freescale.com 	qspi_init_ahb_read(&qspi->priv);
8825f7f70c1SPeng Fan #endif
8835bc48308SHaikun.Wang@freescale.com 
8845bc48308SHaikun.Wang@freescale.com 	qspi_module_disable(&qspi->priv, 0);
8855bc48308SHaikun.Wang@freescale.com 
8866b57ff6fSAlison Wang 	return &qspi->slave;
8876b57ff6fSAlison Wang }
8886b57ff6fSAlison Wang 
8896b57ff6fSAlison Wang void spi_free_slave(struct spi_slave *slave)
8906b57ff6fSAlison Wang {
8916b57ff6fSAlison Wang 	struct fsl_qspi *qspi = to_qspi_spi(slave);
8926b57ff6fSAlison Wang 
8936b57ff6fSAlison Wang 	free(qspi);
8946b57ff6fSAlison Wang }
8956b57ff6fSAlison Wang 
8966b57ff6fSAlison Wang int spi_claim_bus(struct spi_slave *slave)
8976b57ff6fSAlison Wang {
8986b57ff6fSAlison Wang 	return 0;
8996b57ff6fSAlison Wang }
9006b57ff6fSAlison Wang 
9015bc48308SHaikun.Wang@freescale.com void spi_release_bus(struct spi_slave *slave)
902a2358783SPeng Fan {
9035bc48308SHaikun.Wang@freescale.com 	/* Nothing to do */
9046b57ff6fSAlison Wang }
9056b57ff6fSAlison Wang 
9066b57ff6fSAlison Wang int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
9076b57ff6fSAlison Wang 		const void *dout, void *din, unsigned long flags)
9086b57ff6fSAlison Wang {
9096b57ff6fSAlison Wang 	struct fsl_qspi *qspi = to_qspi_spi(slave);
9106b57ff6fSAlison Wang 
9115bc48308SHaikun.Wang@freescale.com 	return qspi_xfer(&qspi->priv, bitlen, dout, din, flags);
912a2358783SPeng Fan }
9136b57ff6fSAlison Wang 
9145bc48308SHaikun.Wang@freescale.com void spi_init(void)
9156b57ff6fSAlison Wang {
9166b57ff6fSAlison Wang 	/* Nothing to do */
9176b57ff6fSAlison Wang }
9185bc48308SHaikun.Wang@freescale.com #else
9195bc48308SHaikun.Wang@freescale.com static int fsl_qspi_child_pre_probe(struct udevice *dev)
9205bc48308SHaikun.Wang@freescale.com {
921bcbe3d15SSimon Glass 	struct spi_slave *slave = dev_get_parent_priv(dev);
9225bc48308SHaikun.Wang@freescale.com 
9235bc48308SHaikun.Wang@freescale.com 	slave->max_write_size = TX_BUFFER_SIZE;
9245bc48308SHaikun.Wang@freescale.com 
9255bc48308SHaikun.Wang@freescale.com 	return 0;
9265bc48308SHaikun.Wang@freescale.com }
9275bc48308SHaikun.Wang@freescale.com 
9285bc48308SHaikun.Wang@freescale.com static int fsl_qspi_probe(struct udevice *bus)
9295bc48308SHaikun.Wang@freescale.com {
930*4e147418SYuan Yao 	u32 amba_size_per_chip;
9315bc48308SHaikun.Wang@freescale.com 	struct fsl_qspi_platdata *plat = dev_get_platdata(bus);
9325bc48308SHaikun.Wang@freescale.com 	struct fsl_qspi_priv *priv = dev_get_priv(bus);
9335bc48308SHaikun.Wang@freescale.com 	struct dm_spi_bus *dm_spi_bus;
934*4e147418SYuan Yao 	int i;
9355bc48308SHaikun.Wang@freescale.com 
9365bc48308SHaikun.Wang@freescale.com 	dm_spi_bus = bus->uclass_priv;
9375bc48308SHaikun.Wang@freescale.com 
9385bc48308SHaikun.Wang@freescale.com 	dm_spi_bus->max_hz = plat->speed_hz;
9395bc48308SHaikun.Wang@freescale.com 
940c2a4cb17SGong Qianyu 	priv->regs = (struct fsl_qspi_regs *)(uintptr_t)plat->reg_base;
9415bc48308SHaikun.Wang@freescale.com 	priv->flags = plat->flags;
9425bc48308SHaikun.Wang@freescale.com 
9435bc48308SHaikun.Wang@freescale.com 	priv->speed_hz = plat->speed_hz;
944bf9bffa9SYuan Yao 	/*
945bf9bffa9SYuan Yao 	 * QSPI SFADR width is 32bits, the max dest addr is 4GB-1.
946bf9bffa9SYuan Yao 	 * AMBA memory zone should be located on the 0~4GB space
947bf9bffa9SYuan Yao 	 * even on a 64bits cpu.
948bf9bffa9SYuan Yao 	 */
949bf9bffa9SYuan Yao 	priv->amba_base[0] = (u32)plat->amba_base;
950bf9bffa9SYuan Yao 	priv->amba_total_size = (u32)plat->amba_total_size;
9515bc48308SHaikun.Wang@freescale.com 	priv->flash_num = plat->flash_num;
9525bc48308SHaikun.Wang@freescale.com 	priv->num_chipselect = plat->num_chipselect;
9535bc48308SHaikun.Wang@freescale.com 
9545bc48308SHaikun.Wang@freescale.com 	qspi_write32(priv->flags, &priv->regs->mcr,
9555bc48308SHaikun.Wang@freescale.com 		     QSPI_MCR_RESERVED_MASK | QSPI_MCR_MDIS_MASK);
9565bc48308SHaikun.Wang@freescale.com 
9575bc48308SHaikun.Wang@freescale.com 	qspi_cfg_smpr(priv, ~(QSPI_SMPR_FSDLY_MASK | QSPI_SMPR_DDRSMP_MASK |
9585bc48308SHaikun.Wang@freescale.com 		QSPI_SMPR_FSPHS_MASK | QSPI_SMPR_HSENA_MASK), 0);
9595bc48308SHaikun.Wang@freescale.com 
960*4e147418SYuan Yao 	/*
961*4e147418SYuan Yao 	 * Assign AMBA memory zone for every chipselect
962*4e147418SYuan Yao 	 * QuadSPI has two channels, every channel has two chipselects.
963*4e147418SYuan Yao 	 * If the property 'num-cs' in dts is 2, the AMBA memory will be divided
964*4e147418SYuan Yao 	 * into two parts and assign to every channel. This indicate that every
965*4e147418SYuan Yao 	 * channel only has one valid chipselect.
966*4e147418SYuan Yao 	 * If the property 'num-cs' in dts is 4, the AMBA memory will be divided
967*4e147418SYuan Yao 	 * into four parts and assign to every chipselect.
968*4e147418SYuan Yao 	 * Every channel will has two valid chipselects.
969*4e147418SYuan Yao 	 */
970*4e147418SYuan Yao 	amba_size_per_chip = priv->amba_total_size >>
971*4e147418SYuan Yao 			     (priv->num_chipselect >> 1);
972*4e147418SYuan Yao 	for (i = 1 ; i < priv->num_chipselect ; i++)
973*4e147418SYuan Yao 		priv->amba_base[i] =
974*4e147418SYuan Yao 			amba_size_per_chip + priv->amba_base[i - 1];
975*4e147418SYuan Yao 
9765bc48308SHaikun.Wang@freescale.com 	/*
9775bc48308SHaikun.Wang@freescale.com 	 * Any read access to non-implemented addresses will provide
9785bc48308SHaikun.Wang@freescale.com 	 * undefined results.
9795bc48308SHaikun.Wang@freescale.com 	 *
9805bc48308SHaikun.Wang@freescale.com 	 * In case single die flash devices, TOP_ADDR_MEMA2 and
9815bc48308SHaikun.Wang@freescale.com 	 * TOP_ADDR_MEMB2 should be initialized/programmed to
9825bc48308SHaikun.Wang@freescale.com 	 * TOP_ADDR_MEMA1 and TOP_ADDR_MEMB1 respectively - in effect,
9835bc48308SHaikun.Wang@freescale.com 	 * setting the size of these devices to 0.  This would ensure
9845bc48308SHaikun.Wang@freescale.com 	 * that the complete memory map is assigned to only one flash device.
9855bc48308SHaikun.Wang@freescale.com 	 */
986*4e147418SYuan Yao 	qspi_write32(priv->flags, &priv->regs->sfa1ad, priv->amba_base[1]);
987*4e147418SYuan Yao 	switch (priv->num_chipselect) {
988*4e147418SYuan Yao 	case 2:
9895bc48308SHaikun.Wang@freescale.com 		qspi_write32(priv->flags, &priv->regs->sfa2ad,
990*4e147418SYuan Yao 			     priv->amba_base[1]);
9915bc48308SHaikun.Wang@freescale.com 		qspi_write32(priv->flags, &priv->regs->sfb1ad,
992*4e147418SYuan Yao 			     priv->amba_base[1] + amba_size_per_chip);
9935bc48308SHaikun.Wang@freescale.com 		qspi_write32(priv->flags, &priv->regs->sfb2ad,
994*4e147418SYuan Yao 			     priv->amba_base[1] + amba_size_per_chip);
995*4e147418SYuan Yao 		break;
996*4e147418SYuan Yao 	case 4:
997*4e147418SYuan Yao 		qspi_write32(priv->flags, &priv->regs->sfa2ad,
998*4e147418SYuan Yao 			     priv->amba_base[2]);
999*4e147418SYuan Yao 		qspi_write32(priv->flags, &priv->regs->sfb1ad,
1000*4e147418SYuan Yao 			     priv->amba_base[3]);
1001*4e147418SYuan Yao 		qspi_write32(priv->flags, &priv->regs->sfb2ad,
1002*4e147418SYuan Yao 			     priv->amba_base[3] + amba_size_per_chip);
1003*4e147418SYuan Yao 		break;
1004*4e147418SYuan Yao 	default:
1005*4e147418SYuan Yao 		debug("Error: Unsupported chipselect number %u!\n",
1006*4e147418SYuan Yao 		      priv->num_chipselect);
1007*4e147418SYuan Yao 		qspi_module_disable(priv, 1);
1008*4e147418SYuan Yao 		return -EINVAL;
1009*4e147418SYuan Yao 	}
10105bc48308SHaikun.Wang@freescale.com 
10115bc48308SHaikun.Wang@freescale.com 	qspi_set_lut(priv);
10125bc48308SHaikun.Wang@freescale.com 
10135bc48308SHaikun.Wang@freescale.com #ifdef CONFIG_SYS_FSL_QSPI_AHB
10145bc48308SHaikun.Wang@freescale.com 	qspi_init_ahb_read(priv);
10155bc48308SHaikun.Wang@freescale.com #endif
10165bc48308SHaikun.Wang@freescale.com 
10175bc48308SHaikun.Wang@freescale.com 	qspi_module_disable(priv, 0);
10185bc48308SHaikun.Wang@freescale.com 
10195bc48308SHaikun.Wang@freescale.com 	return 0;
10205bc48308SHaikun.Wang@freescale.com }
10215bc48308SHaikun.Wang@freescale.com 
10225bc48308SHaikun.Wang@freescale.com static int fsl_qspi_ofdata_to_platdata(struct udevice *bus)
10235bc48308SHaikun.Wang@freescale.com {
1024bf9bffa9SYuan Yao 	struct fdt_resource res_regs, res_mem;
10255bc48308SHaikun.Wang@freescale.com 	struct fsl_qspi_platdata *plat = bus->platdata;
10265bc48308SHaikun.Wang@freescale.com 	const void *blob = gd->fdt_blob;
10275bc48308SHaikun.Wang@freescale.com 	int node = bus->of_offset;
10285bc48308SHaikun.Wang@freescale.com 	int ret, flash_num = 0, subnode;
10295bc48308SHaikun.Wang@freescale.com 
10305bc48308SHaikun.Wang@freescale.com 	if (fdtdec_get_bool(blob, node, "big-endian"))
10315bc48308SHaikun.Wang@freescale.com 		plat->flags |= QSPI_FLAG_REGMAP_ENDIAN_BIG;
10325bc48308SHaikun.Wang@freescale.com 
1033bf9bffa9SYuan Yao 	ret = fdt_get_named_resource(blob, node, "reg", "reg-names",
1034bf9bffa9SYuan Yao 				     "QuadSPI", &res_regs);
10355bc48308SHaikun.Wang@freescale.com 	if (ret) {
1036bf9bffa9SYuan Yao 		debug("Error: can't get regs base addresses(ret = %d)!\n", ret);
1037bf9bffa9SYuan Yao 		return -ENOMEM;
1038bf9bffa9SYuan Yao 	}
1039bf9bffa9SYuan Yao 	ret = fdt_get_named_resource(blob, node, "reg", "reg-names",
1040bf9bffa9SYuan Yao 				     "QuadSPI-memory", &res_mem);
1041bf9bffa9SYuan Yao 	if (ret) {
1042bf9bffa9SYuan Yao 		debug("Error: can't get AMBA base addresses(ret = %d)!\n", ret);
10435bc48308SHaikun.Wang@freescale.com 		return -ENOMEM;
10445bc48308SHaikun.Wang@freescale.com 	}
10455bc48308SHaikun.Wang@freescale.com 
10465bc48308SHaikun.Wang@freescale.com 	/* Count flash numbers */
10475bc48308SHaikun.Wang@freescale.com 	fdt_for_each_subnode(blob, subnode, node)
10485bc48308SHaikun.Wang@freescale.com 		++flash_num;
10495bc48308SHaikun.Wang@freescale.com 
10505bc48308SHaikun.Wang@freescale.com 	if (flash_num == 0) {
10515bc48308SHaikun.Wang@freescale.com 		debug("Error: Missing flashes!\n");
10525bc48308SHaikun.Wang@freescale.com 		return -ENODEV;
10535bc48308SHaikun.Wang@freescale.com 	}
10545bc48308SHaikun.Wang@freescale.com 
10555bc48308SHaikun.Wang@freescale.com 	plat->speed_hz = fdtdec_get_int(blob, node, "spi-max-frequency",
10565bc48308SHaikun.Wang@freescale.com 					FSL_QSPI_DEFAULT_SCK_FREQ);
10575bc48308SHaikun.Wang@freescale.com 	plat->num_chipselect = fdtdec_get_int(blob, node, "num-cs",
10585bc48308SHaikun.Wang@freescale.com 					      FSL_QSPI_MAX_CHIPSELECT_NUM);
10595bc48308SHaikun.Wang@freescale.com 
1060bf9bffa9SYuan Yao 	plat->reg_base = res_regs.start;
1061bf9bffa9SYuan Yao 	plat->amba_base = res_mem.start;
1062bf9bffa9SYuan Yao 	plat->amba_total_size = res_mem.end - res_mem.start + 1;
10635bc48308SHaikun.Wang@freescale.com 	plat->flash_num = flash_num;
10645bc48308SHaikun.Wang@freescale.com 
1065bf9bffa9SYuan Yao 	debug("%s: regs=<0x%llx> <0x%llx, 0x%llx>, max-frequency=%d, endianess=%s\n",
10665bc48308SHaikun.Wang@freescale.com 	      __func__,
1067bf9bffa9SYuan Yao 	      (u64)plat->reg_base,
1068bf9bffa9SYuan Yao 	      (u64)plat->amba_base,
1069bf9bffa9SYuan Yao 	      (u64)plat->amba_total_size,
10705bc48308SHaikun.Wang@freescale.com 	      plat->speed_hz,
10715bc48308SHaikun.Wang@freescale.com 	      plat->flags & QSPI_FLAG_REGMAP_ENDIAN_BIG ? "be" : "le"
10725bc48308SHaikun.Wang@freescale.com 	      );
10735bc48308SHaikun.Wang@freescale.com 
10745bc48308SHaikun.Wang@freescale.com 	return 0;
10755bc48308SHaikun.Wang@freescale.com }
10765bc48308SHaikun.Wang@freescale.com 
10775bc48308SHaikun.Wang@freescale.com static int fsl_qspi_xfer(struct udevice *dev, unsigned int bitlen,
10785bc48308SHaikun.Wang@freescale.com 		const void *dout, void *din, unsigned long flags)
10795bc48308SHaikun.Wang@freescale.com {
10805bc48308SHaikun.Wang@freescale.com 	struct fsl_qspi_priv *priv;
10815bc48308SHaikun.Wang@freescale.com 	struct udevice *bus;
10825bc48308SHaikun.Wang@freescale.com 
10835bc48308SHaikun.Wang@freescale.com 	bus = dev->parent;
10845bc48308SHaikun.Wang@freescale.com 	priv = dev_get_priv(bus);
10855bc48308SHaikun.Wang@freescale.com 
10865bc48308SHaikun.Wang@freescale.com 	return qspi_xfer(priv, bitlen, dout, din, flags);
10875bc48308SHaikun.Wang@freescale.com }
10885bc48308SHaikun.Wang@freescale.com 
10895bc48308SHaikun.Wang@freescale.com static int fsl_qspi_claim_bus(struct udevice *dev)
10905bc48308SHaikun.Wang@freescale.com {
10915bc48308SHaikun.Wang@freescale.com 	struct fsl_qspi_priv *priv;
10925bc48308SHaikun.Wang@freescale.com 	struct udevice *bus;
10935bc48308SHaikun.Wang@freescale.com 	struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
10945bc48308SHaikun.Wang@freescale.com 
10955bc48308SHaikun.Wang@freescale.com 	bus = dev->parent;
10965bc48308SHaikun.Wang@freescale.com 	priv = dev_get_priv(bus);
10975bc48308SHaikun.Wang@freescale.com 
1098*4e147418SYuan Yao 	priv->cur_amba_base = priv->amba_base[slave_plat->cs];
10995bc48308SHaikun.Wang@freescale.com 
11005bc48308SHaikun.Wang@freescale.com 	qspi_module_disable(priv, 0);
11015bc48308SHaikun.Wang@freescale.com 
11025bc48308SHaikun.Wang@freescale.com 	return 0;
11035bc48308SHaikun.Wang@freescale.com }
11045bc48308SHaikun.Wang@freescale.com 
11055bc48308SHaikun.Wang@freescale.com static int fsl_qspi_release_bus(struct udevice *dev)
11065bc48308SHaikun.Wang@freescale.com {
11075bc48308SHaikun.Wang@freescale.com 	struct fsl_qspi_priv *priv;
11085bc48308SHaikun.Wang@freescale.com 	struct udevice *bus;
11095bc48308SHaikun.Wang@freescale.com 
11105bc48308SHaikun.Wang@freescale.com 	bus = dev->parent;
11115bc48308SHaikun.Wang@freescale.com 	priv = dev_get_priv(bus);
11125bc48308SHaikun.Wang@freescale.com 
11135bc48308SHaikun.Wang@freescale.com 	qspi_module_disable(priv, 1);
11145bc48308SHaikun.Wang@freescale.com 
11155bc48308SHaikun.Wang@freescale.com 	return 0;
11165bc48308SHaikun.Wang@freescale.com }
11175bc48308SHaikun.Wang@freescale.com 
11185bc48308SHaikun.Wang@freescale.com static int fsl_qspi_set_speed(struct udevice *bus, uint speed)
11195bc48308SHaikun.Wang@freescale.com {
11205bc48308SHaikun.Wang@freescale.com 	/* Nothing to do */
11215bc48308SHaikun.Wang@freescale.com 	return 0;
11225bc48308SHaikun.Wang@freescale.com }
11235bc48308SHaikun.Wang@freescale.com 
11245bc48308SHaikun.Wang@freescale.com static int fsl_qspi_set_mode(struct udevice *bus, uint mode)
11255bc48308SHaikun.Wang@freescale.com {
11265bc48308SHaikun.Wang@freescale.com 	/* Nothing to do */
11275bc48308SHaikun.Wang@freescale.com 	return 0;
11285bc48308SHaikun.Wang@freescale.com }
11295bc48308SHaikun.Wang@freescale.com 
11305bc48308SHaikun.Wang@freescale.com static const struct dm_spi_ops fsl_qspi_ops = {
11315bc48308SHaikun.Wang@freescale.com 	.claim_bus	= fsl_qspi_claim_bus,
11325bc48308SHaikun.Wang@freescale.com 	.release_bus	= fsl_qspi_release_bus,
11335bc48308SHaikun.Wang@freescale.com 	.xfer		= fsl_qspi_xfer,
11345bc48308SHaikun.Wang@freescale.com 	.set_speed	= fsl_qspi_set_speed,
11355bc48308SHaikun.Wang@freescale.com 	.set_mode	= fsl_qspi_set_mode,
11365bc48308SHaikun.Wang@freescale.com };
11375bc48308SHaikun.Wang@freescale.com 
11385bc48308SHaikun.Wang@freescale.com static const struct udevice_id fsl_qspi_ids[] = {
11395bc48308SHaikun.Wang@freescale.com 	{ .compatible = "fsl,vf610-qspi" },
11405bc48308SHaikun.Wang@freescale.com 	{ .compatible = "fsl,imx6sx-qspi" },
11415bc48308SHaikun.Wang@freescale.com 	{ }
11425bc48308SHaikun.Wang@freescale.com };
11435bc48308SHaikun.Wang@freescale.com 
11445bc48308SHaikun.Wang@freescale.com U_BOOT_DRIVER(fsl_qspi) = {
11455bc48308SHaikun.Wang@freescale.com 	.name	= "fsl_qspi",
11465bc48308SHaikun.Wang@freescale.com 	.id	= UCLASS_SPI,
11475bc48308SHaikun.Wang@freescale.com 	.of_match = fsl_qspi_ids,
11485bc48308SHaikun.Wang@freescale.com 	.ops	= &fsl_qspi_ops,
11495bc48308SHaikun.Wang@freescale.com 	.ofdata_to_platdata = fsl_qspi_ofdata_to_platdata,
11505bc48308SHaikun.Wang@freescale.com 	.platdata_auto_alloc_size = sizeof(struct fsl_qspi_platdata),
11515bc48308SHaikun.Wang@freescale.com 	.priv_auto_alloc_size = sizeof(struct fsl_qspi_priv),
11525bc48308SHaikun.Wang@freescale.com 	.probe	= fsl_qspi_probe,
11535bc48308SHaikun.Wang@freescale.com 	.child_pre_probe = fsl_qspi_child_pre_probe,
11545bc48308SHaikun.Wang@freescale.com };
11555bc48308SHaikun.Wang@freescale.com #endif
1156