This commit is contained in:
2025-12-24 17:21:08 +09:00
parent a96323de19
commit 96dc62d8dc
2302 changed files with 455822 additions and 0 deletions

View File

@@ -0,0 +1,249 @@
/*******************************************************************************
* DISCLAIMER
* This software is supplied by Renesas Electronics Corporation and is only
* intended for use with Renesas products. No other uses are authorized. This
* software is owned by Renesas Electronics Corporation and is protected under
* all applicable laws, including copyright laws.
* THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING
* THIS SOFTWARE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT
* LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* AND NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED.
* TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY LAW, NEITHER RENESAS
* ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE
* FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR
* ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR ITS AFFILIATES HAVE
* BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
* Renesas reserves the right, without notice, to make changes to this software
* and to discontinue the availability of this software. By using this software,
* you agree to the additional terms and conditions found by accessing the
* following link:
* http://www.renesas.com/disclaimer
* Copyright 2021-2024 Renesas Electronics Corporation All rights reserved.
*******************************************************************************/
/*******************************************************************************
* DESCRIPTION : eMMC boot
******************************************************************************/
/******************************************************************************
* @file emmc_boot.c
* - Version : 0.07
* @brief eMMC initialze interface.
* .
*****************************************************************************/
/******************************************************************************
* History : DD.MM.YYYY Version Description
* : 30.09.2021 0.01 First Release
* : 22.10.2021 0.02 Remove unnecessary code
* : 22.12.2021 0.03 Support static analysis
* : 06.01.2022 0.04 Add WWDT timer reset function
* : 06.04.2022 0.05 Fix Set SDCLK to 200MHz
* : 23.05.2022 0.06 Integration of S4 and V4H
* : 24.06.2024 0.07 Add process that set SDHI_D1.8/3.3V to 1.8V.
*****************************************************************************/
#include "emmc_boot.h"
#include "mem_io.h"
#include "log.h"
#include "rom_api.h"
#include "image_load_emmc.h"
#include "emmc_hal.h"
#include "emmc_std.h"
#include "emmc_multiboot.h"
#include "emmc_def.h"
#include "emmc_config.h"
#if (RCAR_LSI == RCAR_V4M) /* Gray Hawk */
#include "i2c.h"
#include "remap.h"
#endif /* (RCAR_LSI == RCAR_V4M) */
/************************************************************************************************/
/* Definitions */
/************************************************************************************************/
/************************************************************************************************/
/* Unions */
/************************************************************************************************/
/************************************************************************************************/
/* Structs */
/************************************************************************************************/
/************************************************************************************************/
/* Globals */
/************************************************************************************************/
/************************************************************************************************/
/* Macros */
/************************************************************************************************/
/************************************************************************************************/
/* Prototypes */
/************************************************************************************************/
static void power_on_mmc(void);
static void set_sd_clock(void);
static void init_mmc_pin_function(void);
#if (RCAR_LSI == RCAR_V4M) /* Gray Hawk */
static void sdhi_random_address_read_pmic(uint32_t sl_add, uint32_t access_add, uint32_t *rd_buf);
static void sdhi_page_write_pmic(uint32_t sl_add, uint32_t access_add, uint32_t *wr_buf);
static void pmic_set_sdhi_vdd18(void);
#endif /* (RCAR_LSI == RCAR_V4M) */
void emmc_initialize( void )
{
#if (RCAR_LSI == RCAR_V4M) /* Gray Hawk */
/* Register I2C base address(physical:0xE6600000) to SIC REMAP14 for V4M. */
set_sicremap_fcpr();
pmic_set_sdhi_vdd18();
#endif /* (RCAR_LSI == RCAR_V4M) */
/*****************************************************************
PFC setting
*****************************************************************/
init_mmc_pin_function();
/*****************************************************************
CPG setting
*****************************************************************/
power_on_mmc();
set_sd_clock();
#if (RCAR_SA9_TYPE == EMMC_BOOT)
EMMC_ERROR_CODE result;
/* eMMC driver initialize */
(void)emmc_init(); /* Normal clock mode */
/* Card power on */
(void)emmc_memcard_power(TRUE);
/* Card mount */
result = emmc_mount();
if (result != EMMC_SUCCESS)
{
NOTICE("eMMC initialize error!!\n");
panic;
}
#endif /* (RCAR_SA9_TYPE == EMMC_BOOT) */
} /* End of function emmc_initialize( void ) */
/************************************************************************************************/
/* Func power_on_mmc */
/************************************************************************************************/
static void power_on_mmc(void)
{
uint32_t reg;
uint32_t tmp_val;
tmp_val = CPG_MSTPCR_SDHI;
reg = mem_read32(CPG_MSTPCR7D0);
if ((reg & tmp_val) != 0x0U)
{
reg &= ~(tmp_val);
cpg_reg_write(CPG_MSTPCR7D0, CPG_MSTPSR7D0, reg);
}
do
{
reg = mem_read32(CPG_MSTPCR7D0);
}
while ((reg & tmp_val) != 0x0U); /* wait tmp_val=0 */
} /* End of function power_on_mmc(void) */
/************************************************************************************************/
/* Func set_sd_clock */
/************************************************************************************************/
static void set_sd_clock(void)
{
uint32_t reg;
reg = mem_read32(CPG_SD0CKCR0);
reg &= (~(CPG_SD0CKCR0_STP0HCK | CPG_SD0CKCR0_SDSRCFC_MASK | CPG_SD0CKCR0_SD0FC_MASK));
reg |= CPG_SD0CKCR0_200MHZ;
cpg_reg_write(CPG_SD0CKCR0, CPG_SD0CKCR0, reg); /* Stop SDnH clock & SDn=200MHz */
} /* End of function set_sd_clock(void) */
/************************************************************************************************/
/* Func init_mmc_pin_function */
/************************************************************************************************/
static void init_mmc_pin_function(void)
{
uint32_t reg;
reg = mem_read32(PFC_POC_MMC_RW);
reg &= (~(PFC_POC_MMC_MASK));
reg |= PFC_POC_MMC_VAL;
pfc_reg_write(PFC_POC_MMC_RW, reg);
} /* End of function init_mmc_pin_function(void) */
#if (RCAR_LSI == RCAR_V4M) /* Gray Hawk */
static void sdhi_random_address_read_pmic(uint32_t sl_add, uint32_t access_add, uint32_t *rd_buf)
{
uint32_t data;
/* for PMIC_RAA271005 */
data = (access_add & 0x300U) >> 8U;
i2c3_write(sl_add, 0x00U, data); /* Bank Set */
i2c3_read(sl_add, (access_add & 0x0FFU), rd_buf);
}
/* End of function sdhi_random_address_read_pmic(uint32_t sl_add, uint32_t access_add, uint32_t *rd_buf) */
static void sdhi_page_write_pmic(uint32_t sl_add, uint32_t access_add, uint32_t *wr_buf)
{
uint32_t data;
/* for PMIC_RAA271005 */
data = (access_add & 0x300U) >> 8U;
i2c3_write(sl_add, 0x00U, data); /* Bank Set */
i2c3_read(sl_add, (access_add & 0x0FFU), wr_buf);
}
/* End of function sdhi_page_write_pmic(uint32_t sl_add, uint32_t access_add, uint32_t *wr_buf) */
static void pmic_set_sdhi_vdd18(void)
{
/* In case of Gray Hawk board, change SDHI_18/33 voltage. */
uint32_t slv_addr = 0xA8U; /* for PMIC-RAA271005: "reg 0xA8 0xA9 prot 0xAA 0xAB" */
uint32_t data;
/* Init I2C */
i2c3_init();
/* Setting 1.8V to SDHI_D1.8/3.3V(VDDQ18_33_SDHI) on PMIC-RAA271005 */
data = 0x1U;
i2c3_write(slv_addr, 0x00U, data); /* Write IO_PAGE. Chenge BANK1 */
i2c3_read(slv_addr, 0x3BU, &data);
if ((data & 0x0CU) != 0x0U)
{
data &= ~(0x0CU);
i2c3_write(slv_addr, 0x3BU, data);
}
sdhi_random_address_read_pmic(slv_addr, 0x02U, &data);
if ((data & 0xF0U) == 0xB0U)
{
// RAA271005 rev.B only
data = 0x1U;
sdhi_page_write_pmic(slv_addr, 0x00U, &data); /* Write IO_PAGE. Chenge BANK1 */
sdhi_random_address_read_pmic(slv_addr, 0x3BU, &data); /* Read FLT_CTRL1 */
data &= 0xF3U; /* LDO1 Fault remove */
sdhi_page_write_pmic(slv_addr, 0x3BU, &data); /* Write FLT_CTRL1 */
data = 0x0U;
sdhi_page_write_pmic(slv_addr, 0x00U, &data); /* Write IO_PAGE. Chenge BANK0 */
}
data = 0x75U; /* LDO voltage 1.8V Value */
i2c3_write(slv_addr, 0xBAU, data);
sdhi_random_address_read_pmic(slv_addr, 0xBAU, &data);
}
/* End of function pmic_set_sdhi_vdd18(void) */
#endif /* (RCAR_LSI == RCAR_V4M) */

View File

