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