mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-17 18:14:24 +00:00

On release builds EMMC_TRACE doesn't expand to anything. Some conditionals with no braces end up with empty bodies. This produces a warning when compiling with -Werror=empty-body (enabled by -Wextra). Since TF-A coding guidelines require braces to comply with MISRA guidelines anyway, add them in the whole file. Signed-off-by: Boyan Karatotev <boyan.karatotev@arm.com> Change-Id: Ib4e691efc7acdb8fb8692278c7a9772fc894f77f
631 lines
14 KiB
C
631 lines
14 KiB
C
/*
|
|
* 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;
|
|
}
|