summaryrefslogtreecommitdiff
path: root/cpu/at32ap/atmel_mci.c
diff options
context:
space:
mode:
Diffstat (limited to 'cpu/at32ap/atmel_mci.c')
-rw-r--r--cpu/at32ap/atmel_mci.c80
1 files changed, 76 insertions, 4 deletions
diff --git a/cpu/at32ap/atmel_mci.c b/cpu/at32ap/atmel_mci.c
index 9f62c0f..cf48be1 100644
--- a/cpu/at32ap/atmel_mci.c
+++ b/cpu/at32ap/atmel_mci.c
@@ -56,6 +56,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 +83,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
@@ -225,7 +228,7 @@ mmc_bread(int dev, unsigned long start, lbaint_t blkcnt,
*buffer++ = data;
wordcount++;
}
- } while(wordcount < (512 / 4));
+ } while(wordcount < (mmc_blkdev.blksz / 4));
pr_debug("mmc: read %u words, waiting for BLKE\n", wordcount);
@@ -243,7 +246,7 @@ out:
fail:
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, card status = %08x\n", 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,64 @@ 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;
+ 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 +476,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 +493,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 +506,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);