@@ -0,0 +1,580 @@
/*******************************************************************************
* DISCLAIMER
* This software is supplied by Renesas Electronics Corporation and is only
* intended for use with Renesas products. No other uses are authorized. This
* software is owned by Renesas Electronics Corporation and is protected under
* all applicable laws, including copyright laws.
* THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING
* THIS SOFTWARE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT
* LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* AND NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED.
* TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY LAW, NEITHER RENESAS
* ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE
* FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR
* ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR ITS AFFILIATES HAVE
* BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
* Renesas reserves the right, without notice, to make changes to this software
* and to discontinue the availability of this software. By using this software,
* you agree to the additional terms and conditions found by accessing the
* following link:
* http://www.renesas.com/disclaimer
* Copyright 2021-2022 Renesas Electronics Corporation All rights reserved.
*******************************************************************************/
/*******************************************************************************
* DESCRIPTION : eMMC CMD driver
******************************************************************************/
/******************************************************************************
* @file emmc_cmd.c
* - Version : 0.04
* @brief control of CMD in SDHI.
* .
*****************************************************************************/
/******************************************************************************
* History : DD.MM.YYYY Version Description
* : 22.02.2022 0.01 First Release
* : 22.10.2021 0.02 Remove unnecessary code
* : 22.12.2021 0.03 Support static analysis
* : 06.01.2022 0.04 Modify SDHI access from DMA to PIO.
*****************************************************************************/
#include "emmc_config.h"
#include "emmc_hal.h"
#include "emmc_std.h"
#include "emmc_registers.h"
#include "emmc_def.h"
#include "micro_wait.h"
#include "log.h"
/* ***************** MACROS, CONSTANTS, COMPILATION FLAGS ****************** */
/* ********************** STRUCTURES, TYPE DEFINITIONS ********************* */
/* ********************** DECLARATION OF EXTERNAL DATA ********************* */
/* ************************** FUNCTION PROTOTYPES ************************** */
static void emmc_read_response(uint32_t *response);
static void emmc_little_to_big(uint8_t *p, uint32_t value);
static void emmc_data_transfer_dma(void);
static EMMC_ERROR_CODE emmc_response_check(const uint32_t *response, uint32_t error_mask);
static void emmc_softreset(void);
static void emmc_WaitCmd2Cmd_8Cycle(void);
/* ********************************* CODE ********************************** */
/* execute MMC command.
*
* - Pre-conditions:<BR>
* * Clock to memory card IF is enabled.
* - Post-conditions:<BR>
* Requested command is executed successfully
*
* param[in] error_mask Errors to be checked (error values; HAL_MEMCARD_ERRORS)
* param[in,out] *response Response from the card (virtual address)
* return eMMC error code.
*/
EMMC_ERROR_CODE emmc_exec_cmd(uint32_t error_mask, uint32_t *response)
{
EMMC_ERROR_CODE rtn_code = EMMC_ERR;
HAL_MEMCARD_RESPONSE_TYPE response_type;
HAL_MEMCARD_COMMAND_TYPE cmd_type;
EMMC_INT_STATE state;
/* parameter check */
if (response == NULL) {
ERROR("%s:0x%08x\n",__func__,EMMC_ERR_PARAM);
return EMMC_ERR_PARAM;
}
/* state check */
if (mmc_drv_obj.clock_enable != TRUE) {
ERROR("%s:0x%08x\n",__func__,EMMC_ERR_STATE);
return EMMC_ERR_STATE;
}
if (mmc_drv_obj.state_machine_blocking == TRUE) {
ERROR("%s:0x%08x\n",__func__,EMMC_ERR);
return EMMC_ERR;
}
state = ESTATE_BEGIN;
response_type = (HAL_MEMCARD_RESPONSE_TYPE)(uintptr_t)((uint32_t)(mmc_drv_obj.cmd_info.cmd) & (uint32_t)HAL_MEMCARD_RESPONSE_TYPE_MASK);
cmd_type = (HAL_MEMCARD_COMMAND_TYPE)(uintptr_t)((uint32_t)(mmc_drv_obj.cmd_info.cmd) & (uint32_t)HAL_MEMCARD_COMMAND_TYPE_MASK);
/* state machine */
while ((mmc_drv_obj.force_terminate != TRUE) && (state != ESTATE_END)) {
/* The interrupt factor flag is observed. */
(void)emmc_interrupt();
/* wait interrupt */
if (mmc_drv_obj.state_machine_blocking == TRUE) {
continue;
}
switch (state) {
case ESTATE_BEGIN:
/* Busy check */
if ((mmc_drv_obj.error_info.info2 & SD_INFO2_CBSY) != 0U) {
ERROR("%s:0x%08x\n",__func__,EMMC_ERR_CARD_BUSY);
return EMMC_ERR_CARD_BUSY;
}
/* clear register */
mem_write32(SD_INFO1, 0x00000000U);
mem_write32(SD_INFO2, SD_INFO2_CLEAR);
mem_write32(SD_INFO1_MASK, SD_INFO1_INFO0);
mem_write32(SD_INFO2_MASK, ( SD_INFO2_ALL_ERR | SD_INFO2_CLEAR ));
/* fallthrough */
case ESTATE_ISSUE_CMD:
/* ARG */
mem_write32(SD_ARG, mmc_drv_obj.cmd_info.arg);
/* issue cmd */
mem_write32(SD_CMD, mmc_drv_obj.cmd_info.hw);
/* Set driver flag */
mmc_drv_obj.state_machine_blocking = TRUE;
if (response_type == HAL_MEMCARD_RESPONSE_NONE) {
state = ESTATE_NON_RESP_CMD;
} else {
state = ESTATE_RCV_RESP;
}
break;
case ESTATE_NON_RESP_CMD:
/* interrupt disable */
mem_write32(SD_INFO1_MASK, 0x00000000U);
mem_write32(SD_INFO2_MASK, SD_INFO2_CLEAR);
/* check interrupt */
if ((mmc_drv_obj.int_event2 & SD_INFO2_ALL_ERR) != 0U) {
/* error interrupt */
rtn_code = EMMC_ERR_INFO2;
state = ESTATE_ERROR;
} else if ((mmc_drv_obj.int_event1 & SD_INFO1_INFO0) == 0U) {
/* not receive expected interrupt */
rtn_code = EMMC_ERR_RESPONSE;
state = ESTATE_ERROR;
} else {
emmc_WaitCmd2Cmd_8Cycle();
state = ESTATE_END;
}
break;
case ESTATE_RCV_RESP:
/* interrupt disable */
mem_write32(SD_INFO1_MASK, 0x00000000U);
mem_write32(SD_INFO2_MASK, SD_INFO2_CLEAR);
/* check interrupt */
if ((mmc_drv_obj.int_event2 & SD_INFO2_ALL_ERR) != 0U) {
/* error interrupt */
rtn_code = EMMC_ERR_INFO2;
state = ESTATE_ERROR;
break;
} else if ((mmc_drv_obj.int_event1 & SD_INFO1_INFO0) == 0U) {
/* not receive expected interrupt */
rtn_code = EMMC_ERR_RESPONSE;
state = ESTATE_ERROR;
break;
} else {
/* nop */
}
/* read response */
emmc_read_response(response);
/* check response */
rtn_code = emmc_response_check(response, error_mask);
if (rtn_code != EMMC_SUCCESS) {
state = ESTATE_ERROR;
break;
}
if (response_type == HAL_MEMCARD_RESPONSE_R1b) {
/* R1b */
mem_write32(SD_INFO2_MASK, ( SD_INFO2_ALL_ERR | SD_INFO2_CLEAR ));
state = ESTATE_RCV_RESPONSE_BUSY;
} else {
state = ESTATE_CHECK_RESPONSE_COMPLETE;
}
break;
case ESTATE_RCV_RESPONSE_BUSY:
/* check interrupt */
if ((mmc_drv_obj.int_event2 & SD_INFO2_ALL_ERR) != 0U) {
/* error interrupt */
rtn_code = EMMC_ERR_INFO2;
state = ESTATE_ERROR;
break;
}
/* DAT0 not Busy */
if ((SD_INFO2_DAT0 & mmc_drv_obj.error_info.info2) != 0U) {
state = ESTATE_CHECK_RESPONSE_COMPLETE;
break;
}
break;
case ESTATE_CHECK_RESPONSE_COMPLETE:
if (cmd_type >= HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE) {
state = ESTATE_DATA_TRANSFER;
} else {
emmc_WaitCmd2Cmd_8Cycle();
state = ESTATE_END;
}
break;
case ESTATE_DATA_TRANSFER:
/* ADTC command */
mmc_drv_obj.during_transfer = TRUE;
mmc_drv_obj.state_machine_blocking = TRUE;
if (mmc_drv_obj.transfer_mode == HAL_MEMCARD_DMA) {
/* DMA */
emmc_data_transfer_dma();
} else {
/* PIO */
/* interrupt enable (FIFO read/write enable) */
if (mmc_drv_obj.cmd_info.dir == HAL_MEMCARD_WRITE) {
mem_write32(SD_INFO2_MASK, ( SD_INFO2_BWE | SD_INFO2_ALL_ERR | SD_INFO2_CLEAR ));
} else {
mem_write32(SD_INFO2_MASK, ( SD_INFO2_BRE | SD_INFO2_ALL_ERR | SD_INFO2_CLEAR ));
}
}
state = ESTATE_DATA_TRANSFER_COMPLETE;
break;
case ESTATE_DATA_TRANSFER_COMPLETE:
/* check interrupt */
if ((mmc_drv_obj.int_event2 & SD_INFO2_ALL_ERR) != 0U) {
/* error interrupt */
rtn_code = EMMC_ERR_INFO2;
state = ESTATE_TRANSFER_ERROR;
break;
} else {
/* success. nothing to do. */
}
/* DMAC error ? */
if (mmc_drv_obj.dma_error_flag == TRUE) {
/* Error occurred in DMAC driver. */
rtn_code = EMMC_ERR_FROM_DMAC_TRANSFER;
state = ESTATE_TRANSFER_ERROR;
} else if (mmc_drv_obj.during_dma_transfer == TRUE) {
/* DMAC not finished. unknown error */
rtn_code = EMMC_ERR;
state = ESTATE_TRANSFER_ERROR;
} else {
mem_write32(SD_INFO1_MASK, SD_INFO1_INFO2);
mem_write32(SD_INFO2_MASK, ( SD_INFO2_ALL_ERR | SD_INFO2_CLEAR ));
mmc_drv_obj.state_machine_blocking = TRUE;
state = ESTATE_ACCESS_END;
}
break;
case ESTATE_ACCESS_END:
/* clear flag */
if (HAL_MEMCARD_DMA == mmc_drv_obj.transfer_mode) {
mem_write32(CC_EXT_MODE, CC_EXT_MODE_CLEAR); /* W (CC_EXT_MODE, H'0000_1010) SD_BUF DMA transfer disabled */
mem_write32(SD_STOP, 0x00000000U);
mmc_drv_obj.during_dma_transfer = FALSE;
}
mem_write32(SD_INFO1_MASK, 0x00000000U);
mem_write32(SD_INFO2_MASK, SD_INFO2_CLEAR);
mem_write32(SD_INFO1, 0x00000000U);
mem_write32(SD_INFO2, SD_INFO2_CLEAR);
if ((mmc_drv_obj.int_event1 & SD_INFO1_INFO2) != 0U) {
emmc_WaitCmd2Cmd_8Cycle();
state = ESTATE_END;
} else {
state = ESTATE_ERROR;
}
break;
case ESTATE_TRANSFER_ERROR:
/* The error occurred in the Data transfer. */
if (HAL_MEMCARD_DMA == mmc_drv_obj.transfer_mode) {
mem_write32(CC_EXT_MODE, CC_EXT_MODE_CLEAR); /* W (CC_EXT_MODE, H'0000_1010) SD_BUF DMA transfer disabled */
mem_write32(SD_STOP, 0x00000000U);
mmc_drv_obj.during_dma_transfer = FALSE;
}
/* fallthrough */
case ESTATE_ERROR:
emmc_softreset();
ERROR("%s:0x%08x\n",__func__,rtn_code);
return rtn_code;
default:
state = ESTATE_END;
break;
} /* switch (state) */
} /* while ( (mmc_drv_obj.force_terminate != TRUE) && (state != ESTATE_END) ) */
/* force terminate */
if (mmc_drv_obj.force_terminate == TRUE) {
/* timeout timer is expired. Or, PIO data transfer error. */
/* Timeout occurred in the DMA transfer. */
if (mmc_drv_obj.during_dma_transfer == TRUE) {
mmc_drv_obj.during_dma_transfer = FALSE;
}
emmc_softreset();
return EMMC_ERR_FORCE_TERMINATE; /* error information has already been written. */
}
/* success */
mmc_drv_obj.during_transfer = FALSE;
return EMMC_SUCCESS;
}
/** host controller softrest.
*
* - Pre-conditions:<BR>
* .
* - Post-conditions:<BR>
* .
*
* param None.
* return None.
*/
static void emmc_softreset(void)
{
int32_t loop = 10000;
int32_t retry = 1000;
/* flag clear */
mmc_drv_obj.during_transfer = FALSE;
mmc_drv_obj.during_dma_transfer = FALSE;
mmc_drv_obj.state_machine_blocking = FALSE;
mmc_drv_obj.force_terminate = FALSE;
mmc_drv_obj.dma_error_flag = FALSE;
/* during operation ? */
if ((mem_read32(SD_INFO2) & SD_INFO2_CBSY) != 0U) {
/* wait CMDSEQ = 0 */
while (loop > 0) {
if ((mem_read32(SD_INFO2) & SD_INFO2_CBSY) == 0U) {
break; /* ready */
}
loop--;
if ((loop == 0) && (retry > 0)) {
micro_wait(1000U); /* wait 1ms */
loop = 10000;
retry--;
}
}
}
/* reset */
mem_write32(SOFT_RST, ( mem_read32(SOFT_RST) & (~SOFT_RST_SDRST) )); /* Soft reset */
mem_write32(SOFT_RST, ( mem_read32(SOFT_RST) | SOFT_RST_SDRST )); /* Soft reset released */
/* initialize */
mem_write32(SD_INFO1, 0x00000000U);
mem_write32(SD_INFO2, SD_INFO2_CLEAR);
mem_write32(SD_INFO1_MASK, 0x00000000U); /* all interrupt disable */
mem_write32(SD_INFO2_MASK, SD_INFO2_CLEAR); /* all interrupt disable */
}
/** read response
*
* - Pre-conditions:<BR>
* Called from emmc_exec_cmd().
* - Post-conditions:<BR>
* .
*
* param[in,out] *response Response from the card
* return None.
*/
static void emmc_read_response(uint32_t *response)
{
uint8_t *p = NULL;
if (response == NULL) {
return;
}
/* read response */
if (mmc_drv_obj.response_length == EMMC_MAX_RESPONSE_LENGTH) {
/* CSD or CID */
p = (uint8_t *)(response);
emmc_little_to_big(p, ((mem_read32(SD_RSP76) << 8U) | (mem_read32(SD_RSP54) >> 24U))); /* [127:96] */
emmc_little_to_big(p + 4U, ((mem_read32(SD_RSP54) << 8U) | (mem_read32(SD_RSP32) >> 24U))); /* [95:64] */
emmc_little_to_big(p + 8U, ((mem_read32(SD_RSP32) << 8U) | (mem_read32(SD_RSP10) >> 24U))); /* [63:32] */
emmc_little_to_big(p + 12U, (mem_read32(SD_RSP10) << 8U)); /* [31:0] */
} else {
*response = mem_read32(SD_RSP10); /* [39:8] */
}
}
/** response check
*
* - Pre-conditions:<BR>
* Called from emmc_exec_cmd().
* - Post-conditions:<BR>
* .
*
* param[in] *response Response from the card
* param[in] error_mask Errors to be checked (for R1/R1b response)
* return error code.
*/
static EMMC_ERROR_CODE emmc_response_check(const uint32_t *response, uint32_t error_mask)
{
HAL_MEMCARD_RESPONSE_TYPE response_type = (HAL_MEMCARD_RESPONSE_TYPE)(uintptr_t)((uint32_t)(mmc_drv_obj.cmd_info.cmd)
& (uint32_t)HAL_MEMCARD_RESPONSE_TYPE_MASK);
if (response == NULL) {
return EMMC_ERR_PARAM;
}
if (response_type == HAL_MEMCARD_RESPONSE_NONE) {
return EMMC_SUCCESS;
}
/* response check */
if (response_type <= HAL_MEMCARD_RESPONSE_R1b) {
/* R1 or R1b */
mmc_drv_obj.current_state = (EMMC_R1_STATE)((*response & EMMC_R1_STATE_MASK) >> EMMC_R1_STATE_SHIFT);
if ((*response & error_mask) != 0U) {
return EMMC_ERR_CARD_STATUS_BIT;
}
} else if (response_type == HAL_MEMCARD_RESPONSE_R4) {
/* R4 */
if ((*response & EMMC_R4_STATUS) != 0U) {
return EMMC_ERR_CARD_STATUS_BIT;
}
} else {
; /* nothing to do. other type does not have status bit */
}
return EMMC_SUCCESS;
}
/** brief converts endian from little to big
*
* - Pre-conditions:<BR>
* .
* - Post-conditions:<BR>
* .
*
* param[in,out] p destination buffer address.
* param[in] value convert data.(little)
* return None.
*/
static void emmc_little_to_big(uint8_t *p, uint32_t value)
{
if (p == NULL) {
return;
}
p[0] = (uint8_t)(value >> 24U);
p[1] = (uint8_t)(value >> 16U);
p[2] = (uint8_t)(value >> 8U);
p[3] = (uint8_t)value;
}
/** data transfer with DMA.
*
* - Pre-conditions:<BR>
* Called from emmc_exec_cmd().
* - Post-conditions:<BR>
* .
*
* return error code.
*/
static void emmc_data_transfer_dma(void)
{
mmc_drv_obj.during_dma_transfer = TRUE;
mmc_drv_obj.dma_error_flag = FALSE;
mem_write32(SD_INFO1_MASK, 0x00000000U);
mem_write32(SD_INFO2_MASK, ( SD_INFO2_ALL_ERR | SD_INFO2_CLEAR ));
/* DMAC setting */
if (mmc_drv_obj.cmd_info.dir == HAL_MEMCARD_WRITE) {
/* transfer complete interrupt enable */
mem_write32(DM_CM_INFO1_MASK, ( DM_CM_INFO_MASK_CLEAR | DM_CM_INFO_CH0_ENABLE ));
mem_write32(DM_CM_INFO2_MASK, ( DM_CM_INFO_MASK_CLEAR | DM_CM_INFO_CH0_ENABLE ));
/* BUFF --> FIFO */
mem_write32(DM_CM_DTRAN_MODE, ( DM_CM_DTRAN_MODE_CH0 | DM_CM_DTRAN_MODE_BIT_WIDTH )); /* CH0(downstream), 64-bit width */
} else {
/* transfer complete interrupt enable */
mem_write32(DM_CM_INFO1_MASK, ( DM_CM_INFO_MASK_CLEAR | DM_CM_INFO_CH1_ENABLE ));
mem_write32(DM_CM_INFO2_MASK, ( DM_CM_INFO_MASK_CLEAR | DM_CM_INFO_CH1_ENABLE ));
/* FIFO --> BUFF */
mem_write32(DM_CM_DTRAN_MODE, ( DM_CM_DTRAN_MODE_CH1 | DM_CM_DTRAN_MODE_BIT_WIDTH )); /* CH0(downstream), 64-bit width */
}
mem_write32(DM_DTRAN_ADDR, ( ( (uintptr_t)mmc_drv_obj.buff_address_virtual & DM_DTRAN_ADDR_WRITE_MASK ) )); /* Set address */
mem_write32(DM_CM_DTRAN_CTRL, DM_CM_DTRAN_CTRL_START); /* DMAC Start */
}
/** wait cmd-cmd 8cycle
*
* - Pre-conditions:<BR>
*
* - Post-conditions:<BR>
* .
*
* return None.
*/
static void emmc_WaitCmd2Cmd_8Cycle(void)
{
uint32_t dataL, wait = 0U;
dataL = mem_read32(SD_CLK_CTRL);
dataL &= 0x000000FFU;
switch (dataL) {
case 0xFFU: /* 1/1 10 us wait ( 1/200MHz)*8= 0.04 us(min) */
wait = 10U;
break;
case 0x00U: /* 1/2 10 us wait ( 2/200MHz)*8= 0.08 us(min) */
wait = 10U;
break;
case 0x01U: /* 1/4 10 us wait ( 4/200MHz)*8= 0.16 us(min) */
wait = 10U;
break;
case 0x02U: /* 1/8 10 us wait ( 8/200MHz)*8= 0.32 us(min) */
wait = 10U;
break;
case 0x04U: /* 1/16 10 us wait ( 16/200MHz)*8= 0.64 us(min) */
wait = 10U;
break;
case 0x08U: /* 1/32 10 us wait ( 32/200MHz)*8= 1.28 us(min) */
wait = 10U;
break;
case 0x10U: /* 1/64 10 us wait ( 64/200MHz)*8= 2.56 us(min) */
wait = 10U;
break;
case 0x20U: /* 1/128 10 us wait (128/200MHz)*8= 5.12 us(min) */
wait = 10U;
break;
case 0x40U: /* 1/256 20 us wait (256/200MHz)*8= 10.24 us(min) */
wait = 20U;
break;
case 0x80U: /* 1/512 30 us wait (512/200MHz)*8= 20.48 us(min) */
wait = 30U;
break;
default:
/* nop */
break;
}
micro_wait(wait);
}
/* ******************************** END ************************************ */

