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