xref: /rk3399_rockchip-uboot/drivers/spi/rockchip_sfc.c (revision 113ced8fa404a3284c0eb76492b52eba6d82dfa7)
1c1cd6cb6SAndy Yan /*
2c6d59f03SAndy Yan  * SFC driver for rockchip
3c1cd6cb6SAndy Yan  *
4c6d59f03SAndy Yan  * (C) Copyright 2017 Rockchip Electronics Co., Ltd
5c1cd6cb6SAndy Yan  * Yifeng.zhao, Software Engineering, <zhao0116@gmail.com>.
6c1cd6cb6SAndy Yan  *
7c1cd6cb6SAndy Yan  * SPDX-License-Identifier:     GPL-2.0+
8c1cd6cb6SAndy Yan  */
9c1cd6cb6SAndy Yan 
10c1cd6cb6SAndy Yan #include <common.h>
1137911cf6SAndy Yan #include <bouncebuf.h>
12c1cd6cb6SAndy Yan #include <clk.h>
13c1cd6cb6SAndy Yan #include <dm.h>
14c1cd6cb6SAndy Yan #include <dt-structs.h>
15c1cd6cb6SAndy Yan #include <errno.h>
16c1cd6cb6SAndy Yan #include <spi.h>
17c1cd6cb6SAndy Yan #include <linux/errno.h>
18c1cd6cb6SAndy Yan #include <asm/io.h>
19c1cd6cb6SAndy Yan #include <asm/arch/clock.h>
20c1cd6cb6SAndy Yan #include <asm/arch/periph.h>
21c1cd6cb6SAndy Yan #include <dm/pinctrl.h>
22c1cd6cb6SAndy Yan 
23c1cd6cb6SAndy Yan DECLARE_GLOBAL_DATA_PTR;
24c1cd6cb6SAndy Yan 
2539b850deSJon Lin #ifdef SFC_DEBUG
2639b850deSJon Lin #define SFC_DBG printf
2739b850deSJon Lin #else
2839b850deSJon Lin #define SFC_DBG(args...)
2939b850deSJon Lin #endif
3039b850deSJon Lin 
31c6d59f03SAndy Yan struct rockchip_sfc_reg {
32c6d59f03SAndy Yan 	u32 ctrl;
33c6d59f03SAndy Yan 	u32 imr;
34c6d59f03SAndy Yan 	u32 iclr;
35c6d59f03SAndy Yan 	u32 ftlr;
36c6d59f03SAndy Yan 	u32 rcvr;
37c6d59f03SAndy Yan 	u32 ax;
38c6d59f03SAndy Yan 	u32 abit;
39c6d59f03SAndy Yan 	u32 isr;
40c6d59f03SAndy Yan 	u32 fsr;
41c6d59f03SAndy Yan 	u32 sr;
42c6d59f03SAndy Yan 	u32 risr;
43c6d59f03SAndy Yan 	u32 reserved[21];
44c6d59f03SAndy Yan 	u32 dmatr;
45c6d59f03SAndy Yan 	u32 dmaaddr;
46c6d59f03SAndy Yan 	u32 reserved1[30];
47c6d59f03SAndy Yan 	u32 cmd;
48c6d59f03SAndy Yan 	u32 addr;
49c6d59f03SAndy Yan 	u32 data;
50c6d59f03SAndy Yan };
5139b850deSJon Lin 
52c6d59f03SAndy Yan check_member(rockchip_sfc_reg, data, 0x108);
53c6d59f03SAndy Yan 
54c6d59f03SAndy Yan /*SFC_CTRL*/
55c6d59f03SAndy Yan #define SFC_DATA_WIDTH_SHIFT	12
56c6d59f03SAndy Yan #define SFC_DATA_WIDTH_MASK	GENMASK(13, 12)
57c6d59f03SAndy Yan #define SFC_ADDR_WIDTH_SHIFT	10
58c6d59f03SAndy Yan #define SFC_ADDR_WIDTH_MASK	GENMASK(11, 10)
59c6d59f03SAndy Yan #define SFC_CMD_WIDTH_SHIFT	8
60c6d59f03SAndy Yan #define SFC_CMD_WIDTH_MASK	GENMASK(9, 8)
61c6d59f03SAndy Yan #define SFC_DATA_SHIFT_NEGETIVE	BIT(1)
62c6d59f03SAndy Yan 
63c6d59f03SAndy Yan /*SFC_CMD*/
64c6d59f03SAndy Yan #define SFC_DUMMY_BITS_SHIFT	8
65c6d59f03SAndy Yan #define SFC_RW_SHIFT		12
66c6d59f03SAndy Yan #define SFC_WR			1
67c6d59f03SAndy Yan #define SFC_RD			0
68c6d59f03SAndy Yan #define SFC_ADDR_BITS_SHIFT	14
69c6d59f03SAndy Yan #define SFC_ADDR_BITS_MASK	GENMASK(15, 14)
70c6d59f03SAndy Yan #define SFC_ADDR_0BITS		0
71c6d59f03SAndy Yan #define SFC_ADDR_24BITS		1
72c6d59f03SAndy Yan #define SFC_ADDR_32BITS		2
73c6d59f03SAndy Yan #define SFC_ADDR_XBITS		3
74c6d59f03SAndy Yan #define SFC_TRB_SHIFT		(16)
75c6d59f03SAndy Yan #define SFC_TRB_MASK		GENMASK(29, 16)
76c6d59f03SAndy Yan 
77c6d59f03SAndy Yan /* Dma start trigger signal. Auto cleared after write */
78c6d59f03SAndy Yan #define SFC_DMA_START		BIT(0)
79c6d59f03SAndy Yan 
80c6d59f03SAndy Yan #define SFC_RESET		BIT(0)
81c6d59f03SAndy Yan 
82c6d59f03SAndy Yan /*SFC_FSR*/
83c6d59f03SAndy Yan #define SFC_RXLV_SHIFT		(16)
84c6d59f03SAndy Yan #define SFC_RXLV_MASK		GENMASK(20, 16)
85c6d59f03SAndy Yan #define SFC_TXLV_SHIFT		(8)
86c6d59f03SAndy Yan #define SFC_TXLV_MASK		GENMASK(12, 8)
87c6d59f03SAndy Yan #define SFC_RX_FULL		BIT(3)	/* rx fifo full */
88c6d59f03SAndy Yan #define SFC_RX_EMPTY		BIT(2)	/* rx fifo empty */
89c6d59f03SAndy Yan #define SFC_TX_EMPTY		BIT(1)	/* tx fifo empty */
90c6d59f03SAndy Yan #define SFC_TX_FULL		BIT(0)	/* tx fifo full */
91c6d59f03SAndy Yan 
92c6d59f03SAndy Yan #define SFC_BUSY		BIT(0)	/* sfc busy flag */
93c6d59f03SAndy Yan 
94c6d59f03SAndy Yan /*SFC_RISR*/
95c6d59f03SAndy Yan #define DMA_FINISH_INT		BIT(7)        /* dma interrupt */
96c6d59f03SAndy Yan #define SPI_ERR_INT		BIT(6)        /* Nspi error interrupt */
97c6d59f03SAndy Yan #define AHB_ERR_INT		BIT(5)        /* Ahb bus error interrupt */
98c6d59f03SAndy Yan #define TRANS_FINISH_INT	BIT(4)        /* Transfer finish interrupt */
99c6d59f03SAndy Yan #define TX_EMPTY_INT		BIT(3)        /* Tx fifo empty interrupt */
100c6d59f03SAndy Yan #define TX_OF_INT		BIT(2)        /* Tx fifo overflow interrupt */
101c6d59f03SAndy Yan #define RX_UF_INT		BIT(1)        /* Rx fifo underflow interrupt */
102c6d59f03SAndy Yan #define RX_FULL_INT		BIT(0)        /* Rx fifo full interrupt */
103c6d59f03SAndy Yan 
104c6d59f03SAndy Yan #define SFC_MAX_TRB		(512 * 31)
105c6d59f03SAndy Yan 
106ae52cbcbSJon Lin #define SFC_MAX_RATE		(150 * 1000 * 1000)
107ae52cbcbSJon Lin #define SFC_DEFAULT_RATE	(80 * 1000 * 1000)
108ae52cbcbSJon Lin #define SFC_MIN_RATE		(10 * 1000 * 1000)
109ae52cbcbSJon Lin 
110c1cd6cb6SAndy Yan enum rockchip_sfc_if_type {
111c1cd6cb6SAndy Yan 	IF_TYPE_STD,
112c1cd6cb6SAndy Yan 	IF_TYPE_DUAL,
113c1cd6cb6SAndy Yan 	IF_TYPE_QUAD,
114c1cd6cb6SAndy Yan };
115c1cd6cb6SAndy Yan 
116c1cd6cb6SAndy Yan struct rockchip_sfc_platdata {
117c1cd6cb6SAndy Yan 	s32 frequency;
11814b86dc9SJon Lin 	void *base;
119c1cd6cb6SAndy Yan };
120c1cd6cb6SAndy Yan 
121c1cd6cb6SAndy Yan struct rockchip_sfc {
122c1cd6cb6SAndy Yan 	struct rockchip_sfc_reg *regbase;
123c1cd6cb6SAndy Yan 	struct clk clk;
124c1cd6cb6SAndy Yan 	unsigned int max_freq;
125c1cd6cb6SAndy Yan 	unsigned int mode;
126c1cd6cb6SAndy Yan 	unsigned int speed_hz;
127c1cd6cb6SAndy Yan 	u32 cmd;
128c1cd6cb6SAndy Yan 	u32 addr;
129da4954b7SAndy Yan 	u8 addr_bits;
13088ea3acbSJon Lin 	u8 addr_xbits_ext;
131da4954b7SAndy Yan 	u8 dummy_bits;
132da4954b7SAndy Yan 	u8 rw;
133da4954b7SAndy Yan 	u32 trb;
134c1cd6cb6SAndy Yan };
135c1cd6cb6SAndy Yan 
136c1cd6cb6SAndy Yan static int rockchip_sfc_ofdata_to_platdata(struct udevice *bus)
137c1cd6cb6SAndy Yan {
138c1cd6cb6SAndy Yan 	struct rockchip_sfc_platdata *plat = dev_get_platdata(bus);
139c1cd6cb6SAndy Yan 	struct rockchip_sfc *sfc = dev_get_priv(bus);
14014b86dc9SJon Lin 	ofnode subnode;
141c1cd6cb6SAndy Yan 	int ret;
142c1cd6cb6SAndy Yan 
14314b86dc9SJon Lin 	plat->base = dev_read_addr_ptr(bus);
144c1cd6cb6SAndy Yan 	ret = clk_get_by_index(bus, 0, &sfc->clk);
145c1cd6cb6SAndy Yan 	if (ret < 0) {
14614b86dc9SJon Lin 		printf("Could not get clock for %s: %d\n", bus->name, ret);
147c1cd6cb6SAndy Yan 		return ret;
148c1cd6cb6SAndy Yan 	}
149c1cd6cb6SAndy Yan 
15014b86dc9SJon Lin 	subnode = dev_read_first_subnode(bus);
15114b86dc9SJon Lin 	if (!ofnode_valid(subnode)) {
15214b86dc9SJon Lin 		printf("Error: subnode with SPI flash config missing!\n");
153c1cd6cb6SAndy Yan 		return -ENODEV;
154c1cd6cb6SAndy Yan 	}
155c1cd6cb6SAndy Yan 
15614b86dc9SJon Lin 	plat->frequency = ofnode_read_u32_default(subnode, "spi-max-frequency",
157c1cd6cb6SAndy Yan 						  100000000);
158ae52cbcbSJon Lin 	if (plat->frequency > SFC_MAX_RATE || plat->frequency < SFC_MIN_RATE)
159ae52cbcbSJon Lin 		plat->frequency = SFC_DEFAULT_RATE;
160ae52cbcbSJon Lin 	sfc->max_freq = plat->frequency;
161c1cd6cb6SAndy Yan 
162c1cd6cb6SAndy Yan 	return 0;
163c1cd6cb6SAndy Yan }
164c1cd6cb6SAndy Yan 
165c1cd6cb6SAndy Yan static int rockchip_sfc_probe(struct udevice *bus)
166c1cd6cb6SAndy Yan {
167c1cd6cb6SAndy Yan 	struct rockchip_sfc_platdata *plat = dev_get_platdata(bus);
168c1cd6cb6SAndy Yan 	struct rockchip_sfc *sfc = dev_get_priv(bus);
169ae52cbcbSJon Lin 	struct dm_spi_bus *dm_spi_bus;
170c1cd6cb6SAndy Yan 
171ae52cbcbSJon Lin 	dm_spi_bus = bus->uclass_priv;
172ae52cbcbSJon Lin 	dm_spi_bus->max_hz = plat->frequency;
173c1cd6cb6SAndy Yan 	sfc->regbase = (struct rockchip_sfc_reg *)plat->base;
174c1cd6cb6SAndy Yan 
175c1cd6cb6SAndy Yan 	return 0;
176c1cd6cb6SAndy Yan }
177c1cd6cb6SAndy Yan 
178c1cd6cb6SAndy Yan static int rockchip_sfc_reset(struct rockchip_sfc *sfc)
179c1cd6cb6SAndy Yan {
180c1cd6cb6SAndy Yan 	struct rockchip_sfc_reg *regs = sfc->regbase;
181c1cd6cb6SAndy Yan 	int tbase = get_timer(0);
182c1cd6cb6SAndy Yan 	u32 rcvr;
183c1cd6cb6SAndy Yan 	int ret = 0;
184c1cd6cb6SAndy Yan 
185c1cd6cb6SAndy Yan 	writel(SFC_RESET, &regs->rcvr);
186c1cd6cb6SAndy Yan 	do {
187c1cd6cb6SAndy Yan 		rcvr = readl(&regs->rcvr);
188c1cd6cb6SAndy Yan 		if (get_timer(tbase) > 1000) {
189c1cd6cb6SAndy Yan 			debug("sfc reset timeout\n");
190c1cd6cb6SAndy Yan 			ret =  -ETIMEDOUT;
191c1cd6cb6SAndy Yan 			break;
192c1cd6cb6SAndy Yan 		}
193c1cd6cb6SAndy Yan 		udelay(1);
194c1cd6cb6SAndy Yan 	} while (rcvr);
195c1cd6cb6SAndy Yan 
196c1cd6cb6SAndy Yan 	writel(0xFFFFFFFF, &regs->iclr);
197c1cd6cb6SAndy Yan 
198c1cd6cb6SAndy Yan 	debug("sfc reset\n");
199c1cd6cb6SAndy Yan 
200c1cd6cb6SAndy Yan 	return ret;
201c1cd6cb6SAndy Yan }
202c1cd6cb6SAndy Yan 
203915fcf0cSAndy Yan /* The SFC_CTRL register is a global control register,
204915fcf0cSAndy Yan  * when the controller is in busy state(SFC_SR),
205915fcf0cSAndy Yan  * SFC_CTRL cannot be set.
206915fcf0cSAndy Yan  */
207915fcf0cSAndy Yan static int rockchip_sfc_wait_idle(struct rockchip_sfc *sfc,
208915fcf0cSAndy Yan 				  u32 timeout_ms)
209915fcf0cSAndy Yan {
210915fcf0cSAndy Yan 	struct rockchip_sfc_reg *regs = sfc->regbase;
211915fcf0cSAndy Yan 	unsigned long tbase = get_timer(0);
212915fcf0cSAndy Yan 	u32 sr, fsr;
213915fcf0cSAndy Yan 
214915fcf0cSAndy Yan 	while (1) {
215915fcf0cSAndy Yan 		sr = readl(&regs->sr);
216915fcf0cSAndy Yan 		fsr = readl(&regs->fsr);
21739b850deSJon Lin 		if ((fsr & SFC_TX_EMPTY) &&
21839b850deSJon Lin 		    (fsr & SFC_RX_EMPTY) &&
21939b850deSJon Lin 		    !(sr & SFC_BUSY))
220915fcf0cSAndy Yan 			break;
221915fcf0cSAndy Yan 		if (get_timer(tbase) > timeout_ms) {
222915fcf0cSAndy Yan 			printf("waite sfc idle timeout(sr:0x%08x fsr:0x%08x)\n",
223915fcf0cSAndy Yan 				sr, fsr);
224915fcf0cSAndy Yan 			rockchip_sfc_reset(sfc);
225915fcf0cSAndy Yan 			return -ETIMEDOUT;
226915fcf0cSAndy Yan 		}
227915fcf0cSAndy Yan 		udelay(100);
228915fcf0cSAndy Yan 	}
229915fcf0cSAndy Yan 
230915fcf0cSAndy Yan 	return 0;
231915fcf0cSAndy Yan }
232915fcf0cSAndy Yan 
233c1cd6cb6SAndy Yan static u8 rockchip_sfc_get_if_type(struct rockchip_sfc *sfc)
234c1cd6cb6SAndy Yan {
235c1cd6cb6SAndy Yan 	int type = IF_TYPE_STD;
236c1cd6cb6SAndy Yan 
237da4954b7SAndy Yan 	if (sfc->rw == SFC_WR) {
238c1cd6cb6SAndy Yan 		if (sfc->mode & SPI_TX_QUAD)
239c1cd6cb6SAndy Yan 			type = IF_TYPE_QUAD;
240c1cd6cb6SAndy Yan 		else if (sfc->mode & SPI_TX_DUAL)
241c1cd6cb6SAndy Yan 			type = IF_TYPE_DUAL;
242c1cd6cb6SAndy Yan 		else
243c1cd6cb6SAndy Yan 			type = IF_TYPE_STD;
244c1cd6cb6SAndy Yan 	} else {
245c1cd6cb6SAndy Yan 		if (sfc->mode & SPI_RX_QUAD)
246c1cd6cb6SAndy Yan 			type = IF_TYPE_QUAD;
247c1cd6cb6SAndy Yan 		else if (sfc->mode & SPI_RX_DUAL)
248c1cd6cb6SAndy Yan 			type = IF_TYPE_DUAL;
249c1cd6cb6SAndy Yan 		else
250c1cd6cb6SAndy Yan 			type = IF_TYPE_STD;
251c1cd6cb6SAndy Yan 	}
252c1cd6cb6SAndy Yan 
253c1cd6cb6SAndy Yan 	return type;
254c1cd6cb6SAndy Yan }
255c1cd6cb6SAndy Yan 
256da4954b7SAndy Yan static void rockchip_sfc_setup_xfer(struct rockchip_sfc *sfc, u32 trb)
257c1cd6cb6SAndy Yan {
258c1cd6cb6SAndy Yan 	struct rockchip_sfc_reg *regs = sfc->regbase;
259c1cd6cb6SAndy Yan 	u32 val = 0x02;
260c1cd6cb6SAndy Yan 	u8 data_width = IF_TYPE_STD;
261c1cd6cb6SAndy Yan 
26239b850deSJon Lin 	SFC_DBG("--- sfc.addr_bit %x\n", sfc->addr_bits);
26339b850deSJon Lin 
26439b850deSJon Lin 	if (sfc->addr_bits == SFC_ADDR_24BITS ||
26539b850deSJon Lin 	    sfc->addr_bits == SFC_ADDR_32BITS)
266c1cd6cb6SAndy Yan 		data_width = rockchip_sfc_get_if_type(sfc);
267c1cd6cb6SAndy Yan 
268*113ced8fSJon Lin 	if (sfc->addr_bits == SFC_ADDR_XBITS)
26988ea3acbSJon Lin 		writel(sfc->addr_xbits_ext - 1, &regs->abit);
27088ea3acbSJon Lin 
271c1cd6cb6SAndy Yan 	val |= (data_width << SFC_DATA_WIDTH_SHIFT);
272c1cd6cb6SAndy Yan 
273915fcf0cSAndy Yan 	rockchip_sfc_wait_idle(sfc, 10);
274915fcf0cSAndy Yan 
27539b850deSJon Lin 	SFC_DBG("--- sfc.ctrl %x\n", val);
276c1cd6cb6SAndy Yan 	writel(val, &regs->ctrl);
277da4954b7SAndy Yan 
278da4954b7SAndy Yan 	val = sfc->cmd;
279da4954b7SAndy Yan 	val |= trb << SFC_TRB_SHIFT;
280da4954b7SAndy Yan 	val |= sfc->rw << SFC_RW_SHIFT;
281da4954b7SAndy Yan 	val |= sfc->addr_bits << SFC_ADDR_BITS_SHIFT;
282da4954b7SAndy Yan 	val |= sfc->dummy_bits << SFC_DUMMY_BITS_SHIFT;
283da4954b7SAndy Yan 
28439b850deSJon Lin 	SFC_DBG("--- sfc.cmd %x\n", val);
285da4954b7SAndy Yan 	writel(val, &regs->cmd);
286da4954b7SAndy Yan 
28739b850deSJon Lin 	if (sfc->addr_bits & SFC_ADDR_XBITS) {
28839b850deSJon Lin 		SFC_DBG("--- sfc.addr %x\n", sfc->addr);
289c1cd6cb6SAndy Yan 		writel(sfc->addr, &regs->addr);
290c1cd6cb6SAndy Yan 	}
29139b850deSJon Lin }
292c1cd6cb6SAndy Yan 
29330f161d1SAndy Yan static int rockchip_sfc_dma_xfer(struct rockchip_sfc *sfc, void *buffer, size_t trb)
294c1cd6cb6SAndy Yan {
295c1cd6cb6SAndy Yan 	struct rockchip_sfc_reg *regs = sfc->regbase;
29637911cf6SAndy Yan 	struct bounce_buffer bb;
29737911cf6SAndy Yan 	unsigned int bb_flags;
298c1cd6cb6SAndy Yan 	int timeout = 1000;
299c1cd6cb6SAndy Yan 	int ret = 0;
300c1cd6cb6SAndy Yan 	int risr;
301c1cd6cb6SAndy Yan 	unsigned long tbase;
302c1cd6cb6SAndy Yan 
30337911cf6SAndy Yan 	if (sfc->rw == SFC_WR)
30437911cf6SAndy Yan 		bb_flags = GEN_BB_READ;
30537911cf6SAndy Yan 	else
30637911cf6SAndy Yan 		bb_flags = GEN_BB_WRITE;
30737911cf6SAndy Yan 
30830f161d1SAndy Yan 	ret = bounce_buffer_start(&bb, buffer, trb, bb_flags);
30937911cf6SAndy Yan 	if (ret)
31037911cf6SAndy Yan 		return ret;
31130f161d1SAndy Yan 
31237911cf6SAndy Yan 	rockchip_sfc_setup_xfer(sfc, bb.len_aligned);
313c1cd6cb6SAndy Yan 
314c1cd6cb6SAndy Yan 	writel(0xFFFFFFFF, &regs->iclr);
31514b86dc9SJon Lin 	writel((unsigned long)bb.bounce_buffer, &regs->dmaaddr);
316c1cd6cb6SAndy Yan 	writel(SFC_DMA_START, &regs->dmatr);
317c1cd6cb6SAndy Yan 
318c1cd6cb6SAndy Yan 	tbase = get_timer(0);
319c1cd6cb6SAndy Yan 	do {
320c1cd6cb6SAndy Yan 		udelay(1);
321c1cd6cb6SAndy Yan 		risr = readl(&regs->risr);
322c1cd6cb6SAndy Yan 		if (get_timer(tbase) > timeout) {
323c1cd6cb6SAndy Yan 			debug("dma timeout\n");
324c1cd6cb6SAndy Yan 			ret = -ETIMEDOUT;
325c1cd6cb6SAndy Yan 			break;
326c1cd6cb6SAndy Yan 		}
327c1cd6cb6SAndy Yan 	} while (!(risr & TRANS_FINISH_INT));
328c1cd6cb6SAndy Yan 
329c1cd6cb6SAndy Yan 	writel(0xFFFFFFFF, &regs->iclr);
330c1cd6cb6SAndy Yan 
33137911cf6SAndy Yan 	bounce_buffer_stop(&bb);
33237911cf6SAndy Yan 
333c1cd6cb6SAndy Yan 	return ret;
334c1cd6cb6SAndy Yan }
335c1cd6cb6SAndy Yan 
336da4954b7SAndy Yan static int rockchip_sfc_wait_fifo_ready(struct rockchip_sfc *sfc, int rw,
337c1cd6cb6SAndy Yan 					u32 timeout)
338c1cd6cb6SAndy Yan {
339c1cd6cb6SAndy Yan 	struct rockchip_sfc_reg *regs = sfc->regbase;
340c1cd6cb6SAndy Yan 	unsigned long tbase = get_timer(0);
341c1cd6cb6SAndy Yan 	u8 level;
342c1cd6cb6SAndy Yan 	u32 fsr;
343c1cd6cb6SAndy Yan 
344c1cd6cb6SAndy Yan 	do {
345c1cd6cb6SAndy Yan 		fsr = readl(&regs->fsr);
346da4954b7SAndy Yan 		if (rw == SFC_WR)
347c1cd6cb6SAndy Yan 			level = (fsr & SFC_TXLV_MASK) >> SFC_TXLV_SHIFT;
348c1cd6cb6SAndy Yan 		else
349c1cd6cb6SAndy Yan 			level = (fsr & SFC_RXLV_MASK) >> SFC_RXLV_SHIFT;
350c1cd6cb6SAndy Yan 		if (get_timer(tbase) > timeout)
351c1cd6cb6SAndy Yan 			return -ETIMEDOUT;
352c1cd6cb6SAndy Yan 		udelay(1);
353c1cd6cb6SAndy Yan 	} while (!level);
354c1cd6cb6SAndy Yan 
355c1cd6cb6SAndy Yan 	return level;
356c1cd6cb6SAndy Yan }
357c1cd6cb6SAndy Yan 
358da4954b7SAndy Yan static int rockchip_sfc_write_fifo(struct rockchip_sfc *sfc, u32 *buf, u32 len)
359c1cd6cb6SAndy Yan {
360c1cd6cb6SAndy Yan 	struct rockchip_sfc_reg *regs = sfc->regbase;
361c1cd6cb6SAndy Yan 	u32 bytes = len & 0x3;
362c1cd6cb6SAndy Yan 	u32 words = len >> 2;
363915fcf0cSAndy Yan 	int tx_level = 0;
364c1cd6cb6SAndy Yan 	u32 val = 0;
365c1cd6cb6SAndy Yan 	u8 count;
366c1cd6cb6SAndy Yan 
367c1cd6cb6SAndy Yan 	while (words) {
368da4954b7SAndy Yan 		tx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_WR, 1000);
369c1cd6cb6SAndy Yan 		if (tx_level <= 0)
370c1cd6cb6SAndy Yan 			return tx_level;
371915fcf0cSAndy Yan 		count = min(words, (u32)tx_level);
372c1cd6cb6SAndy Yan 		writesl(&regs->data, buf, count);
373c1cd6cb6SAndy Yan 		buf += count;
374c1cd6cb6SAndy Yan 		words -= count;
375c1cd6cb6SAndy Yan 	}
376c1cd6cb6SAndy Yan 
377da4954b7SAndy Yan 	/* handle the last non 4byte aligned bytes */
378c1cd6cb6SAndy Yan 	if (bytes) {
379da4954b7SAndy Yan 		tx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_WR, 1000);
380c1cd6cb6SAndy Yan 		if (tx_level <= 0)
381c1cd6cb6SAndy Yan 			return tx_level;
382c1cd6cb6SAndy Yan 		memcpy(&val, buf, bytes);
383c1cd6cb6SAndy Yan 		writel(val, &regs->data);
384c1cd6cb6SAndy Yan 	}
385c1cd6cb6SAndy Yan 
386c1cd6cb6SAndy Yan 	return 0;
387c1cd6cb6SAndy Yan }
388c1cd6cb6SAndy Yan 
389da4954b7SAndy Yan static int rockchip_sfc_read_fifo(struct rockchip_sfc *sfc, u32 *buf, u32 len)
390c1cd6cb6SAndy Yan {
391c1cd6cb6SAndy Yan 	struct rockchip_sfc_reg *regs = sfc->regbase;
392c1cd6cb6SAndy Yan 	u32 bytes = len & 0x3;
393c1cd6cb6SAndy Yan 	u32 words = len >> 2;
394915fcf0cSAndy Yan 	int rx_level = 0;
395c1cd6cb6SAndy Yan 	u32 count;
396c1cd6cb6SAndy Yan 	u32 val;
397c1cd6cb6SAndy Yan 
398c1cd6cb6SAndy Yan 	while (words) {
399da4954b7SAndy Yan 		rx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_RD, 1000);
400c1cd6cb6SAndy Yan 		if (rx_level <= 0)
401c1cd6cb6SAndy Yan 			return rx_level;
402915fcf0cSAndy Yan 		count = min(words, (u32)rx_level);
403c1cd6cb6SAndy Yan 		readsl(&regs->data, buf, count);
404c1cd6cb6SAndy Yan 		buf += count;
405c1cd6cb6SAndy Yan 		words -= count;
406c1cd6cb6SAndy Yan 	}
407c1cd6cb6SAndy Yan 
408da4954b7SAndy Yan 	/* handle the last non 4 bytes aligned bytes */
409c1cd6cb6SAndy Yan 	if (bytes) {
410da4954b7SAndy Yan 		rx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_RD, 1000);
411c1cd6cb6SAndy Yan 		if (rx_level <= 0)
412c1cd6cb6SAndy Yan 			return rx_level;
413c1cd6cb6SAndy Yan 		val = readl(&regs->data);
414c1cd6cb6SAndy Yan 		memcpy(buf, &val, bytes);
415c1cd6cb6SAndy Yan 	}
416c1cd6cb6SAndy Yan 
417c1cd6cb6SAndy Yan 	return 0;
418c1cd6cb6SAndy Yan }
419c1cd6cb6SAndy Yan 
42030f161d1SAndy Yan static int rockchip_sfc_pio_xfer(struct rockchip_sfc *sfc, void *buf, u32 len)
421c1cd6cb6SAndy Yan {
422c1cd6cb6SAndy Yan 	int ret = 0;
423c1cd6cb6SAndy Yan 
424da4954b7SAndy Yan 	rockchip_sfc_setup_xfer(sfc, len);
42530f161d1SAndy Yan 
426c1cd6cb6SAndy Yan 	if (len) {
427da4954b7SAndy Yan 		if (sfc->rw == SFC_WR)
42830f161d1SAndy Yan 			ret = rockchip_sfc_write_fifo(sfc, (u32 *)buf, len);
429c1cd6cb6SAndy Yan 		else
43030f161d1SAndy Yan 			ret = rockchip_sfc_read_fifo(sfc, (u32 *)buf, len);
431c1cd6cb6SAndy Yan 	}
432c1cd6cb6SAndy Yan 
433c1cd6cb6SAndy Yan 	return ret;
434c1cd6cb6SAndy Yan }
435c1cd6cb6SAndy Yan 
43630f161d1SAndy Yan static int rockchip_sfc_read(struct rockchip_sfc *sfc, u32 offset,
43730f161d1SAndy Yan 			     void *buf, size_t len)
438c1cd6cb6SAndy Yan {
4396bf64646SAndy Yan 	u32 dma_trans;
44030f161d1SAndy Yan 	u32 trb;
44130f161d1SAndy Yan 	u8 bytes;
44230f161d1SAndy Yan 	int ret;
443c1cd6cb6SAndy Yan 
44437911cf6SAndy Yan 	if (len >= ARCH_DMA_MINALIGN) {
44530f161d1SAndy Yan 		bytes = len & (ARCH_DMA_MINALIGN - 1);
4466bf64646SAndy Yan 		dma_trans = len - bytes;
4476bf64646SAndy Yan 	} else {
4486bf64646SAndy Yan 		dma_trans = 0;
4496bf64646SAndy Yan 		bytes = len;
4506bf64646SAndy Yan 	}
4516bf64646SAndy Yan 
45230f161d1SAndy Yan 	while (dma_trans) {
45330f161d1SAndy Yan 		trb = min_t(size_t, dma_trans, SFC_MAX_TRB);
45430f161d1SAndy Yan 		ret = rockchip_sfc_dma_xfer(sfc, buf, trb);
45530f161d1SAndy Yan 		if (ret < 0)
45630f161d1SAndy Yan 			return ret;
45730f161d1SAndy Yan 		dma_trans -= trb;
45830f161d1SAndy Yan 		sfc->addr += trb;
45930f161d1SAndy Yan 		buf += trb;
4606bf64646SAndy Yan 	}
4616bf64646SAndy Yan 
4626bf64646SAndy Yan 	/*
46330f161d1SAndy Yan 	 * transfer the last non dma anligned byte by pio mode
4646bf64646SAndy Yan 	 */
46530f161d1SAndy Yan 	if (bytes)
4666bf64646SAndy Yan 		ret = rockchip_sfc_pio_xfer(sfc, buf, bytes);
467c1cd6cb6SAndy Yan 
46830f161d1SAndy Yan 	return 0;
46930f161d1SAndy Yan }
47030f161d1SAndy Yan 
47130f161d1SAndy Yan static int rockchip_sfc_write(struct rockchip_sfc *sfc, u32 offset,
47230f161d1SAndy Yan 			      void *buf, size_t len)
47330f161d1SAndy Yan {
47430f161d1SAndy Yan 	if (len > SFC_MAX_TRB) {
47530f161d1SAndy Yan 		printf("out of the max sfc trb");
47630f161d1SAndy Yan 		return -EINVAL;
47730f161d1SAndy Yan 	}
47830f161d1SAndy Yan 
47930f161d1SAndy Yan 	if (len && !(len & (ARCH_DMA_MINALIGN - 1)))
48030f161d1SAndy Yan 		return rockchip_sfc_dma_xfer(sfc, buf, len);
48130f161d1SAndy Yan 	else
48230f161d1SAndy Yan 		return rockchip_sfc_pio_xfer(sfc, buf, len);
48330f161d1SAndy Yan 
48430f161d1SAndy Yan 	return 0;
48530f161d1SAndy Yan }
48630f161d1SAndy Yan 
48730f161d1SAndy Yan static int rockchip_sfc_do_xfer(struct rockchip_sfc *sfc, void *buf, size_t len)
48830f161d1SAndy Yan {
48930f161d1SAndy Yan 	if (sfc->rw)
49030f161d1SAndy Yan 		return rockchip_sfc_write(sfc, sfc->addr, buf, len);
49130f161d1SAndy Yan 	else
49230f161d1SAndy Yan 		return rockchip_sfc_read(sfc, sfc->addr, buf, len);
493c1cd6cb6SAndy Yan }
494c1cd6cb6SAndy Yan 
495c1cd6cb6SAndy Yan static int rockchip_sfc_xfer(struct udevice *dev, unsigned int bitlen,
496c1cd6cb6SAndy Yan 			     const void *dout, void *din, unsigned long flags)
497c1cd6cb6SAndy Yan {
498c1cd6cb6SAndy Yan 	struct udevice *bus = dev->parent;
499c1cd6cb6SAndy Yan 	struct rockchip_sfc *sfc = dev_get_priv(bus);
500c1cd6cb6SAndy Yan 	int len = bitlen >> 3;
501c1cd6cb6SAndy Yan 	u8 *pcmd = (u8 *)dout;
50230f161d1SAndy Yan 	void *data_buf;
503c1cd6cb6SAndy Yan 	int ret = 0;
504c1cd6cb6SAndy Yan 
505c1cd6cb6SAndy Yan 	if (flags & SPI_XFER_BEGIN) {
506c1cd6cb6SAndy Yan 		sfc->cmd = pcmd[0];
5076e121371SJon Lin 		switch (len) {
5086e121371SJon Lin 		case 6: /* Nor >16MB 0x6b dummy op */
5096e121371SJon Lin 			sfc->addr_bits = SFC_ADDR_32BITS;
5106e121371SJon Lin 			sfc->dummy_bits = 8;
5116e121371SJon Lin 			sfc->addr = pcmd[4] | (pcmd[3] << 8) | (pcmd[2] << 16) | (pcmd[1] << 24);
5126e121371SJon Lin 			break;
5136e121371SJon Lin 		case 5: /* Nor <=16MB 0x6b dummy op, Nor >16MB no dummy op */
51498730755SJon Lin 			if (sfc->cmd == 0x6b) {
51598730755SJon Lin 				sfc->addr_bits = SFC_ADDR_24BITS;
51698730755SJon Lin 				sfc->dummy_bits = 8;
51798730755SJon Lin 				sfc->addr = pcmd[3] | (pcmd[2] << 8) | (pcmd[1] << 16);
51898730755SJon Lin 			} else {
5196e121371SJon Lin 				sfc->addr_bits = SFC_ADDR_32BITS;
5206e121371SJon Lin 				sfc->dummy_bits = 0;
5216e121371SJon Lin 				sfc->addr = pcmd[4] | (pcmd[3] << 8) | (pcmd[2] << 16) | (pcmd[1] << 24);
52298730755SJon Lin 			}
5236e121371SJon Lin 			break;
5246e121371SJon Lin 		case 4: /* Nand erase and read, Nor <=16MB no dummy op */
5256e121371SJon Lin 			sfc->addr_bits = SFC_ADDR_24BITS;
5266e121371SJon Lin 			sfc->dummy_bits = 0;
527c1cd6cb6SAndy Yan 			sfc->addr = pcmd[3] | (pcmd[2] << 8) | (pcmd[1] << 16);
5286e121371SJon Lin 			break;
5296e121371SJon Lin 		case 3: /* Nand prog,  */
5306e121371SJon Lin 			sfc->addr_bits = SFC_ADDR_XBITS;
53188ea3acbSJon Lin 			sfc->addr_xbits_ext = 16;
53239b850deSJon Lin 			sfc->dummy_bits = 0;
53339b850deSJon Lin 			sfc->addr = pcmd[2] | pcmd[1] << 8;
5346e121371SJon Lin 			break;
5356e121371SJon Lin 		case 2: /* Nand read/write feature */
5366e121371SJon Lin 			sfc->addr_bits = SFC_ADDR_XBITS;
53788ea3acbSJon Lin 			sfc->addr_xbits_ext = 8;
53839b850deSJon Lin 			sfc->dummy_bits = 0;
53939b850deSJon Lin 			sfc->addr = pcmd[1];
5406e121371SJon Lin 			break;
5416e121371SJon Lin 		default: /* Nand/Nor Read/Write status */
5426e121371SJon Lin 			sfc->addr_bits = SFC_ADDR_0BITS;
543da4954b7SAndy Yan 			sfc->dummy_bits = 0;
544da4954b7SAndy Yan 			sfc->addr = 0;
5456e121371SJon Lin 			break;
546c1cd6cb6SAndy Yan 		}
5476e121371SJon Lin 		SFC_DBG("%s %d %x %d %d %x\n", __func__, len, sfc->cmd, sfc->addr_bits,
5486e121371SJon Lin 			sfc->dummy_bits, sfc->addr);
549c1cd6cb6SAndy Yan 	}
550c1cd6cb6SAndy Yan 	if (flags & SPI_XFER_END) {
551da4954b7SAndy Yan 		if (din) {
552da4954b7SAndy Yan 			sfc->rw = SFC_RD;
55330f161d1SAndy Yan 			data_buf = din;
55430f161d1SAndy Yan 		} else {
555da4954b7SAndy Yan 			sfc->rw = SFC_WR;
55630f161d1SAndy Yan 			data_buf = (void *)dout;
557c1cd6cb6SAndy Yan 		}
55830f161d1SAndy Yan 
55930f161d1SAndy Yan 		if (flags == (SPI_XFER_BEGIN | SPI_XFER_END)) {
56030f161d1SAndy Yan 			len = 0;
56130f161d1SAndy Yan 			data_buf = NULL;
56230f161d1SAndy Yan 		}
56330f161d1SAndy Yan 
56430f161d1SAndy Yan 		ret = rockchip_sfc_do_xfer(sfc, data_buf, len);
565da4954b7SAndy Yan 	}
566c1cd6cb6SAndy Yan 
567c1cd6cb6SAndy Yan 	return ret;
568c1cd6cb6SAndy Yan }
569c1cd6cb6SAndy Yan 
570c1cd6cb6SAndy Yan static int rockchip_sfc_set_speed(struct udevice *bus, uint speed)
571c1cd6cb6SAndy Yan {
572c1cd6cb6SAndy Yan 	struct rockchip_sfc *sfc = dev_get_priv(bus);
573c1cd6cb6SAndy Yan 
574c1cd6cb6SAndy Yan 	if (speed > sfc->max_freq)
575c1cd6cb6SAndy Yan 		speed = sfc->max_freq;
576c1cd6cb6SAndy Yan 
577c1cd6cb6SAndy Yan 	sfc->speed_hz = speed;
578ae52cbcbSJon Lin 	clk_set_rate(&sfc->clk, sfc->speed_hz);
579ae52cbcbSJon Lin 	SFC_DBG("%s clk= %ld\n", __func__, clk_get_rate(&sfc->clk));
580c1cd6cb6SAndy Yan 
581c1cd6cb6SAndy Yan 	return 0;
582c1cd6cb6SAndy Yan }
583c1cd6cb6SAndy Yan 
584c1cd6cb6SAndy Yan static int rockchip_sfc_set_mode(struct udevice *bus, uint mode)
585c1cd6cb6SAndy Yan {
586c1cd6cb6SAndy Yan 	struct rockchip_sfc *sfc = dev_get_priv(bus);
587c1cd6cb6SAndy Yan 
588c1cd6cb6SAndy Yan 	sfc->mode = mode;
589c1cd6cb6SAndy Yan 
590c1cd6cb6SAndy Yan 	return 0;
591c1cd6cb6SAndy Yan }
592c1cd6cb6SAndy Yan 
593c1cd6cb6SAndy Yan static const struct dm_spi_ops rockchip_sfc_ops = {
594c1cd6cb6SAndy Yan 	.xfer		= rockchip_sfc_xfer,
595c1cd6cb6SAndy Yan 	.set_speed	= rockchip_sfc_set_speed,
596c1cd6cb6SAndy Yan 	.set_mode	= rockchip_sfc_set_mode,
597c1cd6cb6SAndy Yan };
598c1cd6cb6SAndy Yan 
599c1cd6cb6SAndy Yan static const struct udevice_id rockchip_sfc_ids[] = {
600c1cd6cb6SAndy Yan 	{ .compatible = "rockchip,sfc" },
601c1cd6cb6SAndy Yan 	{ }
602c1cd6cb6SAndy Yan };
603c1cd6cb6SAndy Yan 
604c1cd6cb6SAndy Yan U_BOOT_DRIVER(rockchip_sfc_driver) = {
605c1cd6cb6SAndy Yan 	.name	= "rockchip_sfc",
606c1cd6cb6SAndy Yan 	.id	= UCLASS_SPI,
607c1cd6cb6SAndy Yan 	.of_match = rockchip_sfc_ids,
608c1cd6cb6SAndy Yan 	.ops	= &rockchip_sfc_ops,
609c1cd6cb6SAndy Yan 	.ofdata_to_platdata = rockchip_sfc_ofdata_to_platdata,
610c1cd6cb6SAndy Yan 	.platdata_auto_alloc_size = sizeof(struct rockchip_sfc_platdata),
611c1cd6cb6SAndy Yan 	.priv_auto_alloc_size = sizeof(struct rockchip_sfc),
612c1cd6cb6SAndy Yan 	.probe	= rockchip_sfc_probe,
613c1cd6cb6SAndy Yan };
614