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