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