static int init_mmc_for_env(struct mmc *mmc) { if (!mmc) { puts("No MMC card found\n"); return -1; } if (mmc_init(mmc)) { puts("MMC init failed\n"); return -1; } #ifdef CONFIG_SYS_MMC_ENV_PART if (CONFIG_SYS_MMC_ENV_PART != mmc->part_num) { int mmc_env_devno = mmc_get_env_devno(); if (mmc_switch_part(mmc_env_devno, CONFIG_SYS_MMC_ENV_PART)) { puts("MMC partition switch failed\n"); return -1; } } #endif return 0; }
static void fini_mmc_for_env(struct mmc *mmc) { #ifdef CONFIG_SYS_MMC_ENV_PART if (CONFIG_SYS_MMC_ENV_PART != mmc->part_num) mmc_switch_part(CONFIG_SYS_MMC_ENV_DEV, mmc->part_num); #endif }
static void fini_mmc_for_env(struct mmc *mmc) { #ifdef CONFIG_SYS_MMC_ENV_PART int mmc_env_devno = mmc_get_env_devno(); if (CONFIG_SYS_MMC_ENV_PART != mmc->part_num) mmc_switch_part(mmc_env_devno, mmc->part_num); #endif }
static void fini_mmc_for_env(struct mmc *mmc) { #ifdef CONFIG_SYS_MMC_ENV_PART int dev = CONFIG_SYS_MMC_ENV_DEV; #ifdef CONFIG_SPL_BUILD dev = 0; #endif if (mmc_get_env_part(mmc) != mmc->part_num) mmc_switch_part(dev, mmc->part_num); #endif }
static int mmc_select_hwpart(struct udevice *bdev, int hwpart) { struct udevice *mmc_dev = dev_get_parent(bdev); struct mmc *mmc = mmc_get_mmc_dev(mmc_dev); struct blk_desc *desc = dev_get_uclass_platdata(bdev); if (desc->hwpart == hwpart) return 0; if (mmc->part_config == MMCPART_NOAVAILABLE) return -EMEDIUMTYPE; return mmc_switch_part(mmc, hwpart); }
static int mmc_access_part(struct dfu_entity *dfu, struct mmc *mmc, int part) { int ret; if (part == mmc->part_num) return 0; ret = mmc_switch_part(dfu->dev_num, part); if (ret) { error("Cannot switch to partition %d\n", part); return ret; } mmc->part_num = part; return 0; }
static struct mmc_part *get_partition(AvbOps *ops, const char *partition) { int ret; u8 dev_num; int part_num = 0; struct mmc_part *part; struct blk_desc *mmc_blk; part = malloc(sizeof(struct mmc_part)); if (!part) return NULL; dev_num = get_boot_device(ops); part->mmc = find_mmc_device(dev_num); if (!part->mmc) { printf("No MMC device at slot %x\n", dev_num); return NULL; } if (mmc_init(part->mmc)) { printf("MMC initialization failed\n"); return NULL; } ret = mmc_switch_part(part->mmc, part_num); if (ret) return NULL; mmc_blk = mmc_get_blk_desc(part->mmc); if (!mmc_blk) { printf("Error - failed to obtain block descriptor\n"); return NULL; } ret = part_get_info_by_name(mmc_blk, partition, &part->info); if (!ret) { printf("Can't find partition '%s'\n", partition); return NULL; } part->dev_num = dev_num; part->mmc_blk = mmc_blk; return part; }
static int mmc_set_env_part(struct mmc *mmc) { uint part = mmc_get_env_part(mmc); int dev = CONFIG_SYS_MMC_ENV_DEV; int ret = 0; #ifdef CONFIG_SPL_BUILD dev = 0; #endif if (part != mmc->part_num) { ret = mmc_switch_part(dev, part); if (ret) puts("MMC partition switch failed\n"); } return ret; }
/* * This needs to be called with host claimed * @part: GPP partition part ID, should be 1/2/3/4. * @addr: GPP write group unit */ int mmc_set_user_wp(struct mmc_card *card, unsigned int part, unsigned int wpg) { struct mmc_command cmd = {0}; int err = 0; u32 status = 0; if (!card) return -ENODEV; mmc_claim_host(card->host); /* * enable WP to partitions * set bit2 of ext_csd[171], permanent write protect */ err = mmc_switch_bits(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_USER_WP, EXT_CSD_PERMANENT_WP, card->ext_csd.generic_cmd6_time, true, true); if (err) { pr_err("%s: enable permanent write protect err %d!\n", __func__, err); mmc_release_host(card->host); return err; } err = mmc_switch_part(card, part); if (err) goto switchback; cmd.opcode = MMC_SET_WRITE_PROT; cmd.arg = wpg * card->ext_csd.wpg_sz; cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); if (err) { pr_err("%s: failed to set addr 0x%x write protected, err %d\n", __func__, cmd.arg, err); goto out; } /* Must check status to be sure of no errors */ do { err = mmc_send_status(card, &status); if (err) { pr_err("%s: card status get err %d, status 0x%x\n", __func__, err, status); goto out; } if (card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) break; if (mmc_host_is_spi(card->host)) break; } while (R1_CURRENT_STATE(status) == R1_STATE_PRG); if (mmc_host_is_spi(card->host)) { if (status & R1_SPI_ILLEGAL_COMMAND) { pr_err("%s: error card status 0x%x\n", __func__, status); err = -EILSEQ; goto out; } } else { if (status & 0xFDFFA000) pr_warn("%s: unexpected status %#x after switch", __func__, status); if (status & R1_SWITCH_ERROR) { pr_err("%s: card switch error, status 0x%x\n", __func__, status); err = -EIO; goto out; } if (status & R1_OUT_OF_RANGE) { pr_err("%s: addr out of range, status 0x%x\n", __func__, status); err = -EINVAL; } } out: err = mmc_switch_part(card, EXT_CSD_PART_CONFIG_ACC_USER); if (err) { pr_warn("%s: switch to USER partition failed!\n", __func__); WARN_ON(err); } switchback: /* * clear bit2 of ext_csd[171], permanent write protect */ err = mmc_switch_bits(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_USER_WP, EXT_CSD_PERMANENT_WP, card->ext_csd.generic_cmd6_time, true, false); if (err) { pr_err("%s: clear write protect err %d!\n", __func__, err); } mmc_release_host(card->host); return err; }
/* * @part: GPP partition part number * @addr: GPP write group */ int mmc_wp_status(struct mmc_card *card, unsigned int part, unsigned int addr, u8 *wp_status) { struct mmc_command cmd = {0}; struct mmc_data data = {0}; struct mmc_request mrq = {0}; struct scatterlist sg; u32 status = 0; int err = 0; u8 *rbuf = NULL; if (!card) return -ENODEV; if (!card->ext_csd.gpp_sz[part - EXT_CSD_PART_CONFIG_ACC_GP0]) { pr_err("%s: doesn't have GPP%d\n", __func__, part - 3); return -ENODEV; } rbuf = kzalloc(8, GFP_KERNEL); if (rbuf == NULL) { pr_err("%s: no memory\n", __func__); return -ENOMEM; } cmd.opcode = MMC_SEND_WRITE_PROT_TYPE; cmd.arg = addr * card->ext_csd.wpg_sz; cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; data.sg = &sg; data.sg_len = 1; data.blksz = 8; data.blocks = 1; data.flags = MMC_DATA_READ; sg_init_one(data.sg, rbuf, 8); mrq.data = &data; mrq.cmd = &cmd; mmc_claim_host(card->host); mmc_set_data_timeout(&data, card); err = mmc_switch_part(card, part); if (err) { mmc_release_host(card->host); dev_err(mmc_dev(card->host), "%s: swith error %d\n", __func__, err); goto out; } mmc_wait_for_req(card->host, &mrq); if (cmd.error) { dev_err(mmc_dev(card->host), "%s: cmd error %d\n", __func__, cmd.error); } if (data.error) { dev_err(mmc_dev(card->host), "%s: data error %d\n", __func__, data.error); } /* Must check status to be sure of no errors */ do { err = mmc_send_status(card, &status); if (err) { pr_err("%s: get card status err %d, status 0x%x\n", __func__, err, status); goto out; } if (card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) break; if (mmc_host_is_spi(card->host)) break; } while (R1_CURRENT_STATE(status) == R1_STATE_PRG); if (mmc_host_is_spi(card->host)) { if (status & R1_SPI_ILLEGAL_COMMAND) { pr_err("%s: error card status 0x%x\n", __func__, status); goto out; } } else { if (status & 0xFDFFA000) pr_warn("%s: unexpected status %#x after switch", __func__, status); if (status & R1_SWITCH_ERROR) { pr_err("%s: card switch error, status 0x%x\n", __func__, status); } if (status & R1_OUT_OF_RANGE) { pr_err("%s: addr out of range, status 0x%x\n", __func__, status); goto out; } } mmc_switch_part(card, EXT_CSD_PART_CONFIG_ACC_USER); mmc_release_host(card->host); sg_copy_from_buffer(data.sg, 1, rbuf, 8); /* * the first write protect group type is in the last two * bits in the last byte read from the device. */ *wp_status = rbuf[7] & 0x3; kfree(rbuf); return 0; out: kfree(rbuf); return -EPERM; }
static int mmc_burn_image(size_t image_size) { struct mmc *mmc; lbaint_t start_lba; lbaint_t blk_count; ulong blk_written; int err; const u8 mmc_dev_num = CONFIG_SYS_MMC_ENV_DEV; #ifdef CONFIG_BLK struct blk_desc *blk_desc; #endif mmc = find_mmc_device(mmc_dev_num); if (!mmc) { printf("No SD/MMC/eMMC card found\n"); return -ENOMEDIUM; } err = mmc_init(mmc); if (err) { printf("%s(%d) init failed\n", IS_SD(mmc) ? "SD" : "MMC", mmc_dev_num); return err; } #ifdef CONFIG_SYS_MMC_ENV_PART if (mmc->part_num != CONFIG_SYS_MMC_ENV_PART) { err = mmc_switch_part(mmc_dev_num, CONFIG_SYS_MMC_ENV_PART); if (err) { printf("MMC partition switch failed\n"); return err; } } #endif /* SD reserves LBA-0 for MBR and boots from LBA-1, * MMC/eMMC boots from LBA-0 */ start_lba = IS_SD(mmc) ? 1 : 0; #ifdef CONFIG_BLK blk_count = image_size / mmc->write_bl_len; if (image_size % mmc->write_bl_len) blk_count += 1; blk_desc = mmc_get_blk_desc(mmc); if (!blk_desc) { printf("Error - failed to obtain block descriptor\n"); return -ENODEV; } blk_written = blk_dwrite(blk_desc, start_lba, blk_count, (void *)get_load_addr()); #else blk_count = image_size / mmc->block_dev.blksz; if (image_size % mmc->block_dev.blksz) blk_count += 1; blk_written = mmc->block_dev.block_write(mmc_dev_num, start_lba, blk_count, (void *)get_load_addr()); #endif /* CONFIG_BLK */ if (blk_written != blk_count) { printf("Error - written %#lx blocks\n", blk_written); return -ENOSPC; } printf("Done!\n"); #ifdef CONFIG_SYS_MMC_ENV_PART if (mmc->part_num != CONFIG_SYS_MMC_ENV_PART) mmc_switch_part(mmc_dev_num, mmc->part_num); #endif return 0; }
/******************************************************************************* Reset environment variables. ********************************************************************************/ int resetenv_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { #if defined(CONFIG_ENV_IS_IN_FLASH ) ulong stop_addr; ulong start_addr; #elif defined(CONFIG_ENV_IS_IN_MMC) lbaint_t start_lba; lbaint_t blk_count; ulong blk_erased; ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE); struct mmc *mmc; int err; #endif #if defined(CONFIG_ENV_IS_IN_NAND) size_t env_offset = CONFIG_ENV_OFFSET; nand_info_t *nand = &nand_info[0]; printf("Erasing 0x%x - 0x%x:",env_offset, env_offset + CONFIG_ENV_RANGE); nand_erase(nand, env_offset, CONFIG_ENV_RANGE); puts ("[Done]\n"); #elif defined(CONFIG_ENV_IS_IN_SPI_FLASH) u32 sector = 1; if (CONFIG_ENV_SIZE > CONFIG_ENV_SECT_SIZE) { sector = CONFIG_ENV_SIZE / CONFIG_ENV_SECT_SIZE; if (CONFIG_ENV_SIZE % CONFIG_ENV_SECT_SIZE) sector++; } #ifdef CONFIG_SPI_FLASH_PROTECTION printf("Unprotecting flash:"); spi_flash_protect(flash, 0); printf("\t\t[Done]\n"); #endif printf("Erasing 0x%x - 0x%x:",CONFIG_ENV_OFFSET, CONFIG_ENV_OFFSET + sector * CONFIG_ENV_SECT_SIZE); if(!flash) { flash = spi_flash_probe(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS, CONFIG_SF_DEFAULT_SPEED, CONFIG_SF_DEFAULT_MODE); if (!flash) { printf("Failed to probe SPI Flash\n"); set_default_env("!spi_flash_probe() failed"); return 0; } } if (spi_flash_erase(flash, CONFIG_ENV_OFFSET, sector * CONFIG_ENV_SECT_SIZE)) return 1; puts("\t[Done]\n"); #ifdef CONFIG_SPI_FLASH_PROTECTION printf("Protecting flash:"); spi_flash_protect(flash, 1); printf("\t\t[Done]\n"); #endif #elif defined(CONFIG_ENV_IS_IN_FLASH ) start_addr = CONFIG_ENV_ADDR; stop_addr = start_addr + CONFIG_ENV_SIZE - 1; printf("Erasing sector 0x%x:",CONFIG_ENV_OFFSET); flash_sect_protect (0, start_addr, stop_addr); flash_sect_erase (start_addr, stop_addr); flash_sect_protect (1, start_addr, stop_addr); printf("\t[Done]\n"); #elif defined(CONFIG_ENV_IS_IN_MMC) start_lba = CONFIG_ENV_ADDR / CONFIG_ENV_SECT_SIZE; blk_count = CONFIG_ENV_SIZE / CONFIG_ENV_SECT_SIZE; mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV); if (!mmc) { printf("No MMC card found\n"); return 1; } if (mmc_init(mmc)) { printf("MMC(%d) init failed\n", CONFIG_SYS_MMC_ENV_DEV); return 1; } #ifdef CONFIG_SYS_MMC_ENV_PART /* Valid for MMC/eMMC only - switch to ENV partition */ if (CONFIG_SYS_MMC_ENV_PART != mmc->part_num) { if (mmc_switch_part(CONFIG_SYS_MMC_ENV_DEV, CONFIG_SYS_MMC_ENV_PART)) { printf("MMC partition switch failed\n"); return 1; } } #endif printf("Erasing 0x"LBAF" blocks starting at sector 0x"LBAF" :", blk_count, start_lba); /* For some unknown reason the mmc_berase() fails with timeout if called before any futher write to MMC/SD (for instance, right after u-boot bring up). However the mmc_bwrite() always succeds. Writing zeroes into SD/MMC blocks is similar operation as doing so to IDE/SATA disk and therefore can be used for erasing the imformation stored on the media. blk_erased = mmc_berase(CONFIG_SYS_MMC_ENV_DEV, start_lba, blk_count); */ memset(buf, 0, CONFIG_ENV_SIZE); blk_erased = mmc_bwrite(CONFIG_SYS_MMC_ENV_DEV, start_lba, blk_count, buf); if (blk_erased != blk_count) { printf("\t[FAIL] - erased %#lx blocks\n", blk_erased); err = 1; } else { printf("\t[Done]\n"); err = 0; } #ifdef CONFIG_SYS_MMC_ENV_PART /* Valid for MMC/eMMC only - restore current partition */ if (CONFIG_SYS_MMC_ENV_PART != mmc->part_num) mmc_switch_part(CONFIG_SYS_MMC_ENV_DEV, mmc->part_num); #endif if (err) return err; #endif printf("Warning: Default Environment Variables will take effect Only after RESET\n"); return 0; }
int spl_mmc_load_image(void) { struct mmc *mmc; int err; u32 boot_mode; mmc_initialize(gd->bd); /* We register only one device. So, the dev id is always 0 */ mmc = find_mmc_device(0); if (!mmc) { #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT puts("spl: mmc device not found!!\n"); #endif return -1; } err = mmc_init(mmc); if (err) { #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT printf("spl: mmc init failed: err - %d\n", err); #endif return -1; } boot_mode = spl_boot_mode(); if (boot_mode == MMCSD_MODE_RAW) { debug("boot mode - RAW\n"); #ifdef CONFIG_SPL_OS_BOOT if (spl_start_uboot() || mmc_load_image_raw_os(mmc)) #endif err = mmc_load_image_raw(mmc, CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR); #ifdef CONFIG_SPL_FAT_SUPPORT } else if (boot_mode == MMCSD_MODE_FAT) { debug("boot mode - FAT\n"); #ifdef CONFIG_SPL_OS_BOOT if (spl_start_uboot() || spl_load_image_fat_os(&mmc->block_dev, CONFIG_SYS_MMC_SD_FAT_BOOT_PARTITION)) #endif err = spl_load_image_fat(&mmc->block_dev, CONFIG_SYS_MMC_SD_FAT_BOOT_PARTITION, CONFIG_SPL_FAT_LOAD_PAYLOAD_NAME); #endif #ifdef CONFIG_SUPPORT_EMMC_BOOT } else if (boot_mode == MMCSD_MODE_EMMCBOOT) { /* * We need to check what the partition is configured to. * 1 and 2 match up to boot0 / boot1 and 7 is user data * which is the first physical partition (0). */ int part = (mmc->part_config >> 3) & PART_ACCESS_MASK; if (part == 7) part = 0; if (mmc_switch_part(0, part)) { #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT puts("MMC partition switch failed\n"); #endif return -1; } #ifdef CONFIG_SPL_OS_BOOT if (spl_start_uboot() || mmc_load_image_raw_os(mmc)) #endif err = mmc_load_image_raw(mmc, CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR); #endif } else {