]>
Commit | Line | Data |
---|---|---|
dec61c78 TL |
1 | /* |
2 | * | |
3 | * (C) Copyright 2000-2003 | |
4 | * Wolfgang Denk, DENX Software Engineering, [email protected]. | |
5 | * | |
6 | * Copyright (C) 2004-2009 Freescale Semiconductor, Inc. | |
7 | * TsiChung Liew ([email protected]) | |
8 | * | |
1a459660 | 9 | * SPDX-License-Identifier: GPL-2.0+ |
dec61c78 TL |
10 | */ |
11 | ||
12 | #include <common.h> | |
13 | #include <spi.h> | |
14 | #include <malloc.h> | |
15 | #include <asm/immap.h> | |
16 | ||
17 | struct cf_spi_slave { | |
18 | struct spi_slave slave; | |
19 | uint baudrate; | |
20 | int charbit; | |
21 | }; | |
22 | ||
23 | int cfspi_xfer(struct spi_slave *slave, uint bitlen, const void *dout, | |
24 | void *din, ulong flags); | |
25 | struct spi_slave *cfspi_setup_slave(struct cf_spi_slave *cfslave, uint mode); | |
26 | void cfspi_init(void); | |
27 | void cfspi_tx(u32 ctrl, u16 data); | |
28 | u16 cfspi_rx(void); | |
29 | ||
30 | extern void cfspi_port_conf(void); | |
31 | extern int cfspi_claim_bus(uint bus, uint cs); | |
32 | extern void cfspi_release_bus(uint bus, uint cs); | |
33 | ||
34 | DECLARE_GLOBAL_DATA_PTR; | |
35 | ||
b97e0cd7 WW |
36 | #ifndef CONFIG_SPI_IDLE_VAL |
37 | #if defined(CONFIG_SPI_MMC) | |
38 | #define CONFIG_SPI_IDLE_VAL 0xFFFF | |
39 | #else | |
40 | #define CONFIG_SPI_IDLE_VAL 0x0 | |
41 | #endif | |
42 | #endif | |
43 | ||
dec61c78 TL |
44 | #if defined(CONFIG_CF_DSPI) |
45 | /* DSPI specific mode */ | |
46 | #define SPI_MODE_MOD 0x00200000 | |
47 | #define SPI_DBLRATE 0x00100000 | |
48 | ||
49 | void cfspi_init(void) | |
50 | { | |
51 | volatile dspi_t *dspi = (dspi_t *) MMAP_DSPI; | |
52 | ||
53 | cfspi_port_conf(); /* port configuration */ | |
54 | ||
55 | dspi->mcr = DSPI_MCR_MSTR | DSPI_MCR_CSIS7 | DSPI_MCR_CSIS6 | | |
56 | DSPI_MCR_CSIS5 | DSPI_MCR_CSIS4 | DSPI_MCR_CSIS3 | | |
57 | DSPI_MCR_CSIS2 | DSPI_MCR_CSIS1 | DSPI_MCR_CSIS0 | | |
58 | DSPI_MCR_CRXF | DSPI_MCR_CTXF; | |
59 | ||
60 | /* Default setting in platform configuration */ | |
61 | #ifdef CONFIG_SYS_DSPI_CTAR0 | |
62 | dspi->ctar[0] = CONFIG_SYS_DSPI_CTAR0; | |
63 | #endif | |
64 | #ifdef CONFIG_SYS_DSPI_CTAR1 | |
65 | dspi->ctar[1] = CONFIG_SYS_DSPI_CTAR1; | |
66 | #endif | |
67 | #ifdef CONFIG_SYS_DSPI_CTAR2 | |
68 | dspi->ctar[2] = CONFIG_SYS_DSPI_CTAR2; | |
69 | #endif | |
70 | #ifdef CONFIG_SYS_DSPI_CTAR3 | |
71 | dspi->ctar[3] = CONFIG_SYS_DSPI_CTAR3; | |
72 | #endif | |
73 | #ifdef CONFIG_SYS_DSPI_CTAR4 | |
74 | dspi->ctar[4] = CONFIG_SYS_DSPI_CTAR4; | |
75 | #endif | |
76 | #ifdef CONFIG_SYS_DSPI_CTAR5 | |
77 | dspi->ctar[5] = CONFIG_SYS_DSPI_CTAR5; | |
78 | #endif | |
79 | #ifdef CONFIG_SYS_DSPI_CTAR6 | |
80 | dspi->ctar[6] = CONFIG_SYS_DSPI_CTAR6; | |
81 | #endif | |
82 | #ifdef CONFIG_SYS_DSPI_CTAR7 | |
83 | dspi->ctar[7] = CONFIG_SYS_DSPI_CTAR7; | |
84 | #endif | |
85 | } | |
86 | ||
87 | void cfspi_tx(u32 ctrl, u16 data) | |
88 | { | |
89 | volatile dspi_t *dspi = (dspi_t *) MMAP_DSPI; | |
90 | ||
91 | while ((dspi->sr & 0x0000F000) >= 4) ; | |
92 | ||
93 | dspi->tfr = (ctrl | data); | |
94 | } | |
95 | ||
96 | u16 cfspi_rx(void) | |
97 | { | |
98 | volatile dspi_t *dspi = (dspi_t *) MMAP_DSPI; | |
99 | ||
100 | while ((dspi->sr & 0x000000F0) == 0) ; | |
101 | ||
102 | return (dspi->rfr & 0xFFFF); | |
103 | } | |
104 | ||
105 | int cfspi_xfer(struct spi_slave *slave, uint bitlen, const void *dout, | |
106 | void *din, ulong flags) | |
107 | { | |
108 | struct cf_spi_slave *cfslave = (struct cf_spi_slave *)slave; | |
109 | u16 *spi_rd16 = NULL, *spi_wr16 = NULL; | |
110 | u8 *spi_rd = NULL, *spi_wr = NULL; | |
111 | static u32 ctrl = 0; | |
112 | uint len = bitlen >> 3; | |
113 | ||
114 | if (cfslave->charbit == 16) { | |
115 | bitlen >>= 1; | |
116 | spi_wr16 = (u16 *) dout; | |
117 | spi_rd16 = (u16 *) din; | |
118 | } else { | |
119 | spi_wr = (u8 *) dout; | |
120 | spi_rd = (u8 *) din; | |
121 | } | |
122 | ||
123 | if ((flags & SPI_XFER_BEGIN) == SPI_XFER_BEGIN) | |
124 | ctrl |= DSPI_TFR_CONT; | |
125 | ||
126 | ctrl = (ctrl & 0xFF000000) | ((1 << slave->cs) << 16); | |
127 | ||
128 | if (len > 1) { | |
129 | int tmp_len = len - 1; | |
130 | while (tmp_len--) { | |
131 | if (dout != NULL) { | |
132 | if (cfslave->charbit == 16) | |
133 | cfspi_tx(ctrl, *spi_wr16++); | |
134 | else | |
135 | cfspi_tx(ctrl, *spi_wr++); | |
136 | cfspi_rx(); | |
137 | } | |
138 | ||
139 | if (din != NULL) { | |
b97e0cd7 | 140 | cfspi_tx(ctrl, CONFIG_SPI_IDLE_VAL); |
dec61c78 TL |
141 | if (cfslave->charbit == 16) |
142 | *spi_rd16++ = cfspi_rx(); | |
143 | else | |
144 | *spi_rd++ = cfspi_rx(); | |
145 | } | |
146 | } | |
147 | ||
148 | len = 1; /* remaining byte */ | |
149 | } | |
150 | ||
151 | if ((flags & SPI_XFER_END) == SPI_XFER_END) | |
152 | ctrl &= ~DSPI_TFR_CONT; | |
153 | ||
154 | if (len) { | |
155 | if (dout != NULL) { | |
156 | if (cfslave->charbit == 16) | |
157 | cfspi_tx(ctrl, *spi_wr16); | |
158 | else | |
159 | cfspi_tx(ctrl, *spi_wr); | |
160 | cfspi_rx(); | |
161 | } | |
162 | ||
163 | if (din != NULL) { | |
b97e0cd7 | 164 | cfspi_tx(ctrl, CONFIG_SPI_IDLE_VAL); |
dec61c78 TL |
165 | if (cfslave->charbit == 16) |
166 | *spi_rd16 = cfspi_rx(); | |
167 | else | |
168 | *spi_rd = cfspi_rx(); | |
169 | } | |
170 | } else { | |
171 | /* dummy read */ | |
b97e0cd7 | 172 | cfspi_tx(ctrl, CONFIG_SPI_IDLE_VAL); |
dec61c78 TL |
173 | cfspi_rx(); |
174 | } | |
175 | ||
176 | return 0; | |
177 | } | |
178 | ||
179 | struct spi_slave *cfspi_setup_slave(struct cf_spi_slave *cfslave, uint mode) | |
180 | { | |
181 | /* | |
182 | * bit definition for mode: | |
183 | * bit 31 - 28: Transfer size 3 to 16 bits | |
184 | * 27 - 26: PCS to SCK delay prescaler | |
185 | * 25 - 24: After SCK delay prescaler | |
186 | * 23 - 22: Delay after transfer prescaler | |
187 | * 21 : Allow overwrite for bit 31-22 and bit 20-8 | |
188 | * 20 : Double baud rate | |
189 | * 19 - 16: PCS to SCK delay scaler | |
190 | * 15 - 12: After SCK delay scaler | |
191 | * 11 - 8: Delay after transfer scaler | |
192 | * 7 - 0: SPI_CPHA, SPI_CPOL, SPI_LSB_FIRST | |
193 | */ | |
194 | volatile dspi_t *dspi = (dspi_t *) MMAP_DSPI; | |
195 | int prescaler[] = { 2, 3, 5, 7 }; | |
196 | int scaler[] = { | |
197 | 2, 4, 6, 8, | |
198 | 16, 32, 64, 128, | |
199 | 256, 512, 1024, 2048, | |
200 | 4096, 8192, 16384, 32768 | |
201 | }; | |
202 | int i, j, pbrcnt, brcnt, diff, tmp, dbr = 0; | |
203 | int best_i, best_j, bestmatch = 0x7FFFFFFF, baud_speed; | |
204 | u32 bus_setup = 0; | |
205 | ||
206 | tmp = (prescaler[3] * scaler[15]); | |
207 | /* Maximum and minimum baudrate it can handle */ | |
208 | if ((cfslave->baudrate > (gd->bus_clk >> 1)) || | |
209 | (cfslave->baudrate < (gd->bus_clk / tmp))) { | |
210 | printf("Exceed baudrate limitation: Max %d - Min %d\n", | |
211 | (int)(gd->bus_clk >> 1), (int)(gd->bus_clk / tmp)); | |
212 | return NULL; | |
213 | } | |
214 | ||
215 | /* Activate Double Baud when it exceed 1/4 the bus clk */ | |
216 | if ((CONFIG_SYS_DSPI_CTAR0 & DSPI_CTAR_DBR) || | |
217 | (cfslave->baudrate > (gd->bus_clk / (prescaler[0] * scaler[0])))) { | |
218 | bus_setup |= DSPI_CTAR_DBR; | |
219 | dbr = 1; | |
220 | } | |
221 | ||
222 | if (mode & SPI_CPOL) | |
223 | bus_setup |= DSPI_CTAR_CPOL; | |
224 | if (mode & SPI_CPHA) | |
225 | bus_setup |= DSPI_CTAR_CPHA; | |
226 | if (mode & SPI_LSB_FIRST) | |
227 | bus_setup |= DSPI_CTAR_LSBFE; | |
228 | ||
229 | /* Overwrite default value set in platform configuration file */ | |
230 | if (mode & SPI_MODE_MOD) { | |
231 | ||
232 | if ((mode & 0xF0000000) == 0) | |
233 | bus_setup |= | |
234 | dspi->ctar[cfslave->slave.bus] & 0x78000000; | |
235 | else | |
236 | bus_setup |= ((mode & 0xF0000000) >> 1); | |
237 | ||
238 | /* | |
239 | * Check to see if it is enabled by default in platform | |
240 | * config, or manual setting passed by mode parameter | |
241 | */ | |
242 | if (mode & SPI_DBLRATE) { | |
243 | bus_setup |= DSPI_CTAR_DBR; | |
244 | dbr = 1; | |
245 | } | |
246 | bus_setup |= (mode & 0x0FC00000) >> 4; /* PSCSCK, PASC, PDT */ | |
247 | bus_setup |= (mode & 0x000FFF00) >> 4; /* CSSCK, ASC, DT */ | |
248 | } else | |
249 | bus_setup |= (dspi->ctar[cfslave->slave.bus] & 0x78FCFFF0); | |
250 | ||
251 | cfslave->charbit = | |
252 | ((dspi->ctar[cfslave->slave.bus] & 0x78000000) == | |
253 | 0x78000000) ? 16 : 8; | |
254 | ||
255 | pbrcnt = sizeof(prescaler) / sizeof(int); | |
256 | brcnt = sizeof(scaler) / sizeof(int); | |
257 | ||
258 | /* baudrate calculation - to closer value, may not be exact match */ | |
259 | for (best_i = 0, best_j = 0, i = 0; i < pbrcnt; i++) { | |
260 | baud_speed = gd->bus_clk / prescaler[i]; | |
261 | for (j = 0; j < brcnt; j++) { | |
262 | tmp = (baud_speed / scaler[j]) * (1 + dbr); | |
263 | ||
264 | if (tmp > cfslave->baudrate) | |
265 | diff = tmp - cfslave->baudrate; | |
266 | else | |
267 | diff = cfslave->baudrate - tmp; | |
268 | ||
269 | if (diff < bestmatch) { | |
270 | bestmatch = diff; | |
271 | best_i = i; | |
272 | best_j = j; | |
273 | } | |
274 | } | |
275 | } | |
276 | bus_setup |= (DSPI_CTAR_PBR(best_i) | DSPI_CTAR_BR(best_j)); | |
277 | dspi->ctar[cfslave->slave.bus] = bus_setup; | |
278 | ||
279 | return &cfslave->slave; | |
280 | } | |
281 | #endif /* CONFIG_CF_DSPI */ | |
282 | ||
283 | #ifdef CONFIG_CF_QSPI | |
284 | /* 52xx, 53xx */ | |
285 | #endif /* CONFIG_CF_QSPI */ | |
286 | ||
287 | #ifdef CONFIG_CMD_SPI | |
288 | int spi_cs_is_valid(unsigned int bus, unsigned int cs) | |
289 | { | |
290 | if (((cs >= 0) && (cs < 8)) && ((bus >= 0) && (bus < 8))) | |
291 | return 1; | |
292 | else | |
293 | return 0; | |
294 | } | |
295 | ||
296 | void spi_init_f(void) | |
297 | { | |
298 | } | |
299 | ||
300 | void spi_init_r(void) | |
301 | { | |
302 | } | |
303 | ||
304 | void spi_init(void) | |
305 | { | |
306 | cfspi_init(); | |
307 | } | |
308 | ||
309 | struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, | |
310 | unsigned int max_hz, unsigned int mode) | |
311 | { | |
312 | struct cf_spi_slave *cfslave; | |
313 | ||
314 | if (!spi_cs_is_valid(bus, cs)) | |
315 | return NULL; | |
316 | ||
d3504fee | 317 | cfslave = spi_alloc_slave(struct cf_spi_slave, bus, cs); |
dec61c78 TL |
318 | if (!cfslave) |
319 | return NULL; | |
320 | ||
dec61c78 TL |
321 | cfslave->baudrate = max_hz; |
322 | ||
323 | /* specific setup */ | |
324 | return cfspi_setup_slave(cfslave, mode); | |
325 | } | |
326 | ||
327 | void spi_free_slave(struct spi_slave *slave) | |
328 | { | |
329 | free(slave); | |
330 | } | |
331 | ||
332 | int spi_claim_bus(struct spi_slave *slave) | |
333 | { | |
334 | return cfspi_claim_bus(slave->bus, slave->cs); | |
335 | } | |
336 | ||
337 | void spi_release_bus(struct spi_slave *slave) | |
338 | { | |
339 | cfspi_release_bus(slave->bus, slave->cs); | |
340 | } | |
341 | ||
342 | int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, | |
343 | void *din, unsigned long flags) | |
344 | { | |
345 | return cfspi_xfer(slave, bitlen, dout, din, flags); | |
346 | } | |
347 | #endif /* CONFIG_CMD_SPI */ |