arspi.c revision 1.16 1 /* $NetBSD: arspi.c,v 1.16 2025/09/10 01:55:07 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 2006 Urbana-Champaign Independent Media Center.
5 * Copyright (c) 2006 Garrett D'Amore.
6 * All rights reserved.
7 *
8 * Portions of this code were written by Garrett D'Amore for the
9 * Champaign-Urbana Community Wireless Network Project.
10 *
11 * Redistribution and use in source and binary forms, with or
12 * without modification, are permitted provided that the following
13 * conditions are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above
17 * copyright notice, this list of conditions and the following
18 * disclaimer in the documentation and/or other materials provided
19 * with the distribution.
20 * 3. All advertising materials mentioning features or use of this
21 * software must display the following acknowledgements:
22 * This product includes software developed by the Urbana-Champaign
23 * Independent Media Center.
24 * This product includes software developed by Garrett D'Amore.
25 * 4. Urbana-Champaign Independent Media Center's name and Garrett
26 * D'Amore's name may not be used to endorse or promote products
27 * derived from this software without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE URBANA-CHAMPAIGN INDEPENDENT
30 * MEDIA CENTER AND GARRETT D'AMORE ``AS IS'' AND ANY EXPRESS OR
31 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
32 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 * ARE DISCLAIMED. IN NO EVENT SHALL THE URBANA-CHAMPAIGN INDEPENDENT
34 * MEDIA CENTER OR GARRETT D'AMORE BE LIABLE FOR ANY DIRECT, INDIRECT,
35 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 */
43
44 #include <sys/cdefs.h>
45 __KERNEL_RCSID(0, "$NetBSD: arspi.c,v 1.16 2025/09/10 01:55:07 thorpej Exp $");
46
47 #include "locators.h"
48
49 #include <sys/param.h>
50 #include <sys/bus.h>
51 #include <sys/cpu.h>
52 #include <sys/device.h>
53 #include <sys/errno.h>
54 #include <sys/kernel.h>
55 #include <sys/kmem.h>
56 #include <sys/proc.h>
57 #include <sys/systm.h>
58
59 #include <mips/atheros/include/ar5315reg.h>
60 #include <mips/atheros/include/arbusvar.h>
61
62 #include <mips/atheros/dev/arspireg.h>
63
64 #include <dev/spi/spiflash.h>
65 #include <dev/spi/spivar.h>
66
67 /*
68 * This device is intended only to operate with specific SPI flash
69 * parts, and is not a general purpose SPI host. (Or at least if it
70 * is, the Linux and eCos sources do not show how to use it as such.)
71 * And lack of documentation on the Atheros SoCs is less than helpful.
72 *
73 * So for now we just "emulate" enough of the host bus framework to
74 * make the SPI flash drivers happy.
75 */
76
77 struct arspi_job {
78 uint8_t job_opcode;
79 struct spi_chunk *job_chunk;
80 uint32_t job_flags;
81 uint32_t job_addr;
82 uint32_t job_data;
83 int job_rxcnt;
84 int job_txcnt;
85 int job_addrcnt;
86 int job_rresid;
87 int job_wresid;
88 };
89
90 #define JOB_READ 0x1
91 #define JOB_WRITE 0x2
92 #define JOB_LAST 0x4
93 #define JOB_WAIT 0x8 /* job must wait for WIP bits */
94 #define JOB_WREN 0x10 /* WREN needed */
95
96 struct arspi_softc {
97 struct spi_controller sc_spi;
98 void *sc_ih;
99 bool sc_interrupts;
100
101 struct spi_transfer *sc_transfer;
102 struct spi_chunk *sc_wchunk; /* for partial writes */
103 struct spi_transq sc_transq;
104 bus_space_tag_t sc_st;
105 bus_space_handle_t sc_sh;
106 bus_size_t sc_size;
107 };
108
109 #define STATIC
110
111 STATIC int arspi_match(device_t, cfdata_t, void *);
112 STATIC void arspi_attach(device_t, device_t, void *);
113 STATIC void arspi_interrupts(device_t);
114 STATIC int arspi_intr(void *);
115 /* SPI service routines */
116 STATIC int arspi_configure(void *, int, int, int);
117 STATIC int arspi_transfer(void *, struct spi_transfer *);
118 /* internal support */
119 STATIC void arspi_poll(struct arspi_softc *);
120 STATIC void arspi_done(struct arspi_softc *, int);
121 STATIC void arspi_sched(struct arspi_softc *);
122 STATIC int arspi_get_byte(struct spi_chunk **, uint8_t *);
123 STATIC int arspi_put_byte(struct spi_chunk **, uint8_t);
124 STATIC int arspi_make_job(struct spi_transfer *);
125 STATIC void arspi_update_job(struct spi_transfer *);
126 STATIC void arspi_finish_job(struct spi_transfer *);
127
128
129 CFATTACH_DECL_NEW(arspi, sizeof(struct arspi_softc),
130 arspi_match, arspi_attach, NULL, NULL);
131
132 #define GETREG(sc, o) bus_space_read_4(sc->sc_st, sc->sc_sh, o)
133 #define PUTREG(sc, o, v) bus_space_write_4(sc->sc_st, sc->sc_sh, o, v)
134
135 int
136 arspi_match(device_t parent, cfdata_t cf, void *aux)
137 {
138 struct arbus_attach_args *aa = aux;
139
140 if (strcmp(aa->aa_name, cf->cf_name) != 0)
141 return 0;
142 return 1;
143 }
144
145 void
146 arspi_attach(device_t parent, device_t self, void *aux)
147 {
148 struct arspi_softc *sc = device_private(self);
149 struct arbus_attach_args *aa = aux;
150
151 /*
152 * Map registers.
153 */
154 sc->sc_st = aa->aa_bst;
155 sc->sc_size = aa->aa_size;
156 if (bus_space_map(sc->sc_st, aa->aa_addr, sc->sc_size, 0,
157 &sc->sc_sh) != 0) {
158 printf(": unable to map registers!\n");
159 return;
160 }
161
162 aprint_normal(": Atheros SPI controller\n");
163
164 /*
165 * Initialize SPI controller.
166 */
167 sc->sc_spi.sct_cookie = sc;
168 sc->sc_spi.sct_configure = arspi_configure;
169 sc->sc_spi.sct_transfer = arspi_transfer;
170 sc->sc_spi.sct_nslaves = 1;
171
172
173 /*
174 * Initialize the queue.
175 */
176 spi_transq_init(&sc->sc_transq);
177
178 /*
179 * Enable device interrupts.
180 */
181 sc->sc_ih = arbus_intr_establish(aa->aa_cirq, aa->aa_mirq,
182 arspi_intr, sc);
183 if (sc->sc_ih == NULL) {
184 aprint_error("%s: couldn't establish interrupt\n",
185 device_xname(self));
186 /* just leave it in polled mode */
187 } else
188 config_interrupts(self, arspi_interrupts);
189
190 /*
191 * Initialize and attach bus attach.
192 */
193 spibus_attach(self, &sc->sc_spi);
194 }
195
196 void
197 arspi_interrupts(device_t self)
198 {
199 /*
200 * we never leave polling mode, because, apparently, we
201 * are missing some data about how to drive the SPI in interrupt
202 * mode.
203 */
204 #if 0
205 struct arspi_softc *sc = device_private(self);
206 int s;
207
208 s = splbio();
209 sc->sc_interrupts = true;
210 splx(s);
211 #endif
212 }
213
214 int
215 arspi_intr(void *arg)
216 {
217 struct arspi_softc *sc = arg;
218
219 while (GETREG(sc, ARSPI_REG_CTL) & ARSPI_CTL_BUSY);
220
221 arspi_done(sc, 0);
222
223 return 1;
224 }
225
226 void
227 arspi_poll(struct arspi_softc *sc)
228 {
229
230 while (sc->sc_transfer) {
231 arspi_intr(sc);
232 }
233 }
234
235 int
236 arspi_configure(void *cookie, int slave, int mode, int speed)
237 {
238
239 /*
240 * We don't support the full SPI protocol, and hopefully the
241 * firmware has programmed a reasonable mode already. So
242 * just a couple of quick sanity checks, then bail.
243 */
244 if ((mode != 0) || (slave != 0))
245 return EINVAL;
246
247 return 0;
248 }
249
250 int
251 arspi_transfer(void *cookie, struct spi_transfer *st)
252 {
253 struct arspi_softc *sc = cookie;
254 int rv;
255 int s;
256
257 st->st_busprivate = NULL;
258 if ((rv = arspi_make_job(st)) != 0) {
259 if (st->st_busprivate) {
260 struct arspi_job *job = st->st_busprivate;
261 st->st_busprivate = NULL;
262 kmem_free(job, sizeof(*job));
263 }
264 spi_done(st, rv);
265 return rv;
266 }
267
268 s = splbio();
269 spi_transq_enqueue(&sc->sc_transq, st);
270 if (sc->sc_transfer == NULL) {
271 arspi_sched(sc);
272 if (!sc->sc_interrupts)
273 arspi_poll(sc);
274 }
275 splx(s);
276 return 0;
277 }
278
279 void
280 arspi_sched(struct arspi_softc *sc)
281 {
282 struct spi_transfer *st;
283 struct arspi_job *job;
284 uint32_t ctl, cnt;
285
286 for (;;) {
287 if ((st = sc->sc_transfer) == NULL) {
288 if ((st = spi_transq_first(&sc->sc_transq)) == NULL) {
289 /* no work left to do */
290 break;
291 }
292 spi_transq_dequeue(&sc->sc_transq);
293 sc->sc_transfer = st;
294 }
295
296 arspi_update_job(st);
297 job = st->st_busprivate;
298
299 /* there shouldn't be anything running, but ensure it */
300 do {
301 ctl = GETREG(sc, ARSPI_REG_CTL);
302 } while (ctl & ARSPI_CTL_BUSY);
303 /* clear all of the tx and rx bits */
304 ctl &= ~(ARSPI_CTL_TXCNT_MASK | ARSPI_CTL_RXCNT_MASK);
305
306 if (job->job_flags & JOB_WAIT) {
307 PUTREG(sc, ARSPI_REG_OPCODE, SPIFLASH_CMD_RDSR);
308 /* only the opcode for tx */
309 ctl |= (1 << ARSPI_CTL_TXCNT_SHIFT);
310 /* and one rx byte */
311 ctl |= (1 << ARSPI_CTL_RXCNT_SHIFT);
312 } else if (job->job_flags & JOB_WREN) {
313 PUTREG(sc, ARSPI_REG_OPCODE, SPIFLASH_CMD_WREN);
314 /* just the opcode */
315 ctl |= (1 << ARSPI_CTL_TXCNT_SHIFT);
316 /* no rx bytes */
317 } else {
318 /* set the data */
319 PUTREG(sc, ARSPI_REG_DATA, job->job_data);
320
321 /* set the opcode and the address */
322 PUTREG(sc, ARSPI_REG_OPCODE, job->job_opcode |
323 (job->job_addr << 8));
324
325 /* now set txcnt */
326 cnt = 1; /* opcode */
327 cnt += job->job_addrcnt + job->job_txcnt;
328 ctl |= (cnt << ARSPI_CTL_TXCNT_SHIFT);
329
330 /* now set rxcnt */
331 cnt = job->job_rxcnt;
332 ctl |= (cnt << ARSPI_CTL_RXCNT_SHIFT);
333 }
334
335 /* set the start bit */
336 ctl |= ARSPI_CTL_START;
337
338 PUTREG(sc, ARSPI_REG_CTL, ctl);
339 break;
340 }
341 }
342
343 void
344 arspi_done(struct arspi_softc *sc, int err)
345 {
346 struct spi_transfer *st;
347 struct arspi_job *job;
348
349 if ((st = sc->sc_transfer) != NULL) {
350 job = st->st_busprivate;
351
352 if (job->job_flags & JOB_WAIT) {
353 if (err == 0) {
354 if ((GETREG(sc, ARSPI_REG_DATA) &
355 SPIFLASH_SR_BUSY) == 0) {
356 /* intermediate wait done */
357 job->job_flags &= ~JOB_WAIT;
358 goto done;
359 }
360 }
361 } else if (job->job_flags & JOB_WREN) {
362 if (err == 0) {
363 job->job_flags &= ~JOB_WREN;
364 goto done;
365 }
366 } else if (err == 0) {
367 /*
368 * When breaking up write jobs, we have to wait until
369 * the WIP bit is clear, and we have to separately
370 * send WREN for each chunk. These flags facilitate
371 * that.
372 */
373 if (job->job_flags & JOB_WRITE)
374 job->job_flags |= (JOB_WAIT | JOB_WREN);
375 job->job_data = GETREG(sc, ARSPI_REG_DATA);
376 arspi_finish_job(st);
377 }
378
379 if (err || (job->job_flags & JOB_LAST)) {
380 sc->sc_transfer = NULL;
381 st->st_busprivate = NULL;
382 spi_done(st, err);
383 kmem_free(job, sizeof(*job));
384 }
385 }
386 done:
387 arspi_sched(sc);
388 }
389
390 int
391 arspi_get_byte(struct spi_chunk **chunkp, uint8_t *bytep)
392 {
393 struct spi_chunk *chunk;
394
395 chunk = *chunkp;
396
397 /* skip leading empty (or already consumed) chunks */
398 while (chunk && chunk->chunk_wresid == 0)
399 chunk = chunk->chunk_next;
400
401 if (chunk == NULL) {
402 return ENODATA;
403 }
404
405 /*
406 * chunk must be write only. SPI flash doesn't support
407 * any full duplex operations.
408 */
409 if ((chunk->chunk_rptr) || !(chunk->chunk_wptr)) {
410 return EINVAL;
411 }
412
413 *bytep = *chunk->chunk_wptr;
414 chunk->chunk_wptr++;
415 chunk->chunk_wresid--;
416 chunk->chunk_rresid--;
417 /* clearing wptr and rptr makes sanity checks later easier */
418 if (chunk->chunk_wresid == 0)
419 chunk->chunk_wptr = NULL;
420 if (chunk->chunk_rresid == 0)
421 chunk->chunk_rptr = NULL;
422 while (chunk && chunk->chunk_wresid == 0)
423 chunk = chunk->chunk_next;
424
425 *chunkp = chunk;
426 return 0;
427 }
428
429 int
430 arspi_put_byte(struct spi_chunk **chunkp, uint8_t byte)
431 {
432 struct spi_chunk *chunk;
433
434 chunk = *chunkp;
435
436 /* skip leading empty (or already consumed) chunks */
437 while (chunk && chunk->chunk_rresid == 0)
438 chunk = chunk->chunk_next;
439
440 if (chunk == NULL) {
441 return EOVERFLOW;
442 }
443
444 /*
445 * chunk must be read only. SPI flash doesn't support
446 * any full duplex operations.
447 */
448 if ((chunk->chunk_wptr) || !(chunk->chunk_rptr)) {
449 return EINVAL;
450 }
451
452 *chunk->chunk_rptr = byte;
453 chunk->chunk_rptr++;
454 chunk->chunk_wresid--; /* technically this was done at send time */
455 chunk->chunk_rresid--;
456 while (chunk && chunk->chunk_rresid == 0)
457 chunk = chunk->chunk_next;
458
459 *chunkp = chunk;
460 return 0;
461 }
462
463 int
464 arspi_make_job(struct spi_transfer *st)
465 {
466 struct arspi_job *job;
467 struct spi_chunk *chunk;
468 uint8_t byte;
469 int i, rv;
470
471 job = kmem_zalloc(sizeof (struct arspi_job), KM_SLEEP);
472
473 st->st_busprivate = job;
474
475 /* skip any leading empty chunks (should not be any!) */
476 chunk = st->st_chunks;
477
478 /* get transfer opcode */
479 if ((rv = arspi_get_byte(&chunk, &byte)) != 0)
480 return rv;
481
482 job->job_opcode = byte;
483 switch (job->job_opcode) {
484 case SPIFLASH_CMD_WREN:
485 case SPIFLASH_CMD_WRDI:
486 case SPIFLASH_CMD_CHIPERASE:
487 break;
488 case SPIFLASH_CMD_RDJI:
489 job->job_rxcnt = 3;
490 break;
491 case SPIFLASH_CMD_RDSR:
492 job->job_rxcnt = 1;
493 break;
494 case SPIFLASH_CMD_WRSR:
495 /*
496 * is this in data, or in address? stick it in data
497 * for now.
498 */
499 job->job_txcnt = 1;
500 break;
501 case SPIFLASH_CMD_RDID:
502 job->job_addrcnt = 3; /* 3 dummy bytes */
503 job->job_rxcnt = 1;
504 break;
505 case SPIFLASH_CMD_ERASE:
506 job->job_addrcnt = 3;
507 break;
508 case SPIFLASH_CMD_READ:
509 job->job_addrcnt = 3;
510 job->job_flags |= JOB_READ;
511 break;
512 case SPIFLASH_CMD_PROGRAM:
513 job->job_addrcnt = 3;
514 job->job_flags |= JOB_WRITE;
515 break;
516 case SPIFLASH_CMD_READFAST:
517 /*
518 * This is a pain in the arse to support, so we will
519 * rewrite as an ordinary read. But later, after we
520 * obtain the address.
521 */
522 job->job_addrcnt = 3; /* 3 address */
523 job->job_flags |= JOB_READ;
524 break;
525 default:
526 return EINVAL;
527 }
528
529 for (i = 0; i < job->job_addrcnt; i++) {
530 if ((rv = arspi_get_byte(&chunk, &byte)) != 0)
531 return rv;
532 job->job_addr <<= 8;
533 job->job_addr |= byte;
534 }
535
536
537 if (job->job_opcode == SPIFLASH_CMD_READFAST) {
538 /* eat the dummy timing byte */
539 if ((rv = arspi_get_byte(&chunk, &byte)) != 0)
540 return rv;
541 /* rewrite this as a read */
542 job->job_opcode = SPIFLASH_CMD_READ;
543 }
544
545 job->job_chunk = chunk;
546
547 /*
548 * Now quickly check a few other things. Namely, we are not
549 * allowed to have both READ and WRITE.
550 */
551 for (chunk = job->job_chunk; chunk; chunk = chunk->chunk_next) {
552 if (chunk->chunk_wptr) {
553 job->job_wresid += chunk->chunk_wresid;
554 }
555 if (chunk->chunk_rptr) {
556 job->job_rresid += chunk->chunk_rresid;
557 }
558 }
559
560 if (job->job_rresid && job->job_wresid) {
561 return EINVAL;
562 }
563
564 return 0;
565 }
566
567 /*
568 * NB: The Atheros SPI controller runs in little endian mode. So all
569 * data accesses must be swapped appropriately.
570 *
571 * The controller auto-swaps read accesses done through the mapped memory
572 * region, but when using SPI directly, we have to do the right thing to
573 * swap to or from little endian.
574 */
575
576 void
577 arspi_update_job(struct spi_transfer *st)
578 {
579 struct arspi_job *job = st->st_busprivate;
580 uint8_t byte;
581 int i;
582
583 if (job->job_flags & (JOB_WAIT|JOB_WREN))
584 return;
585
586 job->job_rxcnt = 0;
587 job->job_txcnt = 0;
588 job->job_data = 0;
589
590 job->job_txcnt = uimin(job->job_wresid, 4);
591 job->job_rxcnt = uimin(job->job_rresid, 4);
592
593 job->job_wresid -= job->job_txcnt;
594 job->job_rresid -= job->job_rxcnt;
595
596 for (i = 0; i < job->job_txcnt; i++) {
597 arspi_get_byte(&job->job_chunk, &byte);
598 job->job_data |= (byte << (i * 8));
599 }
600
601 if ((!job->job_wresid) && (!job->job_rresid)) {
602 job->job_flags |= JOB_LAST;
603 }
604 }
605
606 void
607 arspi_finish_job(struct spi_transfer *st)
608 {
609 struct arspi_job *job = st->st_busprivate;
610 uint8_t byte;
611 int i;
612
613 job->job_addr += job->job_rxcnt;
614 job->job_addr += job->job_txcnt;
615 for (i = 0; i < job->job_rxcnt; i++) {
616 byte = job->job_data & 0xff;
617 job->job_data >>= 8;
618 arspi_put_byte(&job->job_chunk, byte);
619 }
620 }
621
622