Home | History | Annotate | Line # | Download | only in marvell
mvspi.c revision 1.2.4.2
      1  1.2.4.2  tls /*******************************************************************************
      2  1.2.4.2  tls Copyright (C) Marvell International Ltd. and its affiliates
      3  1.2.4.2  tls 
      4  1.2.4.2  tls Developed by Semihalf
      5  1.2.4.2  tls 
      6  1.2.4.2  tls ********************************************************************************
      7  1.2.4.2  tls Marvell BSD License
      8  1.2.4.2  tls 
      9  1.2.4.2  tls If you received this File from Marvell, you may opt to use, redistribute and/or
     10  1.2.4.2  tls modify this File under the following licensing terms.
     11  1.2.4.2  tls Redistribution and use in source and binary forms, with or without modification,
     12  1.2.4.2  tls are permitted provided that the following conditions are met:
     13  1.2.4.2  tls 
     14  1.2.4.2  tls     *   Redistributions of source code must retain the above copyright notice,
     15  1.2.4.2  tls             this list of conditions and the following disclaimer.
     16  1.2.4.2  tls 
     17  1.2.4.2  tls     *   Redistributions in binary form must reproduce the above copyright
     18  1.2.4.2  tls         notice, this list of conditions and the following disclaimer in the
     19  1.2.4.2  tls         documentation and/or other materials provided with the distribution.
     20  1.2.4.2  tls 
     21  1.2.4.2  tls     *   Neither the name of Marvell nor the names of its contributors may be
     22  1.2.4.2  tls         used to endorse or promote products derived from this software without
     23  1.2.4.2  tls         specific prior written permission.
     24  1.2.4.2  tls 
     25  1.2.4.2  tls THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
     26  1.2.4.2  tls ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     27  1.2.4.2  tls WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     28  1.2.4.2  tls DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
     29  1.2.4.2  tls ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     30  1.2.4.2  tls (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     31  1.2.4.2  tls LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
     32  1.2.4.2  tls ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     33  1.2.4.2  tls (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     34  1.2.4.2  tls SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     35  1.2.4.2  tls 
     36  1.2.4.2  tls *******************************************************************************/
     37  1.2.4.2  tls 
     38  1.2.4.2  tls /*
     39  1.2.4.2  tls  * Transfer mechanism extracted from arspi.c corresponding with the lines
     40  1.2.4.2  tls  * 254-262 in this file.
     41  1.2.4.2  tls  */
     42  1.2.4.2  tls 
     43  1.2.4.2  tls #include <sys/param.h>
     44  1.2.4.2  tls #include <sys/device.h>
     45  1.2.4.2  tls 
     46  1.2.4.2  tls #include <dev/spi/spivar.h>
     47  1.2.4.2  tls 
     48  1.2.4.2  tls #include <dev/marvell/mvspireg.h>
     49  1.2.4.2  tls #include <dev/marvell/marvellvar.h>
     50  1.2.4.2  tls 
     51  1.2.4.2  tls #include "locators.h"
     52  1.2.4.2  tls 
     53  1.2.4.2  tls extern uint32_t mvTclk;
     54  1.2.4.2  tls 
     55  1.2.4.2  tls struct mvspi_softc {
     56  1.2.4.2  tls 	struct device		sc_dev;
     57  1.2.4.2  tls 	struct spi_controller	sc_spi;
     58  1.2.4.2  tls 	void			*sc_ih;
     59  1.2.4.2  tls 	bool			sc_interrupts;
     60  1.2.4.2  tls 
     61  1.2.4.2  tls 	struct spi_transfer	*sc_transfer;
     62  1.2.4.2  tls 	struct spi_chunk	*sc_wchunk;	/* For partial writes */
     63  1.2.4.2  tls 	struct spi_transq	sc_transq;
     64  1.2.4.2  tls 	bus_space_tag_t		sc_st;
     65  1.2.4.2  tls 	bus_space_handle_t	sc_sh;
     66  1.2.4.2  tls 	bus_size_t		sc_size;
     67  1.2.4.2  tls };
     68  1.2.4.2  tls 
     69  1.2.4.2  tls int mvspi_match(struct device *, struct cfdata *, void *);
     70  1.2.4.2  tls void mvspi_attach(struct device *, struct device *, void *);
     71  1.2.4.2  tls /* SPI service routines */
     72  1.2.4.2  tls int mvspi_configure(void *, int, int, int);
     73  1.2.4.2  tls int mvspi_transfer(void *, struct spi_transfer *);
     74  1.2.4.2  tls /* Internal support */
     75  1.2.4.2  tls void mvspi_sched(struct mvspi_softc *);
     76  1.2.4.2  tls void mvspi_assert(struct mvspi_softc *sc);
     77  1.2.4.2  tls void mvspi_deassert(struct mvspi_softc *sc);
     78  1.2.4.2  tls 
     79  1.2.4.2  tls #define	GETREG(sc, x)					\
     80  1.2.4.2  tls 	bus_space_read_4(sc->sc_st, sc->sc_sh, x)
     81  1.2.4.2  tls #define	PUTREG(sc, x, v)				\
     82  1.2.4.2  tls 	bus_space_write_4(sc->sc_st, sc->sc_sh, x, v)
     83  1.2.4.2  tls 
     84  1.2.4.2  tls /* Attach structure */
     85  1.2.4.2  tls CFATTACH_DECL_NEW(mvspi_mbus, sizeof(struct mvspi_softc),
     86  1.2.4.2  tls     mvspi_match, mvspi_attach, NULL, NULL);
     87  1.2.4.2  tls 
     88  1.2.4.2  tls int
     89  1.2.4.2  tls mvspi_match(struct device *parent, struct cfdata *cf, void *aux)
     90  1.2.4.2  tls {
     91  1.2.4.2  tls 	struct marvell_attach_args *mva = aux;
     92  1.2.4.2  tls 
     93  1.2.4.2  tls 	if (strcmp(mva->mva_name, cf->cf_name) != 0)
     94  1.2.4.2  tls 		return 0;
     95  1.2.4.2  tls 	if (mva->mva_offset == MVA_OFFSET_DEFAULT ||
     96  1.2.4.2  tls 	    mva->mva_irq == MVA_IRQ_DEFAULT)
     97  1.2.4.2  tls 		return 0;
     98  1.2.4.2  tls 
     99  1.2.4.2  tls 	mva->mva_size = MVSPI_SIZE;
    100  1.2.4.2  tls 	return 1;
    101  1.2.4.2  tls }
    102  1.2.4.2  tls 
    103  1.2.4.2  tls void
    104  1.2.4.2  tls mvspi_attach(struct device *parent, struct device *self, void *aux)
    105  1.2.4.2  tls {
    106  1.2.4.2  tls 	struct mvspi_softc *sc =  device_private(self);
    107  1.2.4.2  tls   	struct marvell_attach_args *mva = aux;
    108  1.2.4.2  tls 	struct spibus_attach_args sba;
    109  1.2.4.2  tls 	int ctl;
    110  1.2.4.2  tls 
    111  1.2.4.2  tls 	aprint_normal(": Marvell SPI controller\n");
    112  1.2.4.2  tls 
    113  1.2.4.2  tls 	/*
    114  1.2.4.2  tls 	 * Map registers.
    115  1.2.4.2  tls 	 */
    116  1.2.4.2  tls 	sc->sc_st = mva->mva_iot;
    117  1.2.4.2  tls 	sc->sc_size = mva->mva_size;
    118  1.2.4.2  tls 
    119  1.2.4.2  tls 	if (bus_space_subregion(sc->sc_st, mva->mva_ioh, mva->mva_offset,
    120  1.2.4.2  tls 	    mva->mva_size, &sc->sc_sh)) {
    121  1.2.4.2  tls 		aprint_error_dev(self, "Cannot map registers\n");
    122  1.2.4.2  tls 		return;
    123  1.2.4.2  tls 	}
    124  1.2.4.2  tls 
    125  1.2.4.2  tls 	/*
    126  1.2.4.2  tls 	 * Initialize hardware.
    127  1.2.4.2  tls 	 */
    128  1.2.4.2  tls 	ctl = GETREG(sc, MVSPI_INTCONF_REG);
    129  1.2.4.2  tls 
    130  1.2.4.2  tls 	ctl &= MVSPI_DIRHS_MASK;
    131  1.2.4.2  tls 	ctl &= MVSPI_1BYTE_MASK;
    132  1.2.4.2  tls 
    133  1.2.4.2  tls 	PUTREG(sc, MVSPI_INTCONF_REG, ctl),
    134  1.2.4.2  tls 
    135  1.2.4.2  tls 	/*
    136  1.2.4.2  tls 	 * Initialize SPI controller.
    137  1.2.4.2  tls 	 */
    138  1.2.4.2  tls 	sc->sc_spi.sct_cookie = sc;
    139  1.2.4.2  tls 	sc->sc_spi.sct_configure = mvspi_configure;
    140  1.2.4.2  tls 	sc->sc_spi.sct_transfer = mvspi_transfer;
    141  1.2.4.2  tls 	sc->sc_spi.sct_nslaves = 1;
    142  1.2.4.2  tls 
    143  1.2.4.2  tls 	/*
    144  1.2.4.2  tls 	 * Initialize the queue.
    145  1.2.4.2  tls 	 */
    146  1.2.4.2  tls 	spi_transq_init(&sc->sc_transq);
    147  1.2.4.2  tls 
    148  1.2.4.2  tls 	/*
    149  1.2.4.2  tls 	 * Initialize and attach bus attach.
    150  1.2.4.2  tls 	 */
    151  1.2.4.2  tls 	sba.sba_controller = &sc->sc_spi;
    152  1.2.4.2  tls 	(void) config_found_ia(self, "spibus", &sba, spibus_print);
    153  1.2.4.2  tls }
    154  1.2.4.2  tls 
    155  1.2.4.2  tls int
    156  1.2.4.2  tls mvspi_configure(void *cookie, int slave, int mode, int speed)
    157  1.2.4.2  tls {
    158  1.2.4.2  tls 	struct mvspi_softc *sc = cookie;
    159  1.2.4.2  tls 	uint32_t ctl = 0, spr, sppr;
    160  1.2.4.2  tls 	uint32_t divider;
    161  1.2.4.2  tls 	uint32_t best_spr = 0, best_sppr = 0;
    162  1.2.4.2  tls 	uint32_t best_sppr0, best_spprhi;
    163  1.2.4.2  tls 	uint8_t exact_match = 0;
    164  1.2.4.2  tls 	uint32_t min_baud_offset = 0xFFFFFFFF;
    165  1.2.4.2  tls 
    166  1.2.4.2  tls 	if (slave < 0 || slave > 7)
    167  1.2.4.2  tls 		return EINVAL;
    168  1.2.4.2  tls 
    169  1.2.4.2  tls 	switch(mode) {
    170  1.2.4.2  tls 		case SPI_MODE_0:
    171  1.2.4.2  tls 			ctl &= ~(MVSPI_CPOL_MASK);
    172  1.2.4.2  tls 			/* In boards documentation, CPHA is inverted */
    173  1.2.4.2  tls 			ctl &= MVSPI_CPHA_MASK;
    174  1.2.4.2  tls 			break;
    175  1.2.4.2  tls 		case SPI_MODE_1:
    176  1.2.4.2  tls 			ctl |= MVSPI_CPOL_MASK;
    177  1.2.4.2  tls 			ctl &= MVSPI_CPHA_MASK;
    178  1.2.4.2  tls 			break;
    179  1.2.4.2  tls 		case SPI_MODE_2:
    180  1.2.4.2  tls 			ctl &= ~(MVSPI_CPOL_MASK);
    181  1.2.4.2  tls 			ctl |= ~(MVSPI_CPHA_MASK);
    182  1.2.4.2  tls 			break;
    183  1.2.4.2  tls 		case SPI_MODE_3:
    184  1.2.4.2  tls 			ctl |= MVSPI_CPOL_MASK;
    185  1.2.4.2  tls 			ctl |= ~(MVSPI_CPHA_MASK);
    186  1.2.4.2  tls 			break;
    187  1.2.4.2  tls 		default:
    188  1.2.4.2  tls 			return EINVAL;
    189  1.2.4.2  tls 	}
    190  1.2.4.2  tls 
    191  1.2.4.2  tls 	/* Find the best prescale configuration - less or equal:
    192  1.2.4.2  tls 	 * SPI actual frecuency = core_clk / (SPR * (2 ^ SPPR))
    193  1.2.4.2  tls 	 * Try to find the minimal SPR and SPPR values that offer
    194  1.2.4.2  tls 	 * the best prescale config.
    195  1.2.4.2  tls 	 *
    196  1.2.4.2  tls 	 */
    197  1.2.4.2  tls 	for (spr = 1; spr <= MVSPI_SPR_MAXVALUE; spr++) {
    198  1.2.4.2  tls 		for (sppr = 0; sppr <= MVSPI_SPPR_MAXVALUE; sppr++) {
    199  1.2.4.2  tls 			divider = spr * (1 << sppr);
    200  1.2.4.2  tls 			/* Check for higher - irrelevant */
    201  1.2.4.2  tls 			if ((mvTclk / divider) > speed)
    202  1.2.4.2  tls 				continue;
    203  1.2.4.2  tls 
    204  1.2.4.2  tls 			/* Check for exact fit */
    205  1.2.4.2  tls 			if ((mvTclk / divider) == speed) {
    206  1.2.4.2  tls 				best_spr = spr;
    207  1.2.4.2  tls 				best_sppr = sppr;
    208  1.2.4.2  tls 				exact_match = 1;
    209  1.2.4.2  tls 				break;
    210  1.2.4.2  tls 			}
    211  1.2.4.2  tls 
    212  1.2.4.2  tls 			/* Check if this is better than the previous one */
    213  1.2.4.2  tls 			if ((speed - (mvTclk / divider)) < min_baud_offset) {
    214  1.2.4.2  tls 				min_baud_offset = (speed - (mvTclk / divider));
    215  1.2.4.2  tls 				best_spr = spr;
    216  1.2.4.2  tls 				best_sppr = sppr;
    217  1.2.4.2  tls 			}
    218  1.2.4.2  tls 		}
    219  1.2.4.2  tls 
    220  1.2.4.2  tls 		if (exact_match == 1)
    221  1.2.4.2  tls 			break;
    222  1.2.4.2  tls 	}
    223  1.2.4.2  tls 
    224  1.2.4.2  tls 	if (best_spr == 0) {
    225  1.2.4.2  tls 		printf("%s ERROR: SPI baud rate prescale error!\n", __func__);
    226  1.2.4.2  tls 		return -1;
    227  1.2.4.2  tls 	}
    228  1.2.4.2  tls 
    229  1.2.4.2  tls 	ctl &= ~(MVSPI_SPR_MASK);
    230  1.2.4.2  tls 	ctl &= ~(MVSPI_SPPR_MASK);
    231  1.2.4.2  tls 	ctl |= best_spr;
    232  1.2.4.2  tls 
    233  1.2.4.2  tls 	best_spprhi = best_sppr & MVSPI_SPPRHI_MASK;
    234  1.2.4.2  tls 	best_spprhi = best_spprhi << 5;
    235  1.2.4.2  tls 
    236  1.2.4.2  tls 	ctl |= best_spprhi;
    237  1.2.4.2  tls 
    238  1.2.4.2  tls 	best_sppr0 = best_sppr & MVSPI_SPPR0_MASK;
    239  1.2.4.2  tls 	best_sppr0 = best_sppr0 << 4;
    240  1.2.4.2  tls 
    241  1.2.4.2  tls 	ctl |= best_sppr0;
    242  1.2.4.2  tls 
    243  1.2.4.2  tls 	PUTREG(sc, MVSPI_INTCONF_REG, ctl);
    244  1.2.4.2  tls 
    245  1.2.4.2  tls 	return 0;
    246  1.2.4.2  tls }
    247  1.2.4.2  tls 
    248  1.2.4.2  tls int
    249  1.2.4.2  tls mvspi_transfer(void *cookie, struct spi_transfer *st)
    250  1.2.4.2  tls {
    251  1.2.4.2  tls 	struct mvspi_softc *sc = cookie;
    252  1.2.4.2  tls 	int s;
    253  1.2.4.2  tls 
    254  1.2.4.2  tls 	s = splbio();
    255  1.2.4.2  tls 	spi_transq_enqueue(&sc->sc_transq, st);
    256  1.2.4.2  tls 	if (sc->sc_transfer == NULL) {
    257  1.2.4.2  tls 		mvspi_sched(sc);
    258  1.2.4.2  tls 	}
    259  1.2.4.2  tls 	splx(s);
    260  1.2.4.2  tls 	return 0;
    261  1.2.4.2  tls }
    262  1.2.4.2  tls 
    263  1.2.4.2  tls void
    264  1.2.4.2  tls mvspi_assert(struct mvspi_softc *sc)
    265  1.2.4.2  tls {
    266  1.2.4.2  tls 	int ctl;
    267  1.2.4.2  tls 
    268  1.2.4.2  tls 	if (sc->sc_transfer->st_slave < 0 && sc->sc_transfer->st_slave > 7) {
    269  1.2.4.2  tls 		printf("%s ERROR: Slave number %d not valid!\n",  __func__, sc->sc_transfer->st_slave);
    270  1.2.4.2  tls 		return;
    271  1.2.4.2  tls 	} else
    272  1.2.4.2  tls 		/* Enable appropriate CSn according to its slave number */
    273  1.2.4.2  tls 		PUTREG(sc, MVSPI_CTRL_REG, (sc->sc_transfer->st_slave << 2));
    274  1.2.4.2  tls 
    275  1.2.4.2  tls 	/* Enable CSnAct */
    276  1.2.4.2  tls 	ctl = GETREG(sc, MVSPI_CTRL_REG);
    277  1.2.4.2  tls 	ctl |= MVSPI_CSNACT_MASK;
    278  1.2.4.2  tls 	PUTREG(sc, MVSPI_CTRL_REG, ctl);
    279  1.2.4.2  tls }
    280  1.2.4.2  tls 
    281  1.2.4.2  tls void
    282  1.2.4.2  tls mvspi_deassert(struct mvspi_softc *sc)
    283  1.2.4.2  tls {
    284  1.2.4.2  tls 	int ctl = GETREG(sc, MVSPI_CTRL_REG);
    285  1.2.4.2  tls 	ctl &= ~(MVSPI_CSNACT_MASK);
    286  1.2.4.2  tls 	PUTREG(sc, MVSPI_CTRL_REG, ctl);
    287  1.2.4.2  tls }
    288  1.2.4.2  tls 
    289  1.2.4.2  tls void
    290  1.2.4.2  tls mvspi_sched(struct mvspi_softc *sc)
    291  1.2.4.2  tls {
    292  1.2.4.2  tls 	struct spi_transfer *st;
    293  1.2.4.2  tls 	struct spi_chunk *chunk;
    294  1.2.4.2  tls 	int i, j, ctl;
    295  1.2.4.2  tls 	uint8_t byte;
    296  1.2.4.2  tls 	int ready = FALSE;
    297  1.2.4.2  tls 
    298  1.2.4.2  tls 	for (;;) {
    299  1.2.4.2  tls 		if ((st = sc->sc_transfer) == NULL) {
    300  1.2.4.2  tls 			if ((st = spi_transq_first(&sc->sc_transq)) == NULL) {
    301  1.2.4.2  tls 				/* No work left to do */
    302  1.2.4.2  tls 				break;
    303  1.2.4.2  tls 			}
    304  1.2.4.2  tls 			spi_transq_dequeue(&sc->sc_transq);
    305  1.2.4.2  tls 			sc->sc_transfer = st;
    306  1.2.4.2  tls 		}
    307  1.2.4.2  tls 
    308  1.2.4.2  tls 		chunk = st->st_chunks;
    309  1.2.4.2  tls 
    310  1.2.4.2  tls 		mvspi_assert(sc);
    311  1.2.4.2  tls 
    312  1.2.4.2  tls 		do {
    313  1.2.4.2  tls 			for (i = chunk->chunk_wresid; i > 0; i--) {
    314  1.2.4.2  tls 				/* First clear the ready bit */
    315  1.2.4.2  tls 				ctl = GETREG(sc, MVSPI_CTRL_REG);
    316  1.2.4.2  tls 				ctl &= ~(MVSPI_CR_SMEMRDY);
    317  1.2.4.2  tls 				PUTREG(sc, MVSPI_CTRL_REG, ctl);
    318  1.2.4.2  tls 
    319  1.2.4.2  tls 				if (chunk->chunk_wptr){
    320  1.2.4.2  tls 					byte = *chunk->chunk_wptr;
    321  1.2.4.2  tls 					chunk->chunk_wptr++;
    322  1.2.4.2  tls 				} else
    323  1.2.4.2  tls 					byte = MVSPI_DUMMY_BYTE;
    324  1.2.4.2  tls 
    325  1.2.4.2  tls 				/* Transmit data */
    326  1.2.4.2  tls 				PUTREG(sc, MVSPI_DATAOUT_REG, byte);
    327  1.2.4.2  tls 
    328  1.2.4.2  tls 				/* Wait with timeout for memory ready */
    329  1.2.4.2  tls 				for (j = 0; j < MVSPI_WAIT_RDY_MAX_LOOP; j++) {
    330  1.2.4.2  tls 					if (GETREG(sc, MVSPI_CTRL_REG) &
    331  1.2.4.2  tls 						MVSPI_CR_SMEMRDY) {
    332  1.2.4.2  tls 						ready = TRUE;
    333  1.2.4.2  tls 						break;
    334  1.2.4.2  tls 					}
    335  1.2.4.2  tls 
    336  1.2.4.2  tls 				}
    337  1.2.4.2  tls 
    338  1.2.4.2  tls 				if (!ready) {
    339  1.2.4.2  tls 					mvspi_deassert(sc);
    340  1.2.4.2  tls 					spi_done(st, EBUSY);
    341  1.2.4.2  tls 					return;
    342  1.2.4.2  tls 				}
    343  1.2.4.2  tls 
    344  1.2.4.2  tls 				/* Check that the RX data is needed */
    345  1.2.4.2  tls 				if (chunk->chunk_rptr) {
    346  1.2.4.2  tls 					*chunk->chunk_rptr =
    347  1.2.4.2  tls 						GETREG(sc, MVSPI_DATAIN_REG);
    348  1.2.4.2  tls 					chunk->chunk_rptr++;
    349  1.2.4.2  tls 
    350  1.2.4.2  tls 				}
    351  1.2.4.2  tls 
    352  1.2.4.2  tls 			}
    353  1.2.4.2  tls 
    354  1.2.4.2  tls 			chunk = chunk->chunk_next;
    355  1.2.4.2  tls 
    356  1.2.4.2  tls 		} while (chunk != NULL);
    357  1.2.4.2  tls 
    358  1.2.4.2  tls 		mvspi_deassert(sc);
    359  1.2.4.2  tls 
    360  1.2.4.2  tls 		spi_done(st, 0);
    361  1.2.4.2  tls 		sc->sc_transfer = NULL;
    362  1.2.4.2  tls 
    363  1.2.4.2  tls 
    364  1.2.4.2  tls 		break;
    365  1.2.4.2  tls 	}
    366  1.2.4.2  tls }
    367