xref: /rk3399_rockchip-uboot/drivers/spi/rockchip_sfc.c (revision 6bf6464692c7c2969bc3dbeb7e5b39f8162d5f24)
1c1cd6cb6SAndy Yan /*
2c1cd6cb6SAndy Yan  * sfc driver for rockchip
3c1cd6cb6SAndy Yan  *
4c1cd6cb6SAndy Yan  * (C) Copyright 2008-2016 Rockchip Electronics
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>
11c1cd6cb6SAndy Yan #include <clk.h>
12c1cd6cb6SAndy Yan #include <dm.h>
13c1cd6cb6SAndy Yan #include <dt-structs.h>
14c1cd6cb6SAndy Yan #include <errno.h>
15c1cd6cb6SAndy Yan #include <spi.h>
16c1cd6cb6SAndy Yan #include <linux/errno.h>
17c1cd6cb6SAndy Yan #include <asm/io.h>
18c1cd6cb6SAndy Yan #include <asm/arch/clock.h>
19c1cd6cb6SAndy Yan #include <asm/arch/periph.h>
20c1cd6cb6SAndy Yan #include <dm/pinctrl.h>
21c1cd6cb6SAndy Yan #include "rockchip_sfc.h"
22c1cd6cb6SAndy Yan 
23c1cd6cb6SAndy Yan DECLARE_GLOBAL_DATA_PTR;
24c1cd6cb6SAndy Yan 
25c1cd6cb6SAndy Yan enum rockchip_sfc_if_type {
26c1cd6cb6SAndy Yan 	IF_TYPE_STD,
27c1cd6cb6SAndy Yan 	IF_TYPE_DUAL,
28c1cd6cb6SAndy Yan 	IF_TYPE_QUAD,
29c1cd6cb6SAndy Yan };
30c1cd6cb6SAndy Yan 
31c1cd6cb6SAndy Yan struct rockchip_sfc_platdata {
32c1cd6cb6SAndy Yan 	s32 frequency;
33c1cd6cb6SAndy Yan 	fdt_addr_t base;
34c1cd6cb6SAndy Yan };
35c1cd6cb6SAndy Yan 
36c1cd6cb6SAndy Yan struct rockchip_sfc {
37c1cd6cb6SAndy Yan 	struct rockchip_sfc_reg *regbase;
38c1cd6cb6SAndy Yan 	struct clk clk;
39c1cd6cb6SAndy Yan 	unsigned int max_freq;
40c1cd6cb6SAndy Yan 	unsigned int mode;
41c1cd6cb6SAndy Yan 	unsigned int speed_hz;
42c1cd6cb6SAndy Yan 	u32 cmd;
43c1cd6cb6SAndy Yan 	u32 addr;
44c1cd6cb6SAndy Yan };
45c1cd6cb6SAndy Yan 
46c1cd6cb6SAndy Yan static int rockchip_sfc_ofdata_to_platdata(struct udevice *bus)
47c1cd6cb6SAndy Yan {
48c1cd6cb6SAndy Yan 	struct rockchip_sfc_platdata *plat = dev_get_platdata(bus);
49c1cd6cb6SAndy Yan 	struct rockchip_sfc *sfc = dev_get_priv(bus);
50c1cd6cb6SAndy Yan 	const void *blob = gd->fdt_blob;
51c1cd6cb6SAndy Yan 	int node = dev_of_offset(bus);
52c1cd6cb6SAndy Yan 	int subnode;
53c1cd6cb6SAndy Yan 	int ret;
54c1cd6cb6SAndy Yan 
55c1cd6cb6SAndy Yan 	plat->base = devfdt_get_addr(bus);
56c1cd6cb6SAndy Yan 
57c1cd6cb6SAndy Yan 	ret = clk_get_by_index(bus, 0, &sfc->clk);
58c1cd6cb6SAndy Yan 	if (ret < 0) {
59c1cd6cb6SAndy Yan 		debug("Could not get clock for %s: %d\n", bus->name, ret);
60c1cd6cb6SAndy Yan 		return ret;
61c1cd6cb6SAndy Yan 	}
62c1cd6cb6SAndy Yan 
63c1cd6cb6SAndy Yan 	subnode = fdt_first_subnode(blob, node);
64c1cd6cb6SAndy Yan 	if (subnode < 0) {
65c1cd6cb6SAndy Yan 		debug("Error: subnode with SPI flash config missing!\n");
66c1cd6cb6SAndy Yan 		return -ENODEV;
67c1cd6cb6SAndy Yan 	}
68c1cd6cb6SAndy Yan 
69c1cd6cb6SAndy Yan 	plat->frequency = fdtdec_get_int(blob, subnode, "spi-max-frequency",
70c1cd6cb6SAndy Yan 					 100000000);
71c1cd6cb6SAndy Yan 
72c1cd6cb6SAndy Yan 	return 0;
73c1cd6cb6SAndy Yan }
74c1cd6cb6SAndy Yan 
75c1cd6cb6SAndy Yan static int rockchip_sfc_probe(struct udevice *bus)
76c1cd6cb6SAndy Yan {
77c1cd6cb6SAndy Yan 	struct rockchip_sfc_platdata *plat = dev_get_platdata(bus);
78c1cd6cb6SAndy Yan 	struct rockchip_sfc *sfc = dev_get_priv(bus);
79c1cd6cb6SAndy Yan 	int ret;
80c1cd6cb6SAndy Yan 
81c1cd6cb6SAndy Yan 	sfc->regbase = (struct rockchip_sfc_reg *)plat->base;
82c1cd6cb6SAndy Yan 
83c1cd6cb6SAndy Yan 	sfc->max_freq = plat->frequency;
84c1cd6cb6SAndy Yan 
85c1cd6cb6SAndy Yan 	ret = clk_set_rate(&sfc->clk, sfc->max_freq);
86c1cd6cb6SAndy Yan 	if (ret < 0) {
87c1cd6cb6SAndy Yan 		debug("%s: Failed to set clock: %d\n", __func__, ret);
88c1cd6cb6SAndy Yan 		return ret;
89c1cd6cb6SAndy Yan 	}
90c1cd6cb6SAndy Yan 
91c1cd6cb6SAndy Yan 	return 0;
92c1cd6cb6SAndy Yan }
93c1cd6cb6SAndy Yan 
94c1cd6cb6SAndy Yan static int rockchip_sfc_reset(struct rockchip_sfc *sfc)
95c1cd6cb6SAndy Yan {
96c1cd6cb6SAndy Yan 	struct rockchip_sfc_reg *regs = sfc->regbase;
97c1cd6cb6SAndy Yan 	int tbase = get_timer(0);
98c1cd6cb6SAndy Yan 	u32 rcvr;
99c1cd6cb6SAndy Yan 	int ret = 0;
100c1cd6cb6SAndy Yan 
101c1cd6cb6SAndy Yan 	writel(SFC_RESET, &regs->rcvr);
102c1cd6cb6SAndy Yan 	do {
103c1cd6cb6SAndy Yan 		rcvr = readl(&regs->rcvr);
104c1cd6cb6SAndy Yan 		if (get_timer(tbase) > 1000) {
105c1cd6cb6SAndy Yan 			debug("sfc reset timeout\n");
106c1cd6cb6SAndy Yan 			ret =  -ETIMEDOUT;
107c1cd6cb6SAndy Yan 			break;
108c1cd6cb6SAndy Yan 		}
109c1cd6cb6SAndy Yan 		udelay(1);
110c1cd6cb6SAndy Yan 	} while (rcvr);
111c1cd6cb6SAndy Yan 
112c1cd6cb6SAndy Yan 	writel(0xFFFFFFFF, &regs->iclr);
113c1cd6cb6SAndy Yan 
114c1cd6cb6SAndy Yan 	debug("sfc reset\n");
115c1cd6cb6SAndy Yan 
116c1cd6cb6SAndy Yan 	return ret;
117c1cd6cb6SAndy Yan }
118c1cd6cb6SAndy Yan 
119c1cd6cb6SAndy Yan static u8 rockchip_sfc_get_if_type(struct rockchip_sfc *sfc)
120c1cd6cb6SAndy Yan {
121c1cd6cb6SAndy Yan 	int type = IF_TYPE_STD;
122c1cd6cb6SAndy Yan 
123c1cd6cb6SAndy Yan 	if (sfc->cmd & SFC_WR) {
124c1cd6cb6SAndy Yan 		if (sfc->mode & SPI_TX_QUAD)
125c1cd6cb6SAndy Yan 			type = IF_TYPE_QUAD;
126c1cd6cb6SAndy Yan 		else if (sfc->mode & SPI_TX_DUAL)
127c1cd6cb6SAndy Yan 			type = IF_TYPE_DUAL;
128c1cd6cb6SAndy Yan 		else
129c1cd6cb6SAndy Yan 			type = IF_TYPE_STD;
130c1cd6cb6SAndy Yan 	} else {
131c1cd6cb6SAndy Yan 		if (sfc->mode & SPI_RX_QUAD)
132c1cd6cb6SAndy Yan 			type = IF_TYPE_QUAD;
133c1cd6cb6SAndy Yan 		else if (sfc->mode & SPI_RX_DUAL)
134c1cd6cb6SAndy Yan 			type = IF_TYPE_DUAL;
135c1cd6cb6SAndy Yan 		else
136c1cd6cb6SAndy Yan 			type = IF_TYPE_STD;
137c1cd6cb6SAndy Yan 	}
138c1cd6cb6SAndy Yan 
139c1cd6cb6SAndy Yan 	return type;
140c1cd6cb6SAndy Yan }
141c1cd6cb6SAndy Yan 
142c1cd6cb6SAndy Yan static void rockchip_sfc_setup_xfer(struct rockchip_sfc *sfc)
143c1cd6cb6SAndy Yan {
144c1cd6cb6SAndy Yan 	struct rockchip_sfc_reg *regs = sfc->regbase;
145c1cd6cb6SAndy Yan 	u32 val = 0x02;
146c1cd6cb6SAndy Yan 	u32 fsr = readl(&regs->fsr);
147c1cd6cb6SAndy Yan 	u32 sr = readl(&regs->sr);
148c1cd6cb6SAndy Yan 	u8 data_width = IF_TYPE_STD;
149c1cd6cb6SAndy Yan 
150c1cd6cb6SAndy Yan 	if (!(fsr & SFC_TX_EMPTY) || !(fsr & SFC_RX_EMPTY) || (sr & SFC_BUSY))
151c1cd6cb6SAndy Yan 		rockchip_sfc_reset(sfc);
152c1cd6cb6SAndy Yan 
153c1cd6cb6SAndy Yan 	if (sfc->cmd & SFC_ADDR_XBITS)
154c1cd6cb6SAndy Yan 		data_width = rockchip_sfc_get_if_type(sfc);
155c1cd6cb6SAndy Yan 
156c1cd6cb6SAndy Yan 	val |= (data_width << SFC_DATA_WIDTH_SHIFT);
157c1cd6cb6SAndy Yan 
158c1cd6cb6SAndy Yan 	writel(val, &regs->ctrl);
159c1cd6cb6SAndy Yan 	writel(sfc->cmd, &regs->cmd);
160c1cd6cb6SAndy Yan 	if (sfc->cmd & SFC_ADDR_XBITS)
161c1cd6cb6SAndy Yan 		writel(sfc->addr, &regs->addr);
162c1cd6cb6SAndy Yan }
163c1cd6cb6SAndy Yan 
164c1cd6cb6SAndy Yan static int rockchip_sfc_do_dma_xfer(struct rockchip_sfc *sfc, u32 *buffer)
165c1cd6cb6SAndy Yan {
166c1cd6cb6SAndy Yan 	struct rockchip_sfc_reg *regs = sfc->regbase;
167c1cd6cb6SAndy Yan 	int timeout = 1000;
168c1cd6cb6SAndy Yan 	int ret = 0;
169c1cd6cb6SAndy Yan 	int risr;
170c1cd6cb6SAndy Yan 	unsigned long tbase;
171c1cd6cb6SAndy Yan 
172c1cd6cb6SAndy Yan 	rockchip_sfc_setup_xfer(sfc);
173c1cd6cb6SAndy Yan 
174c1cd6cb6SAndy Yan 	writel(0xFFFFFFFF, &regs->iclr);
175c1cd6cb6SAndy Yan 	writel((u32)buffer, &regs->dmaaddr);
176c1cd6cb6SAndy Yan 	writel(SFC_DMA_START, &regs->dmatr);
177c1cd6cb6SAndy Yan 
178c1cd6cb6SAndy Yan 	tbase = get_timer(0);
179c1cd6cb6SAndy Yan 	do {
180c1cd6cb6SAndy Yan 		udelay(1);
181c1cd6cb6SAndy Yan 		risr = readl(&regs->risr);
182c1cd6cb6SAndy Yan 		if (get_timer(tbase) > timeout) {
183c1cd6cb6SAndy Yan 			debug("dma timeout\n");
184c1cd6cb6SAndy Yan 			ret = -ETIMEDOUT;
185c1cd6cb6SAndy Yan 			break;
186c1cd6cb6SAndy Yan 		}
187c1cd6cb6SAndy Yan 	} while (!(risr & TRANS_FINISH_INT));
188c1cd6cb6SAndy Yan 
189c1cd6cb6SAndy Yan 	writel(0xFFFFFFFF, &regs->iclr);
190c1cd6cb6SAndy Yan 
191c1cd6cb6SAndy Yan 	return ret;
192c1cd6cb6SAndy Yan }
193c1cd6cb6SAndy Yan 
194c1cd6cb6SAndy Yan static int rockchip_sfc_dma_xfer(struct rockchip_sfc *sfc, u32 *buf, u32 len)
195c1cd6cb6SAndy Yan {
196c1cd6cb6SAndy Yan 	u32 trb;
197c1cd6cb6SAndy Yan 	u32 *p32_data = buf;
198c1cd6cb6SAndy Yan 	int ret = 0;
199c1cd6cb6SAndy Yan 
200c1cd6cb6SAndy Yan 	while (len) {
201c1cd6cb6SAndy Yan 		trb = min(len, (u32)SFC_MAX_TRB);
202*6bf64646SAndy Yan 		sfc->cmd &= ~SFC_TRB_MASK;
203c1cd6cb6SAndy Yan 		sfc->cmd |= (trb << SFC_TRB_SHIFT);
204c1cd6cb6SAndy Yan 		ret = rockchip_sfc_do_dma_xfer(sfc, p32_data);
205c1cd6cb6SAndy Yan 		if (ret < 0)
206c1cd6cb6SAndy Yan 			break;
207c1cd6cb6SAndy Yan 		len -= trb;
208c1cd6cb6SAndy Yan 		sfc->addr += trb;
209c1cd6cb6SAndy Yan 		p32_data += (trb >> 2);
210c1cd6cb6SAndy Yan 	}
211c1cd6cb6SAndy Yan 
212c1cd6cb6SAndy Yan 	return ret;
213c1cd6cb6SAndy Yan }
214c1cd6cb6SAndy Yan 
215c1cd6cb6SAndy Yan static int rockchip_sfc_wait_fifo_ready(struct rockchip_sfc *sfc, int wr,
216c1cd6cb6SAndy Yan 					u32 timeout)
217c1cd6cb6SAndy Yan {
218c1cd6cb6SAndy Yan 	struct rockchip_sfc_reg *regs = sfc->regbase;
219c1cd6cb6SAndy Yan 	unsigned long tbase = get_timer(0);
220c1cd6cb6SAndy Yan 	u8 level;
221c1cd6cb6SAndy Yan 	u32 fsr;
222c1cd6cb6SAndy Yan 
223c1cd6cb6SAndy Yan 	do {
224c1cd6cb6SAndy Yan 		fsr = readl(&regs->fsr);
225c1cd6cb6SAndy Yan 		if (wr)
226c1cd6cb6SAndy Yan 			level = (fsr & SFC_TXLV_MASK) >> SFC_TXLV_SHIFT;
227c1cd6cb6SAndy Yan 		else
228c1cd6cb6SAndy Yan 			level = (fsr & SFC_RXLV_MASK) >> SFC_RXLV_SHIFT;
229c1cd6cb6SAndy Yan 		if (get_timer(tbase) > timeout)
230c1cd6cb6SAndy Yan 			return -ETIMEDOUT;
231c1cd6cb6SAndy Yan 		udelay(1);
232c1cd6cb6SAndy Yan 	} while (!level);
233c1cd6cb6SAndy Yan 
234c1cd6cb6SAndy Yan 	return level;
235c1cd6cb6SAndy Yan }
236c1cd6cb6SAndy Yan 
237c1cd6cb6SAndy Yan static int rockchip_sfc_write(struct rockchip_sfc *sfc, u32 *buf, u32 len)
238c1cd6cb6SAndy Yan {
239c1cd6cb6SAndy Yan 	struct rockchip_sfc_reg *regs = sfc->regbase;
240c1cd6cb6SAndy Yan 	u32 bytes = len & 0x3;
241c1cd6cb6SAndy Yan 	u32 words = len >> 2;
242c1cd6cb6SAndy Yan 	u32 tx_level = 0;
243c1cd6cb6SAndy Yan 	u32 val = 0;
244c1cd6cb6SAndy Yan 	u8 count;
245c1cd6cb6SAndy Yan 
246c1cd6cb6SAndy Yan 	while (words) {
247c1cd6cb6SAndy Yan 		tx_level = rockchip_sfc_wait_fifo_ready(sfc, 1, 1000);
248c1cd6cb6SAndy Yan 		if (tx_level <= 0)
249c1cd6cb6SAndy Yan 			return tx_level;
250c1cd6cb6SAndy Yan 		count = min(words, tx_level);
251c1cd6cb6SAndy Yan 		writesl(&regs->data, buf, count);
252c1cd6cb6SAndy Yan 		buf += count;
253c1cd6cb6SAndy Yan 		words -= count;
254c1cd6cb6SAndy Yan 	}
255c1cd6cb6SAndy Yan 
256c1cd6cb6SAndy Yan 	/* handle the last none word aligned bytes */
257c1cd6cb6SAndy Yan 	if (bytes) {
258c1cd6cb6SAndy Yan 		tx_level = rockchip_sfc_wait_fifo_ready(sfc, 1, 1000);
259c1cd6cb6SAndy Yan 		if (tx_level <= 0)
260c1cd6cb6SAndy Yan 			return tx_level;
261c1cd6cb6SAndy Yan 		memcpy(&val, buf, bytes);
262c1cd6cb6SAndy Yan 		writel(val, &regs->data);
263c1cd6cb6SAndy Yan 	}
264c1cd6cb6SAndy Yan 
265c1cd6cb6SAndy Yan 	return 0;
266c1cd6cb6SAndy Yan }
267c1cd6cb6SAndy Yan 
268c1cd6cb6SAndy Yan static int rockchip_sfc_read(struct rockchip_sfc *sfc, u32 *buf, u32 len)
269c1cd6cb6SAndy Yan {
270c1cd6cb6SAndy Yan 	struct rockchip_sfc_reg *regs = sfc->regbase;
271c1cd6cb6SAndy Yan 	u32 bytes = len & 0x3;
272c1cd6cb6SAndy Yan 	u32 words = len >> 2;
273c1cd6cb6SAndy Yan 	u32 rx_level = 0;
274c1cd6cb6SAndy Yan 	u32 count;
275c1cd6cb6SAndy Yan 	u32 val;
276c1cd6cb6SAndy Yan 
277c1cd6cb6SAndy Yan 	while (words) {
278c1cd6cb6SAndy Yan 		rx_level = rockchip_sfc_wait_fifo_ready(sfc, 0, 1000);
279c1cd6cb6SAndy Yan 		if (rx_level <= 0)
280c1cd6cb6SAndy Yan 			return rx_level;
281c1cd6cb6SAndy Yan 		count = min(words, rx_level);
282c1cd6cb6SAndy Yan 		readsl(&regs->data, buf, count);
283c1cd6cb6SAndy Yan 		buf += count;
284c1cd6cb6SAndy Yan 		words -= count;
285c1cd6cb6SAndy Yan 	}
286c1cd6cb6SAndy Yan 
287c1cd6cb6SAndy Yan 	/* handle the last none word aligned bytes */
288c1cd6cb6SAndy Yan 	if (bytes) {
289c1cd6cb6SAndy Yan 		rx_level = rockchip_sfc_wait_fifo_ready(sfc, 0, 1000);
290c1cd6cb6SAndy Yan 		if (rx_level <= 0)
291c1cd6cb6SAndy Yan 			return rx_level;
292c1cd6cb6SAndy Yan 		val = readl(&regs->data);
293c1cd6cb6SAndy Yan 		memcpy(buf, &val, bytes);
294c1cd6cb6SAndy Yan 	}
295c1cd6cb6SAndy Yan 
296c1cd6cb6SAndy Yan 	return 0;
297c1cd6cb6SAndy Yan }
298c1cd6cb6SAndy Yan 
299c1cd6cb6SAndy Yan static int rockchip_sfc_pio_xfer(struct rockchip_sfc *sfc, u32 *buf, u32 len)
300c1cd6cb6SAndy Yan {
301c1cd6cb6SAndy Yan 	int ret = 0;
302c1cd6cb6SAndy Yan 	int rw = sfc->cmd & SFC_WR;
303c1cd6cb6SAndy Yan 
304*6bf64646SAndy Yan 	sfc->cmd &= ~SFC_TRB_MASK;
305c1cd6cb6SAndy Yan 	sfc->cmd |= (len << SFC_TRB_SHIFT);
306c1cd6cb6SAndy Yan 	rockchip_sfc_setup_xfer(sfc);
307c1cd6cb6SAndy Yan 	if (len) {
308c1cd6cb6SAndy Yan 		if (rw)
309c1cd6cb6SAndy Yan 			ret = rockchip_sfc_write(sfc, buf, len);
310c1cd6cb6SAndy Yan 		else
311c1cd6cb6SAndy Yan 			ret = rockchip_sfc_read(sfc, buf, len);
312c1cd6cb6SAndy Yan 	}
313c1cd6cb6SAndy Yan 
314c1cd6cb6SAndy Yan 	return ret;
315c1cd6cb6SAndy Yan }
316c1cd6cb6SAndy Yan 
317c1cd6cb6SAndy Yan static int rockchip_sfc_do_xfer(struct rockchip_sfc *sfc, u32 *buf, u32 len)
318c1cd6cb6SAndy Yan {
319c1cd6cb6SAndy Yan 	int ret = 0;
320*6bf64646SAndy Yan 	u32 bytes = len & 0x3;
321*6bf64646SAndy Yan 	u32 dma_trans;
322c1cd6cb6SAndy Yan 
323*6bf64646SAndy Yan 	if (len >= SFC_MAX_TRB) {
324*6bf64646SAndy Yan 		dma_trans = len - bytes;
325*6bf64646SAndy Yan 	} else {
326*6bf64646SAndy Yan 		dma_trans = 0;
327*6bf64646SAndy Yan 		bytes = len;
328*6bf64646SAndy Yan 	}
329*6bf64646SAndy Yan 
330*6bf64646SAndy Yan 	if (dma_trans) {
331*6bf64646SAndy Yan 		ret = rockchip_sfc_dma_xfer(sfc, buf, dma_trans);
332*6bf64646SAndy Yan 		buf += (dma_trans  >> 2);
333*6bf64646SAndy Yan 	}
334*6bf64646SAndy Yan 
335*6bf64646SAndy Yan 	/*
336*6bf64646SAndy Yan 	 * transfer the last non 4 bytes anligned byte by pio mode
337*6bf64646SAndy Yan 	 * there are also some commands like WREN(0x06) that execute
338*6bf64646SAndy Yan 	 * whth no data, we also need to handle it here.
339*6bf64646SAndy Yan 	 */
340*6bf64646SAndy Yan 	if (bytes || (!bytes && !dma_trans))
341*6bf64646SAndy Yan 		ret = rockchip_sfc_pio_xfer(sfc, buf, bytes);
342c1cd6cb6SAndy Yan 
343c1cd6cb6SAndy Yan 	return ret;
344c1cd6cb6SAndy Yan }
345c1cd6cb6SAndy Yan 
346c1cd6cb6SAndy Yan static int rockchip_sfc_xfer(struct udevice *dev, unsigned int bitlen,
347c1cd6cb6SAndy Yan 			     const void *dout, void *din, unsigned long flags)
348c1cd6cb6SAndy Yan {
349c1cd6cb6SAndy Yan 	struct udevice *bus = dev->parent;
350c1cd6cb6SAndy Yan 	struct rockchip_sfc *sfc = dev_get_priv(bus);
351c1cd6cb6SAndy Yan 	int len = bitlen >> 3;
352c1cd6cb6SAndy Yan 	u8 *pcmd = (u8 *)dout;
353c1cd6cb6SAndy Yan 	int ret = 0;
354c1cd6cb6SAndy Yan 
355c1cd6cb6SAndy Yan 	if (flags & SPI_XFER_BEGIN) {
356c1cd6cb6SAndy Yan 		sfc->cmd = pcmd[0];
357c1cd6cb6SAndy Yan 		if (len >= 4) {
358c1cd6cb6SAndy Yan 			sfc->cmd |= SFC_ADDR_24BITS | (((len - 4) * 8) << 8);
359c1cd6cb6SAndy Yan 			sfc->addr = pcmd[3] | (pcmd[2] << 8) | (pcmd[1] << 16);
360c1cd6cb6SAndy Yan 		}
361c1cd6cb6SAndy Yan 	}
362c1cd6cb6SAndy Yan 
363c1cd6cb6SAndy Yan 	if (flags == (SPI_XFER_BEGIN | SPI_XFER_END))
364c1cd6cb6SAndy Yan 		len = 0;
365c1cd6cb6SAndy Yan 
366c1cd6cb6SAndy Yan 	if (flags & SPI_XFER_END) {
367*6bf64646SAndy Yan 		if (dout)
368c1cd6cb6SAndy Yan 			sfc->cmd |= SFC_WR;
369c1cd6cb6SAndy Yan 
370c1cd6cb6SAndy Yan 		if (din)
371c1cd6cb6SAndy Yan 			ret = rockchip_sfc_do_xfer(sfc, (u32 *)din, len);
372c1cd6cb6SAndy Yan 		else if (dout)
373c1cd6cb6SAndy Yan 			ret = rockchip_sfc_do_xfer(sfc, (u32 *)dout, len);
374c1cd6cb6SAndy Yan 	}
375c1cd6cb6SAndy Yan 
376c1cd6cb6SAndy Yan 	return ret;
377c1cd6cb6SAndy Yan }
378c1cd6cb6SAndy Yan 
379c1cd6cb6SAndy Yan static int rockchip_sfc_set_speed(struct udevice *bus, uint speed)
380c1cd6cb6SAndy Yan {
381c1cd6cb6SAndy Yan 	struct rockchip_sfc *sfc = dev_get_priv(bus);
382c1cd6cb6SAndy Yan 
383c1cd6cb6SAndy Yan 	if (speed > sfc->max_freq)
384c1cd6cb6SAndy Yan 		speed = sfc->max_freq;
385c1cd6cb6SAndy Yan 
386c1cd6cb6SAndy Yan 	sfc->speed_hz = speed;
387c1cd6cb6SAndy Yan 
388c1cd6cb6SAndy Yan 	return 0;
389c1cd6cb6SAndy Yan }
390c1cd6cb6SAndy Yan 
391c1cd6cb6SAndy Yan static int rockchip_sfc_set_mode(struct udevice *bus, uint mode)
392c1cd6cb6SAndy Yan {
393c1cd6cb6SAndy Yan 	struct rockchip_sfc *sfc = dev_get_priv(bus);
394c1cd6cb6SAndy Yan 
395c1cd6cb6SAndy Yan 	sfc->mode = mode;
396c1cd6cb6SAndy Yan 
397c1cd6cb6SAndy Yan 	return 0;
398c1cd6cb6SAndy Yan }
399c1cd6cb6SAndy Yan 
400c1cd6cb6SAndy Yan static const struct dm_spi_ops rockchip_sfc_ops = {
401c1cd6cb6SAndy Yan 	.xfer		= rockchip_sfc_xfer,
402c1cd6cb6SAndy Yan 	.set_speed	= rockchip_sfc_set_speed,
403c1cd6cb6SAndy Yan 	.set_mode	= rockchip_sfc_set_mode,
404c1cd6cb6SAndy Yan };
405c1cd6cb6SAndy Yan 
406c1cd6cb6SAndy Yan static const struct udevice_id rockchip_sfc_ids[] = {
407c1cd6cb6SAndy Yan 	{ .compatible = "rockchip,sfc" },
408c1cd6cb6SAndy Yan 	{ }
409c1cd6cb6SAndy Yan };
410c1cd6cb6SAndy Yan 
411c1cd6cb6SAndy Yan U_BOOT_DRIVER(rockchip_sfc_driver) = {
412c1cd6cb6SAndy Yan 	.name	= "rockchip_sfc",
413c1cd6cb6SAndy Yan 	.id	= UCLASS_SPI,
414c1cd6cb6SAndy Yan 	.of_match = rockchip_sfc_ids,
415c1cd6cb6SAndy Yan 	.ops	= &rockchip_sfc_ops,
416c1cd6cb6SAndy Yan 	.ofdata_to_platdata = rockchip_sfc_ofdata_to_platdata,
417c1cd6cb6SAndy Yan 	.platdata_auto_alloc_size = sizeof(struct rockchip_sfc_platdata),
418c1cd6cb6SAndy Yan 	.priv_auto_alloc_size = sizeof(struct rockchip_sfc),
419c1cd6cb6SAndy Yan 	.probe	= rockchip_sfc_probe,
420c1cd6cb6SAndy Yan };
421