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