xref: /OK3568_Linux_fs/u-boot/drivers/rkflash/sfc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Copyright (c) 2018 Fuzhou Rockchip Electronics Co., Ltd
3  *
4  * SPDX-License-Identifier:	GPL-2.0
5  */
6 
7 #include <common.h>
8 #include <linux/delay.h>
9 #include <bouncebuf.h>
10 #include <asm/io.h>
11 
12 #include "sfc.h"
13 
14 #define SFC_MAX_IOSIZE_VER3		(1024 * 8)
15 #define SFC_MAX_IOSIZE_VER4		(0xFFFFFFFF)
16 
17 static void __iomem *g_sfc_reg;
18 
sfc_reset(void)19 static void sfc_reset(void)
20 {
21 	int timeout = 10000;
22 
23 	writel(SFC_RESET, g_sfc_reg + SFC_RCVR);
24 
25 	while ((readl(g_sfc_reg + SFC_RCVR) == SFC_RESET) && (timeout > 0)) {
26 		sfc_delay(1);
27 		timeout--;
28 	}
29 
30 	writel(0xFFFFFFFF, g_sfc_reg + SFC_ICLR);
31 }
32 
sfc_get_version(void)33 u16 sfc_get_version(void)
34 {
35 	return  (u32)(readl(g_sfc_reg + SFC_VER) & 0xffff);
36 }
37 
sfc_get_max_iosize(void)38 u32 sfc_get_max_iosize(void)
39 {
40 	if (sfc_get_version() >= SFC_VER_4)
41 		return SFC_MAX_IOSIZE_VER4;
42 	else
43 		return SFC_MAX_IOSIZE_VER3;
44 }
45 
sfc_set_delay_lines(u16 cells)46 void sfc_set_delay_lines(u16 cells)
47 {
48 	u16 cell_max = SCLK_SMP_SEL_MAX_V4;
49 
50 	if (sfc_get_version() >= SFC_VER_5)
51 		cell_max = SCLK_SMP_SEL_MAX_V5;
52 
53 	if (cells > cell_max)
54 		cells = cell_max;
55 
56 	writel(SCLK_SMP_SEL_EN | cells, g_sfc_reg + SFC_DLL_CTRL0);
57 }
58 
sfc_disable_delay_lines(void)59 void sfc_disable_delay_lines(void)
60 {
61 	writel(0, g_sfc_reg + SFC_DLL_CTRL0);
62 }
63 
sfc_init(void __iomem * reg_addr)64 int sfc_init(void __iomem *reg_addr)
65 {
66 	g_sfc_reg = reg_addr;
67 	writel(0, g_sfc_reg + SFC_CTRL);
68 
69 	if (sfc_get_version() >= SFC_VER_4)
70 		writel(1, g_sfc_reg + SFC_LEN_CTRL);
71 
72 	return SFC_OK;
73 }
74 
sfc_clean_irq(void)75 void sfc_clean_irq(void)
76 {
77 	writel(0xFFFFFFFF, g_sfc_reg + SFC_ICLR);
78 	writel(0xFFFFFFFF, g_sfc_reg + SFC_IMR);
79 }
80 
sfc_request(struct rk_sfc_op * op,u32 addr,void * data,u32 size)81 int sfc_request(struct rk_sfc_op *op, u32 addr, void *data, u32 size)
82 {
83 	int ret = SFC_OK;
84 	union SFCCMD_DATA cmd;
85 	int reg;
86 	int timeout = 0;
87 
88 	reg = readl(g_sfc_reg + SFC_FSR);
89 
90 	if (!(reg & SFC_TXEMPTY) || !(reg & SFC_RXEMPTY) ||
91 	    (readl(g_sfc_reg + SFC_SR) & SFC_BUSY))
92 		sfc_reset();
93 
94 	cmd.d32 = op->sfcmd.d32;
95 
96 	if (cmd.b.addrbits == SFC_ADDR_XBITS) {
97 		union SFCCTRL_DATA ctrl;
98 
99 		ctrl.d32 = op->sfctrl.d32;
100 
101 		if (!ctrl.b.addrbits)
102 			return SFC_PARAM_ERR;
103 
104 		/* Controller plus 1 automatically */
105 		writel(ctrl.b.addrbits - 1, g_sfc_reg + SFC_ABIT);
106 	}
107 
108 	/* shift in the data at negedge sclk_out */
109 	op->sfctrl.d32 |= 0x2;
110 	cmd.b.datasize = size;
111 
112 	if (sfc_get_version() >= SFC_VER_4)
113 		writel(size, g_sfc_reg + SFC_LEN_EXT);
114 	else
115 		cmd.b.datasize = size;
116 
117 	writel(op->sfctrl.d32, g_sfc_reg + SFC_CTRL);
118 	writel(cmd.d32, g_sfc_reg + SFC_CMD);
119 
120 	if (cmd.b.addrbits)
121 		writel(addr, g_sfc_reg + SFC_ADDR);
122 
123 	if (!size)
124 		goto exit_wait;
125 
126 	if (op->sfctrl.b.enbledma) {
127 		struct bounce_buffer bb;
128 		unsigned int bb_flags;
129 
130 		if (cmd.b.rw == SFC_WRITE)
131 			bb_flags = GEN_BB_READ;
132 		else
133 			bb_flags = GEN_BB_WRITE;
134 
135 		ret = bounce_buffer_start(&bb, data, size, bb_flags);
136 		if (ret)
137 			return ret;
138 
139 		writel(0xFFFFFFFF, g_sfc_reg + SFC_ICLR);
140 		writel(~((u32)DMA_INT), g_sfc_reg + SFC_IMR);
141 		writel((unsigned long)bb.bounce_buffer, g_sfc_reg + SFC_DMA_ADDR);
142 		writel(SFC_DMA_START, g_sfc_reg + SFC_DMA_TRIGGER);
143 
144 		timeout = size * 10;
145 
146 		while ((readl(g_sfc_reg + SFC_SR) & SFC_BUSY) &&
147 		       (timeout-- > 0))
148 			sfc_delay(1);
149 
150 		writel(0xFFFFFFFF, g_sfc_reg + SFC_ICLR);
151 
152 		if (timeout <= 0)
153 			ret = SFC_WAIT_TIMEOUT;
154 		bounce_buffer_stop(&bb);
155 	} else {
156 		u32 i, words, count, bytes;
157 		union SFCFSR_DATA    fifostat;
158 		u32 *p_data = (u32 *)data;
159 
160 		if (cmd.b.rw == SFC_WRITE) {
161 			words  = (size + 3) >> 2;
162 
163 			while (words) {
164 				fifostat.d32 = readl(g_sfc_reg + SFC_FSR);
165 
166 				if (fifostat.b.txlevel > 0) {
167 					count = words < fifostat.b.txlevel ?
168 						words : fifostat.b.txlevel;
169 
170 					for (i = 0; i < count; i++) {
171 						writel(*p_data++,
172 						       g_sfc_reg + SFC_DATA);
173 						words--;
174 					}
175 
176 					if (words == 0)
177 						break;
178 
179 					timeout = 0;
180 				} else {
181 					sfc_delay(1);
182 
183 					if (timeout++ > 10000) {
184 						ret = SFC_TX_TIMEOUT;
185 						break;
186 					}
187 				}
188 			}
189 		} else {
190 			/* SFC_READ == cmd.b.rw */
191 			bytes = size & 0x3;
192 			words = size >> 2;
193 
194 			while (words) {
195 				fifostat.d32 = readl(g_sfc_reg + SFC_FSR);
196 
197 				if (fifostat.b.rxlevel > 0) {
198 					u32 count;
199 
200 					count = words < fifostat.b.rxlevel ?
201 						words : fifostat.b.rxlevel;
202 
203 					for (i = 0; i < count; i++) {
204 						*p_data++ = readl(g_sfc_reg +
205 								  SFC_DATA);
206 						words--;
207 					}
208 
209 					if (words == 0)
210 						break;
211 
212 					timeout = 0;
213 				} else {
214 					sfc_delay(1);
215 
216 					if (timeout++ > 10000) {
217 						ret = SFC_RX_TIMEOUT;
218 						break;
219 					}
220 				}
221 			}
222 
223 			timeout = 0;
224 
225 			while (bytes) {
226 				fifostat.d32 = readl(g_sfc_reg + SFC_FSR);
227 
228 				if (fifostat.b.rxlevel > 0) {
229 					u8 *p_data1 = (u8 *)p_data;
230 
231 					words = readl(g_sfc_reg + SFC_DATA);
232 
233 					for (i = 0; i < bytes; i++)
234 						p_data1[i] =
235 							(u8)((words >> (i * 8)) & 0xFF);
236 
237 					break;
238 				}
239 
240 				sfc_delay(1);
241 
242 				if (timeout++ > 10000) {
243 					ret = SFC_RX_TIMEOUT;
244 					break;
245 				}
246 			}
247 		}
248 	}
249 
250 exit_wait:
251 	timeout = 0;    /* wait cmd or data send complete */
252 
253 	while (readl(g_sfc_reg + SFC_SR) & SFC_BUSY) {
254 		sfc_delay(1);
255 
256 		if (timeout++ > 100000) {         /* wait 100ms */
257 			ret = SFC_TX_TIMEOUT;
258 			break;
259 		}
260 	}
261 
262 	sfc_delay(1); /* CS# High Time (read/write) >100ns */
263 	return ret;
264 }
265