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