]>
Commit | Line | Data |
---|---|---|
59d06122 RR |
1 | /* |
2 | * Freescale Coldfire Queued SPI driver | |
3 | * | |
4 | * NOTE: | |
5 | * This driver is written to transfer 8 bit at-a-time and uses the dedicated | |
6 | * SPI slave select pins as bit-banged GPIO to work with spi_flash subsystem. | |
7 | * | |
59d06122 RR |
8 | * Copyright (C) 2011 Ruggedcom, Inc. |
9 | * Richard Retanubun (richardretanubun@freescale.com) | |
10 | * | |
1a459660 | 11 | * SPDX-License-Identifier: GPL-2.0+ |
59d06122 RR |
12 | */ |
13 | ||
14 | #include <common.h> | |
15 | #include <malloc.h> | |
16 | #include <spi.h> | |
17 | #include <asm/immap.h> | |
18 | #include <asm/io.h> | |
19 | ||
20 | DECLARE_GLOBAL_DATA_PTR; | |
21 | ||
22 | #define clamp(x, low, high) (min(max(low, x), high)) | |
23 | #define to_cf_qspi_slave(s) container_of(s, struct cf_qspi_slave, s) | |
24 | ||
25 | struct cf_qspi_slave { | |
26 | struct spi_slave slave; /* Specific bus:cs ID for each device */ | |
27 | qspi_t *regs; /* Pointer to SPI controller registers */ | |
28 | u16 qmr; /* QMR: Queued Mode Register */ | |
29 | u16 qwr; /* QWR: Queued Wrap Register */ | |
30 | u16 qcr; /* QCR: Queued Command Ram */ | |
31 | }; | |
32 | ||
33 | /* Register write wrapper functions */ | |
34 | static void write_qmr(volatile qspi_t *qspi, u16 val) { qspi->mr = val; } | |
35 | static void write_qdlyr(volatile qspi_t *qspi, u16 val) { qspi->dlyr = val; } | |
36 | static void write_qwr(volatile qspi_t *qspi, u16 val) { qspi->wr = val; } | |
37 | static void write_qir(volatile qspi_t *qspi, u16 val) { qspi->ir = val; } | |
38 | static void write_qar(volatile qspi_t *qspi, u16 val) { qspi->ar = val; } | |
39 | static void write_qdr(volatile qspi_t *qspi, u16 val) { qspi->dr = val; } | |
40 | /* Register read wrapper functions */ | |
41 | static u16 read_qdlyr(volatile qspi_t *qspi) { return qspi->dlyr; } | |
42 | static u16 read_qwr(volatile qspi_t *qspi) { return qspi->wr; } | |
43 | static u16 read_qir(volatile qspi_t *qspi) { return qspi->ir; } | |
44 | static u16 read_qdr(volatile qspi_t *qspi) { return qspi->dr; } | |
45 | ||
46 | /* These call points may be different for each ColdFire CPU */ | |
47 | extern void cfspi_port_conf(void); | |
48 | static void cfspi_cs_activate(uint bus, uint cs, uint cs_active_high); | |
49 | static void cfspi_cs_deactivate(uint bus, uint cs, uint cs_active_high); | |
50 | ||
51 | int spi_claim_bus(struct spi_slave *slave) | |
52 | { | |
53 | return 0; | |
54 | } | |
55 | void spi_release_bus(struct spi_slave *slave) | |
56 | { | |
57 | } | |
58 | ||
59 | __attribute__((weak)) | |
60 | void spi_init(void) | |
61 | { | |
62 | cfspi_port_conf(); | |
63 | } | |
64 | ||
65 | __attribute__((weak)) | |
66 | void spi_cs_activate(struct spi_slave *slave) | |
67 | { | |
68 | struct cf_qspi_slave *dev = to_cf_qspi_slave(slave); | |
69 | ||
70 | cfspi_cs_activate(slave->bus, slave->cs, !(dev->qwr & QSPI_QWR_CSIV)); | |
71 | } | |
72 | ||
73 | __attribute__((weak)) | |
74 | void spi_cs_deactivate(struct spi_slave *slave) | |
75 | { | |
76 | struct cf_qspi_slave *dev = to_cf_qspi_slave(slave); | |
77 | ||
78 | cfspi_cs_deactivate(slave->bus, slave->cs, !(dev->qwr & QSPI_QWR_CSIV)); | |
79 | } | |
80 | ||
81 | __attribute__((weak)) | |
82 | int spi_cs_is_valid(unsigned int bus, unsigned int cs) | |
83 | { | |
84 | /* Only 1 bus and 4 chipselect per controller */ | |
85 | if (bus == 0 && (cs >= 0 && cs < 4)) | |
86 | return 1; | |
87 | else | |
88 | return 0; | |
89 | } | |
90 | ||
91 | void spi_free_slave(struct spi_slave *slave) | |
92 | { | |
93 | struct cf_qspi_slave *dev = to_cf_qspi_slave(slave); | |
94 | ||
95 | free(dev); | |
96 | } | |
97 | ||
98 | /* Translate information given by spi_setup_slave to members of cf_qspi_slave */ | |
99 | struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, | |
100 | unsigned int max_hz, unsigned int mode) | |
101 | { | |
102 | struct cf_qspi_slave *dev = NULL; | |
103 | ||
104 | if (!spi_cs_is_valid(bus, cs)) | |
105 | return NULL; | |
106 | ||
d3504fee | 107 | dev = spi_alloc_slave(struct cf_qspi_slave, bus, cs); |
59d06122 RR |
108 | if (!dev) |
109 | return NULL; | |
110 | ||
111 | /* Initialize to known value */ | |
59d06122 RR |
112 | dev->regs = (qspi_t *)MMAP_QSPI; |
113 | dev->qmr = 0; | |
114 | dev->qwr = 0; | |
115 | dev->qcr = 0; | |
116 | ||
117 | ||
118 | /* Map max_hz to QMR[BAUD] */ | |
119 | if (max_hz == 0) /* Go as fast as possible */ | |
120 | dev->qmr = 2u; | |
121 | else /* Get the closest baud rate */ | |
122 | dev->qmr = clamp(((gd->bus_clk >> 2) + max_hz - 1)/max_hz, | |
123 | 2u, 255u); | |
124 | ||
125 | /* Map mode to QMR[CPOL] and QMR[CPHA] */ | |
126 | if (mode & SPI_CPOL) | |
127 | dev->qmr |= QSPI_QMR_CPOL; | |
128 | ||
129 | if (mode & SPI_CPHA) | |
130 | dev->qmr |= QSPI_QMR_CPHA; | |
131 | ||
132 | /* Hardcode bit length to 8 bit per transter */ | |
133 | dev->qmr |= QSPI_QMR_BITS_8; | |
134 | ||
135 | /* Set QMR[MSTR] to enable QSPI as master */ | |
136 | dev->qmr |= QSPI_QMR_MSTR; | |
137 | ||
138 | /* | |
139 | * Set QCR and QWR to default values for spi flash operation. | |
140 | * If more custom QCR and QRW are needed, overload mode variable | |
141 | */ | |
142 | dev->qcr = (QSPI_QDR_CONT | QSPI_QDR_BITSE); | |
143 | ||
144 | if (!(mode & SPI_CS_HIGH)) | |
145 | dev->qwr |= QSPI_QWR_CSIV; | |
146 | ||
147 | return &dev->slave; | |
148 | } | |
149 | ||
150 | /* Transfer 8 bit at a time */ | |
151 | int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, | |
152 | void *din, unsigned long flags) | |
153 | { | |
154 | struct cf_qspi_slave *dev = to_cf_qspi_slave(slave); | |
155 | volatile qspi_t *qspi = dev->regs; | |
156 | u8 *txbuf = (u8 *)dout; | |
157 | u8 *rxbuf = (u8 *)din; | |
0cb8394f | 158 | u32 count = DIV_ROUND_UP(bitlen, 8); |
59d06122 RR |
159 | u32 n, i = 0; |
160 | ||
161 | /* Sanitize arguments */ | |
162 | if (slave == NULL) { | |
163 | printf("%s: NULL slave ptr\n", __func__); | |
164 | return -1; | |
165 | } | |
166 | ||
167 | if (flags & SPI_XFER_BEGIN) | |
168 | spi_cs_activate(slave); | |
169 | ||
170 | /* There is something to send, lets process it. spi_xfer is also called | |
171 | * just to toggle chip select, so bitlen of 0 is valid */ | |
172 | if (count > 0) { | |
173 | /* | |
174 | * NOTE: Since chip select is driven as a bit-bang-ed GPIO | |
175 | * using spi_cs_activate() and spi_cs_deactivate(), | |
176 | * the chip select settings inside the controller | |
177 | * (i.e. QCR[CONT] and QWR[CSIV]) are moot. The bits are set to | |
178 | * keep the controller settings consistent with the actual | |
179 | * operation of the bus. | |
180 | */ | |
181 | ||
182 | /* Write the slave device's settings for the controller.*/ | |
183 | write_qmr(qspi, dev->qmr); | |
184 | write_qwr(qspi, dev->qwr); | |
185 | ||
186 | /* Limit transfer to 16 at a time */ | |
187 | n = min(count, 16u); | |
188 | do { | |
189 | /* Setup queue end point */ | |
190 | write_qwr(qspi, ((read_qwr(qspi) & QSPI_QWR_ENDQP_MASK) | |
191 | | QSPI_QWR_ENDQP((n-1)))); | |
192 | ||
193 | /* Write Command RAM */ | |
194 | write_qar(qspi, QSPI_QAR_CMD); | |
195 | for (i = 0; i < n; ++i) | |
196 | write_qdr(qspi, dev->qcr); | |
197 | ||
198 | /* Write TxBuf, if none given, fill with ZEROes */ | |
199 | write_qar(qspi, QSPI_QAR_TRANS); | |
200 | if (txbuf) { | |
201 | for (i = 0; i < n; ++i) | |
202 | write_qdr(qspi, *txbuf++); | |
203 | } else { | |
204 | for (i = 0; i < n; ++i) | |
205 | write_qdr(qspi, 0); | |
206 | } | |
207 | ||
208 | /* Clear QIR[SPIF] by writing a 1 to it */ | |
209 | write_qir(qspi, read_qir(qspi) | QSPI_QIR_SPIF); | |
210 | /* Set QDLYR[SPE] to start sending */ | |
211 | write_qdlyr(qspi, read_qdlyr(qspi) | QSPI_QDLYR_SPE); | |
212 | ||
213 | /* Poll QIR[SPIF] for transfer completion */ | |
214 | while ((read_qir(qspi) & QSPI_QIR_SPIF) != 1) | |
215 | udelay(1); | |
216 | ||
217 | /* If given read RxBuf, load data to it */ | |
218 | if (rxbuf) { | |
219 | write_qar(qspi, QSPI_QAR_RECV); | |
220 | for (i = 0; i < n; ++i) | |
221 | *rxbuf++ = read_qdr(qspi); | |
222 | } | |
223 | ||
224 | /* Decrement count */ | |
225 | count -= n; | |
226 | } while (count); | |
227 | } | |
228 | ||
229 | if (flags & SPI_XFER_END) | |
230 | spi_cs_deactivate(slave); | |
231 | ||
232 | return 0; | |
233 | } | |
234 | ||
235 | /* Each MCF CPU may have different pin assignments for chip selects. */ | |
236 | #if defined(CONFIG_M5271) | |
237 | /* Assert chip select, val = [1|0] , dir = out, mode = GPIO */ | |
238 | void cfspi_cs_activate(uint bus, uint cs, uint cs_active_high) | |
239 | { | |
240 | debug("%s: bus %d cs %d cs_active_high %d\n", | |
241 | __func__, bus, cs, cs_active_high); | |
242 | ||
243 | switch (cs) { | |
244 | case 0: /* QSPI_CS[0] = PQSPI[3] */ | |
245 | if (cs_active_high) | |
246 | mbar_writeByte(MCF_GPIO_PPDSDR_QSPI, 0x08); | |
247 | else | |
248 | mbar_writeByte(MCF_GPIO_PCLRR_QSPI, 0xF7); | |
249 | ||
250 | mbar_writeByte(MCF_GPIO_PDDR_QSPI, | |
251 | mbar_readByte(MCF_GPIO_PDDR_QSPI) | 0x08); | |
252 | ||
253 | mbar_writeByte(MCF_GPIO_PAR_QSPI, | |
254 | mbar_readByte(MCF_GPIO_PAR_QSPI) & 0xDF); | |
255 | break; | |
256 | case 1: /* QSPI_CS[1] = PQSPI[4] */ | |
257 | if (cs_active_high) | |
258 | mbar_writeByte(MCF_GPIO_PPDSDR_QSPI, 0x10); | |
259 | else | |
260 | mbar_writeByte(MCF_GPIO_PCLRR_QSPI, 0xEF); | |
261 | ||
262 | mbar_writeByte(MCF_GPIO_PDDR_QSPI, | |
263 | mbar_readByte(MCF_GPIO_PDDR_QSPI) | 0x10); | |
264 | ||
265 | mbar_writeByte(MCF_GPIO_PAR_QSPI, | |
266 | mbar_readByte(MCF_GPIO_PAR_QSPI) & 0x3F); | |
267 | break; | |
268 | case 2: /* QSPI_CS[2] = PTIMER[7] */ | |
269 | if (cs_active_high) | |
270 | mbar_writeByte(MCF_GPIO_PPDSDR_TIMER, 0x80); | |
271 | else | |
272 | mbar_writeByte(MCF_GPIO_PCLRR_TIMER, 0x7F); | |
273 | ||
274 | mbar_writeByte(MCF_GPIO_PDDR_TIMER, | |
275 | mbar_readByte(MCF_GPIO_PDDR_TIMER) | 0x80); | |
276 | ||
277 | mbar_writeShort(MCF_GPIO_PAR_TIMER, | |
278 | mbar_readShort(MCF_GPIO_PAR_TIMER) & 0x3FFF); | |
279 | break; | |
280 | case 3: /* QSPI_CS[3] = PTIMER[3] */ | |
281 | if (cs_active_high) | |
282 | mbar_writeByte(MCF_GPIO_PPDSDR_TIMER, 0x08); | |
283 | else | |
284 | mbar_writeByte(MCF_GPIO_PCLRR_TIMER, 0xF7); | |
285 | ||
286 | mbar_writeByte(MCF_GPIO_PDDR_TIMER, | |
287 | mbar_readByte(MCF_GPIO_PDDR_TIMER) | 0x08); | |
288 | ||
289 | mbar_writeShort(MCF_GPIO_PAR_TIMER, | |
290 | mbar_readShort(MCF_GPIO_PAR_TIMER) & 0xFF3F); | |
291 | break; | |
292 | } | |
293 | } | |
294 | ||
295 | /* Deassert chip select, val = [1|0], dir = in, mode = GPIO | |
296 | * direction set as IN to undrive the pin, external pullup/pulldown will bring | |
297 | * bus to deassert state. | |
298 | */ | |
299 | void cfspi_cs_deactivate(uint bus, uint cs, uint cs_active_high) | |
300 | { | |
301 | debug("%s: bus %d cs %d cs_active_high %d\n", | |
302 | __func__, bus, cs, cs_active_high); | |
303 | ||
304 | switch (cs) { | |
305 | case 0: /* QSPI_CS[0] = PQSPI[3] */ | |
306 | if (cs_active_high) | |
307 | mbar_writeByte(MCF_GPIO_PCLRR_QSPI, 0xF7); | |
308 | else | |
309 | mbar_writeByte(MCF_GPIO_PPDSDR_QSPI, 0x08); | |
310 | ||
311 | mbar_writeByte(MCF_GPIO_PDDR_QSPI, | |
312 | mbar_readByte(MCF_GPIO_PDDR_QSPI) & 0xF7); | |
313 | ||
314 | mbar_writeByte(MCF_GPIO_PAR_QSPI, | |
315 | mbar_readByte(MCF_GPIO_PAR_QSPI) & 0xDF); | |
316 | break; | |
317 | case 1: /* QSPI_CS[1] = PQSPI[4] */ | |
318 | if (cs_active_high) | |
319 | mbar_writeByte(MCF_GPIO_PCLRR_QSPI, 0xEF); | |
320 | else | |
321 | mbar_writeByte(MCF_GPIO_PPDSDR_QSPI, 0x10); | |
322 | ||
323 | mbar_writeByte(MCF_GPIO_PDDR_QSPI, | |
324 | mbar_readByte(MCF_GPIO_PDDR_QSPI) & 0xEF); | |
325 | ||
326 | mbar_writeByte(MCF_GPIO_PAR_QSPI, | |
327 | mbar_readByte(MCF_GPIO_PAR_QSPI) & 0x3F); | |
328 | break; | |
329 | case 2: /* QSPI_CS[2] = PTIMER[7] */ | |
330 | if (cs_active_high) | |
331 | mbar_writeByte(MCF_GPIO_PCLRR_TIMER, 0x7F); | |
332 | else | |
333 | mbar_writeByte(MCF_GPIO_PPDSDR_TIMER, 0x80); | |
334 | ||
335 | mbar_writeByte(MCF_GPIO_PDDR_TIMER, | |
336 | mbar_readByte(MCF_GPIO_PDDR_TIMER) & 0x7F); | |
337 | ||
338 | mbar_writeShort(MCF_GPIO_PAR_TIMER, | |
339 | mbar_readShort(MCF_GPIO_PAR_TIMER) & 0x3FFF); | |
340 | break; | |
341 | case 3: /* QSPI_CS[3] = PTIMER[3] */ | |
342 | if (cs_active_high) | |
343 | mbar_writeByte(MCF_GPIO_PCLRR_TIMER, 0xF7); | |
344 | else | |
345 | mbar_writeByte(MCF_GPIO_PPDSDR_TIMER, 0x08); | |
346 | ||
347 | mbar_writeByte(MCF_GPIO_PDDR_TIMER, | |
348 | mbar_readByte(MCF_GPIO_PDDR_TIMER) & 0xF7); | |
349 | ||
350 | mbar_writeShort(MCF_GPIO_PAR_TIMER, | |
351 | mbar_readShort(MCF_GPIO_PAR_TIMER) & 0xFF3F); | |
352 | break; | |
353 | } | |
354 | } | |
355 | #endif /* CONFIG_M5271 */ |