summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorMartin LUNDHOLM <martin.xa.lundholm@stericsson.com>2010-08-23 17:31:29 +0200
committerMichael BRANDT <michael.brandt@stericsson.com>2010-08-30 19:39:16 +0200
commit3a5b27b58258ff61dfae3167bc46fed0146ddffd (patch)
treef185f10ccb07c693998340343afc4a680949aea7 /common
parent6e7432129841a6177b097c5d2388c6aa9ed257c3 (diff)
U-boot: MMC update.
MMC has been updated with several improvements. Primarily MMC performance has been improved by using assembler code for low level FIFO handling. Also some MMC functionality has been added, e.g. support for DDR and reliable write. Data and command delay times were incremented, otherwise hangups and timeouts were observed. Tested on HREF+ 1.1 V21 and HREF+ 1.1 V32 (Micron PoP). Following WP depends on this change (more reliable SD card write support): ST-Ericsson ID: WP264488 Change-Id: Ic92abffe1640aa9375b8d43a6b8522ca8296a368 Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/4056 Reviewed-by: Michael BRANDT <michael.brandt@stericsson.com> Tested-by: Michael BRANDT <michael.brandt@stericsson.com>
Diffstat (limited to 'common')
-rw-r--r--common/cmd_mmc.c245
1 files changed, 241 insertions, 4 deletions
diff --git a/common/cmd_mmc.c b/common/cmd_mmc.c
index 0e3393b5f..66a4882fe 100644
--- a/common/cmd_mmc.c
+++ b/common/cmd_mmc.c
@@ -25,6 +25,8 @@
#include <command.h>
#include <mmc.h>
+#define READ_WRITE_TEST "rwr"
+
#ifndef CONFIG_GENERIC_MMC
static int curr_device = -1;
@@ -114,6 +116,135 @@ static void print_mmcinfo(struct mmc *mmc)
printf("Bus Width: %d-bit\n", mmc->bus_width);
}
+static void print_csd(struct mmc *mmc)
+{
+ printf("mmc->csd[0] = 0x%08X\n", mmc->csd[0]);
+ printf("mmc->csd[1] = 0x%08X\n", mmc->csd[1]);
+ printf("mmc->csd[2] = 0x%08X\n", mmc->csd[2]);
+ printf("mmc->csd[3] = 0x%08X\n", mmc->csd[3]);
+
+ printf("csd->csd_structure = 0x%02X\n", CSD_STRUCTURE(mmc->csd));
+ printf("csd->spec_vers = 0x%02X\n", CSD_SPEC_VERS(mmc->csd));
+ printf("csd->taac = 0x%02X\n", CSD_TAAC(mmc->csd));
+ printf("csd->nsac = 0x%02X\n", CSD_NSAC(mmc->csd));
+ printf("csd->tran_speed = 0x%02X\n", CSD_TRAN_SPEED(mmc->csd));
+ printf("csd->ccc = 0x%04X\n", CSD_CCC(mmc->csd));
+ printf("csd->read_bl_len = 0x%02X\n", CSD_READ_BL_LEN(mmc->csd));
+ printf("csd->read_bl_partial = 0x%02X\n",
+ CSD_READ_BL_PARTIAL(mmc->csd));
+ printf("csd->write_blk_misalign = 0x%02X\n",
+ CSD_WRITE_BLK_MISALIGN(mmc->csd));
+ printf("csd->read_blk_misalign = 0x%02X\n",
+ CSD_READ_BLK_MISALIGN(mmc->csd));
+ printf("csd->dsr_imp = 0x%02X\n", CSD_DSR_IMP(mmc->csd));
+ printf("csd->c_size = 0x%04X\n", CSD_C_SIZE(mmc->csd));
+ printf("csd->vdd_r_curr_min = 0x%04X\n", CSD_VDD_R_CURR_MIN(mmc->csd));
+ printf("csd->vdd_r_curr_max = 0x%04X\n", CSD_VDD_R_CURR_MAX(mmc->csd));
+ printf("csd->vdd_w_curr_min = 0x%04X\n", CSD_VDD_W_CURR_MIN(mmc->csd));
+ printf("csd->vdd_w_curr_max = 0x%04X\n", CSD_VDD_W_CURR_MAX(mmc->csd));
+ printf("csd->c_size_mult = 0x%04X\n", CSD_C_SIZE_MULT(mmc->csd));
+ printf("csd->erase_grp_size = 0x%04X\n", CSD_ERASE_GRP_SIZE(mmc->csd));
+ printf("csd->erase_grp_mult = 0x%04X\n", CSD_ERASE_GRP_MULT(mmc->csd));
+ printf("csd->wp_grp_size = 0x%04X\n", CSD_WP_GRP_SIZE(mmc->csd));
+ printf("csd->wp_grp_enable = 0x%02X\n", CSD_WP_GRP_ENABLE(mmc->csd));
+ printf("csd->default_ecc = 0x%02X\n", CSD_DEFAULT_ECC(mmc->csd));
+ printf("csd->r2w_factor = 0x%04X\n", CSD_R2W_FACTOR(mmc->csd));
+ printf("csd->write_bl_len = 0x%04X\n", CSD_WRITE_BL_LEN(mmc->csd));
+ printf("csd->write_bl_partial = 0x%02X\n",
+ CSD_WRITE_BL_PARTIAL(mmc->csd));
+ printf("csd->file_format_grp = 0x%02X\n",
+ CSD_FILE_FORMAT_GRP(mmc->csd));
+ printf("csd->copy = 0x%02X\n", CSD_COPY(mmc->csd));
+ printf("csd->perm_write_protect = 0x%02X\n",
+ CSD_PERM_WRITE_PROTECT(mmc->csd));
+ printf("csd->tmp_write_protect = 0x%02X\n",
+ CSD_TMP_WRITE_PROTECT(mmc->csd));
+ printf("csd->ecc = 0x%02X\n", CSD_ECC(mmc->csd));
+ printf("csd->crc = 0x%02X\n", CSD_CRC(mmc->csd));
+ printf("csd->one = 0x%02X\n", CSD_ONE(mmc->csd));
+}
+
+static void print_ext_csd(char *ext_csd)
+{
+ printf("ext_csd->s_cmd_set = 0x%02X\n", ext_csd[504]);
+ printf("ext_csd->hpl_features = 0x%02X\n", ext_csd[503]);
+ printf("ext_csd->bkops_support = 0x%02X\n", ext_csd[502]);
+ printf("ext_csd->bkops_status = 0x%02X\n", ext_csd[246]);
+ printf("ext_csd->correctly_prg_sectors_num = 0x%08X\n",
+ ext_csd[245] * (1 << 24) | ext_csd[244] * (1 << 16) |
+ ext_csd[243] * (1 << 8) | ext_csd[242]);
+ printf("ext_csd->ini_timeout_ap = 0x%02X\n", ext_csd[241]);
+ printf("ext_csd->pwr_cl_ddr_52_360 = 0x%02X\n", ext_csd[239]);
+ printf("ext_csd->pwr_cl_ddr_52_195 = 0x%02X\n", ext_csd[238]);
+ printf("ext_csd->min_perf_ddr_w_8_52 = 0x%02X\n", ext_csd[235]);
+ printf("ext_csd->min_perf_ddr_r_8_52 = 0x%02X\n", ext_csd[234]);
+ printf("ext_csd->trim_mult = 0x%02X\n", ext_csd[232]);
+ printf("ext_csd->sec_feature_support = 0x%02X\n", ext_csd[231]);
+ printf("ext_csd->sec_erase_mult = 0x%02X\n", ext_csd[230]);
+ printf("ext_csd->sec_trim_mult = 0x%02X\n", ext_csd[229]);
+ printf("ext_csd->boot_info = 0x%02X\n", ext_csd[228]);
+ printf("ext_csd->boot_size_mult = 0x%02X\n", ext_csd[226]);
+ printf("ext_csd->acc_size = 0x%02X\n", ext_csd[225]);
+ printf("ext_csd->hc_erase_gp_size = 0x%02X\n", ext_csd[224]);
+ printf("ext_csd->erase_timeout_mult = 0x%02X\n", ext_csd[223]);
+ printf("ext_csd->rel_wr_sec_c = 0x%02X\n", ext_csd[222]);
+ printf("ext_csd->hc_wp_grp_size = 0x%02X\n", ext_csd[221]);
+ printf("ext_csd->s_c_vcc = 0x%02X\n", ext_csd[220]);
+ printf("ext_csd->s_c_vccq = 0x%02X\n", ext_csd[219]);
+ printf("ext_csd->s_a_timeout = 0x%02X\n", ext_csd[217]);
+ printf("ext_csd->sec_count = 0x%08X\n", ext_csd[215] * (1 << 24) |
+ ext_csd[214] * (1 << 16)|ext_csd[213]*(1 << 8)|ext_csd[212]);
+ printf("ext_csd->min_perf_w_8_52 = 0x%02X\n", ext_csd[210]);
+ printf("ext_csd->min_perf_r_8_52 = 0x%02X\n", ext_csd[209]);
+ printf("ext_csd->min_perf_w_8_26_4_52 = 0x%02X\n", ext_csd[208]);
+ printf("ext_csd->min_perf_r_8_26_4_52 = 0x%02X\n", ext_csd[207]);
+ printf("ext_csd->min_perf_w_4_26 = 0x%02X\n", ext_csd[206]);
+ printf("ext_csd->min_perf_r_4_26 = 0x%02X\n", ext_csd[205]);
+ printf("ext_csd->pwr_cl_26_360 = 0x%02X\n", ext_csd[203]);
+ printf("ext_csd->pwr_cl_52_360 = 0x%02X\n", ext_csd[202]);
+ printf("ext_csd->pwr_cl_26_195 = 0x%02X\n", ext_csd[201]);
+ printf("ext_csd->pwr_cl_52_195 = 0x%02X\n", ext_csd[200]);
+ printf("ext_csd->partition_switch_time = 0x%02X\n", ext_csd[199]);
+ printf("ext_csd->out_of_interrupt_time = 0x%02X\n", ext_csd[198]);
+ printf("ext_csd->card_type = 0x%02X\n", ext_csd[196]);
+ printf("ext_csd->csd_structure = 0x%02X\n", ext_csd[194]);
+ printf("ext_csd->ext_csd_rev = 0x%02X\n", ext_csd[192]);
+ printf("ext_csd->cmd_set = 0x%02X\n", ext_csd[191]);
+ printf("ext_csd->cmd_set_rev = 0x%02X\n", ext_csd[189]);
+ printf("ext_csd->power_class = 0x%02X\n", ext_csd[187]);
+ printf("ext_csd->hs_timing = 0x%02X\n", ext_csd[185]);
+ printf("ext_csd->bus_width = 0x%02X\n", ext_csd[183]);
+ printf("ext_csd->erased_mem_cont = 0x%02X\n", ext_csd[181]);
+ printf("ext_csd->partition_config = 0x%02X\n", ext_csd[179]);
+ printf("ext_csd->boot_config_prot = 0x%02X\n", ext_csd[178]);
+ printf("ext_csd->boot_bus_width = 0x%02X\n", ext_csd[177]);
+ printf("ext_csd->erase_group_def = 0x%02X\n", ext_csd[175]);
+ printf("ext_csd->boot_wp = 0x%02X\n", ext_csd[173]);
+ printf("ext_csd->user_wp = 0x%02X\n", ext_csd[171]);
+ printf("ext_csd->fw_config = 0x%02X\n", ext_csd[169]);
+ printf("ext_csd->rpmb_size_mult = 0x%02X\n", ext_csd[168]);
+ printf("ext_csd->wr_rel_set = 0x%02X\n", ext_csd[167]);
+ printf("ext_csd->wr_rel_param = 0x%02X\n", ext_csd[166]);
+ printf("ext_csd->bkops_start = 0x%02X\n", ext_csd[164]);
+ printf("ext_csd->bkops_en = 0x%02X\n", ext_csd[163]);
+ printf("ext_csd->rst_n_function = 0x%02X\n", ext_csd[162]);
+ printf("ext_csd->hpi_mgmt = 0x%02X\n", ext_csd[161]);
+ printf("ext_csd->partitioning_support = 0x%02X\n", ext_csd[160]);
+ printf("ext_csd->max_en_size_mult = 0x%08X\n", ext_csd[159] * (1 << 16)
+ | ext_csd[158] * (1 << 8) | ext_csd[157]);
+ printf("ext_csd->partitions_attribute = 0x%02X\n", ext_csd[156]);
+ printf("ext_csd->partition_setting_completed = 0x%02X\n", ext_csd[155]);
+ printf("ext_csd->gp_size_mult = 0x%08X\n", ext_csd[146] * (1 << 24) |
+ ext_csd[145] * (1 << 16) | ext_csd[144] * (1 << 8) |
+ ext_csd[143]);
+ printf("ext_csd->enh_size_mult = 0x%08X\n", ext_csd[142] * (1 << 16) |
+ ext_csd[141]*(1 << 8) | ext_csd[140]);
+ printf("ext_csd->enh_start_addr = 0x%08X\n", ext_csd[139] * (1 << 24) |
+ ext_csd[138] * (1 << 16) | ext_csd[137] * (1 << 8) |
+ ext_csd[136]);
+ printf("ext_csd->sec_bad_blk_mgmnt = 0x%02X\n", ext_csd[134]);
+}
+
int do_mmcinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
struct mmc *mmc;
@@ -130,13 +261,37 @@ int do_mmcinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
mmc_init(mmc);
print_mmcinfo(mmc);
+
+ if ((argc > 2) && (strcmp(argv[2], "csd") == 0))
+ print_csd(mmc);
+
+ /* Print Ext CSD */
+ if ((argc > 2) && (strcmp(argv[2], "ext_csd") == 0)) {
+ char ext_csd[512];
+ struct mmc_cmd cmd;
+ struct mmc_data data;
+
+ /* Get the Card Status Register */
+ cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
+ cmd.resp_type = MMC_RSP_R1;
+ cmd.cmdarg = 0;
+ cmd.flags = 0;
+
+ data.dest = ext_csd;
+ data.blocks = 1;
+ data.blocksize = 512;
+ data.flags = MMC_DATA_READ;
+
+ if (!mmc->send_cmd(mmc, &cmd, &data))
+ print_ext_csd(ext_csd);
+ }
}
return 0;
}
-U_BOOT_CMD(mmcinfo, 2, 0, do_mmcinfo,
- "mmcinfo <dev num>-- display MMC info\n",
+U_BOOT_CMD(mmcinfo, 3, 0, do_mmcinfo,
+ "mmcinfo <dev num> [csd | ext_csd] -- display MMC info\n",
""
);
@@ -182,7 +337,7 @@ int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
if (!mmc)
return 1;
- printf("\nMMC read: dev # %d, block # %d, count %d ... ",
+ printf("\nMMC read: dev # %d, block # %d, count %d\n",
dev, blk, cnt);
mmc_init(mmc);
@@ -207,7 +362,7 @@ int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
if (!mmc)
return 1;
- printf("\nMMC write: dev # %d, block # %d, count %d ... ",
+ printf("\nMMC write: dev # %d, block # %d, count %d\n",
dev, blk, cnt);
mmc_init(mmc);
@@ -217,6 +372,86 @@ int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
printf("%d blocks written: %s\n",
n, (n == cnt) ? "OK" : "ERROR");
return (n == cnt) ? 0 : 1;
+ } else if (strcmp(argv[1], READ_WRITE_TEST) == 0) {
+ int dev = simple_strtoul(argv[2], NULL, 10);
+ int blk = simple_strtoul(argv[3], NULL, 10);
+ u32 cnt = simple_strtoul(argv[4], NULL, 10);
+ u32 loops = simple_strtoul(argv[5], NULL, 10);
+ u32 n;
+ struct mmc *mmc = find_mmc_device(dev);
+ char *s = getenv("loadaddr");
+ /* Assume we can use up to 16MB at "loadaddr" */
+ static const u32 max_transfer_size = 8 * 1024 * 1024;
+ u32 transfer_size = cnt * mmc->block_dev.blksz;;
+ u8 *read_buf = (u8 *) simple_strtoul(s, NULL, 16);
+ u8 *ver_buf = (u8 *) read_buf + max_transfer_size;
+
+ if (!mmc)
+ return 1;
+
+ if (!mmc->block_dev.blksz)
+ mmc_init(mmc);
+
+ if (!loops) {
+ printf("mmc " READ_WRITE_TEST " failed! "
+ "loops(%u)\n", loops);
+ return 1;
+ }
+ if (!transfer_size ||
+ (transfer_size > max_transfer_size)) {
+ printf("mmc " READ_WRITE_TEST " failed! "
+ "(0 < transfer_size(%u) < %u)\n",
+ transfer_size, max_transfer_size);
+ return 1;
+ }
+
+ if (s == NULL)
+ return 1;
+
+ printf("\nMMC " READ_WRITE_TEST ": dev(%u), "
+ "block(%u), cnt(%u) loops(%u)\n",
+ dev, blk, cnt, loops);
+
+ while (loops--) {
+ memset(read_buf, 0, transfer_size);
+ memset(ver_buf, 0, transfer_size);
+ n = mmc->block_dev.block_read(dev, blk, cnt,
+ read_buf);
+ if (n != cnt) {
+ printf("mmc " READ_WRITE_TEST
+ " failed! loops(%u) n(%u)\n",
+ loops, n);
+ return 1;
+ }
+ /* Flush cache after read */
+ flush_cache((ulong)read_buf, transfer_size);
+ n = mmc->block_dev.block_write(dev, blk, cnt,
+ read_buf);
+ if (n != cnt) {
+ printf("mmc " READ_WRITE_TEST
+ " failed! loops(%u) n(%u)\n",
+ loops, n);
+ return 1;
+ }
+ n = mmc->block_dev.block_read(dev, blk, cnt,
+ ver_buf);
+ if (n != cnt) {
+ printf("mmc " READ_WRITE_TEST
+ " failed! loops(%u) n(%u)\n",
+ loops, n);
+ return 1;
+ }
+ /* Flush cache after read */
+ flush_cache((ulong)read_buf, transfer_size);
+ if (memcmp(read_buf, ver_buf, transfer_size)) {
+ printf("mmc " READ_WRITE_TEST
+ " failed! loops(%u)\n",
+ loops);
+ return 1;
+ }
+ }
+ printf("mmc " READ_WRITE_TEST " ok!\n");
+ return 0;
} else {
printf("Usage:\n%s\n", cmdtp->usage);
rc = 1;
@@ -231,6 +466,8 @@ U_BOOT_CMD(
"MMC sub system",
"read <device num> addr blk# cnt\n"
"mmc write <device num> addr blk# cnt\n"
+ "mmc " READ_WRITE_TEST " <device num> blk# cnt loops - reads, "
+ "writes,reads and verifies a chunk of data\n"
"mmc rescan <device num>\n"
"mmc list - lists available devices");
#endif