123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631 |
- /*
- * Copyright (c) 2016 - 2020, Broadcom
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
- #include <string.h>
- #include <emmc_api.h>
- #include <cmn_plat_util.h>
- #define MAX_CMD_RETRY 10
- #if EMMC_USE_DMA
- #define USE_DMA 1
- #else
- #define USE_DMA 0
- #endif
- struct emmc_global_buffer emmc_global_buf;
- struct emmc_global_buffer *emmc_global_buf_ptr = &emmc_global_buf;
- struct emmc_global_vars emmc_global_vars;
- struct emmc_global_vars *emmc_global_vars_ptr = &emmc_global_vars;
- static struct sd_handle *sdio_gethandle(void);
- static uint32_t sdio_idle(struct sd_handle *p_sdhandle);
- static uint32_t sdio_read(struct sd_handle *p_sdhandle,
- uintptr_t mem_addr,
- uintptr_t storage_addr,
- size_t storage_size,
- size_t bytes_to_read);
- #ifdef INCLUDE_EMMC_DRIVER_WRITE_CODE
- static uint32_t sdio_write(struct sd_handle *p_sdhandle,
- uintptr_t mem_addr,
- uintptr_t data_addr,
- size_t bytes_to_write);
- #endif
- static struct sd_handle *sdio_init(void);
- static int32_t bcm_emmc_card_ready_state(struct sd_handle *p_sdhandle);
- static void init_globals(void)
- {
- memset((void *)emmc_global_buf_ptr, 0, sizeof(*emmc_global_buf_ptr));
- memset((void *)emmc_global_vars_ptr, 0, sizeof(*emmc_global_vars_ptr));
- }
- /*
- * This function is used to change partition
- */
- uint32_t emmc_partition_select(uint32_t partition)
- {
- int rc;
- struct sd_handle *sd_handle = sdio_gethandle();
- if (sd_handle->device == 0) {
- EMMC_TRACE("eMMC init is not done");
- return 0;
- }
- switch (partition) {
- case EMMC_BOOT_PARTITION1:
- rc = set_boot_config(sd_handle,
- SDIO_HW_EMMC_EXT_CSD_BOOT_ACC_BOOT1);
- EMMC_TRACE(
- "Change to Boot Partition 1 result:%d (0 means SD_OK)\n",
- rc);
- break;
- case EMMC_BOOT_PARTITION2:
- rc = set_boot_config(sd_handle,
- SDIO_HW_EMMC_EXT_CSD_BOOT_ACC_BOOT2);
- EMMC_TRACE(
- "Change to Boot Partition 2 result:%d (0 means SD_OK)\n",
- rc);
- break;
- case EMMC_USE_CURRENT_PARTITION:
- rc = SD_OK;
- EMMC_TRACE("Stay on current partition");
- break;
- case EMMC_USER_AREA:
- default:
- rc = set_boot_config(sd_handle,
- SDIO_HW_EMMC_EXT_CSD_BOOT_ACC_USER);
- EMMC_TRACE("Change to User area result:%d (0 means SD_OK)\n",
- rc);
- break;
- }
- return (rc == SD_OK);
- }
- /*
- * Initialize emmc controller for eMMC
- * Returns 0 on fail condition
- */
- uint32_t bcm_emmc_init(bool card_rdy_only)
- {
- struct sd_handle *p_sdhandle;
- uint32_t result = 0;
- EMMC_TRACE("Enter emmc_controller_init()\n");
- /* If eMMC is already initialized, skip init */
- if (emmc_global_vars_ptr->init_done)
- return 1;
- init_globals();
- p_sdhandle = sdio_init();
- if (p_sdhandle == NULL) {
- ERROR("eMMC init failed");
- return result;
- }
- if (card_rdy_only) {
- /* Put the card in Ready state, Not complete init */
- result = bcm_emmc_card_ready_state(p_sdhandle);
- return !result;
- }
- if (sdio_idle(p_sdhandle) == EMMC_BOOT_OK) {
- set_config(p_sdhandle, SD_NORMAL_SPEED, MAX_CMD_RETRY, USE_DMA,
- SD_DMA_BOUNDARY_256K, EMMC_BLOCK_SIZE,
- EMMC_WFE_RETRY);
- if (!select_blk_sz(p_sdhandle,
- p_sdhandle->device->cfg.blockSize)) {
- emmc_global_vars_ptr->init_done = 1;
- result = 1;
- } else {
- ERROR("Select Block Size failed\n");
- }
- } else {
- ERROR("eMMC init failed");
- }
- /* Initialization is failed, so deinit HW setting */
- if (result == 0)
- emmc_deinit();
- return result;
- }
- /*
- * Function to de-init SDIO controller for eMMC
- */
- void emmc_deinit(void)
- {
- emmc_global_vars_ptr->init_done = 0;
- emmc_global_vars_ptr->sdHandle.card = 0;
- emmc_global_vars_ptr->sdHandle.device = 0;
- }
- /*
- * Read eMMC memory
- * Returns read_size
- */
- uint32_t emmc_read(uintptr_t mem_addr, uintptr_t storage_addr,
- size_t storage_size, size_t bytes_to_read)
- {
- struct sd_handle *sd_handle = sdio_gethandle();
- if (sd_handle->device == 0) {
- EMMC_TRACE("eMMC init is not done");
- return 0;
- }
- return sdio_read(sdio_gethandle(), mem_addr, storage_addr,
- storage_size, bytes_to_read);
- }
- #ifdef INCLUDE_EMMC_DRIVER_ERASE_CODE
- #define EXT_CSD_ERASE_GRP_SIZE 224
- static int emmc_block_erase(uintptr_t mem_addr, size_t blocks)
- {
- struct sd_handle *sd_handle = sdio_gethandle();
- if (sd_handle->device == 0) {
- ERROR("eMMC init is not done");
- return -1;
- }
- return erase_card(sdio_gethandle(), mem_addr, blocks);
- }
- int emmc_erase(uintptr_t mem_addr, size_t num_of_blocks, uint32_t partition)
- {
- int err = 0;
- size_t block_count = 0, blocks = 0;
- size_t erase_group = 0;
- erase_group =
- emmc_global_buf_ptr->u.Ext_CSD_storage[EXT_CSD_ERASE_GRP_SIZE]*1024;
- INFO("eMMC Erase Group Size=0x%lx\n", erase_group);
- emmc_partition_select(partition);
- while (block_count < num_of_blocks) {
- blocks = ((num_of_blocks - block_count) > erase_group) ?
- erase_group : (num_of_blocks - block_count);
- err = emmc_block_erase(mem_addr + block_count, blocks);
- if (err)
- break;
- block_count += blocks;
- }
- if (err == 0)
- INFO("eMMC Erase of partition %d successful\n", partition);
- else
- ERROR("eMMC Erase of partition %d Failed(%i)\n", partition, err);
- return err;
- }
- #endif
- #ifdef INCLUDE_EMMC_DRIVER_WRITE_CODE
- /*
- * Write to eMMC memory
- * Returns written_size
- */
- uint32_t emmc_write(uintptr_t mem_addr, uintptr_t data_addr,
- size_t bytes_to_write)
- {
- struct sd_handle *sd_handle = sdio_gethandle();
- if (sd_handle->device == 0) {
- EMMC_TRACE("eMMC init is not done");
- return 0;
- }
- return sdio_write(sd_handle, mem_addr, data_addr, bytes_to_write);
- }
- #endif
- /*
- * Send SDIO Cmd
- * Return 0 for pass condition
- */
- uint32_t send_sdio_cmd(uint32_t cmdIndex, uint32_t argument,
- uint32_t options, struct sd_resp *resp)
- {
- struct sd_handle *sd_handle = sdio_gethandle();
- if (sd_handle->device == 0) {
- EMMC_TRACE("eMMC init is not done");
- return 1;
- }
- return send_cmd(sd_handle, cmdIndex, argument, options, resp);
- }
- /*
- * This function return SDIO handle
- */
- struct sd_handle *sdio_gethandle(void)
- {
- return &emmc_global_vars_ptr->sdHandle;
- }
- /*
- * Initialize SDIO controller
- */
- struct sd_handle *sdio_init(void)
- {
- uint32_t SDIO_base;
- struct sd_handle *p_sdhandle = &emmc_global_vars_ptr->sdHandle;
- SDIO_base = EMMC_CTRL_REGS_BASE_ADDR;
- if (SDIO_base == SDIO0_EMMCSDXC_SYSADDR) {
- EMMC_TRACE(" ---> for SDIO 0 Controller\n\n");
- }
- memset(p_sdhandle, 0, sizeof(struct sd_handle));
- p_sdhandle->device = &emmc_global_vars_ptr->sdDevice;
- p_sdhandle->card = &emmc_global_vars_ptr->sdCard;
- memset(p_sdhandle->device, 0, sizeof(struct sd_dev));
- memset(p_sdhandle->card, 0, sizeof(struct sd_card_info));
- if (chal_sd_start((CHAL_HANDLE *) p_sdhandle->device,
- SD_PIO_MODE, SDIO_base, SDIO_base) != SD_OK) {
- return NULL;
- }
- set_config(p_sdhandle, SD_NORMAL_SPEED, MAX_CMD_RETRY, SD_DMA_OFF,
- SD_DMA_BOUNDARY_4K, EMMC_BLOCK_SIZE, EMMC_WFE_RETRY);
- return &emmc_global_vars_ptr->sdHandle;
- }
- uint32_t sdio_idle(struct sd_handle *p_sdhandle)
- {
- reset_card(p_sdhandle);
- SD_US_DELAY(1000);
- if (init_card(p_sdhandle, SD_CARD_DETECT_MMC) != SD_OK) {
- reset_card(p_sdhandle);
- reset_host_ctrl(p_sdhandle);
- return EMMC_BOOT_NO_CARD;
- }
- return EMMC_BOOT_OK;
- }
- /*
- * This function read eMMC
- */
- uint32_t sdio_read(struct sd_handle *p_sdhandle,
- uintptr_t mem_addr,
- uintptr_t storage_addr,
- size_t storage_size, size_t bytes_to_read)
- {
- uint32_t offset = 0, blockAddr, readLen = 0, rdCount;
- uint32_t remSize, manual_copy_size;
- uint8_t *outputBuf = (uint8_t *) storage_addr;
- const size_t blockSize = p_sdhandle->device->cfg.blockSize;
- VERBOSE("EMMC READ: dst=0x%lx, src=0x%lx, size=0x%lx\n",
- storage_addr, mem_addr, bytes_to_read);
- if (storage_size < bytes_to_read) {
- /* Don't have sufficient storage to complete the operation */
- return 0;
- }
- /* Range check non high capacity memory */
- if ((p_sdhandle->device->ctrl.ocr & SD_CARD_HIGH_CAPACITY) == 0) {
- if (mem_addr > 0x80000000) {
- return 0;
- }
- }
- /* High capacity card use block address mode */
- if (p_sdhandle->device->ctrl.ocr & SD_CARD_HIGH_CAPACITY) {
- blockAddr = (uint32_t) (mem_addr / blockSize);
- offset = (uint32_t) (mem_addr - (blockAddr * blockSize));
- } else {
- blockAddr = (uint32_t) (mem_addr / blockSize) * blockSize;
- offset = (uint32_t) (mem_addr - blockAddr);
- }
- remSize = bytes_to_read;
- rdCount = 0;
- /* Process first unaligned block of MAX_READ_LENGTH */
- if (offset > 0) {
- if (!read_block(p_sdhandle, emmc_global_buf_ptr->u.tempbuf,
- blockAddr, SD_MAX_READ_LENGTH)) {
- if (remSize < (blockSize - offset)) {
- rdCount += remSize;
- manual_copy_size = remSize;
- remSize = 0; /* read is done */
- } else {
- remSize -= (blockSize - offset);
- rdCount += (blockSize - offset);
- manual_copy_size = blockSize - offset;
- }
- /* Check for overflow */
- if (manual_copy_size > storage_size ||
- (((uintptr_t)outputBuf + manual_copy_size) >
- (storage_addr + storage_size))) {
- ERROR("EMMC READ: Overflow 1\n");
- return 0;
- }
- memcpy(outputBuf,
- (void *)((uintptr_t)
- (emmc_global_buf_ptr->u.tempbuf + offset)),
- manual_copy_size);
- /* Update Physical address */
- outputBuf += manual_copy_size;
- if (p_sdhandle->device->ctrl.ocr & SD_CARD_HIGH_CAPACITY) {
- blockAddr++;
- } else {
- blockAddr += blockSize;
- }
- } else {
- return 0;
- }
- }
- while (remSize >= blockSize) {
- if (remSize >= SD_MAX_BLK_TRANSFER_LENGTH) {
- readLen = SD_MAX_BLK_TRANSFER_LENGTH;
- } else {
- readLen = (remSize / blockSize) * blockSize;
- }
- /* Check for overflow */
- if ((rdCount + readLen) > storage_size ||
- (((uintptr_t) outputBuf + readLen) >
- (storage_addr + storage_size))) {
- ERROR("EMMC READ: Overflow\n");
- return 0;
- }
- if (!read_block(p_sdhandle, outputBuf, blockAddr, readLen)) {
- if (p_sdhandle->device->ctrl.ocr & SD_CARD_HIGH_CAPACITY) {
- blockAddr += (readLen / blockSize);
- } else {
- blockAddr += readLen;
- }
- remSize -= readLen;
- rdCount += readLen;
- /* Update Physical address */
- outputBuf += readLen;
- } else {
- return 0;
- }
- }
- /* process the last unaligned block reading */
- if (remSize > 0) {
- if (!read_block(p_sdhandle, emmc_global_buf_ptr->u.tempbuf,
- blockAddr, SD_MAX_READ_LENGTH)) {
- rdCount += remSize;
- /* Check for overflow */
- if (rdCount > storage_size ||
- (((uintptr_t) outputBuf + remSize) >
- (storage_addr + storage_size))) {
- ERROR("EMMC READ: Overflow\n");
- return 0;
- }
- memcpy(outputBuf,
- emmc_global_buf_ptr->u.tempbuf, remSize);
- /* Update Physical address */
- outputBuf += remSize;
- } else {
- rdCount = 0;
- }
- }
- return rdCount;
- }
- #ifdef INCLUDE_EMMC_DRIVER_WRITE_CODE
- static uint32_t sdio_write(struct sd_handle *p_sdhandle, uintptr_t mem_addr,
- uintptr_t data_addr, size_t bytes_to_write)
- {
- uint32_t offset, blockAddr, writeLen, wtCount = 0;
- uint32_t remSize, manual_copy_size = 0;
- uint8_t *inputBuf = (uint8_t *)data_addr;
- /* range check non high capacity memory */
- if ((p_sdhandle->device->ctrl.ocr & SD_CARD_HIGH_CAPACITY) == 0) {
- if (mem_addr > 0x80000000) {
- return 0;
- }
- }
- /* the high capacity card use block address mode */
- if (p_sdhandle->device->ctrl.ocr & SD_CARD_HIGH_CAPACITY) {
- blockAddr =
- (uint32_t)(mem_addr / p_sdhandle->device->cfg.blockSize);
- offset =
- (uint32_t)(mem_addr -
- blockAddr * p_sdhandle->device->cfg.blockSize);
- } else {
- blockAddr =
- ((uint32_t)mem_addr / p_sdhandle->device->cfg.blockSize) *
- p_sdhandle->device->cfg.blockSize;
- offset = (uint32_t) mem_addr - blockAddr;
- }
- remSize = bytes_to_write;
- wtCount = 0;
- /* process first unaligned block */
- if (offset > 0) {
- if (!read_block(p_sdhandle, emmc_global_buf_ptr->u.tempbuf,
- blockAddr, p_sdhandle->device->cfg.blockSize)) {
- if (remSize <
- (p_sdhandle->device->cfg.blockSize - offset)) {
- manual_copy_size = remSize;
- } else {
- manual_copy_size =
- p_sdhandle->device->cfg.blockSize - offset;
- }
- memcpy((void *)((uintptr_t)
- (emmc_global_buf_ptr->u.tempbuf + offset)),
- inputBuf,
- manual_copy_size);
- /* Update Physical address */
- if (!write_block(p_sdhandle,
- emmc_global_buf_ptr->u.tempbuf,
- blockAddr,
- p_sdhandle->device->cfg.blockSize)) {
- if (remSize <
- (p_sdhandle->device->cfg.blockSize -
- offset)) {
- wtCount += remSize;
- manual_copy_size = remSize;
- remSize = 0; /* read is done */
- } else {
- remSize -=
- (p_sdhandle->device->cfg.blockSize -
- offset);
- wtCount +=
- (p_sdhandle->device->cfg.blockSize -
- offset);
- manual_copy_size =
- p_sdhandle->device->cfg.blockSize -
- offset;
- }
- inputBuf += manual_copy_size;
- if (p_sdhandle->device->ctrl.ocr &
- SD_CARD_HIGH_CAPACITY) {
- blockAddr++;
- } else {
- blockAddr +=
- p_sdhandle->device->cfg.blockSize;
- }
- } else
- return 0;
- } else {
- return 0;
- }
- }
- /* process block writing */
- while (remSize >= p_sdhandle->device->cfg.blockSize) {
- if (remSize >= SD_MAX_READ_LENGTH) {
- writeLen = SD_MAX_READ_LENGTH;
- } else {
- writeLen =
- (remSize / p_sdhandle->device->cfg.blockSize) *
- p_sdhandle->device->cfg.blockSize;
- }
- if (!write_block(p_sdhandle, inputBuf, blockAddr, writeLen)) {
- if (p_sdhandle->device->ctrl.ocr & SD_CARD_HIGH_CAPACITY)
- blockAddr +=
- (writeLen /
- p_sdhandle->device->cfg.blockSize);
- else
- blockAddr += writeLen;
- remSize -= writeLen;
- wtCount += writeLen;
- inputBuf += writeLen;
- } else {
- return 0;
- }
- }
- /* process the last unaligned block reading */
- if (remSize > 0) {
- if (!read_block(p_sdhandle,
- emmc_global_buf_ptr->u.tempbuf,
- blockAddr, p_sdhandle->device->cfg.blockSize)) {
- memcpy(emmc_global_buf_ptr->u.tempbuf,
- inputBuf, remSize);
- /* Update Physical address */
- if (!write_block(p_sdhandle,
- emmc_global_buf_ptr->u.tempbuf,
- blockAddr,
- p_sdhandle->device->cfg.blockSize)) {
- wtCount += remSize;
- inputBuf += remSize;
- } else {
- return 0;
- }
- } else {
- wtCount = 0;
- }
- }
- return wtCount;
- }
- #endif
- /*
- * Function to put the card in Ready state by sending CMD0 and CMD1
- */
- static int32_t bcm_emmc_card_ready_state(struct sd_handle *p_sdhandle)
- {
- int32_t result = 0;
- uint32_t argument = MMC_CMD_IDLE_RESET_ARG; /* Exit from Boot mode */
- if (p_sdhandle) {
- send_sdio_cmd(SD_CMD_GO_IDLE_STATE, argument, 0, NULL);
- result = reset_card(p_sdhandle);
- if (result != SD_OK) {
- EMMC_TRACE("eMMC Reset error\n");
- return SD_RESET_ERROR;
- }
- SD_US_DELAY(2000);
- result = mmc_cmd1(p_sdhandle);
- }
- return result;
- }
|