+
+int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ enum mmc_state state;
+
+ if (argc < 2)
+ return cmd_usage(cmdtp);
+
+ if (curr_device < 0) {
+ if (get_mmc_num() > 0)
+ curr_device = 0;
+ else {
+ puts("No MMC device available\n");
+ return 1;
+ }
+ }
+
+ if (strcmp(argv[1], "rescan") == 0) {
+ struct mmc *mmc = find_mmc_device(curr_device);
+
+ if (!mmc) {
+ printf("no mmc device at slot %x\n", curr_device);
+ return 1;
+ }
+
+ mmc->has_init = 0;
+
+ if (mmc_init(mmc))
+ return 1;
+ else
+ return 0;
+ } else if (strncmp(argv[1], "part", 4) == 0) {
+ block_dev_desc_t *mmc_dev;
+ struct mmc *mmc = find_mmc_device(curr_device);
+
+ if (!mmc) {
+ printf("no mmc device at slot %x\n", curr_device);
+ return 1;
+ }
+ mmc_init(mmc);
+ mmc_dev = mmc_get_dev(curr_device);
+ if (mmc_dev != NULL &&
+ mmc_dev->type != DEV_TYPE_UNKNOWN) {
+ print_part(mmc_dev);
+ return 0;
+ }
+
+ puts("get mmc type error!\n");
+ return 1;
+ } else if (strcmp(argv[1], "list") == 0) {
+ print_mmc_devices('\n');
+ return 0;
+ } else if (strcmp(argv[1], "dev") == 0) {
+ int dev, part = -1;
+ struct mmc *mmc;
+
+ if (argc == 2)
+ dev = curr_device;
+ else if (argc == 3)
+ dev = simple_strtoul(argv[2], NULL, 10);
+ else if (argc == 4) {
+ dev = (int)simple_strtoul(argv[2], NULL, 10);
+ part = (int)simple_strtoul(argv[3], NULL, 10);
+ if (part > PART_ACCESS_MASK) {
+ printf("#part_num shouldn't be larger"
+ " than %d\n", PART_ACCESS_MASK);
+ return 1;
+ }
+ } else
+ return cmd_usage(cmdtp);
+
+ mmc = find_mmc_device(dev);
+ if (!mmc) {
+ printf("no mmc device at slot %x\n", dev);
+ return 1;
+ }
+
+ mmc_init(mmc);
+ if (part != -1) {
+ int ret;
+ if (mmc->part_config == MMCPART_NOAVAILABLE) {
+ printf("Card doesn't support part_switch\n");
+ return 1;
+ }
+
+ if (part != mmc->part_num) {
+ ret = mmc_switch_part(dev, part);
+ if (!ret)
+ mmc->part_num = part;
+
+ printf("switch to partions #%d, %s\n",
+ part, (!ret) ? "OK" : "ERROR");
+ }
+ }
+ curr_device = dev;
+ if (mmc->part_config == MMCPART_NOAVAILABLE)
+ printf("mmc%d is current device\n", curr_device);
+ else
+ printf("mmc%d(part %d) is current device\n",
+ curr_device, mmc->part_num);
+
+ return 0;
+ }
+
+ if (strcmp(argv[1], "read") == 0)
+ state = MMC_READ;
+ else if (strcmp(argv[1], "write") == 0)
+ state = MMC_WRITE;
+ else if (strcmp(argv[1], "erase") == 0)
+ state = MMC_ERASE;
+ else
+ state = MMC_INVALID;
+
+ if (state != MMC_INVALID) {
+ struct mmc *mmc = find_mmc_device(curr_device);
+ int idx = 2;
+ u32 blk, cnt, n;
+ void *addr;
+
+ if (state != MMC_ERASE) {
+ addr = (void *)simple_strtoul(argv[idx], NULL, 16);
+ ++idx;
+ } else
+ addr = 0;
+ blk = simple_strtoul(argv[idx], NULL, 16);
+ cnt = simple_strtoul(argv[idx + 1], NULL, 16);
+
+ if (!mmc) {
+ printf("no mmc device at slot %x\n", curr_device);
+ return 1;
+ }
+
+ printf("\nMMC %s: dev # %d, block # %d, count %d ... ",
+ argv[1], curr_device, blk, cnt);
+
+ mmc_init(mmc);
+
+ switch (state) {
+ case MMC_READ:
+ n = mmc->block_dev.block_read(curr_device, blk,
+ cnt, addr);
+ /* flush cache after read */
+ flush_cache((ulong)addr, cnt * 512); /* FIXME */
+ break;
+ case MMC_WRITE:
+ n = mmc->block_dev.block_write(curr_device, blk,
+ cnt, addr);
+ break;
+ case MMC_ERASE:
+ n = mmc->block_dev.block_erase(curr_device, blk, cnt);
+ break;
+ default:
+ BUG();
+ }
+
+ printf("%d blocks %s: %s\n",
+ n, argv[1], (n == cnt) ? "OK" : "ERROR");
+ return (n == cnt) ? 0 : 1;
+ }
+
+ return cmd_usage(cmdtp);
+}
+
+U_BOOT_CMD(
+ mmc, 6, 1, do_mmcops,
+ "MMC sub system",
+ "read addr blk# cnt\n"
+ "mmc write addr blk# cnt\n"
+ "mmc erase blk# cnt\n"
+ "mmc rescan\n"
+ "mmc part - lists available partition on current mmc device\n"
+ "mmc dev [dev] [part] - show or set current mmc device [partition]\n"
+ "mmc list - lists available devices");
+#endif