This uses the new MMC framework

Some contributions by Dave Liu <[EMAIL PROTECTED]>

Signed-off-by: Andy Fleming <[EMAIL PROTECTED]>
---
 drivers/mmc/Makefile    |    1 +
 drivers/mmc/fsl_esdhc.c |  344 +++++++++++++++++++++++++++++++++++++++++++++++
 include/fsl_esdhc.h     |  136 +++++++++++++++++++
 3 files changed, 481 insertions(+), 0 deletions(-)
 create mode 100644 drivers/mmc/fsl_esdhc.c
 create mode 100644 include/fsl_esdhc.h

diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index d5a969c..040be8d 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -27,6 +27,7 @@ LIB   := $(obj)libmmc.a
 
 COBJS-$(CONFIG_GENERIC_MMC) += mmc.o
 COBJS-$(CONFIG_ATMEL_MCI) += atmel_mci.o
+COBJS-$(CONFIG_FSL_ESDHC) += fsl_esdhc.o
 
 COBJS  := $(COBJS-y)
 SRCS   := $(COBJS:.o=.c)
diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c
new file mode 100644
index 0000000..f6c6fff
--- /dev/null
+++ b/drivers/mmc/fsl_esdhc.c
@@ -0,0 +1,344 @@
+/*
+ * Copyright 2007, Freescale Semiconductor, Inc
+ * Andy Fleming
+ *
+ * Based vaguely on the pxa mmc code:
+ * (C) Copyright 2003
+ * Kyle Harris, Nexus Technologies, Inc. [EMAIL PROTECTED]
+ *
+ * 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 <config.h>
+#include <common.h>
+#include <command.h>
+#include <mmc.h>
+#include <part.h>
+#include <malloc.h>
+#include <mmc.h>
+#include <fsl_esdhc.h>
+#include <asm/io.h>
+
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct fsl_esdhc {
+       uint    dsaddr;
+       uint    blkattr;
+       uint    cmdarg;
+       uint    xfertyp;
+       uint    cmdrsp0;
+       uint    cmdrsp1;
+       uint    cmdrsp2;
+       uint    cmdrsp3;
+       uint    datport;
+       uint    prsstat;
+       uint    proctl;
+       uint    sysctl;
+       uint    irqstat;
+       uint    irqstaten;
+       uint    irqsigen;
+       uint    autoc12err;
+       uint    hostcapblt;
+       uint    wml;
+       char    reserved1[8];
+       uint    fevt;
+       char    reserved2[168];
+       uint    hostver;
+       char    reserved3[780];
+       uint    scr;
+};
+
+static uint xfertyps[] = {
+       XFERTYP_RSPTYP_NONE,
+       XFERTYP_RSPTYP_48 | XFERTYP_CICEN | XFERTYP_CCCEN,
+       XFERTYP_RSPTYP_48_BUSY | XFERTYP_CICEN | XFERTYP_CCCEN,
+       XFERTYP_RSPTYP_136 | XFERTYP_CCCEN,
+       XFERTYP_RSPTYP_48,
+       XFERTYP_RSPTYP_48,
+       XFERTYP_RSPTYP_48 | XFERTYP_CICEN | XFERTYP_CCCEN,
+       XFERTYP_RSPTYP_48_BUSY | XFERTYP_CICEN | XFERTYP_CCCEN,
+       XFERTYP_RSPTYP_48 | XFERTYP_CICEN | XFERTYP_CCCEN,
+       XFERTYP_RSPTYP_48 | XFERTYP_CICEN | XFERTYP_CCCEN
+};
+
+/* Return the XFERTYP flags for a given command and data packet */
+uint esdhc_xfertyp(struct mmc_cmd *cmd, struct mmc_data *data)
+{
+       uint xfertyp = 0;
+
+       if (data) {
+               xfertyp |= XFERTYP_DPSEL | XFERTYP_DMAEN;
+
+               if (data->blocks > 1) {
+                       xfertyp |= XFERTYP_MSBSEL;
+                       xfertyp |= XFERTYP_BCEN;
+               }
+
+               if (data->flags & MMC_DATA_READ)
+                       xfertyp |= XFERTYP_DTDSEL;
+       }
+
+       xfertyp |= xfertyps[cmd->resp_type];
+
+       return xfertyp;
+}
+
+static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data)
+{
+       uint wml_value;
+       int timeout;
+       struct fsl_esdhc *regs = mmc->priv;
+       u32 temp;
+
+       wml_value = data->blocksize/4;
+
+       if (data->flags & MMC_DATA_READ) {
+               if (wml_value > 0x10)
+                       wml_value = 0x10;
+
+               wml_value = 0x100000 | wml_value;
+
+               out_be32(&regs->dsaddr, (u32)data->dest);
+       } else {
+               if (wml_value > 0x80)
+                       wml_value = 0x80;
+               if ((in_be32(&regs->prsstat) & PRSSTAT_WPSPL) == 0) {
+                       printf("\nThe SD card is locked. Can not write to a 
locked card.\n\n");
+                       return TIMEOUT;
+               }
+               wml_value = wml_value << 16 | 0x10;
+               out_be32(&regs->dsaddr, (u32)data->src);
+       }
+
+       out_be32(&regs->wml, wml_value);
+
+       out_be32(&regs->blkattr, data->blocks << 16 | data->blocksize);
+
+       /* Calculate the timeout period for data transactions */
+       timeout = __ilog2(mmc->tran_speed/10);
+       timeout -= 13;
+
+       if (timeout > 14)
+               timeout = 14;
+
+       if (timeout < 0)
+               timeout = 0;
+
+       temp = in_be32(&regs->sysctl);
+#define SYSCTL_TIMEOUT_MASK    0x000f0000
+       temp &= ~(SYSCTL_TIMEOUT_MASK);
+       temp |= timeout << 16;
+       out_be32(&regs->sysctl, temp);
+
+       return 0;
+}
+
+
+/*
+ * Sends a command out on the bus.  Takes the mmc pointer,
+ * a command pointer, and an optional data pointer.
+ */
+static int
+esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
+{
+       uint    xfertyp;
+       uint    irqstat;
+       volatile struct fsl_esdhc *regs = mmc->priv;
+
+       out_be32(&regs->irqstat, -1);
+
+       sync();
+
+       /* Wait for the bus to be idle */
+       while ((in_be32(&regs->prsstat) & PRSSTAT_CICHB) ||
+                       (in_be32(&regs->prsstat) & PRSSTAT_CIDHB));
+
+       while (in_be32(&regs->prsstat) & PRSSTAT_DLA);
+
+       /* Wait at least 8 SD clock cycles before the next command */
+       /*
+        * Note: This is way more than 8 cycles, but 1ms seems to
+        * resolve timing issues with some cards
+        */
+       udelay(1000);
+
+       /* Set up for a data transfer if we have one */
+       if (data) {
+               int err;
+
+               err = esdhc_setup_data(mmc, data);
+               if(err)
+                       return err;
+       }
+
+       /* Figure out the transfer arguments */
+       xfertyp = esdhc_xfertyp(cmd, data);
+
+       /* Send the command */
+       out_be32(&regs->cmdarg, cmd->cmdarg);
+       out_be32(&regs->xfertyp, XFERTYP_CMD(cmd->cmdidx) | xfertyp);
+
+       /* Wait for the command to complete */
+       while (!(in_be32(&regs->irqstat) & IRQSTAT_CC));
+
+       irqstat = in_be32(&regs->irqstat);
+       out_be32(&regs->irqstat, irqstat);
+
+       if (irqstat & CMD_ERR)
+               return COMM_ERR;
+
+       if (irqstat & IRQSTAT_CTOE)
+               return TIMEOUT;
+
+       /* Copy the response to the response buffer */
+       if (cmd->resp_type == MMC_CMD_R2) {
+               u32 cmdrsp3, cmdrsp2, cmdrsp1, cmdrsp0;
+
+               cmdrsp3 = in_be32(&regs->cmdrsp3);
+               cmdrsp2 = in_be32(&regs->cmdrsp2);
+               cmdrsp1 = in_be32(&regs->cmdrsp1);
+               cmdrsp0 = in_be32(&regs->cmdrsp0);
+               ((uint *)(cmd->response))[0] = (cmdrsp3 << 8) | (cmdrsp2 >> 24);
+               ((uint *)(cmd->response))[1] = (cmdrsp2 << 8) | (cmdrsp1 >> 24);
+               ((uint *)(cmd->response))[2] = (cmdrsp1 << 8) | (cmdrsp0 >> 24);
+               ((uint *)(cmd->response))[3] = (cmdrsp0 << 8);
+       } else
+               ((uint *)(cmd->response))[0] = in_be32(&regs->cmdrsp0);
+
+       /* Wait until all of the blocks are transferred */
+       if (data) {
+               do {
+                       irqstat = in_be32(&regs->irqstat);
+
+                       if (irqstat & DATA_ERR)
+                               return COMM_ERR;
+
+                       if (irqstat & IRQSTAT_DTOE)
+                               return TIMEOUT;
+               } while (!(irqstat & IRQSTAT_TC) &&
+                               (in_be32(&regs->prsstat) & PRSSTAT_DLA));
+       }
+
+       out_be32(&regs->irqstat, -1);
+
+       return 0;
+}
+
+void set_sysctl(struct mmc *mmc, uint clock)
+{
+       int sdhc_clk = gd->sdhc_clk;
+       int div, pre_div;
+       volatile struct fsl_esdhc *regs = mmc->priv;
+       uint clk;
+       u32 temp;
+
+       if (sdhc_clk / 16 > clock) {
+               for (pre_div = 2; pre_div < 256; pre_div *= 2)
+                       if ((sdhc_clk / pre_div) <= (clock * 16))
+                               break;
+       } else
+               pre_div = 2;
+
+       for (div = 1; div <= 16; div++)
+               if ((sdhc_clk / (div * pre_div)) <= clock)
+                       break;
+
+       pre_div >>= 1;
+       div -= 1;
+
+       clk = (pre_div << 8) | (div << 4);
+
+       temp = in_be32(&regs->sysctl);
+#define SYSCTL_CLOCK_MASK      0x00000fff
+       temp &= SYSCTL_CLOCK_MASK;
+       temp |= clk;
+       out_be32(&regs->sysctl, temp);
+
+       udelay(10000);
+
+       setbits_be32(&regs->sysctl, SYSCTL_PEREN);
+}
+
+static void esdhc_set_ios(struct mmc *mmc)
+{
+       struct fsl_esdhc *regs = mmc->priv;
+
+       /* Set the clock speed */
+       set_sysctl(mmc, mmc->clock);
+
+       /* Set the bus width */
+       clrbits_be32(&regs->proctl, PROCTL_DTW_4 | PROCTL_DTW_8);
+
+       if (mmc->bus_width == 4)
+               setbits_be32(&regs->proctl, PROCTL_DTW_4);
+       else if (mmc->bus_width == 8)
+               setbits_be32(&regs->proctl, PROCTL_DTW_8);
+}
+
+static int esdhc_init(struct mmc *mmc)
+{
+       struct fsl_esdhc *regs = mmc->priv;
+       int timeout = 1000;
+
+       /* Enable cache snooping */
+       out_be32(&regs->scr, 0x00000040);
+
+       out_be32(&regs->sysctl, SYSCTL_HCKEN | SYSCTL_IPGEN);
+
+       /* Set the initial clock speed */
+       set_sysctl(mmc, 400000);
+
+       /* Disable the BRR and BWR bits in IRQSTAT */
+       clrbits_be32(&regs->irqstaten, IRQSTATEN_BRR | IRQSTATEN_BWR);
+
+       /* Put the PROCTL reg back to the default */
+       out_be32(&regs->proctl, PROCTL_INIT);
+
+       while (!(in_be32(&regs->prsstat) & PRSSTAT_CINS) && --timeout)
+               udelay(1000);
+
+       if (timeout <= 0)
+               return NO_CARD_ERR;
+
+       return 0;
+}
+
+static int esdhc_initialize(bd_t *bis)
+{
+       struct fsl_esdhc *regs = (struct fsl_esdhc *)CFG_FSL_ESDHC_ADDR;
+       struct mmc *mmc;
+
+       mmc = malloc(sizeof(struct mmc));
+
+       sprintf(mmc->name, "FSL_ESDHC");
+       mmc->priv = regs;
+       mmc->send_cmd = esdhc_send_cmd;
+       mmc->set_ios = esdhc_set_ios;
+       mmc->init = esdhc_init;
+
+       mmc_register(mmc);
+
+       return 0;
+}
+
+int fsl_esdhc_mmc_init(bd_t *bis)
+{
+       return esdhc_initialize(bis);
+}
diff --git a/include/fsl_esdhc.h b/include/fsl_esdhc.h
new file mode 100644
index 0000000..6a504e8
--- /dev/null
+++ b/include/fsl_esdhc.h
@@ -0,0 +1,136 @@
+/*
+ * FSL SD/MMC Defines
+ *-------------------------------------------------------------------
+ *
+ * Copyright 2007-2008, Freescale Semiconductor, Inc
+ *
+ * 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
+ *
+ *-------------------------------------------------------------------
+ *
+ */
+
+#ifndef  __FSL_ESDHC_H__
+#define        __FSL_ESDHC_H__
+
+/* FSL eSDHC-specific constants */
+#define SYSCTL                 0x0002e02c
+#define SYSCTL_INITA           0x08000000
+#define SYSCTL_PEREN           0x00000004
+#define SYSCTL_HCKEN           0x00000002
+#define SYSCTL_IPGEN           0x00000001
+
+#define IRQSTAT                        0x0002e030
+#define IRQSTAT_DMAE           (0x10000000)
+#define IRQSTAT_AC12E          (0x01000000)
+#define IRQSTAT_DEBE           (0x00400000)
+#define IRQSTAT_DCE            (0x00200000)
+#define IRQSTAT_DTOE           (0x00100000)
+#define IRQSTAT_CIE            (0x00080000)
+#define IRQSTAT_CEBE           (0x00040000)
+#define IRQSTAT_CCE            (0x00020000)
+#define IRQSTAT_CTOE           (0x00010000)
+#define IRQSTAT_CINT           (0x00000100)
+#define IRQSTAT_CRM            (0x00000080)
+#define IRQSTAT_CINS           (0x00000040)
+#define IRQSTAT_BRR            (0x00000020)
+#define IRQSTAT_BWR            (0x00000010)
+#define IRQSTAT_DINT           (0x00000008)
+#define IRQSTAT_BGE            (0x00000004)
+#define IRQSTAT_TC             (0x00000002)
+#define IRQSTAT_CC             (0x00000001)
+
+#define CMD_ERR                (IRQSTAT_CIE | IRQSTAT_CEBE | IRQSTAT_CCE)
+#define DATA_ERR       (IRQSTAT_DEBE | IRQSTAT_DCE | IRQSTAT_DTOE)
+
+#define IRQSTATEN              0x0002e034
+#define IRQSTATEN_DMAE         (0x10000000)
+#define IRQSTATEN_AC12E                (0x01000000)
+#define IRQSTATEN_DEBE         (0x00400000)
+#define IRQSTATEN_DCE          (0x00200000)
+#define IRQSTATEN_DTOE         (0x00100000)
+#define IRQSTATEN_CIE          (0x00080000)
+#define IRQSTATEN_CEBE         (0x00040000)
+#define IRQSTATEN_CCE          (0x00020000)
+#define IRQSTATEN_CTOE         (0x00010000)
+#define IRQSTATEN_CINT         (0x00000100)
+#define IRQSTATEN_CRM          (0x00000080)
+#define IRQSTATEN_CINS         (0x00000040)
+#define IRQSTATEN_BRR          (0x00000020)
+#define IRQSTATEN_BWR          (0x00000010)
+#define IRQSTATEN_DINT         (0x00000008)
+#define IRQSTATEN_BGE          (0x00000004)
+#define IRQSTATEN_TC           (0x00000002)
+#define IRQSTATEN_CC           (0x00000001)
+
+#define PRSSTAT                        0x0002e024
+#define PRSSTAT_CLSL           (0x00800000)
+#define PRSSTAT_WPSPL          (0x00080000)
+#define PRSSTAT_CDPL           (0x00040000)
+#define PRSSTAT_CINS           (0x00010000)
+#define PRSSTAT_BREN           (0x00000800)
+#define PRSSTAT_DLA            (0x00000004)
+#define PRSSTAT_CICHB          (0x00000002)
+#define PRSSTAT_CIDHB          (0x00000001)
+
+#define PROCTL                 0x0002e028
+#define PROCTL_INIT            0x00000020
+#define PROCTL_DTW_4           0x00000002
+#define PROCTL_DTW_8           0x00000004
+
+#define CMDARG                 0x0002e008
+
+#define XFERTYP                        0x0002e00c
+#define XFERTYP_CMD(x)         ((x & 0x3f) << 24)
+#define XFERTYP_CMDTYP_NORMAL  0x0
+#define XFERTYP_CMDTYP_SUSPEND 0x00400000
+#define XFERTYP_CMDTYP_RESUME  0x00800000
+#define XFERTYP_CMDTYP_ABORT   0x00c00000
+#define XFERTYP_DPSEL          0x00200000
+#define XFERTYP_CICEN          0x00100000
+#define XFERTYP_CCCEN          0x00080000
+#define XFERTYP_RSPTYP_NONE    0
+#define XFERTYP_RSPTYP_136     0x00010000
+#define XFERTYP_RSPTYP_48      0x00020000
+#define XFERTYP_RSPTYP_48_BUSY 0x00030000
+#define XFERTYP_MSBSEL         0x00000020
+#define XFERTYP_DTDSEL         0x00000010
+#define XFERTYP_AC12EN         0x00000004
+#define XFERTYP_BCEN           0x00000002
+#define XFERTYP_DMAEN          0x00000001
+
+#define CINS_TIMEOUT           1000
+
+#define DSADDR         0x2e004
+
+#define CMDRSP0                0x2e010
+#define CMDRSP1                0x2e014
+#define CMDRSP2                0x2e018
+#define CMDRSP3                0x2e01c
+
+#define DATPORT                0x2e020
+
+#define WML            0x2e044
+#define WML_WRITE      0x00010000
+
+#define BLKATTR                0x2e004
+#define BLKATTR_CNT(x) ((x & 0xffff) << 16)
+#define BLKATTR_SIZE(x)        (x & 0x1fff)
+#define MAX_BLK_CNT    0x7fff  /* so malloc will have enough room with 32M */
+
+int fsl_esdhc_mmc_init(bd_t *bis);
+
+#endif  /* __FSL_ESDHC_H__ */
-- 
1.5.4.GIT

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to