[BACK]Return to mvspi.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / marvell

Annotation of src/sys/dev/marvell/mvspi.c, Revision 1.5.10.1

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

CVSweb <webmaster@jp.NetBSD.org>