uboot/drivers/spi/fsl_espi.c
<<
>>
Prefs
   1/*
   2 * eSPI controller driver.
   3 *
   4 * Copyright 2010-2011 Freescale Semiconductor, Inc.
   5 * Author: Mingkai Hu (Mingkai.hu@freescale.com)
   6 *
   7 * This program is free software; you can redistribute it and/or
   8 * modify it under the terms of the GNU General Public License as
   9 * published by the Free Software Foundation; either version 2 of
  10 * the License, or (at your option) any later version.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * along with this program; if not, write to the Free Software
  19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  20 * MA 02111-1307 USA
  21 */
  22
  23#include <common.h>
  24
  25#include <malloc.h>
  26#include <spi.h>
  27#include <asm/immap_85xx.h>
  28
  29struct fsl_spi_slave {
  30        struct spi_slave slave;
  31        unsigned int    div16;
  32        unsigned int    pm;
  33        unsigned int    mode;
  34        size_t          cmd_len;
  35        u8              cmd_buf[16];
  36        size_t          data_len;
  37        unsigned int    max_transfer_length;
  38};
  39
  40#define to_fsl_spi_slave(s) container_of(s, struct fsl_spi_slave, slave)
  41
  42#define ESPI_MAX_CS_NUM         4
  43
  44#define ESPI_EV_RNE             (1 << 9)
  45#define ESPI_EV_TNF             (1 << 8)
  46
  47#define ESPI_MODE_EN            (1 << 31)       /* Enable interface */
  48#define ESPI_MODE_TXTHR(x)      ((x) << 8)      /* Tx FIFO threshold */
  49#define ESPI_MODE_RXTHR(x)      ((x) << 0)      /* Rx FIFO threshold */
  50
  51#define ESPI_COM_CS(x)          ((x) << 30)
  52#define ESPI_COM_TRANLEN(x)     ((x) << 0)
  53
  54#define ESPI_CSMODE_CI_INACTIVEHIGH     (1 << 31)
  55#define ESPI_CSMODE_CP_BEGIN_EDGCLK     (1 << 30)
  56#define ESPI_CSMODE_REV_MSB_FIRST       (1 << 29)
  57#define ESPI_CSMODE_DIV16               (1 << 28)
  58#define ESPI_CSMODE_PM(x)               ((x) << 24)
  59#define ESPI_CSMODE_POL_ASSERTED_LOW    (1 << 20)
  60#define ESPI_CSMODE_LEN(x)              ((x) << 16)
  61#define ESPI_CSMODE_CSBEF(x)            ((x) << 12)
  62#define ESPI_CSMODE_CSAFT(x)            ((x) << 8)
  63#define ESPI_CSMODE_CSCG(x)             ((x) << 3)
  64
  65#define ESPI_CSMODE_INIT_VAL (ESPI_CSMODE_POL_ASSERTED_LOW | \
  66                ESPI_CSMODE_CSBEF(0) | ESPI_CSMODE_CSAFT(0) | \
  67                ESPI_CSMODE_CSCG(1))
  68
  69#define ESPI_MAX_DATA_TRANSFER_LEN 0xFFF0
  70
  71struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
  72                unsigned int max_hz, unsigned int mode)
  73{
  74        struct fsl_spi_slave *fsl;
  75        sys_info_t sysinfo;
  76        unsigned long spibrg = 0;
  77        unsigned char pm = 0;
  78
  79        if (!spi_cs_is_valid(bus, cs))
  80                return NULL;
  81
  82        fsl = malloc(sizeof(struct fsl_spi_slave));
  83        if (!fsl)
  84                return NULL;
  85
  86        fsl->slave.bus = bus;
  87        fsl->slave.cs = cs;
  88        fsl->mode = mode;
  89        fsl->max_transfer_length = ESPI_MAX_DATA_TRANSFER_LEN;
  90
  91        /* Set eSPI BRG clock source */
  92        get_sys_info(&sysinfo);
  93        spibrg = sysinfo.freqSystemBus / 2;
  94        fsl->div16 = 0;
  95        if ((spibrg / max_hz) > 32) {
  96                fsl->div16 = ESPI_CSMODE_DIV16;
  97                pm = spibrg / (max_hz * 16 * 2);
  98                if (pm > 16) {
  99                        pm = 16;
 100                        debug("Requested speed is too low: %d Hz, %ld Hz "
 101                                "is used.\n", max_hz, spibrg / (32 * 16));
 102                }
 103        } else
 104                pm = spibrg / (max_hz * 2);
 105        if (pm)
 106                pm--;
 107        fsl->pm = pm;
 108
 109        return &fsl->slave;
 110}
 111
 112void spi_free_slave(struct spi_slave *slave)
 113{
 114        struct fsl_spi_slave *fsl = to_fsl_spi_slave(slave);
 115        free(fsl);
 116}
 117
 118void spi_init(void)
 119{
 120
 121}
 122
 123int spi_claim_bus(struct spi_slave *slave)
 124{
 125        struct fsl_spi_slave *fsl = to_fsl_spi_slave(slave);
 126        ccsr_espi_t *espi = (void *)(CONFIG_SYS_MPC85xx_ESPI_ADDR);
 127        unsigned char pm = fsl->pm;
 128        unsigned int cs = slave->cs;
 129        unsigned int mode =  fsl->mode;
 130        unsigned int div16 = fsl->div16;
 131        int i;
 132
 133        debug("%s: bus:%i cs:%i\n", __func__, slave->bus, cs);
 134
 135        /* Enable eSPI interface */
 136        out_be32(&espi->mode, ESPI_MODE_RXTHR(3)
 137                        | ESPI_MODE_TXTHR(4) | ESPI_MODE_EN);
 138
 139        out_be32(&espi->event, 0xffffffff); /* Clear all eSPI events */
 140        out_be32(&espi->mask, 0x00000000); /* Mask  all eSPI interrupts */
 141
 142        /* Init CS mode interface */
 143        for (i = 0; i < ESPI_MAX_CS_NUM; i++)
 144                out_be32(&espi->csmode[i], ESPI_CSMODE_INIT_VAL);
 145
 146        out_be32(&espi->csmode[cs], in_be32(&espi->csmode[cs]) &
 147                ~(ESPI_CSMODE_PM(0xF) | ESPI_CSMODE_DIV16
 148                | ESPI_CSMODE_CI_INACTIVEHIGH | ESPI_CSMODE_CP_BEGIN_EDGCLK
 149                | ESPI_CSMODE_REV_MSB_FIRST | ESPI_CSMODE_LEN(0xF)));
 150
 151        /* Set eSPI BRG clock source */
 152        out_be32(&espi->csmode[cs], in_be32(&espi->csmode[cs])
 153                | ESPI_CSMODE_PM(pm) | div16);
 154
 155        /* Set eSPI mode */
 156        if (mode & SPI_CPHA)
 157                out_be32(&espi->csmode[cs], in_be32(&espi->csmode[cs])
 158                        | ESPI_CSMODE_CP_BEGIN_EDGCLK);
 159        if (mode & SPI_CPOL)
 160                out_be32(&espi->csmode[cs], in_be32(&espi->csmode[cs])
 161                        | ESPI_CSMODE_CI_INACTIVEHIGH);
 162
 163        /* Character bit order: msb first */
 164        out_be32(&espi->csmode[cs], in_be32(&espi->csmode[cs])
 165                | ESPI_CSMODE_REV_MSB_FIRST);
 166
 167        /* Character length in bits, between 0x3~0xf, i.e. 4bits~16bits */
 168        out_be32(&espi->csmode[cs], in_be32(&espi->csmode[cs])
 169                | ESPI_CSMODE_LEN(7));
 170
 171        return 0;
 172}
 173
 174void spi_release_bus(struct spi_slave *slave)
 175{
 176
 177}
 178
 179int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *data_out,
 180                void *data_in, unsigned long flags)
 181{
 182        struct fsl_spi_slave *fsl = to_fsl_spi_slave(slave);
 183        ccsr_espi_t *espi = (void *)(CONFIG_SYS_MPC85xx_ESPI_ADDR);
 184        unsigned int tmpdout, tmpdin, event;
 185        const void *dout = NULL;
 186        void *din = NULL;
 187        int len = 0;
 188        int num_blks, num_chunks, max_tran_len, tran_len;
 189        int num_bytes;
 190        unsigned char *ch;
 191        unsigned char *buffer = NULL;
 192        size_t buf_len;
 193        u8 *cmd_buf = fsl->cmd_buf;
 194        size_t cmd_len = fsl->cmd_len;
 195        size_t data_len = bitlen / 8;
 196        size_t rx_offset = 0;
 197
 198        max_tran_len = fsl->max_transfer_length;
 199        switch (flags) {
 200        case SPI_XFER_BEGIN:
 201                cmd_len = fsl->cmd_len = data_len;
 202                memcpy(cmd_buf, data_out, cmd_len);
 203                return 0;
 204        case 0:
 205        case SPI_XFER_END:
 206                if (bitlen == 0) {
 207                        spi_cs_deactivate(slave);
 208                        return 0;
 209                }
 210                buf_len = 2 * cmd_len + min(data_len, max_tran_len);
 211                len = cmd_len + data_len;
 212                rx_offset = cmd_len;
 213                buffer = (unsigned char *)malloc(buf_len);
 214                if (!buffer) {
 215                        debug("SF: Failed to malloc memory.\n");
 216                        return 1;
 217                }
 218                memcpy(buffer, cmd_buf, cmd_len);
 219                if (cmd_len != 1) {
 220                        if (data_in == NULL)
 221                                memcpy(buffer + cmd_len, data_out, data_len);
 222                }
 223                break;
 224        case SPI_XFER_BEGIN | SPI_XFER_END:
 225                len = data_len;
 226                buffer = (unsigned char *)malloc(len * 2);
 227                if (!buffer) {
 228                        debug("SF: Failed to malloc memory.\n");
 229                        return 1;
 230                }
 231                memcpy(buffer, data_out, len);
 232                rx_offset = len;
 233                cmd_len = 0;
 234                break;
 235        }
 236
 237        debug("spi_xfer: slave %u:%u dout %08X(%p) din %08X(%p) len %u\n",
 238              slave->bus, slave->cs, *(uint *) dout,
 239              dout, *(uint *) din, din, len);
 240
 241        num_chunks = data_len / max_tran_len +
 242                (data_len % max_tran_len ? 1 : 0);
 243        while (num_chunks--) {
 244                if (data_in)
 245                        din = buffer + rx_offset;
 246                dout = buffer;
 247                tran_len = min(data_len , max_tran_len);
 248                num_blks = (tran_len + cmd_len) / 4 +
 249                        ((tran_len + cmd_len) % 4 ? 1 : 0);
 250                num_bytes = (tran_len + cmd_len) % 4;
 251                fsl->data_len = tran_len + cmd_len;
 252                spi_cs_activate(slave);
 253
 254                /* Clear all eSPI events */
 255                out_be32(&espi->event , 0xffffffff);
 256                /* handle data in 32-bit chunks */
 257                while (num_blks--) {
 258
 259                        event = in_be32(&espi->event);
 260                        if (event & ESPI_EV_TNF) {
 261                                tmpdout = *(u32 *)dout;
 262
 263                                /* Set up the next iteration */
 264                                if (len > 4) {
 265                                        len -= 4;
 266                                        dout += 4;
 267                                }
 268
 269                                out_be32(&espi->tx, tmpdout);
 270                                out_be32(&espi->event, ESPI_EV_TNF);
 271                                debug("***spi_xfer:...%08x written\n", tmpdout);
 272                        }
 273
 274                        /* Wait for eSPI transmit to get out */
 275                        udelay(80);
 276
 277                        event = in_be32(&espi->event);
 278                        if (event & ESPI_EV_RNE) {
 279                                tmpdin = in_be32(&espi->rx);
 280                                if (num_blks == 0 && num_bytes != 0) {
 281                                        ch = (unsigned char *)&tmpdin;
 282                                        while (num_bytes--)
 283                                                *(unsigned char *)din++ = *ch++;
 284                                } else {
 285                                        *(u32 *) din = tmpdin;
 286                                        din += 4;
 287                                }
 288
 289                                out_be32(&espi->event, in_be32(&espi->event)
 290                                                | ESPI_EV_RNE);
 291                                debug("***spi_xfer:...%08x readed\n", tmpdin);
 292                        }
 293                }
 294                if (data_in) {
 295                        memcpy(data_in, buffer + 2 * cmd_len, tran_len);
 296                        if (*buffer == 0x0b) {
 297                                data_in += tran_len;
 298                                data_len -= tran_len;
 299                                *(int *)buffer += tran_len;
 300                        }
 301                }
 302                spi_cs_deactivate(slave);
 303        }
 304
 305        free(buffer);
 306        return 0;
 307}
 308
 309int spi_cs_is_valid(unsigned int bus, unsigned int cs)
 310{
 311        return bus == 0 && cs < ESPI_MAX_CS_NUM;
 312}
 313
 314void spi_cs_activate(struct spi_slave *slave)
 315{
 316        struct fsl_spi_slave *fsl = to_fsl_spi_slave(slave);
 317        ccsr_espi_t *espi = (void *)(CONFIG_SYS_MPC85xx_ESPI_ADDR);
 318        unsigned int com = 0;
 319        size_t data_len = fsl->data_len;
 320
 321        com &= ~(ESPI_COM_CS(0x3) | ESPI_COM_TRANLEN(0xFFFF));
 322        com |= ESPI_COM_CS(slave->cs);
 323        com |= ESPI_COM_TRANLEN(data_len - 1);
 324        out_be32(&espi->com, com);
 325}
 326
 327void spi_cs_deactivate(struct spi_slave *slave)
 328{
 329        ccsr_espi_t *espi = (void *)(CONFIG_SYS_MPC85xx_ESPI_ADDR);
 330
 331        /* clear the RXCNT and TXCNT */
 332        out_be32(&espi->mode, in_be32(&espi->mode) & (~ESPI_MODE_EN));
 333        out_be32(&espi->mode, in_be32(&espi->mode) | ESPI_MODE_EN);
 334}
 335