View File

@@ -0,0 +1,311 @@
/*******************************************************************************
* DISCLAIMER
* This software is supplied by Renesas Electronics Corporation and is only
* intended for use with Renesas products. No other uses are authorized. This
* software is owned by Renesas Electronics Corporation and is protected under
* all applicable laws, including copyright laws.
* THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING
* THIS SOFTWARE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT
* LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* AND NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED.
* TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY LAW, NEITHER RENESAS
* ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE
* FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR
* ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR ITS AFFILIATES HAVE
* BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
* Renesas reserves the right, without notice, to make changes to this software
* and to discontinue the availability of this software. By using this software,
* you agree to the additional terms and conditions found by accessing the
* following link:
* http://www.renesas.com/disclaimer
* Copyright 2021-2022 Renesas Electronics Corporation All rights reserved.
*******************************************************************************/
/*******************************************************************************
* DESCRIPTION : eMMC initialze
******************************************************************************/
/******************************************************************************
* @file emmc_init.c
* - Version : 0.05
* @brief initialize of SDHI driver.
* .
*****************************************************************************/
/******************************************************************************
* History : DD.MM.YYYY Version Description
* : 22.02.2022 0.01 First Release
* : 22.10.2021 0.02 Remove unnecessary code
* : 22.12.2021 0.03 Support static analysis
* : 06.01.2022 0.04 Modify SDHI access from DMA to PIO.
* : 06.04/2022 0.05 Del SDnH clock & SDn=200MHz(Duplicate settings)
*****************************************************************************/
/* ************************ HEADER (INCLUDE) SECTION *********************** */
#include "emmc_config.h"
#include "emmc_hal.h"
#include "emmc_std.h"
#include "emmc_registers.h"
#include "emmc_def.h"
/* ***************** MACROS, CONSTANTS, COMPILATION FLAGS ****************** */
/* ********************** STRUCTURES, TYPE DEFINITIONS ********************* */
/* ********************** DECLARATION OF EXTERNAL DATA ********************* */
st_mmc_base mmc_drv_obj;
/* ************************** FUNCTION PROTOTYPES ************************** */
static void emmc_drv_init(void);
static EMMC_ERROR_CODE emmc_dev_init(void);
static EMMC_ERROR_CODE emmc_dev_finalize(void);
static void emmc_memset(void *buff, uint8_t data, uint32_t cnt);
static EMMC_ERROR_CODE emmc_reset_controller(void);
static void emmc_driver_config(void);
static void emmc_set_data_timeout(uint32_t data_timeout);
/* ********************************* CODE ********************************** */
/** brief eMMC initialize.
*
* - Pre-conditions:<BR>
* .
* - Post-conditions:<BR>
* .
*
* retval EMMC_SUCCESS successful.
* retval EMMC_ERR error from interrupt API.
*/
EMMC_ERROR_CODE emmc_init(void)
{
/* initialize H/W */
(void)emmc_reset_controller();
/* Configuration */
emmc_driver_config();
return EMMC_SUCCESS;
}
/** terminate emmc driver
*
* EMMC H/W and S/W resource is released.
*
* - Pre-conditions:<BR>
* .
* - Post-conditions:<BR>
* .
*
* return None.
*/
EMMC_ERROR_CODE emmc_terminate(void)
{
EMMC_ERROR_CODE result = EMMC_ERR;
/* H/W finalize */
result = emmc_dev_finalize();
/* driver finalize */
emmc_memset((uint8_t *)(&mmc_drv_obj), 0U, sizeof(st_mmc_base)); /* clear global variable */
return result;
}
/** Function executes full reset to MMC host controller without taking power out from the memory card.
*
* - Pre-conditions:<BR>
* .
* - Post-conditions:<BR>
* Reset MMC host controller without taking power out from the memory card.
* Memory card preserves its state.
*
* return None
*/
static EMMC_ERROR_CODE emmc_reset_controller(void)
{
EMMC_ERROR_CODE result = EMMC_ERR;
/* initialize mmc driver */
emmc_drv_init();
mmc_drv_obj.base_address = MMC0_SD_BASE;
/* initialize H/W */
result = emmc_dev_init();
mmc_drv_obj.initialize = TRUE;
return result;
}
/** Configuration eMMC driver
*
* - Pre-conditions:<BR>
* initialized eMMC driver.
* - Post-conditions:<BR>
* .
*
* return None
*/
static void emmc_driver_config(void)
{
/* Read/Write data timeout */
emmc_set_data_timeout(EMMC_RW_DATA_TIMEOUT);
}
/** Sets data timeout
*
* Sets the data timeout value for read and write operations.
*
* - Pre-conditions:<BR>
* initialized eMMC driver.
*
* - Post-conditions:<BR>
* After this function is called, the timeout value is set according to argument.
*
* param[in] time_out The desired timeout value in milliseconds.
* return None
*/
static void emmc_set_data_timeout(uint32_t data_timeout)
{
mmc_drv_obj.data_timeout = data_timeout;
}
/** eMMC driver initialize. (software)
*
* - Pre-conditions:<BR>
* .
* - Post-conditions:<BR>
* .
*
* return None.
*/
static void emmc_drv_init(void)
{
/* initialize */
emmc_memset((uint8_t *)(&mmc_drv_obj), 0U, sizeof(st_mmc_base));
mmc_drv_obj.data_timeout = EMMC_RW_DATA_TIMEOUT;
mmc_drv_obj.bus_width = HAL_MEMCARD_DATA_WIDTH_1_BIT;
}
/** eMMC driver initialize. (H/W)
*
* - Pre-conditions:<BR>
* .
* - Post-conditions:<BR>
* .
*
* return None.
*/
static EMMC_ERROR_CODE emmc_dev_init(void)
{
/* MMCIF initialize */
mem_write32(SD_INFO1, 0x00000000U); /* all interrupt clear */
mem_write32(SD_INFO2, SD_INFO2_CLEAR); /* all interrupt clear */
mem_write32(SD_INFO1_MASK, 0x00000000U); /* all interrupt disable */
mem_write32(SD_INFO2_MASK, SD_INFO2_CLEAR); /* all interrupt disable */
mem_write32(HOST_MODE, 0x00000000U); /* SD_BUF access width = 64-bit */
mem_write32(SD_OPTION, 0x0000C0EEU); /* Bus width = 1bit, timeout=MAX */
mem_write32(SD_CLK_CTRL, 0x00000000U); /* Automatic Control=Disable, Clock Output=Disable */
return EMMC_SUCCESS;
}
/** EMMC H/W finalize
*
* EMMC Host and Card hardware resource is released.
*
* - Pre-conditions:<BR>
* .
*
* - Post-conditions:<BR>
* .
* return None.
*/
static EMMC_ERROR_CODE emmc_dev_finalize(void)
{
EMMC_ERROR_CODE result = EMMC_ERR;
/* MMC power off
* the power supply of eMMC device is always turning on.
* RST_n : Hi --> Low level.
*/
result = emmc_memcard_power(FALSE);
mem_write32(SD_INFO1, 0x00000000U);
mem_write32(SD_INFO2, 0x00000800U);
mem_write32(DM_CM_INFO1, 0x00000000U);
mem_write32(DM_CM_INFO2, 0x00000000U);
mem_write32(SD_CLK_CTRL, 0x00000020U);
mem_write32(CC_EXT_MODE, 0x00000000U);
mem_write32(SD_STOP, 0x00000000U);
mem_write32(SD_SECCNT, 0x00000000U);
mem_write32(DM_CM_DTRAN_MODE, 0x00000000U);
mem_write32(DM_DTRAN_ADDR, 0x00000000U);
mem_write32(SD_OPTION, 0x00000000U);
mem_write32(DM_CM_DTRAN_CTRL, 0x00000000U);
return result;
}
/** Set power to memory card IF.
* This function control Vcc and Vccq and RST_n.
*
* attention
* CPU cannot control Vcc&Vccq.
* The power supply of eMMC device is always turning on.
*
* param[in] mode TRUE = power on, FALSE = power off
*
* retval EMMC_SUCCESS powering succeeded
* retval EMMC_ERR_CARD_POWER powering failed
*/
EMMC_ERROR_CODE emmc_memcard_power(uint32_t mode)
{
if (mode == TRUE) {
/* power on (Vcc&Vccq is always power on) */
mmc_drv_obj.card_power_enable = TRUE;
} else {
/* power off (Vcc&Vccq is always power on) */
mmc_drv_obj.card_power_enable = FALSE;
mmc_drv_obj.mount = FALSE;
mmc_drv_obj.selected = FALSE;
}
return EMMC_SUCCESS;
}
/** memset(). no use C standard library.
*
* - Pre-conditions:<BR>
* .
* - Post-conditions:<BR>
* .
*
* param[in,out] buff pointer to buffer (virtual)
* param[in] data fill data.
* param[in] cnt fill size (number of bytes)
* return None.
*/
static void emmc_memset(void *buff, uint8_t data, uint32_t cnt)
{
uint8_t *tmp = NULL;
tmp = (uint8_t *)buff;
if (buff == NULL) {
return;
}
while (cnt > 0U) {
*tmp = data;
tmp++;
cnt--;
}
}
/* ******************************** END ************************************ */

