uboot/drivers/spi/cf_spi.c
<<
>>
Prefs
   1/*
   2 *
   3 * (C) Copyright 2000-2003
   4 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
   5 *
   6 * Copyright (C) 2004-2009 Freescale Semiconductor, Inc.
   7 * TsiChung Liew (Tsi-Chung.Liew@freescale.com)
   8 *
   9 * SPDX-License-Identifier:     GPL-2.0+
  10 */
  11
  12#include <common.h>
  13#include <spi.h>
  14#include <malloc.h>
  15#include <asm/immap.h>
  16
  17struct cf_spi_slave {
  18        struct spi_slave slave;
  19        uint baudrate;
  20        int charbit;
  21};
  22
  23extern void cfspi_port_conf(void);
  24extern int cfspi_claim_bus(uint bus, uint cs);
  25extern void cfspi_release_bus(uint bus, uint cs);
  26
  27DECLARE_GLOBAL_DATA_PTR;
  28
  29#ifndef CONFIG_SPI_IDLE_VAL
  30#if defined(CONFIG_SPI_MMC)
  31#define CONFIG_SPI_IDLE_VAL     0xFFFF
  32#else
  33#define CONFIG_SPI_IDLE_VAL     0x0
  34#endif
  35#endif
  36
  37#if defined(CONFIG_CF_DSPI)
  38/* DSPI specific mode */
  39#define SPI_MODE_MOD    0x00200000
  40#define SPI_DBLRATE     0x00100000
  41
  42static inline struct cf_spi_slave *to_cf_spi_slave(struct spi_slave *slave)
  43{
  44        return container_of(slave, struct cf_spi_slave, slave);
  45}
  46
  47static void cfspi_init(void)
  48{
  49        volatile dspi_t *dspi = (dspi_t *) MMAP_DSPI;
  50
  51        cfspi_port_conf();      /* port configuration */
  52
  53        dspi->mcr = DSPI_MCR_MSTR | DSPI_MCR_CSIS7 | DSPI_MCR_CSIS6 |
  54            DSPI_MCR_CSIS5 | DSPI_MCR_CSIS4 | DSPI_MCR_CSIS3 |
  55            DSPI_MCR_CSIS2 | DSPI_MCR_CSIS1 | DSPI_MCR_CSIS0 |
  56            DSPI_MCR_CRXF | DSPI_MCR_CTXF;
  57
  58        /* Default setting in platform configuration */
  59#ifdef CONFIG_SYS_DSPI_CTAR0
  60        dspi->ctar[0] = CONFIG_SYS_DSPI_CTAR0;
  61#endif
  62#ifdef CONFIG_SYS_DSPI_CTAR1
  63        dspi->ctar[1] = CONFIG_SYS_DSPI_CTAR1;
  64#endif
  65#ifdef CONFIG_SYS_DSPI_CTAR2
  66        dspi->ctar[2] = CONFIG_SYS_DSPI_CTAR2;
  67#endif
  68#ifdef CONFIG_SYS_DSPI_CTAR3
  69        dspi->ctar[3] = CONFIG_SYS_DSPI_CTAR3;
  70#endif
  71#ifdef CONFIG_SYS_DSPI_CTAR4
  72        dspi->ctar[4] = CONFIG_SYS_DSPI_CTAR4;
  73#endif
  74#ifdef CONFIG_SYS_DSPI_CTAR5
  75        dspi->ctar[5] = CONFIG_SYS_DSPI_CTAR5;
  76#endif
  77#ifdef CONFIG_SYS_DSPI_CTAR6
  78        dspi->ctar[6] = CONFIG_SYS_DSPI_CTAR6;
  79#endif
  80#ifdef CONFIG_SYS_DSPI_CTAR7
  81        dspi->ctar[7] = CONFIG_SYS_DSPI_CTAR7;
  82#endif
  83}
  84
  85static void cfspi_tx(u32 ctrl, u16 data)
  86{
  87        volatile dspi_t *dspi = (dspi_t *) MMAP_DSPI;
  88
  89        while ((dspi->sr & 0x0000F000) >= 4) ;
  90
  91        dspi->tfr = (ctrl | data);
  92}
  93
  94static u16 cfspi_rx(void)
  95{
  96        volatile dspi_t *dspi = (dspi_t *) MMAP_DSPI;
  97
  98        while ((dspi->sr & 0x000000F0) == 0) ;
  99
 100        return (dspi->rfr & 0xFFFF);
 101}
 102
 103static int cfspi_xfer(struct spi_slave *slave, uint bitlen, const void *dout,
 104                      void *din, ulong flags)
 105{
 106        struct cf_spi_slave *cfslave = to_cf_spi_slave(slave);
 107        u16 *spi_rd16 = NULL, *spi_wr16 = NULL;
 108        u8 *spi_rd = NULL, *spi_wr = NULL;
 109        static u32 ctrl = 0;
 110        uint len = bitlen >> 3;
 111
 112        if (cfslave->charbit == 16) {
 113                bitlen >>= 1;
 114                spi_wr16 = (u16 *) dout;
 115                spi_rd16 = (u16 *) din;
 116        } else {
 117                spi_wr = (u8 *) dout;
 118                spi_rd = (u8 *) din;
 119        }
 120
 121        if ((flags & SPI_XFER_BEGIN) == SPI_XFER_BEGIN)
 122                ctrl |= DSPI_TFR_CONT;
 123
 124        ctrl = (ctrl & 0xFF000000) | ((1 << slave->cs) << 16);
 125
 126        if (len > 1) {
 127                int tmp_len = len - 1;
 128                while (tmp_len--) {
 129                        if (dout != NULL) {
 130                                if (cfslave->charbit == 16)
 131                                        cfspi_tx(ctrl, *spi_wr16++);
 132                                else
 133                                        cfspi_tx(ctrl, *spi_wr++);
 134                                cfspi_rx();
 135                        }
 136
 137                        if (din != NULL) {
 138                                cfspi_tx(ctrl, CONFIG_SPI_IDLE_VAL);
 139                                if (cfslave->charbit == 16)
 140                                        *spi_rd16++ = cfspi_rx();
 141                                else
 142                                        *spi_rd++ = cfspi_rx();
 143                        }
 144                }
 145
 146                len = 1;        /* remaining byte */
 147        }
 148
 149        if ((flags & SPI_XFER_END) == SPI_XFER_END)
 150                ctrl &= ~DSPI_TFR_CONT;
 151
 152        if (len) {
 153                if (dout != NULL) {
 154                        if (cfslave->charbit == 16)
 155                                cfspi_tx(ctrl, *spi_wr16);
 156                        else
 157                                cfspi_tx(ctrl, *spi_wr);
 158                        cfspi_rx();
 159                }
 160
 161                if (din != NULL) {
 162                        cfspi_tx(ctrl, CONFIG_SPI_IDLE_VAL);
 163                        if (cfslave->charbit == 16)
 164                                *spi_rd16 = cfspi_rx();
 165                        else
 166                                *spi_rd = cfspi_rx();
 167                }
 168        } else {
 169                /* dummy read */
 170                cfspi_tx(ctrl, CONFIG_SPI_IDLE_VAL);
 171                cfspi_rx();
 172        }
 173
 174        return 0;
 175}
 176
 177static struct spi_slave *cfspi_setup_slave(struct cf_spi_slave *cfslave,
 178                                           uint mode)
 179{
 180        /*
 181         * bit definition for mode:
 182         * bit 31 - 28: Transfer size 3 to 16 bits
 183         *     27 - 26: PCS to SCK delay prescaler
 184         *     25 - 24: After SCK delay prescaler
 185         *     23 - 22: Delay after transfer prescaler
 186         *     21     : Allow overwrite for bit 31-22 and bit 20-8
 187         *     20     : Double baud rate
 188         *     19 - 16: PCS to SCK delay scaler
 189         *     15 - 12: After SCK delay scaler
 190         *     11 -  8: Delay after transfer scaler
 191         *      7 -  0: SPI_CPHA, SPI_CPOL, SPI_LSB_FIRST
 192         */
 193        volatile dspi_t *dspi = (dspi_t *) MMAP_DSPI;
 194        int prescaler[] = { 2, 3, 5, 7 };
 195        int scaler[] = {
 196                2, 4, 6, 8,
 197                16, 32, 64, 128,
 198                256, 512, 1024, 2048,
 199                4096, 8192, 16384, 32768
 200        };
 201        int i, j, pbrcnt, brcnt, diff, tmp, dbr = 0;
 202        int best_i, best_j, bestmatch = 0x7FFFFFFF, baud_speed;
 203        u32 bus_setup = 0;
 204
 205        tmp = (prescaler[3] * scaler[15]);
 206        /* Maximum and minimum baudrate it can handle */
 207        if ((cfslave->baudrate > (gd->bus_clk >> 1)) ||
 208            (cfslave->baudrate < (gd->bus_clk / tmp))) {
 209                printf("Exceed baudrate limitation: Max %d - Min %d\n",
 210                       (int)(gd->bus_clk >> 1), (int)(gd->bus_clk / tmp));
 211                return NULL;
 212        }
 213
 214        /* Activate Double Baud when it exceed 1/4 the bus clk */
 215        if ((CONFIG_SYS_DSPI_CTAR0 & DSPI_CTAR_DBR) ||
 216            (cfslave->baudrate > (gd->bus_clk / (prescaler[0] * scaler[0])))) {
 217                bus_setup |= DSPI_CTAR_DBR;
 218                dbr = 1;
 219        }
 220
 221        if (mode & SPI_CPOL)
 222                bus_setup |= DSPI_CTAR_CPOL;
 223        if (mode & SPI_CPHA)
 224                bus_setup |= DSPI_CTAR_CPHA;
 225        if (mode & SPI_LSB_FIRST)
 226                bus_setup |= DSPI_CTAR_LSBFE;
 227
 228        /* Overwrite default value set in platform configuration file */
 229        if (mode & SPI_MODE_MOD) {
 230
 231                if ((mode & 0xF0000000) == 0)
 232                        bus_setup |=
 233                            dspi->ctar[cfslave->slave.bus] & 0x78000000;
 234                else
 235                        bus_setup |= ((mode & 0xF0000000) >> 1);
 236
 237                /*
 238                 * Check to see if it is enabled by default in platform
 239                 * config, or manual setting passed by mode parameter
 240                 */
 241                if (mode & SPI_DBLRATE) {
 242                        bus_setup |= DSPI_CTAR_DBR;
 243                        dbr = 1;
 244                }
 245                bus_setup |= (mode & 0x0FC00000) >> 4;  /* PSCSCK, PASC, PDT */
 246                bus_setup |= (mode & 0x000FFF00) >> 4;  /* CSSCK, ASC, DT */
 247        } else
 248                bus_setup |= (dspi->ctar[cfslave->slave.bus] & 0x78FCFFF0);
 249
 250        cfslave->charbit =
 251            ((dspi->ctar[cfslave->slave.bus] & 0x78000000) ==
 252             0x78000000) ? 16 : 8;
 253
 254        pbrcnt = sizeof(prescaler) / sizeof(int);
 255        brcnt = sizeof(scaler) / sizeof(int);
 256
 257        /* baudrate calculation - to closer value, may not be exact match */
 258        for (best_i = 0, best_j = 0, i = 0; i < pbrcnt; i++) {
 259                baud_speed = gd->bus_clk / prescaler[i];
 260                for (j = 0; j < brcnt; j++) {
 261                        tmp = (baud_speed / scaler[j]) * (1 + dbr);
 262
 263                        if (tmp > cfslave->baudrate)
 264                                diff = tmp - cfslave->baudrate;
 265                        else
 266                                diff = cfslave->baudrate - tmp;
 267
 268                        if (diff < bestmatch) {
 269                                bestmatch = diff;
 270                                best_i = i;
 271                                best_j = j;
 272                        }
 273                }
 274        }
 275        bus_setup |= (DSPI_CTAR_PBR(best_i) | DSPI_CTAR_BR(best_j));
 276        dspi->ctar[cfslave->slave.bus] = bus_setup;
 277
 278        return &cfslave->slave;
 279}
 280#endif                          /* CONFIG_CF_DSPI */
 281
 282#ifdef CONFIG_CMD_SPI
 283int spi_cs_is_valid(unsigned int bus, unsigned int cs)
 284{
 285        if (((cs >= 0) && (cs < 8)) && ((bus >= 0) && (bus < 8)))
 286                return 1;
 287        else
 288                return 0;
 289}
 290
 291void spi_init_f(void)
 292{
 293}
 294
 295void spi_init_r(void)
 296{
 297}
 298
 299void spi_init(void)
 300{
 301        cfspi_init();
 302}
 303
 304struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 305                                  unsigned int max_hz, unsigned int mode)
 306{
 307        struct cf_spi_slave *cfslave;
 308
 309        if (!spi_cs_is_valid(bus, cs))
 310                return NULL;
 311
 312        cfslave = spi_alloc_slave(struct cf_spi_slave, bus, cs);
 313        if (!cfslave)
 314                return NULL;
 315
 316        cfslave->baudrate = max_hz;
 317
 318        /* specific setup */
 319        return cfspi_setup_slave(cfslave, mode);
 320}
 321
 322void spi_free_slave(struct spi_slave *slave)
 323{
 324        struct cf_spi_slave *cfslave = to_cf_spi_slave(slave);
 325
 326        free(cfslave);
 327}
 328
 329int spi_claim_bus(struct spi_slave *slave)
 330{
 331        return cfspi_claim_bus(slave->bus, slave->cs);
 332}
 333
 334void spi_release_bus(struct spi_slave *slave)
 335{
 336        cfspi_release_bus(slave->bus, slave->cs);
 337}
 338
 339int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
 340             void *din, unsigned long flags)
 341{
 342        return cfspi_xfer(slave, bitlen, dout, din, flags);
 343}
 344#endif                          /* CONFIG_CMD_SPI */
 345