uboot/drivers/mmc/ftsdc010_mci.c
<<
>>
Prefs
   1/*
   2 * Faraday MMC/SD Host Controller
   3 *
   4 * (C) Copyright 2010 Faraday Technology
   5 * Dante Su <dantesu@faraday-tech.com>
   6 *
   7 * SPDX-License-Identifier:     GPL-2.0+
   8 */
   9
  10#include <common.h>
  11#include <malloc.h>
  12#include <part.h>
  13#include <mmc.h>
  14
  15#include <asm/io.h>
  16#include <linux/errno.h>
  17#include <asm/byteorder.h>
  18#include <faraday/ftsdc010.h>
  19
  20#define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 4) /* 250 ms */
  21#define CFG_RST_TIMEOUT CONFIG_SYS_HZ /* 1 sec reset timeout */
  22
  23struct ftsdc010_chip {
  24        void __iomem *regs;
  25        uint32_t wprot;   /* write protected (locked) */
  26        uint32_t rate;    /* actual SD clock in Hz */
  27        uint32_t sclk;    /* FTSDC010 source clock in Hz */
  28        uint32_t fifo;    /* fifo depth in bytes */
  29        uint32_t acmd;
  30        struct mmc_config cfg;  /* mmc configuration */
  31};
  32
  33static inline int ftsdc010_send_cmd(struct mmc *mmc, struct mmc_cmd *mmc_cmd)
  34{
  35        struct ftsdc010_chip *chip = mmc->priv;
  36        struct ftsdc010_mmc __iomem *regs = chip->regs;
  37        int ret = -ETIMEDOUT;
  38        uint32_t ts, st;
  39        uint32_t cmd   = FTSDC010_CMD_IDX(mmc_cmd->cmdidx);
  40        uint32_t arg   = mmc_cmd->cmdarg;
  41        uint32_t flags = mmc_cmd->resp_type;
  42
  43        cmd |= FTSDC010_CMD_CMD_EN;
  44
  45        if (chip->acmd) {
  46                cmd |= FTSDC010_CMD_APP_CMD;
  47                chip->acmd = 0;
  48        }
  49
  50        if (flags & MMC_RSP_PRESENT)
  51                cmd |= FTSDC010_CMD_NEED_RSP;
  52
  53        if (flags & MMC_RSP_136)
  54                cmd |= FTSDC010_CMD_LONG_RSP;
  55
  56        writel(FTSDC010_STATUS_RSP_MASK | FTSDC010_STATUS_CMD_SEND,
  57                &regs->clr);
  58        writel(arg, &regs->argu);
  59        writel(cmd, &regs->cmd);
  60
  61        if (!(flags & (MMC_RSP_PRESENT | MMC_RSP_136))) {
  62                for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
  63                        if (readl(&regs->status) & FTSDC010_STATUS_CMD_SEND) {
  64                                writel(FTSDC010_STATUS_CMD_SEND, &regs->clr);
  65                                ret = 0;
  66                                break;
  67                        }
  68                }
  69        } else {
  70                st = 0;
  71                for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
  72                        st = readl(&regs->status);
  73                        writel(st & FTSDC010_STATUS_RSP_MASK, &regs->clr);
  74                        if (st & FTSDC010_STATUS_RSP_MASK)
  75                                break;
  76                }
  77                if (st & FTSDC010_STATUS_RSP_CRC_OK) {
  78                        if (flags & MMC_RSP_136) {
  79                                mmc_cmd->response[0] = readl(&regs->rsp3);
  80                                mmc_cmd->response[1] = readl(&regs->rsp2);
  81                                mmc_cmd->response[2] = readl(&regs->rsp1);
  82                                mmc_cmd->response[3] = readl(&regs->rsp0);
  83                        } else {
  84                                mmc_cmd->response[0] = readl(&regs->rsp0);
  85                        }
  86                        ret = 0;
  87                } else {
  88                        debug("ftsdc010: rsp err (cmd=%d, st=0x%x)\n",
  89                                mmc_cmd->cmdidx, st);
  90                }
  91        }
  92
  93        if (ret) {
  94                debug("ftsdc010: cmd timeout (op code=%d)\n",
  95                        mmc_cmd->cmdidx);
  96        } else if (mmc_cmd->cmdidx == MMC_CMD_APP_CMD) {
  97                chip->acmd = 1;
  98        }
  99
 100        return ret;
 101}
 102
 103static void ftsdc010_clkset(struct mmc *mmc, uint32_t rate)
 104{
 105        struct ftsdc010_chip *chip = mmc->priv;
 106        struct ftsdc010_mmc __iomem *regs = chip->regs;
 107        uint32_t div;
 108
 109        for (div = 0; div < 0x7f; ++div) {
 110                if (rate >= chip->sclk / (2 * (div + 1)))
 111                        break;
 112        }
 113        chip->rate = chip->sclk / (2 * (div + 1));
 114
 115        writel(FTSDC010_CCR_CLK_DIV(div), &regs->ccr);
 116
 117        if (IS_SD(mmc)) {
 118                setbits_le32(&regs->ccr, FTSDC010_CCR_CLK_SD);
 119
 120                if (chip->rate > 25000000)
 121                        setbits_le32(&regs->ccr, FTSDC010_CCR_CLK_HISPD);
 122                else
 123                        clrbits_le32(&regs->ccr, FTSDC010_CCR_CLK_HISPD);
 124        }
 125}
 126
 127static int ftsdc010_wait(struct ftsdc010_mmc __iomem *regs, uint32_t mask)
 128{
 129        int ret = -ETIMEDOUT;
 130        uint32_t st, ts;
 131
 132        for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
 133                st = readl(&regs->status);
 134                if (!(st & mask))
 135                        continue;
 136                writel(st & mask, &regs->clr);
 137                ret = 0;
 138                break;
 139        }
 140
 141        if (ret)
 142                debug("ftsdc010: wait st(0x%x) timeout\n", mask);
 143
 144        return ret;
 145}
 146
 147/*
 148 * u-boot mmc api
 149 */
 150
 151static int ftsdc010_request(struct mmc *mmc, struct mmc_cmd *cmd,
 152        struct mmc_data *data)
 153{
 154        int ret = -EOPNOTSUPP;
 155        uint32_t len = 0;
 156        struct ftsdc010_chip *chip = mmc->priv;
 157        struct ftsdc010_mmc __iomem *regs = chip->regs;
 158
 159        if (data && (data->flags & MMC_DATA_WRITE) && chip->wprot) {
 160                printf("ftsdc010: the card is write protected!\n");
 161                return ret;
 162        }
 163
 164        if (data) {
 165                uint32_t dcr;
 166
 167                len = data->blocksize * data->blocks;
 168
 169                /* 1. data disable + fifo reset */
 170                dcr = 0;
 171#ifdef CONFIG_FTSDC010_SDIO
 172                dcr |= FTSDC010_DCR_FIFO_RST;
 173#endif
 174                writel(dcr, &regs->dcr);
 175
 176                /* 2. clear status register */
 177                writel(FTSDC010_STATUS_DATA_MASK | FTSDC010_STATUS_FIFO_URUN
 178                        | FTSDC010_STATUS_FIFO_ORUN, &regs->clr);
 179
 180                /* 3. data timeout (1 sec) */
 181                writel(chip->rate, &regs->dtr);
 182
 183                /* 4. data length (bytes) */
 184                writel(len, &regs->dlr);
 185
 186                /* 5. data enable */
 187                dcr = (ffs(data->blocksize) - 1) | FTSDC010_DCR_DATA_EN;
 188                if (data->flags & MMC_DATA_WRITE)
 189                        dcr |= FTSDC010_DCR_DATA_WRITE;
 190                writel(dcr, &regs->dcr);
 191        }
 192
 193        ret = ftsdc010_send_cmd(mmc, cmd);
 194        if (ret) {
 195                printf("ftsdc010: CMD%d failed\n", cmd->cmdidx);
 196                return ret;
 197        }
 198
 199        if (!data)
 200                return ret;
 201
 202        if (data->flags & MMC_DATA_WRITE) {
 203                const uint8_t *buf = (const uint8_t *)data->src;
 204
 205                while (len > 0) {
 206                        int wlen;
 207
 208                        /* wait for tx ready */
 209                        ret = ftsdc010_wait(regs, FTSDC010_STATUS_FIFO_URUN);
 210                        if (ret)
 211                                break;
 212
 213                        /* write bytes to ftsdc010 */
 214                        for (wlen = 0; wlen < len && wlen < chip->fifo; ) {
 215                                writel(*(uint32_t *)buf, &regs->dwr);
 216                                buf  += 4;
 217                                wlen += 4;
 218                        }
 219
 220                        len -= wlen;
 221                }
 222
 223        } else {
 224                uint8_t *buf = (uint8_t *)data->dest;
 225
 226                while (len > 0) {
 227                        int rlen;
 228
 229                        /* wait for rx ready */
 230                        ret = ftsdc010_wait(regs, FTSDC010_STATUS_FIFO_ORUN);
 231                        if (ret)
 232                                break;
 233
 234                        /* fetch bytes from ftsdc010 */
 235                        for (rlen = 0; rlen < len && rlen < chip->fifo; ) {
 236                                *(uint32_t *)buf = readl(&regs->dwr);
 237                                buf  += 4;
 238                                rlen += 4;
 239                        }
 240
 241                        len -= rlen;
 242                }
 243
 244        }
 245
 246        if (!ret) {
 247                ret = ftsdc010_wait(regs,
 248                        FTSDC010_STATUS_DATA_END | FTSDC010_STATUS_DATA_ERROR);
 249        }
 250
 251        return ret;
 252}
 253
 254static void ftsdc010_set_ios(struct mmc *mmc)
 255{
 256        struct ftsdc010_chip *chip = mmc->priv;
 257        struct ftsdc010_mmc __iomem *regs = chip->regs;
 258
 259        ftsdc010_clkset(mmc, mmc->clock);
 260
 261        clrbits_le32(&regs->bwr, FTSDC010_BWR_MODE_MASK);
 262        switch (mmc->bus_width) {
 263        case 4:
 264                setbits_le32(&regs->bwr, FTSDC010_BWR_MODE_4BIT);
 265                break;
 266        case 8:
 267                setbits_le32(&regs->bwr, FTSDC010_BWR_MODE_8BIT);
 268                break;
 269        default:
 270                setbits_le32(&regs->bwr, FTSDC010_BWR_MODE_1BIT);
 271                break;
 272        }
 273}
 274
 275static int ftsdc010_init(struct mmc *mmc)
 276{
 277        struct ftsdc010_chip *chip = mmc->priv;
 278        struct ftsdc010_mmc __iomem *regs = chip->regs;
 279        uint32_t ts;
 280
 281        if (readl(&regs->status) & FTSDC010_STATUS_CARD_DETECT)
 282                return -ENOMEDIUM;
 283
 284        if (readl(&regs->status) & FTSDC010_STATUS_WRITE_PROT) {
 285                printf("ftsdc010: write protected\n");
 286                chip->wprot = 1;
 287        }
 288
 289        chip->fifo = (readl(&regs->feature) & 0xff) << 2;
 290
 291        /* 1. chip reset */
 292        writel(FTSDC010_CMD_SDC_RST, &regs->cmd);
 293        for (ts = get_timer(0); get_timer(ts) < CFG_RST_TIMEOUT; ) {
 294                if (readl(&regs->cmd) & FTSDC010_CMD_SDC_RST)
 295                        continue;
 296                break;
 297        }
 298        if (readl(&regs->cmd) & FTSDC010_CMD_SDC_RST) {
 299                printf("ftsdc010: reset failed\n");
 300                return -EOPNOTSUPP;
 301        }
 302
 303        /* 2. enter low speed mode (400k card detection) */
 304        ftsdc010_clkset(mmc, 400000);
 305
 306        /* 3. interrupt disabled */
 307        writel(0, &regs->int_mask);
 308
 309        return 0;
 310}
 311
 312static const struct mmc_ops ftsdc010_ops = {
 313        .send_cmd       = ftsdc010_request,
 314        .set_ios        = ftsdc010_set_ios,
 315        .init           = ftsdc010_init,
 316};
 317
 318int ftsdc010_mmc_init(int devid)
 319{
 320        struct mmc *mmc;
 321        struct ftsdc010_chip *chip;
 322        struct ftsdc010_mmc __iomem *regs;
 323#ifdef CONFIG_FTSDC010_BASE_LIST
 324        uint32_t base_list[] = CONFIG_FTSDC010_BASE_LIST;
 325
 326        if (devid < 0 || devid >= ARRAY_SIZE(base_list))
 327                return -1;
 328        regs = (void __iomem *)base_list[devid];
 329#else
 330        regs = (void __iomem *)(CONFIG_FTSDC010_BASE + (devid << 20));
 331#endif
 332
 333        chip = malloc(sizeof(struct ftsdc010_chip));
 334        if (!chip)
 335                return -ENOMEM;
 336        memset(chip, 0, sizeof(struct ftsdc010_chip));
 337
 338        chip->regs = regs;
 339#ifdef CONFIG_SYS_CLK_FREQ
 340        chip->sclk = CONFIG_SYS_CLK_FREQ;
 341#else
 342        chip->sclk = clk_get_rate("SDC");
 343#endif
 344
 345        chip->cfg.name = "ftsdc010";
 346        chip->cfg.ops = &ftsdc010_ops;
 347        chip->cfg.host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz;
 348        switch (readl(&regs->bwr) & FTSDC010_BWR_CAPS_MASK) {
 349        case FTSDC010_BWR_CAPS_4BIT:
 350                chip->cfg.host_caps |= MMC_MODE_4BIT;
 351                break;
 352        case FTSDC010_BWR_CAPS_8BIT:
 353                chip->cfg.host_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
 354                break;
 355        default:
 356                break;
 357        }
 358
 359        chip->cfg.voltages  = MMC_VDD_32_33 | MMC_VDD_33_34;
 360        chip->cfg.f_max     = chip->sclk / 2;
 361        chip->cfg.f_min     = chip->sclk / 0x100;
 362
 363        chip->cfg.part_type = PART_TYPE_DOS;
 364        chip->cfg.b_max     = CONFIG_SYS_MMC_MAX_BLK_COUNT;
 365
 366        mmc = mmc_create(&chip->cfg, chip);
 367        if (mmc == NULL) {
 368                free(chip);
 369                return -ENOMEM;
 370        }
 371
 372        return 0;
 373}
 374