View File

@@ -0,0 +1,227 @@
/*******************************************************************************
* DISCLAIMER
* This software is supplied by Renesas Electronics Corporation and is only
* intended for use with Renesas products. No other uses are authorized. This
* software is owned by Renesas Electronics Corporation and is protected under
* all applicable laws, including copyright laws.
* THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING
* THIS SOFTWARE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT
* LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* AND NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED.
* TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY LAW, NEITHER RENESAS
* ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE
* FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR
* ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR ITS AFFILIATES HAVE
* BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
* Renesas reserves the right, without notice, to make changes to this software
* and to discontinue the availability of this software. By using this software,
* you agree to the additional terms and conditions found by accessing the
* following link:
* http://www.renesas.com/disclaimer
* Copyright 2021-2022 Renesas Electronics Corporation All rights reserved.
*******************************************************************************/
/*******************************************************************************
* DESCRIPTION : eMMC interrupt
******************************************************************************/
/******************************************************************************
* @file emmc_interrupt.c
* - Version : 0.04
* @brief state check of SDHI.
* .
*****************************************************************************/
/******************************************************************************
* History : DD.MM.YYYY Version Description
* : 22.02.2022 0.01 First Release
* : 22.10.2021 0.02 Remove unnecessary code
* : 22.12.2021 0.03 Support static analysis
* : 06.01.2022 0.04 Modify SDHI access from DMA to PIO.
*****************************************************************************/
#include "emmc_config.h"
#include "emmc_hal.h"
#include "emmc_std.h"
#include "emmc_registers.h"
#include "emmc_def.h"
#include "log.h"
#include <stdint.h>
/* ***************** MACROS, CONSTANTS, COMPILATION FLAGS ****************** */
/* ********************** STRUCTURES, TYPE DEFINITIONS ********************* */
/* ********************** DECLARATION OF EXTERNAL DATA ********************* */
/* ************************** FUNCTION PROTOTYPES ************************** */
static EMMC_ERROR_CODE emmc_trans_sector(uint32_t *buff_address_virtual);
/* ********************************* CODE ********************************** */
/** emmc driver interrupt service routine.
*
* - Pre-conditions:<BR>
* Must be block emmc driver state machine.
* - Post-conditions:<BR>
* unblocking emmc driver state machine.
*
* retval INT_SUCCESS
*/
uint32_t emmc_interrupt(void)
{
EMMC_ERROR_CODE result = EMMC_ERR;
/* SD_INFO */
mmc_drv_obj.error_info.info1 = mem_read32(SD_INFO1);
mmc_drv_obj.error_info.info2 = mem_read32(SD_INFO2);
/* SD_INFO EVENT */
mmc_drv_obj.int_event1 = mmc_drv_obj.error_info.info1 & mem_read32(SD_INFO1_MASK);
mmc_drv_obj.int_event2 = mmc_drv_obj.error_info.info2 & mem_read32(SD_INFO2_MASK);
/* ERR_STS */
mmc_drv_obj.error_info.status1 = mem_read32(SD_ERR_STS1);
mmc_drv_obj.error_info.status2 = mem_read32(SD_ERR_STS2);
/* DM_CM_INFO */
mmc_drv_obj.error_info.dm_info1 = mem_read32(DM_CM_INFO1);
mmc_drv_obj.error_info.dm_info2 = mem_read32(DM_CM_INFO2);
/* DM_CM_INFO EVENT */
mmc_drv_obj.dm_event1 = mmc_drv_obj.error_info.dm_info1 & mem_read32(DM_CM_INFO1_MASK);
mmc_drv_obj.dm_event2 = mmc_drv_obj.error_info.dm_info2 & mem_read32(DM_CM_INFO2_MASK);
/* ERR SD_INFO2 */
if ((SD_INFO2_ALL_ERR & mmc_drv_obj.int_event2) != 0U) {
mem_write32(SD_INFO1_MASK, 0x00000000U); /* interrupt disable */
mem_write32(SD_INFO2_MASK, SD_INFO2_CLEAR); /* interrupt disable */
mem_write32(SD_INFO1, 0x00000000U); /* interrupt clear */
mem_write32(SD_INFO2, SD_INFO2_CLEAR); /* interrupt clear */
mmc_drv_obj.state_machine_blocking = FALSE;
}
/* PIO Transfer */
/* BWE/BRE */
else if ((( SD_INFO2_BWE | SD_INFO2_BRE) & mmc_drv_obj.int_event2) != 0U) {
/* BWE */
if (( SD_INFO2_BWE & mmc_drv_obj.int_event2) != 0U) {
mem_write32(SD_INFO2, (mem_read32(SD_INFO2) & ~SD_INFO2_BWE)); /* interrupt clear */
}
/* BRE */
else {
mem_write32(SD_INFO2, (mem_read32(SD_INFO2) & ~SD_INFO2_BRE)); /* interrupt clear */
}
result = emmc_trans_sector((uint32_t *)mmc_drv_obj.buff_address_virtual); /* sector R/W */
mmc_drv_obj.buff_address_virtual += EMMC_BLOCK_LENGTH;
mmc_drv_obj.remain_size -= EMMC_BLOCK_LENGTH;
if (result != EMMC_SUCCESS) {
/* data transfer error */
ERROR("%s:0x%08x\n",__func__, result);
/* Panic */
mem_write32(SD_INFO1_MASK, 0x00000000U); /* interrupt disable */
mem_write32(SD_INFO2_MASK, SD_INFO2_CLEAR); /* interrupt disable */
mem_write32(SD_INFO1, 0x00000000U); /* interrupt clear */
mem_write32(SD_INFO2, SD_INFO2_CLEAR); /* interrupt clear */
mmc_drv_obj.force_terminate = TRUE;
} else {
mmc_drv_obj.during_transfer = FALSE;
}
mmc_drv_obj.state_machine_blocking = FALSE;
}
/* DMA_TRANSFER */
/* DM_CM_INFO1: DMA-ch0 transfer complete or error occured */
else if ((DM_CM_INFO_DTRANEND0 & mmc_drv_obj.dm_event1) != 0U) {
mem_write32(DM_CM_INFO1, 0x00000000U);
mem_write32(DM_CM_INFO2, 0x00000000U);
mem_write32(SD_INFO2, (mem_read32(SD_INFO2) & ~SD_INFO2_BWE)); /* interrupt clear */
/* DM_CM_INFO2: DMA-ch0 error occured */
if (( DM_CM_INFO_DTRANEND0 & mmc_drv_obj.dm_event2) != 0U) {
mmc_drv_obj.dma_error_flag = TRUE;
} else {
mmc_drv_obj.during_dma_transfer = FALSE;
mmc_drv_obj.during_transfer = FALSE;
}
mmc_drv_obj.state_machine_blocking = FALSE; /* wait next interrupt */
}
/* DM_CM_INFO1: DMA-ch1 transfer complete or error occured */
else if ((DM_CM_INFO_DTRANEND1 & mmc_drv_obj.dm_event1) != 0U) {
mem_write32(DM_CM_INFO1, 0x00000000U);
mem_write32(DM_CM_INFO2, 0x00000000U);
mem_write32(SD_INFO2, (mem_read32(SD_INFO2) & ~SD_INFO2_BRE)); /* interrupt clear */
/* DM_CM_INFO2: DMA-ch1 error occured */
if (( DM_CM_INFO_DTRANEND1 & mmc_drv_obj.dm_event2) != 0U) {
mmc_drv_obj.dma_error_flag = TRUE;
} else {
mmc_drv_obj.during_dma_transfer = FALSE;
mmc_drv_obj.during_transfer = FALSE;
}
mmc_drv_obj.state_machine_blocking = FALSE; /* wait next interrupt */
}
/* Response end */
else if ((SD_INFO1_INFO0 & mmc_drv_obj.int_event1) != 0U) {
mem_write32(SD_INFO1, (mem_read32(SD_INFO1) & ~SD_INFO1_INFO0)); /* interrupt clear */
mmc_drv_obj.state_machine_blocking = FALSE;
}
/* Access end */
else if ((SD_INFO1_INFO2 & mmc_drv_obj.int_event1) != 0U) {
mem_write32(SD_INFO1, (mem_read32(SD_INFO1) & ~SD_INFO1_INFO2)); /* interrupt clear */
mmc_drv_obj.state_machine_blocking = FALSE;
} else {
/* nothing to do. */
}
return 0U;
}
/** Data transfer function with PIO (Single sector).
*
* - Pre-conditions:<BR>
* Called from interrupt service.
* - Post-conditions:<BR>
* .
*
* param[in,out] buff_address_virtual Dest/Src buffer address(virtual).
* retval EMMC_SUCCESS successful.
* retval EMMC_ERR_PARAM parameter error.
* retval EMMC_ERR_STATE state error.
*/
static EMMC_ERROR_CODE emmc_trans_sector(uint32_t *buff_address_virtual)
{
uint32_t length, i;
uint64_t *bufPtrLL;
if (buff_address_virtual == NULL) {
return EMMC_ERR_PARAM;
}
if ((mmc_drv_obj.during_transfer != TRUE) || (mmc_drv_obj.remain_size == 0U)) {
return EMMC_ERR_STATE;
}
bufPtrLL = (uint64_t*)buff_address_virtual;
length = mmc_drv_obj.remain_size;
/* data transefer */
for (i = 0U; i < (length >> 3U); i++) {
/* Write */
if (mmc_drv_obj.cmd_info.dir == HAL_MEMCARD_WRITE) {
mem_write64(SD_BUF0, *bufPtrLL); /* buffer --> FIFO */
}
/* Read */
else {
*bufPtrLL = mem_read64(SD_BUF0); /* FIFO --> buffer */
}
bufPtrLL++;
}
return EMMC_SUCCESS;
}
/* ******************************** END ************************************ */

