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