uboot/drivers/mmc/arm_pl180_mmci.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * ARM PrimeCell MultiMedia Card Interface - PL180
   4 *
   5 * Copyright (C) ST-Ericsson SA 2010
   6 *
   7 * Author: Ulf Hansson <ulf.hansson@stericsson.com>
   8 * Author: Martin Lundholm <martin.xa.lundholm@stericsson.com>
   9 * Ported to drivers/mmc/ by: Matt Waddel <matt.waddel@linaro.org>
  10 */
  11
  12/* #define DEBUG */
  13
  14#include "common.h"
  15#include <clk.h>
  16#include <errno.h>
  17#include <malloc.h>
  18#include <mmc.h>
  19#include <dm/device_compat.h>
  20
  21#include <asm/io.h>
  22#include <asm-generic/gpio.h>
  23
  24#include "arm_pl180_mmci.h"
  25
  26#ifdef CONFIG_DM_MMC
  27#include <dm.h>
  28#define MMC_CLOCK_MAX   48000000
  29#define MMC_CLOCK_MIN   400000
  30
  31struct arm_pl180_mmc_plat {
  32        struct mmc_config cfg;
  33        struct mmc mmc;
  34};
  35#endif
  36
  37static int wait_for_command_end(struct mmc *dev, struct mmc_cmd *cmd)
  38{
  39        u32 hoststatus, statusmask;
  40        struct pl180_mmc_host *host = dev->priv;
  41
  42        statusmask = SDI_STA_CTIMEOUT | SDI_STA_CCRCFAIL;
  43        if ((cmd->resp_type & MMC_RSP_PRESENT))
  44                statusmask |= SDI_STA_CMDREND;
  45        else
  46                statusmask |= SDI_STA_CMDSENT;
  47
  48        do
  49                hoststatus = readl(&host->base->status) & statusmask;
  50        while (!hoststatus);
  51
  52        writel(statusmask, &host->base->status_clear);
  53        if (hoststatus & SDI_STA_CTIMEOUT) {
  54                debug("CMD%d time out\n", cmd->cmdidx);
  55                return -ETIMEDOUT;
  56        } else if ((hoststatus & SDI_STA_CCRCFAIL) &&
  57                   (cmd->resp_type & MMC_RSP_CRC)) {
  58                printf("CMD%d CRC error\n", cmd->cmdidx);
  59                return -EILSEQ;
  60        }
  61
  62        if (cmd->resp_type & MMC_RSP_PRESENT) {
  63                cmd->response[0] = readl(&host->base->response0);
  64                cmd->response[1] = readl(&host->base->response1);
  65                cmd->response[2] = readl(&host->base->response2);
  66                cmd->response[3] = readl(&host->base->response3);
  67                debug("CMD%d response[0]:0x%08X, response[1]:0x%08X, "
  68                        "response[2]:0x%08X, response[3]:0x%08X\n",
  69                        cmd->cmdidx, cmd->response[0], cmd->response[1],
  70                        cmd->response[2], cmd->response[3]);
  71        }
  72
  73        return 0;
  74}
  75
  76/* send command to the mmc card and wait for results */
  77static int do_command(struct mmc *dev, struct mmc_cmd *cmd)
  78{
  79        int result;
  80        u32 sdi_cmd = 0;
  81        struct pl180_mmc_host *host = dev->priv;
  82
  83        sdi_cmd = ((cmd->cmdidx & SDI_CMD_CMDINDEX_MASK) | SDI_CMD_CPSMEN);
  84
  85        if (cmd->resp_type) {
  86                sdi_cmd |= SDI_CMD_WAITRESP;
  87                if (cmd->resp_type & MMC_RSP_136)
  88                        sdi_cmd |= SDI_CMD_LONGRESP;
  89        }
  90
  91        writel((u32)cmd->cmdarg, &host->base->argument);
  92        udelay(COMMAND_REG_DELAY);
  93        writel(sdi_cmd, &host->base->command);
  94        result = wait_for_command_end(dev, cmd);
  95
  96        /* After CMD2 set RCA to a none zero value. */
  97        if ((result == 0) && (cmd->cmdidx == MMC_CMD_ALL_SEND_CID))
  98                dev->rca = 10;
  99
 100        /* After CMD3 open drain is switched off and push pull is used. */
 101        if ((result == 0) && (cmd->cmdidx == MMC_CMD_SET_RELATIVE_ADDR)) {
 102                u32 sdi_pwr = readl(&host->base->power) & ~SDI_PWR_OPD;
 103                writel(sdi_pwr, &host->base->power);
 104        }
 105
 106        return result;
 107}
 108
 109static int read_bytes(struct mmc *dev, u32 *dest, u32 blkcount, u32 blksize)
 110{
 111        u32 *tempbuff = dest;
 112        u64 xfercount = blkcount * blksize;
 113        struct pl180_mmc_host *host = dev->priv;
 114        u32 status, status_err;
 115
 116        debug("read_bytes: blkcount=%u blksize=%u\n", blkcount, blksize);
 117
 118        status = readl(&host->base->status);
 119        status_err = status & (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT |
 120                               SDI_STA_RXOVERR);
 121        while ((!status_err) && (xfercount >= sizeof(u32))) {
 122                if (status & SDI_STA_RXDAVL) {
 123                        *(tempbuff) = readl(&host->base->fifo);
 124                        tempbuff++;
 125                        xfercount -= sizeof(u32);
 126                }
 127                status = readl(&host->base->status);
 128                status_err = status & (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT |
 129                                       SDI_STA_RXOVERR);
 130        }
 131
 132        status_err = status &
 133                (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | SDI_STA_DBCKEND |
 134                 SDI_STA_RXOVERR);
 135        while (!status_err) {
 136                status = readl(&host->base->status);
 137                status_err = status &
 138                        (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | SDI_STA_DBCKEND |
 139                         SDI_STA_RXOVERR);
 140        }
 141
 142        if (status & SDI_STA_DTIMEOUT) {
 143                printf("Read data timed out, xfercount: %llu, status: 0x%08X\n",
 144                        xfercount, status);
 145                return -ETIMEDOUT;
 146        } else if (status & SDI_STA_DCRCFAIL) {
 147                printf("Read data bytes CRC error: 0x%x\n", status);
 148                return -EILSEQ;
 149        } else if (status & SDI_STA_RXOVERR) {
 150                printf("Read data RX overflow error\n");
 151                return -EIO;
 152        }
 153
 154        writel(SDI_ICR_MASK, &host->base->status_clear);
 155
 156        if (xfercount) {
 157                printf("Read data error, xfercount: %llu\n", xfercount);
 158                return -ENOBUFS;
 159        }
 160
 161        return 0;
 162}
 163
 164static int write_bytes(struct mmc *dev, u32 *src, u32 blkcount, u32 blksize)
 165{
 166        u32 *tempbuff = src;
 167        int i;
 168        u64 xfercount = blkcount * blksize;
 169        struct pl180_mmc_host *host = dev->priv;
 170        u32 status, status_err;
 171
 172        debug("write_bytes: blkcount=%u blksize=%u\n", blkcount, blksize);
 173
 174        status = readl(&host->base->status);
 175        status_err = status & (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT);
 176        while (!status_err && xfercount) {
 177                if (status & SDI_STA_TXFIFOBW) {
 178                        if (xfercount >= SDI_FIFO_BURST_SIZE * sizeof(u32)) {
 179                                for (i = 0; i < SDI_FIFO_BURST_SIZE; i++)
 180                                        writel(*(tempbuff + i),
 181                                                &host->base->fifo);
 182                                tempbuff += SDI_FIFO_BURST_SIZE;
 183                                xfercount -= SDI_FIFO_BURST_SIZE * sizeof(u32);
 184                        } else {
 185                                while (xfercount >= sizeof(u32)) {
 186                                        writel(*(tempbuff), &host->base->fifo);
 187                                        tempbuff++;
 188                                        xfercount -= sizeof(u32);
 189                                }
 190                        }
 191                }
 192                status = readl(&host->base->status);
 193                status_err = status & (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT);
 194        }
 195
 196        status_err = status &
 197                (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | SDI_STA_DBCKEND);
 198        while (!status_err) {
 199                status = readl(&host->base->status);
 200                status_err = status &
 201                        (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | SDI_STA_DBCKEND);
 202        }
 203
 204        if (status & SDI_STA_DTIMEOUT) {
 205                printf("Write data timed out, xfercount:%llu,status:0x%08X\n",
 206                       xfercount, status);
 207                return -ETIMEDOUT;
 208        } else if (status & SDI_STA_DCRCFAIL) {
 209                printf("Write data CRC error\n");
 210                return -EILSEQ;
 211        }
 212
 213        writel(SDI_ICR_MASK, &host->base->status_clear);
 214
 215        if (xfercount) {
 216                printf("Write data error, xfercount:%llu", xfercount);
 217                return -ENOBUFS;
 218        }
 219
 220        return 0;
 221}
 222
 223static int do_data_transfer(struct mmc *dev,
 224                            struct mmc_cmd *cmd,
 225                            struct mmc_data *data)
 226{
 227        int error = -ETIMEDOUT;
 228        struct pl180_mmc_host *host = dev->priv;
 229        u32 blksz = 0;
 230        u32 data_ctrl = 0;
 231        u32 data_len = (u32) (data->blocks * data->blocksize);
 232
 233        if (!host->version2) {
 234                blksz = (ffs(data->blocksize) - 1);
 235                data_ctrl |= ((blksz << 4) & SDI_DCTRL_DBLKSIZE_MASK);
 236        } else {
 237                blksz = data->blocksize;
 238                data_ctrl |= (blksz << SDI_DCTRL_DBLOCKSIZE_V2_SHIFT);
 239        }
 240        data_ctrl |= SDI_DCTRL_DTEN | SDI_DCTRL_BUSYMODE;
 241
 242        writel(SDI_DTIMER_DEFAULT, &host->base->datatimer);
 243        writel(data_len, &host->base->datalength);
 244        udelay(DATA_REG_DELAY);
 245
 246        if (data->flags & MMC_DATA_READ) {
 247                data_ctrl |= SDI_DCTRL_DTDIR_IN;
 248                writel(data_ctrl, &host->base->datactrl);
 249
 250                error = do_command(dev, cmd);
 251                if (error)
 252                        return error;
 253
 254                error = read_bytes(dev, (u32 *)data->dest, (u32)data->blocks,
 255                                   (u32)data->blocksize);
 256        } else if (data->flags & MMC_DATA_WRITE) {
 257                error = do_command(dev, cmd);
 258                if (error)
 259                        return error;
 260
 261                writel(data_ctrl, &host->base->datactrl);
 262                error = write_bytes(dev, (u32 *)data->src, (u32)data->blocks,
 263                                                        (u32)data->blocksize);
 264        }
 265
 266        return error;
 267}
 268
 269static int host_request(struct mmc *dev,
 270                        struct mmc_cmd *cmd,
 271                        struct mmc_data *data)
 272{
 273        int result;
 274
 275        if (data)
 276                result = do_data_transfer(dev, cmd, data);
 277        else
 278                result = do_command(dev, cmd);
 279
 280        return result;
 281}
 282
 283static int  host_set_ios(struct mmc *dev)
 284{
 285        struct pl180_mmc_host *host = dev->priv;
 286        u32 sdi_clkcr;
 287
 288        sdi_clkcr = readl(&host->base->clock);
 289
 290        /* Ramp up the clock rate */
 291        if (dev->clock) {
 292                u32 clkdiv = 0;
 293                u32 tmp_clock;
 294
 295                if (dev->clock >= dev->cfg->f_max) {
 296                        clkdiv = 0;
 297                        dev->clock = dev->cfg->f_max;
 298                } else {
 299                        clkdiv = (host->clock_in / dev->clock) - 2;
 300                }
 301
 302                tmp_clock = host->clock_in / (clkdiv + 2);
 303                while (tmp_clock > dev->clock) {
 304                        clkdiv++;
 305                        tmp_clock = host->clock_in / (clkdiv + 2);
 306                }
 307
 308                if (clkdiv > SDI_CLKCR_CLKDIV_MASK)
 309                        clkdiv = SDI_CLKCR_CLKDIV_MASK;
 310
 311                tmp_clock = host->clock_in / (clkdiv + 2);
 312                dev->clock = tmp_clock;
 313                sdi_clkcr &= ~(SDI_CLKCR_CLKDIV_MASK);
 314                sdi_clkcr |= clkdiv;
 315        }
 316
 317        /* Set the bus width */
 318        if (dev->bus_width) {
 319                u32 buswidth = 0;
 320
 321                switch (dev->bus_width) {
 322                case 1:
 323                        buswidth |= SDI_CLKCR_WIDBUS_1;
 324                        break;
 325                case 4:
 326                        buswidth |= SDI_CLKCR_WIDBUS_4;
 327                        break;
 328                case 8:
 329                        buswidth |= SDI_CLKCR_WIDBUS_8;
 330                        break;
 331                default:
 332                        printf("Invalid bus width: %d\n", dev->bus_width);
 333                        break;
 334                }
 335                sdi_clkcr &= ~(SDI_CLKCR_WIDBUS_MASK);
 336                sdi_clkcr |= buswidth;
 337        }
 338
 339        writel(sdi_clkcr, &host->base->clock);
 340        udelay(CLK_CHANGE_DELAY);
 341
 342        return 0;
 343}
 344
 345#ifndef CONFIG_DM_MMC
 346/* MMC uses open drain drivers in the enumeration phase */
 347static int mmc_host_reset(struct mmc *dev)
 348{
 349        struct pl180_mmc_host *host = dev->priv;
 350
 351        writel(host->pwr_init, &host->base->power);
 352
 353        return 0;
 354}
 355
 356static const struct mmc_ops arm_pl180_mmci_ops = {
 357        .send_cmd = host_request,
 358        .set_ios = host_set_ios,
 359        .init = mmc_host_reset,
 360};
 361
 362/*
 363 * mmc_host_init - initialize the mmc controller.
 364 * Set initial clock and power for mmc slot.
 365 * Initialize mmc struct and register with mmc framework.
 366 */
 367
 368int arm_pl180_mmci_init(struct pl180_mmc_host *host, struct mmc **mmc)
 369{
 370        u32 sdi_u32;
 371
 372        writel(host->pwr_init, &host->base->power);
 373        writel(host->clkdiv_init, &host->base->clock);
 374        udelay(CLK_CHANGE_DELAY);
 375
 376        /* Disable mmc interrupts */
 377        sdi_u32 = readl(&host->base->mask0) & ~SDI_MASK0_MASK;
 378        writel(sdi_u32, &host->base->mask0);
 379
 380        host->cfg.name = host->name;
 381        host->cfg.ops = &arm_pl180_mmci_ops;
 382
 383        /* TODO remove the duplicates */
 384        host->cfg.host_caps = host->caps;
 385        host->cfg.voltages = host->voltages;
 386        host->cfg.f_min = host->clock_min;
 387        host->cfg.f_max = host->clock_max;
 388        if (host->b_max != 0)
 389                host->cfg.b_max = host->b_max;
 390        else
 391                host->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
 392
 393        *mmc = mmc_create(&host->cfg, host);
 394        if (!*mmc)
 395                return -1;
 396        debug("registered mmc interface number is:%d\n",
 397              (*mmc)->block_dev.devnum);
 398
 399        return 0;
 400}
 401#endif
 402
 403#ifdef CONFIG_DM_MMC
 404static void arm_pl180_mmc_init(struct pl180_mmc_host *host)
 405{
 406        u32 sdi_u32;
 407
 408        writel(host->pwr_init, &host->base->power);
 409        writel(host->clkdiv_init, &host->base->clock);
 410        udelay(CLK_CHANGE_DELAY);
 411
 412        /* Disable mmc interrupts */
 413        sdi_u32 = readl(&host->base->mask0) & ~SDI_MASK0_MASK;
 414        writel(sdi_u32, &host->base->mask0);
 415}
 416
 417static int arm_pl180_mmc_probe(struct udevice *dev)
 418{
 419        struct arm_pl180_mmc_plat *pdata = dev_get_platdata(dev);
 420        struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
 421        struct mmc *mmc = &pdata->mmc;
 422        struct pl180_mmc_host *host = dev->priv;
 423        struct mmc_config *cfg = &pdata->cfg;
 424        struct clk clk;
 425        u32 bus_width;
 426        u32 periphid;
 427        int ret;
 428
 429        ret = clk_get_by_index(dev, 0, &clk);
 430        if (ret < 0)
 431                return ret;
 432
 433        ret = clk_enable(&clk);
 434        if (ret) {
 435                clk_free(&clk);
 436                dev_err(dev, "failed to enable clock\n");
 437                return ret;
 438        }
 439
 440        host->pwr_init = INIT_PWR;
 441        host->clkdiv_init = SDI_CLKCR_CLKDIV_INIT_V1 | SDI_CLKCR_CLKEN |
 442                            SDI_CLKCR_HWFC_EN;
 443        host->clock_in = clk_get_rate(&clk);
 444
 445        periphid = dev_read_u32_default(dev, "arm,primecell-periphid", 0);
 446        switch (periphid) {
 447        case STM32_MMCI_ID: /* stm32 variant */
 448                host->version2 = false;
 449                break;
 450        default:
 451                host->version2 = true;
 452        }
 453
 454        cfg->name = dev->name;
 455        cfg->voltages = VOLTAGE_WINDOW_SD;
 456        cfg->host_caps = 0;
 457        cfg->f_min = host->clock_in / (2 * (SDI_CLKCR_CLKDIV_INIT_V1 + 1));
 458        cfg->f_max = dev_read_u32_default(dev, "max-frequency", MMC_CLOCK_MAX);
 459        cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
 460
 461        gpio_request_by_name(dev, "cd-gpios", 0, &host->cd_gpio, GPIOD_IS_IN);
 462
 463        bus_width = dev_read_u32_default(dev, "bus-width", 1);
 464        switch (bus_width) {
 465        case 8:
 466                cfg->host_caps |= MMC_MODE_8BIT;
 467                /* Hosts capable of 8-bit transfers can also do 4 bits */
 468        case 4:
 469                cfg->host_caps |= MMC_MODE_4BIT;
 470                break;
 471        case 1:
 472                break;
 473        default:
 474                dev_err(dev, "Invalid bus-width value %u\n", bus_width);
 475        }
 476
 477        arm_pl180_mmc_init(host);
 478        mmc->priv = host;
 479        mmc->dev = dev;
 480        upriv->mmc = mmc;
 481
 482        return 0;
 483}
 484
 485int arm_pl180_mmc_bind(struct udevice *dev)
 486{
 487        struct arm_pl180_mmc_plat *plat = dev_get_platdata(dev);
 488
 489        return mmc_bind(dev, &plat->mmc, &plat->cfg);
 490}
 491
 492static int dm_host_request(struct udevice *dev, struct mmc_cmd *cmd,
 493                           struct mmc_data *data)
 494{
 495        struct mmc *mmc = mmc_get_mmc_dev(dev);
 496
 497        return host_request(mmc, cmd, data);
 498}
 499
 500static int dm_host_set_ios(struct udevice *dev)
 501{
 502        struct mmc *mmc = mmc_get_mmc_dev(dev);
 503
 504        return host_set_ios(mmc);
 505}
 506
 507static int dm_mmc_getcd(struct udevice *dev)
 508{
 509        struct pl180_mmc_host *host = dev->priv;
 510        int value = 1;
 511
 512        if (dm_gpio_is_valid(&host->cd_gpio))
 513                value = dm_gpio_get_value(&host->cd_gpio);
 514
 515        return value;
 516}
 517
 518static const struct dm_mmc_ops arm_pl180_dm_mmc_ops = {
 519        .send_cmd = dm_host_request,
 520        .set_ios = dm_host_set_ios,
 521        .get_cd = dm_mmc_getcd,
 522};
 523
 524static int arm_pl180_mmc_ofdata_to_platdata(struct udevice *dev)
 525{
 526        struct pl180_mmc_host *host = dev->priv;
 527        fdt_addr_t addr;
 528
 529        addr = dev_read_addr(dev);
 530        if (addr == FDT_ADDR_T_NONE)
 531                return -EINVAL;
 532
 533        host->base = (void *)addr;
 534
 535        return 0;
 536}
 537
 538static const struct udevice_id arm_pl180_mmc_match[] = {
 539        { .compatible = "arm,pl180" },
 540        { .compatible = "arm,primecell" },
 541        { /* sentinel */ }
 542};
 543
 544U_BOOT_DRIVER(arm_pl180_mmc) = {
 545        .name = "arm_pl180_mmc",
 546        .id = UCLASS_MMC,
 547        .of_match = arm_pl180_mmc_match,
 548        .ops = &arm_pl180_dm_mmc_ops,
 549        .probe = arm_pl180_mmc_probe,
 550        .ofdata_to_platdata = arm_pl180_mmc_ofdata_to_platdata,
 551        .bind = arm_pl180_mmc_bind,
 552        .priv_auto_alloc_size = sizeof(struct pl180_mmc_host),
 553        .platdata_auto_alloc_size = sizeof(struct arm_pl180_mmc_plat),
 554};
 555#endif
 556