arspi.c revision 1.10
1/* $NetBSD: arspi.c,v 1.10 2012/10/27 17:18:02 chs 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.10 2012/10/27 17:18:02 chs 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/malloc.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
77struct 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
96struct 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
111STATIC int arspi_match(device_t, cfdata_t, void *);
112STATIC void arspi_attach(device_t, device_t, void *);
113STATIC void arspi_interrupts(device_t);
114STATIC int arspi_intr(void *);
115/* SPI service routines */
116STATIC int arspi_configure(void *, int, int, int);
117STATIC int arspi_transfer(void *, struct spi_transfer *);
118/* internal support */
119STATIC void arspi_poll(struct arspi_softc *);
120STATIC void arspi_done(struct arspi_softc *, int);
121STATIC void arspi_sched(struct arspi_softc *);
122STATIC int arspi_get_byte(struct spi_chunk **, uint8_t *);
123STATIC int arspi_put_byte(struct spi_chunk **, uint8_t);
124STATIC int arspi_make_job(struct spi_transfer *);
125STATIC void arspi_update_job(struct spi_transfer *);
126STATIC void arspi_finish_job(struct spi_transfer *);
127
128
129CFATTACH_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
135int
136arspi_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
145void
146arspi_attach(device_t parent, device_t self, void *aux)
147{
148	struct arspi_softc *sc = device_private(self);
149	struct spibus_attach_args sba;
150	struct arbus_attach_args *aa = aux;
151
152	/*
153	 * Map registers.
154	 */
155	sc->sc_st = aa->aa_bst;
156	sc->sc_size = aa->aa_size;
157	if (bus_space_map(sc->sc_st, aa->aa_addr, sc->sc_size, 0,
158		&sc->sc_sh) != 0) {
159		printf(": unable to map registers!\n");
160		return;
161	}
162
163	aprint_normal(": Atheros SPI controller\n");
164
165	/*
166	 * Initialize SPI controller.
167	 */
168	sc->sc_spi.sct_cookie = sc;
169	sc->sc_spi.sct_configure = arspi_configure;
170	sc->sc_spi.sct_transfer = arspi_transfer;
171	sc->sc_spi.sct_nslaves = 1;
172
173
174	/*
175	 * Initialize the queue.
176	 */
177	spi_transq_init(&sc->sc_transq);
178
179	/*
180	 * Enable device interrupts.
181	 */
182	sc->sc_ih = arbus_intr_establish(aa->aa_cirq, aa->aa_mirq,
183	    arspi_intr, sc);
184	if (sc->sc_ih == NULL) {
185		aprint_error("%s: couldn't establish interrupt\n",
186		    device_xname(self));
187		/* just leave it in polled mode */
188	} else
189		config_interrupts(self, arspi_interrupts);
190
191	/*
192	 * Initialize and attach bus attach.
193	 */
194	sba.sba_controller = &sc->sc_spi;
195	(void) config_found_ia(self, "spibus", &sba, spibus_print);
196}
197
198void
199arspi_interrupts(device_t self)
200{
201	/*
202	 * we never leave polling mode, because, apparently, we
203	 * are missing some data about how to drive the SPI in interrupt
204	 * mode.
205	 */
206#if 0
207	struct arspi_softc *sc = device_private(self);
208	int	s;
209
210	s = splbio();
211	sc->sc_interrupts = true;
212	splx(s);
213#endif
214}
215
216int
217arspi_intr(void *arg)
218{
219	struct arspi_softc *sc = arg;
220
221	while (GETREG(sc, ARSPI_REG_CTL) & ARSPI_CTL_BUSY);
222
223	arspi_done(sc, 0);
224
225	return 1;
226}
227
228void
229arspi_poll(struct arspi_softc *sc)
230{
231
232	while (sc->sc_transfer) {
233		arspi_intr(sc);
234	}
235}
236
237int
238arspi_configure(void *cookie, int slave, int mode, int speed)
239{
240
241	/*
242	 * We don't support the full SPI protocol, and hopefully the
243	 * firmware has programmed a reasonable mode already.  So
244	 * just a couple of quick sanity checks, then bail.
245	 */
246	if ((mode != 0) || (slave != 0))
247		return EINVAL;
248
249	return 0;
250}
251
252int
253arspi_transfer(void *cookie, struct spi_transfer *st)
254{
255	struct arspi_softc *sc = cookie;
256	int rv;
257	int s;
258
259	st->st_busprivate = NULL;
260	if ((rv = arspi_make_job(st)) != 0) {
261		if (st->st_busprivate) {
262			free(st->st_busprivate, M_DEVBUF);
263			st->st_busprivate = NULL;
264		}
265		spi_done(st, rv);
266		return rv;
267	}
268
269	s = splbio();
270	spi_transq_enqueue(&sc->sc_transq, st);
271	if (sc->sc_transfer == NULL) {
272		arspi_sched(sc);
273		if (!sc->sc_interrupts)
274			arspi_poll(sc);
275	}
276	splx(s);
277	return 0;
278}
279
280void
281arspi_sched(struct arspi_softc *sc)
282{
283	struct spi_transfer *st;
284	struct arspi_job *job;
285	uint32_t ctl, cnt;
286
287	for (;;) {
288		if ((st = sc->sc_transfer) == NULL) {
289			if ((st = spi_transq_first(&sc->sc_transq)) == NULL) {
290				/* no work left to do */
291				break;
292			}
293			spi_transq_dequeue(&sc->sc_transq);
294			sc->sc_transfer = st;
295		}
296
297		arspi_update_job(st);
298		job = st->st_busprivate;
299
300		/* there shouldn't be anything running, but ensure it */
301		do {
302			ctl = GETREG(sc, ARSPI_REG_CTL);
303		}  while (ctl & ARSPI_CTL_BUSY);
304		/* clear all of the tx and rx bits */
305		ctl &= ~(ARSPI_CTL_TXCNT_MASK | ARSPI_CTL_RXCNT_MASK);
306
307		if (job->job_flags & JOB_WAIT) {
308			PUTREG(sc, ARSPI_REG_OPCODE, SPIFLASH_CMD_RDSR);
309			/* only the opcode for tx */
310			ctl |= (1 << ARSPI_CTL_TXCNT_SHIFT);
311			/* and one rx byte */
312			ctl |= (1 << ARSPI_CTL_RXCNT_SHIFT);
313		} else if (job->job_flags & JOB_WREN) {
314			PUTREG(sc, ARSPI_REG_OPCODE, SPIFLASH_CMD_WREN);
315			/* just the opcode */
316			ctl |= (1 << ARSPI_CTL_TXCNT_SHIFT);
317			/* no rx bytes */
318		} else {
319			/* set the data */
320			PUTREG(sc, ARSPI_REG_DATA, job->job_data);
321
322			/* set the opcode and the address */
323			PUTREG(sc, ARSPI_REG_OPCODE, job->job_opcode |
324			    (job->job_addr << 8));
325
326			/* now set txcnt */
327			cnt = 1;	/* opcode */
328			cnt += job->job_addrcnt + job->job_txcnt;
329			ctl |= (cnt << ARSPI_CTL_TXCNT_SHIFT);
330
331			/* now set rxcnt */
332			cnt = job->job_rxcnt;
333			ctl |= (cnt << ARSPI_CTL_RXCNT_SHIFT);
334		}
335
336		/* set the start bit */
337		ctl |= ARSPI_CTL_START;
338
339		PUTREG(sc, ARSPI_REG_CTL, ctl);
340		break;
341	}
342}
343
344void
345arspi_done(struct arspi_softc *sc, int err)
346{
347	struct spi_transfer *st;
348	struct arspi_job *job;
349
350	if ((st = sc->sc_transfer) != NULL) {
351		job = st->st_busprivate;
352
353		if (job->job_flags & JOB_WAIT) {
354			if (err == 0) {
355				if ((GETREG(sc, ARSPI_REG_DATA) &
356				    SPIFLASH_SR_BUSY) == 0) {
357					/* intermediate wait done */
358					job->job_flags &= ~JOB_WAIT;
359					goto done;
360				}
361			}
362		} else if (job->job_flags & JOB_WREN) {
363			if (err == 0) {
364				job->job_flags &= ~JOB_WREN;
365				goto done;
366			}
367		} else if (err == 0) {
368			/*
369			 * When breaking up write jobs, we have to wait until
370			 * the WIP bit is clear, and we have to separately
371			 * send WREN for each chunk.  These flags facilitate
372			 * that.
373			 */
374			if (job->job_flags & JOB_WRITE)
375				job->job_flags |= (JOB_WAIT | JOB_WREN);
376			job->job_data = GETREG(sc, ARSPI_REG_DATA);
377			arspi_finish_job(st);
378		}
379
380		if (err || (job->job_flags & JOB_LAST)) {
381			sc->sc_transfer = NULL;
382			st->st_busprivate = NULL;
383			spi_done(st, err);
384			free(job, M_DEVBUF);
385		}
386	}
387done:
388	arspi_sched(sc);
389}
390
391int
392arspi_get_byte(struct spi_chunk **chunkp, uint8_t *bytep)
393{
394	struct spi_chunk *chunk;
395
396	chunk = *chunkp;
397
398	/* skip leading empty (or already consumed) chunks */
399	while (chunk && chunk->chunk_wresid == 0)
400		chunk = chunk->chunk_next;
401
402	if (chunk == NULL) {
403		return ENODATA;
404	}
405
406	/*
407	 * chunk must be write only.  SPI flash doesn't support
408	 * any full duplex operations.
409	 */
410	if ((chunk->chunk_rptr) || !(chunk->chunk_wptr)) {
411		return EINVAL;
412	}
413
414	*bytep = *chunk->chunk_wptr;
415	chunk->chunk_wptr++;
416	chunk->chunk_wresid--;
417	chunk->chunk_rresid--;
418	/* clearing wptr and rptr makes sanity checks later easier */
419	if (chunk->chunk_wresid == 0)
420		chunk->chunk_wptr = NULL;
421	if (chunk->chunk_rresid == 0)
422		chunk->chunk_rptr = NULL;
423	while (chunk && chunk->chunk_wresid == 0)
424		chunk = chunk->chunk_next;
425
426	*chunkp = chunk;
427	return 0;
428}
429
430int
431arspi_put_byte(struct spi_chunk **chunkp, uint8_t byte)
432{
433	struct spi_chunk *chunk;
434
435	chunk = *chunkp;
436
437	/* skip leading empty (or already consumed) chunks */
438	while (chunk && chunk->chunk_rresid == 0)
439		chunk = chunk->chunk_next;
440
441	if (chunk == NULL) {
442		return EOVERFLOW;
443	}
444
445	/*
446	 * chunk must be read only.  SPI flash doesn't support
447	 * any full duplex operations.
448	 */
449	if ((chunk->chunk_wptr) || !(chunk->chunk_rptr)) {
450		return EINVAL;
451	}
452
453	*chunk->chunk_rptr = byte;
454	chunk->chunk_rptr++;
455	chunk->chunk_wresid--;	/* technically this was done at send time */
456	chunk->chunk_rresid--;
457	while (chunk && chunk->chunk_rresid == 0)
458		chunk = chunk->chunk_next;
459
460	*chunkp = chunk;
461	return 0;
462}
463
464int
465arspi_make_job(struct spi_transfer *st)
466{
467	struct arspi_job *job;
468	struct spi_chunk *chunk;
469	uint8_t byte;
470	int i, rv;
471
472	job = malloc(sizeof (struct arspi_job), M_DEVBUF, M_ZERO);
473	if (job == NULL) {
474		return ENOMEM;
475	}
476
477	st->st_busprivate = job;
478
479	/* skip any leading empty chunks (should not be any!) */
480	chunk = st->st_chunks;
481
482	/* get transfer opcode */
483	if ((rv = arspi_get_byte(&chunk, &byte)) != 0)
484		return rv;
485
486	job->job_opcode = byte;
487	switch (job->job_opcode) {
488	case SPIFLASH_CMD_WREN:
489	case SPIFLASH_CMD_WRDI:
490	case SPIFLASH_CMD_CHIPERASE:
491		break;
492	case SPIFLASH_CMD_RDJI:
493		job->job_rxcnt = 3;
494		break;
495	case SPIFLASH_CMD_RDSR:
496		job->job_rxcnt = 1;
497		break;
498	case SPIFLASH_CMD_WRSR:
499		/*
500		 * is this in data, or in address?  stick it in data
501		 * for now.
502		 */
503		job->job_txcnt = 1;
504		break;
505	case SPIFLASH_CMD_RDID:
506		job->job_addrcnt = 3;	/* 3 dummy bytes */
507		job->job_rxcnt = 1;
508		break;
509	case SPIFLASH_CMD_ERASE:
510		job->job_addrcnt = 3;
511		break;
512	case SPIFLASH_CMD_READ:
513		job->job_addrcnt = 3;
514		job->job_flags |= JOB_READ;
515		break;
516	case SPIFLASH_CMD_PROGRAM:
517		job->job_addrcnt = 3;
518		job->job_flags |= JOB_WRITE;
519		break;
520	case SPIFLASH_CMD_READFAST:
521		/*
522		 * This is a pain in the arse to support, so we will
523		 * rewrite as an ordinary read.  But later, after we
524		 * obtain the address.
525		 */
526		job->job_addrcnt = 3;	/* 3 address */
527		job->job_flags |= JOB_READ;
528		break;
529	default:
530		return EINVAL;
531	}
532
533	for (i = 0; i < job->job_addrcnt; i++) {
534		if ((rv = arspi_get_byte(&chunk, &byte)) != 0)
535			return rv;
536		job->job_addr <<= 8;
537		job->job_addr |= byte;
538	}
539
540
541	if (job->job_opcode == SPIFLASH_CMD_READFAST) {
542		/* eat the dummy timing byte */
543		if ((rv = arspi_get_byte(&chunk, &byte)) != 0)
544			return rv;
545		/* rewrite this as a read */
546		job->job_opcode = SPIFLASH_CMD_READ;
547	}
548
549	job->job_chunk = chunk;
550
551	/*
552	 * Now quickly check a few other things.   Namely, we are not
553	 * allowed to have both READ and WRITE.
554	 */
555	for (chunk = job->job_chunk; chunk; chunk = chunk->chunk_next) {
556		if (chunk->chunk_wptr) {
557			job->job_wresid += chunk->chunk_wresid;
558		}
559		if (chunk->chunk_rptr) {
560			job->job_rresid += chunk->chunk_rresid;
561		}
562	}
563
564	if (job->job_rresid && job->job_wresid) {
565		return EINVAL;
566	}
567
568	return 0;
569}
570
571/*
572 * NB: The Atheros SPI controller runs in little endian mode. So all
573 * data accesses must be swapped appropriately.
574 *
575 * The controller auto-swaps read accesses done through the mapped memory
576 * region, but when using SPI directly, we have to do the right thing to
577 * swap to or from little endian.
578 */
579
580void
581arspi_update_job(struct spi_transfer *st)
582{
583	struct arspi_job *job = st->st_busprivate;
584	uint8_t byte;
585	int i;
586
587	if (job->job_flags & (JOB_WAIT|JOB_WREN))
588		return;
589
590	job->job_rxcnt = 0;
591	job->job_txcnt = 0;
592	job->job_data = 0;
593
594	job->job_txcnt = min(job->job_wresid, 4);
595	job->job_rxcnt = min(job->job_rresid, 4);
596
597	job->job_wresid -= job->job_txcnt;
598	job->job_rresid -= job->job_rxcnt;
599
600	for (i = 0; i < job->job_txcnt; i++) {
601		arspi_get_byte(&job->job_chunk, &byte);
602		job->job_data |= (byte << (i * 8));
603	}
604
605	if ((!job->job_wresid) && (!job->job_rresid)) {
606		job->job_flags |= JOB_LAST;
607	}
608}
609
610void
611arspi_finish_job(struct spi_transfer *st)
612{
613	struct arspi_job *job = st->st_busprivate;
614	uint8_t	byte;
615	int i;
616
617	job->job_addr += job->job_rxcnt;
618	job->job_addr += job->job_txcnt;
619	for (i = 0; i < job->job_rxcnt; i++) {
620		byte = job->job_data & 0xff;
621		job->job_data >>= 8;
622		arspi_put_byte(&job->job_chunk, byte);
623	}
624}
625
626