View File

@@ -0,0 +1,767 @@
/*******************************************************************************
* DISCLAIMER
* This software is supplied by Renesas Electronics Corporation and is only
* intended for use with Renesas products. No other uses are authorized. This
* software is owned by Renesas Electronics Corporation and is protected under
* all applicable laws, including copyright laws.
* THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING
* THIS SOFTWARE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT
* LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* AND NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED.
* TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY LAW, NEITHER RENESAS
* ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE
* FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR
* ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR ITS AFFILIATES HAVE
* BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
* Renesas reserves the right, without notice, to make changes to this software
* and to discontinue the availability of this software. By using this software,
* you agree to the additional terms and conditions found by accessing the
* following link:
* http://www.renesas.com/disclaimer
* Copyright 2021-2022 Renesas Electronics Corporation All rights reserved.
*******************************************************************************/
/*******************************************************************************
* DESCRIPTION : eMMC Mount
******************************************************************************/
/******************************************************************************
* @file emmc_mount.c
* - Version : 0.04
* @brief initialize of condition.
* .
*****************************************************************************/
/******************************************************************************
* History : DD.MM.YYYY Version Description
* : 22.02.2022 0.01 First Release
* : 22.10.2021 0.02 Remove unnecessary code
* : 22.12.2021 0.03 Support static analysis
* : 06.01.2022 0.04 Modify SDHI access from DMA to PIO.
*****************************************************************************/
/* ************************ HEADER (INCLUDE) SECTION *********************** */
#include "emmc_config.h"
#include "emmc_hal.h"
#include "emmc_std.h"
#include "emmc_registers.h"
#include "emmc_def.h"
#include <stdint.h>
#include "micro_wait.h"
#include "remap.h"
#include "log.h"
/* ***************** MACROS, CONSTANTS, COMPILATION FLAGS ****************** */
/* ********************** STRUCTURES, TYPE DEFINITIONS ********************* */
/* ********************** DECLARATION OF EXTERNAL DATA ********************* */
/* ************************** FUNCTION PROTOTYPES ************************** */
static EMMC_ERROR_CODE emmc_clock_ctrl(uint32_t mode);
static EMMC_ERROR_CODE emmc_card_init(void);
static EMMC_ERROR_CODE emmc_high_speed(void);
static EMMC_ERROR_CODE emmc_bus_width(uint32_t width);
static uint32_t emmc_set_timeout_register_value(uint32_t freq);
static void set_sd_clk(uint32_t clkDiv);
static uint32_t emmc_calc_tran_speed(uint32_t* freq);
/* ********************************* CODE ********************************** */
/** eMMC mount operation.
*
* Sequence is the following.
* 1) Bus initialization (emmc_card_init())
* 2) Switching to high speed mode. (emmc_high_speed())
* 3) Changing the data bus width. (emmc_bus_width())
*
* - Pre-conditions:<BR>
* eMMC driver is initialized. The power supply of MMC IF must be turning on.
* - Post-conditions:<BR>
* MMC card state changes to transfer state.
*
* return eMMC error code.
*/
EMMC_ERROR_CODE emmc_mount(void)
{
EMMC_ERROR_CODE result = EMMC_ERR;
/* state check */
if ((mmc_drv_obj.initialize != TRUE) || (mmc_drv_obj.card_power_enable != TRUE)
|| ((mem_read32(SD_INFO2) & SD_INFO2_CBSY) != 0U)) {
ERROR("%s:0x%08x\n",__func__,EMMC_ERR_STATE);
return EMMC_ERR_STATE;
}
/* initialize card (IDLE state --> Transfer state) */
result = emmc_card_init();
if (result != EMMC_SUCCESS) {
ERROR("%s\n",__func__);
(void)emmc_clock_ctrl(FALSE);
return result;
}
/* Switching high speed mode */
result = emmc_high_speed();
if (result != EMMC_SUCCESS) {
ERROR("%s\n",__func__);
(void)emmc_clock_ctrl(FALSE);
return result;
}
/* Changing the data bus width */
result = emmc_bus_width(8U);
if (result != EMMC_SUCCESS) {
ERROR("%s\n",__func__);
(void)emmc_clock_ctrl(FALSE);
return result;
}
/* mount complete */
mmc_drv_obj.mount = TRUE;
return EMMC_SUCCESS;
}
/** Bus initialization function
*
* - Pre-conditions:<BR>
* eMMC driver is initialized. The power supply of MMC IF must be turning on.
* - Post-conditions:<BR>
* MMC card state changes to transfer state.
*
* retval EMMC_SUCCESS successful.
* return eMMC error code.
* attention upper layer must be check pre-conditions.
*/
static EMMC_ERROR_CODE emmc_card_init(void)
{
int32_t retry;
uint32_t freq = MMC_400KHZ; /* 390KHz */
EMMC_ERROR_CODE result = EMMC_ERR;
uint32_t resultCalc = 0U;
/* state check */
if ((mmc_drv_obj.initialize != TRUE) || (mmc_drv_obj.card_power_enable != TRUE)
|| ((mem_read32(SD_INFO2) & SD_INFO2_CBSY) != 0U)) {
ERROR("%s:0x%08x\n",__func__,EMMC_ERR_STATE);
return EMMC_ERR_STATE;
}
/* clock on (force change) */
mmc_drv_obj.current_freq = 0U;
mmc_drv_obj.max_freq = MMC_20MHZ; /* MMC_20MHZ = MMC_12MHZ = 12.187MHz */
result = emmc_set_request_mmc_clock(&freq);
if (result != EMMC_SUCCESS) {
ERROR("%s\n",__func__);
return EMMC_ERR;
}
micro_wait(1000U); /* wait 1ms */
/* CMD0, arg=0x00000000 */
result = emmc_send_idle_cmd (0x00000000U);
if (result != EMMC_SUCCESS) {
ERROR("%s\n",__func__);
return result;
}
micro_wait(200U); /* wait 74clock 390kHz(189.74us)*/
/* CMD1 */
emmc_make_nontrans_cmd(CMD1_SEND_OP_COND, EMMC_HOST_OCR_VALUE);
for (retry = 300; retry > 0; retry--) {
result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
if (result != EMMC_SUCCESS) {
ERROR("%s\n",__func__);
return result;
}
if ((mmc_drv_obj.r3_ocr & EMMC_OCR_STATUS_BIT) != 0U) {
break; /* card is ready. exit loop */
}
micro_wait(1000U); /* wait 1ms */
}
if (retry == 0) {
ERROR("%s:0x%08x\n",__func__,EMMC_ERR_TIMEOUT);
return EMMC_ERR_TIMEOUT;
}
if ((mmc_drv_obj.r3_ocr & EMMC_OCR_ACCESS_MODE_MASK) != EMMC_OCR_ACCESS_MODE_SECT) {
/* unknown value */
ERROR("%s:0x%08x\n",__func__,EMMC_ERR);
return EMMC_ERR;
}
/* CMD2 */
emmc_make_nontrans_cmd(CMD2_ALL_SEND_CID_MMC, 0x00000000U);
mmc_drv_obj.response = (uint32_t *)(&mmc_drv_obj.cid_data[0U]); /* use CID special buffer */
result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
if (result != EMMC_SUCCESS) {
ERROR("%s\n",__func__);
return result;
}
/* CMD3 */
emmc_make_nontrans_cmd(CMD3_SET_RELATIVE_ADDR, EMMC_RCA << 16U);
result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
if (result != EMMC_SUCCESS) {
ERROR("%s\n",__func__);
return result;
}
/* CMD9 : CSD */
emmc_make_nontrans_cmd(CMD9_SEND_CSD, EMMC_RCA << 16U);
mmc_drv_obj.response = (uint32_t *)(&mmc_drv_obj.csd_data[0U]); /* use CSD special buffer */
result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
if (result != EMMC_SUCCESS) {
ERROR("%s\n",__func__);
return result;
}
/* card version check */
if (EMMC_CSD_SPEC_VARS() < 4U) {
ERROR("%s:0x%08x\n",__func__,EMMC_ERR_ILLEGAL_CARD);
return EMMC_ERR_ILLEGAL_CARD;
}
/* CMD7 (select card) */
emmc_make_nontrans_cmd(CMD7_SELECT_CARD, EMMC_RCA << 16U);
result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
if (result != EMMC_SUCCESS) {
ERROR("%s\n",__func__);
return result;
}
mmc_drv_obj.selected = TRUE;
/* card speed check */
resultCalc = emmc_calc_tran_speed(&freq); /* Card spec is calculated from TRAN_SPEED(CSD). */
if (resultCalc == 0U) {
ERROR("%s:0x%08x\n",__func__,EMMC_ERR_ILLEGAL_CARD);
return EMMC_ERR_ILLEGAL_CARD;
}
mmc_drv_obj.max_freq = freq; /* max frequency (card spec) */
result = emmc_set_request_mmc_clock(&freq);
if (result != EMMC_SUCCESS) {
ERROR("%s\n",__func__);
return EMMC_ERR;
}
/* set read/write timeout */
mmc_drv_obj.data_timeout = emmc_set_timeout_register_value(freq);
mem_write32(SD_OPTION, ((mem_read32(SD_OPTION) & ~(SD_OPTION_TIMEOUT_CNT_MASK)) | mmc_drv_obj.data_timeout));
/* SET_BLOCKLEN:512byte */
/* CMD16 */
emmc_make_nontrans_cmd(CMD16_SET_BLOCKLEN, EMMC_BLOCK_LENGTH);
result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
if (result != EMMC_SUCCESS) {
ERROR("%s\n",__func__);
return result;
}
/* Transfer Data Length */
mem_write32(SD_SIZE, EMMC_BLOCK_LENGTH);
/* CMD8 : EXT_CSD */
emmc_make_trans_cmd(CMD8_SEND_EXT_CSD, 0x00000000U, (uint32_t *)(&mmc_drv_obj.ext_csd_data[0U]),
EMMC_MAX_EXT_CSD_LENGTH, HAL_MEMCARD_READ, HAL_MEMCARD_NOT_DMA);
result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
if (result != EMMC_SUCCESS) {
/* CMD12 is not send.
* If BUS initialization is failed, user must be execute Bus initialization again.
* Bus initialization is start CMD0(soft reset command).
*/
ERROR("%s\n",__func__);
return result;
}
return EMMC_SUCCESS;
}
/** Switching to high-speed mode
*
* - Pre-conditions:<BR>
* Executing Bus initializatin by emmc_card_init().
* EXT_CSD data must be stored in mmc_drv_obj.ext_csd_data[].
*
* - Post-conditions:<BR>
* Change the clock frequency to 26MHz or 52MHz.
*
* retval EMMC_SUCCESS successful or aleady switching.
* retval EMMC_ERR_STATE state error.
* retval EMMC_ERR unknown error.
* return emmc error code.
*/
static EMMC_ERROR_CODE emmc_high_speed(void)
{
uint32_t freq; /**< High speed mode clock frequency */
EMMC_ERROR_CODE result = EMMC_ERR;
uint8_t cardType;
/* state check */
if (mmc_drv_obj.selected != TRUE) {
ERROR("%s:0x%08x\n",__func__,EMMC_ERR_STATE);
return EMMC_ERR_STATE;
}
/* max frequency */
cardType = (uint8_t)mmc_drv_obj.ext_csd_data[EMMC_EXT_CSD_CARD_TYPE];
if ((cardType & EMMC_EXT_CSD_CARD_TYPE_52MHZ) != 0U) {
freq = MMC_52MHZ;
} else if ((cardType & EMMC_EXT_CSD_CARD_TYPE_26MHZ) != 0U) {
freq = MMC_26MHZ;
} else {
freq = MMC_20MHZ;
}
/* Hi-Speed-mode selction */
if (( MMC_52MHZ == freq) || ( MMC_26MHZ == freq)) {
/* CMD6 */
emmc_make_nontrans_cmd(CMD6_SWITCH, EMMC_SWITCH_HS_TIMING);
result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
if (result != EMMC_SUCCESS) {
ERROR("%s\n",__func__);
return result;
}
}
/* set mmc clock */
mmc_drv_obj.max_freq = freq;
result = emmc_set_request_mmc_clock(&freq);
if (result != EMMC_SUCCESS) {
ERROR("%s\n",__func__);
return EMMC_ERR;
}
/* set read/write timeout */
mmc_drv_obj.data_timeout = emmc_set_timeout_register_value(freq);
mem_write32(SD_OPTION, ((mem_read32(SD_OPTION) & ~(SD_OPTION_TIMEOUT_CNT_MASK)) | mmc_drv_obj.data_timeout));
/* CMD13 */
emmc_make_nontrans_cmd(CMD13_SEND_STATUS, EMMC_RCA << 16U);
result = emmc_exec_cmd(EMMC_R1_ERROR_MASK_WITHOUT_CRC, mmc_drv_obj.response);
if (result != EMMC_SUCCESS) {
ERROR("%s\n",__func__);
return result;
}
return EMMC_SUCCESS;
}
/** Changing the data bus width
*
* if chinging the data bus width failed, card is reset by CMD0.
* Please do Bus initialization over again.
*
* - Pre-conditions:<BR>
* Executing Bus initializatin by emmc_card_init().
*
* - Post-conditions:<BR>
* Change the data bus width to 8bit or 4bit.
* mmc_drv_obj.ext_csd_data is updated.
*
* param[in] width bus width (8 or 4)
* retval EMMC_SUCCESS successful.
* retval EMMC_ERR_PARAM parameter error
* retval EMMC_ERR_STATE state error.
*
*/
static EMMC_ERROR_CODE emmc_bus_width(uint32_t width)
{
EMMC_ERROR_CODE result = EMMC_ERR;
/* parameter check */
if ((width != 8U) && (width != 4U) && (width != 1U)) {
ERROR("%s:0x%08x\n",__func__,EMMC_ERR_PARAM);
return EMMC_ERR_PARAM;
}
/* state check */
if (mmc_drv_obj.selected != TRUE) {
ERROR("%s:0x%08x\n",__func__,EMMC_ERR_STATE);
return EMMC_ERR_STATE;
}
mmc_drv_obj.bus_width = (HAL_MEMCARD_DATA_WIDTH)(width >> 2U); /* 2 = 8bit, 1 = 4bit, 0 =1bit */
/* CMD6 */
emmc_make_nontrans_cmd(CMD6_SWITCH, ( EMMC_SWITCH_BUS_WIDTH_1 | ((uint32_t)(mmc_drv_obj.bus_width) << 8U)));
result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
if (result != EMMC_SUCCESS) {
/* occurred error */
mmc_drv_obj.bus_width = HAL_MEMCARD_DATA_WIDTH_1_BIT;
goto EXIT;
}
switch (mmc_drv_obj.bus_width) {
case HAL_MEMCARD_DATA_WIDTH_1_BIT:
mem_write32(SD_OPTION, ((mem_read32(SD_OPTION) & ~(SD_OPTION_WIDTH|SD_OPTION_WIDTH8)) | SD_OPTION_WIDTH ));
break;
case HAL_MEMCARD_DATA_WIDTH_4_BIT:
mem_write32(SD_OPTION, (mem_read32(SD_OPTION) & ~(SD_OPTION_WIDTH|SD_OPTION_WIDTH8)));
break;
case HAL_MEMCARD_DATA_WIDTH_8_BIT:
default:
mem_write32(SD_OPTION, ((mem_read32(SD_OPTION) & ~(SD_OPTION_WIDTH|SD_OPTION_WIDTH8)) | SD_OPTION_WIDTH8 ));
break;
}
/* CMD13 */
emmc_make_nontrans_cmd(CMD13_SEND_STATUS, EMMC_RCA << 16U);
result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
if (result != EMMC_SUCCESS) {
goto EXIT;
}
/* CMD8 : EXT_CSD */
emmc_make_trans_cmd(CMD8_SEND_EXT_CSD, 0x00000000U, (uint32_t *)(&mmc_drv_obj.ext_csd_data[0U]),
EMMC_MAX_EXT_CSD_LENGTH, HAL_MEMCARD_READ, HAL_MEMCARD_NOT_DMA);
result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
if (result != EMMC_SUCCESS) {
goto EXIT;
}
return EMMC_SUCCESS;
EXIT:
ERROR("%s:0x%08x\n",__func__,result);
return result;
}
/** select access partition
*
* This function write the EXT_CSD register(PARTITION_ACCESS: PARTITION_CONFIG[2:0]).
*
* - Pre-conditions:<BR>
* MMC card is mounted.
*
* - Post-conditions:<BR>
* selected partition can access.
*
* param[in] id user selects partitions to access.
* retval EMMC_SUCCESS successful.
* retval EMMC_ERR_STATE state error.
* retval EMMC_ERR_PARAM parameter error.
* return emmc error code.
*/
EMMC_ERROR_CODE emmc_select_partition(EMMC_PARTITION_ID id)
{
EMMC_ERROR_CODE result = EMMC_ERR;
uint32_t partition;
uint32_t partition_config;
/* state check */
if (mmc_drv_obj.mount != TRUE) {
ERROR("%s:0x%08x\n",__func__,EMMC_ERR_STATE);
return EMMC_ERR_STATE;
}
/* id has PARTITION_ACCESS(Bit[2:0]) */
if ((uint32_t)((uint32_t)id & ~(uint32_t)PARTITION_ID_MASK) != 0U) {
ERROR("%s:0x%08x\n",__func__,EMMC_ERR_PARAM);
return EMMC_ERR_PARAM;
}
/* EXT_CSD[179] value */
partition_config = (uint32_t)mmc_drv_obj.ext_csd_data[EMMC_EXT_CSD_PARTITION_CONFIG];
if ((partition_config & (uint32_t)PARTITION_ID_MASK) == (uint32_t)id) {
result = EMMC_SUCCESS;
} else {
partition_config = ((partition_config & (~(uint32_t)PARTITION_ID_MASK)) | (uint32_t)id);
partition = EMMC_SWITCH_PARTITION_CONFIG | (partition_config << 8U);
result = emmc_set_ext_csd(partition);
}
return result;
}
/** set EXT CSD data
*
* - Pre-conditions:<BR>
* MMC card is mounted.
*
* - Post-conditions:<BR>
* mmc_drv_obj.ext_csd_data[] is updated.
*
* param[in] arg argument of CMD6
* return emmc error code.
*/
EMMC_ERROR_CODE emmc_set_ext_csd(uint32_t arg)
{
EMMC_ERROR_CODE result = EMMC_ERR;
/* CMD6 */
emmc_make_nontrans_cmd(CMD6_SWITCH, arg);
result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
if (result != EMMC_SUCCESS) {
return result;
}
/* CMD13 */
emmc_make_nontrans_cmd(CMD13_SEND_STATUS, EMMC_RCA << 16U);
result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
if (result != EMMC_SUCCESS) {
return result;
}
/* CMD8 : EXT_CSD */
emmc_make_trans_cmd(CMD8_SEND_EXT_CSD, 0x00000000, (uint32_t *)(&mmc_drv_obj.ext_csd_data[0U]),
EMMC_MAX_EXT_CSD_LENGTH, HAL_MEMCARD_READ, HAL_MEMCARD_NOT_DMA);
result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
if (result != EMMC_SUCCESS) {
return result;
}
return EMMC_SUCCESS;
}
/** set request MMC clock frequency.
*
* Function returns EMMC_SUCCESS if clock is already running in the desired frequency.
* EMMC_ERR is returned if the HW doesn't support requested clock frequency.
* If matching frequence cannot be set the closest frequence below should be selected.
* For example if 50MHz is requested, but HW supports only 48MHz then 48MHz should be returned in the freq parameter.
*
* - Pre-conditions:<BR>
* initialized eMMC driver with emmc_init().
* Memory card and MMCSDIO host controller needs to be powered up beforehand.
*
* - Post-conditions:<BR>
* Desired clock frequency is set to memory card IF.
*
* param[in] freq frequency [Hz]
* retval EMMC_SUCCESS successful.
* retval EMMC_ERR_STATE state error.
* retval EMMC_ERR busy
*/
EMMC_ERROR_CODE emmc_set_request_mmc_clock(const uint32_t *freq)
{
/* parameter check */
if (freq == NULL) {
ERROR("%s:0x%08x\n",__func__,EMMC_ERR_PARAM);
return EMMC_ERR_PARAM;
}
/* state check */
if ((mmc_drv_obj.initialize != TRUE) || (mmc_drv_obj.card_power_enable != TRUE)) {
ERROR("%s:0x%08x\n",__func__,EMMC_ERR_STATE);
return EMMC_ERR_STATE;
}
/* clock is already running in the desired frequency. */
if ((mmc_drv_obj.clock_enable == TRUE) && (mmc_drv_obj.current_freq == *freq)) {
return EMMC_SUCCESS;
}
/* busy check */
if ((mem_read32(SD_INFO2) & SD_INFO2_CBSY) != 0U) {
ERROR("%s:0x%08x\n",__func__,EMMC_ERR_CARD_BUSY);
return EMMC_ERR;
}
set_sd_clk(*freq);
mmc_drv_obj.clock_enable = FALSE;
return emmc_clock_ctrl(TRUE); /* clock on */
}
/** set sd clock.
*
* - Pre-conditions:<BR>
* CSD data must be stored in mmc_drv_obj.csd_data[].
*
* - Post-conditions:<BR>
* set mmc clock.
*
* param[in] clkDiv request freq
* return None.
*/
static void set_sd_clk(uint32_t clkDiv)
{
uint32_t dataL;
dataL = (mem_read32(SD_CLK_CTRL) & (~SD_CLK_CTRL_CLKDIV_MASK));
switch (clkDiv) {
case 1U: /* 1/1 */
dataL |= 0x000000FFU;
break;
case 2U: /* 1/2 */
dataL |= 0x00000000U;
break;
case 4U: /* 1/4 */
dataL |= 0x00000001U;
break;
case 8U: /* 1/8 */
dataL |= 0x00000002U;
break;
case 16U: /* 1/16 */
dataL |= 0x00000004U;
break;
case 32U:/* 1/32 */
dataL |= 0x00000008U;
break;
case 64U:/* 1/64 */
dataL |= 0x00000010U;
break;
case 128U:/* 1/128 */
dataL |= 0x00000020U;
break;
case 256U: /* 1/256 */
dataL |= 0x00000040U;
break;
case 512U:/* 1/512 */
dataL |= 0x00000080U;
break;
default:
/* nop */
break;
}
mem_write32(SD_CLK_CTRL, dataL);
mmc_drv_obj.current_freq = (uint32_t)clkDiv;
}
/** Enable/Disable MMC clock
*
* - Pre-conditions:<BR>
* Before enabling the clock for the first time the desired clock frequency must be set with
* emmc_set_clock_freq().
* Berore setting mmc_drv_obj.data_timeout with emmc_set_data_timeout().
*
* - Post-conditions:<BR>
* After this function is called, clock to memory card IF is on/off.
*
* param[in] mode TRUE = clock on, FALSE = clock off
* retval EMMC_SUCCESS succeeded
* retval EMMC_ERR Busy
*/
static EMMC_ERROR_CODE emmc_clock_ctrl(uint32_t mode)
{
uint32_t value;
/* busy check */
if ((mem_read32(SD_INFO2) & SD_INFO2_CBSY) != 0U) {
ERROR("%s:0x%08x\n",__func__,EMMC_ERR_CARD_BUSY);
return EMMC_ERR;
}
if (mode == TRUE) {
/* clock ON */
value = ((mem_read32(SD_CLK_CTRL) | MMC_SD_CLK_START) & SD_CLK_WRITE_MASK);
mem_write32(SD_CLK_CTRL, value); /* on */
mmc_drv_obj.clock_enable = TRUE;
} else {
/* clock OFF */
value = ((mem_read32(SD_CLK_CTRL) & MMC_SD_CLK_STOP) & SD_CLK_WRITE_MASK);
mem_write32(SD_CLK_CTRL, value); /* off */
mmc_drv_obj.clock_enable = FALSE;
}
return EMMC_SUCCESS;
}
/** Calculate Card support frequency.
* TRAN_SPEED defines the clock frequency when not in high speed mode.
*
* - Pre-conditions:<BR>
* CSD data must be stored in mmc_drv_obj.csd_data[].
*
* - Post-conditions:<BR>
* None.
* return Frquency[Hz]
*/
static uint32_t emmc_calc_tran_speed(uint32_t* freq)
{
const uint32_t unit[8U] = {10000U, 100000U, 1000000U, 10000000U, 0U, 0U, 0U, 0U}; /**< frequency unit (1/10) */
const uint32_t mult[16U] = {0U, 10U, 12U, 13U, 15U, 20U, 26U, 30U, 35U, 40U, 45U, 52U, 55U, 60U, 70U, 80U}; /**< multiple factor (x10) */
uint32_t maxFreq = 0U;
uint32_t result = 0U;
uint32_t tran_speed = EMMC_CSD_TRAN_SPEED();
/* tran_speed = 0x32
* unit[tran_speed&0x7] = uint[0x2] = 1000000
* mult[(tran_speed&0x78)>>3] = mult[0x30>>3] = mult[6] = 26
* 1000000 * 26 = 26000000 (26MHz)
*/
maxFreq = unit[tran_speed & EMMC_TRANSPEED_FREQ_UNIT_MASK]
* mult[(tran_speed & EMMC_TRANSPEED_MULT_MASK) >> EMMC_TRANSPEED_MULT_SHIFT];
if (maxFreq == 0U) {
result = 0U;
} else if ( MMC_FREQ_52MHZ <= maxFreq) {
*freq = MMC_52MHZ;
result = 1U;
} else if ( MMC_FREQ_26MHZ <= maxFreq) {
*freq = MMC_26MHZ;
result = 1U;
} else if ( MMC_FREQ_20MHZ <= maxFreq) {
*freq = MMC_20MHZ;
result = 1U;
} else {
*freq = MMC_400KHZ;
result = 1U;
}
return result;
}
/** Calculate read/write timeout.
*
* - Pre-conditions:<BR>
* CSD data must be stored in mmc_drv_obj.csd_data[].
*
* - Post-conditions:<BR>
* set mmc clock.
*
* param[in] freq Base clock Div
* return SD_OPTION Timeout Counter
*/
static uint32_t emmc_set_timeout_register_value(uint32_t freq)
{
uint32_t timeoutCnt = 0U; /* SD_OPTION - Timeout Counter */
switch (freq) {
case 1U:/* SDCLK * 2^27 */
timeoutCnt = 0xE0U;
break;
case 2U:/* SDCLK * 2^27 */
timeoutCnt = 0xE0U;
break;
case 4U:/* SDCLK * 2^26 */
timeoutCnt = 0xD0U;
break;
case 8U:/* SDCLK * 2^25 */
timeoutCnt = 0xC0U;
break;
case 16U:/* SDCLK * 2^24 */
timeoutCnt = 0xB0U;
break;
case 32U:/* SDCLK * 2^23 */
timeoutCnt = 0xA0U;
break;
case 64U:/* SDCLK * 2^22 */
timeoutCnt = 0x90U;
break;
case 128U:/* SDCLK * 2^21 */
timeoutCnt = 0x80U;
break;
case 256U:/* SDCLK * 2^20 */
timeoutCnt = 0x70U;
break;
case 512U:/* SDCLK * 2^19 */
timeoutCnt = 0x60U;
break;
default:
/* nop */
break;
}
return timeoutCnt;
}

