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