xref: /rk3399_rockchip-uboot/drivers/spi/rockchip_sfc.c (revision fa413375b735f8ebe3c793c8c145d679fad8d635)
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;
43*fa413375SJon Lin 	u32 ver;
44*fa413375SJon Lin 	u32 reserved[20];
45c6d59f03SAndy Yan 	u32 dmatr;
46c6d59f03SAndy Yan 	u32 dmaaddr;
47*fa413375SJon Lin 	u32 len_ctrl;
48*fa413375SJon Lin 	u32 len_ext;
49*fa413375SJon Lin 	u32 reserved1[28];
50c6d59f03SAndy Yan 	u32 cmd;
51c6d59f03SAndy Yan 	u32 addr;
52c6d59f03SAndy Yan 	u32 data;
53c6d59f03SAndy Yan };
5439b850deSJon Lin 
55c6d59f03SAndy Yan check_member(rockchip_sfc_reg, data, 0x108);
56c6d59f03SAndy Yan 
57c6d59f03SAndy Yan /*SFC_CTRL*/
58c6d59f03SAndy Yan #define SFC_DATA_WIDTH_SHIFT	12
59c6d59f03SAndy Yan #define SFC_DATA_WIDTH_MASK	GENMASK(13, 12)
60c6d59f03SAndy Yan #define SFC_ADDR_WIDTH_SHIFT	10
61c6d59f03SAndy Yan #define SFC_ADDR_WIDTH_MASK	GENMASK(11, 10)
62c6d59f03SAndy Yan #define SFC_CMD_WIDTH_SHIFT	8
63c6d59f03SAndy Yan #define SFC_CMD_WIDTH_MASK	GENMASK(9, 8)
64c6d59f03SAndy Yan #define SFC_DATA_SHIFT_NEGETIVE	BIT(1)
65c6d59f03SAndy Yan 
66c6d59f03SAndy Yan /*SFC_CMD*/
67c6d59f03SAndy Yan #define SFC_DUMMY_BITS_SHIFT	8
68c6d59f03SAndy Yan #define SFC_RW_SHIFT		12
69c6d59f03SAndy Yan #define SFC_WR			1
70c6d59f03SAndy Yan #define SFC_RD			0
71c6d59f03SAndy Yan #define SFC_ADDR_BITS_SHIFT	14
72c6d59f03SAndy Yan #define SFC_ADDR_BITS_MASK	GENMASK(15, 14)
73c6d59f03SAndy Yan #define SFC_ADDR_0BITS		0
74c6d59f03SAndy Yan #define SFC_ADDR_24BITS		1
75c6d59f03SAndy Yan #define SFC_ADDR_32BITS		2
76c6d59f03SAndy Yan #define SFC_ADDR_XBITS		3
77c6d59f03SAndy Yan #define SFC_TRB_SHIFT		(16)
78c6d59f03SAndy Yan #define SFC_TRB_MASK		GENMASK(29, 16)
79c6d59f03SAndy Yan 
80c6d59f03SAndy Yan /* Dma start trigger signal. Auto cleared after write */
81c6d59f03SAndy Yan #define SFC_DMA_START		BIT(0)
82c6d59f03SAndy Yan 
83c6d59f03SAndy Yan #define SFC_RESET		BIT(0)
84c6d59f03SAndy Yan 
85c6d59f03SAndy Yan /*SFC_FSR*/
86c6d59f03SAndy Yan #define SFC_RXLV_SHIFT		(16)
87c6d59f03SAndy Yan #define SFC_RXLV_MASK		GENMASK(20, 16)
88c6d59f03SAndy Yan #define SFC_TXLV_SHIFT		(8)
89c6d59f03SAndy Yan #define SFC_TXLV_MASK		GENMASK(12, 8)
90c6d59f03SAndy Yan #define SFC_RX_FULL		BIT(3)	/* rx fifo full */
91c6d59f03SAndy Yan #define SFC_RX_EMPTY		BIT(2)	/* rx fifo empty */
92c6d59f03SAndy Yan #define SFC_TX_EMPTY		BIT(1)	/* tx fifo empty */
93c6d59f03SAndy Yan #define SFC_TX_FULL		BIT(0)	/* tx fifo full */
94c6d59f03SAndy Yan 
95c6d59f03SAndy Yan #define SFC_BUSY		BIT(0)	/* sfc busy flag */
96c6d59f03SAndy Yan 
97c6d59f03SAndy Yan /*SFC_RISR*/
98c6d59f03SAndy Yan #define DMA_FINISH_INT		BIT(7)        /* dma interrupt */
99c6d59f03SAndy Yan #define SPI_ERR_INT		BIT(6)        /* Nspi error interrupt */
100c6d59f03SAndy Yan #define AHB_ERR_INT		BIT(5)        /* Ahb bus error interrupt */
101c6d59f03SAndy Yan #define TRANS_FINISH_INT	BIT(4)        /* Transfer finish interrupt */
102c6d59f03SAndy Yan #define TX_EMPTY_INT		BIT(3)        /* Tx fifo empty interrupt */
103c6d59f03SAndy Yan #define TX_OF_INT		BIT(2)        /* Tx fifo overflow interrupt */
104c6d59f03SAndy Yan #define RX_UF_INT		BIT(1)        /* Rx fifo underflow interrupt */
105c6d59f03SAndy Yan #define RX_FULL_INT		BIT(0)        /* Rx fifo full interrupt */
106c6d59f03SAndy Yan 
107*fa413375SJon Lin #define SFC_MAX_TRB_VER3	(512 * 31)
108*fa413375SJon Lin #define SFC_MAX_TRB_VER4	(0xFFFFFFFF)
109c6d59f03SAndy Yan 
110ae52cbcbSJon Lin #define SFC_MAX_RATE		(150 * 1000 * 1000)
111ae52cbcbSJon Lin #define SFC_DEFAULT_RATE	(80 * 1000 * 1000)
112ae52cbcbSJon Lin #define SFC_MIN_RATE		(10 * 1000 * 1000)
113ae52cbcbSJon Lin 
114*fa413375SJon Lin #define SFC_VER_3		0x3
115*fa413375SJon Lin #define SFC_VER_4		0x4
116*fa413375SJon Lin 
117c1cd6cb6SAndy Yan enum rockchip_sfc_if_type {
118c1cd6cb6SAndy Yan 	IF_TYPE_STD,
119c1cd6cb6SAndy Yan 	IF_TYPE_DUAL,
120c1cd6cb6SAndy Yan 	IF_TYPE_QUAD,
121c1cd6cb6SAndy Yan };
122c1cd6cb6SAndy Yan 
123c1cd6cb6SAndy Yan struct rockchip_sfc_platdata {
124c1cd6cb6SAndy Yan 	s32 frequency;
12514b86dc9SJon Lin 	void *base;
126c1cd6cb6SAndy Yan };
127c1cd6cb6SAndy Yan 
128c1cd6cb6SAndy Yan struct rockchip_sfc {
129c1cd6cb6SAndy Yan 	struct rockchip_sfc_reg *regbase;
130c1cd6cb6SAndy Yan 	struct clk clk;
131c1cd6cb6SAndy Yan 	unsigned int max_freq;
132c1cd6cb6SAndy Yan 	unsigned int mode;
133c1cd6cb6SAndy Yan 	unsigned int speed_hz;
134*fa413375SJon Lin 	u32 max_iosize;
135c1cd6cb6SAndy Yan 	u32 cmd;
136c1cd6cb6SAndy Yan 	u32 addr;
137da4954b7SAndy Yan 	u8 addr_bits;
13888ea3acbSJon Lin 	u8 addr_xbits_ext;
139da4954b7SAndy Yan 	u8 dummy_bits;
140da4954b7SAndy Yan 	u8 rw;
141da4954b7SAndy Yan 	u32 trb;
142c1cd6cb6SAndy Yan };
143c1cd6cb6SAndy Yan 
144c1cd6cb6SAndy Yan static int rockchip_sfc_ofdata_to_platdata(struct udevice *bus)
145c1cd6cb6SAndy Yan {
146c1cd6cb6SAndy Yan 	struct rockchip_sfc_platdata *plat = dev_get_platdata(bus);
147c1cd6cb6SAndy Yan 	struct rockchip_sfc *sfc = dev_get_priv(bus);
148c1cd6cb6SAndy Yan 	int ret;
149c1cd6cb6SAndy Yan 
15014b86dc9SJon Lin 	plat->base = dev_read_addr_ptr(bus);
151c1cd6cb6SAndy Yan 	ret = clk_get_by_index(bus, 0, &sfc->clk);
152c1cd6cb6SAndy Yan 	if (ret < 0) {
15314b86dc9SJon Lin 		printf("Could not get clock for %s: %d\n", bus->name, ret);
154c1cd6cb6SAndy Yan 		return ret;
155c1cd6cb6SAndy Yan 	}
156c1cd6cb6SAndy Yan 
157c1cd6cb6SAndy Yan 	return 0;
158c1cd6cb6SAndy Yan }
159c1cd6cb6SAndy Yan 
160*fa413375SJon Lin u32 rockchip_sfc_get_version(struct rockchip_sfc *sfc)
161*fa413375SJon Lin {
162*fa413375SJon Lin 	struct rockchip_sfc_reg *regs = sfc->regbase;
163*fa413375SJon Lin 
164*fa413375SJon Lin 	return  (u32)(readl(&regs->ver) & 0xFFFF);
165*fa413375SJon Lin }
166*fa413375SJon Lin 
167c1cd6cb6SAndy Yan static int rockchip_sfc_probe(struct udevice *bus)
168c1cd6cb6SAndy Yan {
169c1cd6cb6SAndy Yan 	struct rockchip_sfc_platdata *plat = dev_get_platdata(bus);
170c1cd6cb6SAndy Yan 	struct rockchip_sfc *sfc = dev_get_priv(bus);
171*fa413375SJon Lin 	struct rockchip_sfc_reg *regs;
172ae52cbcbSJon Lin 	struct dm_spi_bus *dm_spi_bus;
173c1cd6cb6SAndy Yan 
174ae52cbcbSJon Lin 	dm_spi_bus = bus->uclass_priv;
175ae52cbcbSJon Lin 	dm_spi_bus->max_hz = plat->frequency;
176c1cd6cb6SAndy Yan 	sfc->regbase = (struct rockchip_sfc_reg *)plat->base;
17731e5d7a3SJon Lin 	sfc->max_freq = SFC_MAX_RATE;
17831e5d7a3SJon Lin 	sfc->speed_hz = SFC_DEFAULT_RATE;
17931e5d7a3SJon Lin 	clk_set_rate(&sfc->clk, sfc->speed_hz);
180c1cd6cb6SAndy Yan 
181*fa413375SJon Lin 	regs = sfc->regbase;
182*fa413375SJon Lin 	if (rockchip_sfc_get_version(sfc) >= SFC_VER_4) {
183*fa413375SJon Lin 		sfc->max_iosize = SFC_MAX_TRB_VER4;
184*fa413375SJon Lin 		writel(1, &regs->len_ctrl);
185*fa413375SJon Lin 	} else {
186*fa413375SJon Lin 		sfc->max_iosize = SFC_MAX_TRB_VER3;
187*fa413375SJon Lin 	}
188*fa413375SJon Lin 
189c1cd6cb6SAndy Yan 	return 0;
190c1cd6cb6SAndy Yan }
191c1cd6cb6SAndy Yan 
192c1cd6cb6SAndy Yan static int rockchip_sfc_reset(struct rockchip_sfc *sfc)
193c1cd6cb6SAndy Yan {
194c1cd6cb6SAndy Yan 	struct rockchip_sfc_reg *regs = sfc->regbase;
195c1cd6cb6SAndy Yan 	int tbase = get_timer(0);
196c1cd6cb6SAndy Yan 	u32 rcvr;
197c1cd6cb6SAndy Yan 	int ret = 0;
198c1cd6cb6SAndy Yan 
199c1cd6cb6SAndy Yan 	writel(SFC_RESET, &regs->rcvr);
200c1cd6cb6SAndy Yan 	do {
201c1cd6cb6SAndy Yan 		rcvr = readl(&regs->rcvr);
202c1cd6cb6SAndy Yan 		if (get_timer(tbase) > 1000) {
203c1cd6cb6SAndy Yan 			debug("sfc reset timeout\n");
204c1cd6cb6SAndy Yan 			ret =  -ETIMEDOUT;
205c1cd6cb6SAndy Yan 			break;
206c1cd6cb6SAndy Yan 		}
207c1cd6cb6SAndy Yan 		udelay(1);
208c1cd6cb6SAndy Yan 	} while (rcvr);
209c1cd6cb6SAndy Yan 
210c1cd6cb6SAndy Yan 	writel(0xFFFFFFFF, &regs->iclr);
211c1cd6cb6SAndy Yan 
212c1cd6cb6SAndy Yan 	debug("sfc reset\n");
213c1cd6cb6SAndy Yan 
214c1cd6cb6SAndy Yan 	return ret;
215c1cd6cb6SAndy Yan }
216c1cd6cb6SAndy Yan 
217915fcf0cSAndy Yan /* The SFC_CTRL register is a global control register,
218915fcf0cSAndy Yan  * when the controller is in busy state(SFC_SR),
219915fcf0cSAndy Yan  * SFC_CTRL cannot be set.
220915fcf0cSAndy Yan  */
221915fcf0cSAndy Yan static int rockchip_sfc_wait_idle(struct rockchip_sfc *sfc,
222915fcf0cSAndy Yan 				  u32 timeout_ms)
223915fcf0cSAndy Yan {
224915fcf0cSAndy Yan 	struct rockchip_sfc_reg *regs = sfc->regbase;
225915fcf0cSAndy Yan 	unsigned long tbase = get_timer(0);
226915fcf0cSAndy Yan 	u32 sr, fsr;
227915fcf0cSAndy Yan 
228915fcf0cSAndy Yan 	while (1) {
229915fcf0cSAndy Yan 		sr = readl(&regs->sr);
230915fcf0cSAndy Yan 		fsr = readl(&regs->fsr);
23139b850deSJon Lin 		if ((fsr & SFC_TX_EMPTY) &&
23239b850deSJon Lin 		    (fsr & SFC_RX_EMPTY) &&
23339b850deSJon Lin 		    !(sr & SFC_BUSY))
234915fcf0cSAndy Yan 			break;
235915fcf0cSAndy Yan 		if (get_timer(tbase) > timeout_ms) {
236915fcf0cSAndy Yan 			printf("waite sfc idle timeout(sr:0x%08x fsr:0x%08x)\n",
237915fcf0cSAndy Yan 			       sr, fsr);
238915fcf0cSAndy Yan 			rockchip_sfc_reset(sfc);
239915fcf0cSAndy Yan 			return -ETIMEDOUT;
240915fcf0cSAndy Yan 		}
241915fcf0cSAndy Yan 		udelay(100);
242915fcf0cSAndy Yan 	}
243915fcf0cSAndy Yan 
244915fcf0cSAndy Yan 	return 0;
245915fcf0cSAndy Yan }
246915fcf0cSAndy Yan 
247c1cd6cb6SAndy Yan static u8 rockchip_sfc_get_if_type(struct rockchip_sfc *sfc)
248c1cd6cb6SAndy Yan {
249c1cd6cb6SAndy Yan 	int type = IF_TYPE_STD;
250c1cd6cb6SAndy Yan 
251da4954b7SAndy Yan 	if (sfc->rw == SFC_WR) {
252c1cd6cb6SAndy Yan 		if (sfc->mode & SPI_TX_QUAD)
253c1cd6cb6SAndy Yan 			type = IF_TYPE_QUAD;
254c1cd6cb6SAndy Yan 		else if (sfc->mode & SPI_TX_DUAL)
255c1cd6cb6SAndy Yan 			type = IF_TYPE_DUAL;
256c1cd6cb6SAndy Yan 		else
257c1cd6cb6SAndy Yan 			type = IF_TYPE_STD;
258c1cd6cb6SAndy Yan 	} else {
259c1cd6cb6SAndy Yan 		if (sfc->mode & SPI_RX_QUAD)
260c1cd6cb6SAndy Yan 			type = IF_TYPE_QUAD;
261c1cd6cb6SAndy Yan 		else if (sfc->mode & SPI_RX_DUAL)
262c1cd6cb6SAndy Yan 			type = IF_TYPE_DUAL;
263c1cd6cb6SAndy Yan 		else
264c1cd6cb6SAndy Yan 			type = IF_TYPE_STD;
265c1cd6cb6SAndy Yan 	}
266c1cd6cb6SAndy Yan 
267c1cd6cb6SAndy Yan 	return type;
268c1cd6cb6SAndy Yan }
269c1cd6cb6SAndy Yan 
270da4954b7SAndy Yan static void rockchip_sfc_setup_xfer(struct rockchip_sfc *sfc, u32 trb)
271c1cd6cb6SAndy Yan {
272c1cd6cb6SAndy Yan 	struct rockchip_sfc_reg *regs = sfc->regbase;
273*fa413375SJon Lin 	u32 val;
274c1cd6cb6SAndy Yan 	u8 data_width = IF_TYPE_STD;
275c1cd6cb6SAndy Yan 
276*fa413375SJon Lin 	rockchip_sfc_wait_idle(sfc, 10);
27739b850deSJon Lin 
27839b850deSJon Lin 	if (sfc->addr_bits == SFC_ADDR_24BITS ||
27939b850deSJon Lin 	    sfc->addr_bits == SFC_ADDR_32BITS)
280c1cd6cb6SAndy Yan 		data_width = rockchip_sfc_get_if_type(sfc);
281c1cd6cb6SAndy Yan 
282*fa413375SJon Lin 	SFC_DBG("--- sfc.addr_bit %x\n", sfc->addr_bits);
283113ced8fSJon Lin 	if (sfc->addr_bits == SFC_ADDR_XBITS)
28488ea3acbSJon Lin 		writel(sfc->addr_xbits_ext - 1, &regs->abit);
28588ea3acbSJon Lin 
286*fa413375SJon Lin 	if (rockchip_sfc_get_version(sfc) >= SFC_VER_4) {
287*fa413375SJon Lin 		SFC_DBG("--- sfc.len_ext %x\n", trb);
288*fa413375SJon Lin 		writel(trb, &regs->len_ext);
289*fa413375SJon Lin 	}
290c1cd6cb6SAndy Yan 
291*fa413375SJon Lin 	val = 0x02;
292*fa413375SJon Lin 	val |= (data_width << SFC_DATA_WIDTH_SHIFT);
293915fcf0cSAndy Yan 
29439b850deSJon Lin 	SFC_DBG("--- sfc.ctrl %x\n", val);
295c1cd6cb6SAndy Yan 	writel(val, &regs->ctrl);
296da4954b7SAndy Yan 
297da4954b7SAndy Yan 	val = sfc->cmd;
298*fa413375SJon Lin 	val |= (trb & 0x3fff) << SFC_TRB_SHIFT;
299da4954b7SAndy Yan 	val |= sfc->rw << SFC_RW_SHIFT;
300da4954b7SAndy Yan 	val |= sfc->addr_bits << SFC_ADDR_BITS_SHIFT;
301da4954b7SAndy Yan 	val |= sfc->dummy_bits << SFC_DUMMY_BITS_SHIFT;
302da4954b7SAndy Yan 
30339b850deSJon Lin 	SFC_DBG("--- sfc.cmd %x\n", val);
304da4954b7SAndy Yan 	writel(val, &regs->cmd);
305da4954b7SAndy Yan 
30639b850deSJon Lin 	if (sfc->addr_bits & SFC_ADDR_XBITS) {
30739b850deSJon Lin 		SFC_DBG("--- sfc.addr %x\n", sfc->addr);
308c1cd6cb6SAndy Yan 		writel(sfc->addr, &regs->addr);
309c1cd6cb6SAndy Yan 	}
31039b850deSJon Lin }
311c1cd6cb6SAndy Yan 
312*fa413375SJon Lin static int rockchip_sfc_dma_xfer(struct rockchip_sfc *sfc, void *buffer,
313*fa413375SJon Lin 				 size_t trb)
314c1cd6cb6SAndy Yan {
315c1cd6cb6SAndy Yan 	struct rockchip_sfc_reg *regs = sfc->regbase;
31637911cf6SAndy Yan 	struct bounce_buffer bb;
31737911cf6SAndy Yan 	unsigned int bb_flags;
318*fa413375SJon Lin 	int timeout = trb * 1000;
319c1cd6cb6SAndy Yan 	int ret = 0;
320c1cd6cb6SAndy Yan 	int risr;
321c1cd6cb6SAndy Yan 	unsigned long tbase;
322c1cd6cb6SAndy Yan 
32337911cf6SAndy Yan 	if (sfc->rw == SFC_WR)
32437911cf6SAndy Yan 		bb_flags = GEN_BB_READ;
32537911cf6SAndy Yan 	else
32637911cf6SAndy Yan 		bb_flags = GEN_BB_WRITE;
32737911cf6SAndy Yan 
32830f161d1SAndy Yan 	ret = bounce_buffer_start(&bb, buffer, trb, bb_flags);
32937911cf6SAndy Yan 	if (ret)
33037911cf6SAndy Yan 		return ret;
33130f161d1SAndy Yan 
33237911cf6SAndy Yan 	rockchip_sfc_setup_xfer(sfc, bb.len_aligned);
333c1cd6cb6SAndy Yan 
334c1cd6cb6SAndy Yan 	writel(0xFFFFFFFF, &regs->iclr);
33514b86dc9SJon Lin 	writel((unsigned long)bb.bounce_buffer, &regs->dmaaddr);
336c1cd6cb6SAndy Yan 	writel(SFC_DMA_START, &regs->dmatr);
337c1cd6cb6SAndy Yan 
338c1cd6cb6SAndy Yan 	tbase = get_timer(0);
339c1cd6cb6SAndy Yan 	do {
340c1cd6cb6SAndy Yan 		udelay(1);
341c1cd6cb6SAndy Yan 		risr = readl(&regs->risr);
342c1cd6cb6SAndy Yan 		if (get_timer(tbase) > timeout) {
343c1cd6cb6SAndy Yan 			debug("dma timeout\n");
344c1cd6cb6SAndy Yan 			ret = -ETIMEDOUT;
345c1cd6cb6SAndy Yan 			break;
346c1cd6cb6SAndy Yan 		}
347c1cd6cb6SAndy Yan 	} while (!(risr & TRANS_FINISH_INT));
348c1cd6cb6SAndy Yan 
349c1cd6cb6SAndy Yan 	writel(0xFFFFFFFF, &regs->iclr);
350c1cd6cb6SAndy Yan 
35137911cf6SAndy Yan 	bounce_buffer_stop(&bb);
35237911cf6SAndy Yan 
353c1cd6cb6SAndy Yan 	return ret;
354c1cd6cb6SAndy Yan }
355c1cd6cb6SAndy Yan 
356da4954b7SAndy Yan static int rockchip_sfc_wait_fifo_ready(struct rockchip_sfc *sfc, int rw,
357c1cd6cb6SAndy Yan 					u32 timeout)
358c1cd6cb6SAndy Yan {
359c1cd6cb6SAndy Yan 	struct rockchip_sfc_reg *regs = sfc->regbase;
360c1cd6cb6SAndy Yan 	unsigned long tbase = get_timer(0);
361c1cd6cb6SAndy Yan 	u8 level;
362c1cd6cb6SAndy Yan 	u32 fsr;
363c1cd6cb6SAndy Yan 
364c1cd6cb6SAndy Yan 	do {
365c1cd6cb6SAndy Yan 		fsr = readl(&regs->fsr);
366da4954b7SAndy Yan 		if (rw == SFC_WR)
367c1cd6cb6SAndy Yan 			level = (fsr & SFC_TXLV_MASK) >> SFC_TXLV_SHIFT;
368c1cd6cb6SAndy Yan 		else
369c1cd6cb6SAndy Yan 			level = (fsr & SFC_RXLV_MASK) >> SFC_RXLV_SHIFT;
370c1cd6cb6SAndy Yan 		if (get_timer(tbase) > timeout)
371c1cd6cb6SAndy Yan 			return -ETIMEDOUT;
372c1cd6cb6SAndy Yan 		udelay(1);
373c1cd6cb6SAndy Yan 	} while (!level);
374c1cd6cb6SAndy Yan 
375c1cd6cb6SAndy Yan 	return level;
376c1cd6cb6SAndy Yan }
377c1cd6cb6SAndy Yan 
378da4954b7SAndy Yan static int rockchip_sfc_write_fifo(struct rockchip_sfc *sfc, u32 *buf, u32 len)
379c1cd6cb6SAndy Yan {
380c1cd6cb6SAndy Yan 	struct rockchip_sfc_reg *regs = sfc->regbase;
381c1cd6cb6SAndy Yan 	u32 bytes = len & 0x3;
382c1cd6cb6SAndy Yan 	u32 words = len >> 2;
383915fcf0cSAndy Yan 	int tx_level = 0;
384c1cd6cb6SAndy Yan 	u32 val = 0;
385c1cd6cb6SAndy Yan 	u8 count;
386c1cd6cb6SAndy Yan 
387c1cd6cb6SAndy Yan 	while (words) {
388da4954b7SAndy Yan 		tx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_WR, 1000);
389c1cd6cb6SAndy Yan 		if (tx_level <= 0)
390c1cd6cb6SAndy Yan 			return tx_level;
391915fcf0cSAndy Yan 		count = min(words, (u32)tx_level);
392c1cd6cb6SAndy Yan 		writesl(&regs->data, buf, count);
393c1cd6cb6SAndy Yan 		buf += count;
394c1cd6cb6SAndy Yan 		words -= count;
395c1cd6cb6SAndy Yan 	}
396c1cd6cb6SAndy Yan 
397da4954b7SAndy Yan 	/* handle the last non 4byte aligned bytes */
398c1cd6cb6SAndy Yan 	if (bytes) {
399da4954b7SAndy Yan 		tx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_WR, 1000);
400c1cd6cb6SAndy Yan 		if (tx_level <= 0)
401c1cd6cb6SAndy Yan 			return tx_level;
402c1cd6cb6SAndy Yan 		memcpy(&val, buf, bytes);
403c1cd6cb6SAndy Yan 		writel(val, &regs->data);
404c1cd6cb6SAndy Yan 	}
405c1cd6cb6SAndy Yan 
406c1cd6cb6SAndy Yan 	return 0;
407c1cd6cb6SAndy Yan }
408c1cd6cb6SAndy Yan 
409da4954b7SAndy Yan static int rockchip_sfc_read_fifo(struct rockchip_sfc *sfc, u32 *buf, u32 len)
410c1cd6cb6SAndy Yan {
411c1cd6cb6SAndy Yan 	struct rockchip_sfc_reg *regs = sfc->regbase;
412c1cd6cb6SAndy Yan 	u32 bytes = len & 0x3;
413c1cd6cb6SAndy Yan 	u32 words = len >> 2;
414915fcf0cSAndy Yan 	int rx_level = 0;
415c1cd6cb6SAndy Yan 	u32 count;
416c1cd6cb6SAndy Yan 	u32 val;
417c1cd6cb6SAndy Yan 
418c1cd6cb6SAndy Yan 	while (words) {
419da4954b7SAndy Yan 		rx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_RD, 1000);
420c1cd6cb6SAndy Yan 		if (rx_level <= 0)
421c1cd6cb6SAndy Yan 			return rx_level;
422915fcf0cSAndy Yan 		count = min(words, (u32)rx_level);
423c1cd6cb6SAndy Yan 		readsl(&regs->data, buf, count);
424c1cd6cb6SAndy Yan 		buf += count;
425c1cd6cb6SAndy Yan 		words -= count;
426c1cd6cb6SAndy Yan 	}
427c1cd6cb6SAndy Yan 
428da4954b7SAndy Yan 	/* handle the last non 4 bytes aligned bytes */
429c1cd6cb6SAndy Yan 	if (bytes) {
430da4954b7SAndy Yan 		rx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_RD, 1000);
431c1cd6cb6SAndy Yan 		if (rx_level <= 0)
432c1cd6cb6SAndy Yan 			return rx_level;
433c1cd6cb6SAndy Yan 		val = readl(&regs->data);
434c1cd6cb6SAndy Yan 		memcpy(buf, &val, bytes);
435c1cd6cb6SAndy Yan 	}
436c1cd6cb6SAndy Yan 
437c1cd6cb6SAndy Yan 	return 0;
438c1cd6cb6SAndy Yan }
439c1cd6cb6SAndy Yan 
44030f161d1SAndy Yan static int rockchip_sfc_pio_xfer(struct rockchip_sfc *sfc, void *buf, u32 len)
441c1cd6cb6SAndy Yan {
442c1cd6cb6SAndy Yan 	int ret = 0;
443c1cd6cb6SAndy Yan 
444da4954b7SAndy Yan 	rockchip_sfc_setup_xfer(sfc, len);
44530f161d1SAndy Yan 
446c1cd6cb6SAndy Yan 	if (len) {
447da4954b7SAndy Yan 		if (sfc->rw == SFC_WR)
44830f161d1SAndy Yan 			ret = rockchip_sfc_write_fifo(sfc, (u32 *)buf, len);
449c1cd6cb6SAndy Yan 		else
45030f161d1SAndy Yan 			ret = rockchip_sfc_read_fifo(sfc, (u32 *)buf, len);
451c1cd6cb6SAndy Yan 	}
452c1cd6cb6SAndy Yan 
453c1cd6cb6SAndy Yan 	return ret;
454c1cd6cb6SAndy Yan }
455c1cd6cb6SAndy Yan 
45630f161d1SAndy Yan static int rockchip_sfc_read(struct rockchip_sfc *sfc, u32 offset,
45730f161d1SAndy Yan 			     void *buf, size_t len)
458c1cd6cb6SAndy Yan {
4596bf64646SAndy Yan 	u32 dma_trans;
46030f161d1SAndy Yan 	u32 trb;
46130f161d1SAndy Yan 	u8 bytes;
46230f161d1SAndy Yan 	int ret;
463c1cd6cb6SAndy Yan 
46437911cf6SAndy Yan 	if (len >= ARCH_DMA_MINALIGN) {
46530f161d1SAndy Yan 		bytes = len & (ARCH_DMA_MINALIGN - 1);
4666bf64646SAndy Yan 		dma_trans = len - bytes;
4676bf64646SAndy Yan 	} else {
4686bf64646SAndy Yan 		dma_trans = 0;
4696bf64646SAndy Yan 		bytes = len;
4706bf64646SAndy Yan 	}
4716bf64646SAndy Yan 
47230f161d1SAndy Yan 	while (dma_trans) {
473*fa413375SJon Lin 		trb = min_t(size_t, dma_trans, sfc->max_iosize);
47430f161d1SAndy Yan 		ret = rockchip_sfc_dma_xfer(sfc, buf, trb);
47530f161d1SAndy Yan 		if (ret < 0)
47630f161d1SAndy Yan 			return ret;
47730f161d1SAndy Yan 		dma_trans -= trb;
47830f161d1SAndy Yan 		sfc->addr += trb;
47930f161d1SAndy Yan 		buf += trb;
4806bf64646SAndy Yan 	}
4816bf64646SAndy Yan 
4826bf64646SAndy Yan 	/*
48330f161d1SAndy Yan 	 * transfer the last non dma anligned byte by pio mode
4846bf64646SAndy Yan 	 */
48530f161d1SAndy Yan 	if (bytes)
4866bf64646SAndy Yan 		ret = rockchip_sfc_pio_xfer(sfc, buf, bytes);
487c1cd6cb6SAndy Yan 
48830f161d1SAndy Yan 	return 0;
48930f161d1SAndy Yan }
49030f161d1SAndy Yan 
49130f161d1SAndy Yan static int rockchip_sfc_write(struct rockchip_sfc *sfc, u32 offset,
49230f161d1SAndy Yan 			      void *buf, size_t len)
49330f161d1SAndy Yan {
494*fa413375SJon Lin 	if (len > sfc->max_iosize) {
49530f161d1SAndy Yan 		printf("out of the max sfc trb");
49630f161d1SAndy Yan 		return -EINVAL;
49730f161d1SAndy Yan 	}
49830f161d1SAndy Yan 
49930f161d1SAndy Yan 	if (len && !(len & (ARCH_DMA_MINALIGN - 1)))
50030f161d1SAndy Yan 		return rockchip_sfc_dma_xfer(sfc, buf, len);
50130f161d1SAndy Yan 	else
50230f161d1SAndy Yan 		return rockchip_sfc_pio_xfer(sfc, buf, len);
50330f161d1SAndy Yan 
50430f161d1SAndy Yan 	return 0;
50530f161d1SAndy Yan }
50630f161d1SAndy Yan 
50730f161d1SAndy Yan static int rockchip_sfc_do_xfer(struct rockchip_sfc *sfc, void *buf, size_t len)
50830f161d1SAndy Yan {
50930f161d1SAndy Yan 	if (sfc->rw)
51030f161d1SAndy Yan 		return rockchip_sfc_write(sfc, sfc->addr, buf, len);
51130f161d1SAndy Yan 	else
51230f161d1SAndy Yan 		return rockchip_sfc_read(sfc, sfc->addr, buf, len);
513c1cd6cb6SAndy Yan }
514c1cd6cb6SAndy Yan 
515c1cd6cb6SAndy Yan static int rockchip_sfc_xfer(struct udevice *dev, unsigned int bitlen,
516c1cd6cb6SAndy Yan 			     const void *dout, void *din, unsigned long flags)
517c1cd6cb6SAndy Yan {
518c1cd6cb6SAndy Yan 	struct udevice *bus = dev->parent;
519c1cd6cb6SAndy Yan 	struct rockchip_sfc *sfc = dev_get_priv(bus);
520c1cd6cb6SAndy Yan 	int len = bitlen >> 3;
521c1cd6cb6SAndy Yan 	u8 *pcmd = (u8 *)dout;
52230f161d1SAndy Yan 	void *data_buf;
523c1cd6cb6SAndy Yan 	int ret = 0;
524c1cd6cb6SAndy Yan 
525c1cd6cb6SAndy Yan 	if (flags & SPI_XFER_BEGIN) {
526c1cd6cb6SAndy Yan 		sfc->cmd = pcmd[0];
5276e121371SJon Lin 		switch (len) {
5286e121371SJon Lin 		case 6: /* Nor >16MB 0x6b dummy op */
5296e121371SJon Lin 			sfc->addr_bits = SFC_ADDR_32BITS;
5306e121371SJon Lin 			sfc->dummy_bits = 8;
5316e121371SJon Lin 			sfc->addr = pcmd[4] | (pcmd[3] << 8) | (pcmd[2] << 16) | (pcmd[1] << 24);
5326e121371SJon Lin 			break;
5336e121371SJon Lin 		case 5: /* Nor <=16MB 0x6b dummy op, Nor >16MB no dummy op */
53498730755SJon Lin 			if (sfc->cmd == 0x6b) {
53598730755SJon Lin 				sfc->addr_bits = SFC_ADDR_24BITS;
53698730755SJon Lin 				sfc->dummy_bits = 8;
53798730755SJon Lin 				sfc->addr = pcmd[3] | (pcmd[2] << 8) | (pcmd[1] << 16);
53898730755SJon Lin 			} else {
5396e121371SJon Lin 				sfc->addr_bits = SFC_ADDR_32BITS;
5406e121371SJon Lin 				sfc->dummy_bits = 0;
5416e121371SJon Lin 				sfc->addr = pcmd[4] | (pcmd[3] << 8) | (pcmd[2] << 16) | (pcmd[1] << 24);
54298730755SJon Lin 			}
5436e121371SJon Lin 			break;
5446e121371SJon Lin 		case 4: /* Nand erase and read, Nor <=16MB no dummy op */
5456e121371SJon Lin 			sfc->addr_bits = SFC_ADDR_24BITS;
5466e121371SJon Lin 			sfc->dummy_bits = 0;
547c1cd6cb6SAndy Yan 			sfc->addr = pcmd[3] | (pcmd[2] << 8) | (pcmd[1] << 16);
5486e121371SJon Lin 			break;
5496e121371SJon Lin 		case 3: /* Nand prog,  */
5506e121371SJon Lin 			sfc->addr_bits = SFC_ADDR_XBITS;
55188ea3acbSJon Lin 			sfc->addr_xbits_ext = 16;
55239b850deSJon Lin 			sfc->dummy_bits = 0;
55339b850deSJon Lin 			sfc->addr = pcmd[2] | pcmd[1] << 8;
5546e121371SJon Lin 			break;
5556e121371SJon Lin 		case 2: /* Nand read/write feature */
5566e121371SJon Lin 			sfc->addr_bits = SFC_ADDR_XBITS;
55788ea3acbSJon Lin 			sfc->addr_xbits_ext = 8;
55839b850deSJon Lin 			sfc->dummy_bits = 0;
55939b850deSJon Lin 			sfc->addr = pcmd[1];
5606e121371SJon Lin 			break;
5616e121371SJon Lin 		default: /* Nand/Nor Read/Write status */
5626e121371SJon Lin 			sfc->addr_bits = SFC_ADDR_0BITS;
563da4954b7SAndy Yan 			sfc->dummy_bits = 0;
564da4954b7SAndy Yan 			sfc->addr = 0;
5656e121371SJon Lin 			break;
566c1cd6cb6SAndy Yan 		}
567*fa413375SJon Lin 		SFC_DBG("%s %d %x %d %d %x\n", __func__, len, sfc->cmd,
568*fa413375SJon Lin 			sfc->addr_bits, sfc->dummy_bits, sfc->addr);
569c1cd6cb6SAndy Yan 	}
570c1cd6cb6SAndy Yan 	if (flags & SPI_XFER_END) {
571da4954b7SAndy Yan 		if (din) {
572da4954b7SAndy Yan 			sfc->rw = SFC_RD;
57330f161d1SAndy Yan 			data_buf = din;
57430f161d1SAndy Yan 		} else {
575da4954b7SAndy Yan 			sfc->rw = SFC_WR;
57630f161d1SAndy Yan 			data_buf = (void *)dout;
577c1cd6cb6SAndy Yan 		}
57830f161d1SAndy Yan 
57930f161d1SAndy Yan 		if (flags == (SPI_XFER_BEGIN | SPI_XFER_END)) {
58030f161d1SAndy Yan 			len = 0;
58130f161d1SAndy Yan 			data_buf = NULL;
58230f161d1SAndy Yan 		}
58330f161d1SAndy Yan 
584cbd9216dSJon Lin 		if (sfc->cmd == 0x9f && len == 4) {
585cbd9216dSJon Lin 			/* SPI Nand read id */
586cbd9216dSJon Lin 			sfc->addr_bits = SFC_ADDR_XBITS;
587cbd9216dSJon Lin 			sfc->addr_xbits_ext = 8;
588cbd9216dSJon Lin 			sfc->dummy_bits = 0;
589cbd9216dSJon Lin 			sfc->addr = 0;
590cbd9216dSJon Lin 			((u8 *)data_buf)[0] = 0xff;
591cbd9216dSJon Lin 			ret = rockchip_sfc_do_xfer(sfc, &((u8 *)data_buf)[1], 3);
592cbd9216dSJon Lin 		} else {
59330f161d1SAndy Yan 			ret = rockchip_sfc_do_xfer(sfc, data_buf, len);
594da4954b7SAndy Yan 		}
595cbd9216dSJon Lin 	}
596c1cd6cb6SAndy Yan 
597c1cd6cb6SAndy Yan 	return ret;
598c1cd6cb6SAndy Yan }
599c1cd6cb6SAndy Yan 
600c1cd6cb6SAndy Yan static int rockchip_sfc_set_speed(struct udevice *bus, uint speed)
601c1cd6cb6SAndy Yan {
602c1cd6cb6SAndy Yan 	struct rockchip_sfc *sfc = dev_get_priv(bus);
603c1cd6cb6SAndy Yan 
604c1cd6cb6SAndy Yan 	if (speed > sfc->max_freq)
605c1cd6cb6SAndy Yan 		speed = sfc->max_freq;
606c1cd6cb6SAndy Yan 
607c1cd6cb6SAndy Yan 	sfc->speed_hz = speed;
608ae52cbcbSJon Lin 	clk_set_rate(&sfc->clk, sfc->speed_hz);
609ae52cbcbSJon Lin 	SFC_DBG("%s clk= %ld\n", __func__, clk_get_rate(&sfc->clk));
610c1cd6cb6SAndy Yan 
611c1cd6cb6SAndy Yan 	return 0;
612c1cd6cb6SAndy Yan }
613c1cd6cb6SAndy Yan 
614c1cd6cb6SAndy Yan static int rockchip_sfc_set_mode(struct udevice *bus, uint mode)
615c1cd6cb6SAndy Yan {
616c1cd6cb6SAndy Yan 	struct rockchip_sfc *sfc = dev_get_priv(bus);
617c1cd6cb6SAndy Yan 
618c1cd6cb6SAndy Yan 	sfc->mode = mode;
619c1cd6cb6SAndy Yan 
620c1cd6cb6SAndy Yan 	return 0;
621c1cd6cb6SAndy Yan }
622c1cd6cb6SAndy Yan 
623c1cd6cb6SAndy Yan static const struct dm_spi_ops rockchip_sfc_ops = {
624c1cd6cb6SAndy Yan 	.xfer		= rockchip_sfc_xfer,
625c1cd6cb6SAndy Yan 	.set_speed	= rockchip_sfc_set_speed,
626c1cd6cb6SAndy Yan 	.set_mode	= rockchip_sfc_set_mode,
627c1cd6cb6SAndy Yan };
628c1cd6cb6SAndy Yan 
629c1cd6cb6SAndy Yan static const struct udevice_id rockchip_sfc_ids[] = {
630c1cd6cb6SAndy Yan 	{ .compatible = "rockchip,sfc" },
631c1cd6cb6SAndy Yan 	{ }
632c1cd6cb6SAndy Yan };
633c1cd6cb6SAndy Yan 
634c1cd6cb6SAndy Yan U_BOOT_DRIVER(rockchip_sfc_driver) = {
635c1cd6cb6SAndy Yan 	.name	= "rockchip_sfc",
636c1cd6cb6SAndy Yan 	.id	= UCLASS_SPI,
637c1cd6cb6SAndy Yan 	.of_match = rockchip_sfc_ids,
638c1cd6cb6SAndy Yan 	.ops	= &rockchip_sfc_ops,
639c1cd6cb6SAndy Yan 	.ofdata_to_platdata = rockchip_sfc_ofdata_to_platdata,
640c1cd6cb6SAndy Yan 	.platdata_auto_alloc_size = sizeof(struct rockchip_sfc_platdata),
641c1cd6cb6SAndy Yan 	.priv_auto_alloc_size = sizeof(struct rockchip_sfc),
642c1cd6cb6SAndy Yan 	.probe	= rockchip_sfc_probe,
643c1cd6cb6SAndy Yan };
644