/* * Function: mmc device sleep * Arg : None * Return : Clean up function for storage * Flow : Put the mmc card to sleep */ void mmc_device_sleep() { void *dev; dev = target_mmc_device(); if (target_mmc_device()) { mmc_put_card_to_sleep((struct mmc_device *)dev); } }
int ufs_get_boot_lun() { int ret = 0; void *dev; dev = target_mmc_device(); if (!(target_mmc_device())) ret = dme_get_bbootlunen((struct ufs_dev *)dev); return ret; }
int ufs_set_boot_lun(uint32_t boot_lun_id) { int ret = 0; void *dev; dev = target_mmc_device(); if (!(target_mmc_device())) ret = dme_set_bbootlunen((struct ufs_dev *)dev, boot_lun_id); return ret; }
/* * Function : mmc get LUN from ufs * Arg : LUN number * Return type : lun number for UFS and 0 for emmc */ uint8_t mmc_get_lun(void) { void *dev; uint8_t lun=0; dev = target_mmc_device(); if (!target_mmc_device()) { lun = ((struct ufs_dev*)dev)->current_lun; } return lun; }
/* * Function: storage page size * Arg : None * Return : Returns the page size for the card * Flow : Get the page size for storage */ uint32_t mmc_page_size() { if (target_mmc_device()) { return BOARD_KERNEL_PAGESIZE; } else { void *dev; dev = target_mmc_device(); return ufs_get_page_size((struct ufs_dev *)dev); } }
int rpmb_init() { int ret = 0; dev = target_mmc_device(); /* 1. Initialize storage specific data */ if (platform_boot_dev_isemmc()) { struct mmc_device *mmc_dev = (struct mmc_device *) dev; info.size = mmc_dev->card.rpmb_size / RPMB_MIN_BLK_SZ; info.rel_wr_count = mmc_dev->card.rel_wr_count; info.dev_type = EMMC_RPMB; } else { struct ufs_dev *ufs_dev = (struct ufs_dev *) dev; ufs_rpmb_init(ufs_dev); info.size = ufs_dev->rpmb_num_blocks; info.rel_wr_count = ufs_dev->rpmb_rw_size; info.dev_type = UFS_RPMB; } /* Register & start the listener */ ret = rpmb_listener_start(); if (ret < 0) { dprintf(CRITICAL, "Error registering the handler\n"); goto err; } err: return ret; }
void platform_boot_dev_cmdline(char *buf) { uint32_t val = 0; void *dev; dev = target_mmc_device(); val = platform_get_boot_dev(); switch(val) { case BOOT_DEFAULT: case BOOT_EMMC: sprintf(buf, "%x.sdhci", ((struct mmc_device *)dev)->host.base); break; case BOOT_UFS: sprintf(buf, "%x.ufshc", ((struct ufs_dev *)dev)->base); break; case BOOT_NAND: sprintf(buf, "%x.nandc", nand_device_base()); break; default: dprintf(CRITICAL,"ERROR: Unexpected boot_device val=%x",val); ASSERT(0); }; }
/* * Function: get mmc card * Arg : None * Return : Pointer to mmc card structure * Flow : Get the card pointer from the device structure */ static struct mmc_card *get_mmc_card() { struct mmc_device *dev; struct mmc_card *card; dev = target_mmc_device(); card = &dev->card; return card; }
/* * Function: mmc get psn * Arg : None * Return : Returns the product serial number * Flow : Get the PSN from card */ uint32_t mmc_get_psn(void) { if (target_mmc_device()) { struct mmc_card *card; card = get_mmc_card(); return card->cid.psn; } else { void *dev; dev = target_mmc_device(); return ufs_get_serial_num((struct ufs_dev *)dev); } }
/* * Function: mmc get capacity * Arg : None * Return : Returns the density of the emmc card * Flow : Get the density from card */ uint64_t mmc_get_device_capacity() { if (target_mmc_device()) { struct mmc_card *card; card = get_mmc_card(); return card->capacity; } else { void *dev; dev = target_mmc_device(); return ufs_get_dev_capacity((struct ufs_dev *)dev); } }
/* * Function: mmc get blocksize * Arg : None * Return : Returns the block size of the storage * Flow : Get the block size form the card */ uint32_t mmc_get_device_blocksize() { if (target_mmc_device()) { struct mmc_card *card; card = get_mmc_card(); return card->block_size; } else { void *dev; dev = target_mmc_device(); return ufs_get_page_size((struct ufs_dev *)dev); } }
/* * Function: get mmc card * Arg : None * Return : Pointer to mmc card structure * Flow : Get the card pointer from the device structure */ static struct mmc_card *get_mmc_card() { void *dev; struct mmc_card *card; dev = target_mmc_device(); card = &((struct mmc_device*)dev)->card; return card; }
/* * Function: mmc erase card * Arg : Block address & length * Return : Returns 0 * Flow : Erase the card from specified addr */ uint32_t mmc_erase_card(uint64_t addr, uint64_t len) { struct mmc_device *dev; dev = target_mmc_device(); ASSERT(!(addr % MMC_BLK_SZ)); ASSERT(!(len % MMC_BLK_SZ)); if (mmc_sdhci_erase(dev, (addr / MMC_BLK_SZ), len)) { dprintf(CRITICAL, "MMC erase failed\n"); return 1; } return 0; }
/* * Function: mmc_write * Arg : Data address on card, data length, i/p buffer * Return : 0 on Success, non zero on failure * Flow : Write the data from in to the card */ uint32_t mmc_write(uint64_t data_addr, uint32_t data_len, void *in) { uint32_t val = 0; uint32_t write_size = SDHCI_ADMA_MAX_TRANS_SZ; uint8_t *sptr = (uint8_t *)in; struct mmc_device *dev; dev = target_mmc_device(); ASSERT(!(data_addr % MMC_BLK_SZ)); if (data_len % MMC_BLK_SZ) data_len = ROUNDUP(data_len, MMC_BLK_SZ); /* TODO: This function is aware of max data that can be * tranferred using sdhci adma mode, need to have a cleaner * implementation to keep this function independent of sdhci * limitations */ while (data_len > write_size) { val = mmc_sdhci_write(dev, (void *)sptr, (data_addr / MMC_BLK_SZ), (write_size / MMC_BLK_SZ)); if (val) { dprintf(CRITICAL, "Failed Writing block @ %x\n", (data_addr / MMC_BLK_SZ)); return val; } sptr += write_size; data_addr += write_size; data_len -= write_size; } if (data_len) val = mmc_sdhci_write(dev, (void *)sptr, (data_addr / MMC_BLK_SZ), (data_len / MMC_BLK_SZ)); if (val) dprintf(CRITICAL, "Failed Writing block @ %x\n", (data_addr / MMC_BLK_SZ)); return val; }
/* * Function: mmc_read * Arg : Data address on card, o/p buffer & data length * Return : 0 on Success, non zero on failure * Flow : Read data from the card to out */ uint32_t mmc_read(uint64_t data_addr, uint32_t *out, uint32_t data_len) { uint32_t ret = 0; uint32_t read_size = SDHCI_ADMA_MAX_TRANS_SZ; struct mmc_device *dev; uint8_t *sptr = (uint8_t *)out; ASSERT(!(data_addr % MMC_BLK_SZ)); ASSERT(!(data_len % MMC_BLK_SZ)); dev = target_mmc_device(); /* TODO: This function is aware of max data that can be * tranferred using sdhci adma mode, need to have a cleaner * implementation to keep this function independent of sdhci * limitations */ while (data_len > read_size) { ret = mmc_sdhci_read(dev, (void *)sptr, (data_addr / MMC_BLK_SZ), (read_size / MMC_BLK_SZ)); if (ret) { dprintf(CRITICAL, "Failed Reading block @ %x\n", (data_addr / MMC_BLK_SZ)); return ret; } sptr += read_size; data_addr += read_size; data_len -= read_size; } if (data_len) ret = mmc_sdhci_read(dev, (void *)sptr, (data_addr / MMC_BLK_SZ), (data_len / MMC_BLK_SZ)); if (ret) dprintf(CRITICAL, "Failed Reading block @ %x\n", (data_addr / MMC_BLK_SZ)); return ret; }
void platform_boot_dev_cmdline(char *buf) { uint32_t val = 0; void *dev = target_mmc_device(); val = platform_get_boot_dev(); switch(val) { #if !USE_MDM_BOOT_CFG case BOOT_DEFAULT: snprintf(buf, ((sizeof((struct mmc_device *)dev)->host.base)*2) + 7,"%x.sdhci", ((struct mmc_device *)dev)->host.base); break; case BOOT_UFS: snprintf(buf, ((sizeof((struct ufs_dev *)dev)->base)*2) + 7, "%x.ufshc", ((struct ufs_dev *)dev)->base); break; #endif case BOOT_EMMC: snprintf(buf, ((sizeof((struct mmc_device *)dev)->host.base)*2) + 7,"%x.sdhci", ((struct mmc_device *)dev)->host.base); break; default: dprintf(CRITICAL,"ERROR: Unexpected boot_device val=%x",val); ASSERT(0); }; }
uint32_t mmc_write_protect(const char *ptn_name, int set_clr) { void *dev = NULL; struct mmc_card *card = NULL; uint32_t block_size; unsigned long long ptn = 0; uint64_t size; int index = -1; #ifdef UFS_SUPPORT int ret = 0; #endif dev = target_mmc_device(); block_size = mmc_get_device_blocksize(); if (target_mmc_device()) { card = &((struct mmc_device *)dev)->card; index = partition_get_index(ptn_name); ptn = partition_get_offset(index); if(!ptn) { return 1; } /* Convert the size to blocks */ size = partition_get_size(index) / block_size; /* * For read only partitions the minimum size allocated on the disk is * 1 WP GRP size. If the size of partition is less than 1 WP GRP size * protect atleast one WP group. */ if (partition_read_only(index) && size < card->wp_grp_size) { /* Write protect api takes the size in bytes, convert size to bytes */ size = card->wp_grp_size * block_size; } else { size *= block_size; } /* Set the power on WP bit */ return mmc_set_clr_power_on_wp_user((struct mmc_device *)dev, (ptn / block_size), size, set_clr); } else { #ifdef UFS_SUPPORT /* Enable the power on WP fo all LUNs which have WP bit is enabled */ ret = dme_set_fpoweronwpen((struct ufs_dev*) dev); if (ret < 0) { dprintf(CRITICAL, "Failure to WP UFS partition\n"); return 1; } #endif } return 0; }
int rpmb_init() { int ret = 0; dev = target_mmc_device(); /* 1. Initialize storage specific data */ if (platform_boot_dev_isemmc()) { struct mmc_device *mmc_dev = (struct mmc_device *) dev; info.size = mmc_dev->card.rpmb_size / RPMB_MIN_BLK_SZ; if (mmc_dev->card.ext_csd[MMC_EXT_CSD_REV] < 8) { //as per emmc spec rel_wr_count should be 1 for emmc version < 5.1 dprintf(SPEW, "EMMC Version < 5.1\n"); info.rel_wr_count = 1; } else { if (mmc_dev->card.ext_csd[MMC_EXT_CSD_EN_RPMB_REL_WR] == 0) { dprintf(SPEW, "EMMC Version >= 5.1 EN_RPMB_REL_WR = 0\n"); // according to emmc version 5.1 and above if EN_RPMB_REL_WR in extended // csd is not set the maximum number of frames that can be reliably written // to emmc would be 2 info.rel_wr_count = 2; } else { dprintf(SPEW, "EMMC Version >= 5.1 EN_RPMB_REL_WR = 1\n"); // according to emmc version 5.1 and above if EN_RPMB_REL_WR in extended // csd is set the maximum number of frames that can be reliably written // to emmc would be 32 info.rel_wr_count = 32; } } /* * tz changes required for supporting * multiple frames are not present * force the number of frames to be minimum * i.e. one for tz 3.0 and earlier. */ if( qseecom_get_version() < QSEE_VERSION_40 ) info.rel_wr_count = 1; info.dev_type = EMMC_RPMB; } #ifdef UFS_SUPPORT else { struct ufs_dev *ufs_dev = (struct ufs_dev *) dev; ufs_rpmb_init(ufs_dev); info.size = ufs_dev->rpmb_num_blocks; info.rel_wr_count = ufs_dev->rpmb_rw_size; info.dev_type = UFS_RPMB; } #endif /* Register & start the listener */ ret = rpmb_listener_start(); if (ret < 0) { dprintf(CRITICAL, "Error registering the handler\n"); goto err; } err: return ret; }
/* * Function: mmc_write * Arg : Data address on card, data length, i/p buffer * Return : 0 on Success, non zero on failure * Flow : Write the data from in to the card */ uint32_t mmc_write(uint64_t data_addr, uint32_t data_len, void *in) { uint32_t val = 0; int ret = 0; uint32_t block_size = 0; uint32_t write_size = SDHCI_ADMA_MAX_TRANS_SZ; uint8_t *sptr = (uint8_t *)in; void *dev; dev = target_mmc_device(); block_size = mmc_get_device_blocksize(); ASSERT(!(data_addr % block_size)); if (data_len % block_size) data_len = ROUNDUP(data_len, block_size); /* * Flush the cache before handing over the data to * storage driver */ arch_clean_invalidate_cache_range((addr_t)in, data_len); if (target_mmc_device()) { /* TODO: This function is aware of max data that can be * tranferred using sdhci adma mode, need to have a cleaner * implementation to keep this function independent of sdhci * limitations */ while (data_len > write_size) { val = mmc_sdhci_write((struct mmc_device *)dev, (void *)sptr, (data_addr / block_size), (write_size / block_size)); if (val) { dprintf(CRITICAL, "Failed Writing block @ %x\n",(unsigned int)(data_addr / block_size)); return val; } sptr += write_size; data_addr += write_size; data_len -= write_size; } if (data_len) val = mmc_sdhci_write((struct mmc_device *)dev, (void *)sptr, (data_addr / block_size), (data_len / block_size)); if (val) dprintf(CRITICAL, "Failed Writing block @ %x\n",(unsigned int)(data_addr / block_size)); } else { ret = ufs_write((struct ufs_dev *)dev, data_addr, (addr_t)in, (data_len / block_size)); if (ret) { dprintf(CRITICAL, "Error: UFS write failed writing to block: %llu\n", data_addr); val = 1; } } return val; }
/* * Function: mmc erase card * Arg : Block address & length * Return : Returns 0 * Flow : Erase the card from specified addr */ uint32_t mmc_erase_card(uint64_t addr, uint64_t len) { struct mmc_device *dev; uint32_t block_size; uint32_t unaligned_blks; uint32_t head_unit; uint32_t tail_unit; uint32_t erase_unit_sz; uint32_t blk_addr; uint32_t blk_count; uint64_t blks_to_erase; block_size = mmc_get_device_blocksize(); dev = target_mmc_device(); ASSERT(!(addr % block_size)); ASSERT(!(len % block_size)); if (target_mmc_device()) { erase_unit_sz = mmc_get_eraseunit_size(); dprintf(SPEW, "erase_unit_sz:0x%x\n", erase_unit_sz); blk_addr = addr / block_size; blk_count = len / block_size; dprintf(INFO, "Erasing card: 0x%x:0x%x\n", blk_addr, blk_count); head_unit = blk_addr / erase_unit_sz; tail_unit = (blk_addr + blk_count - 1) / erase_unit_sz; if (tail_unit - head_unit <= 1) { dprintf(INFO, "SDHCI unit erase not required\n"); return mmc_zero_out(dev, blk_addr, blk_count); } unaligned_blks = erase_unit_sz - (blk_addr % erase_unit_sz); if (unaligned_blks < erase_unit_sz) { dprintf(SPEW, "Handling unaligned head blocks\n"); if (mmc_zero_out(dev, blk_addr, unaligned_blks)) return 1; blk_addr += unaligned_blks; blk_count -= unaligned_blks; head_unit = blk_addr / erase_unit_sz; tail_unit = (blk_addr + blk_count - 1) / erase_unit_sz; if (tail_unit - head_unit <= 1) { dprintf(INFO, "SDHCI unit erase not required\n"); return mmc_zero_out(dev, blk_addr, blk_count); } } unaligned_blks = blk_count % erase_unit_sz; blks_to_erase = blk_count - unaligned_blks; dprintf(SPEW, "Performing SDHCI erase: 0x%x:0x%x\n", blk_addr,(unsigned int)blks_to_erase); if (mmc_sdhci_erase((struct mmc_device *)dev, blk_addr, blks_to_erase * block_size)) { dprintf(CRITICAL, "MMC erase failed\n"); return 1; } blk_addr += blks_to_erase; if (unaligned_blks) { dprintf(SPEW, "Handling unaligned tail blocks\n"); if (mmc_zero_out(dev, blk_addr, unaligned_blks)) return 1; } } else { if(ufs_erase((struct ufs_dev *)dev, addr, (len / block_size))) { dprintf(CRITICAL, "mmc_erase_card: UFS erase failed\n"); return 1; } } return 0; }