uboot/drivers/mmc/gen_atmel_mci.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2010
   3 * Rob Emanuele <rob@emanuele.us>
   4 * Reinhard Meyer, EMK Elektronik <reinhard.meyer@emk-elektronik.de>
   5 *
   6 * Original Driver:
   7 * Copyright (C) 2004-2006 Atmel Corporation
   8 *
   9 * SPDX-License-Identifier:     GPL-2.0+
  10 */
  11
  12#include <common.h>
  13#include <mmc.h>
  14#include <part.h>
  15#include <malloc.h>
  16#include <asm/io.h>
  17#include <linux/errno.h>
  18#include <asm/byteorder.h>
  19#include <asm/arch/clk.h>
  20#include <asm/arch/hardware.h>
  21#include "atmel_mci.h"
  22
  23#ifndef CONFIG_SYS_MMC_CLK_OD
  24# define CONFIG_SYS_MMC_CLK_OD  150000
  25#endif
  26
  27#define MMC_DEFAULT_BLKLEN      512
  28
  29#if defined(CONFIG_ATMEL_MCI_PORTB)
  30# define MCI_BUS 1
  31#else
  32# define MCI_BUS 0
  33#endif
  34
  35struct atmel_mci_priv {
  36        struct mmc_config       cfg;
  37        struct atmel_mci        *mci;
  38        unsigned int            initialized:1;
  39        unsigned int            curr_clk;
  40};
  41
  42/* Read Atmel MCI IP version */
  43static unsigned int atmel_mci_get_version(struct atmel_mci *mci)
  44{
  45        return readl(&mci->version) & 0x00000fff;
  46}
  47
  48/*
  49 * Print command and status:
  50 *
  51 * - always when DEBUG is defined
  52 * - on command errors
  53 */
  54static void dump_cmd(u32 cmdr, u32 arg, u32 status, const char* msg)
  55{
  56        debug("gen_atmel_mci: CMDR %08x (%2u) ARGR %08x (SR: %08x) %s\n",
  57              cmdr, cmdr & 0x3F, arg, status, msg);
  58}
  59
  60/* Setup for MCI Clock and Block Size */
  61static void mci_set_mode(struct mmc *mmc, u32 hz, u32 blklen)
  62{
  63        struct atmel_mci_priv *priv = mmc->priv;
  64        atmel_mci_t *mci = priv->mci;
  65        u32 bus_hz = get_mci_clk_rate();
  66        u32 clkdiv = 255;
  67        unsigned int version = atmel_mci_get_version(mci);
  68        u32 clkodd = 0;
  69        u32 mr;
  70
  71        debug("mci: bus_hz is %u, setting clock %u Hz, block size %u\n",
  72                bus_hz, hz, blklen);
  73        if (hz > 0) {
  74                if (version >= 0x500) {
  75                        clkdiv = DIV_ROUND_UP(bus_hz, hz) - 2;
  76                        if (clkdiv > 511)
  77                                clkdiv = 511;
  78
  79                        clkodd = clkdiv & 1;
  80                        clkdiv >>= 1;
  81
  82                        debug("mci: setting clock %u Hz, block size %u\n",
  83                              bus_hz / (clkdiv * 2 + clkodd + 2), blklen);
  84                } else {
  85                        /* find clkdiv yielding a rate <= than requested */
  86                        for (clkdiv = 0; clkdiv < 255; clkdiv++) {
  87                                if ((bus_hz / (clkdiv + 1) / 2) <= hz)
  88                                        break;
  89                        }
  90                        debug("mci: setting clock %u Hz, block size %u\n",
  91                              (bus_hz / (clkdiv + 1)) / 2, blklen);
  92
  93                }
  94        }
  95        if (version >= 0x500)
  96                priv->curr_clk = bus_hz / (clkdiv * 2 + clkodd + 2);
  97        else
  98                priv->curr_clk = (bus_hz / (clkdiv + 1)) / 2;
  99        blklen &= 0xfffc;
 100
 101        mr = MMCI_BF(CLKDIV, clkdiv);
 102
 103        /* MCI IP version >= 0x200 has R/WPROOF */
 104        if (version >= 0x200)
 105                mr |= MMCI_BIT(RDPROOF) | MMCI_BIT(WRPROOF);
 106
 107        /*
 108         * MCI IP version >= 0x500 use bit 16 as clkodd.
 109         * MCI IP version < 0x500 use upper 16 bits for blklen.
 110         */
 111        if (version >= 0x500)
 112                mr |= MMCI_BF(CLKODD, clkodd);
 113        else
 114                mr |= MMCI_BF(BLKLEN, blklen);
 115
 116        writel(mr, &mci->mr);
 117
 118        /* MCI IP version >= 0x200 has blkr */
 119        if (version >= 0x200)
 120                writel(MMCI_BF(BLKLEN, blklen), &mci->blkr);
 121
 122        if (mmc->card_caps & mmc->cfg->host_caps & MMC_MODE_HS)
 123                writel(MMCI_BIT(HSMODE), &mci->cfg);
 124
 125        priv->initialized = 1;
 126}
 127
 128/* Return the CMDR with flags for a given command and data packet */
 129static u32 mci_encode_cmd(
 130        struct mmc_cmd *cmd, struct mmc_data *data, u32* error_flags)
 131{
 132        u32 cmdr = 0;
 133
 134        /* Default Flags for Errors */
 135        *error_flags |= (MMCI_BIT(DTOE) | MMCI_BIT(RDIRE) | MMCI_BIT(RENDE) |
 136                MMCI_BIT(RINDE) | MMCI_BIT(RTOE));
 137
 138        /* Default Flags for the Command */
 139        cmdr |= MMCI_BIT(MAXLAT);
 140
 141        if (data) {
 142                cmdr |= MMCI_BF(TRCMD, 1);
 143                if (data->blocks > 1)
 144                        cmdr |= MMCI_BF(TRTYP, 1);
 145                if (data->flags & MMC_DATA_READ)
 146                        cmdr |= MMCI_BIT(TRDIR);
 147        }
 148
 149        if (cmd->resp_type & MMC_RSP_CRC)
 150                *error_flags |= MMCI_BIT(RCRCE);
 151        if (cmd->resp_type & MMC_RSP_136)
 152                cmdr |= MMCI_BF(RSPTYP, 2);
 153        else if (cmd->resp_type & MMC_RSP_BUSY)
 154                cmdr |= MMCI_BF(RSPTYP, 3);
 155        else if (cmd->resp_type & MMC_RSP_PRESENT)
 156                cmdr |= MMCI_BF(RSPTYP, 1);
 157
 158        return cmdr | MMCI_BF(CMDNB, cmd->cmdidx);
 159}
 160
 161/* Entered into function pointer in mci_send_cmd */
 162static u32 mci_data_read(atmel_mci_t *mci, u32* data, u32 error_flags)
 163{
 164        u32 status;
 165
 166        do {
 167                status = readl(&mci->sr);
 168                if (status & (error_flags | MMCI_BIT(OVRE)))
 169                        goto io_fail;
 170        } while (!(status & MMCI_BIT(RXRDY)));
 171
 172        if (status & MMCI_BIT(RXRDY)) {
 173                *data = readl(&mci->rdr);
 174                status = 0;
 175        }
 176io_fail:
 177        return status;
 178}
 179
 180/* Entered into function pointer in mci_send_cmd */
 181static u32 mci_data_write(atmel_mci_t *mci, u32* data, u32 error_flags)
 182{
 183        u32 status;
 184
 185        do {
 186                status = readl(&mci->sr);
 187                if (status & (error_flags | MMCI_BIT(UNRE)))
 188                        goto io_fail;
 189        } while (!(status & MMCI_BIT(TXRDY)));
 190
 191        if (status & MMCI_BIT(TXRDY)) {
 192                writel(*data, &mci->tdr);
 193                status = 0;
 194        }
 195io_fail:
 196        return status;
 197}
 198
 199/*
 200 * Entered into mmc structure during driver init
 201 *
 202 * Sends a command out on the bus and deals with the block data.
 203 * Takes the mmc pointer, a command pointer, and an optional data pointer.
 204 */
 205static int
 206mci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
 207{
 208        struct atmel_mci_priv *priv = mmc->priv;
 209        atmel_mci_t *mci = priv->mci;
 210        u32 cmdr;
 211        u32 error_flags = 0;
 212        u32 status;
 213
 214        if (!priv->initialized) {
 215                puts ("MCI not initialized!\n");
 216                return -ECOMM;
 217        }
 218
 219        /* Figure out the transfer arguments */
 220        cmdr = mci_encode_cmd(cmd, data, &error_flags);
 221
 222        /* For multi blocks read/write, set the block register */
 223        if ((cmd->cmdidx == MMC_CMD_READ_MULTIPLE_BLOCK)
 224                        || (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK))
 225                writel(data->blocks | MMCI_BF(BLKLEN, mmc->read_bl_len),
 226                        &mci->blkr);
 227
 228        /* Send the command */
 229        writel(cmd->cmdarg, &mci->argr);
 230        writel(cmdr, &mci->cmdr);
 231
 232#ifdef DEBUG
 233        dump_cmd(cmdr, cmd->cmdarg, 0, "DEBUG");
 234#endif
 235
 236        /* Wait for the command to complete */
 237        while (!((status = readl(&mci->sr)) & MMCI_BIT(CMDRDY)));
 238
 239        if ((status & error_flags) & MMCI_BIT(RTOE)) {
 240                dump_cmd(cmdr, cmd->cmdarg, status, "Command Time Out");
 241                return -ETIMEDOUT;
 242        } else if (status & error_flags) {
 243                dump_cmd(cmdr, cmd->cmdarg, status, "Command Failed");
 244                return -ECOMM;
 245        }
 246
 247        /* Copy the response to the response buffer */
 248        if (cmd->resp_type & MMC_RSP_136) {
 249                cmd->response[0] = readl(&mci->rspr);
 250                cmd->response[1] = readl(&mci->rspr1);
 251                cmd->response[2] = readl(&mci->rspr2);
 252                cmd->response[3] = readl(&mci->rspr3);
 253        } else
 254                cmd->response[0] = readl(&mci->rspr);
 255
 256        /* transfer all of the blocks */
 257        if (data) {
 258                u32 word_count, block_count;
 259                u32* ioptr;
 260                u32 sys_blocksize, dummy, i;
 261                u32 (*mci_data_op)
 262                        (atmel_mci_t *mci, u32* data, u32 error_flags);
 263
 264                if (data->flags & MMC_DATA_READ) {
 265                        mci_data_op = mci_data_read;
 266                        sys_blocksize = mmc->read_bl_len;
 267                        ioptr = (u32*)data->dest;
 268                } else {
 269                        mci_data_op = mci_data_write;
 270                        sys_blocksize = mmc->write_bl_len;
 271                        ioptr = (u32*)data->src;
 272                }
 273
 274                status = 0;
 275                for (block_count = 0;
 276                                block_count < data->blocks && !status;
 277                                block_count++) {
 278                        word_count = 0;
 279                        do {
 280                                status = mci_data_op(mci, ioptr, error_flags);
 281                                word_count++;
 282                                ioptr++;
 283                        } while (!status && word_count < (data->blocksize/4));
 284#ifdef DEBUG
 285                        if (data->flags & MMC_DATA_READ)
 286                        {
 287                                u32 cnt = word_count * 4;
 288                                printf("Read Data:\n");
 289                                print_buffer(0, data->dest + cnt * block_count,
 290                                             1, cnt, 0);
 291                        }
 292#endif
 293#ifdef DEBUG
 294                        if (!status && word_count < (sys_blocksize / 4))
 295                                printf("filling rest of block...\n");
 296#endif
 297                        /* fill the rest of a full block */
 298                        while (!status && word_count < (sys_blocksize / 4)) {
 299                                status = mci_data_op(mci, &dummy,
 300                                        error_flags);
 301                                word_count++;
 302                        }
 303                        if (status) {
 304                                dump_cmd(cmdr, cmd->cmdarg, status,
 305                                        "Data Transfer Failed");
 306                                return -ECOMM;
 307                        }
 308                }
 309
 310                /* Wait for Transfer End */
 311                i = 0;
 312                do {
 313                        status = readl(&mci->sr);
 314
 315                        if (status & error_flags) {
 316                                dump_cmd(cmdr, cmd->cmdarg, status,
 317                                        "DTIP Wait Failed");
 318                                return -ECOMM;
 319                        }
 320                        i++;
 321                } while ((status & MMCI_BIT(DTIP)) && i < 10000);
 322                if (status & MMCI_BIT(DTIP)) {
 323                        dump_cmd(cmdr, cmd->cmdarg, status,
 324                                "XFER DTIP never unset, ignoring");
 325                }
 326        }
 327
 328        /*
 329         * After the switch command, wait for 8 clocks before the next
 330         * command
 331         */
 332        if (cmd->cmdidx == MMC_CMD_SWITCH)
 333                udelay(8*1000000 / priv->curr_clk); /* 8 clk in us */
 334
 335        return 0;
 336}
 337
 338/* Entered into mmc structure during driver init */
 339static void mci_set_ios(struct mmc *mmc)
 340{
 341        struct atmel_mci_priv *priv = mmc->priv;
 342        atmel_mci_t *mci = priv->mci;
 343        int bus_width = mmc->bus_width;
 344        unsigned int version = atmel_mci_get_version(mci);
 345        int busw;
 346
 347        /* Set the clock speed */
 348        mci_set_mode(mmc, mmc->clock, MMC_DEFAULT_BLKLEN);
 349
 350        /*
 351         * set the bus width and select slot for this interface
 352         * there is no capability for multiple slots on the same interface yet
 353         */
 354        if ((version & 0xf00) >= 0x300) {
 355                switch (bus_width) {
 356                case 8:
 357                        busw = 3;
 358                        break;
 359                case 4:
 360                        busw = 2;
 361                        break;
 362                default:
 363                        busw = 0;
 364                        break;
 365                }
 366
 367                writel(busw << 6 | MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr);
 368        } else {
 369                busw = (bus_width == 4) ? 1 : 0;
 370
 371                writel(busw << 7 | MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr);
 372        }
 373}
 374
 375/* Entered into mmc structure during driver init */
 376static int mci_init(struct mmc *mmc)
 377{
 378        struct atmel_mci_priv *priv = mmc->priv;
 379        atmel_mci_t *mci = priv->mci;
 380
 381        /* Initialize controller */
 382        writel(MMCI_BIT(SWRST), &mci->cr);      /* soft reset */
 383        writel(MMCI_BIT(PWSDIS), &mci->cr);     /* disable power save */
 384        writel(MMCI_BIT(MCIEN), &mci->cr);      /* enable mci */
 385        writel(MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr);   /* select port */
 386
 387        /* This delay can be optimized, but stick with max value */
 388        writel(0x7f, &mci->dtor);
 389        /* Disable Interrupts */
 390        writel(~0UL, &mci->idr);
 391
 392        /* Set default clocks and blocklen */
 393        mci_set_mode(mmc, CONFIG_SYS_MMC_CLK_OD, MMC_DEFAULT_BLKLEN);
 394
 395        return 0;
 396}
 397
 398static const struct mmc_ops atmel_mci_ops = {
 399        .send_cmd       = mci_send_cmd,
 400        .set_ios        = mci_set_ios,
 401        .init           = mci_init,
 402};
 403
 404/*
 405 * This is the only exported function
 406 *
 407 * Call it with the MCI register base address
 408 */
 409int atmel_mci_init(void *regs)
 410{
 411        struct mmc *mmc;
 412        struct mmc_config *cfg;
 413        struct atmel_mci_priv *priv;
 414        unsigned int version;
 415
 416        priv = calloc(1, sizeof(*priv));
 417        if (!priv)
 418                return -ENOMEM;
 419
 420        cfg = &priv->cfg;
 421
 422        cfg->name = "mci";
 423        cfg->ops = &atmel_mci_ops;
 424
 425        priv->mci = (struct atmel_mci *)regs;
 426        priv->initialized = 0;
 427
 428        /* need to be able to pass these in on a board by board basis */
 429        cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
 430        version = atmel_mci_get_version(priv->mci);
 431        if ((version & 0xf00) >= 0x300) {
 432                cfg->host_caps = MMC_MODE_8BIT;
 433                cfg->host_caps |= MMC_MODE_HS | MMC_MODE_HS_52MHz;
 434        }
 435
 436        cfg->host_caps |= MMC_MODE_4BIT;
 437
 438        /*
 439         * min and max frequencies determined by
 440         * max and min of clock divider
 441         */
 442        cfg->f_min = get_mci_clk_rate() / (2*256);
 443        cfg->f_max = get_mci_clk_rate() / (2*1);
 444
 445        cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
 446
 447        mmc = mmc_create(cfg, priv);
 448
 449        if (mmc == NULL) {
 450                free(priv);
 451                return -ENODEV;
 452        }
 453        /* NOTE: possibly leaking the priv structure */
 454
 455        return 0;
 456}
 457