View File

@@ -0,0 +1,95 @@
/*******************************************************************************
* DISCLAIMER
* This software is supplied by Renesas Electronics Corporation and is only
* intended for use with Renesas products. No other uses are authorized. This
* software is owned by Renesas Electronics Corporation and is protected under
* all applicable laws, including copyright laws.
* THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING
* THIS SOFTWARE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT
* LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* AND NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED.
* TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY LAW, NEITHER RENESAS
* ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE
* FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR
* ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR ITS AFFILIATES HAVE
* BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
* Renesas reserves the right, without notice, to make changes to this software
* and to discontinue the availability of this software. By using this software,
* you agree to the additional terms and conditions found by accessing the
* following link:
* http://www.renesas.com/disclaimer
* Copyright 2021-2022 Renesas Electronics Corporation All rights reserved.
*******************************************************************************/
/*******************************************************************************
* DESCRIPTION : eMMC multi boot
******************************************************************************/
/******************************************************************************
* @file emmc_multiboot.c
* - Version : 0.04
* @brief data access interface to emmc.
* .
*****************************************************************************/
/******************************************************************************
* History : DD.MM.YYYY Version Description
* : 22.02.2022 0.01 First Release
* : 22.10.2021 0.02 Remove unnecessary code
* : 22.12.2021 0.03 Support static analysis
* : 06.01.2022 0.04 Modify SDHI access from DMA to PIO.
*****************************************************************************/
/* ************************ HEADER (INCLUDE) SECTION *********************** */
#include "emmc_config.h"
#include "emmc_hal.h"
#include "emmc_std.h"
#include "emmc_def.h"
#include "emmc_multiboot.h"
#include "rom_api.h"
#include "types.h"
/* ********************** STRUCTURES, TYPE DEFINITIONS ********************* */
/* ********************** DECLARATION OF EXTERNAL DATA ********************* */
/* ************************** FUNCTION PROTOTYPES ************************** */
uint32_t emmc_check_result(uint32_t result);
/* ********************************* CODE ********************************** */
#if defined(__RH850__)
uint32_t emmc_trans_data(uint32_t next_bootPartition, uintptr_t sourceSct, uintptr_t targetAd, uint32_t sectorSize)
{
EMMC_ERROR_CODE result;
uint32_t rtn_val = EMMC_DEV_ERR;
/* Partition select */
result = emmc_select_partition((EMMC_PARTITION_ID)next_bootPartition);
if (result == EMMC_SUCCESS) {
result = emmc_read_sector((uint32_t *)targetAd, sourceSct, sectorSize, LOADIMAGE_FLAGS_DMA_ENABLE);
}
/* EMMC_ERROR_CODE -> ROM_XX */
rtn_val = emmc_check_result((uint32_t)result);
return rtn_val;
}
#endif /* #if defined(__RH850__) */
uint32_t emmc_check_result(uint32_t result)
{
uint32_t ret = EMMC_DEV_ERR_FAULT_INJECTION;
if (result == EMMC_SUCCESS) {
ret = EMMC_DEV_OK;
} else if (result == EMMC_ERR) {
ret = EMMC_DEV_ERR;
} else { /* other */
ret = EMMC_DEV_ERR_HW;
}
return ret;
}
/* ******************************** END ************************************ */

