]> git.ipfire.org Git - people/ms/u-boot.git/blobdiff - cpu/at32ap/atmel_mci.c
Merge branch 'master' of git://www.denx.de/git/u-boot-ppc4xx
[people/ms/u-boot.git] / cpu / at32ap / atmel_mci.c
index 3e3789bcdd90f775a0a4c5eb35512fa904760442..3795addf05af60ca10e69d6e6d8e7bf086e7f3b1 100644 (file)
@@ -21,8 +21,6 @@
  */
 #include <common.h>
 
-#ifdef CONFIG_MMC
-
 #include <part.h>
 #include <mmc.h>
 
@@ -56,6 +54,7 @@
 #define MMC_DEFAULT_RCA                1
 
 static unsigned int mmc_rca;
+static int mmc_card_is_sd;
 static block_dev_desc_t mmc_blkdev;
 
 block_dev_desc_t *mmc_get_dev(int dev)
@@ -82,7 +81,9 @@ static void mci_set_mode(unsigned long hz, unsigned long blklen)
 
        blklen &= 0xfffc;
        mmci_writel(MR, (MMCI_BF(CLKDIV, clkdiv)
-                        | MMCI_BF(BLKLEN, blklen)));
+                        | MMCI_BF(BLKLEN, blklen)
+                        | MMCI_BIT(RDPROOF)
+                        | MMCI_BIT(WRPROOF)));
 }
 
 #define RESP_NO_CRC    1
@@ -136,7 +137,7 @@ mmc_cmd(unsigned long cmd, unsigned long arg,
 
        pr_debug("mmc: status 0x%08lx\n", status);
 
-       if (status & ERROR_FLAGS) {
+       if (status & error_flags) {
                printf("mmc: command %lu failed (status: 0x%08lx)\n",
                       cmd, status);
                return -EIO;
@@ -179,12 +180,13 @@ static int mmc_acmd(unsigned long cmd, unsigned long arg,
 
 static unsigned long
 mmc_bread(int dev, unsigned long start, lbaint_t blkcnt,
-         unsigned long *buffer)
+         void *buffer)
 {
        int ret, i = 0;
        unsigned long resp[4];
        unsigned long card_status, data;
        unsigned long wordcount;
+       u32 *p = buffer;
        u32 status;
 
        if (blkcnt == 0)
@@ -195,11 +197,11 @@ mmc_bread(int dev, unsigned long start, lbaint_t blkcnt,
 
        /* Put the device into Transfer state */
        ret = mmc_cmd(MMC_CMD_SELECT_CARD, mmc_rca << 16, resp, R1 | NCR);
-       if (ret) goto fail;
+       if (ret) goto out;
 
        /* Set block length */
        ret = mmc_cmd(MMC_CMD_SET_BLOCKLEN, mmc_blkdev.blksz, resp, R1 | NCR);
-       if (ret) goto fail;
+       if (ret) goto out;
 
        pr_debug("MCI_DTOR = %08lx\n", mmci_readl(DTOR));
 
@@ -208,7 +210,7 @@ mmc_bread(int dev, unsigned long start, lbaint_t blkcnt,
                              start * mmc_blkdev.blksz, resp,
                              (R1 | NCR | TRCMD_START | TRDIR_READ
                               | TRTYP_BLOCK));
-               if (ret) goto fail;
+               if (ret) goto out;
 
                ret = -EIO;
                wordcount = 0;
@@ -216,16 +218,16 @@ mmc_bread(int dev, unsigned long start, lbaint_t blkcnt,
                        do {
                                status = mmci_readl(SR);
                                if (status & (ERROR_FLAGS | MMCI_BIT(OVRE)))
-                                       goto fail;
+                                       goto read_error;
                        } while (!(status & MMCI_BIT(RXRDY)));
 
                        if (status & MMCI_BIT(RXRDY)) {
                                data = mmci_readl(RDR);
-                               // pr_debug("%x\n", data);
-                               *buffer++ = data;
+                               /* pr_debug("%x\n", data); */
+                               *p++ = data;
                                wordcount++;
                        }
-               } while(wordcount < (512 / 4));
+               } while(wordcount < (mmc_blkdev.blksz / 4));
 
                pr_debug("mmc: read %u words, waiting for BLKE\n", wordcount);
 
@@ -241,9 +243,10 @@ out:
        mmc_cmd(MMC_CMD_SELECT_CARD, 0, resp, NCR);
        return i;
 
-fail:
+read_error:
        mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR);
-       printf("mmc: bread failed, card status = ", card_status);
+       printf("mmc: bread failed, status = %08x, card status = %08x\n",
+              status, card_status);
        goto out;
 }
 
@@ -371,6 +374,7 @@ static int sd_init_card(struct mmc_cid *cid, int verbose)
        mmc_rca = resp[0] >> 16;
        if (verbose)
                printf("SD Card detected (RCA %u)\n", mmc_rca);
+       mmc_card_is_sd = 1;
        return 0;
 }
 
@@ -405,10 +409,65 @@ static int mmc_init_card(struct mmc_cid *cid, int verbose)
        return ret;
 }
 
