]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - drivers/mmc/imx_ssp_mmc.c
Update from 2013.01 to 2013.07
[karo-tx-uboot.git] / drivers / mmc / imx_ssp_mmc.c
diff --git a/drivers/mmc/imx_ssp_mmc.c b/drivers/mmc/imx_ssp_mmc.c
deleted file mode 100644 (file)
index fc480a5..0000000
+++ /dev/null
@@ -1,385 +0,0 @@
-/*
- * (C) Copyright 2008-2010 Freescale Semiconductor, Inc.
- * Terry Lv
- *
- * Copyright 2007, Freescale Semiconductor, Inc
- * Andy Fleming
- *
- * Based vaguely on the pxa mmc code:
- * (C) Copyright 2003
- * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
-#include <common.h>
-#include <malloc.h>
-#include <mmc.h>
-#include <asm/arch/regs-ssp.h>
-#include <asm/arch/regs-clkctrl.h>
-#include <imx_ssp_mmc.h>
-
-#undef IMX_SSP_MMC_DEBUG
-
-static inline int ssp_mmc_read(struct mmc *mmc, uint reg)
-{
-       struct imx_ssp_mmc_cfg *cfg = (struct imx_ssp_mmc_cfg *)mmc->priv;
-       return REG_RD(cfg->ssp_mmc_base, reg);
-}
-
-static inline void ssp_mmc_write(struct mmc *mmc, uint reg, uint val)
-{
-       struct imx_ssp_mmc_cfg *cfg = (struct imx_ssp_mmc_cfg *)mmc->priv;
-       REG_WR(cfg->ssp_mmc_base, reg, val);
-}
-
-static inline void mdelay(unsigned long msec)
-{
-       unsigned long i;
-       for (i = 0; i < msec; i++)
-               udelay(1000);
-}
-
-static inline void sdelay(unsigned long sec)
-{
-       unsigned long i;
-       for (i = 0; i < sec; i++)
-               mdelay(1000);
-}
-
-/*
- * Sends a command out on the bus.  Takes the mmc pointer,
- * a command pointer, and an optional data pointer.
- */
-static int
-ssp_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
-{
-       int i;
-
-#ifdef IMX_SSP_MMC_DEBUG
-       printf("MMC%d: CMD%d\n", mmc->block_dev.dev, cmd->cmdidx);
-#endif
-
-       /* Check bus busy */
-       i = 0;
-       while (ssp_mmc_read(mmc, HW_SSP_STATUS) & (BM_SSP_STATUS_BUSY |
-               BM_SSP_STATUS_DATA_BUSY | BM_SSP_STATUS_CMD_BUSY)) {
-               mdelay(1);
-               i++;
-               if (i == 1000) {
-                       printf("MMC%d: Bus busy timeout!\n",
-                               mmc->block_dev.dev);
-                       return TIMEOUT;
-               }
-       }
-
-       /* See if card is present */
-       if (ssp_mmc_read(mmc, HW_SSP_STATUS) & BM_SSP_STATUS_CARD_DETECT) {
-               printf("MMC%d: No card detected!\n", mmc->block_dev.dev);
-               return NO_CARD_ERR;
-       }
-
-       /* Clear all control bits except bus width */
-       ssp_mmc_write(mmc, HW_SSP_CTRL0_CLR, 0xff3fffff);
-
-       /* Set up command */
-       if (!(cmd->resp_type & MMC_RSP_CRC))
-               ssp_mmc_write(mmc, HW_SSP_CTRL0_SET, BM_SSP_CTRL0_IGNORE_CRC);
-       if (cmd->resp_type & MMC_RSP_PRESENT)   /* Need to get response */
-               ssp_mmc_write(mmc, HW_SSP_CTRL0_SET, BM_SSP_CTRL0_GET_RESP);
-       if (cmd->resp_type & MMC_RSP_136)       /* It's a 136 bits response */
-               ssp_mmc_write(mmc, HW_SSP_CTRL0_SET, BM_SSP_CTRL0_LONG_RESP);
-
-       /* Command index */
-       ssp_mmc_write(mmc, HW_SSP_CMD0,
-               (ssp_mmc_read(mmc, HW_SSP_CMD0) & ~BM_SSP_CMD0_CMD) |
-               (cmd->cmdidx << BP_SSP_CMD0_CMD));
-       /* Command argument */
-       ssp_mmc_write(mmc, HW_SSP_CMD1, cmd->cmdarg);
-
-       /* Set up data */
-       if (data) {
-               /* READ or WRITE */
-               if (data->flags & MMC_DATA_READ) {
-                       ssp_mmc_write(mmc, HW_SSP_CTRL0_SET,
-                               BM_SSP_CTRL0_READ);
-               } else if (ssp_mmc_is_wp(mmc)) {
-                       printf("MMC%d: Can not write a locked card!\n",
-                               mmc->block_dev.dev);
-                       return UNUSABLE_ERR;
-               }
-               ssp_mmc_write(mmc, HW_SSP_CTRL0_SET, BM_SSP_CTRL0_DATA_XFER);
-               ssp_mmc_write(mmc, HW_SSP_BLOCK_SIZE,
-                       ((data->blocks - 1) <<
-                               BP_SSP_BLOCK_SIZE_BLOCK_COUNT) |
-                       ((ffs(data->blocksize) - 1) <<
-                               BP_SSP_BLOCK_SIZE_BLOCK_SIZE));
-               ssp_mmc_write(mmc, HW_SSP_XFER_SIZE,
-                       data->blocksize * data->blocks);
-       }
-
-       /* Kick off the command */
-       ssp_mmc_write(mmc, HW_SSP_CTRL0_SET, BM_SSP_CTRL0_WAIT_FOR_IRQ);
-       ssp_mmc_write(mmc, HW_SSP_CTRL0_SET, BM_SSP_CTRL0_ENABLE);
-       ssp_mmc_write(mmc, HW_SSP_CTRL0_SET, BM_SSP_CTRL0_RUN);
-
-       /* Wait for the command to complete */
-       i = 0;
-       do {
-               mdelay(10);
-               if (i++ == 100) {
-                       printf("MMC%d: Command %d busy\n",
-                               mmc->block_dev.dev,
-                               cmd->cmdidx);
-                       break;
-               }
-       } while (ssp_mmc_read(mmc, HW_SSP_STATUS) &
-               BM_SSP_STATUS_CMD_BUSY);
-
-       /* Check command timeout */
-       if (ssp_mmc_read(mmc, HW_SSP_STATUS) &
-               BM_SSP_STATUS_RESP_TIMEOUT) {
-#ifdef IMX_SSP_MMC_DEBUG
-               printf("MMC%d: Command %d timeout\n", mmc->block_dev.dev,
-                       cmd->cmdidx);
-#endif
-               return TIMEOUT;
-       }
-
-       /* Check command errors */
-       if (ssp_mmc_read(mmc, HW_SSP_STATUS) &
-               (BM_SSP_STATUS_RESP_CRC_ERR | BM_SSP_STATUS_RESP_ERR)) {
-               printf("MMC%d: Command %d error (status 0x%08x)!\n",
-                       mmc->block_dev.dev, cmd->cmdidx,
-                       ssp_mmc_read(mmc, HW_SSP_STATUS));
-               return COMM_ERR;
-       }
-
-       /* Copy response to response buffer */
-       if (cmd->resp_type & MMC_RSP_136) {
-               cmd->response[3] = ssp_mmc_read(mmc, HW_SSP_SDRESP0);
-               cmd->response[2] = ssp_mmc_read(mmc, HW_SSP_SDRESP1);
-               cmd->response[1] = ssp_mmc_read(mmc, HW_SSP_SDRESP2);
-               cmd->response[0] = ssp_mmc_read(mmc, HW_SSP_SDRESP3);
-       } else
-               cmd->response[0] = ssp_mmc_read(mmc, HW_SSP_SDRESP0);
-
-       /* Return if no data to process */
-       if (!data)
-               return 0;
-
-       /* Process the data */
-       u32 xfer_cnt = data->blocksize * data->blocks;
-       u32 *tmp_ptr;
-
-       if (data->flags & MMC_DATA_READ) {
-               tmp_ptr = (u32 *)data->dest;
-               while (xfer_cnt > 0) {
-                       if ((ssp_mmc_read(mmc, HW_SSP_STATUS) &
-                               BM_SSP_STATUS_FIFO_EMPTY) == 0) {
-                               *tmp_ptr++ = ssp_mmc_read(mmc, HW_SSP_DATA);
-                               xfer_cnt -= 4;
-                       }
-               }
-       } else {
-               tmp_ptr = (u32 *)data->src;
-               while (xfer_cnt > 0) {
-                       if ((ssp_mmc_read(mmc, HW_SSP_STATUS) &
-                               BM_SSP_STATUS_FIFO_FULL) == 0) {
-                               ssp_mmc_write(mmc, HW_SSP_DATA, *tmp_ptr++);
-                               xfer_cnt -= 4;
-                       }
-               }
-       }
-
-       /* Check data errors */
-       if (ssp_mmc_read(mmc, HW_SSP_STATUS) &
-               (BM_SSP_STATUS_TIMEOUT | BM_SSP_STATUS_DATA_CRC_ERR |
-               BM_SSP_STATUS_FIFO_OVRFLW | BM_SSP_STATUS_FIFO_UNDRFLW)) {
-               printf("MMC%d: Data error with command %d (status 0x%08x)!\n",
-                       mmc->block_dev.dev, cmd->cmdidx,
-                       ssp_mmc_read(mmc, HW_SSP_STATUS));
-               return COMM_ERR;
-       }
-
-       return 0;
-}
-
-static void set_bit_clock(struct mmc *mmc, u32 clock)
-{
-       const u32 sspclk = 480000 * 18 / 29 / 1;        /* 297931 KHz */
-       u32 divide, rate, tgtclk;
-
-       /*
-        * SSP bit rate = SSPCLK / (CLOCK_DIVIDE * (1 + CLOCK_RATE)),
-        * CLOCK_DIVIDE has to be an even value from 2 to 254, and
-        * CLOCK_RATE could be any integer from 0 to 255.
-        */
-       clock /= 1000;          /* KHz */
-       for (divide = 2; divide < 254; divide += 2) {
-               rate = sspclk / clock / divide;
-               if (rate <= 256)
-                       break;
-       }
-
-       tgtclk = sspclk / divide / rate;
-       while (tgtclk > clock) {
-               rate++;
-               tgtclk = sspclk / divide / rate;
-       }
-       if (rate > 256)
-               rate = 256;
-
-       /* Always set timeout the maximum */
-       ssp_mmc_write(mmc, HW_SSP_TIMING, BM_SSP_TIMING_TIMEOUT |
-               divide << BP_SSP_TIMING_CLOCK_DIVIDE |
-               (rate - 1) << BP_SSP_TIMING_CLOCK_RATE);
-
-#ifdef IMX_SSP_MMC_DEBUG
-       printf("MMC%d: Set clock rate to %d KHz (requested %d KHz)\n",
-               mmc->block_dev.dev, tgtclk, clock);
-#endif
-}
-
-static void ssp_mmc_set_ios(struct mmc *mmc)
-{
-       u32 regval;
-
-       /* Set the clock speed */
-       if (mmc->clock)
-               set_bit_clock(mmc, mmc->clock);
-
-       /* Set the bus width */
-       regval = ssp_mmc_read(mmc, HW_SSP_CTRL0);
-       regval &= ~BM_SSP_CTRL0_BUS_WIDTH;
-       switch (mmc->bus_width) {
-       case 1:
-               regval |= (BV_SSP_CTRL0_BUS_WIDTH__ONE_BIT <<
-                               BP_SSP_CTRL0_BUS_WIDTH);
-               break;
-       case 4:
-               regval |= (BV_SSP_CTRL0_BUS_WIDTH__FOUR_BIT <<
-                               BP_SSP_CTRL0_BUS_WIDTH);
-               break;
-       case 8:
-               regval |= (BV_SSP_CTRL0_BUS_WIDTH__EIGHT_BIT <<
-                               BP_SSP_CTRL0_BUS_WIDTH);
-       }
-       ssp_mmc_write(mmc, HW_SSP_CTRL0, regval);
-
-#ifdef IMX_SSP_MMC_DEBUG
-       printf("MMC%d: Set %d bits bus width\n",
-               mmc->block_dev.dev, mmc->bus_width);
-#endif
-}
-
-static int ssp_mmc_init(struct mmc *mmc)
-{
-       struct imx_ssp_mmc_cfg *cfg = (struct imx_ssp_mmc_cfg *)mmc->priv;
-       u32 regval;
-
-       /*
-        * Set up SSPCLK
-        */
-       /* Set REF_IO0 at 297.731 MHz */
-       regval = REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_FRAC0);
-       regval &= ~BM_CLKCTRL_FRAC0_IO0FRAC;
-       REG_WR(REGS_CLKCTRL_BASE, HW_CLKCTRL_FRAC0,
-               regval | (29 << BP_CLKCTRL_FRAC0_IO0FRAC));
-       /* Enable REF_IO0 */
-       REG_CLR(REGS_CLKCTRL_BASE, HW_CLKCTRL_FRAC0,
-               BM_CLKCTRL_FRAC0_CLKGATEIO0);
-
-       /* Source SSPCLK from REF_IO0 */
-       REG_CLR(REGS_CLKCTRL_BASE, HW_CLKCTRL_CLKSEQ,
-               cfg->clkctrl_clkseq_ssp_offset);
-       /* Turn on SSPCLK */
-       REG_WR(REGS_CLKCTRL_BASE, cfg->clkctrl_ssp_offset,
-               REG_RD(REGS_CLKCTRL_BASE, cfg->clkctrl_ssp_offset) &
-               ~BM_CLKCTRL_SSP_CLKGATE);
-       /* Set SSPCLK divide 1 */
-       regval = REG_RD(REGS_CLKCTRL_BASE, cfg->clkctrl_ssp_offset);
-       regval &= ~(BM_CLKCTRL_SSP_DIV_FRAC_EN | BM_CLKCTRL_SSP_DIV);
-       REG_WR(REGS_CLKCTRL_BASE, cfg->clkctrl_ssp_offset,
-               regval | (1 << BP_CLKCTRL_SSP_DIV));
-       /* Wait for new divide ready */
-       do {
-               udelay(10);
-       } while (REG_RD(REGS_CLKCTRL_BASE, cfg->clkctrl_ssp_offset) &
-               BM_CLKCTRL_SSP_BUSY);
-
-       /* Prepare for software reset */
-       ssp_mmc_write(mmc, HW_SSP_CTRL0_CLR, BM_SSP_CTRL0_SFTRST);
-       ssp_mmc_write(mmc, HW_SSP_CTRL0_CLR, BM_SSP_CTRL0_CLKGATE);
-       /* Assert reset */
-       ssp_mmc_write(mmc, HW_SSP_CTRL0_SET, BM_SSP_CTRL0_SFTRST);
-       /* Wait for confirmation */
-       while (!(ssp_mmc_read(mmc, HW_SSP_CTRL0) & BM_SSP_CTRL0_CLKGATE))
-               ;
-       /* Done */
-       ssp_mmc_write(mmc, HW_SSP_CTRL0_CLR, BM_SSP_CTRL0_SFTRST);
-       ssp_mmc_write(mmc, HW_SSP_CTRL0_CLR, BM_SSP_CTRL0_CLKGATE);
-
-       /* 8 bits word length in MMC mode */
-       regval = ssp_mmc_read(mmc, HW_SSP_CTRL1);
-       regval &= ~(BM_SSP_CTRL1_SSP_MODE | BM_SSP_CTRL1_WORD_LENGTH);
-       ssp_mmc_write(mmc, HW_SSP_CTRL1, regval |
-               (BV_SSP_CTRL1_SSP_MODE__SD_MMC << BP_SSP_CTRL1_SSP_MODE) |
-               (BV_SSP_CTRL1_WORD_LENGTH__EIGHT_BITS <<
-                       BP_SSP_CTRL1_WORD_LENGTH));
-
-       /* Set initial bit clock 400 KHz */
-       set_bit_clock(mmc, 400000);
-
-       /* Send initial 74 clock cycles (185 us @ 400 KHz)*/
-       ssp_mmc_write(mmc, HW_SSP_CMD0_SET, BM_SSP_CMD0_CONT_CLKING_EN);
-       udelay(200);
-       ssp_mmc_write(mmc, HW_SSP_CMD0_CLR, BM_SSP_CMD0_CONT_CLKING_EN);
-
-       return 0;
-}
-
-int imx_ssp_mmc_initialize(bd_t *bis, struct imx_ssp_mmc_cfg *cfg)
-{
-       struct mmc *mmc;
-
-       mmc = malloc(sizeof(struct mmc));
-       sprintf(mmc->name, "IMX_SSP_MMC");
-       mmc->send_cmd = ssp_mmc_send_cmd;
-       mmc->set_ios = ssp_mmc_set_ios;
-       mmc->init = ssp_mmc_init;
-       mmc->priv = cfg;
-
-       mmc->voltages = MMC_VDD_32_33 | MMC_VDD_31_32 | MMC_VDD_30_31 |
-                       MMC_VDD_29_30 | MMC_VDD_28_29 | MMC_VDD_27_28;
-
-       mmc->host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT |
-                        MMC_MODE_HS_52MHz | MMC_MODE_HS;
-
-       /*
-        * SSPCLK = 480 * 18 / 29 / 1 = 297.731 MHz
-        * SSP bit rate = SSPCLK / (CLOCK_DIVIDE * (1 + CLOCK_RATE)),
-        * CLOCK_DIVIDE has to be an even value from 2 to 254, and
-        * CLOCK_RATE could be any integer from 0 to 255.
-        */
-       mmc->f_min = 400000;
-       mmc->f_max = 148000000; /* 297.731 MHz / 2 */
-
-       mmc_register(mmc);
-       return 0;
-}