View File

@@ -0,0 +1,204 @@
/*******************************************************************************
* DISCLAIMER
* This software is supplied by Renesas Electronics Corporation and is only
* intended for use with Renesas products. No other uses are authorized. This
* software is owned by Renesas Electronics Corporation and is protected under
* all applicable laws, including copyright laws.
* THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING
* THIS SOFTWARE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT
* LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* AND NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED.
* TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY LAW, NEITHER RENESAS
* ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE
* FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR
* ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR ITS AFFILIATES HAVE
* BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
* Renesas reserves the right, without notice, to make changes to this software
* and to discontinue the availability of this software. By using this software,
* you agree to the additional terms and conditions found by accessing the
* following link:
* http://www.renesas.com/disclaimer
* Copyright 2021-2022 Renesas Electronics Corporation All rights reserved.
*******************************************************************************/
/*******************************************************************************
* DESCRIPTION : eMMC Read data access driver
******************************************************************************/
/******************************************************************************
* @file emmc_read.c
* - Version : 0.04
* @brief read data access function to emmc.
* .
*****************************************************************************/
/******************************************************************************
* History : DD.MM.YYYY Version Description
* : 22.02.2022 0.01 First Release
* : 22.10.2021 0.02 Remove unnecessary code
* : 22.12.2021 0.03 Support static analysis
* : 06.01.2022 0.04 Modify SDHI access from DMA to PIO.
*****************************************************************************/
/* ************************ HEADER (INCLUDE) SECTION *********************** */
#include "emmc_config.h"
#include "emmc_hal.h"
#include "emmc_std.h"
#include "emmc_registers.h"
#include "emmc_def.h"
#include "log.h"
#include <wdt.h>
/* ***************** MACROS, CONSTANTS, COMPILATION FLAGS ****************** */
#define EMMC_RW_SECTOR_COUNT_MAX 0x0000ffffUL
/* ********************** STRUCTURES, TYPE DEFINITIONS ********************* */
/* ********************** DECLARATION OF EXTERNAL DATA ********************* */
/* ************************** FUNCTION PROTOTYPES ************************** */
static EMMC_ERROR_CODE emmc_multiple_block_read (uint32_t *buff_address_virtual, uint32_t sector_number, uint32_t count, HAL_MEMCARD_DATA_TRANSFER_MODE transfer_mode);
static inline uint32_t get_min_value(uint32_t a, uint32_t b)
{
uint32_t ret = a;
if(b < a)
{
ret = b;
}
return ret;
}
/* ********************************* CODE ********************************** */
/** function of read sector
*
* This function always use block read.
* Single block read is not used.
*
* - Pre-conditions:<BR>
* MMC card is mounted.
*
* - Post-conditions:<BR>
* .
*
* param[in,out] buff_address_virtual virtual address of read data buffer.
* param[in] sector_number data address for MMC device (sector number).
* param[in] count number of sector.
* param[in] transfermode Mode of data transfer, DMA or not DMA.
*/
EMMC_ERROR_CODE emmc_read_sector(uint32_t *buff_address_virtual, uint32_t sector_number, uint32_t count,
uint32_t feature_flags)
{
uint32_t trans_count;
uint32_t remain;
EMMC_ERROR_CODE result = EMMC_ERR;
HAL_MEMCARD_DATA_TRANSFER_MODE transfermode;
/* parameter check */
if (count == 0U) {
ERROR("%s:0x%08x\n",__func__,EMMC_ERR_PARAM);
return EMMC_ERR_PARAM;
}
/* state check */
if (mmc_drv_obj.mount != TRUE) {
ERROR("%s:0x%08x\n",__func__,EMMC_ERR_STATE);
return EMMC_ERR_STATE;
}
/* DMA? */
if ((feature_flags & LOADIMAGE_FLAGS_DMA_ENABLE) != 0U) {
transfermode = HAL_MEMCARD_DMA;
} else {
transfermode = HAL_MEMCARD_NOT_DMA;
}
remain = count;
while (remain != 0U) {
trans_count = get_min_value(remain, EMMC_RW_SECTOR_COUNT_MAX);
result = emmc_multiple_block_read(buff_address_virtual, sector_number, trans_count, transfermode);
if (result != EMMC_SUCCESS) {
return result;
}
buff_address_virtual += (EMMC_BLOCK_LENGTH_DW * trans_count);
sector_number += trans_count;
remain -= trans_count;
wdt_restart();
}
return EMMC_SUCCESS;
}
/** multiple block read
*
* Multiple block read with pre-defined block count.
*
* - Pre-conditions:<BR>
* MMC card is mounted.
*
* - Post-conditions:<BR>
* .
*
* param[in,out] buff_address_virtual virtual address of read data buffer.
* param[in] sector_number data address for MMC device (sector number).
* param[in] count number of sector. (0x1 - 0xffff)
* param[in] transfer_mode Mode of data transfer, DMA or not DMA.
*/
static EMMC_ERROR_CODE emmc_multiple_block_read(uint32_t *buff_address_virtual, uint32_t sector_number, uint32_t count,
HAL_MEMCARD_DATA_TRANSFER_MODE transfer_mode)
{
EMMC_ERROR_CODE result = EMMC_ERR;
/* parameter check */
if ((count > EMMC_RW_SECTOR_COUNT_MAX) || (count == 0U)
|| ((transfer_mode != HAL_MEMCARD_DMA) && (transfer_mode != HAL_MEMCARD_NOT_DMA))) {
ERROR("%s:0x%08x\n",__func__,EMMC_ERR_PARAM);
return EMMC_ERR_PARAM;
}
/* CMD23 */
emmc_make_nontrans_cmd(CMD23_SET_BLOCK_COUNT, count);
result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
if (result != EMMC_SUCCESS) {
return result;
}
mem_write32(SD_SECCNT, count);
mem_write32(SD_STOP, 0x00000100U);
mem_write32(CC_EXT_MODE, (CC_EXT_MODE_CLEAR | CC_EXT_MODE_DMASDRW_ENABLE)); /* SD_BUF Read/Write DMA Transfer enable */
/* CMD18 */
emmc_make_trans_cmd(CMD18_READ_MULTIPLE_BLOCK, sector_number, buff_address_virtual, count << EMMC_SECTOR_SIZE_SHIFT,
HAL_MEMCARD_READ, transfer_mode);
result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
if (result != EMMC_SUCCESS) {
return result; /* CMD18 error code */
}
/* CMD13 */
emmc_make_nontrans_cmd(CMD13_SEND_STATUS, EMMC_RCA << 16U);
result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
if (result != EMMC_SUCCESS) {
return result;
}
/* ready status check */
if ((mmc_drv_obj.r1_card_status & EMMC_R1_READY) == 0U) {
ERROR("%s:0x%08x\n",__func__,EMMC_ERR_CARD_BUSY);
return EMMC_ERR_CARD_BUSY;
}
/* state check */
if (mmc_drv_obj.current_state != EMMC_R1_STATE_TRAN) {
ERROR("%s:0x%08x\n",__func__,EMMC_ERR_CARD_STATE);
return EMMC_ERR_CARD_STATE;
}
return EMMC_SUCCESS;
}
/* ******************************** END ************************************ */

