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