diff options
Diffstat (limited to 'cpu/at32ap/atmel_mci.c')
| -rw-r--r-- | cpu/at32ap/atmel_mci.c | 80 | 
1 files changed, 76 insertions, 4 deletions
| diff --git a/cpu/at32ap/atmel_mci.c b/cpu/at32ap/atmel_mci.c index 9f62c0f14..cf48be10b 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); |