View File

@@ -0,0 +1,301 @@
/*******************************************************************************
* DISCLAIMER
* This software is supplied by Renesas Electronics Corporation and is only
* intended for use with Renesas products. No other uses are authorized. This
* software is owned by Renesas Electronics Corporation and is protected under
* all applicable laws, including copyright laws.
* THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING
* THIS SOFTWARE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT
* LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* AND NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED.
* TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY LAW, NEITHER RENESAS
* ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE
* FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR
* ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR ITS AFFILIATES HAVE
* BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
* Renesas reserves the right, without notice, to make changes to this software
* and to discontinue the availability of this software. By using this software,
* you agree to the additional terms and conditions found by accessing the
* following link:
* http://www.renesas.com/disclaimer
* Copyright 2021-2022 Renesas Electronics Corporation All rights reserved.
*******************************************************************************/
/*******************************************************************************
* DESCRIPTION : eMMC Utility
******************************************************************************/
/******************************************************************************
* @file emmc_utility.c
* - Version : 0.04
* @brief Analysis of SDHI data.
* .
*****************************************************************************/
/******************************************************************************
* History : DD.MM.YYYY Version Description
* : 22.02.2022 0.01 First Release
* : 22.10.2021 0.02 Remove unnecessary code
* : 22.12.2021 0.03 Support static analysis
* : 06.01.2022 0.04 Modify SDHI access from DMA to PIO.
*****************************************************************************/
/* ************************ HEADER (INCLUDE) SECTION *********************** */
#include "emmc_config.h"
#include "emmc_hal.h"
#include "emmc_std.h"
#include "emmc_registers.h"
#include "emmc_def.h"
/* ***************** MACROS, CONSTANTS, COMPILATION FLAGS ****************** */
#define BUSY_SIGNAL (1U << 10U)
static const uint32_t cmd_reg_hw[EMMC_CMD_MAX + 1U] = {
0x00000000U, /* CMD0 */
0x00000701U, /* CMD1 */
0x00000002U, /* CMD2 */
0x00000003U, /* CMD3 */
0x00000004U, /* CMD4 */
0x00000505U, /* CMD5 */
0x00000406U, /* CMD6 */
0x00000007U, /* CMD7 */
0x00001C08U, /* CMD8 */
0x00000009U, /* CMD9 */
0x0000000AU, /* CMD10 */
0x00000000U, /* reserved */
0x0000000CU, /* CMD12 */
0x0000000DU, /* CMD13 */
0x00001C0EU, /* CMD14 */
0x0000000FU, /* CMD15 */
0x00000010U, /* CMD16 */
0x00000011U, /* CMD17 */
0x00007C12U, /* CMD18 */
0x00000C13U, /* CMD19 */
0x00000000U,
0x00001C15U, /* CMD21 */
0x00000000U,
0x00000017U, /* CMD23 */
0x00000018U, /* CMD24 */
0x00006C19U, /* CMD25 */
0x00000C1AU, /* CMD26 */
0x0000001BU, /* CMD27 */
0x0000001CU, /* CMD28 */
0x0000001DU, /* CMD29 */
0x0000001EU, /* CMD30 */
0x00001C1FU, /* CMD31 */
0x00000000U,
0x00000000U,
0x00000000U,
0x00000423U, /* CMD35 */
0x00000424U, /* CMD36 */
0x00000000U,
0x00000026U, /* CMD38 */
0x00000427U, /* CMD39 */
0x00000428U, /* CMD40 : send cmd */
0x00000000U,
0x0000002AU, /* CMD42 */
0x00000000U,
0x00000000U,
0x00000000U,
0x00000000U,
0x00000000U,
0x00000000U,
0x00000C31U,
0x00000000U,
0x00000000U,
0x00000000U,
0x00007C35U,
0x00006C36U,
0x00000037U, /* CMD55 */
0x00000038U, /* CMD56 : Read */
0x00000000U,
0x00000000U,
0x00000000U,
0x00000000U
};
/* ********************** STRUCTURES, TYPE DEFINITIONS ********************* */
/* ********************** DECLARATION OF EXTERNAL DATA ********************* */
/* ************************** FUNCTION PROTOTYPES ************************** */
/* ********************************* CODE ********************************** */
/** make non-transfer command data
*
* Response data buffer is automatically selected.
*
* - Pre-conditions:<BR>
* Clock to memory card IF is enabled.
*
* - Post-conditions:<BR>
* After this function is called, command can be executed.
*
* param[in] cmd command information.
* param[in] arg command argument
* return None.
*/
void emmc_make_nontrans_cmd(HAL_MEMCARD_COMMAND cmd, uint32_t arg)
{
/* command information */
mmc_drv_obj.cmd_info.cmd = cmd;
mmc_drv_obj.cmd_info.arg = arg;
mmc_drv_obj.cmd_info.dir = HAL_MEMCARD_READ;
mmc_drv_obj.cmd_info.hw = cmd_reg_hw[(uint32_t)cmd & HAL_MEMCARD_COMMAND_INDEX_MASK];
/* clear data transfer information */
mmc_drv_obj.trans_size = 0U;
mmc_drv_obj.remain_size = 0U;
mmc_drv_obj.buff_address_virtual = NULL;
mmc_drv_obj.buff_address_physical = NULL;
/* response information */
mmc_drv_obj.response_length = 6U;
switch ((HAL_MEMCARD_RESPONSE_TYPE)((uint32_t)(mmc_drv_obj.cmd_info.cmd) & (uint32_t)HAL_MEMCARD_RESPONSE_TYPE_MASK)) {
case HAL_MEMCARD_RESPONSE_NONE:
mmc_drv_obj.response = (uint32_t *)mmc_drv_obj.response_data;
mmc_drv_obj.response_length = 0U;
break;
case HAL_MEMCARD_RESPONSE_R1:
mmc_drv_obj.response = &mmc_drv_obj.r1_card_status;
break;
case HAL_MEMCARD_RESPONSE_R1b:
mmc_drv_obj.cmd_info.hw |= BUSY_SIGNAL; /* bit10 = R1 busy bit */
mmc_drv_obj.response = &mmc_drv_obj.r1_card_status;
break;
case HAL_MEMCARD_RESPONSE_R2:
mmc_drv_obj.response = (uint32_t *)mmc_drv_obj.response_data;
mmc_drv_obj.response_length = 17U;
break;
case HAL_MEMCARD_RESPONSE_R3:
mmc_drv_obj.response = &mmc_drv_obj.r3_ocr;
break;
case HAL_MEMCARD_RESPONSE_R4:
mmc_drv_obj.response = &mmc_drv_obj.r4_resp;
break;
case HAL_MEMCARD_RESPONSE_R5:
mmc_drv_obj.response = &mmc_drv_obj.r5_resp;
break;
default:
mmc_drv_obj.response = (uint32_t *)mmc_drv_obj.response_data;
break;
}
}
/** Making command information for data transfer command.
*
* - Pre-conditions:<BR>
* None.
*
* - Post-conditions:<BR>
* After this function is called, command can be executed.
*
* param[in] cmd command
* param[in] arg command argument
* param[in] buff_address_virtual Pointer to buffer where data is/will be stored. (virtual address)
* Client is responsible of allocation and deallocation of the buffer.
* param[in] len transfer length in bytes
* param[in] dir direction
* param[in] transfer_mode Mode of data transfer, DMA or not DMA.
* return None.
*/
void emmc_make_trans_cmd(HAL_MEMCARD_COMMAND cmd, uint32_t arg, uint32_t *buff_address_virtual, /* virtual address */
uint32_t len, HAL_MEMCARD_OPERATION dir, HAL_MEMCARD_DATA_TRANSFER_MODE transfer_mode)
{
emmc_make_nontrans_cmd(cmd, arg); /* update common information */
/* for data transfer command */
mmc_drv_obj.cmd_info.dir = dir;
mmc_drv_obj.buff_address_virtual = buff_address_virtual;
mmc_drv_obj.buff_address_physical = buff_address_virtual;
mmc_drv_obj.trans_size = len;
mmc_drv_obj.remain_size = len;
mmc_drv_obj.transfer_mode = transfer_mode;
}
/** Send idle command.
* Function execute CMD0.
*
* - Pre-conditions:<BR>
* Clock to MMC I/F enabled.
*
* - Post-conditions:<BR>
* Card reset to idle or pre-idle state.
*
* param[in] arg CMD0 argument.
* return error code
*/
EMMC_ERROR_CODE emmc_send_idle_cmd(uint32_t arg)
{
EMMC_ERROR_CODE result = EMMC_ERR;
uint32_t freq;
/* initialize state */
mmc_drv_obj.mount = FALSE;
mmc_drv_obj.selected = FALSE;
mmc_drv_obj.during_transfer = FALSE;
mmc_drv_obj.during_dma_transfer = FALSE;
mmc_drv_obj.dma_error_flag = FALSE;
mmc_drv_obj.force_terminate = FALSE;
mmc_drv_obj.state_machine_blocking = FALSE;
mmc_drv_obj.bus_width = HAL_MEMCARD_DATA_WIDTH_1_BIT;
mmc_drv_obj.max_freq = MMC_20MHZ; /* 20MHz */
mmc_drv_obj.current_state = EMMC_R1_STATE_IDLE;
/* CMD0 (MMC clock is current frequency. if Data transfer mode, 20MHz or higher.) */
emmc_make_nontrans_cmd(CMD0_GO_IDLE_STATE, arg); /* CMD0 */
result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
if (result != EMMC_SUCCESS) {
return result;
}
/* change MMC clock(400KHz) */
freq = MMC_400KHZ;
result = emmc_set_request_mmc_clock(&freq);
if (result != EMMC_SUCCESS) {
return result;
}
return EMMC_SUCCESS;
}
/** get bit field data for 16bytes data(CSD register).
*
* - Pre-conditions:<BR>
* .
* - Post-conditions:<BR>
* .
*
* param[in] data 16bytes data.
* param[in] top bit number(top). 128>top
* param[in] bottom bit number(bottom). (0<=bottom<=top)
* return bit field.
*/
uint32_t emmc_bit_field(const uint8_t *data, uint32_t top, uint32_t bottom)
{
uint32_t value;
uint32_t index_top = (uint32_t)(15U - (top >> 3U));
uint32_t index_bottom = (uint32_t)(15U - (bottom >> 3U));
if (index_top == index_bottom) {
value = data[index_top];
} else if ((index_top + 1U) == index_bottom) {
value = (uint32_t)(((uint32_t)data[index_top] << 8U) | data[index_bottom]);
} else if ((index_top + 2U) == index_bottom) {
value = (uint32_t)(
((uint32_t)data[index_top] << 16U) | ((uint32_t)data[index_top + 1U] << 8U) | data[index_top + 2U]);
} else {
value = (uint32_t)(
((uint32_t)data[index_top] << 24U) | ((uint32_t)data[index_top + 1U] << 16U)
| ((uint32_t)data[index_top + 2U] << 8U) | data[index_top + 3U]);
}
value = ((value >> (bottom & 0x07U)) & ((1U << ((top - bottom) + 1U)) - 1U));
return value;
}
/* ******************************** END ************************************ */