Logic unit: SDHC Support Purpose: Add support for SD/SDHC cards for AT572D940HF-EB Author: Antnoio R. Costa <antonio.costa <at> atmel.com> Date : 11 Jun 2008
Status ~~~~~~ This patch add support for SD/SDHC cards to AT572D940HF-EB and more generally is a proposal for all Atmel chips. Dued to that I placed atmel_mci.c under the board directory. Plaese give me some feedbacks. The implementation of the CSD interpretation has been re-worked completely. Bit fields are not portable so there were replaced by a vector of 4 32-bit words and some macros. Probing process follow the schema from SD spec 2.0: sdhc --> sd --> mmc Introduced IF_TYPE_SDHC to distinguish between SD and SDHC. Maybe this is not the best method since struct block_dev_descr.priv could point to a structure describing card properties but it was the quickest one and I had no time to spend. Tested SD: - Mediacom 512 MB (spec 1.0) bare FAT16 - Kingstone 1 GB (spec 1.0) FAT16 - Trascend 2 GB (spec 1.01) FAT16 - TakeMS 4 GB (spec 1.10) FAT16 Tested SDHC: - Peak 8 GB (spec 2.0) FAT32 Signed-off-by: Antonio R. Costa <[EMAIL PROTECTED]> diff --git a/board/atmel/at572d940hfeb/atmel_mci.c b/board/atmel/at572d940hfeb/atmel_mci.c new file mode 100644 index 0000000..065a85b --- /dev/null +++ b/board/atmel/at572d940hfeb/atmel_mci.c @@ -0,0 +1,869 @@ +/* + * (C) Copyright 2008 Atmel Corporation + * + * Antonio R. Costa <antonio.costa <at> atmel.com> + * <costa.antonior <at> gmail.com> + * + * 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> + +#ifdef CONFIG_MMC + +#include <part.h> +#include <mmc.h> + +#include <asm/io.h> +#include <asm/errno.h> +#include <asm/byteorder.h> +#include <asm/arch/clk.h> +#include <asm/arch/memory-map.h> +#include <asm/arch/timer.h> +#include <fat.h> + +#include <asm/arch/atmel_mci.h> + +#ifdef DEBUG +#define pr_debug(fmt, args...) printf(fmt, ##args) +#else +#define pr_debug(...) do { } while(0) +#endif + +#ifndef CFG_MMC_CLK_OD +#define CFG_MMC_CLK_OD 150000 +#endif + +#ifndef CFG_MMC_CLK_PP +#define CFG_MMC_CLK_PP 5000000 +#endif + +#ifndef CFG_MMC_OP_COND +#define CFG_MMC_OP_COND 0x401f8000 +#endif + +#define MMC_DEFAULT_BLKLEN 512 +#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) +{ + return &mmc_blkdev; +} + +static int mci_reset(void) +{ + + mmci_writel(CR, MMCI_BIT(SWRST)); + mmci_writel(CR, MMCI_BIT(MCIEN)); + mmci_writel(CR, MMCI_BIT(PWSDIS)); + + mmci_writel(CMDR, (1 << 11) | (1 << 8)); // Init command + while (!(mmci_readl(SR) & MMCI_BIT(CMDRDY))) ; + return 0; +} + +static void mci_set_mode(unsigned long hz, unsigned long blklen) +{ + unsigned long bus_hz; + unsigned long clkdiv; + + bus_hz = get_mci_clk_rate(); + clkdiv = (bus_hz / hz) / 2 - 1; + + pr_debug("mmc: setting clock %lu Hz, clkdiv %lu, block size %lu\n", + hz, clkdiv, blklen); + + if (clkdiv & ~255UL) { + clkdiv = 255; + printf("mmc: clock %lu too low; setting CLKDIV to 255\n", hz); + } + + blklen &= 0xfffc; + mmci_writel(MR, (MMCI_BF(CLKDIV, clkdiv) + | MMCI_BF(BLKLEN, blklen) + | MMCI_BIT(RDPROOF) + | MMCI_BIT(WRPROOF))); +} + +#define RESP_NO_CRC 1 +#define R1 MMCI_BF(RSPTYP, 1) // 48-bit CRC +#define R2 MMCI_BF(RSPTYP, 2) // 136-bit CRC +#define R3 (R1 | RESP_NO_CRC) +#define R6 R1 +#define R7 R1 +#define NID MMCI_BF(MAXLAT, 0) +#define NCR MMCI_BF(MAXLAT, 1) +#define TRCMD_START MMCI_BF(TRCMD, 1) +#define TRDIR_READ MMCI_BF(TRDIR, 1) +#define TRTYP_BLOCK MMCI_BF(TRTYP, 0) +#define INIT_CMD MMCI_BF(SPCMD, 1) +#define OPEN_DRAIN MMCI_BF(OPDCMD, 1) + +#define ERROR_FLAGS (MMCI_BIT(DTOE) \ + | MMCI_BIT(RDIRE) \ + | MMCI_BIT(RENDE) \ + | MMCI_BIT(RINDE) \ + | MMCI_BIT(RTOE)) + +static int +mmc_cmd(unsigned long cmd, unsigned long arg, void *resp, unsigned long flags) +{ + unsigned long *response = resp; + int i, response_words = 0; + unsigned long error_flags; + u32 status; + + pr_debug("mmc: CMD%lu 0x%lx (flags 0x%lx)\n", cmd, arg, flags); + + error_flags = ERROR_FLAGS; + if (!(flags & RESP_NO_CRC)) + error_flags |= MMCI_BIT(RCRCE); + + flags &= ~MMCI_BF(CMDNB, ~0UL); + + if (MMCI_BFEXT(RSPTYP, flags) == MMCI_RSPTYP_48_BIT_RESP) + response_words = 1; + else if (MMCI_BFEXT(RSPTYP, flags) == MMCI_RSPTYP_136_BIT_RESP) + response_words = 4; + + mmci_writel(ARGR, arg); + mmci_writel(CMDR, cmd | flags); + do { + udelay(40); + status = mmci_readl(SR); + } while (!(status & MMCI_BIT(CMDRDY))); + + pr_debug("mmc: status 0x%08lx\n", status); + + if (status & ERROR_FLAGS) { + printf("mmc: command %lu failed (status: 0x%08lx)\n", + cmd, status); + return -EIO; + } + + if (response_words) + pr_debug("mmc: response:"); + + for (i = 0; i < response_words; i++) { + response[i] = mmci_readl(RSPR); + pr_debug(" %08lx", response[i]); + } + pr_debug("\n"); + + return 0; +} + +static int mmc_acmd(unsigned long cmd, unsigned long arg, + void *resp, unsigned long flags) __attribute ((noinline)); + +static int mmc_acmd(unsigned long cmd, unsigned long arg, + void *resp, unsigned long flags) +{ + unsigned long aresp[4]; + int ret; + + /* + * Seems like the APP_CMD part of an ACMD has 64 cycles max + * latency even though the ACMD part doesn't. This isn't + * entirely clear in the SD Card spec, but some cards refuse + * to work if we attempt to use 5 cycles max latency here... + */ + + pr_debug("acmd: flags 0x%lx \n", flags); + ret = mmc_cmd(MMC_CMD_APP_CMD, 0, aresp, + R1 | NCR | (flags & OPEN_DRAIN)); + if (ret) + return ret; + if ((aresp[0] & (R1_ILLEGAL_COMMAND | R1_APP_CMD)) != R1_APP_CMD) + return -EIO; + + ret = mmc_cmd(cmd, arg, resp, flags); + + return ret; +} + +static unsigned long +mmc_bread(int dev, unsigned long start, lbaint_t blkcnt, unsigned long *buffer) +{ + int ret, start_inc = 0, i = 0; + unsigned long resp[4]; + unsigned long card_status; + unsigned long wordcount; + u32 status; +// block_dev_desc_t mmc_blkdev = *(block_dev_desc_t*) dev; + + if (blkcnt == 0) + return 0; + + /* + * ARC: + * For SDHC cards start is the number of the first block to read; + * for regular SD cards start is the address of the first byte to read + */ + start = (mmc_blkdev.if_type == IF_TYPE_SDHC) ? start : start * 512; + start_inc = (mmc_blkdev.if_type == IF_TYPE_SDHC) ? 1 : 512; + + pr_debug + ("mmc_bread: dev %d, type %u, start %lx, blkcnt %lx buffer: 0x%p\n", + dev, mmc_blkdev.if_type, start, blkcnt, buffer); + + /* Put the device into Transfer state */ + ret = mmc_cmd(MMC_CMD_SELECT_CARD, mmc_rca << 16, resp, R1 | NCR); + + if (ret) + goto out; + + /* + * ARC: set the bus width to 4-bits + * 0x1 1-bit, 0x2 4-bits + */ + if ((mmc_blkdev.if_type == IF_TYPE_SD) + || (mmc_blkdev.if_type == IF_TYPE_SDHC)) { + unsigned long resp[4]; + ret = mmc_cmd(MMC_CMD_APP_CMD, mmc_rca << 16, resp, R1 | NCR); + if (ret) + return ret; + if ((resp[0] & (R1_ILLEGAL_COMMAND | R1_APP_CMD)) != R1_APP_CMD) + return -ENODEV; + + ret = mmc_cmd(MMC_ACMD_BUS_WIDTH, 0x2, resp, R1 | NCR); + } + + /* Set block length */ + /* + * ARC: useless but not dungerous for SDHC + */ + ret = mmc_cmd(MMC_CMD_SET_BLOCKLEN, mmc_blkdev.blksz, resp, R1 | NCR); + if (ret) + goto out; + + /* + * ARC: wait for card in ready state + */ + do { + ret = + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, resp, R1 | NCR); + } while ((ret != 0) && (resp[0] & (1 << 8))); + + for (i = 0; i < blkcnt; i++, start += start_inc) { + /* + * ARC: enables and configure PDC + */ + pr_debug("bread: buffer address: 0x%p\n", buffer); + ret = mmci_readl(MR); + mmci_writel(MR, (ret | MMCI_BIT(PDCMODE))); + mmci_writel(PTCR, (MMCI_PTCR_TXTDIS | MMCI_PTCR_RXTDIS)); + mmci_writel(RPR, (u32) buffer); + mmci_writel(RCR, mmc_blkdev.blksz / 4); + mmci_writel(PTCR, MMCI_PTCR_RXTEN); + + ret = mmc_cmd(MMC_CMD_READ_SINGLE_BLOCK, + start, resp, + (R1 | NCR | TRCMD_START | TRDIR_READ | + TRTYP_BLOCK)); + if (ret) + goto read_error; + + do { + status = mmci_readl(SR); + } while (!(status & MMCI_BIT(RXBUFF)) + && !(status & ERROR_FLAGS)); + /* + * ARC: disable PDC + */ + + ret = mmci_readl(MR); + mmci_writel(MR, (ret & ~MMCI_BIT(PDCMODE))); + + if (status & ERROR_FLAGS) { + ret = + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, resp, + R1 | NCR); + printf + ("Error reading from card: 0x%08x, status: 0x%08x\n", + mmc_rca, resp[0]); + goto read_error; + } + + wordcount = (mmc_blkdev.blksz / 4) - mmci_readl(RCR); + buffer += wordcount; + mmci_writel(PTCR, (MMCI_PTCR_TXTDIS | MMCI_PTCR_RXTDIS)); + + pr_debug("mmc: read %u words, waiting for BLKE\n", wordcount); + + while (!(status & MMCI_BIT(BLKE))) + status = mmci_readl(SR); + } + + out: + /* Put the device back into Standby state */ + mmc_cmd(MMC_CMD_SELECT_CARD, 0, resp, NCR); + return i; + + read_error: + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + printf + ("mmc: bread failed, rca = 0x%08x, status = 0x%08x, card status = 0x%08x\n", + mmc_rca, status, card_status); + goto out; +} + +static void mmc_parse_cid(struct mmc_cid *cid, unsigned long *resp) +{ + cid->mid = resp[0] >> 24; + cid->oid = (resp[0] >> 8) & 0xffff; + cid->pnm[0] = resp[0]; + cid->pnm[1] = resp[1] >> 24; + cid->pnm[2] = resp[1] >> 16; + cid->pnm[3] = resp[1] >> 8; + cid->pnm[4] = resp[1]; + cid->pnm[5] = resp[2] >> 24; + cid->pnm[6] = 0; + cid->prv = resp[2] >> 16; + cid->psn = (resp[2] << 16) | (resp[3] >> 16); + cid->mdt = resp[3] >> 8; +} + +static void sd_parse_cid(struct mmc_cid *cid, unsigned long *resp) +{ + cid->mid = resp[0] >> 24; + cid->oid = (resp[0] >> 8) & 0xffff; + cid->pnm[0] = resp[0]; + cid->pnm[1] = resp[1] >> 24; + cid->pnm[2] = resp[1] >> 16; + cid->pnm[3] = resp[1] >> 8; + cid->pnm[4] = resp[1]; + cid->pnm[5] = 0; + cid->pnm[6] = 0; + cid->prv = resp[2] >> 24; + cid->psn = (resp[2] << 8) | (resp[3] >> 24); + cid->mdt = (resp[3] >> 8) & 0x0fff; +} + +static void mmc_dump_cid(const struct mmc_cid *cid) +{ + puts("----- CID -----\n"); + printf("Manufacturer ID: %02lX\n", cid->mid); + printf("OEM/Application ID: %04lX\n", cid->oid); + printf("Product name: %s\n", cid->pnm); + printf("Product Revision: %lu.%lu\n", + cid->prv >> 4, cid->prv & 0x0f); + printf("Product Serial Number: %lu\n", cid->psn); + printf("Manufacturing Date: %02lu/%02lu\n", + cid->mdt >> 4, cid->mdt & 0x0f); + puts("----- CID -----\n"); +} + +static void mmc_dump_csd(const mmc_csd_t pcsd) +{ + printf("CSD data: %08lx %08lx %08lx %08lx\n", + pcsd[0], pcsd[1], pcsd[2], pcsd[3]); + printf("CSD structure version: %u\n", 1 + SD_CSD_FIELD(VER, pcsd)); + printf("TAAC: %u\n", SD_CSD_FIELD(TAAC, pcsd)); + printf("NSAC: %u\n", SD_CSD_FIELD(NSAC, pcsd)); + printf("Card command classes: %03x\n", SD_CSD_FIELD(CCC, pcsd)); + printf("Read block length: %u\n", 1 << SD_CSD_FIELD(RBLEN, pcsd)); + if (SD_CSD_FIELD(RBP, pcsd)) + puts("Supports partial reads\n"); + else + puts("Does not support partial reads\n"); + printf("Write block length: %u\n", 1 << SD_CSD_FIELD(WBL, pcsd)); + if (SD_CSD_FIELD(WBP, pcsd)) + puts("Supports partial writes\n"); + else + puts("Does not support partial writes\n"); + if (SD_CSD_FIELD(WPGE, pcsd)) + printf("Supports group WP: %u\n", + SD_CSD_FIELD(WPGS, pcsd) + 1); + else + puts("Does not support group WP\n"); + + /* + * ARC: capacity is computed dependig on CSD version: + * SD cards capacity depends on read_block_len parameter and a multiplier, + * SDHC cadrs capacity depend on the # of blocks insted, block length is fixed to 512K + */ + printf("Card capacity: %llu MB\n", + (unsigned long long)((SD_CSD_VER(pcsd) == 0) ? + (SD_CSD_1x_CSIZE(pcsd) + + 1) * + ((1 << + (SD_CSD_1x_FIELD(CSMUL, pcsd) + + 2)) * + (1 << + SD_CSD_1x_FIELD(RBLEN, + pcsd))) + : ((unsigned long long) + (SD_CSD_2x_CSIZE(pcsd) + + 1ULL) * 512ULL * 1024ULL)) / 1048576); + + printf("File format: %u/%u\n", + SD_CSD_FIELD(FFG, pcsd), SD_CSD_FIELD(FF, pcsd)); + puts("Write protection: "); + if (SD_CSD_FIELD(PWP, pcsd)) + puts(" permanent"); + if (SD_CSD_FIELD(TWP, pcsd)) + puts(" temporary"); + putc('\n'); +} + +#if 0 +static void mmc_dump_csd(const union mmc_csd *u_csd) +{ + if (u_csd->csd_1_x.csd_structure == 0) { + struct mmc_csd_1_x *csd = (struct mmc_csd_1_x *)&u_csd->csd_1_x; + unsigned long *csd_raw = (unsigned long *)u_csd; + puts("--- CSD ver: 1 --- \n"); + printf("CSD data: %08lx %08lx %08lx %08lx\n", + csd_raw[0], csd_raw[1], csd_raw[2], csd_raw[3]); + printf("CSD structure version: 1.%u\n", csd->csd_structure); + printf("MMC System Spec version: %u\n", csd->spec_vers); + printf("Card command classes: %03x\n", csd->ccc); + printf("Read block length: %u\n", 1 << csd->read_bl_len); + if (csd->read_bl_partial) + puts("Supports partial reads\n"); + else + puts("Does not support partial reads\n"); + printf("Write block length: %u\n", 1 << csd->write_bl_len); + if (csd->write_bl_partial) + puts("Supports partial writes\n"); + else + puts("Does not support partial writes\n"); + if (csd->wp_grp_enable) + printf("Supports group WP: %u\n", + csd->wp_grp_size + 1); + else + puts("Does not support group WP\n"); + printf("Card capacity: %u bytes\n", + (csd->c_size + + 1) * (1 << (csd->c_size_mult + + 2)) * (1 << csd->read_bl_len)); + printf("File format: %u/%u\n", csd->file_format_grp, + csd->file_format); + puts("Write protection: "); + if (csd->perm_write_protect) + puts(" permanent"); + if (csd->tmp_write_protect) + puts(" temporary"); + putc('\n'); + } else if (u_csd->csd_1_x.csd_structure == 1) { + struct mmc_csd_2_0 *csd = (struct mmc_csd_2_0 *)&u_csd->csd_2_0; + unsigned long *csd_raw = (unsigned long *)u_csd; + puts("--- CSD ver: 2 --- \n"); + printf("CSD data: %08lx %08lx %08lx %08lx\n", + csd_raw[0], csd_raw[1], csd_raw[2], csd_raw[3]); + printf("CSD structure version: %u\n", csd->csd_structure); + printf("Card command classes: %03x\n", csd->ccc); + printf("Read block length: %u\n", 1 << csd->read_bl_len); + if (csd->read_bl_partial) + puts("Supports partial reads\n"); + else + puts("Does not support partial reads\n"); + printf("Write block length: %u\n", 1 << csd->write_bl_len); + if (csd->write_bl_partial) + puts("Supports partial writes\n"); + else + puts("Does not support partial writes\n"); + if (csd->wp_grp_enable) + printf("Supports group WP: %u\n", + csd->wp_grp_size + 1); + else + puts("Does not support group WP\n"); + printf("Card capacity: %u bytes\n", + (csd->c_size + 1) * (512 * 1024)); + printf("File format: %u/%u\n", + csd->file_format_grp, csd->file_format); + puts("Write protection: "); + if (csd->perm_write_protect) + puts(" permanent"); + if (csd->tmp_write_protect) + puts(" temporary"); + putc('\n'); + } +} +#endif /* 0 */ + +static int mmc_idle_cards(void) +{ + int ret; + + /* Reset and initialize all cards */ + /* Send CMD0 */ + ret = mmc_cmd(MMC_CMD_GO_IDLE_STATE, 0, NULL, 0); + if (ret) + return ret; + + /* Keep the bus idle for 74 clock cycles */ + return mmc_cmd(0, 0, NULL, INIT_CMD); +} + +static int sd_init_card(struct mmc_cid *cid, block_dev_desc_t * mmc_blkdev_p, + int verbose) __attribute__((noinline)); + +static int sd_init_card(struct mmc_cid *cid, block_dev_desc_t * mmc_blkdev_p, + int verbose) +{ + unsigned long resp[4]; + int i, ret = 0; + u32 status; + + mci_reset(); + mmc_idle_cards(); + if(verbose) + puts("mmc: Probing for SDHC ...\n"); + /* Send supported voltage range */ + /* SD cards 1.x do not answer to CMD8 */ + ret = mmc_cmd(MMC_CMD_IF_COND, ((1 << 8) | 0xAA), resp, R7 | NCR); + if (ret == -EIO) { + /* + * ARC: No answer let's try SD 1.x + */ + if(verbose) + puts("mmc: No answer to CMD8 trying SD\n"); + mmc_blkdev_p->if_type = IF_TYPE_SD; + } else if (ret) { + /* Other errors or most probably 2.0 voltage mismatch */ + puts("mmc: Unknown error on CMD8\n"); + mmc_blkdev_p->if_type = IF_TYPE_UNKNOWN; + return -ENODEV; + } else { + /* + * ARC: probably an SDHC card + */ + mmc_blkdev_p->if_type = IF_TYPE_SDHC; + if(verbose) + puts("mmc: SD 2.0 or later card found\n"); + + /* Check if the card supports this voltage */ + if (resp[0] != ((1 << 8) | 0xAA)) { + pr_debug("mmc: Invalid voltage range\n"); + return -ENODEV; + } + } + + /* + * ARC: HC (30) bit set according to response to + * CMD8 command + */ + + pr_debug("mmc: Sending ACMD41 %s HC set\n", + ((mmc_blkdev_p->if_type == + IF_TYPE_SDHC) ? "with" : "without")); + + for (i = 1; i <= SD_MAX_RETRIES; i++) { + pr_debug("ACMD41 arg: 0x%08x \n", + CFG_MMC_OP_COND & + ((mmc_blkdev_p->if_type == + IF_TYPE_SDHC) ? 0xffffffff : 0xbfffffff)); + { + /* + * ARC: Some cards need this delay + * during voltage negotiation otherwise + * they report an error between two ACMD41 probes + * More investigation needed. + */ + int volatile i =100000; + while(i-->0); + } + + ret = + mmc_acmd(MMC_ACMD_SD_SEND_OP_COND, + CFG_MMC_OP_COND & + ((mmc_blkdev_p->if_type == + IF_TYPE_SDHC) ? 0xffffffff : 0xbfffffff), resp, + R3 | NCR); + /* + * ARC: if no answer try again + */ + if (ret == -EIO) { + if(verbose) + printf("Retrying (%d/%d) ... \n",i,SD_MAX_RETRIES); + continue; + } + if (ret || (resp[0] & 0x80000000)) + break; + ret = -ETIMEDOUT; + } + + /* + * ARC: Card did not answer to ACMD41 + * so it's a MMC card + */ + if (ret) { + mmc_blkdev.if_type = IF_TYPE_MMC; + puts("No answer to ACMD41 trying mmc card\n"); + return ret; + } + + /* + * ARC: check for HC bit, if its not set + * sd card is SD + */ + if ((resp[0] & 0xc0000000) == 0x80000000) { + mmc_blkdev.if_type = IF_TYPE_SD; + } + + ret = mmc_cmd(MMC_CMD_ALL_SEND_CID, 0, resp, R2 | NID); + if (ret) + return ret; + sd_parse_cid(cid, resp); + if (verbose) + mmc_dump_cid(cid); + + /* Get RCA of the card that responded */ + ret = mmc_cmd(MMC_CMD_SD_SEND_RELATIVE_ADDR, 0, resp, R6 | NCR); + if (ret) + return ret; + + mmc_rca = resp[0] >> 16; + if (verbose) + printf("SD Card detected RCA: 0x%x type: %s\n", + mmc_rca, + ((mmc_blkdev.if_type == + IF_TYPE_SDHC) ? "SDHC" : ((mmc_blkdev.if_type == + IF_TYPE_SD) ? "SD" : + "MMC"))); + + mmc_card_is_sd = 1; + return 0; +} + +static int mmc_init_card(struct mmc_cid *cid, int verbose) +{ + unsigned long resp[4]; + int i, ret = 0; + + mmc_idle_cards(); + for (i = 0; i < 1000; i++) { + ret = mmc_cmd(MMC_CMD_SEND_OP_COND, CFG_MMC_OP_COND, resp, + R3 | NID | OPEN_DRAIN); + if (ret || (resp[0] & 0x80000000)) + break; + ret = -ETIMEDOUT; + } + + if (ret) + return ret; + + /* Get CID of all cards. FIXME: Support more than one card */ + ret = mmc_cmd(MMC_CMD_ALL_SEND_CID, 0, resp, R2 | NID | OPEN_DRAIN); + if (ret) + return ret; + mmc_parse_cid(cid, resp); + if (verbose) + mmc_dump_cid(cid); + + /* Set Relative Address of the card that responded */ + ret = mmc_cmd(MMC_CMD_SET_RELATIVE_ADDR, mmc_rca << 16, resp, + R1 | NCR | OPEN_DRAIN); + return ret; +} + +static void mci_set_data_timeout(mmc_csd_t * pu_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; + + unsigned long sys_freq = 0; + + sys_get_freq(AT91_MASTER_FREQ, &sys_freq); + pr_debug("mmc: sys_frequency: %lu\n", sys_freq); + + if ((mmc_blkdev.if_type == IF_TYPE_SD) || + (mmc_blkdev.if_type == IF_TYPE_SDHC)) { + /* SDHC cards maximum timeout is 100ms + * 100ms = dtocyc * mci_cycle_period s => + * 0.1s = dtocyc * (sys_freq/(2*(clkdiv+1)))^-1 s => + * dtocyc = 0.1*(sys_freq/(2*(clkdiv+1))) => + * dtocyc = sys_freq/(20*(clkdiv+1)) + */ + unsigned long clkdiv = mmci_readl(MR); + + clkdiv = MMCI_BF(CLKDIV, clkdiv); + timeout_clks = sys_freq / (20 * (clkdiv + 1)); + pr_debug("mmc: timeout cycles %lu\n", timeout_clks); + } else { + e = MMC_CSD_FIELD(TAAC, pu_csd) & 0x07; + m = (MMC_CSD_FIELD(TAAC, pu_csd) >> 3) & 0x0f; + + timeout_ns = (taac_exp[e] * taac_mant[m] + 9) / 10; + timeout_clks = MMC_CSD_FIELD(NSAC, pu_csd) * 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 + 1)); + mmci_writel(DTOR, dtor); + + pr_debug("mmc: Using %u cycles data timeout (DTOR=0x%x)\n", + dtocyc << shift, dtor); +} + +int mmc_init(int verbose) +{ + struct mmc_cid cid; + mmc_csd_t u_csd; + unsigned int max_blksz; + int ret; + + /* Initialize controller */ + mmci_writel(CR, MMCI_BIT(SWRST)); + mmci_writel(CR, MMCI_BIT(MCIEN)); + mmci_writel(DTOR, 0x5f); + mmci_writel(IDR, ~0UL); + mci_set_mode(CFG_MMC_CLK_OD, MMC_DEFAULT_BLKLEN); + + mmc_card_is_sd = 0; + mmc_blkdev.if_type = IF_TYPE_UNKNOWN; + + ret = sd_init_card(&cid, &mmc_blkdev, verbose); + + /* No SD card so try MMC */ + if (ret) { + mmc_rca = MMC_DEFAULT_RCA; + ret = mmc_init_card(&cid, verbose); + } + /* No MMC card so abort */ + if (ret) + return ret; + + /* Get CSD from the card */ + ret = mmc_cmd(MMC_CMD_SEND_CSD, mmc_rca << 16, &u_csd, R2 | NCR); + if (ret) + return ret; + if (verbose) + mmc_dump_csd((void *)&u_csd); + + /* + * ARC: If the card type is not MMC then + * check for SD CSD version: + * 0 => SD + * !0 => SDHC + */ + /* + if(mmc_blkdev.if_type != IF_TYPE_MMC) + if(SD_CSD_FIELD(VER,&u_csd) == 0) + mmc_blkdev.if_type = IF_TYPE_SD; + else + mmc_blkdev.if_type = IF_TYPE_SDHC; + */ + + mci_set_data_timeout(&u_csd); + + /* Initialize the blockdev structure */ + if (mmc_blkdev.if_type == IF_TYPE_UNKNOWN) + mmc_blkdev.if_type = IF_TYPE_MMC; + + mmc_blkdev.part_type = PART_TYPE_DOS; + mmc_blkdev.block_read = mmc_bread; + sprintf((char *)mmc_blkdev.vendor, + "Man %02x%04x Snr %08x", cid.mid, cid.oid, cid.psn); + strncpy((char *)mmc_blkdev.product, cid.pnm, + sizeof(mmc_blkdev.product)); + sprintf((char *)mmc_blkdev.revision, "%x %x", + cid.prv >> 4, cid.prv & 0x0f); + + /* + * 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 << MMC_CSD_FIELD(RBLEN, &u_csd); + if ((mmc_blkdev.if_type == IF_TYPE_MMC) & + ((max_blksz < 512) + || ((max_blksz > 512) && !MMC_CSD_FIELD(RBP, &u_csd))) + ) { + printf("Card does not support 512 byte reads, aborting.\n"); + return -ENODEV; + } + mmc_blkdev.blksz = 512; + if (MMC_CSD_VER(&u_csd) == 0) + /* CSD ver 1.x */ + mmc_blkdev.lba = + (MMC_CSD_FIELD(CSIZE, &u_csd) + + 1) * (1 << (MMC_CSD_FIELD(CSMUL, &u_csd) + 2)); + else + /* CSD ver 2.0 */ + mmc_blkdev.lba = + (SD_CSD_FIELD(CSIZE, &u_csd) + 1) * (512 * 1024); + + mci_set_mode(CFG_MMC_CLK_PP, mmc_blkdev.blksz); + + init_part(&mmc_blkdev); + if (fat_register_device(&mmc_blkdev, 1)) + printf("Could not register MMC fat device\n"); + if(verbose) + print_part_dos(&mmc_blkdev); + return 0; +} + +int mmc_read(ulong src, uchar * dst, int size) +{ + return -ENOSYS; +} + +int mmc_write(uchar * src, ulong dst, int size) +{ + return -ENOSYS; +} + +int mmc2info(ulong addr) +{ + return 0; +} + +#endif /* CONFIG_MMC */ diff --git a/include/asm-arm/arch-at572d940hf/atmel_mci.h b/include/asm-arm/arch-at572d940hf/atmel_mci.h new file mode 100644 index 0000000..ace93a1 --- /dev/null +++ b/include/asm-arm/arch-at572d940hf/atmel_mci.h @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2005-2006 Atmel Corporation + * + * 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 + */ + + +#ifndef __CPU_AT32AP_ATMEL_MCI_H__ +#define __CPU_AT32AP_ATMEL_MCI_H__ + +/* Atmel MultiMedia Card Interface (MCI) registers */ +#define MMCI_CR 0x0000 +#define MMCI_MR 0x0004 +#define MMCI_DTOR 0x0008 +#define MMCI_SDCR 0x000c +#define MMCI_ARGR 0x0010 +#define MMCI_CMDR 0x0014 +#define MMCI_RSPR 0x0020 +#define MMCI_RSPR1 0x0024 +#define MMCI_RSPR2 0x0028 +#define MMCI_RSPR3 0x002c +#define MMCI_RDR 0x0030 +#define MMCI_TDR 0x0034 +#define MMCI_SR 0x0040 +#define MMCI_IER 0x0044 +#define MMCI_IDR 0x0048 +#define MMCI_IMR 0x004c + +#define MMCI_RPR 0x100 +#define MMCI_RCR 0x104 +#define MMCI_TPR 0x108 +#define MMCI_TCR 0x10C +#define MMCI_RNPR 0x110 +#define MMCI_RNCR 0x114 +#define MMCI_TNPR 0x118 +#define MMCI_TNCR 0x11C +#define MMCI_PTCR 0x120 +#define MMCI_PTSR 0x124 + +#define MMCI_PTCR_RXTEN 0x1 +#define MMCI_PTCR_RXTDIS 0x2 +#define MMCI_PTCR_TXTEN 0x100 +#define MMCI_PTCR_TXTDIS 0x200 + + + + +/* Bitfields in CR */ +#define MMCI_MCIEN_OFFSET 0 +#define MMCI_MCIEN_SIZE 1 +#define MMCI_MCIDIS_OFFSET 1 +#define MMCI_MCIDIS_SIZE 1 +#define MMCI_PWSEN_OFFSET 2 +#define MMCI_PWSEN_SIZE 1 +#define MMCI_PWSDIS_OFFSET 3 +#define MMCI_PWSDIS_SIZE 1 +#define MMCI_SWRST_OFFSET 7 +#define MMCI_SWRST_SIZE 1 + +/* Bitfields in MR */ +#define MMCI_CLKDIV_OFFSET 0 +#define MMCI_CLKDIV_SIZE 8 +#define MMCI_PWSDIV_OFFSET 8 +#define MMCI_PWSDIV_SIZE 3 +#define MMCI_RDPROOF_OFFSET 11 +#define MMCI_RDPROOF_SIZE 1 +#define MMCI_WRPROOF_OFFSET 12 +#define MMCI_WRPROOF_SIZE 1 +#define MMCI_PDCPADV_OFFSET 14 +#define MMCI_PDCPADV_SIZE 1 +#define MMCI_PDCMODE_OFFSET 15 +#define MMCI_PDCMODE_SIZE 1 +#define MMCI_BLKLEN_OFFSET 16 +#define MMCI_BLKLEN_SIZE 16 + +/* Bitfields in DTOR */ +#define MMCI_DTOCYC_OFFSET 0 +#define MMCI_DTOCYC_SIZE 4 +#define MMCI_DTOMUL_OFFSET 4 +#define MMCI_DTOMUL_SIZE 3 + +/* Bitfields in SDCR */ +#define MMCI_SCDSEL_OFFSET 0 +#define MMCI_SCDSEL_SIZE 4 +#define MMCI_SCDBUS_OFFSET 7 +#define MMCI_SCDBUS_SIZE 1 + +/* Bitfields in ARGR */ +#define MMCI_ARG_OFFSET 0 +#define MMCI_ARG_SIZE 32 + +/* Bitfields in CMDR */ +#define MMCI_CMDNB_OFFSET 0 +#define MMCI_CMDNB_SIZE 6 +#define MMCI_RSPTYP_OFFSET 6 +#define MMCI_RSPTYP_SIZE 2 +#define MMCI_SPCMD_OFFSET 8 +#define MMCI_SPCMD_SIZE 3 +#define MMCI_OPDCMD_OFFSET 11 +#define MMCI_OPDCMD_SIZE 1 +#define MMCI_MAXLAT_OFFSET 12 +#define MMCI_MAXLAT_SIZE 1 +#define MMCI_TRCMD_OFFSET 16 +#define MMCI_TRCMD_SIZE 2 +#define MMCI_TRDIR_OFFSET 18 +#define MMCI_TRDIR_SIZE 1 +#define MMCI_TRTYP_OFFSET 19 +#define MMCI_TRTYP_SIZE 2 + +/* Bitfields in RSPRx */ +#define MMCI_RSP_OFFSET 0 +#define MMCI_RSP_SIZE 32 + +/* Bitfields in SR/IER/IDR/IMR */ +#define MMCI_CMDRDY_OFFSET 0 +#define MMCI_CMDRDY_SIZE 1 +#define MMCI_RXRDY_OFFSET 1 +#define MMCI_RXRDY_SIZE 1 +#define MMCI_TXRDY_OFFSET 2 +#define MMCI_TXRDY_SIZE 1 +#define MMCI_BLKE_OFFSET 3 +#define MMCI_BLKE_SIZE 1 +#define MMCI_DTIP_OFFSET 4 +#define MMCI_DTIP_SIZE 1 +#define MMCI_NOTBUSY_OFFSET 5 +#define MMCI_NOTBUSY_SIZE 1 +#define MMCI_ENDRX_OFFSET 6 +#define MMCI_ENDRX_SIZE 1 +#define MMCI_ENDTX_OFFSET 7 +#define MMCI_ENDTX_SIZE 1 +#define MMCI_RXBUFF_OFFSET 14 +#define MMCI_RXBUFF_SIZE 1 +#define MMCI_TXBUFE_OFFSET 15 +#define MMCI_TXBUFE_SIZE 1 +#define MMCI_RINDE_OFFSET 16 +#define MMCI_RINDE_SIZE 1 +#define MMCI_RDIRE_OFFSET 17 +#define MMCI_RDIRE_SIZE 1 +#define MMCI_RCRCE_OFFSET 18 +#define MMCI_RCRCE_SIZE 1 +#define MMCI_RENDE_OFFSET 19 +#define MMCI_RENDE_SIZE 1 +#define MMCI_RTOE_OFFSET 20 +#define MMCI_RTOE_SIZE 1 +#define MMCI_DCRCE_OFFSET 21 +#define MMCI_DCRCE_SIZE 1 +#define MMCI_DTOE_OFFSET 22 +#define MMCI_DTOE_SIZE 1 +#define MMCI_OVRE_OFFSET 30 +#define MMCI_OVRE_SIZE 1 +#define MMCI_UNRE_OFFSET 31 +#define MMCI_UNRE_SIZE 1 + +/* Constants for DTOMUL */ +#define MMCI_DTOMUL_1_CYCLE 0 +#define MMCI_DTOMUL_16_CYCLES 1 +#define MMCI_DTOMUL_128_CYCLES 2 +#define MMCI_DTOMUL_256_CYCLES 3 +#define MMCI_DTOMUL_1024_CYCLES 4 +#define MMCI_DTOMUL_4096_CYCLES 5 +#define MMCI_DTOMUL_65536_CYCLES 6 +#define MMCI_DTOMUL_1048576_CYCLES 7 + +/* Constants for RSPTYP */ +#define MMCI_RSPTYP_NO_RESP 0 +#define MMCI_RSPTYP_48_BIT_RESP 1 +#define MMCI_RSPTYP_136_BIT_RESP 2 + +/* Constants for SPCMD */ +#define MMCI_SPCMD_NO_SPEC_CMD 0 +#define MMCI_SPCMD_INIT_CMD 1 +#define MMCI_SPCMD_SYNC_CMD 2 +#define MMCI_SPCMD_INT_CMD 4 +#define MMCI_SPCMD_INT_RESP 5 + +/* Constants for TRCMD */ +#define MMCI_TRCMD_NO_TRANS 0 +#define MMCI_TRCMD_START_TRANS 1 +#define MMCI_TRCMD_STOP_TRANS 2 + +/* Constants for TRTYP */ +#define MMCI_TRTYP_BLOCK 0 +#define MMCI_TRTYP_MULTI_BLOCK 1 +#define MMCI_TRTYP_STREAM 2 + +/* Bit manipulation macros */ +#define MMCI_BIT(name) \ + (1 << MMCI_##name##_OFFSET) +#define MMCI_BF(name,value) \ + (((value) & ((1 << MMCI_##name##_SIZE) - 1)) \ + << MMCI_##name##_OFFSET) +#define MMCI_BFEXT(name,value) \ + (((value) >> MMCI_##name##_OFFSET)\ + & ((1 << MMCI_##name##_SIZE) - 1)) +#define MMCI_BFINS(name,value,old) \ + (((old) & ~(((1 << MMCI_##name##_SIZE) - 1) \ + << MMCI_##name##_OFFSET)) \ + | MMCI_BF(name,value)) + +/* Register access macros */ +#define mmci_readl(reg) \ + readl((volatile void *)MMCI_BASE + MMCI_##reg) +#define mmci_writel(reg,value) \ + writel((value), (volatile void *)MMCI_BASE + MMCI_##reg) + +#define SD_MAX_RETRIES 50 + +#endif /* __CPU_AT32AP_ATMEL_MCI_H__ */ diff --git a/include/asm-arm/arch-at572d940hf/mmc.h b/include/asm-arm/arch-at572d940hf/mmc.h new file mode 100644 index 0000000..3fb47db --- /dev/null +++ b/include/asm-arm/arch-at572d940hf/mmc.h @@ -0,0 +1,350 @@ +/* + * Copyright (C) 2008 Atmel Corporation + * + * Antonio R. Costa <antonio.costa <at> atmel.com> + * <costa.antonior <at> gmail.com> + * + * 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 + */ + +#ifndef __ASM_AT572D940_MMC_H +#define __ASM_AT572D940_MMC_H + +struct mmc_cid { + unsigned long psn; + unsigned short oid; + unsigned char mid; + unsigned char prv; + unsigned char mdt; + char pnm[7]; +}; + +/* + * Bitfileds are ugly and not portable, + * So lets redefine the CSD + */ + +typedef unsigned long mmc_csd_t[4]; +typedef unsigned long sd_csd_t[4]; + +/* + * CSD ver: 2.0 manipulation macros + */ + +/* + * Masks + */ + +#define CSD_2x_VER_MASK 0x3 +#define CSD_2x_RSVD1_MASK 0x3f +#define CSD_2x_TAAC_MASK 0xff +#define CSD_2x_NSAC_MASK 0xff +#define CSD_2x_TRANSPEED_MASK 0xff + +#define CSD_2x_CCC_MASK 0xfff +#define CSD_2x_RBLEN_MASK 0xff +#define CSD_2x_RBP_MASK 0x1 +#define CSD_2x_WBM_MASK 0x1 +#define CSD_2x_RBM_MASK 0x1 +#define CSD_2x_DSRIMP_MASK 0x1 +#define CSD_2x_RSVD2_MASK 0x3f +#define CSD_2x_CSIZE_H_MASK 0x3f + +#define CSD_2x_CSIZE_MASK 0xffff +#define CSD_2x_RSVD3_MASK 0x1 +#define CSD_2x_ERBL_MASK 0x1 +#define CSD_2x_SECSIZE_MASK 0x7f +#define CSD_2x_WPGS_MASK 0x7f + +#define CSD_2x_WPGE_MASK 0x1 +#define CSD_2x_RSVD4_MASK 0x3 +#define CSD_2x_R2WF_MASK 0x7 +#define CSD_2x_WBL_MASK 0xf +#define CSD_2x_WBP_MASK 0x1 +#define CSD_2x_RSVD5_MASK 0x1f +#define CSD_2x_FFG_MASK 0x1 +#define CSD_2x_COPY_MASK 0x1 +#define CSD_2x_PWP_MASK 0x1 +#define CSD_2x_TWP_MASK 0x1 +#define CSD_2x_FF_MASK 0x3 +#define CSD_2x_RSVD6_MASK 0x3 +#define CSD_2x_CRC_MASK 0x7f +#define CSD_2x_ONE_MASK 0x1 + +/* + * Offsets inside the single word + */ + +#define CSD_2x_VER_OFF 30 +#define CSD_2x_RSVD1_OFF 24 +#define CSD_2x_TAAC_OFF 16 +#define CSD_2x_NSAC_OFF 8 +#define CSD_2x_TRANSPEED_OFF 0 + +#define CSD_2x_CCC_OFF 20 +#define CSD_2x_RBLEN_OFF 16 +#define CSD_2x_RBP_OFF 15 +#define CSD_2x_WBM_OFF 14 +#define CSD_2x_RBM_OFF 13 +#define CSD_2x_DSRIMP_OFF 12 +#define CSD_2x_RSVD2_OFF 6 +#define CSD_2x_CSIZE_H_OFF 0 + +#define CSD_2x_CSIZE_OFF 16 +#define CSD_2x_RSVD3_OFF 15 +#define CSD_2x_ERBL_OFF 14 +#define CSD_2x_SECSIZE_OFF 7 +#define CSD_2x_WPGS_OFF 0 + +#define CSD_2x_WPGE_OFF 31 +#define CSD_2x_RSVD4_OFF 29 +#define CSD_2x_R2WF_OFF 26 +#define CSD_2x_WBL_OFF 22 +#define CSD_2x_WBP_OFF 21 +#define CSD_2x_RSVD5_OFF 16 +#define CSD_2x_FFG_OFF 15 +#define CSD_2x_COPY_OFF 14 +#define CSD_2x_PWP_OFF 13 +#define CSD_2x_TWP_OFF 12 +#define CSD_2x_FF_OFF 10 +#define CSD_2x_RSVD6_OFF 8 +#define CSD_2x_CRC_OFF 1 +#define CSD_2x_ONE_OFF 0 + +/* + * Word in which the field is placed + */ + +#define CSD_2x_VER_W 0 +#define CSD_2x_RSVD1_W 0 +#define CSD_2x_TAAC_W 0 +#define CSD_2x_NSAC_W 0 +#define CSD_2x_TRANSPEED_W 0 + +#define CSD_2x_CCC_W 1 +#define CSD_2x_RBLEN_W 1 +#define CSD_2x_RBP_W 1 +#define CSD_2x_WBM_W 1 +#define CSD_2x_RBM_W 1 +#define CSD_2x_DSRIMP_W 1 +#define CSD_2x_RSVD2_W 1 +#define CSD_2x_CSIZE_H_W 1 + +#define CSD_2x_CSIZE_W 2 +#define CSD_2x_RSVD3_W 2 +#define CSD_2x_ERBL_W 2 +#define CSD_2x_SECSIZE_W 2 +#define CSD_2x_WPGS_W 2 + +#define CSD_2x_WPGE_W 3 +#define CSD_2x_RSVD4_W 3 +#define CSD_2x_R2WF_W 3 +#define CSD_2x_WBL_W 3 +#define CSD_2x_WBP_W 3 +#define CSD_2x_RSVD5_W 3 +#define CSD_2x_FFG_W 3 +#define CSD_2x_COPY_W 3 +#define CSD_2x_PWP_W 3 +#define CSD_2x_TWP_W 3 +#define CSD_2x_FF_W 3 +#define CSD_2x_RSVD6_W 3 +#define CSD_2x_CRC_W 3 +#define CSD_2x_ONE_W 3 + +/* + * ARC: + * Please note that CSIZE field crosses the word boundary, + * anyway since SD spec 2.0 states that the highest 6 bits + * shall be set to 0s the following macro still works + */ + +#define SD_CSD_2x_CSIZE(pcsd) \ + (((unsigned long long) SD_CSD_2x_FIELD(CSIZE,pcsd)) | (((unsigned long long) SD_CSD_2x_FIELD(CSIZE_H,pcsd)) << 16)) + +#define SD_CSD_2x_FIELD(name,pcsd) \ + ((((unsigned long *)pcsd)[CSD_2x_## name ##_W] >> CSD_2x_## name ##_OFF) & CSD_2x_## name ##_MASK) + +#define CSD_1x_VER_MASK 0x3 +#define CSD_1x_RSVD1_MASK 0x3f +#define CSD_1x_TAAC_MASK 0xff +#define CSD_1x_NSAC_MASK 0xff +#define CSD_1x_TRANSPEED_MASK 0xff + +#define CSD_1x_CCC_MASK 0xfff +#define CSD_1x_RBLEN_MASK 0xf +#define CSD_1x_RBP_MASK 0x1 +#define CSD_1x_WBM_MASK 0x1 +#define CSD_1x_RBM_MASK 0x1 +#define CSD_1x_DSRIMP_MASK 0x1 +#define CSD_1x_RSVD2_MASK 0x3 +#define CSD_1x_CSIZE_H_MASK 0x3ff + +#define CSD_1x_CSIZE_MASK 0x3 +#define CSD_1x_RCMIN_MASK 0x7 +#define CSD_1x_RCMAX_MASK 0x7 +#define CSD_1x_WCMIN_MASK 0x7 +#define CSD_1x_WCMAX_MASK 0x7 +#define CSD_1x_CSMUL_MASK 0x7 +#define CSD_1x_ESBE_MASK 0x1 +#define CSD_1x_SEC_SIZE_MASK 0x7ff + +#define CSD_1x_WPGS_MASK 0x7ff +#define CSD_1x_WPGE_MASK 0x1 +#define CSD_1x_RSVD4_MASK 0x3 +#define CSD_1x_R2WF_MASK 0x7 +#define CSD_1x_WBL_MASK 0xf +#define CSD_1x_WBP_MASK 0x1 +#define CSD_1x_RSVD5_MASK 0x1f +#define CSD_1x_FFG_MASK 0x1 +#define CSD_1x_COPY_MASK 0x1 +#define CSD_1x_PWP_MASK 0x1 +#define CSD_1x_TWP_MASK 0x1 +#define CSD_1x_FF_MASK 0x3 +#define CSD_1x_RSVD6_MASK 0x3 +#define CSD_1x_CRC_MASK 0x7f +#define CSD_1x_ONE_MASK 0x1 + +/* + * Offsets inside the single word + */ + +#define CSD_1x_VER_OFF 30 +#define CSD_1x_RSVD1_OFF 24 +#define CSD_1x_TAAC_OFF 16 +#define CSD_1x_NSAC_OFF 8 +#define CSD_1x_TRANSPEED_OFF 0 + +#define CSD_1x_CCC_OFF 20 +#define CSD_1x_RBLEN_OFF 16 +#define CSD_1x_RBP_OFF 15 +#define CSD_1x_WBM_OFF 14 +#define CSD_1x_RBM_OFF 13 +#define CSD_1x_DSRIMP_OFF 12 +#define CSD_1x_RSVD2_OFF 10 +#define CSD_1x_CSIZE_H_OFF 0 + +#define CSD_1x_CSIZE_OFF 30 +#define CSD_1x_RCMIN_OFF 27 +#define CSD_1x_RCMAX_OFF 24 +#define CSD_1x_WCMIN_OFF 21 +#define CSD_1x_WCMAX_OFF 18 +#define CSD_1x_CSMUL_OFF 15 +#define CSD_1x_ERBL_OFF 14 +#define CSD_1x_SECSIZE_OFF 7 +#define CSD_1x_WPGS_OFF 0 + +#define CSD_1x_WPGE_OFF 31 +#define CSD_1x_RSVD4_OFF 29 +#define CSD_1x_R2WF_OFF 26 +#define CSD_1x_WBL_OFF 22 +#define CSD_1x_WBP_OFF 21 +#define CSD_1x_RSVD5_OFF 16 +#define CSD_1x_FFG_OFF 15 +#define CSD_1x_COPY_OFF 14 +#define CSD_1x_PWP_OFF 13 +#define CSD_1x_TWP_OFF 12 +#define CSD_1x_FF_OFF 10 +#define CSD_1x_RSVD6_OFF 8 +#define CSD_1x_CRC_OFF 1 +#define CSD_1x_ONE_OFF 0 + +/* + * Word in which the field is placed + */ + +#define CSD_1x_VER_W 0 +#define CSD_1x_RSVD1_W 0 +#define CSD_1x_TAAC_W 0 +#define CSD_1x_NSAC_W 0 +#define CSD_1x_TRANSPEED_W 0 + +#define CSD_1x_CCC_W 1 +#define CSD_1x_RBLEN_W 1 +#define CSD_1x_RBP_W 1 +#define CSD_1x_WBM_W 1 +#define CSD_1x_RBM_W 1 +#define CSD_1x_DSRIMP_W 1 +#define CSD_1x_RSVD2_W 1 +#define CSD_1x_CSIZE_H_W 1 + +#define CSD_1x_CSIZE_W 2 +#define CSD_1x_RCMIN_W 2 +#define CSD_1x_RCMAX_W 2 +#define CSD_1x_WCMIN_W 2 +#define CSD_1x_WCMAX_W 2 +#define CSD_1x_CSMUL_W 2 +#define CSD_1x_ERBL_W 2 +#define CSD_1x_SECSIZE_W 2 +#define CSD_1x_WPGS_W 2 + +#define CSD_1x_WPGE_W 3 +#define CSD_1x_RSVD4_W 3 +#define CSD_1x_R2WF_W 3 +#define CSD_1x_WBL_W 3 +#define CSD_1x_WBP_W 3 +#define CSD_1x_RSVD5_W 3 +#define CSD_1x_FFG_W 3 +#define CSD_1x_COPY_W 3 +#define CSD_1x_PWP_W 3 +#define CSD_1x_TWP_W 3 +#define CSD_1x_FF_W 3 +#define CSD_1x_RSVD6_W 3 +#define CSD_1x_CRC_W 3 +#define CSD_1x_ONE_W 3 + +#define SD_CSD_1x_FIELD(name,pcsd) \ + ((((unsigned long *)pcsd)[CSD_1x_## name ##_W] >> CSD_1x_## name ##_OFF) & CSD_1x_## name ##_MASK) + +#define SD_CSD_FIELD(name,pcsd) \ + ((SD_CSD_1x_FIELD(VER,pcsd) == 0x0) ? SD_CSD_1x_FIELD(name,pcsd) : SD_CSD_2x_FIELD(name,pcsd)) + +#define SD_CSD_1x_CSIZE(pcsd) \ + (SD_CSD_1x_FIELD(CSIZE,pcsd)+(SD_CSD_1x_FIELD(CSIZE_H,pcsd) << 2)) + +#define SD_CSD_VER(pcsd) \ + (SD_CSD_1x_FIELD(VER,pcsd)) + +#define MMC_CSD_VER(pcsd) SD_CSD_VER(pcsd) +#define MMC_CSD_FIELD(name,pcsd) SD_CSD_1x_FIELD(name,pcsd) + +/* MMC Command numbers */ +#define MMC_CMD_GO_IDLE_STATE 0 +#define MMC_CMD_SEND_OP_COND 1 +#define MMC_CMD_ALL_SEND_CID 2 +#define MMC_CMD_SET_RELATIVE_ADDR 3 +#define MMC_CMD_SD_SEND_RELATIVE_ADDR 3 +#define MMC_CMD_SET_DSR 4 +#define MMC_CMD_SELECT_CARD 7 +#define MMC_CMD_IF_COND 8 +#define MMC_CMD_SEND_CSD 9 +#define MMC_CMD_SEND_CID 10 +#define MMC_CMD_SEND_STATUS 13 +#define MMC_CMD_SET_BLOCKLEN 16 +#define MMC_CMD_READ_SINGLE_BLOCK 17 +#define MMC_CMD_READ_MULTIPLE_BLOCK 18 +#define MMC_CMD_WRITE_BLOCK 24 +#define MMC_CMD_APP_CMD 55 + +#define MMC_ACMD_BUS_WIDTH 6 +#define MMC_ACMD_SD_SEND_OP_COND 41 + +#define R1_ILLEGAL_COMMAND (1 << 22) +#define R1_APP_CMD (1 << 5) + +#endif /* __ASM_AT572D940_MMC_H */ -- 1.5.4.3 ------------------------------------------------------------------------- Check out the new SourceForge.net Marketplace. It's the best place to buy or sell services for just about anything Open Source. http://sourceforge.net/services/buy/index.php _______________________________________________ U-Boot-Users mailing list U-Boot-Users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/u-boot-users