+static void mci_set_data_timeout(struct mmc_csd *csd)
+{
+       static const unsigned int dtomul_to_shift[] = {
+               0, 4, 7, 8, 10, 12, 16, 20,
+       };
+       static const unsigned int taac_exp[] = {
+               1, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
+       };
+       static const unsigned int taac_mant[] = {
+               0,  10, 12, 13, 15, 60, 25, 30,
+               35, 40, 45, 50, 55, 60, 70, 80,
+       };
+       unsigned int timeout_ns, timeout_clks;
+       unsigned int e, m;
+       unsigned int dtocyc, dtomul;
+       unsigned int shift;
+       u32 dtor;
+
+       e = csd->taac & 0x07;
+       m = (csd->taac >> 3) & 0x0f;
+
+       timeout_ns = (taac_exp[e] * taac_mant[m] + 9) / 10;
+       timeout_clks = csd->nsac * 100;
+
+       timeout_clks += (((timeout_ns + 9) / 10)
+                        * ((CFG_MMC_CLK_PP + 99999) / 100000) + 9999) / 10000;
+       if (!mmc_card_is_sd)
+               timeout_clks *= 10;
+       else
+               timeout_clks *= 100;
+
+       dtocyc = timeout_clks;
+       dtomul = 0;
+       shift = 0;
+       while (dtocyc > 15 && dtomul < 8) {
+               dtomul++;
+               shift = dtomul_to_shift[dtomul];
+               dtocyc = (timeout_clks + (1 << shift) - 1) >> shift;
+       }
+
+       if (dtomul >= 8) {
+               dtomul = 7;
+               dtocyc = 15;
+               puts("Warning: Using maximum data timeout\n");
+       }
+
+       dtor = (MMCI_BF(DTOMUL, dtomul)
+               | MMCI_BF(DTOCYC, dtocyc));
+       mmci_writel(DTOR, dtor);
+
+       printf("mmc: Using %u cycles data timeout (DTOR=0x%x)\n",
+              dtocyc << shift, dtor);
+}
+
 int mmc_init(int verbose)
 {
        struct mmc_cid cid;
        struct mmc_csd csd;
+       unsigned int max_blksz;
        int ret;
 
        /* Initialize controller */
@@ -418,6 +477,8 @@ int mmc_init(int verbose)
        mmci_writel(IDR, ~0UL);
        mci_set_mode(CFG_MMC_CLK_OD, MMC_DEFAULT_BLKLEN);
 
+       mmc_card_is_sd = 0;
+
        ret = sd_init_card(&cid, verbose);
        if (ret) {
                mmc_rca = MMC_DEFAULT_RCA;
@@ -433,6 +494,8 @@ int mmc_init(int verbose)
        if (verbose)
                mmc_dump_csd(&csd);
 
+       mci_set_data_timeout(&csd);
+
        /* Initialize the blockdev structure */
        mmc_blkdev.if_type = IF_TYPE_MMC;
        mmc_blkdev.part_type = PART_TYPE_DOS;
@@ -444,7 +507,17 @@ int mmc_init(int verbose)
                sizeof(mmc_blkdev.product));
        sprintf((char *)mmc_blkdev.revision, "%x %x",
                cid.prv >> 4, cid.prv & 0x0f);
-       mmc_blkdev.blksz = 1 << csd.read_bl_len;
+
+       /*
+        * If we can't use 512 byte blocks, refuse to deal with the
+        * card. Tons of code elsewhere seems to depend on this.
+        */
+       max_blksz = 1 << csd.read_bl_len;
+       if (max_blksz < 512 || (max_blksz > 512 && !csd.read_bl_partial)) {
+               printf("Card does not support 512 byte reads, aborting.\n");
+               return -ENODEV;
+       }
+       mmc_blkdev.blksz = 512;
        mmc_blkdev.lba = (csd.c_size + 1) * (1 << (csd.c_size_mult + 2));
 
        mci_set_mode(CFG_MMC_CLK_PP, mmc_blkdev.blksz);
@@ -473,5 +546,3 @@ int mmc2info(ulong addr)
 {
        return 0;
 }
-
-#endif /* CONFIG_MMC */