uboot/drivers/mmc/mmc_spi.c
<<
>>
Prefs
   1/*
   2 * generic mmc spi driver
   3 *
   4 * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
   5 * Copyright 2019 Bhargav Shah <bhargavshah1988@gmail.com>
   6 *
   7 * Licensed under the GPL-2 or later.
   8 */
   9#include <common.h>
  10#include <errno.h>
  11#include <malloc.h>
  12#include <part.h>
  13#include <mmc.h>
  14#include <stdlib.h>
  15#include <u-boot/crc.h>
  16#include <linux/crc7.h>
  17#include <asm/byteorder.h>
  18#include <dm.h>
  19#include <spi.h>
  20
  21/* MMC/SD in SPI mode reports R1 status always */
  22#define R1_SPI_IDLE                     BIT(0)
  23#define R1_SPI_ERASE_RESET              BIT(1)
  24#define R1_SPI_ILLEGAL_COMMAND          BIT(2)
  25#define R1_SPI_COM_CRC                  BIT(3)
  26#define R1_SPI_ERASE_SEQ                BIT(4)
  27#define R1_SPI_ADDRESS                  BIT(5)
  28#define R1_SPI_PARAMETER                BIT(6)
  29/* R1 bit 7 is always zero, reuse this bit for error */
  30#define R1_SPI_ERROR                    BIT(7)
  31
  32/* Response tokens used to ack each block written: */
  33#define SPI_MMC_RESPONSE_CODE(x)        ((x) & 0x1f)
  34#define SPI_RESPONSE_ACCEPTED           ((2 << 1)|1)
  35#define SPI_RESPONSE_CRC_ERR            ((5 << 1)|1)
  36#define SPI_RESPONSE_WRITE_ERR          ((6 << 1)|1)
  37
  38/* Read and write blocks start with these tokens and end with crc;
  39 * on error, read tokens act like a subset of R2_SPI_* values.
  40 */
  41/* single block write multiblock read */
  42#define SPI_TOKEN_SINGLE                0xfe
  43/* multiblock write */
  44#define SPI_TOKEN_MULTI_WRITE           0xfc
  45/* terminate multiblock write */
  46#define SPI_TOKEN_STOP_TRAN             0xfd
  47
  48/* MMC SPI commands start with a start bit "0" and a transmit bit "1" */
  49#define MMC_SPI_CMD(x) (0x40 | (x))
  50
  51/* bus capability */
  52#define MMC_SPI_VOLTAGE                 (MMC_VDD_32_33 | MMC_VDD_33_34)
  53#define MMC_SPI_MIN_CLOCK               400000  /* 400KHz to meet MMC spec */
  54#define MMC_SPI_MAX_CLOCK               25000000 /* SD/MMC legacy speed */
  55
  56/* timeout value */
  57#define CMD_TIMEOUT                     8
  58#define READ_TIMEOUT                    3000000 /* 1 sec */
  59#define WRITE_TIMEOUT                   3000000 /* 1 sec */
  60
  61struct mmc_spi_plat {
  62        struct mmc_config cfg;
  63        struct mmc mmc;
  64};
  65
  66struct mmc_spi_priv {
  67        struct spi_slave *spi;
  68};
  69
  70static int mmc_spi_sendcmd(struct udevice *dev,
  71                           ushort cmdidx, u32 cmdarg, u32 resp_type,
  72                           u8 *resp, u32 resp_size,
  73                           bool resp_match, u8 resp_match_value)
  74{
  75        int i, rpos = 0, ret = 0;
  76        u8 cmdo[7], r;
  77
  78        debug("%s: cmd%d cmdarg=0x%x resp_type=0x%x "
  79              "resp_size=%d resp_match=%d resp_match_value=0x%x\n",
  80              __func__, cmdidx, cmdarg, resp_type,
  81              resp_size, resp_match, resp_match_value);
  82
  83        cmdo[0] = 0xff;
  84        cmdo[1] = MMC_SPI_CMD(cmdidx);
  85        cmdo[2] = cmdarg >> 24;
  86        cmdo[3] = cmdarg >> 16;
  87        cmdo[4] = cmdarg >> 8;
  88        cmdo[5] = cmdarg;
  89        cmdo[6] = (crc7(0, &cmdo[1], 5) << 1) | 0x01;
  90        ret = dm_spi_xfer(dev, sizeof(cmdo) * 8, cmdo, NULL, SPI_XFER_BEGIN);
  91        if (ret)
  92                return ret;
  93
  94        ret = dm_spi_xfer(dev, 1 * 8, NULL, &r, 0);
  95        if (ret)
  96                return ret;
  97
  98        if (!resp || !resp_size)
  99                return 0;
 100
 101        debug("%s: cmd%d", __func__, cmdidx);
 102
 103        if (resp_match) {
 104                r = ~resp_match_value;
 105                i = CMD_TIMEOUT;
 106                while (i--) {
 107                        ret = dm_spi_xfer(dev, 1 * 8, NULL, &r, 0);
 108                        if (ret)
 109                                return ret;
 110                        debug(" resp%d=0x%x", rpos, r);
 111                        rpos++;
 112                        if (r == resp_match_value)
 113                                break;
 114                }
 115                if (!i && (r != resp_match_value))
 116                        return -ETIMEDOUT;
 117        }
 118
 119        for (i = 0; i < resp_size; i++) {
 120                if (i == 0 && resp_match) {
 121                        resp[i] = resp_match_value;
 122                        continue;
 123                }
 124                ret = dm_spi_xfer(dev, 1 * 8, NULL, &r, 0);
 125                if (ret)
 126                        return ret;
 127                debug(" resp%d=0x%x", rpos, r);
 128                rpos++;
 129                resp[i] = r;
 130        }
 131
 132        debug("\n");
 133
 134        return 0;
 135}
 136
 137static int mmc_spi_readdata(struct udevice *dev,
 138                            void *xbuf, u32 bcnt, u32 bsize)
 139{
 140        u16 crc;
 141        u8 *buf = xbuf, r1;
 142        int i, ret = 0;
 143
 144        while (bcnt--) {
 145                for (i = 0; i < READ_TIMEOUT; i++) {
 146                        ret = dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0);
 147                        if (ret)
 148                                return ret;
 149                        if (r1 == SPI_TOKEN_SINGLE)
 150                                break;
 151                }
 152                debug("%s: data tok%d 0x%x\n", __func__, i, r1);
 153                if (r1 == SPI_TOKEN_SINGLE) {
 154                        ret = dm_spi_xfer(dev, bsize * 8, NULL, buf, 0);
 155                        if (ret)
 156                                return ret;
 157                        ret = dm_spi_xfer(dev, 2 * 8, NULL, &crc, 0);
 158                        if (ret)
 159                                return ret;
 160#ifdef CONFIG_MMC_SPI_CRC_ON
 161                        if (be16_to_cpu(crc16_ccitt(0, buf, bsize)) != crc) {
 162                                debug("%s: data crc error\n", __func__);
 163                                r1 = R1_SPI_COM_CRC;
 164                                break;
 165                        }
 166#endif
 167                        r1 = 0;
 168                } else {
 169                        r1 = R1_SPI_ERROR;
 170                        break;
 171                }
 172                buf += bsize;
 173        }
 174
 175        if (r1 & R1_SPI_COM_CRC)
 176                ret = -ECOMM;
 177        else if (r1) /* other errors */
 178                ret = -ETIMEDOUT;
 179
 180        return ret;
 181}
 182
 183static int mmc_spi_writedata(struct udevice *dev, const void *xbuf,
 184                             u32 bcnt, u32 bsize, int multi)
 185{
 186        const u8 *buf = xbuf;
 187        u8 r1, tok[2];
 188        u16 crc;
 189        int i, ret = 0;
 190
 191        tok[0] = 0xff;
 192        tok[1] = multi ? SPI_TOKEN_MULTI_WRITE : SPI_TOKEN_SINGLE;
 193
 194        while (bcnt--) {
 195#ifdef CONFIG_MMC_SPI_CRC_ON
 196                crc = cpu_to_be16(crc16_ccitt(0, (u8 *)buf, bsize));
 197#endif
 198                dm_spi_xfer(dev, 2 * 8, tok, NULL, 0);
 199                dm_spi_xfer(dev, bsize * 8, buf, NULL, 0);
 200                dm_spi_xfer(dev, 2 * 8, &crc, NULL, 0);
 201                for (i = 0; i < CMD_TIMEOUT; i++) {
 202                        dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0);
 203                        if ((r1 & 0x10) == 0) /* response token */
 204                                break;
 205                }
 206                debug("%s: data tok%d 0x%x\n", __func__, i, r1);
 207                if (SPI_MMC_RESPONSE_CODE(r1) == SPI_RESPONSE_ACCEPTED) {
 208                        debug("%s: data accepted\n", __func__);
 209                        for (i = 0; i < WRITE_TIMEOUT; i++) { /* wait busy */
 210                                dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0);
 211                                if (i && r1 == 0xff) {
 212                                        r1 = 0;
 213                                        break;
 214                                }
 215                        }
 216                        if (i == WRITE_TIMEOUT) {
 217                                debug("%s: data write timeout 0x%x\n",
 218                                      __func__, r1);
 219                                r1 = R1_SPI_ERROR;
 220                                break;
 221                        }
 222                } else {
 223                        debug("%s: data error 0x%x\n", __func__, r1);
 224                        r1 = R1_SPI_COM_CRC;
 225                        break;
 226                }
 227                buf += bsize;
 228        }
 229        if (multi && bcnt == -1) { /* stop multi write */
 230                tok[1] = SPI_TOKEN_STOP_TRAN;
 231                dm_spi_xfer(dev, 2 * 8, tok, NULL, 0);
 232                for (i = 0; i < WRITE_TIMEOUT; i++) { /* wait busy */
 233                        dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0);
 234                        if (i && r1 == 0xff) {
 235                                r1 = 0;
 236                                break;
 237                        }
 238                }
 239                if (i == WRITE_TIMEOUT) {
 240                        debug("%s: data write timeout 0x%x\n", __func__, r1);
 241                        r1 = R1_SPI_ERROR;
 242                }
 243        }
 244
 245        if (r1 & R1_SPI_COM_CRC)
 246                ret = -ECOMM;
 247        else if (r1) /* other errors */
 248                ret = -ETIMEDOUT;
 249
 250        return ret;
 251}
 252
 253static int dm_mmc_spi_set_ios(struct udevice *dev)
 254{
 255        return 0;
 256}
 257
 258static int dm_mmc_spi_request(struct udevice *dev, struct mmc_cmd *cmd,
 259                              struct mmc_data *data)
 260{
 261        int i, multi, ret = 0;
 262        u8 *resp = NULL;
 263        u32 resp_size = 0;
 264        bool resp_match = false;
 265        u8 resp8 = 0, resp40[5] = { 0 }, resp_match_value = 0;
 266
 267        dm_spi_claim_bus(dev);
 268
 269        for (i = 0; i < 4; i++)
 270                cmd->response[i] = 0;
 271
 272        switch (cmd->cmdidx) {
 273        case SD_CMD_APP_SEND_OP_COND:
 274        case MMC_CMD_SEND_OP_COND:
 275                resp = &resp8;
 276                resp_size = sizeof(resp8);
 277                cmd->cmdarg = 0x40000000;
 278                break;
 279        case SD_CMD_SEND_IF_COND:
 280                resp = (u8 *)&resp40[0];
 281                resp_size = sizeof(resp40);
 282                resp_match = true;
 283                resp_match_value = R1_SPI_IDLE;
 284                break;
 285        case MMC_CMD_SPI_READ_OCR:
 286                resp = (u8 *)&resp40[0];
 287                resp_size = sizeof(resp40);
 288                break;
 289        case MMC_CMD_SEND_STATUS:
 290        case MMC_CMD_SET_BLOCKLEN:
 291        case MMC_CMD_SPI_CRC_ON_OFF:
 292        case MMC_CMD_STOP_TRANSMISSION:
 293                resp = &resp8;
 294                resp_size = sizeof(resp8);
 295                resp_match = true;
 296                resp_match_value = 0x0;
 297                break;
 298        case MMC_CMD_SEND_CSD:
 299        case MMC_CMD_SEND_CID:
 300        case MMC_CMD_READ_SINGLE_BLOCK:
 301        case MMC_CMD_READ_MULTIPLE_BLOCK:
 302        case MMC_CMD_WRITE_SINGLE_BLOCK:
 303        case MMC_CMD_WRITE_MULTIPLE_BLOCK:
 304                break;
 305        default:
 306                resp = &resp8;
 307                resp_size = sizeof(resp8);
 308                resp_match = true;
 309                resp_match_value = R1_SPI_IDLE;
 310                break;
 311        };
 312
 313        ret = mmc_spi_sendcmd(dev, cmd->cmdidx, cmd->cmdarg, cmd->resp_type,
 314                              resp, resp_size, resp_match, resp_match_value);
 315        if (ret)
 316                goto done;
 317
 318        switch (cmd->cmdidx) {
 319        case SD_CMD_APP_SEND_OP_COND:
 320        case MMC_CMD_SEND_OP_COND:
 321                cmd->response[0] = (resp8 & R1_SPI_IDLE) ? 0 : OCR_BUSY;
 322                break;
 323        case SD_CMD_SEND_IF_COND:
 324        case MMC_CMD_SPI_READ_OCR:
 325                cmd->response[0] = resp40[4];
 326                cmd->response[0] |= (uint)resp40[3] << 8;
 327                cmd->response[0] |= (uint)resp40[2] << 16;
 328                cmd->response[0] |= (uint)resp40[1] << 24;
 329                break;
 330        case MMC_CMD_SEND_STATUS:
 331                cmd->response[0] = (resp8 & 0xff) ?
 332                        MMC_STATUS_ERROR : MMC_STATUS_RDY_FOR_DATA;
 333                break;
 334        case MMC_CMD_SEND_CID:
 335        case MMC_CMD_SEND_CSD:
 336                ret = mmc_spi_readdata(dev, cmd->response, 1, 16);
 337                if (ret)
 338                        return ret;
 339                for (i = 0; i < 4; i++)
 340                        cmd->response[i] =
 341                                cpu_to_be32(cmd->response[i]);
 342                break;
 343        default:
 344                cmd->response[0] = resp8;
 345                break;
 346        }
 347
 348        debug("%s: cmd%d resp0=0x%x resp1=0x%x resp2=0x%x resp3=0x%x\n",
 349              __func__, cmd->cmdidx, cmd->response[0], cmd->response[1],
 350              cmd->response[2], cmd->response[3]);
 351
 352        if (data) {
 353                debug("%s: data flags=0x%x blocks=%d block_size=%d\n",
 354                      __func__, data->flags, data->blocks, data->blocksize);
 355                multi = (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK);
 356                if (data->flags == MMC_DATA_READ)
 357                        ret = mmc_spi_readdata(dev, data->dest,
 358                                               data->blocks, data->blocksize);
 359                else if  (data->flags == MMC_DATA_WRITE)
 360                        ret = mmc_spi_writedata(dev, data->src,
 361                                                data->blocks, data->blocksize,
 362                                                multi);
 363        }
 364
 365done:
 366        dm_spi_xfer(dev, 0, NULL, NULL, SPI_XFER_END);
 367
 368        dm_spi_release_bus(dev);
 369
 370        return ret;
 371}
 372
 373static int mmc_spi_probe(struct udevice *dev)
 374{
 375        struct mmc_spi_priv *priv = dev_get_priv(dev);
 376        struct mmc_spi_plat *plat = dev_get_platdata(dev);
 377        struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
 378        char *name;
 379
 380        priv->spi = dev_get_parent_priv(dev);
 381        if (!priv->spi->max_hz)
 382                priv->spi->max_hz = MMC_SPI_MAX_CLOCK;
 383        priv->spi->speed = 0;
 384        priv->spi->mode = SPI_MODE_0;
 385        priv->spi->wordlen = 8;
 386
 387        name = malloc(strlen(dev->parent->name) + strlen(dev->name) + 4);
 388        if (!name)
 389                return -ENOMEM;
 390        sprintf(name, "%s:%s", dev->parent->name, dev->name);
 391
 392        plat->cfg.name = name;
 393        plat->cfg.host_caps = MMC_MODE_SPI;
 394        plat->cfg.voltages = MMC_SPI_VOLTAGE;
 395        plat->cfg.f_min = MMC_SPI_MIN_CLOCK;
 396        plat->cfg.f_max = priv->spi->max_hz;
 397        plat->cfg.part_type = PART_TYPE_DOS;
 398        plat->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
 399
 400        plat->mmc.cfg = &plat->cfg;
 401        plat->mmc.priv = priv;
 402        plat->mmc.dev = dev;
 403
 404        upriv->mmc = &plat->mmc;
 405
 406        return 0;
 407}
 408
 409static int mmc_spi_bind(struct udevice *dev)
 410{
 411        struct mmc_spi_plat *plat = dev_get_platdata(dev);
 412
 413        return mmc_bind(dev, &plat->mmc, &plat->cfg);
 414}
 415
 416static const struct dm_mmc_ops mmc_spi_ops = {
 417        .send_cmd       = dm_mmc_spi_request,
 418        .set_ios        = dm_mmc_spi_set_ios,
 419};
 420
 421static const struct udevice_id dm_mmc_spi_match[] = {
 422        { .compatible = "mmc-spi-slot" },
 423        { /* sentinel */ }
 424};
 425
 426U_BOOT_DRIVER(mmc_spi) = {
 427        .name = "mmc_spi",
 428        .id = UCLASS_MMC,
 429        .of_match = dm_mmc_spi_match,
 430        .ops = &mmc_spi_ops,
 431        .probe = mmc_spi_probe,
 432        .bind = mmc_spi_bind,
 433        .platdata_auto_alloc_size = sizeof(struct mmc_spi_plat),
 434        .priv_auto_alloc_size = sizeof(struct mmc_spi_priv),
 435};
 436