Unverified Commit a51443fa authored by Soby Mathew's avatar Soby Mathew Committed by GitHub
Browse files

Merge pull request #1582 from ldts/rcar_gen3/upstream

rcar_gen3: initial support
parents 0059be2d 84433c50
/*
* Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights
* reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "emmc_config.h"
#include "emmc_def.h"
#include "emmc_hal.h"
#include "emmc_registers.h"
#include "emmc_std.h"
#include "rcar_def.h"
#include <mmio.h>
#include <stddef.h>
static EMMC_ERROR_CODE emmc_trans_sector(uint32_t *buff_address_virtual);
uint32_t emmc_interrupt(void)
{
EMMC_ERROR_CODE result;
uint32_t prr_data;
uint32_t cut_ver;
uint32_t end_bit;
prr_data = mmio_read_32((uintptr_t) RCAR_PRR);
cut_ver = prr_data & RCAR_CUT_MASK;
if ((prr_data & RCAR_PRODUCT_MASK) == RCAR_PRODUCT_H3) {
if (cut_ver == RCAR_CUT_VER10) {
end_bit = BIT17;
} else if (cut_ver == RCAR_CUT_VER11) {
end_bit = BIT17;
} else {
end_bit = BIT20;
}
} else if ((prr_data & RCAR_PRODUCT_MASK) == RCAR_PRODUCT_M3) {
if (cut_ver == RCAR_CUT_VER10) {
end_bit = BIT17;
} else {
end_bit = BIT20;
}
} else {
end_bit = BIT20;
}
/* SD_INFO */
mmc_drv_obj.error_info.info1 = GETR_32(SD_INFO1);
mmc_drv_obj.error_info.info2 = GETR_32(SD_INFO2);
/* SD_INFO EVENT */
mmc_drv_obj.int_event1 =
mmc_drv_obj.error_info.info1 & GETR_32(SD_INFO1_MASK);
mmc_drv_obj.int_event2 =
mmc_drv_obj.error_info.info2 & GETR_32(SD_INFO2_MASK);
/* ERR_STS */
mmc_drv_obj.error_info.status1 = GETR_32(SD_ERR_STS1);
mmc_drv_obj.error_info.status2 = GETR_32(SD_ERR_STS2);
/* DM_CM_INFO */
mmc_drv_obj.error_info.dm_info1 = GETR_32(DM_CM_INFO1);
mmc_drv_obj.error_info.dm_info2 = GETR_32(DM_CM_INFO2);
/* DM_CM_INFO EVENT */
mmc_drv_obj.dm_event1 =
mmc_drv_obj.error_info.dm_info1 & GETR_32(DM_CM_INFO1_MASK);
mmc_drv_obj.dm_event2 =
mmc_drv_obj.error_info.dm_info2 & GETR_32(DM_CM_INFO2_MASK);
/* ERR SD_INFO2 */
if ((SD_INFO2_ALL_ERR & mmc_drv_obj.int_event2) != 0) {
SETR_32(SD_INFO1_MASK, 0x00000000U); /* interrupt disable */
SETR_32(SD_INFO2_MASK, SD_INFO2_CLEAR); /* interrupt disable */
SETR_32(SD_INFO1, 0x00000000U); /* interrupt clear */
SETR_32(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)) {
/* BWE */
if (SD_INFO2_BWE & mmc_drv_obj.int_event2) {
SETR_32(SD_INFO2, (GETR_32(SD_INFO2) & ~SD_INFO2_BWE));
}
/* BRE */
else {
SETR_32(SD_INFO2, (GETR_32(SD_INFO2) & ~SD_INFO2_BRE));
}
result = emmc_trans_sector(mmc_drv_obj.buff_address_virtual);
mmc_drv_obj.buff_address_virtual += EMMC_BLOCK_LENGTH;
mmc_drv_obj.remain_size -= EMMC_BLOCK_LENGTH;
if (result != EMMC_SUCCESS) {
/* data transfer error */
emmc_write_error_info(EMMC_FUNCNO_NONE, result);
/* Panic */
SETR_32(SD_INFO1_MASK, 0x00000000U);
SETR_32(SD_INFO2_MASK, SD_INFO2_CLEAR);
SETR_32(SD_INFO1, 0x00000000U);
/* interrupt clear */
SETR_32(SD_INFO2, SD_INFO2_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 occurred */
else if ((BIT16 & mmc_drv_obj.dm_event1) != 0) {
SETR_32(DM_CM_INFO1, 0x00000000U);
SETR_32(DM_CM_INFO2, 0x00000000U);
/* interrupt clear */
SETR_32(SD_INFO2, (GETR_32(SD_INFO2) & ~SD_INFO2_BWE));
/* DM_CM_INFO2: DMA-ch0 error occured */
if ((BIT16 & mmc_drv_obj.dm_event2) != 0) {
mmc_drv_obj.dma_error_flag = TRUE;
} else {
mmc_drv_obj.during_dma_transfer = FALSE;
mmc_drv_obj.during_transfer = FALSE;
}
/* wait next interrupt */
mmc_drv_obj.state_machine_blocking = FALSE;
}
/* DM_CM_INFO1: DMA-ch1 transfer complete or error occured */
else if ((end_bit & mmc_drv_obj.dm_event1) != 0U) {
SETR_32(DM_CM_INFO1, 0x00000000U);
SETR_32(DM_CM_INFO2, 0x00000000U);
/* interrupt clear */
SETR_32(SD_INFO2, (GETR_32(SD_INFO2) & ~SD_INFO2_BRE));
/* DM_CM_INFO2: DMA-ch1 error occured */
if ((BIT17 & mmc_drv_obj.dm_event2) != 0) {
mmc_drv_obj.dma_error_flag = TRUE;
} else {
mmc_drv_obj.during_dma_transfer = FALSE;
mmc_drv_obj.during_transfer = FALSE;
}
/* wait next interrupt */
mmc_drv_obj.state_machine_blocking = FALSE;
}
/* Response end */
else if ((SD_INFO1_INFO0 & mmc_drv_obj.int_event1) != 0) {
/* interrupt clear */
SETR_32(SD_INFO1, (GETR_32(SD_INFO1) & ~SD_INFO1_INFO0));
mmc_drv_obj.state_machine_blocking = FALSE;
}
/* Access end */
else if ((SD_INFO1_INFO2 & mmc_drv_obj.int_event1) != 0) {
/* interrupt clear */
SETR_32(SD_INFO1, (GETR_32(SD_INFO1) & ~SD_INFO1_INFO2));
mmc_drv_obj.state_machine_blocking = FALSE;
} else {
/* nothing to do. */
}
return (uint32_t) 0;
}
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 == 0)) {
return EMMC_ERR_STATE;
}
bufPtrLL = (uint64_t *) buff_address_virtual;
length = mmc_drv_obj.remain_size;
/* data transefer */
for (i = 0; i < (length >> 3); i++) {
/* Write */
if (mmc_drv_obj.cmd_info.dir == HAL_MEMCARD_WRITE) {
SETR_64(SD_BUF0, *bufPtrLL); /* buffer --> FIFO */
}
/* Read */
else {
/* Checks when the read data reaches SD_SIZE. */
/* The BRE bit is cleared at emmc_interrupt function. */
if (((i %
(uint32_t) (EMMC_BLOCK_LENGTH >>
EMMC_BUF_SIZE_SHIFT)) == 0U)
&& (i != 0U)) {
/* BRE check */
while (((GETR_32(SD_INFO2)) & SD_INFO2_BRE) ==
0U) {
/* ERROR check */
if (((GETR_32(SD_INFO2)) &
SD_INFO2_ALL_ERR) != 0U) {
return EMMC_ERR_TRANSFER;
}
}
/* BRE clear */
SETR_32(SD_INFO2,
(uint32_t) (GETR_32(SD_INFO2) &
~SD_INFO2_BRE));
}
*bufPtrLL = GETR_64(SD_BUF0); /* FIFO --> buffer */
}
bufPtrLL++;
}
return EMMC_SUCCESS;
}
/*
* Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <debug.h>
#include <mmio.h>
#include "emmc_config.h"
#include "emmc_hal.h"
#include "emmc_std.h"
#include "emmc_registers.h"
#include "emmc_def.h"
#include "micro_delay.h"
#include "rcar_def.h"
static EMMC_ERROR_CODE emmc_clock_ctrl(uint8_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);
static void emmc_get_partition_access(void);
static void emmc_set_bootpartition(void);
static void emmc_set_bootpartition(void)
{
uint32_t reg;
reg = mmio_read_32(RCAR_PRR) & (RCAR_PRODUCT_MASK | RCAR_CUT_MASK);
if (reg == RCAR_PRODUCT_M3_CUT10) {
mmc_drv_obj.boot_partition_en =
(EMMC_PARTITION_ID) ((mmc_drv_obj.ext_csd_data[179] &
EMMC_BOOT_PARTITION_EN_MASK) >>
EMMC_BOOT_PARTITION_EN_SHIFT);
} else if ((reg == RCAR_PRODUCT_H3_CUT20)
|| (reg == RCAR_PRODUCT_M3_CUT11)) {
mmc_drv_obj.boot_partition_en = mmc_drv_obj.partition_access;
} else {
if ((mmio_read_32(MFISBTSTSR) & MFISBTSTSR_BOOT_PARTITION) !=
0U) {
mmc_drv_obj.boot_partition_en = PARTITION_ID_BOOT_2;
} else {
mmc_drv_obj.boot_partition_en = PARTITION_ID_BOOT_1;
}
}
}
static EMMC_ERROR_CODE emmc_card_init(void)
{
int32_t retry;
uint32_t freq = MMC_400KHZ; /* 390KHz */
EMMC_ERROR_CODE result;
uint32_t resultCalc;
/* state check */
if ((mmc_drv_obj.initialize != TRUE)
|| (mmc_drv_obj.card_power_enable != TRUE)
|| ((GETR_32(SD_INFO2) & SD_INFO2_CBSY) != 0)
) {
emmc_write_error_info(EMMC_FUNCNO_CARD_INIT, EMMC_ERR_STATE);
return EMMC_ERR_STATE;
}
/* clock on (force change) */
mmc_drv_obj.current_freq = 0;
mmc_drv_obj.max_freq = MMC_20MHZ;
result = emmc_set_request_mmc_clock(&freq);
if (result != EMMC_SUCCESS) {
emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT);
return EMMC_ERR;
}
rcar_micro_delay(1000U); /* wait 1ms */
/* Get current access partition */
emmc_get_partition_access();
/* CMD0, arg=0x00000000 */
result = emmc_send_idle_cmd(0x00000000);
if (result != EMMC_SUCCESS) {
emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT);
return result;
}
rcar_micro_delay(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) {
emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT);
return result;
}
if ((mmc_drv_obj.r3_ocr & EMMC_OCR_STATUS_BIT) != 0) {
break; /* card is ready. exit loop */
}
rcar_micro_delay(1000U); /* wait 1ms */
}
if (retry == 0) {
emmc_write_error_info(EMMC_FUNCNO_CARD_INIT, EMMC_ERR_TIMEOUT);
return EMMC_ERR_TIMEOUT;
}
switch (mmc_drv_obj.r3_ocr & EMMC_OCR_ACCESS_MODE_MASK) {
case EMMC_OCR_ACCESS_MODE_SECT:
mmc_drv_obj.access_mode = TRUE; /* sector mode */
break;
default:
/* unknown value */
emmc_write_error_info(EMMC_FUNCNO_CARD_INIT, EMMC_ERR);
return EMMC_ERR;
}
/* CMD2 */
emmc_make_nontrans_cmd(CMD2_ALL_SEND_CID_MMC, 0x00000000);
mmc_drv_obj.response = (uint32_t *) (&mmc_drv_obj.cid_data[0]); /* use CID special buffer */
result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
if (result != EMMC_SUCCESS) {
emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT);
return result;
}
/* CMD3 */
emmc_make_nontrans_cmd(CMD3_SET_RELATIVE_ADDR, EMMC_RCA << 16);
result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
if (result != EMMC_SUCCESS) {
emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT);
return result;
}
/* CMD9 (CSD) */
emmc_make_nontrans_cmd(CMD9_SEND_CSD, EMMC_RCA << 16);
mmc_drv_obj.response = (uint32_t *) (&mmc_drv_obj.csd_data[0]); /* use CSD special buffer */
result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
if (result != EMMC_SUCCESS) {
emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT);
return result;
}
/* card version check */
if (EMMC_CSD_SPEC_VARS() < 4) {
emmc_write_error_info(EMMC_FUNCNO_CARD_INIT,
EMMC_ERR_ILLEGAL_CARD);
return EMMC_ERR_ILLEGAL_CARD;
}
/* CMD7 (select card) */
emmc_make_nontrans_cmd(CMD7_SELECT_CARD, EMMC_RCA << 16);
result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
if (result != EMMC_SUCCESS) {
emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT);
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 == 0) {
emmc_write_error_info(EMMC_FUNCNO_CARD_INIT,
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) {
emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT);
return EMMC_ERR;
}
/* set read/write timeout */
mmc_drv_obj.data_timeout = emmc_set_timeout_register_value(freq);
SETR_32(SD_OPTION,
((GETR_32(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) {
emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT);
return result;
}
/* Transfer Data Length */
SETR_32(SD_SIZE, EMMC_BLOCK_LENGTH);
/* CMD8 (EXT_CSD) */
emmc_make_trans_cmd(CMD8_SEND_EXT_CSD, 0x00000000,
(uint32_t *) (&mmc_drv_obj.ext_csd_data[0]),
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).
*/
emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT);
return result;
}
/* Set boot partition */
emmc_set_bootpartition();
return EMMC_SUCCESS;
}
static EMMC_ERROR_CODE emmc_high_speed(void)
{
uint32_t freq; /**< High speed mode clock frequency */
EMMC_ERROR_CODE result;
uint8_t cardType;
/* state check */
if (mmc_drv_obj.selected != TRUE) {
emmc_write_error_info(EMMC_FUNCNO_HIGH_SPEED, 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) != 0)
freq = MMC_52MHZ;
else if ((cardType & EMMC_EXT_CSD_CARD_TYPE_26MHZ) != 0)
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) {
emmc_write_error_info_func_no(EMMC_FUNCNO_HIGH_SPEED);
return result;
}
mmc_drv_obj.hs_timing = TIMING_HIGH_SPEED; /* High-Speed */
}
/* set mmc clock */
mmc_drv_obj.max_freq = freq;
result = emmc_set_request_mmc_clock(&freq);
if (result != EMMC_SUCCESS) {
emmc_write_error_info_func_no(EMMC_FUNCNO_HIGH_SPEED);
return EMMC_ERR;
}
/* set read/write timeout */
mmc_drv_obj.data_timeout = emmc_set_timeout_register_value(freq);
SETR_32(SD_OPTION,
((GETR_32(SD_OPTION) & ~(SD_OPTION_TIMEOUT_CNT_MASK)) |
mmc_drv_obj.data_timeout));
/* CMD13 */
emmc_make_nontrans_cmd(CMD13_SEND_STATUS, EMMC_RCA << 16);
result =
emmc_exec_cmd(EMMC_R1_ERROR_MASK_WITHOUT_CRC, mmc_drv_obj.response);
if (result != EMMC_SUCCESS) {
emmc_write_error_info_func_no(EMMC_FUNCNO_HIGH_SPEED);
return result;
}
return EMMC_SUCCESS;
}
static EMMC_ERROR_CODE emmc_clock_ctrl(uint8_t mode)
{
uint32_t value;
/* busy check */
if ((GETR_32(SD_INFO2) & SD_INFO2_CBSY) != 0) {
emmc_write_error_info(EMMC_FUNCNO_SET_CLOCK,
EMMC_ERR_CARD_BUSY);
return EMMC_ERR;
}
if (mode == TRUE) {
/* clock ON */
value =
((GETR_32(SD_CLK_CTRL) | MMC_SD_CLK_START) &
SD_CLK_WRITE_MASK);
SETR_32(SD_CLK_CTRL, value); /* on */
mmc_drv_obj.clock_enable = TRUE;
} else {
/* clock OFF */
value =
((GETR_32(SD_CLK_CTRL) & MMC_SD_CLK_STOP) &
SD_CLK_WRITE_MASK);
SETR_32(SD_CLK_CTRL, value); /* off */
mmc_drv_obj.clock_enable = FALSE;
}
return EMMC_SUCCESS;
}
static EMMC_ERROR_CODE emmc_bus_width(uint32_t width)
{
EMMC_ERROR_CODE result = EMMC_ERR;
/* parameter check */
if ((width != 8) && (width != 4) && (width != 1)) {
emmc_write_error_info(EMMC_FUNCNO_BUS_WIDTH, EMMC_ERR_PARAM);
return EMMC_ERR_PARAM;
}
/* state check */
if (mmc_drv_obj.selected != TRUE) {
emmc_write_error_info(EMMC_FUNCNO_BUS_WIDTH, EMMC_ERR_STATE);
return EMMC_ERR_STATE;
}
mmc_drv_obj.bus_width = (HAL_MEMCARD_DATA_WIDTH) (width >> 2); /* 2 = 8bit, 1 = 4bit, 0 =1bit */
/* CMD6 */
emmc_make_nontrans_cmd(CMD6_SWITCH,
(EMMC_SWITCH_BUS_WIDTH_1 |
(mmc_drv_obj.bus_width << 8)));
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:
SETR_32(SD_OPTION,
((GETR_32(SD_OPTION) & ~(BIT15 | BIT13)) | BIT15));
break;
case HAL_MEMCARD_DATA_WIDTH_4_BIT:
SETR_32(SD_OPTION, (GETR_32(SD_OPTION) & ~(BIT15 | BIT13)));
break;
case HAL_MEMCARD_DATA_WIDTH_8_BIT:
SETR_32(SD_OPTION,
((GETR_32(SD_OPTION) & ~(BIT15 | BIT13)) | BIT13));
break;
default:
goto EXIT;
}
/* CMD13 */
emmc_make_nontrans_cmd(CMD13_SEND_STATUS, EMMC_RCA << 16);
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, 0x00000000,
(uint32_t *) (&mmc_drv_obj.ext_csd_data[0]),
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:
emmc_write_error_info(EMMC_FUNCNO_BUS_WIDTH, result);
ERROR("BL2: emmc bus_width error end\n");
return result;
}
EMMC_ERROR_CODE emmc_select_partition(EMMC_PARTITION_ID id)
{
EMMC_ERROR_CODE result;
uint32_t arg;
uint32_t partition_config;
/* state check */
if (mmc_drv_obj.mount != TRUE) {
emmc_write_error_info(EMMC_FUNCNO_NONE, EMMC_ERR_STATE);
return EMMC_ERR_STATE;
}
/* id = PARTITION_ACCESS(Bit[2:0]) */
if ((id & ~PARTITION_ID_MASK) != 0) {
emmc_write_error_info(EMMC_FUNCNO_NONE, 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 & PARTITION_ID_MASK) == id) {
result = EMMC_SUCCESS;
} else {
partition_config =
(uint32_t) ((partition_config & ~PARTITION_ID_MASK) | id);
arg = EMMC_SWITCH_PARTITION_CONFIG | (partition_config << 8);
result = emmc_set_ext_csd(arg);
}
return result;
}
static void set_sd_clk(uint32_t clkDiv)
{
uint32_t dataL;
dataL = (GETR_32(SD_CLK_CTRL) & (~SD_CLK_CTRL_CLKDIV_MASK));
switch (clkDiv) {
case 1:
dataL |= 0x000000FFU;
break; /* 1/1 */
case 2:
dataL |= 0x00000000U;
break; /* 1/2 */
case 4:
dataL |= 0x00000001U;
break; /* 1/4 */
case 8:
dataL |= 0x00000002U;
break; /* 1/8 */
case 16:
dataL |= 0x00000004U;
break; /* 1/16 */
case 32:
dataL |= 0x00000008U;
break; /* 1/32 */
case 64:
dataL |= 0x00000010U;
break; /* 1/64 */
case 128:
dataL |= 0x00000020U;
break; /* 1/128 */
case 256:
dataL |= 0x00000040U;
break; /* 1/256 */
case 512:
dataL |= 0x00000080U;
break; /* 1/512 */
}
SETR_32(SD_CLK_CTRL, dataL);
mmc_drv_obj.current_freq = (uint32_t) clkDiv;
}
static void emmc_get_partition_access(void)
{
uint32_t reg;
EMMC_ERROR_CODE result;
reg = mmio_read_32(RCAR_PRR) & (RCAR_PRODUCT_MASK | RCAR_CUT_MASK);
if ((reg == RCAR_PRODUCT_H3_CUT20) || (reg == RCAR_PRODUCT_M3_CUT11)) {
SETR_32(SD_OPTION, 0x000060EEU); /* 8 bits width */
/* CMD8 (EXT_CSD) */
emmc_make_trans_cmd(CMD8_SEND_EXT_CSD, 0x00000000U,
(uint32_t *) (&mmc_drv_obj.ext_csd_data[0]),
EMMC_MAX_EXT_CSD_LENGTH,
HAL_MEMCARD_READ, HAL_MEMCARD_NOT_DMA);
mmc_drv_obj.get_partition_access_flag = TRUE;
result =
emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
mmc_drv_obj.get_partition_access_flag = FALSE;
if (result == EMMC_SUCCESS) {
mmc_drv_obj.partition_access =
(EMMC_PARTITION_ID) (mmc_drv_obj.ext_csd_data[179]
& PARTITION_ID_MASK);
} else if (result == EMMC_ERR_CMD_TIMEOUT) {
mmc_drv_obj.partition_access = PARTITION_ID_BOOT_1;
} else {
emmc_write_error_info(EMMC_FUNCNO_GET_PERTITION_ACCESS,
result);
panic();
}
SETR_32(SD_OPTION, 0x0000C0EEU); /* Initialize */
}
}
static uint32_t emmc_calc_tran_speed(uint32_t *freq)
{
const uint32_t unit[8] = { 10000, 100000, 1000000, 10000000,
0, 0, 0, 0 }; /**< frequency unit (1/10) */
const uint32_t mult[16] = { 0, 10, 12, 13, 15, 20, 26, 30, 35, 40, 45,
52, 55, 60, 70, 80 };
uint32_t maxFreq;
uint32_t result;
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)
*/
result = 1;
maxFreq =
unit[tran_speed & EMMC_TRANSPEED_FREQ_UNIT_MASK] *
mult[(tran_speed & EMMC_TRANSPEED_MULT_MASK) >>
EMMC_TRANSPEED_MULT_SHIFT];
if (maxFreq == 0) {
result = 0;
} else if (MMC_FREQ_52MHZ <= maxFreq)
*freq = MMC_52MHZ;
else if (MMC_FREQ_26MHZ <= maxFreq)
*freq = MMC_26MHZ;
else if (MMC_FREQ_20MHZ <= maxFreq)
*freq = MMC_20MHZ;
else
*freq = MMC_400KHZ;
return result;
}
static uint32_t emmc_set_timeout_register_value(uint32_t freq)
{
uint32_t timeoutCnt; /* SD_OPTION - Timeout Counter */
switch (freq) {
case 1U:
timeoutCnt = 0xE0U;
break; /* SDCLK * 2^27 */
case 2U:
timeoutCnt = 0xE0U;
break; /* SDCLK * 2^27 */
case 4U:
timeoutCnt = 0xD0U;
break; /* SDCLK * 2^26 */
case 8U:
timeoutCnt = 0xC0U;
break; /* SDCLK * 2^25 */
case 16U:
timeoutCnt = 0xB0U;
break; /* SDCLK * 2^24 */
case 32U:
timeoutCnt = 0xA0U;
break; /* SDCLK * 2^23 */
case 64U:
timeoutCnt = 0x90U;
break; /* SDCLK * 2^22 */
case 128U:
timeoutCnt = 0x80U;
break; /* SDCLK * 2^21 */
case 256U:
timeoutCnt = 0x70U;
break; /* SDCLK * 2^20 */
case 512U:
timeoutCnt = 0x70U;
break; /* SDCLK * 2^20 */
default:
timeoutCnt = 0xE0U;
break; /* SDCLK * 2^27 */
}
return timeoutCnt;
}
EMMC_ERROR_CODE emmc_set_ext_csd(uint32_t arg)
{
EMMC_ERROR_CODE result;
/* 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 << 16);
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[0]),
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;
}
EMMC_ERROR_CODE emmc_set_request_mmc_clock(uint32_t *freq)
{
/* parameter check */
if (freq == NULL) {
emmc_write_error_info(EMMC_FUNCNO_SET_CLOCK, EMMC_ERR_PARAM);
return EMMC_ERR_PARAM;
}
/* state check */
if ((mmc_drv_obj.initialize != TRUE)
|| (mmc_drv_obj.card_power_enable != TRUE)) {
emmc_write_error_info(EMMC_FUNCNO_SET_CLOCK, 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 ((GETR_32(SD_INFO2) & SD_INFO2_CBSY) != 0) {
emmc_write_error_info(EMMC_FUNCNO_SET_CLOCK,
EMMC_ERR_CARD_BUSY);
return EMMC_ERR;
}
set_sd_clk(*freq);
mmc_drv_obj.clock_enable = FALSE;
return emmc_clock_ctrl(TRUE); /* clock on */
}
EMMC_ERROR_CODE rcar_emmc_mount(void)
{
EMMC_ERROR_CODE result;
/* state check */
if ((mmc_drv_obj.initialize != TRUE)
|| (mmc_drv_obj.card_power_enable != TRUE)
|| ((GETR_32(SD_INFO2) & SD_INFO2_CBSY) != 0)
) {
emmc_write_error_info(EMMC_FUNCNO_MOUNT, EMMC_ERR_STATE);
return EMMC_ERR_STATE;
}
/* initialize card (IDLE state --> Transfer state) */
result = emmc_card_init();
if (result != EMMC_SUCCESS) {
emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT);
if (emmc_clock_ctrl(FALSE) != EMMC_SUCCESS) {
/* nothing to do. */
}
return result;
}
/* Switching high speed mode */
result = emmc_high_speed();
if (result != EMMC_SUCCESS) {
emmc_write_error_info_func_no(EMMC_FUNCNO_HIGH_SPEED);
if (emmc_clock_ctrl(FALSE) != EMMC_SUCCESS) {
/* nothing to do. */
}
return result;
}
/* Changing the data bus width */
result = emmc_bus_width(8);
if (result != EMMC_SUCCESS) {
emmc_write_error_info_func_no(EMMC_FUNCNO_BUS_WIDTH);
if (emmc_clock_ctrl(FALSE) != EMMC_SUCCESS) {
/* nothing to do. */
}
return result;
}
/* mount complete */
mmc_drv_obj.mount = TRUE;
return EMMC_SUCCESS;
}
/*
* Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include "emmc_config.h"
#include "emmc_hal.h"
#include "emmc_std.h"
#include "emmc_registers.h"
#include "emmc_def.h"
#define MIN_EMMC(a, b) (((a) < (b)) ? (a) : (b))
#define EMMC_RW_SECTOR_COUNT_MAX 0x0000ffffU
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;
/* parameter check */
if ((count > EMMC_RW_SECTOR_COUNT_MAX)
|| (count == 0)
|| ((transfer_mode != HAL_MEMCARD_DMA)
&& (transfer_mode != HAL_MEMCARD_NOT_DMA))
) {
emmc_write_error_info(EMMC_FUNCNO_READ_SECTOR, 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;
}
SETR_32(SD_SECCNT, count);
SETR_32(SD_STOP, 0x00000100);
SETR_32(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 << 16);
result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
if (result != EMMC_SUCCESS) {
return result;
}
#if RCAR_BL2_DCACHE == 1
if (transfer_mode == HAL_MEMCARD_NOT_DMA) {
flush_dcache_range((uint64_t) buff_address_virtual,
((size_t) count << EMMC_SECTOR_SIZE_SHIFT));
}
#endif /* RCAR_BL2_DCACHE == 1 */
/* ready status check */
if ((mmc_drv_obj.r1_card_status & EMMC_R1_READY) == 0) {
emmc_write_error_info(EMMC_FUNCNO_READ_SECTOR,
EMMC_ERR_CARD_BUSY);
return EMMC_ERR_CARD_BUSY;
}
/* state check */
if (mmc_drv_obj.current_state != EMMC_R1_STATE_TRAN) {
emmc_write_error_info(EMMC_FUNCNO_READ_SECTOR,
EMMC_ERR_CARD_STATE);
return EMMC_ERR_CARD_STATE;
}
return EMMC_SUCCESS;
}
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;
HAL_MEMCARD_DATA_TRANSFER_MODE transfer_mode;
/* parameter check */
if (count == 0) {
emmc_write_error_info(EMMC_FUNCNO_READ_SECTOR, EMMC_ERR_PARAM);
return EMMC_ERR_PARAM;
}
/* state check */
if (mmc_drv_obj.mount != TRUE) {
emmc_write_error_info(EMMC_FUNCNO_READ_SECTOR, EMMC_ERR_STATE);
return EMMC_ERR_STATE;
}
/* DMA? */
if ((feature_flags & LOADIMAGE_FLAGS_DMA_ENABLE) != 0) {
transfer_mode = HAL_MEMCARD_DMA;
} else {
transfer_mode = HAL_MEMCARD_NOT_DMA;
}
remain = count;
while (remain != 0) {
trans_count = MIN_EMMC(remain, EMMC_RW_SECTOR_COUNT_MAX);
result =
emmc_multiple_block_read(buff_address_virtual,
sector_number, trans_count,
transfer_mode);
if (result != EMMC_SUCCESS) {
return result;
}
buff_address_virtual += (EMMC_BLOCK_LENGTH_DW * trans_count);
sector_number += trans_count;
remain -= trans_count;
}
return EMMC_SUCCESS;
}
/*
* Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/**
* @file emmc_registers.h
* @brief emmc boot driver is expecting this header file. HS-MMC module header file.
*
*/
#ifndef __EMMC_REGISTERS_H__
#define __EMMC_REGISTERS_H__
/* ************************ HEADER (INCLUDE) SECTION *********************** */
/* ***************** MACROS, CONSTANTS, COMPILATION FLAGS ****************** */
/* MMC channel select */
#define MMC_CH0 (0U) /* SDHI2/MMC0 */
#define MMC_CH1 (1U) /* SDHI3/MMC1 */
#if RCAR_LSI == RCAR_E3
#define USE_MMC_CH (MMC_CH1) /* R-Car E3 */
#else /* RCAR_LSI == RCAR_E3 */
#define USE_MMC_CH (MMC_CH0) /* R-Car H3/M3/M3N */
#endif /* RCAR_LSI == RCAR_E3 */
#define BIT0 (0x00000001U)
#define BIT1 (0x00000002U)
#define BIT2 (0x00000004U)
#define BIT3 (0x00000008U)
#define BIT4 (0x00000010U)
#define BIT5 (0x00000020U)
#define BIT6 (0x00000040U)
#define BIT7 (0x00000080U)
#define BIT8 (0x00000100U)
#define BIT9 (0x00000200U)
#define BIT10 (0x00000400U)
#define BIT11 (0x00000800U)
#define BIT12 (0x00001000U)
#define BIT13 (0x00002000U)
#define BIT14 (0x00004000U)
#define BIT15 (0x00008000U)
#define BIT16 (0x00010000U)
#define BIT17 (0x00020000U)
#define BIT18 (0x00040000U)
#define BIT19 (0x00080000U)
#define BIT20 (0x00100000U)
#define BIT21 (0x00200000U)
#define BIT22 (0x00400000U)
#define BIT23 (0x00800000U)
#define BIT24 (0x01000000U)
#define BIT25 (0x02000000U)
#define BIT26 (0x04000000U)
#define BIT27 (0x08000000U)
#define BIT28 (0x10000000U)
#define BIT29 (0x20000000U)
#define BIT30 (0x40000000U)
#define BIT31 (0x80000000U)
/** @brief Clock Pulse Generator (CPG) registers
*/
#define CPG_BASE (0xE6150000U)
#define CPG_MSTPSR3 (CPG_BASE+0x0048U) /* Module stop status register 3 */
#define CPG_SMSTPCR3 (CPG_BASE+0x013CU) /* System module stop control register 3 */
#define CPG_SD2CKCR (CPG_BASE+0x0268U) /* SDHI2 clock frequency control register */
#define CPG_SD3CKCR (CPG_BASE+0x026CU) /* SDHI3 clock frequency control register */
#define CPG_CPGWPR (CPG_BASE+0x0900U) /* CPG Write Protect Register */
#if USE_MMC_CH == MMC_CH0
#define CPG_SDxCKCR (CPG_SD2CKCR) /* SDHI2/MMC0 */
#else /* USE_MMC_CH == MMC_CH0 */
#define CPG_SDxCKCR (CPG_SD3CKCR) /* SDHI3/MMC1 */
#endif /* USE_MMC_CH == MMC_CH0 */
/** Boot Status register
*/
#define MFISBTSTSR (0xE6260604U)
#define MFISBTSTSR_BOOT_PARTITION (0x00000010U)
/** brief eMMC registers
*/
#define MMC0_SD_BASE (0xEE140000U)
#define MMC1_SD_BASE (0xEE160000U)
#if USE_MMC_CH == MMC_CH0
#define MMC_SD_BASE (MMC0_SD_BASE)
#else /* USE_MMC_CH == MMC_CH0 */
#define MMC_SD_BASE (MMC1_SD_BASE)
#endif /* USE_MMC_CH == MMC_CH0 */
#define SD_CMD (MMC_SD_BASE + 0x0000U)
#define SD_PORTSEL (MMC_SD_BASE + 0x0008U)
#define SD_ARG (MMC_SD_BASE + 0x0010U)
#define SD_ARG1 (MMC_SD_BASE + 0x0018U)
#define SD_STOP (MMC_SD_BASE + 0x0020U)
#define SD_SECCNT (MMC_SD_BASE + 0x0028U)
#define SD_RSP10 (MMC_SD_BASE + 0x0030U)
#define SD_RSP1 (MMC_SD_BASE + 0x0038U)
#define SD_RSP32 (MMC_SD_BASE + 0x0040U)
#define SD_RSP3 (MMC_SD_BASE + 0x0048U)
#define SD_RSP54 (MMC_SD_BASE + 0x0050U)
#define SD_RSP5 (MMC_SD_BASE + 0x0058U)
#define SD_RSP76 (MMC_SD_BASE + 0x0060U)
#define SD_RSP7 (MMC_SD_BASE + 0x0068U)
#define SD_INFO1 (MMC_SD_BASE + 0x0070U)
#define SD_INFO2 (MMC_SD_BASE + 0x0078U)
#define SD_INFO1_MASK (MMC_SD_BASE + 0x0080U)
#define SD_INFO2_MASK (MMC_SD_BASE + 0x0088U)
#define SD_CLK_CTRL (MMC_SD_BASE + 0x0090U)
#define SD_SIZE (MMC_SD_BASE + 0x0098U)
#define SD_OPTION (MMC_SD_BASE + 0x00A0U)
#define SD_ERR_STS1 (MMC_SD_BASE + 0x00B0U)
#define SD_ERR_STS2 (MMC_SD_BASE + 0x00B8U)
#define SD_BUF0 (MMC_SD_BASE + 0x00C0U)
#define SDIO_MODE (MMC_SD_BASE + 0x00D0U)
#define SDIO_INFO1 (MMC_SD_BASE + 0x00D8U)
#define SDIO_INFO1_MASK (MMC_SD_BASE + 0x00E0U)
#define CC_EXT_MODE (MMC_SD_BASE + 0x0360U)
#define SOFT_RST (MMC_SD_BASE + 0x0380U)
#define VERSION (MMC_SD_BASE + 0x0388U)
#define HOST_MODE (MMC_SD_BASE + 0x0390U)
#define DM_CM_DTRAN_MODE (MMC_SD_BASE + 0x0820U)
#define DM_CM_DTRAN_CTRL (MMC_SD_BASE + 0x0828U)
#define DM_CM_RST (MMC_SD_BASE + 0x0830U)
#define DM_CM_INFO1 (MMC_SD_BASE + 0x0840U)
#define DM_CM_INFO1_MASK (MMC_SD_BASE + 0x0848U)
#define DM_CM_INFO2 (MMC_SD_BASE + 0x0850U)
#define DM_CM_INFO2_MASK (MMC_SD_BASE + 0x0858U)
#define DM_DTRAN_ADDR (MMC_SD_BASE + 0x0880U)
/** @brief SD_INFO1 Registers
*/
#define SD_INFO1_HPIRES 0x00010000UL /* Response Reception Completion */
#define SD_INFO1_INFO10 0x00000400UL /* Indicates the SDDAT3 state */
#define SD_INFO1_INFO9 0x00000200UL /* SDDAT3 Card Insertion */
#define SD_INFO1_INFO8 0x00000100UL /* SDDAT3 Card Removal */
#define SD_INFO1_INFO7 0x00000080UL /* Write Protect */
#define SD_INFO1_INFO5 0x00000020UL /* Indicates the ISDCD state */
#define SD_INFO1_INFO4 0x00000010UL /* ISDCD Card Insertion */
#define SD_INFO1_INFO3 0x00000008UL /* ISDCD Card Removal */
#define SD_INFO1_INFO2 0x00000004UL /* Access end */
#define SD_INFO1_INFO0 0x00000001UL /* Response end */
/** @brief SD_INFO2 Registers
*/
#define SD_INFO2_ILA 0x00008000UL /* Illegal Access Error */
#define SD_INFO2_CBSY 0x00004000UL /* Command Type Register Busy */
#define SD_INFO2_SCLKDIVEN 0x00002000UL
#define SD_INFO2_BWE 0x00000200UL /* SD_BUF Write Enable */
#define SD_INFO2_BRE 0x00000100UL /* SD_BUF Read Enable */
#define SD_INFO2_DAT0 0x00000080UL /* SDDAT0 */
#define SD_INFO2_ERR6 0x00000040UL /* Response Timeout */
#define SD_INFO2_ERR5 0x00000020UL /* SD_BUF Illegal Read Access */
#define SD_INFO2_ERR4 0x00000010UL /* SD_BUF Illegal Write Access */
#define SD_INFO2_ERR3 0x00000008UL /* Data Timeout */
#define SD_INFO2_ERR2 0x00000004UL /* END Error */
#define SD_INFO2_ERR1 0x00000002UL /* CRC Error */
#define SD_INFO2_ERR0 0x00000001UL /* CMD Error */
#define SD_INFO2_ALL_ERR 0x0000807FUL
#define SD_INFO2_CLEAR 0x00000800UL /* BIT11 The write value should always be 1. HWM_0003 */
/** @brief SOFT_RST
*/
#define SOFT_RST_SDRST 0x00000001UL
/** @brief SD_CLK_CTRL
*/
#define SD_CLK_CTRL_SDCLKOFFEN 0x00000200UL
#define SD_CLK_CTRL_SCLKEN 0x00000100UL
#define SD_CLK_CTRL_CLKDIV_MASK 0x000000FFUL
#define SD_CLOCK_ENABLE 0x00000100UL
#define SD_CLOCK_DISABLE 0x00000000UL
#define SD_CLK_WRITE_MASK 0x000003FFUL
#define SD_CLK_CLKDIV_CLEAR_MASK 0xFFFFFF0FUL
/** @brief SD_OPTION
*/
#define SD_OPTION_TIMEOUT_CNT_MASK 0x000000F0UL
/** @brief MMC Clock Frequency
* 200MHz * 1/x = output clock
*/
#define MMC_CLK_OFF 0UL /* Clock output is disabled */
#define MMC_400KHZ 512UL /* 200MHz * 1/512 = 390 KHz */
#define MMC_20MHZ 16UL /* 200MHz * 1/16 = 12.5 MHz Normal speed mode */
#define MMC_26MHZ 8UL /* 200MHz * 1/8 = 25 MHz High speed mode 26Mhz */
#define MMC_52MHZ 4UL /* 200MHz * 1/4 = 50 MHz High speed mode 52Mhz */
#define MMC_100MHZ 2UL /* 200MHz * 1/2 = 100 MHz */
#define MMC_200MHZ 1UL /* 200MHz * 1/1 = 200 MHz */
#define MMC_FREQ_52MHZ 52000000UL
#define MMC_FREQ_26MHZ 26000000UL
#define MMC_FREQ_20MHZ 20000000UL
/** @brief MMC Clock DIV
*/
#define MMC_SD_CLK_START 0x00000100UL /* CLOCK On */
#define MMC_SD_CLK_STOP (~0x00000100UL) /* CLOCK stop */
#define MMC_SD_CLK_DIV1 0x000000FFUL /* 1/1 */
#define MMC_SD_CLK_DIV2 0x00000000UL /* 1/2 */
#define MMC_SD_CLK_DIV4 0x00000001UL /* 1/4 */
#define MMC_SD_CLK_DIV8 0x00000002UL /* 1/8 */
#define MMC_SD_CLK_DIV16 0x00000004UL /* 1/16 */
#define MMC_SD_CLK_DIV32 0x00000008UL /* 1/32 */
#define MMC_SD_CLK_DIV64 0x00000010UL /* 1/64 */
#define MMC_SD_CLK_DIV128 0x00000020UL /* 1/128 */
#define MMC_SD_CLK_DIV256 0x00000040UL /* 1/256 */
#define MMC_SD_CLK_DIV512 0x00000080UL /* 1/512 */
/** @brief DM_CM_DTRAN_MODE
*/
#define DM_CM_DTRAN_MODE_CH0 0x00000000UL /* CH0(downstream) */
#define DM_CM_DTRAN_MODE_CH1 0x00010000UL /* CH1(upstream) */
#define DM_CM_DTRAN_MODE_BIT_WIDTH 0x00000030UL
/** @brief CC_EXT_MODE
*/
#define CC_EXT_MODE_DMASDRW_ENABLE 0x00000002UL /* SD_BUF Read/Write DMA Transfer */
#define CC_EXT_MODE_CLEAR 0x00001010UL /* BIT 12 & 4 always 1. */
/** @brief DM_CM_INFO_MASK
*/
#define DM_CM_INFO_MASK_CLEAR 0xFFFCFFFEUL
#define DM_CM_INFO_CH0_ENABLE 0x00010001UL
#define DM_CM_INFO_CH1_ENABLE 0x00020001UL
/** @brief DM_DTRAN_ADDR
*/
#define DM_DTRAN_ADDR_WRITE_MASK 0xFFFFFFF8UL
/** @brief DM_CM_DTRAN_CTRL
*/
#define DM_CM_DTRAN_CTRL_START 0x00000001UL
/** @brief SYSC Registers
*/
#if USE_MMC_CH == MMC_CH0
#define CPG_MSTP_MMC (BIT12) /* SDHI2/MMC0 */
#else /* USE_MMC_CH == MMC_CH0 */
#define CPG_MSTP_MMC (BIT11) /* SDHI3/MMC1 */
#endif /* USE_MMC_CH == MMC_CH0 */
/* ********************** STRUCTURES, TYPE DEFINITIONS ********************* */
/* ********************** DECLARATION OF EXTERNAL DATA ********************* */
/* ************************** FUNCTION PROTOTYPES ************************** */
/* ********************************* CODE ********************************** */
#endif /* __EMMC_REGISTERS_H__ */
/* ******************************** END ************************************ */
/*
* Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/**
* @file emmc_std.h
* @brief eMMC boot is expecting this header file
*
*/
#ifndef __EMMC_STD_H__
#define __EMMC_STD_H__
#include "emmc_hal.h"
/* ************************ HEADER (INCLUDE) SECTION *********************** */
/* ***************** MACROS, CONSTANTS, COMPILATION FLAGS ****************** */
#ifndef FALSE
#define FALSE 0U
#endif
#ifndef TRUE
#define TRUE 1U
#endif
/** @brief 64bit registers
**/
#define SETR_64(r, v) (*(volatile uint64_t *)(r) = (v))
#define GETR_64(r) (*(volatile uint64_t *)(r))
/** @brief 32bit registers
**/
#define SETR_32(r, v) (*(volatile uint32_t *)(r) = (v))
#define GETR_32(r) (*(volatile uint32_t *)(r))
/** @brief 16bit registers
*/
#define SETR_16(r, v) (*(volatile uint16_t *)(r) = (v))
#define GETR_16(r) (*(volatile uint16_t *)(r))
/** @brief 8bit registers
*/
#define SETR_8(r, v) (*(volatile uint8_t *)(r) = (v))
#define GETR_8(r) (*(volatile uint8_t *)(r))
/** @brief CSD register Macros
*/
#define EMMC_GET_CID(x, y) (emmc_bit_field(mmc_drv_obj.cid_data, (x), (y)))
#define EMMC_CID_MID() (EMMC_GET_CID(127, 120))
#define EMMC_CID_CBX() (EMMC_GET_CID(113, 112))
#define EMMC_CID_OID() (EMMC_GET_CID(111, 104))
#define EMMC_CID_PNM1() (EMMC_GET_CID(103, 88))
#define EMMC_CID_PNM2() (EMMC_GET_CID(87, 56))
#define EMMC_CID_PRV() (EMMC_GET_CID(55, 48))
#define EMMC_CID_PSN() (EMMC_GET_CID(47, 16))
#define EMMC_CID_MDT() (EMMC_GET_CID(15, 8))
#define EMMC_CID_CRC() (EMMC_GET_CID(7, 1))
/** @brief CSD register Macros
*/
#define EMMC_GET_CSD(x, y) (emmc_bit_field(mmc_drv_obj.csd_data, (x), (y)))
#define EMMC_CSD_CSD_STRUCTURE() (EMMC_GET_CSD(127, 126))
#define EMMC_CSD_SPEC_VARS() (EMMC_GET_CSD(125, 122))
#define EMMC_CSD_TAAC() (EMMC_GET_CSD(119, 112))
#define EMMC_CSD_NSAC() (EMMC_GET_CSD(111, 104))
#define EMMC_CSD_TRAN_SPEED() (EMMC_GET_CSD(103, 96))
#define EMMC_CSD_CCC() (EMMC_GET_CSD(95, 84))
#define EMMC_CSD_READ_BL_LEN() (EMMC_GET_CSD(83, 80))
#define EMMC_CSD_READ_BL_PARTIAL() (EMMC_GET_CSD(79, 79))
#define EMMC_CSD_WRITE_BLK_MISALIGN() (EMMC_GET_CSD(78, 78))
#define EMMC_CSD_READ_BLK_MISALIGN() (EMMC_GET_CSD(77, 77))
#define EMMC_CSD_DSR_IMP() (EMMC_GET_CSD(76, 76))
#define EMMC_CSD_C_SIZE() (EMMC_GET_CSD(73, 62))
#define EMMC_CSD_VDD_R_CURR_MIN() (EMMC_GET_CSD(61, 59))
#define EMMC_CSD_VDD_R_CURR_MAX() (EMMC_GET_CSD(58, 56))
#define EMMC_CSD_VDD_W_CURR_MIN() (EMMC_GET_CSD(55, 53))
#define EMMC_CSD_VDD_W_CURR_MAX() (EMMC_GET_CSD(52, 50))
#define EMMC_CSD_C_SIZE_MULT() (EMMC_GET_CSD(49, 47))
#define EMMC_CSD_ERASE_GRP_SIZE() (EMMC_GET_CSD(46, 42))
#define EMMC_CSD_ERASE_GRP_MULT() (EMMC_GET_CSD(41, 37))
#define EMMC_CSD_WP_GRP_SIZE() (EMMC_GET_CSD(36, 32))
#define EMMC_CSD_WP_GRP_ENABLE() (EMMC_GET_CSD(31, 31))
#define EMMC_CSD_DEFALT_ECC() (EMMC_GET_CSD(30, 29))
#define EMMC_CSD_R2W_FACTOR() (EMMC_GET_CSD(28, 26))
#define EMMC_CSD_WRITE_BL_LEN() (EMMC_GET_CSD(25, 22))
#define EMMC_CSD_WRITE_BL_PARTIAL() (EMMC_GET_CSD(21, 21))
#define EMMC_CSD_CONTENT_PROT_APP() (EMMC_GET_CSD(16, 16))
#define EMMC_CSD_FILE_FORMAT_GRP() (EMMC_GET_CSD(15, 15))
#define EMMC_CSD_COPY() (EMMC_GET_CSD(14, 14))
#define EMMC_CSD_PERM_WRITE_PROTECT() (EMMC_GET_CSD(13, 13))
#define EMMC_CSD_TMP_WRITE_PROTECT() (EMMC_GET_CSD(12, 12))
#define EMMC_CSD_FILE_FORMAT() (EMMC_GET_CSD(11, 10))
#define EMMC_CSD_ECC() (EMMC_GET_CSD(9, 8))
#define EMMC_CSD_CRC() (EMMC_GET_CSD(7, 1))
/** @brief for sector access
*/
#define EMMC_4B_BOUNDARY_CHECK_MASK 0x00000003
#define EMMC_SECTOR_SIZE_SHIFT 9U /* 512 = 2^9 */
#define EMMC_SECTOR_SIZE 512
#define EMMC_BLOCK_LENGTH 512
#define EMMC_BLOCK_LENGTH_DW 128
#define EMMC_BUF_SIZE_SHIFT 3U /* 8byte = 2^3 */
/** @brief eMMC specification clock
*/
#define EMMC_CLOCK_SPEC_400K 400000UL /**< initialize clock 400KHz */
#define EMMC_CLOCK_SPEC_20M 20000000UL /**< normal speed 20MHz */
#define EMMC_CLOCK_SPEC_26M 26000000UL /**< high speed 26MHz */
#define EMMC_CLOCK_SPEC_52M 52000000UL /**< high speed 52MHz */
#define EMMC_CLOCK_SPEC_100M 100000000UL /**< high speed 100MHz */
/** @brief EMMC driver error code. (extended HAL_MEMCARD_RETURN)
*/
typedef enum {
EMMC_ERR = 0, /**< unknown error */
EMMC_SUCCESS, /**< OK */
EMMC_ERR_FROM_DMAC, /**< DMAC allocation error */
EMMC_ERR_FROM_DMAC_TRANSFER, /**< DMAC transfer error */
EMMC_ERR_CARD_STATUS_BIT, /**< card status error. Non-masked error bit was set in the card status */
EMMC_ERR_CMD_TIMEOUT, /**< command timeout error */
EMMC_ERR_DATA_TIMEOUT, /**< data timeout error */
EMMC_ERR_CMD_CRC, /**< command CRC error */
EMMC_ERR_DATA_CRC, /**< data CRC error */
EMMC_ERR_PARAM, /**< parameter error */
EMMC_ERR_RESPONSE, /**< response error */
EMMC_ERR_RESPONSE_BUSY, /**< response busy error */
EMMC_ERR_TRANSFER, /**< data transfer error */
EMMC_ERR_READ_SECTOR, /**< read sector error */
EMMC_ERR_WRITE_SECTOR, /**< write sector error */
EMMC_ERR_STATE, /**< state error */
EMMC_ERR_TIMEOUT, /**< timeout error */
EMMC_ERR_ILLEGAL_CARD, /**< illegal card */
EMMC_ERR_CARD_BUSY, /**< Busy state */
EMMC_ERR_CARD_STATE, /**< card state error */
EMMC_ERR_SET_TRACE, /**< trace information error */
EMMC_ERR_FROM_TIMER, /**< Timer error */
EMMC_ERR_FORCE_TERMINATE, /**< Force terminate */
EMMC_ERR_CARD_POWER, /**< card power fail */
EMMC_ERR_ERASE_SECTOR, /**< erase sector error */
EMMC_ERR_INFO2 /**< exec cmd error info2 */
} EMMC_ERROR_CODE;
/** @brief Function number */
#define EMMC_FUNCNO_NONE 0U
#define EMMC_FUNCNO_DRIVER_INIT 1U
#define EMMC_FUNCNO_CARD_POWER_ON 2U
#define EMMC_FUNCNO_MOUNT 3U
#define EMMC_FUNCNO_CARD_INIT 4U
#define EMMC_FUNCNO_HIGH_SPEED 5U
#define EMMC_FUNCNO_BUS_WIDTH 6U
#define EMMC_FUNCNO_MULTI_BOOT_SELECT_PARTITION 7U
#define EMMC_FUNCNO_MULTI_BOOT_READ_SECTOR 8U
#define EMMC_FUNCNO_TRANS_DATA_READ_SECTOR 9U
#define EMMC_FUNCNO_UBOOT_IMAGE_SELECT_PARTITION 10U
#define EMMC_FUNCNO_UBOOT_IMAGE_READ_SECTOR 11U
#define EMMC_FUNCNO_SET_CLOCK 12U
#define EMMC_FUNCNO_EXEC_CMD 13U
#define EMMC_FUNCNO_READ_SECTOR 14U
#define EMMC_FUNCNO_WRITE_SECTOR 15U
#define EMMC_FUNCNO_ERASE_SECTOR 16U
#define EMMC_FUNCNO_GET_PERTITION_ACCESS 17U
/** @brief Response
*/
/** R1 */
#define EMMC_R1_ERROR_MASK 0xFDBFE080U /* Type 'E' bit and bit14(must be 0). ignore bit22 */
#define EMMC_R1_ERROR_MASK_WITHOUT_CRC (0xFD3FE080U) /* Ignore bit23 (Not check CRC error) */
#define EMMC_R1_STATE_MASK 0x00001E00U /* [12:9] */
#define EMMC_R1_READY 0x00000100U /* bit8 */
#define EMMC_R1_STATE_SHIFT 9
/** R4 */
#define EMMC_R4_RCA_MASK 0xFFFF0000UL
#define EMMC_R4_STATUS 0x00008000UL
/** CSD */
#define EMMC_TRANSPEED_FREQ_UNIT_MASK 0x07 /* bit[2:0] */
#define EMMC_TRANSPEED_FREQ_UNIT_SHIFT 0
#define EMMC_TRANSPEED_MULT_MASK 0x78 /* bit[6:3] */
#define EMMC_TRANSPEED_MULT_SHIFT 3
/** OCR */
#define EMMC_HOST_OCR_VALUE 0x40FF8080
#define EMMC_OCR_STATUS_BIT 0x80000000L /* Card power up status bit */
#define EMMC_OCR_ACCESS_MODE_MASK 0x60000000L /* bit[30:29] */
#define EMMC_OCR_ACCESS_MODE_SECT 0x40000000L
#define EMMC_OCR_ACCESS_MODE_BYTE 0x00000000L
/** EXT_CSD */
#define EMMC_EXT_CSD_S_CMD_SET 504
#define EMMC_EXT_CSD_INI_TIMEOUT_AP 241
#define EMMC_EXT_CSD_PWR_CL_DDR_52_360 239
#define EMMC_EXT_CSD_PWR_CL_DDR_52_195 238
#define EMMC_EXT_CSD_MIN_PERF_DDR_W_8_52 235
#define EMMC_EXT_CSD_MIN_PERF_DDR_R_8_52 234
#define EMMC_EXT_CSD_TRIM_MULT 232
#define EMMC_EXT_CSD_SEC_FEATURE_SUPPORT 231
#define EMMC_EXT_CSD_SEC_ERASE_MULT 229
#define EMMC_EXT_CSD_BOOT_INFO 228
#define EMMC_EXT_CSD_BOOT_SIZE_MULTI 226
#define EMMC_EXT_CSD_ACC_SIZE 225
#define EMMC_EXT_CSD_HC_ERASE_GRP_SIZE 224
#define EMMC_EXT_CSD_ERASE_TIMEOUT_MULT 223
#define EMMC_EXT_CSD_PEL_WR_SEC_C 222
#define EMMC_EXT_CSD_HC_WP_GRP_SIZE 221
#define EMMC_EXT_CSD_S_C_VCC 220
#define EMMC_EXT_CSD_S_C_VCCQ 219
#define EMMC_EXT_CSD_S_A_TIMEOUT 217
#define EMMC_EXT_CSD_SEC_COUNT 215
#define EMMC_EXT_CSD_MIN_PERF_W_8_52 210
#define EMMC_EXT_CSD_MIN_PERF_R_8_52 209
#define EMMC_EXT_CSD_MIN_PERF_W_8_26_4_52 208
#define EMMC_EXT_CSD_MIN_PERF_R_8_26_4_52 207
#define EMMC_EXT_CSD_MIN_PERF_W_4_26 206
#define EMMC_EXT_CSD_MIN_PERF_R_4_26 205
#define EMMC_EXT_CSD_PWR_CL_26_360 203
#define EMMC_EXT_CSD_PWR_CL_52_360 202
#define EMMC_EXT_CSD_PWR_CL_26_195 201
#define EMMC_EXT_CSD_PWR_CL_52_195 200
#define EMMC_EXT_CSD_CARD_TYPE 196
#define EMMC_EXT_CSD_CSD_STRUCTURE 194
#define EMMC_EXT_CSD_EXT_CSD_REV 192
#define EMMC_EXT_CSD_CMD_SET 191
#define EMMC_EXT_CSD_CMD_SET_REV 189
#define EMMC_EXT_CSD_POWER_CLASS 187
#define EMMC_EXT_CSD_HS_TIMING 185
#define EMMC_EXT_CSD_BUS_WIDTH 183
#define EMMC_EXT_CSD_ERASED_MEM_CONT 181
#define EMMC_EXT_CSD_PARTITION_CONFIG 179
#define EMMC_EXT_CSD_BOOT_CONFIG_PROT 178
#define EMMC_EXT_CSD_BOOT_BUS_WIDTH 177
#define EMMC_EXT_CSD_ERASE_GROUP_DEF 175
#define EMMC_EXT_CSD_BOOT_WP 173
#define EMMC_EXT_CSD_USER_WP 171
#define EMMC_EXT_CSD_FW_CONFIG 169
#define EMMC_EXT_CSD_RPMB_SIZE_MULT 168
#define EMMC_EXT_CSD_RST_n_FUNCTION 162
#define EMMC_EXT_CSD_PARTITIONING_SUPPORT 160
#define EMMC_EXT_CSD_MAX_ENH_SIZE_MULT 159
#define EMMC_EXT_CSD_PARTITIONS_ATTRIBUTE 156
#define EMMC_EXT_CSD_PARTITION_SETTING_COMPLETED 155
#define EMMC_EXT_CSD_GP_SIZE_MULT 154
#define EMMC_EXT_CSD_ENH_SIZE_MULT 142
#define EMMC_EXT_CSD_ENH_START_ADDR 139
#define EMMC_EXT_CSD_SEC_BAD_BLK_MGMNT 134
#define EMMC_EXT_CSD_CARD_TYPE_26MHZ 0x01
#define EMMC_EXT_CSD_CARD_TYPE_52MHZ 0x02
#define EMMC_EXT_CSD_CARD_TYPE_DDR_52MHZ_12V 0x04
#define EMMC_EXT_CSD_CARD_TYPE_DDR_52MHZ_18V 0x08
#define EMMC_EXT_CSD_CARD_TYPE_52MHZ_MASK 0x0e
/** SWITCH (CMD6) argument */
#define EXTCSD_ACCESS_BYTE (BIT25|BIT24)
#define EXTCSD_SET_BITS BIT24
#define HS_TIMING_ADD (185<<16) /* H'b9 */
#define HS_TIMING_1 (1<<8)
#define HS_TIMING_HS200 (2<<8)
#define HS_TIMING_HS400 (3<<8)
#define BUS_WIDTH_ADD (183<<16) /* H'b7 */
#define BUS_WIDTH_1 (0<<8)
#define BUS_WIDTH_4 (1<<8)
#define BUS_WIDTH_8 (2<<8)
#define BUS_WIDTH_4DDR (5<<8)
#define BUS_WIDTH_8DDR (6<<8)
#define EMMC_SWITCH_HS_TIMING (EXTCSD_ACCESS_BYTE|HS_TIMING_ADD|HS_TIMING_1) /**< H'03b90100 */
#define EMMC_SWITCH_HS_TIMING_OFF (EXTCSD_ACCESS_BYTE|HS_TIMING_ADD) /**< H'03b90000 */
#define EMMC_SWITCH_BUS_WIDTH_1 (EXTCSD_ACCESS_BYTE|BUS_WIDTH_ADD|BUS_WIDTH_1) /**< H'03b70000 */
#define EMMC_SWITCH_BUS_WIDTH_4 (EXTCSD_ACCESS_BYTE|BUS_WIDTH_ADD|BUS_WIDTH_4) /**< H'03b70100 */
#define EMMC_SWITCH_BUS_WIDTH_8 (EXTCSD_ACCESS_BYTE|BUS_WIDTH_ADD|BUS_WIDTH_8) /**< H'03b70200 */
#define EMMC_SWITCH_BUS_WIDTH_4DDR (EXTCSD_ACCESS_BYTE|BUS_WIDTH_ADD|BUS_WIDTH_4DDR) /**< H'03b70500 */
#define EMMC_SWITCH_BUS_WIDTH_8DDR (EXTCSD_ACCESS_BYTE|BUS_WIDTH_ADD|BUS_WIDTH_8DDR) /**< H'03b70600 */
#define EMMC_SWITCH_PARTITION_CONFIG 0x03B30000UL /**< Partition config = 0x00 */
#define TIMING_HIGH_SPEED 1UL
#define EMMC_BOOT_PARTITION_EN_MASK 0x38U
#define EMMC_BOOT_PARTITION_EN_SHIFT 3U
/** Bus width */
#define EMMC_BUSWIDTH_1BIT CE_CMD_SET_DATW_1BIT
#define EMMC_BUSWIDTH_4BIT CE_CMD_SET_DATW_4BIT
#define EMMC_BUSWIDTH_8BIT CE_CMD_SET_DATW_8BIT
/** for st_mmc_base */
#define EMMC_MAX_RESPONSE_LENGTH 17
#define EMMC_MAX_CID_LENGTH 16
#define EMMC_MAX_CSD_LENGTH 16
#define EMMC_MAX_EXT_CSD_LENGTH 512U
#define EMMC_RES_REG_ALIGNED 4U
#define EMMC_BUF_REG_ALIGNED 8U
/** @brief for TAAC mask
*/
#define TAAC_TIME_UNIT_MASK (0x07)
#define TAAC_MULTIPLIER_FACTOR_MASK (0x0F)
/* ********************** STRUCTURES, TYPE DEFINITIONS ********************* */
/** @brief Partition id
*/
typedef enum {
PARTITION_ID_USER = 0x0, /**< User Area */
PARTITION_ID_BOOT_1 = 0x1, /**< boot partition 1 */
PARTITION_ID_BOOT_2 = 0x2, /**< boot partition 2 */
PARTITION_ID_RPMB = 0x3, /**< Replay Protected Memory Block */
PARTITION_ID_GP_1 = 0x4, /**< General Purpose partition 1 */
PARTITION_ID_GP_2 = 0x5, /**< General Purpose partition 2 */
PARTITION_ID_GP_3 = 0x6, /**< General Purpose partition 3 */
PARTITION_ID_GP_4 = 0x7, /**< General Purpose partition 4 */
PARTITION_ID_MASK = 0x7 /**< [2:0] */
} EMMC_PARTITION_ID;
/** @brief card state in R1 response [12:9]
*/
typedef enum {
EMMC_R1_STATE_IDLE = 0,
EMMC_R1_STATE_READY,
EMMC_R1_STATE_IDENT,
EMMC_R1_STATE_STBY,
EMMC_R1_STATE_TRAN,
EMMC_R1_STATE_DATA,
EMMC_R1_STATE_RCV,
EMMC_R1_STATE_PRG,
EMMC_R1_STATE_DIS,
EMMC_R1_STATE_BTST,
EMMC_R1_STATE_SLEP
} EMMC_R1_STATE;
typedef enum {
ESTATE_BEGIN = 0,
ESTATE_ISSUE_CMD,
ESTATE_NON_RESP_CMD,
ESTATE_RCV_RESP,
ESTATE_RCV_RESPONSE_BUSY,
ESTATE_CHECK_RESPONSE_COMPLETE,
ESTATE_DATA_TRANSFER,
ESTATE_DATA_TRANSFER_COMPLETE,
ESTATE_ACCESS_END,
ESTATE_TRANSFER_ERROR,
ESTATE_ERROR,
ESTATE_END
} EMMC_INT_STATE;
/** @brief eMMC boot driver error information
*/
typedef struct {
uint16_t num; /**< error no */
uint16_t code; /**< error code */
volatile uint32_t info1; /**< SD_INFO1 register value. (hardware dependence) */
volatile uint32_t info2; /**< SD_INFO2 register value. (hardware dependence) */
volatile uint32_t status1;/**< SD_ERR_STS1 register value. (hardware dependence) */
volatile uint32_t status2;/**< SD_ERR_STS2 register value. (hardware dependence) */
volatile uint32_t dm_info1;/**< DM_CM_INFO1 register value. (hardware dependence) */
volatile uint32_t dm_info2;/**< DM_CM_INFO2 register value. (hardware dependence) */
} st_error_info;
/** @brief Command information
*/
typedef struct {
HAL_MEMCARD_COMMAND cmd; /**< Command information */
uint32_t arg; /**< argument */
HAL_MEMCARD_OPERATION dir; /**< direction */
uint32_t hw; /**< H/W dependence. SD_CMD register value. */
} st_command_info;
/** @brief MMC driver base
*/
typedef struct {
st_error_info error_info; /**< error information */
st_command_info cmd_info; /**< command information */
/* for data transfer */
uint32_t *buff_address_virtual; /**< Dest or Src buff */
uint32_t *buff_address_physical; /**< Dest or Src buff */
HAL_MEMCARD_DATA_WIDTH bus_width;
/**< bus width */
uint32_t trans_size; /**< transfer size for this command */
uint32_t remain_size; /**< remain size for this command */
uint32_t response_length; /**< response length for this command */
uint32_t sector_size; /**< sector_size */
/* clock */
uint32_t base_clock; /**< MMC host controller clock */
uint32_t max_freq; /**< Max frequency (Card Spec)[Hz]. It changes dynamically by CSD and EXT_CSD. */
uint32_t request_freq; /**< request freq [Hz] (400K, 26MHz, 52MHz, etc) */
uint32_t current_freq; /**< current MMC clock[Hz] (the closest frequency supported by HW) */
/* state flag */
HAL_MEMCARD_PRESENCE_STATUS card_present;
/**< presence status of the memory card */
uint32_t card_power_enable; /**< True : Power ON */
uint32_t clock_enable; /**< True : Clock ON */
uint32_t initialize; /**< True : initialize complete. */
uint32_t access_mode; /**< True : sector access, FALSE : byte access */
uint32_t mount; /**< True : mount complete. */
uint32_t selected; /**< True : selected card. */
HAL_MEMCARD_DATA_TRANSFER_MODE transfer_mode;
/**< 0: DMA, 1:PIO */
uint32_t image_num; /**< loaded ISSW image No. ISSW have copy image. */
EMMC_R1_STATE current_state; /**< card state */
volatile uint32_t during_cmd_processing; /**< True : during command processing */
volatile uint32_t during_transfer; /**< True : during transfer */
volatile uint32_t during_dma_transfer; /**< True : during transfer (DMA)*/
volatile uint32_t dma_error_flag; /**< True : occurred DMAC error */
volatile uint32_t force_terminate; /**< force terminate flag */
volatile uint32_t state_machine_blocking; /**< state machine blocking flag : True or False */
volatile uint32_t get_partition_access_flag;
/**< True : get partition access processing */
EMMC_PARTITION_ID boot_partition_en; /**< Boot partition */
EMMC_PARTITION_ID partition_access; /**< Current access partition */
/* timeout */
uint32_t hs_timing; /**< high speed */
/* timeout */
uint32_t data_timeout; /**< read and write data timeout.*/
/* retry */
uint32_t retries_after_fail; /**< how many times to try after fail, for instance sending command */
/* interrupt */
volatile uint32_t int_event1; /**< interrupt SD_INFO1 Event */
volatile uint32_t int_event2; /**< interrupt SD_INFO2 Event */
volatile uint32_t dm_event1; /**< interrupt DM_CM_INFO1 Event */
volatile uint32_t dm_event2; /**< interrupt DM_CM_INFO2 Event */
/* response */
uint32_t *response; /**< pointer to buffer for executing command. */
uint32_t r1_card_status; /**< R1 response data */
uint32_t r3_ocr; /**< R3 response data */
uint32_t r4_resp; /**< R4 response data */
uint32_t r5_resp; /**< R5 response data */
uint32_t low_clock_mode_enable;
/**< True : clock mode is low. (MMC clock = Max26MHz) */
uint32_t reserved2;
uint32_t reserved3;
uint32_t reserved4;
/* CSD registers (4byte align) */
uint8_t csd_data[EMMC_MAX_CSD_LENGTH] /**< CSD */
__attribute__ ((aligned(EMMC_RES_REG_ALIGNED)));
/* CID registers (4byte align) */
uint8_t cid_data[EMMC_MAX_CID_LENGTH] /**< CID */
__attribute__ ((aligned(EMMC_RES_REG_ALIGNED)));
/* EXT CSD registers (8byte align) */
uint8_t ext_csd_data[EMMC_MAX_EXT_CSD_LENGTH] /**< EXT_CSD */
__attribute__ ((aligned(EMMC_BUF_REG_ALIGNED)));
/* Response registers (4byte align) */
uint8_t response_data[EMMC_MAX_RESPONSE_LENGTH] /**< other response */
__attribute__ ((aligned(EMMC_RES_REG_ALIGNED)));
} st_mmc_base;
typedef int (*func) (void);
/* ********************** DECLARATION OF EXTERNAL DATA ********************* */
/* ************************** FUNCTION PROTOTYPES ************************** */
uint32_t emmc_get_csd_time(void);
#define MMC_DEBUG
/* ********************************* CODE ********************************** */
/* ******************************** END ************************************ */
#endif /* __EMMC_STD_H__ */
/*
* Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <debug.h>
#include "emmc_config.h"
#include "emmc_hal.h"
#include "emmc_std.h"
#include "emmc_registers.h"
#include "emmc_def.h"
static const uint32_t cmd_reg_hw[EMMC_CMD_MAX + 1] = {
0x00000000, /* CMD0 */
0x00000701, /* CMD1 */
0x00000002, /* CMD2 */
0x00000003, /* CMD3 */
0x00000004, /* CMD4 */
0x00000505, /* CMD5 */
0x00000406, /* CMD6 */
0x00000007, /* CMD7 */
0x00001C08, /* CMD8 */
0x00000009, /* CMD9 */
0x0000000A, /* CMD10 */
0x00000000, /* reserved */
0x0000000C, /* CMD12 */
0x0000000D, /* CMD13 */
0x00001C0E, /* CMD14 */
0x0000000F, /* CMD15 */
0x00000010, /* CMD16 */
0x00000011, /* CMD17 */
0x00007C12, /* CMD18 */
0x00000C13, /* CMD19 */
0x00000000,
0x00001C15, /* CMD21 */
0x00000000,
0x00000017, /* CMD23 */
0x00000018, /* CMD24 */
0x00006C19, /* CMD25 */
0x00000C1A, /* CMD26 */
0x0000001B, /* CMD27 */
0x0000001C, /* CMD28 */
0x0000001D, /* CMD29 */
0x0000001E, /* CMD30 */
0x00001C1F, /* CMD31 */
0x00000000,
0x00000000,
0x00000000,
0x00000423, /* CMD35 */
0x00000424, /* CMD36 */
0x00000000,
0x00000026, /* CMD38 */
0x00000427, /* CMD39 */
0x00000428, /* CMD40(send cmd) */
0x00000000,
0x0000002A, /* CMD42 */
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000C31,
0x00000000,
0x00000000,
0x00000000,
0x00007C35,
0x00006C36,
0x00000037, /* CMD55 */
0x00000038, /* CMD56(Read) */
0x00000000,
0x00000000,
0x00000000,
0x00000000
};
uint32_t emmc_bit_field(uint8_t *data, uint32_t top, uint32_t bottom)
{
uint32_t value;
uint32_t index_top = (uint32_t) (15 - (top >> 3));
uint32_t index_bottom = (uint32_t) (15 - (bottom >> 3));
if (index_top == index_bottom) {
value = data[index_top];
} else if ((index_top + 1) == index_bottom) {
value =
(uint32_t) ((data[index_top] << 8) | data[index_bottom]);
} else if ((index_top + 2) == index_bottom) {
value =
(uint32_t) ((data[index_top] << 16) |
(data[index_top + 1] << 8) | data[index_top +
2]);
} else {
value =
(uint32_t) ((data[index_top] << 24) |
(data[index_top + 1] << 16) |
(data[index_top + 2] << 8) | data[index_top +
3]);
}
value = ((value >> (bottom & 0x07)) & ((1 << (top - bottom + 1)) - 1));
return value;
}
void emmc_write_error_info(uint16_t func_no, EMMC_ERROR_CODE error_code)
{
mmc_drv_obj.error_info.num = func_no;
mmc_drv_obj.error_info.code = (uint16_t) error_code;
ERROR("BL2: emmc err:func_no=0x%x code=0x%x\n", func_no, error_code);
}
void emmc_write_error_info_func_no(uint16_t func_no)
{
mmc_drv_obj.error_info.num = func_no;
ERROR("BL2: emmc err:func_no=0x%x\n", func_no);
}
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[cmd & HAL_MEMCARD_COMMAND_INDEX_MASK];
/* clear data transfer information */
mmc_drv_obj.trans_size = 0;
mmc_drv_obj.remain_size = 0;
mmc_drv_obj.buff_address_virtual = NULL;
mmc_drv_obj.buff_address_physical = NULL;
/* response information */
mmc_drv_obj.response_length = 6;
switch (mmc_drv_obj.cmd_info.cmd & 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 = 0;
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 |= BIT10; /* 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 = 17;
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;
}
}
void emmc_make_trans_cmd(HAL_MEMCARD_COMMAND cmd, uint32_t arg,
uint32_t *buff_address_virtual,
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;
}
EMMC_ERROR_CODE emmc_send_idle_cmd(uint32_t arg)
{
EMMC_ERROR_CODE result;
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_cmd_processing = 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;
}
/*
* Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <mmio.h>
#include <debug.h>
#include "rcar_def.h"
#include "cpg_registers.h"
#include "iic_dvfs.h"
#include "rcar_private.h"
#define DVFS_RETRY_MAX (2U)
#define IIC_DVFS_SET_ICCL_EXTAL_TYPE_0 (0x07)
#define IIC_DVFS_SET_ICCL_EXTAL_TYPE_1 (0x09)
#define IIC_DVFS_SET_ICCL_EXTAL_TYPE_2 (0x0B)
#define IIC_DVFS_SET_ICCL_EXTAL_TYPE_3 (0x0E)
#define IIC_DVFS_SET_ICCL_EXTAL_TYPE_E (0x15)
#define IIC_DVFS_SET_ICCH_EXTAL_TYPE_0 (0x01)
#define IIC_DVFS_SET_ICCH_EXTAL_TYPE_1 (0x02)
#define IIC_DVFS_SET_ICCH_EXTAL_TYPE_2 (0x03)
#define IIC_DVFS_SET_ICCH_EXTAL_TYPE_3 (0x05)
#define IIC_DVFS_SET_ICCH_EXTAL_TYPE_E (0x07)
#define CPG_BIT_SMSTPCR9_DVFS (0x04000000)
#define IIC_DVFS_REG_BASE (0xE60B0000)
#define IIC_DVFS_REG_ICDR (IIC_DVFS_REG_BASE + 0x0000)
#define IIC_DVFS_REG_ICCR (IIC_DVFS_REG_BASE + 0x0004)
#define IIC_DVFS_REG_ICSR (IIC_DVFS_REG_BASE + 0x0008)
#define IIC_DVFS_REG_ICIC (IIC_DVFS_REG_BASE + 0x000C)
#define IIC_DVFS_REG_ICCL (IIC_DVFS_REG_BASE + 0x0010)
#define IIC_DVFS_REG_ICCH (IIC_DVFS_REG_BASE + 0x0014)
#define IIC_DVFS_BIT_ICSR_BUSY (0x10)
#define IIC_DVFS_BIT_ICSR_AL (0x08)
#define IIC_DVFS_BIT_ICSR_TACK (0x04)
#define IIC_DVFS_BIT_ICSR_WAIT (0x02)
#define IIC_DVFS_BIT_ICSR_DTE (0x01)
#define IIC_DVFS_BIT_ICCR_ENABLE (0x80)
#define IIC_DVFS_SET_ICCR_START (0x94)
#define IIC_DVFS_SET_ICCR_STOP (0x90)
#define IIC_DVFS_SET_ICCR_RETRANSMISSION (0x94)
#define IIC_DVFS_SET_ICCR_CHANGE (0x81)
#define IIC_DVFS_SET_ICCR_STOP_READ (0xC0)
#define IIC_DVFS_BIT_ICIC_TACKE (0x04)
#define IIC_DVFS_BIT_ICIC_WAITE (0x02)
#define IIC_DVFS_BIT_ICIC_DTEE (0x01)
#define DVFS_READ_MODE (0x01)
#define DVFS_WRITE_MODE (0x00)
#define IIC_DVFS_SET_DUMMY (0x52)
#define IIC_DVFS_SET_BUSY_LOOP (500000000U)
typedef enum {
DVFS_START = 0,
DVFS_STOP,
DVFS_RETRANSMIT,
DVFS_READ,
DVFS_STOP_READ,
DVFS_SET_SLAVE_READ,
DVFS_SET_SLAVE,
DVFS_WRITE_ADDR,
DVFS_WRITE_DATA,
DVFS_CHANGE_SEND_TO_RECIEVE,
DVFS_DONE,
} DVFS_STATE_T;
#define DVFS_PROCESS (1)
#define DVFS_COMPLETE (0)
#define DVFS_ERROR (-1)
#if IMAGE_BL31
#define IIC_DVFS_FUNC(__name, ...) \
static int32_t __attribute__ ((section (".system_ram"))) \
dvfs_ ##__name(__VA_ARGS__)
#define RCAR_DVFS_API(__name, ...) \
int32_t __attribute__ ((section (".system_ram"))) \
rcar_iic_dvfs_ ##__name(__VA_ARGS__)
#else
#define IIC_DVFS_FUNC(__name, ...) \
static int32_t dvfs_ ##__name(__VA_ARGS__)
#define RCAR_DVFS_API(__name, ...) \
int32_t rcar_iic_dvfs_ ##__name(__VA_ARGS__)
#endif
IIC_DVFS_FUNC(check_error, DVFS_STATE_T *state, uint32_t *err, uint8_t mode)
{
uint8_t icsr_al = 0, icsr_tack = 0;
uint8_t reg, stop;
uint32_t i = 0;
stop = mode == DVFS_READ_MODE ? IIC_DVFS_SET_ICCR_STOP_READ :
IIC_DVFS_SET_ICCR_STOP;
reg = mmio_read_8(IIC_DVFS_REG_ICSR);
icsr_al = (reg & IIC_DVFS_BIT_ICSR_AL) == IIC_DVFS_BIT_ICSR_AL;
icsr_tack = (reg & IIC_DVFS_BIT_ICSR_TACK) == IIC_DVFS_BIT_ICSR_TACK;
if (icsr_al == 0 && icsr_tack == 0)
return DVFS_PROCESS;
if (icsr_al) {
reg = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_AL;
mmio_write_8(IIC_DVFS_REG_ICSR, reg);
if (*state == DVFS_SET_SLAVE)
mmio_write_8(IIC_DVFS_REG_ICDR, IIC_DVFS_SET_DUMMY);
do {
reg = mmio_read_8(IIC_DVFS_REG_ICSR) &
IIC_DVFS_BIT_ICSR_WAIT;
} while (reg == 0);
mmio_write_8(IIC_DVFS_REG_ICCR, stop);
reg = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT;
mmio_write_8(IIC_DVFS_REG_ICSR, reg);
i = 0;
do {
reg = mmio_read_8(IIC_DVFS_REG_ICSR) &
IIC_DVFS_BIT_ICSR_BUSY;
if (reg == 0)
break;
if (i++ > IIC_DVFS_SET_BUSY_LOOP)
panic();
} while (1);
mmio_write_8(IIC_DVFS_REG_ICCR, 0x00U);
(*err)++;
if (*err > DVFS_RETRY_MAX)
return DVFS_ERROR;
*state = DVFS_START;
return DVFS_PROCESS;
}
/* icsr_tack */
mmio_write_8(IIC_DVFS_REG_ICCR, stop);
reg = mmio_read_8(IIC_DVFS_REG_ICIC);
reg &= ~(IIC_DVFS_BIT_ICIC_WAITE | IIC_DVFS_BIT_ICIC_DTEE);
mmio_write_8(IIC_DVFS_REG_ICIC, reg);
reg = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_TACK;
mmio_write_8(IIC_DVFS_REG_ICSR, reg);
i = 0;
while ((mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_BUSY) != 0) {
if (i++ > IIC_DVFS_SET_BUSY_LOOP)
panic();
}
mmio_write_8(IIC_DVFS_REG_ICCR, 0);
(*err)++;
if (*err > DVFS_RETRY_MAX)
return DVFS_ERROR;
*state = DVFS_START;
return DVFS_PROCESS;
}
IIC_DVFS_FUNC(start, DVFS_STATE_T * state)
{
uint8_t iccl = IIC_DVFS_SET_ICCL_EXTAL_TYPE_E;
uint8_t icch = IIC_DVFS_SET_ICCH_EXTAL_TYPE_E;
int32_t result = DVFS_PROCESS;
uint32_t reg, lsi_product;
uint8_t mode;
mode = mmio_read_8(IIC_DVFS_REG_ICCR) | IIC_DVFS_BIT_ICCR_ENABLE;
mmio_write_8(IIC_DVFS_REG_ICCR, mode);
lsi_product = mmio_read_32(RCAR_PRR) & RCAR_PRODUCT_MASK;
if (lsi_product == RCAR_PRODUCT_E3)
goto start;
reg = mmio_read_32(RCAR_MODEMR) & CHECK_MD13_MD14;
switch (reg) {
case MD14_MD13_TYPE_0:
iccl = IIC_DVFS_SET_ICCL_EXTAL_TYPE_0;
icch = IIC_DVFS_SET_ICCH_EXTAL_TYPE_0;
break;
case MD14_MD13_TYPE_1:
iccl = IIC_DVFS_SET_ICCL_EXTAL_TYPE_1;
icch = IIC_DVFS_SET_ICCH_EXTAL_TYPE_1;
break;
case MD14_MD13_TYPE_2:
iccl = IIC_DVFS_SET_ICCL_EXTAL_TYPE_2;
icch = IIC_DVFS_SET_ICCH_EXTAL_TYPE_2;
break;
default:
iccl = IIC_DVFS_SET_ICCL_EXTAL_TYPE_3;
icch = IIC_DVFS_SET_ICCH_EXTAL_TYPE_3;
break;
}
start:
mmio_write_8(IIC_DVFS_REG_ICCL, iccl);
mmio_write_8(IIC_DVFS_REG_ICCH, icch);
mode = mmio_read_8(IIC_DVFS_REG_ICIC)
| IIC_DVFS_BIT_ICIC_TACKE
| IIC_DVFS_BIT_ICIC_WAITE | IIC_DVFS_BIT_ICIC_DTEE;
mmio_write_8(IIC_DVFS_REG_ICIC, mode);
mmio_write_8(IIC_DVFS_REG_ICCR, IIC_DVFS_SET_ICCR_START);
*state = DVFS_SET_SLAVE;
return result;
}
IIC_DVFS_FUNC(set_slave, DVFS_STATE_T * state, uint32_t *err, uint8_t slave)
{
uint8_t mode;
int32_t result;
uint8_t address;
result = dvfs_check_error(state, err, DVFS_WRITE_MODE);
if (result == DVFS_ERROR)
return result;
mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_DTE;
if (mode != IIC_DVFS_BIT_ICSR_DTE)
return result;
mode = mmio_read_8(IIC_DVFS_REG_ICIC) & ~IIC_DVFS_BIT_ICIC_DTEE;
mmio_write_8(IIC_DVFS_REG_ICIC, mode);
address = slave << 1;
mmio_write_8(IIC_DVFS_REG_ICDR, address);
*state = DVFS_WRITE_ADDR;
return result;
}
IIC_DVFS_FUNC(write_addr, DVFS_STATE_T *state, uint32_t *err, uint8_t reg_addr)
{
uint8_t mode;
int32_t result;
result = dvfs_check_error(state, err, DVFS_WRITE_MODE);
if (result == DVFS_ERROR)
return result;
mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_WAIT;
if (mode != IIC_DVFS_BIT_ICSR_WAIT)
return result;
mmio_write_8(IIC_DVFS_REG_ICDR, reg_addr);
mode = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT;
mmio_write_8(IIC_DVFS_REG_ICSR, mode);
*state = DVFS_WRITE_DATA;
return result;
}
IIC_DVFS_FUNC(write_data, DVFS_STATE_T *state, uint32_t *err, uint8_t reg_data)
{
int32_t result;
uint8_t mode;
result = dvfs_check_error(state, err, DVFS_WRITE_MODE);
if (result == DVFS_ERROR)
return result;
mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_WAIT;
if (mode != IIC_DVFS_BIT_ICSR_WAIT)
return result;
mmio_write_8(IIC_DVFS_REG_ICDR, reg_data);
mode = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT;
mmio_write_8(IIC_DVFS_REG_ICSR, mode);
*state = DVFS_STOP;
return result;
}
IIC_DVFS_FUNC(stop, DVFS_STATE_T *state, uint32_t *err)
{
int32_t result;
uint8_t mode;
result = dvfs_check_error(state, err, DVFS_WRITE_MODE);
if (result == DVFS_ERROR)
return result;
mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_WAIT;
if (mode != IIC_DVFS_BIT_ICSR_WAIT)
return result;
mmio_write_8(IIC_DVFS_REG_ICCR, IIC_DVFS_SET_ICCR_STOP);
mode = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT;
mmio_write_8(IIC_DVFS_REG_ICSR, mode);
*state = DVFS_DONE;
return result;
}
IIC_DVFS_FUNC(done, void)
{
uint32_t i;
for (i = 0; i < IIC_DVFS_SET_BUSY_LOOP; i++) {
if (mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_BUSY)
continue;
goto done;
}
panic();
done:
mmio_write_8(IIC_DVFS_REG_ICCR, 0);
return DVFS_COMPLETE;
}
IIC_DVFS_FUNC(write_reg_addr_read, DVFS_STATE_T *state, uint32_t *err,
uint8_t reg_addr)
{
int32_t result;
uint8_t mode;
result = dvfs_check_error(state, err, DVFS_WRITE_MODE);
if (result == DVFS_ERROR)
return result;
mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_WAIT;
if (mode != IIC_DVFS_BIT_ICSR_WAIT)
return result;
mmio_write_8(IIC_DVFS_REG_ICDR, reg_addr);
mode = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT;
mmio_write_8(IIC_DVFS_REG_ICSR, mode);
*state = DVFS_RETRANSMIT;
return result;
}
IIC_DVFS_FUNC(retransmit, DVFS_STATE_T *state, uint32_t *err)
{
int32_t result;
uint8_t mode;
result = dvfs_check_error(state, err, DVFS_WRITE_MODE);
if (result == DVFS_ERROR)
return result;
mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_WAIT;
if (mode != IIC_DVFS_BIT_ICSR_WAIT)
return result;
mmio_write_8(IIC_DVFS_REG_ICCR, IIC_DVFS_SET_ICCR_RETRANSMISSION);
mode = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT;
mmio_write_8(IIC_DVFS_REG_ICSR, mode);
mode = mmio_read_8(IIC_DVFS_REG_ICIC) | IIC_DVFS_BIT_ICIC_DTEE;
mmio_write_8(IIC_DVFS_REG_ICIC, mode);
*state = DVFS_SET_SLAVE_READ;
return result;
}
IIC_DVFS_FUNC(set_slave_read, DVFS_STATE_T *state, uint32_t *err,
uint8_t slave)
{
uint8_t address;
int32_t result;
uint8_t mode;
result = dvfs_check_error(state, err, DVFS_WRITE_MODE);
if (result == DVFS_ERROR)
return result;
mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_DTE;
if (mode != IIC_DVFS_BIT_ICSR_DTE)
return result;
mode = mmio_read_8(IIC_DVFS_REG_ICIC) & ~IIC_DVFS_BIT_ICIC_DTEE;
mmio_write_8(IIC_DVFS_REG_ICIC, mode);
address = ((uint8_t) (slave << 1) + DVFS_READ_MODE);
mmio_write_8(IIC_DVFS_REG_ICDR, address);
*state = DVFS_CHANGE_SEND_TO_RECIEVE;
return result;
}
IIC_DVFS_FUNC(change_send_to_recieve, DVFS_STATE_T *state, uint32_t *err)
{
int32_t result;
uint8_t mode;
result = dvfs_check_error(state, err, DVFS_WRITE_MODE);
if (result == DVFS_ERROR)
return result;
mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_WAIT;
if (mode != IIC_DVFS_BIT_ICSR_WAIT)
return result;
mmio_write_8(IIC_DVFS_REG_ICCR, IIC_DVFS_SET_ICCR_CHANGE);
mode = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT;
mmio_write_8(IIC_DVFS_REG_ICSR, mode);
*state = DVFS_STOP_READ;
return result;
}
IIC_DVFS_FUNC(stop_read, DVFS_STATE_T *state, uint32_t *err)
{
int32_t result;
uint8_t mode;
result = dvfs_check_error(state, err, DVFS_READ_MODE);
if (result == DVFS_ERROR)
return result;
mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_WAIT;
if (mode != IIC_DVFS_BIT_ICSR_WAIT)
return result;
mmio_write_8(IIC_DVFS_REG_ICCR, IIC_DVFS_SET_ICCR_STOP_READ);
mode = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT;
mmio_write_8(IIC_DVFS_REG_ICSR, mode);
mode = mmio_read_8(IIC_DVFS_REG_ICIC) | IIC_DVFS_BIT_ICIC_DTEE;
mmio_write_8(IIC_DVFS_REG_ICIC, mode);
*state = DVFS_READ;
return result;
}
IIC_DVFS_FUNC(read, DVFS_STATE_T *state, uint8_t *reg_data)
{
uint8_t mode;
mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_DTE;
if (mode != IIC_DVFS_BIT_ICSR_DTE)
return DVFS_PROCESS;
mode = mmio_read_8(IIC_DVFS_REG_ICIC) & ~IIC_DVFS_BIT_ICIC_DTEE;
mmio_write_8(IIC_DVFS_REG_ICIC, mode);
*reg_data = mmio_read_8(IIC_DVFS_REG_ICDR);
*state = DVFS_DONE;
return DVFS_PROCESS;
}
RCAR_DVFS_API(send, uint8_t slave, uint8_t reg_addr, uint8_t reg_data)
{
DVFS_STATE_T state = DVFS_START;
int32_t result = DVFS_PROCESS;
uint32_t err = 0;
mstpcr_write(SCMSTPCR9, CPG_MSTPSR9, CPG_BIT_SMSTPCR9_DVFS);
mmio_write_8(IIC_DVFS_REG_ICCR, 0);
again:
switch (state) {
case DVFS_START:
result = dvfs_start(&state);
break;
case DVFS_SET_SLAVE:
result = dvfs_set_slave(&state, &err, slave);
break;
case DVFS_WRITE_ADDR:
result = dvfs_write_addr(&state, &err, reg_addr);
break;
case DVFS_WRITE_DATA:
result = dvfs_write_data(&state, &err, reg_data);
break;
case DVFS_STOP:
result = dvfs_stop(&state, &err);
break;
case DVFS_DONE:
result = dvfs_done();
break;
default:
panic();
break;
}
if (result == DVFS_PROCESS)
goto again;
return result;
}
RCAR_DVFS_API(receive, uint8_t slave, uint8_t reg, uint8_t *data)
{
DVFS_STATE_T state = DVFS_START;
int32_t result = DVFS_PROCESS;
uint32_t err = 0;
mstpcr_write(SCMSTPCR9, CPG_MSTPSR9, CPG_BIT_SMSTPCR9_DVFS);
mmio_write_8(IIC_DVFS_REG_ICCR, 0);
again:
switch (state) {
case DVFS_START:
result = dvfs_start(&state);
break;
case DVFS_SET_SLAVE:
result = dvfs_set_slave(&state, &err, slave);
break;
case DVFS_WRITE_ADDR:
result = dvfs_write_reg_addr_read(&state, &err, reg);
break;
case DVFS_RETRANSMIT:
result = dvfs_retransmit(&state, &err);
break;
case DVFS_SET_SLAVE_READ:
result = dvfs_set_slave_read(&state, &err, slave);
break;
case DVFS_CHANGE_SEND_TO_RECIEVE:
result = dvfs_change_send_to_recieve(&state, &err);
break;
case DVFS_STOP_READ:
result = dvfs_stop_read(&state, &err);
break;
case DVFS_READ:
result = dvfs_read(&state, data);
break;
case DVFS_DONE:
result = dvfs_done();
break;
default:
panic();
break;
}
if (result == DVFS_PROCESS)
goto again;
return result;
}
/*
* Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef IIC_DVFS_H__
#define IIC_DVFS_H__
/* PMIC slave */
#define PMIC (0x30)
#define BKUP_MODE_CNT (0x20)
#define DVFS_SET_VID (0x54)
#define REG_KEEP10 (0x79)
/* EEPROM slave */
#define EEPROM (0x50)
#define BOARD_ID (0x70)
int32_t rcar_iic_dvfs_receive(uint8_t slave, uint8_t reg, uint8_t *data);
int32_t rcar_iic_dvfs_send(uint8_t slave, uint8_t regr, uint8_t data);
#endif
/*
* Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef IO_COMMON_H__
#define IO_COMMON_H__
typedef struct io_drv_spec {
size_t offset;
size_t length;
uint32_t partition;
} io_drv_spec_t;
#endif
/*
* Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <debug.h>
#include <io_driver.h>
#include <io_storage.h>
#include <string.h>
#include "io_common.h"
#include "io_emmcdrv.h"
#include "io_private.h"
#include "emmc_config.h"
#include "emmc_hal.h"
#include "emmc_std.h"
#include "emmc_def.h"
static int32_t emmcdrv_dev_open(const uintptr_t spec __attribute__ ((unused)),
io_dev_info_t **dev_info);
static int32_t emmcdrv_dev_close(io_dev_info_t *dev_info);
typedef struct {
uint32_t in_use;
uintptr_t base;
ssize_t file_pos;
EMMC_PARTITION_ID partition;
} file_state_t;
static file_state_t current_file = { 0 };
static EMMC_PARTITION_ID emmcdrv_bootpartition = PARTITION_ID_USER;
static io_type_t device_type_emmcdrv(void)
{
return IO_TYPE_MEMMAP;
}
static int32_t emmcdrv_block_seek(io_entity_t *entity, int32_t mode,
ssize_t offset)
{
if (mode != IO_SEEK_SET)
return IO_FAIL;
((file_state_t *) entity->info)->file_pos = offset;
return IO_SUCCESS;
}
static int32_t emmcdrv_block_read(io_entity_t *entity, uintptr_t buffer,
size_t length, size_t *length_read)
{
file_state_t *fp = (file_state_t *) entity->info;
uint32_t sector_add, sector_num, emmc_dma = 0;
int32_t result = IO_SUCCESS;
sector_add = current_file.file_pos >> EMMC_SECTOR_SIZE_SHIFT;
sector_num = (length + EMMC_SECTOR_SIZE - 1U) >> EMMC_SECTOR_SIZE_SHIFT;
NOTICE("BL2: Load dst=0x%lx src=(p:%d)0x%lx(%d) len=0x%lx(%d)\n",
buffer,
current_file.partition, current_file.file_pos,
sector_add, length, sector_num);
if (buffer + length - 1 <= UINT32_MAX)
emmc_dma = LOADIMAGE_FLAGS_DMA_ENABLE;
if (emmc_read_sector((uint32_t *) buffer, sector_add, sector_num,
emmc_dma) != EMMC_SUCCESS)
result = IO_FAIL;
*length_read = length;
fp->file_pos += length;
return result;
}
static int32_t emmcdrv_block_open(io_dev_info_t *dev_info,
const uintptr_t spec, io_entity_t *entity)
{
const io_drv_spec_t *block_spec = (io_drv_spec_t *) spec;
if (current_file.in_use) {
WARN("mmc_block: Only one open spec at a time\n");
return IO_RESOURCES_EXHAUSTED;
}
current_file.file_pos = 0;
current_file.in_use = 1;
if (emmcdrv_bootpartition == PARTITION_ID_USER) {
emmcdrv_bootpartition = mmc_drv_obj.boot_partition_en;
if ((PARTITION_ID_BOOT_1 == emmcdrv_bootpartition) ||
(PARTITION_ID_BOOT_2 == emmcdrv_bootpartition)) {
current_file.partition = emmcdrv_bootpartition;
NOTICE("BL2: eMMC boot from partition %d\n",
emmcdrv_bootpartition);
goto done;
}
return IO_FAIL;
}
if (PARTITION_ID_USER == block_spec->partition ||
PARTITION_ID_BOOT_1 == block_spec->partition ||
PARTITION_ID_BOOT_2 == block_spec->partition)
current_file.partition = block_spec->partition;
else
current_file.partition = emmcdrv_bootpartition;
done:
if (emmc_select_partition(current_file.partition) != EMMC_SUCCESS)
return IO_FAIL;
entity->info = (uintptr_t) &current_file;
return IO_SUCCESS;
}
static int32_t emmcdrv_block_close(io_entity_t *entity)
{
memset((void *)&current_file, 0, sizeof(current_file));
entity->info = 0U;
return IO_SUCCESS;
}
static const io_dev_funcs_t emmcdrv_dev_funcs = {
.type = &device_type_emmcdrv,
.open = &emmcdrv_block_open,
.seek = &emmcdrv_block_seek,
.size = NULL,
.read = &emmcdrv_block_read,
.write = NULL,
.close = &emmcdrv_block_close,
.dev_init = NULL,
.dev_close = &emmcdrv_dev_close
};
static const io_dev_info_t emmcdrv_dev_info = {
.funcs = &emmcdrv_dev_funcs,
.info = (uintptr_t) 0
};
static const io_dev_connector_t emmcdrv_dev_connector = {
&emmcdrv_dev_open,
};
static int32_t emmcdrv_dev_open(const uintptr_t spec __attribute__ ((unused)),
io_dev_info_t **dev_info)
{
*dev_info = (io_dev_info_t *) &emmcdrv_dev_info;
return IO_SUCCESS;
}
static int32_t emmcdrv_dev_close(io_dev_info_t *dev_info)
{
return IO_SUCCESS;
}
int32_t rcar_register_io_dev_emmcdrv(const io_dev_connector_t **dev_con)
{
int32_t rc;
rc = io_register_device(&emmcdrv_dev_info);
if (rc == IO_SUCCESS)
*dev_con = &emmcdrv_dev_connector;
return rc;
}
/*
* Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef IO_EMMCDRV_H__
#define IO_EMMCDRV_H__
struct io_dev_connector;
int32_t rcar_register_io_dev_emmcdrv(const io_dev_connector_t **connector);
#endif
/*
* Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <debug.h>
#include <io_driver.h>
#include <io_storage.h>
#include <string.h>
#include "io_common.h"
#include "io_private.h"
#include "io_memdrv.h"
#include "rcar_def.h"
extern void rcar_dma_exec(uintptr_t dst, uint32_t src, uint32_t len);
static int32_t memdrv_dev_open(const uintptr_t dev __attribute__ ((unused)),
io_dev_info_t **dev_info);
static int32_t memdrv_dev_close(io_dev_info_t *dev_info);
/* As we need to be able to keep state for seek, only one file can be open
* at a time. Make this a structure and point to the entity->info. When we
* can malloc memory we can change this to support more open files.
*/
typedef struct {
uint32_t in_use;
uintptr_t base;
ssize_t file_pos;
} file_state_t;
static file_state_t current_file = { 0 };
static io_type_t device_type_memdrv(void)
{
return IO_TYPE_MEMMAP;
}
static int32_t memdrv_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
io_entity_t *entity)
{
const io_drv_spec_t *block_spec = (io_drv_spec_t *) spec;
/* Since we need to track open state for seek() we only allow one open
* spec at a time. When we have dynamic memory we can malloc and set
* entity->info.
*/
if (current_file.in_use)
return IO_RESOURCES_EXHAUSTED;
/* File cursor offset for seek and incremental reads etc. */
current_file.base = block_spec->offset;
current_file.file_pos = 0;
current_file.in_use = 1;
entity->info = (uintptr_t) &current_file;
return IO_SUCCESS;
}
static int32_t memdrv_block_seek(io_entity_t *entity, int32_t mode,
ssize_t offset)
{
if (mode != IO_SEEK_SET)
return IO_FAIL;
((file_state_t *) entity->info)->file_pos = offset;
return IO_SUCCESS;
}
static int32_t memdrv_block_read(io_entity_t *entity, uintptr_t buffer,
size_t length, size_t *cnt)
{
file_state_t *fp;
fp = (file_state_t *) entity->info;
NOTICE("BL2: dst=0x%lx src=0x%lx len=%ld(0x%lx)\n",
buffer, fp->base + fp->file_pos, length, length);
if (FLASH_MEMORY_SIZE < fp->file_pos + length) {
ERROR("BL2: check load image (source address)\n");
return IO_FAIL;
}
rcar_dma_exec(buffer, fp->base + fp->file_pos, length);
fp->file_pos += length;
*cnt = length;
return IO_SUCCESS;
}
static int32_t memdrv_block_close(io_entity_t *entity)
{
entity->info = 0U;
memset((void *)&current_file, 0, sizeof(current_file));
return IO_SUCCESS;
}
static const io_dev_funcs_t memdrv_dev_funcs = {
.type = &device_type_memdrv,
.open = &memdrv_block_open,
.seek = &memdrv_block_seek,
.size = NULL,
.read = &memdrv_block_read,
.write = NULL,
.close = &memdrv_block_close,
.dev_init = NULL,
.dev_close = &memdrv_dev_close,
};
static const io_dev_info_t memdrv_dev_info = {
.funcs = &memdrv_dev_funcs,
.info = 0,
};
static const io_dev_connector_t memdrv_dev_connector = {
.dev_open = &memdrv_dev_open
};
static int32_t memdrv_dev_open(const uintptr_t dev __attribute__ ((unused)),
io_dev_info_t **dev_info)
{
*dev_info = (io_dev_info_t *) &memdrv_dev_info;
return IO_SUCCESS;
}
static int32_t memdrv_dev_close(io_dev_info_t *dev_info)
{
return IO_SUCCESS;
}
int32_t rcar_register_io_dev_memdrv(const io_dev_connector_t **dev_con)
{
int32_t result;
result = io_register_device(&memdrv_dev_info);
if (result == IO_SUCCESS)
*dev_con = &memdrv_dev_connector;
return result;
}
/*
* Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef IO_MEMDRV_H__
#define IO_MEMDRV_H__
struct io_dev_connector;
int32_t rcar_register_io_dev_memdrv(const io_dev_connector_t **connector);
#endif
/*
* Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef IO_PRIVATE_H_
#define IO_PRIVATE_H_
/*
* Return codes reported by 'io_*' APIs
* The value of fail should not overlap with define of the errno.
* The errno is in "include/lib/stdlib/sys/errno.h".
*/
#define IO_SUCCESS (0)
#define IO_FAIL (-0x81)
#define IO_NOT_SUPPORTED (-0x82)
#define IO_RESOURCES_EXHAUSTED (-0x83)
#endif
/*
* Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <auth_mod.h>
#include <bl_common.h>
#include <debug.h>
#include <errno.h>
#include <firmware_image_package.h>
#include <io_driver.h>
#include <io_storage.h>
#include <platform.h>
#include <platform_def.h>
#include <stdint.h>
#include <string.h>
#include <uuid.h>
#include <mmio.h>
#include <arch_helpers.h>
#include "io_rcar.h"
#include "io_common.h"
#include "io_private.h"
extern int32_t plat_get_drv_source(uint32_t id, uintptr_t *dev,
uintptr_t *image_spec);
extern int auth_mod_verify_img(unsigned int img_id, void *ptr,
unsigned int len);
static int32_t rcar_dev_open(const uintptr_t dev_spec __attribute__ ((unused)),
io_dev_info_t **dev_info);
static int32_t rcar_dev_close(io_dev_info_t *dev_info);
typedef struct {
const int32_t name;
const uint32_t offset;
const uint32_t attr;
} plat_rcar_name_offset_t;
typedef struct {
/* Put position above the struct to allow {0} on static init.
* It is a workaround for a known bug in GCC
* http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119
*/
uint32_t position;
uint32_t no_load;
uintptr_t offset;
uint32_t size;
uintptr_t dst;
uintptr_t partition; /* for eMMC */
/* RCAR_EMMC_PARTITION_BOOT_0 */
/* RCAR_EMMC_PARTITION_BOOT_1 */
/* RCAR_EMMC_PARTITION_USER */
} file_state_t;
#define RCAR_GET_FLASH_ADR(a, b) ((uint32_t)((0x40000U * (a)) + (b)))
#define RCAR_ATTR_SET_CALCADDR(a) ((a) & 0xF)
#define RCAR_ATTR_SET_ISNOLOAD(a) (((a) & 0x1) << 16U)
#define RCAR_ATTR_SET_CERTOFF(a) (((a) & 0xF) << 8U)
#define RCAR_ATTR_SET_ALL(a, b, c) ((uint32_t)(RCAR_ATTR_SET_CALCADDR(a) |\
RCAR_ATTR_SET_ISNOLOAD(b) | \
RCAR_ATTR_SET_CERTOFF(c)))
#define RCAR_ATTR_GET_CALCADDR(a) ((a) & 0xFU)
#define RCAR_ATTR_GET_ISNOLOAD(a) (((a) >> 16) & 0x1U)
#define RCAR_ATTR_GET_CERTOFF(a) ((uint32_t)(((a) >> 8) & 0xFU))
#define RCAR_MAX_BL3X_IMAGE (8U)
#define RCAR_SECTOR6_CERT_OFFSET (0x400U)
#define RCAR_SDRAM_certESS (0x43F00000U)
#define RCAR_CERT_SIZE (0x800U)
#define RCAR_CERT_INFO_SIZE_OFFSET (0x264U)
#define RCAR_CERT_INFO_DST_OFFSET (0x154U)
#define RCAR_CERT_INFO_SIZE_OFFSET1 (0x364U)
#define RCAR_CERT_INFO_DST_OFFSET1 (0x1D4U)
#define RCAR_CERT_INFO_SIZE_OFFSET2 (0x464U)
#define RCAR_CERT_INFO_DST_OFFSET2 (0x254U)
#define RCAR_CERT_LOAD (1U)
#define RCAR_FLASH_CERT_HEADER RCAR_GET_FLASH_ADR(6U, 0U)
#define RCAR_EMMC_CERT_HEADER (0x00030000U)
#define RCAR_COUNT_LOAD_BL33 (2U)
#define RCAR_COUNT_LOAD_BL33X (3U)
static const plat_rcar_name_offset_t name_offset[] = {
{BL31_IMAGE_ID, 0U, RCAR_ATTR_SET_ALL(0, 0, 0)},
/* BL3-2 is optional in the platform */
{BL32_IMAGE_ID, 0U, RCAR_ATTR_SET_ALL(1, 0, 1)},
{BL33_IMAGE_ID, 0U, RCAR_ATTR_SET_ALL(2, 0, 2)},
{BL332_IMAGE_ID, 0U, RCAR_ATTR_SET_ALL(3, 0, 3)},
{BL333_IMAGE_ID, 0U, RCAR_ATTR_SET_ALL(4, 0, 4)},
{BL334_IMAGE_ID, 0U, RCAR_ATTR_SET_ALL(5, 0, 5)},
{BL335_IMAGE_ID, 0U, RCAR_ATTR_SET_ALL(6, 0, 6)},
{BL336_IMAGE_ID, 0U, RCAR_ATTR_SET_ALL(7, 0, 7)},
{BL337_IMAGE_ID, 0U, RCAR_ATTR_SET_ALL(8, 0, 8)},
{BL338_IMAGE_ID, 0U, RCAR_ATTR_SET_ALL(9, 0, 9)},
};
#if TRUSTED_BOARD_BOOT
static const plat_rcar_name_offset_t cert_offset[] = {
/* Certificates */
{TRUSTED_KEY_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 0)},
{SOC_FW_KEY_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 0)},
{TRUSTED_OS_FW_KEY_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 0)},
{NON_TRUSTED_FW_KEY_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 0)},
{SOC_FW_CONTENT_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 0)},
{TRUSTED_OS_FW_CONTENT_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 1)},
{NON_TRUSTED_FW_CONTENT_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 2)},
{BL332_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 3)},
{BL333_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 4)},
{BL334_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 5)},
{BL335_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 6)},
{BL336_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 7)},
{BL337_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 8)},
{BL338_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 9)},
};
#endif /* TRUSTED_BOARD_BOOT */
static file_state_t current_file = { 0 };
static uintptr_t rcar_handle, rcar_spec;
static uint64_t rcar_image_header[RCAR_MAX_BL3X_IMAGE + 2U] = { 0U };
static uint64_t rcar_image_header_prttn[RCAR_MAX_BL3X_IMAGE + 2U] = { 0U };
static uint64_t rcar_image_number = { 0U };
static uint32_t rcar_cert_load = { 0U };
static io_type_t device_type_rcar(void)
{
return IO_TYPE_FIRMWARE_IMAGE_PACKAGE;
}
int32_t rcar_get_certificate(const int32_t name, uint32_t *cert)
{
#if TRUSTED_BOARD_BOOT
int32_t i;
for (i = 0; i < ARRAY_SIZE(cert_offset); i++) {
if (name != cert_offset[i].name)
continue;
*cert = RCAR_CERT_SIZE;
*cert *= RCAR_ATTR_GET_CERTOFF(cert_offset[i].attr);
*cert += RCAR_SDRAM_certESS;
return 0;
}
#endif
return -EINVAL;
}
static int32_t file_to_offset(const int32_t name, uintptr_t *offset,
uint32_t *cert, uint32_t *no_load,
uintptr_t *partition)
{
uint32_t addr;
int32_t i;
for (i = 0; i < ARRAY_SIZE(name_offset); i++) {
if (name != name_offset[i].name)
continue;
addr = RCAR_ATTR_GET_CALCADDR(name_offset[i].attr);
if (rcar_image_number + 2 < addr)
continue;
*offset = rcar_image_header[addr];
*cert = RCAR_CERT_SIZE;
*cert *= RCAR_ATTR_GET_CERTOFF(name_offset[i].attr);
*cert += RCAR_SDRAM_certESS;
*no_load = RCAR_ATTR_GET_ISNOLOAD(name_offset[i].attr);
*partition = rcar_image_header_prttn[addr];
return IO_SUCCESS;
}
#if TRUSTED_BOARD_BOOT
for (i = 0; i < ARRAY_SIZE(cert_offset); i++) {
if (name != cert_offset[i].name)
continue;
*no_load = RCAR_ATTR_GET_ISNOLOAD(cert_offset[i].attr);
*partition = 0U;
*offset = 0U;
*cert = 0U;
return IO_SUCCESS;
}
#endif
return -EINVAL;
}
#define RCAR_BOOT_KEY_CERT_NEW (0xE6300F00U)
#define RCAR_CERT_MAGIC_NUM (0xE291F358U)
void rcar_read_certificate(uint64_t cert, uint32_t *len, uintptr_t *dst)
{
uint32_t seed, val, info_1, info_2;
uintptr_t size, dsth, dstl;
cert &= 0xFFFFFFFFU;
seed = mmio_read_32(RCAR_BOOT_KEY_CERT_NEW);
val = mmio_read_32(RCAR_BOOT_KEY_CERT_NEW + 0xC);
info_1 = (val >> 18) & 0x3U;
val = mmio_read_32(cert + 0xC);
info_2 = (val >> 21) & 0x3;
if (seed == RCAR_CERT_MAGIC_NUM) {
if (info_1 != 1) {
ERROR("BL2: Cert is invalid.\n");
*dst = 0;
*len = 0;
return;
}
if (info_2 > 2) {
ERROR("BL2: Cert is invalid.\n");
*dst = 0;
*len = 0;
return;
}
switch (info_2) {
case 2:
size = cert + RCAR_CERT_INFO_SIZE_OFFSET2;
dstl = cert + RCAR_CERT_INFO_DST_OFFSET2;
break;
case 1:
size = cert + RCAR_CERT_INFO_SIZE_OFFSET1;
dstl = cert + RCAR_CERT_INFO_DST_OFFSET1;
break;
case 0:
size = cert + RCAR_CERT_INFO_SIZE_OFFSET;
dstl = cert + RCAR_CERT_INFO_DST_OFFSET;
break;
}
*len = mmio_read_32(size) * 4U;
dsth = dstl + 4U;
*dst = ((uintptr_t) mmio_read_32(dsth) << 32) +
((uintptr_t) mmio_read_32(dstl));
return;
}
size = cert + RCAR_CERT_INFO_SIZE_OFFSET;
*len = mmio_read_32(size) * 4U;
dstl = cert + RCAR_CERT_INFO_DST_OFFSET;
dsth = dstl + 4U;
*dst = ((uintptr_t) mmio_read_32(dsth) << 32) +
((uintptr_t) mmio_read_32(dstl));
}
static int32_t check_load_area(uintptr_t dst, uintptr_t len)
{
uint32_t legacy = dst + len <= UINT32_MAX - 1 ? 1 : 0;
uintptr_t dram_start, dram_end;
uintptr_t prot_start, prot_end;
int32_t result = IO_SUCCESS;
dram_start = legacy ? DRAM1_BASE : DRAM_40BIT_BASE;
dram_end = legacy ? DRAM1_BASE + DRAM1_SIZE :
DRAM_40BIT_BASE + DRAM_40BIT_SIZE;
prot_start = legacy ? DRAM_PROTECTED_BASE : DRAM_40BIT_PROTECTED_BASE;
prot_end = prot_start + DRAM_PROTECTED_SIZE;
if (dst < dram_start || dst > dram_end - len) {
ERROR("BL2: dst address is on the protected area.\n");
result = IO_FAIL;
goto done;
}
/* load image is within SDRAM protected area */
if (dst >= prot_start && dst < prot_end) {
ERROR("BL2: dst address is on the protected area.\n");
result = IO_FAIL;
}
if (dst < prot_start && dst > prot_start - len) {
ERROR("BL2: loaded data is on the protected area.\n");
result = IO_FAIL;
}
done:
if (result == IO_FAIL)
ERROR("BL2: Out of range : dst=0x%lx len=0x%lx\n", dst, len);
return result;
}
static int32_t load_bl33x(void)
{
static int32_t loaded = IO_NOT_SUPPORTED;
uintptr_t dst, partition, handle;
uint32_t noload, cert, len, i;
uintptr_t offset;
int32_t rc;
size_t cnt;
const int32_t img[] = {
BL33_IMAGE_ID,
BL332_IMAGE_ID,
BL333_IMAGE_ID,
BL334_IMAGE_ID,
BL335_IMAGE_ID,
BL336_IMAGE_ID,
BL337_IMAGE_ID,
BL338_IMAGE_ID
};
if (loaded != IO_NOT_SUPPORTED)
return loaded;
for (i = 1; i < rcar_image_number; i++) {
rc = file_to_offset(img[i], &offset, &cert, &noload,
&partition);
if (rc != IO_SUCCESS) {
WARN("load_bl33x: failed to get offset\n");
loaded = IO_FAIL;
return loaded;
}
rcar_read_certificate((uint64_t) cert, &len, &dst);
((io_drv_spec_t *) rcar_spec)->partition = partition;
rc = io_open(rcar_handle, rcar_spec, &handle);
if (rc != IO_SUCCESS) {
WARN("Failed to open FIP (%i)\n", rc);
loaded = IO_FAIL;
return loaded;
}
rc = io_seek(handle, IO_SEEK_SET, offset);
if (rc != IO_SUCCESS) {
WARN("load_bl33x: failed to seek\n");
loaded = IO_FAIL;
return loaded;
}
rc = check_load_area(dst, len);
if (rc != IO_SUCCESS) {
WARN("load_bl33x: check load area\n");
loaded = IO_FAIL;
return loaded;
}
rc = io_read(handle, dst, len, &cnt);
if (rc != IO_SUCCESS) {
WARN("load_bl33x: failed to read\n");
loaded = IO_FAIL;
return loaded;
}
#if TRUSTED_BOARD_BOOT
rc = auth_mod_verify_img(img[i], (void *)dst, len);
if (rc) {
memset((void *)dst, 0x00, len);
loaded = IO_FAIL;
return loaded;
}
#endif
io_close(handle);
}
loaded = IO_SUCCESS;
return loaded;
}
static int32_t rcar_dev_init(io_dev_info_t *dev_info, const uintptr_t name)
{
uint64_t header[64] __aligned(FLASH_TRANS_SIZE_UNIT) = {
0};
uintptr_t handle;
ssize_t offset;
uint32_t i;
int32_t rc;
size_t cnt;
/* Obtain a reference to the image by querying the platform layer */
rc = plat_get_drv_source(name, &rcar_handle, &rcar_spec);
if (rc != IO_SUCCESS) {
WARN("Failed to obtain reference to img %ld (%i)\n", name, rc);
return IO_FAIL;
}
if (RCAR_CERT_LOAD == rcar_cert_load)
return IO_SUCCESS;
rc = io_open(rcar_handle, rcar_spec, &handle);
if (rc != IO_SUCCESS) {
WARN("Failed to access img %ld (%i)\n", name, rc);
return IO_FAIL;
}
/* get start address list */
/* [0] address num */
/* [1] BL33-1 image address */
/* [2] BL33-2 image address */
/* [3] BL33-3 image address */
/* [4] BL33-4 image address */
/* [5] BL33-5 image address */
/* [6] BL33-6 image address */
/* [7] BL33-7 image address */
/* [8] BL33-8 image address */
offset = name == EMMC_DEV_ID ? RCAR_EMMC_CERT_HEADER :
RCAR_FLASH_CERT_HEADER;
rc = io_seek(handle, IO_SEEK_SET, offset);
if (rc != IO_SUCCESS) {
WARN("Firmware Image Package header failed to seek\n");
goto error;
}
#if RCAR_BL2_DCACHE == 1
inv_dcache_range((uint64_t) header, sizeof(header));
#endif
rc = io_read(handle, (uintptr_t) &header, sizeof(header), &cnt);
if (rc != IO_SUCCESS) {
WARN("Firmware Image Package header failed to read\n");
goto error;
}
rcar_image_number = header[0];
for (i = 0; i < rcar_image_number + 2; i++) {
rcar_image_header[i] = header[i * 2 + 1];
rcar_image_header_prttn[i] = header[i * 2 + 2];
}
if (rcar_image_number == 0 || rcar_image_number > RCAR_MAX_BL3X_IMAGE) {
WARN("Firmware Image Package header check failed.\n");
goto error;
}
rc = io_seek(handle, IO_SEEK_SET, offset + RCAR_SECTOR6_CERT_OFFSET);
if (rc != IO_SUCCESS) {
WARN("Firmware Image Package header failed to seek cert\n");
goto error;
}
#if RCAR_BL2_DCACHE == 1
inv_dcache_range(RCAR_SDRAM_certESS,
RCAR_CERT_SIZE * (2 + rcar_image_number));
#endif
rc = io_read(handle, RCAR_SDRAM_certESS,
RCAR_CERT_SIZE * (2 + rcar_image_number), &cnt);
if (rc != IO_SUCCESS) {
WARN("cert file read error.\n");
goto error;
}
rcar_cert_load = RCAR_CERT_LOAD;
error:
if (rc != IO_SUCCESS)
rc = IO_FAIL;
io_close(handle);
return rc;
}
static int32_t rcar_file_open(io_dev_info_t *info, const uintptr_t file_spec,
io_entity_t *entity)
{
const io_drv_spec_t *spec = (io_drv_spec_t *) file_spec;
uintptr_t partition, offset, dst;
uint32_t noload, cert, len;
int32_t rc;
/* Only one file open at a time. We need to track state (ie, file
* cursor position). Since the header lives at * offset zero, this entry
* should never be zero in an active file.
* Once the system supports dynamic memory allocation we will allow more
* than one open file at a time. */
if (current_file.offset != 0U) {
WARN("rcar_file_open : Only one open file at a time.\n");
return IO_RESOURCES_EXHAUSTED;
}
rc = file_to_offset(spec->offset, &offset, &cert, &noload, &partition);
if (rc != IO_SUCCESS) {
WARN("Failed to open file name %ld (%i)\n", spec->offset, rc);
return IO_FAIL;
}
if (noload) {
current_file.offset = 1;
current_file.dst = 0;
current_file.size = 1;
current_file.position = 0;
current_file.no_load = noload;
current_file.partition = 0;
entity->info = (uintptr_t) &current_file;
return IO_SUCCESS;
}
rcar_read_certificate((uint64_t) cert, &len, &dst);
/*----------------*
* Baylibre: HACK *
*----------------*/
if (BL31_IMAGE_ID == spec->offset && len < RCAR_TRUSTED_SRAM_SIZE) {
WARN("r-car ignoring the BL31 size from certificate,"
"using RCAR_TRUSTED_SRAM_SIZE instead\n");
len = RCAR_TRUSTED_SRAM_SIZE;
}
current_file.partition = partition;
current_file.no_load = noload;
current_file.offset = offset;
current_file.position = 0;
current_file.size = len;
current_file.dst = dst;
entity->info = (uintptr_t) &current_file;
return IO_SUCCESS;
}
static int32_t rcar_file_len(io_entity_t *entity, size_t *length)
{
*length = ((file_state_t *) entity->info)->size;
NOTICE("%s: len: 0x%08lx\n", __func__, *length);
return IO_SUCCESS;
}
static int32_t rcar_file_read(io_entity_t *entity, uintptr_t buffer,
size_t length, size_t *cnt)
{
file_state_t *fp = (file_state_t *) entity->info;
ssize_t offset = fp->offset + fp->position;
uintptr_t handle;
int32_t rc;
#ifdef SPD_NONE
static uint32_t load_bl33x_counter = 1;
#else
static uint32_t load_bl33x_counter;
#endif
if (current_file.no_load) {
*cnt = length;
return IO_SUCCESS;
}
((io_drv_spec_t *) rcar_spec)->partition = fp->partition;
rc = io_open(rcar_handle, rcar_spec, &handle);
if (rc != IO_SUCCESS) {
WARN("Failed to open FIP (%i)\n", rc);
return IO_FAIL;
}
rc = io_seek(handle, IO_SEEK_SET, offset);
if (rc != IO_SUCCESS) {
WARN("rcar_file_read: failed to seek\n");
goto error;
}
if (load_bl33x_counter == RCAR_COUNT_LOAD_BL33) {
rc = check_load_area(buffer, length);
if (rc != IO_SUCCESS) {
WARN("rcar_file_read: load area err\n");
goto error;
}
}
rc = io_read(handle, buffer, length, cnt);
if (rc != IO_SUCCESS) {
WARN("Failed to read payload (%i)\n", rc);
goto error;
}
fp->position += *cnt;
io_close(handle);
load_bl33x_counter += 1;
if (load_bl33x_counter == RCAR_COUNT_LOAD_BL33X)
return load_bl33x();
return IO_SUCCESS;
error:
io_close(handle);
return IO_FAIL;
}
static int32_t rcar_file_close(io_entity_t *entity)
{
if (current_file.offset)
memset(&current_file, 0, sizeof(current_file));
entity->info = 0U;
return IO_SUCCESS;
}
static const io_dev_funcs_t rcar_dev_funcs = {
.type = &device_type_rcar,
.open = &rcar_file_open,
.seek = NULL,
.size = &rcar_file_len,
.read = &rcar_file_read,
.write = NULL,
.close = &rcar_file_close,
.dev_init = &rcar_dev_init,
.dev_close = &rcar_dev_close,
};
static const io_dev_info_t rcar_dev_info = {
.funcs = &rcar_dev_funcs,
.info = (uintptr_t) 0
};
static const io_dev_connector_t rcar_dev_connector = {
.dev_open = &rcar_dev_open
};
static int32_t rcar_dev_open(const uintptr_t dev_spec __attribute__ ((unused)),
io_dev_info_t **dev_info)
{
*dev_info = (io_dev_info_t *) &rcar_dev_info;
return IO_SUCCESS;
}
static int32_t rcar_dev_close(io_dev_info_t *dev_info)
{
rcar_handle = 0;
rcar_spec = 0;
return IO_SUCCESS;
}
int32_t rcar_register_io_dev(const io_dev_connector_t **dev_con)
{
int32_t result;
result = io_register_device(&rcar_dev_info);
if (result == IO_SUCCESS)
*dev_con = &rcar_dev_connector;
return result;
}
/*
* Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef IO_RCAR_H__
#define IO_RCAR_H__
int32_t rcar_register_io_dev(const io_dev_connector_t **dev_con);
int32_t rcar_get_certificate(const int32_t name, uint32_t *cert);
void rcar_read_certificate(uint64_t cert, uint32_t *size, uintptr_t *dest);
#endif
/*
* Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <asm_macros.S>
#include "rcar_def.h"
.global rcar_pwrc_switch_stack
.global rcar_pwrc_save_generic_timer
.global rcar_pwrc_restore_generic_timer
#define OFFSET_SP_X9_X10 (0x00)
#define OFFSET_CNTFID0 (0x10)
#define OFFSET_CNTPCT_EL0 (0x18)
#define OFFSET_TIMER_COUNT (0x20)
/*
* x0 : jump address,
* x1 : stack address,
* x2 : arg,
* x3 : stack address (temporary)
*/
func rcar_pwrc_switch_stack
/* lr to stack */
stp x29, x30, [sp,#-16]
/* change stack pointer */
mov x3, sp
mov sp, x1
/* save stack pointer */
sub sp, sp, #16
stp x0, x3, [sp]
/* data synchronization barrier */
dsb sy
/* jump to code */
mov x1, x0
mov x0, x2
blr x1
/* load stack pointer */
ldp x0, x2, [sp,#0]
/* change stack pointer */
mov sp, x2
/* return */
ldp x29, x30, [sp,#-16]
ret
endfunc rcar_pwrc_switch_stack
/* x0 : stack pointer base address */
func rcar_pwrc_save_generic_timer
stp x9, x10, [x0, #OFFSET_SP_X9_X10]
/* save CNTFID0 and cntpct_el0 */
mov_imm x10, (RCAR_CNTC_BASE + CNTFID_OFF)
ldr x9, [x10]
mrs x10, cntpct_el0
stp x9, x10, [x0, #OFFSET_CNTFID0]
ldp x9, x10, [x0, #OFFSET_SP_X9_X10]
ret
endfunc rcar_pwrc_save_generic_timer
/* x0 : Stack pointer base address */
func rcar_pwrc_restore_generic_timer
stp x9, x10, [x0, #OFFSET_SP_X9_X10]
/* restore CNTFID0 and cntpct_el0 */
ldr x10, [x0, #OFFSET_CNTFID0]
mov_imm x9, (RCAR_CNTC_BASE + CNTFID_OFF)
str x10, [x9]
ldp x9, x10, [x0, #OFFSET_CNTPCT_EL0]
add x9, x9, x10
str x9, [x0, #OFFSET_TIMER_COUNT]
ldp x9, x10, [x0, #OFFSET_SP_X9_X10]
ret
endfunc rcar_pwrc_restore_generic_timer
/*
* Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <arch_helpers.h>
#include <assert.h>
#include <bakery_lock.h>
#include <debug.h>
#include <mmio.h>
#include <string.h>
#include <xlat_tables_v2.h>
#include "iic_dvfs.h"
#include "rcar_def.h"
#include "rcar_private.h"
#include "pwrc.h"
/*
* Someday there will be a generic power controller api. At the moment each
* platform has its own pwrc so just exporting functions should be acceptable.
*/
RCAR_INSTANTIATE_LOCK
#define WUP_IRQ_SHIFT (0U)
#define WUP_FIQ_SHIFT (8U)
#define WUP_CSD_SHIFT (16U)
#define BIT_SOFTRESET (1U<<15)
#define BIT_CA53_SCU (1U<<21)
#define BIT_CA57_SCU (1U<<12)
#define REQ_RESUME (1U<<1)
#define REQ_OFF (1U<<0)
#define STATUS_PWRUP (1U<<4)
#define STATUS_PWRDOWN (1U<<0)
#define STATE_CA57_CPU (27U)
#define STATE_CA53_CPU (22U)
#define MODE_L2_DOWN (0x00000002U)
#define CPU_PWR_OFF (0x00000003U)
#define RCAR_PSTR_MASK (0x00000003U)
#define ST_ALL_STANDBY (0x00003333U)
/* Suspend to ram */
#define DBSC4_REG_BASE (0xE6790000U)
#define DBSC4_REG_DBSYSCNT0 (DBSC4_REG_BASE + 0x0100U)
#define DBSC4_REG_DBACEN (DBSC4_REG_BASE + 0x0200U)
#define DBSC4_REG_DBCMD (DBSC4_REG_BASE + 0x0208U)
#define DBSC4_REG_DBRFEN (DBSC4_REG_BASE + 0x0204U)
#define DBSC4_REG_DBWAIT (DBSC4_REG_BASE + 0x0210U)
#define DBSC4_REG_DBCALCNF (DBSC4_REG_BASE + 0x0424U)
#define DBSC4_REG_DBPDLK0 (DBSC4_REG_BASE + 0x0620U)
#define DBSC4_REG_DBPDRGA0 (DBSC4_REG_BASE + 0x0624U)
#define DBSC4_REG_DBPDRGD0 (DBSC4_REG_BASE + 0x0628U)
#define DBSC4_REG_DBCAM0CTRL0 (DBSC4_REG_BASE + 0x0940U)
#define DBSC4_REG_DBCAM0STAT0 (DBSC4_REG_BASE + 0x0980U)
#define DBSC4_REG_DBCAM1STAT0 (DBSC4_REG_BASE + 0x0990U)
#define DBSC4_REG_DBCAM2STAT0 (DBSC4_REG_BASE + 0x09A0U)
#define DBSC4_REG_DBCAM3STAT0 (DBSC4_REG_BASE + 0x09B0U)
#define DBSC4_BIT_DBACEN_ACCEN ((uint32_t)(1U << 0))
#define DBSC4_BIT_DBRFEN_ARFEN ((uint32_t)(1U << 0))
#define DBSC4_BIT_DBCAMxSTAT0 (0x00000001U)
#define DBSC4_SET_DBCMD_OPC_PRE (0x04000000U)
#define DBSC4_SET_DBCMD_OPC_SR (0x0A000000U)
#define DBSC4_SET_DBCMD_OPC_PD (0x08000000U)
#define DBSC4_SET_DBCMD_OPC_MRW (0x0E000000U)
#define DBSC4_SET_DBCMD_CH_ALL (0x00800000U)
#define DBSC4_SET_DBCMD_RANK_ALL (0x00040000U)
#define DBSC4_SET_DBCMD_ARG_ALL (0x00000010U)
#define DBSC4_SET_DBCMD_ARG_ENTER (0x00000000U)
#define DBSC4_SET_DBCMD_ARG_MRW_ODTC (0x00000B00U)
#define DBSC4_SET_DBSYSCNT0_WRITE_ENABLE (0x00001234U)
#define DBSC4_SET_DBSYSCNT0_WRITE_DISABLE (0x00000000U)
#define DBSC4_SET_DBPDLK0_PHY_ACCESS (0x0000A55AU)
#define DBSC4_SET_DBPDRGA0_ACIOCR0 (0x0000001AU)
#define DBSC4_SET_DBPDRGD0_ACIOCR0 (0x33C03C11U)
#define DBSC4_SET_DBPDRGA0_DXCCR (0x00000020U)
#define DBSC4_SET_DBPDRGD0_DXCCR (0x00181006U)
#define DBSC4_SET_DBPDRGA0_PGCR1 (0x00000003U)
#define DBSC4_SET_DBPDRGD0_PGCR1 (0x0380C600U)
#define DBSC4_SET_DBPDRGA0_ACIOCR1 (0x0000001BU)
#define DBSC4_SET_DBPDRGD0_ACIOCR1 (0xAAAAAAAAU)
#define DBSC4_SET_DBPDRGA0_ACIOCR3 (0x0000001DU)
#define DBSC4_SET_DBPDRGD0_ACIOCR3 (0xAAAAAAAAU)
#define DBSC4_SET_DBPDRGA0_ACIOCR5 (0x0000001FU)
#define DBSC4_SET_DBPDRGD0_ACIOCR5 (0x000000AAU)
#define DBSC4_SET_DBPDRGA0_DX0GCR2 (0x000000A2U)
#define DBSC4_SET_DBPDRGD0_DX0GCR2 (0xAAAA0000U)
#define DBSC4_SET_DBPDRGA0_DX1GCR2 (0x000000C2U)
#define DBSC4_SET_DBPDRGD0_DX1GCR2 (0xAAAA0000U)
#define DBSC4_SET_DBPDRGA0_DX2GCR2 (0x000000E2U)
#define DBSC4_SET_DBPDRGD0_DX2GCR2 (0xAAAA0000U)
#define DBSC4_SET_DBPDRGA0_DX3GCR2 (0x00000102U)
#define DBSC4_SET_DBPDRGD0_DX3GCR2 (0xAAAA0000U)
#define DBSC4_SET_DBPDRGA0_ZQCR (0x00000090U)
#define DBSC4_SET_DBPDRGD0_ZQCR_MD19_0 (0x04058904U)
#define DBSC4_SET_DBPDRGD0_ZQCR_MD19_1 (0x04058A04U)
#define DBSC4_SET_DBPDRGA0_DX0GCR0 (0x000000A0U)
#define DBSC4_SET_DBPDRGD0_DX0GCR0 (0x7C0002E5U)
#define DBSC4_SET_DBPDRGA0_DX1GCR0 (0x000000C0U)
#define DBSC4_SET_DBPDRGD0_DX1GCR0 (0x7C0002E5U)
#define DBSC4_SET_DBPDRGA0_DX2GCR0 (0x000000E0U)
#define DBSC4_SET_DBPDRGD0_DX2GCR0 (0x7C0002E5U)
#define DBSC4_SET_DBPDRGA0_DX3GCR0 (0x00000100U)
#define DBSC4_SET_DBPDRGD0_DX3GCR0 (0x7C0002E5U)
#define DBSC4_SET_DBPDRGA0_DX0GCR1 (0x000000A1U)
#define DBSC4_SET_DBPDRGD0_DX0GCR1 (0x55550000U)
#define DBSC4_SET_DBPDRGA0_DX1GCR1 (0x000000C1U)
#define DBSC4_SET_DBPDRGD0_DX1GCR1 (0x55550000U)
#define DBSC4_SET_DBPDRGA0_DX2GCR1 (0x000000E1U)
#define DBSC4_SET_DBPDRGD0_DX2GCR1 (0x55550000U)
#define DBSC4_SET_DBPDRGA0_DX3GCR1 (0x00000101U)
#define DBSC4_SET_DBPDRGD0_DX3GCR1 (0x55550000U)
#define DBSC4_SET_DBPDRGA0_DX0GCR3 (0x000000A3U)
#define DBSC4_SET_DBPDRGD0_DX0GCR3 (0x00008484U)
#define DBSC4_SET_DBPDRGA0_DX1GCR3 (0x000000C3U)
#define DBSC4_SET_DBPDRGD0_DX1GCR3 (0x00008484U)
#define DBSC4_SET_DBPDRGA0_DX2GCR3 (0x000000E3U)
#define DBSC4_SET_DBPDRGD0_DX2GCR3 (0x00008484U)
#define DBSC4_SET_DBPDRGA0_DX3GCR3 (0x00000103U)
#define DBSC4_SET_DBPDRGD0_DX3GCR3 (0x00008484U)
#define RST_BASE (0xE6160000U)
#define RST_MODEMR (RST_BASE + 0x0060U)
#define RST_MODEMR_BIT0 (0x00000001U)
#define RCAR_CONV_MICROSEC (1000000U)
#if PMIC_ROHM_BD9571
#define BIT_BKUP_CTRL_OUT ((uint8_t)(1U << 4))
#define PMIC_BKUP_MODE_CNT (0x20U)
#define PMIC_QLLM_CNT (0x27U)
#define PMIC_RETRY_MAX (100U)
#endif
#define SCTLR_EL3_M_BIT ((uint32_t)1U << 0)
#define RCAR_CA53CPU_NUM_MAX (4U)
#define RCAR_CA57CPU_NUM_MAX (4U)
#define IS_A53A57(c) ((c) == RCAR_CLUSTER_A53A57)
#define IS_CA57(c) ((c) == RCAR_CLUSTER_CA57)
#define IS_CA53(c) ((c) == RCAR_CLUSTER_CA53)
#ifndef __ASSEMBLY__
IMPORT_SYM(unsigned long, __system_ram_start__, SYSTEM_RAM_START);
IMPORT_SYM(unsigned long, __system_ram_end__, SYSTEM_RAM_END);
IMPORT_SYM(unsigned long, __SRAM_COPY_START__, SRAM_COPY_START);
#endif
#if RCAR_SYSTEM_SUSPEND
static void __attribute__ ((section (".system_ram")))
rcar_pwrc_micro_delay(uint64_t micro_sec)
{
uint64_t freq, base, val;
uint64_t wait_time = 0;
freq = read_cntfrq_el0();
base = read_cntpct_el0();
while (micro_sec > wait_time) {
val = read_cntpct_el0() - base;
wait_time = val * RCAR_CONV_MICROSEC / freq;
}
}
#endif
uint32_t rcar_pwrc_status(uint64_t mpidr)
{
uint32_t ret = 0;
uint64_t cm, cpu;
uint32_t reg;
uint32_t c;
rcar_lock_get();
c = rcar_pwrc_get_cluster();
cm = mpidr & MPIDR_CLUSTER_MASK;
if (!IS_A53A57(c) && cm != 0) {
ret = RCAR_INVALID;
goto done;
}
reg = mmio_read_32(RCAR_PRR);
cpu = mpidr & MPIDR_CPU_MASK;
if (IS_CA53(c))
if (reg & (1 << (STATE_CA53_CPU + cpu)))
ret = RCAR_INVALID;
if (IS_CA57(c))
if (reg & (1 << (STATE_CA57_CPU + cpu)))
ret = RCAR_INVALID;
done:
rcar_lock_release();
return ret;
}
static void scu_power_up(uint64_t mpidr)
{
uintptr_t reg_pwrsr, reg_cpumcr, reg_pwron, reg_pwrer;
uint32_t c, sysc_reg_bit;
c = rcar_pwrc_get_mpidr_cluster(mpidr);
reg_cpumcr = IS_CA57(c) ? RCAR_CA57CPUCMCR : RCAR_CA53CPUCMCR;
sysc_reg_bit = IS_CA57(c) ? BIT_CA57_SCU : BIT_CA53_SCU;
reg_pwron = IS_CA57(c) ? RCAR_PWRONCR5 : RCAR_PWRONCR3;
reg_pwrer = IS_CA57(c) ? RCAR_PWRER5 : RCAR_PWRER3;
reg_pwrsr = IS_CA57(c) ? RCAR_PWRSR5 : RCAR_PWRSR3;
if ((mmio_read_32(reg_pwrsr) & STATUS_PWRDOWN) == 0)
return;
if (mmio_read_32(reg_cpumcr) != 0)
mmio_write_32(reg_cpumcr, 0);
mmio_setbits_32(RCAR_SYSCIER, sysc_reg_bit);
mmio_setbits_32(RCAR_SYSCIMR, sysc_reg_bit);
do {
while ((mmio_read_32(RCAR_SYSCSR) & REQ_RESUME) == 0)
;
mmio_write_32(reg_pwron, 1);
} while (mmio_read_32(reg_pwrer) & 1);
while ((mmio_read_32(RCAR_SYSCISR) & sysc_reg_bit) == 0)
;
mmio_write_32(RCAR_SYSCISR, sysc_reg_bit);
while ((mmio_read_32(reg_pwrsr) & STATUS_PWRUP) == 0)
;
}
void rcar_pwrc_cpuon(uint64_t mpidr)
{
uint32_t res_data, on_data;
uintptr_t res_reg, on_reg;
uint32_t limit, c;
uint64_t cpu;
rcar_lock_get();
c = rcar_pwrc_get_mpidr_cluster(mpidr);
res_reg = IS_CA53(c) ? RCAR_CA53RESCNT : RCAR_CA57RESCNT;
on_reg = IS_CA53(c) ? RCAR_CA53WUPCR : RCAR_CA57WUPCR;
limit = IS_CA53(c) ? 0x5A5A0000 : 0xA5A50000;
res_data = mmio_read_32(res_reg) | limit;
scu_power_up(mpidr);
cpu = mpidr & MPIDR_CPU_MASK;
on_data = 1 << cpu;
mmio_write_32(RCAR_CPGWPR, ~on_data);
mmio_write_32(on_reg, on_data);
mmio_write_32(res_reg, res_data & (~(1 << (3 - cpu))));
rcar_lock_release();
}
void rcar_pwrc_cpuoff(uint64_t mpidr)
{
uint32_t c;
uintptr_t reg;
uint64_t cpu;
rcar_lock_get();
cpu = mpidr & MPIDR_CPU_MASK;
c = rcar_pwrc_get_mpidr_cluster(mpidr);
reg = IS_CA53(c) ? RCAR_CA53CPU0CR : RCAR_CA57CPU0CR;
if (read_mpidr_el1() != mpidr)
panic();
mmio_write_32(RCAR_CPGWPR, ~CPU_PWR_OFF);
mmio_write_32(reg + cpu * 0x0010, CPU_PWR_OFF);
rcar_lock_release();
}
void rcar_pwrc_enable_interrupt_wakeup(uint64_t mpidr)
{
uint32_t c, shift_irq, shift_fiq;
uintptr_t reg;
uint64_t cpu;
rcar_lock_get();
cpu = mpidr & MPIDR_CPU_MASK;
c = rcar_pwrc_get_mpidr_cluster(mpidr);
reg = IS_CA53(c) ? RCAR_WUPMSKCA53 : RCAR_WUPMSKCA57;
shift_irq = WUP_IRQ_SHIFT + cpu;
shift_fiq = WUP_FIQ_SHIFT + cpu;
mmio_write_32(reg, ~((uint32_t) 1 << shift_irq) &
~((uint32_t) 1 << shift_fiq));
rcar_lock_release();
}
void rcar_pwrc_disable_interrupt_wakeup(uint64_t mpidr)
{
uint32_t c, shift_irq, shift_fiq;
uintptr_t reg;
uint64_t cpu;
rcar_lock_get();
cpu = mpidr & MPIDR_CPU_MASK;
c = rcar_pwrc_get_mpidr_cluster(mpidr);
reg = IS_CA53(c) ? RCAR_WUPMSKCA53 : RCAR_WUPMSKCA57;
shift_irq = WUP_IRQ_SHIFT + cpu;
shift_fiq = WUP_FIQ_SHIFT + cpu;
mmio_write_32(reg, ((uint32_t) 1 << shift_irq) |
((uint32_t) 1 << shift_fiq));
rcar_lock_release();
}
void rcar_pwrc_clusteroff(uint64_t mpidr)
{
uint32_t c, product, cut, reg;
uintptr_t dst;
rcar_lock_get();
reg = mmio_read_32(RCAR_PRR);
product = reg & RCAR_PRODUCT_MASK;
cut = reg & RCAR_CUT_MASK;
c = rcar_pwrc_get_mpidr_cluster(mpidr);
dst = IS_CA53(c) ? RCAR_CA53CPUCMCR : RCAR_CA57CPUCMCR;
if (RCAR_PRODUCT_M3 == product && cut <= RCAR_M3_CUT_VER11)
goto done;
if (RCAR_PRODUCT_H3 == product && cut <= RCAR_CUT_VER20)
goto done;
/* all of the CPUs in the cluster is in the CoreStandby mode */
mmio_write_32(dst, MODE_L2_DOWN);
done:
rcar_lock_release();
}
#if !PMIC_ROHM_BD9571
void rcar_pwrc_system_reset(void)
{
mmio_write_32(RCAR_SRESCR, 0x5AA50000U | BIT_SOFTRESET);
}
#endif /* PMIC_ROHM_BD9571 */
#define RST_CA53_CPU0_BARH (0xE6160080U)
#define RST_CA53_CPU0_BARL (0xE6160084U)
#define RST_CA57_CPU0_BARH (0xE61600C0U)
#define RST_CA57_CPU0_BARL (0xE61600C4U)
void rcar_pwrc_setup(void)
{
uintptr_t rst_barh;
uintptr_t rst_barl;
uint32_t i, j;
uint64_t reset = (uint64_t) (&plat_secondary_reset) & 0xFFFFFFFF;
const uint32_t cluster[PLATFORM_CLUSTER_COUNT] = {
RCAR_CLUSTER_CA53,
RCAR_CLUSTER_CA57
};
const uintptr_t reg_barh[PLATFORM_CLUSTER_COUNT] = {
RST_CA53_CPU0_BARH,
RST_CA57_CPU0_BARH
};
const uintptr_t reg_barl[PLATFORM_CLUSTER_COUNT] = {
RST_CA53_CPU0_BARL,
RST_CA57_CPU0_BARL
};
for (i = 0; i < PLATFORM_CLUSTER_COUNT; i++) {
rst_barh = reg_barh[i];
rst_barl = reg_barl[i];
for (j = 0; j < rcar_pwrc_get_cpu_num(cluster[i]); j++) {
mmio_write_32(rst_barh, 0);
mmio_write_32(rst_barl, (uint32_t) reset);
rst_barh += 0x10;
rst_barl += 0x10;
}
}
rcar_lock_init();
}
#if RCAR_SYSTEM_SUSPEND
#define DBCAM_FLUSH(__bit) \
do { \
; \
} while (!(mmio_read_32(DBSC4_REG_DBCAM##__bit##STAT0) & DBSC4_BIT_DBCAMxSTAT0))
static void __attribute__ ((section(".system_ram")))
rcar_pwrc_set_self_refresh(void)
{
uint32_t reg = mmio_read_32(RCAR_PRR);
uint32_t cut, product;
product = reg & RCAR_PRODUCT_MASK;
cut = reg & RCAR_CUT_MASK;
if (product == RCAR_PRODUCT_M3)
goto self_refresh;
if (product == RCAR_PRODUCT_H3 && cut < RCAR_CUT_VER20)
goto self_refresh;
mmio_write_32(DBSC4_REG_DBSYSCNT0, DBSC4_SET_DBSYSCNT0_WRITE_ENABLE);
self_refresh:
/* Set the Self-Refresh mode */
mmio_write_32(DBSC4_REG_DBACEN, 0);
if (product == RCAR_PRODUCT_H3 && cut < RCAR_CUT_VER20)
rcar_pwrc_micro_delay(100);
else if (product == RCAR_PRODUCT_H3) {
mmio_write_32(DBSC4_REG_DBCAM0CTRL0, 1);
DBCAM_FLUSH(0);
DBCAM_FLUSH(1);
DBCAM_FLUSH(2);
DBCAM_FLUSH(3);
mmio_write_32(DBSC4_REG_DBCAM0CTRL0, 0);
} else if (product == RCAR_PRODUCT_M3) {
mmio_write_32(DBSC4_REG_DBCAM0CTRL0, 1);
DBCAM_FLUSH(0);
DBCAM_FLUSH(1);
mmio_write_32(DBSC4_REG_DBCAM0CTRL0, 0);
} else {
mmio_write_32(DBSC4_REG_DBCAM0CTRL0, 1);
DBCAM_FLUSH(0);
mmio_write_32(DBSC4_REG_DBCAM0CTRL0, 0);
}
/* Set the SDRAM calibration configuration register */
mmio_write_32(DBSC4_REG_DBCALCNF, 0);
reg = DBSC4_SET_DBCMD_OPC_PRE | DBSC4_SET_DBCMD_CH_ALL |
DBSC4_SET_DBCMD_RANK_ALL | DBSC4_SET_DBCMD_ARG_ALL;
mmio_write_32(DBSC4_REG_DBCMD, reg);
while (mmio_read_32(DBSC4_REG_DBWAIT))
;
/* Self-Refresh entry command */
reg = DBSC4_SET_DBCMD_OPC_SR | DBSC4_SET_DBCMD_CH_ALL |
DBSC4_SET_DBCMD_RANK_ALL | DBSC4_SET_DBCMD_ARG_ENTER;
mmio_write_32(DBSC4_REG_DBCMD, reg);
while (mmio_read_32(DBSC4_REG_DBWAIT))
;
/* Mode Register Write command. (ODT disabled) */
reg = DBSC4_SET_DBCMD_OPC_MRW | DBSC4_SET_DBCMD_CH_ALL |
DBSC4_SET_DBCMD_RANK_ALL | DBSC4_SET_DBCMD_ARG_MRW_ODTC;
mmio_write_32(DBSC4_REG_DBCMD, reg);
while (mmio_read_32(DBSC4_REG_DBWAIT))
;
/* Power Down entry command */
reg = DBSC4_SET_DBCMD_OPC_PD | DBSC4_SET_DBCMD_CH_ALL |
DBSC4_SET_DBCMD_RANK_ALL | DBSC4_SET_DBCMD_ARG_ENTER;
mmio_write_32(DBSC4_REG_DBCMD, reg);
while (mmio_read_32(DBSC4_REG_DBWAIT))
;
/* Set the auto-refresh enable register */
mmio_write_32(DBSC4_REG_DBRFEN, 0U);
rcar_pwrc_micro_delay(1U);
if (product == RCAR_PRODUCT_M3)
return;
if (product == RCAR_PRODUCT_H3 && cut < RCAR_CUT_VER20)
return;
mmio_write_32(DBSC4_REG_DBSYSCNT0, DBSC4_SET_DBSYSCNT0_WRITE_DISABLE);
}
static void __attribute__ ((section(".system_ram")))
rcar_pwrc_set_self_refresh_e3(void)
{
uint32_t ddr_md;
uint32_t reg;
ddr_md = (mmio_read_32(RST_MODEMR) >> 19) & RST_MODEMR_BIT0;
/* Write enable */
mmio_write_32(DBSC4_REG_DBSYSCNT0, DBSC4_SET_DBSYSCNT0_WRITE_ENABLE);
mmio_write_32(DBSC4_REG_DBACEN, 0);
DBCAM_FLUSH(0);
reg = DBSC4_SET_DBCMD_OPC_PRE | DBSC4_SET_DBCMD_CH_ALL |
DBSC4_SET_DBCMD_RANK_ALL | DBSC4_SET_DBCMD_ARG_ALL;
mmio_write_32(DBSC4_REG_DBCMD, reg);
while (mmio_read_32(DBSC4_REG_DBWAIT))
;
reg = DBSC4_SET_DBCMD_OPC_SR | DBSC4_SET_DBCMD_CH_ALL |
DBSC4_SET_DBCMD_RANK_ALL | DBSC4_SET_DBCMD_ARG_ENTER;
mmio_write_32(DBSC4_REG_DBCMD, reg);
while (mmio_read_32(DBSC4_REG_DBWAIT))
;
/* Set the auto-refresh enable register */
/* Set the ARFEN bit to 0 in the DBRFEN */
mmio_write_32(DBSC4_REG_DBRFEN, 0);
mmio_write_32(DBSC4_REG_DBPDLK0, DBSC4_SET_DBPDLK0_PHY_ACCESS);
mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_ACIOCR0);
mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_ACIOCR0);
/* DDR_DXCCR */
mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DXCCR);
mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DXCCR);
/* DDR_PGCR1 */
mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_PGCR1);
mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_PGCR1);
/* DDR_ACIOCR1 */
mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_ACIOCR1);
mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_ACIOCR1);
/* DDR_ACIOCR3 */
mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_ACIOCR3);
mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_ACIOCR3);
/* DDR_ACIOCR5 */
mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_ACIOCR5);
mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_ACIOCR5);
/* DDR_DX0GCR2 */
mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX0GCR2);
mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX0GCR2);
/* DDR_DX1GCR2 */
mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX1GCR2);
mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX1GCR2);
/* DDR_DX2GCR2 */
mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX2GCR2);
mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX2GCR2);
/* DDR_DX3GCR2 */
mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX3GCR2);
mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX3GCR2);
/* DDR_ZQCR */
mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_ZQCR);
mmio_write_32(DBSC4_REG_DBPDRGD0, ddr_md == 0 ?
DBSC4_SET_DBPDRGD0_ZQCR_MD19_0 :
DBSC4_SET_DBPDRGD0_ZQCR_MD19_1);
/* DDR_DX0GCR0 */
mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX0GCR0);
mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX0GCR0);
/* DDR_DX1GCR0 */
mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX1GCR0);
mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX1GCR0);
/* DDR_DX2GCR0 */
mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX2GCR0);
mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX2GCR0);
/* DDR_DX3GCR0 */
mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX3GCR0);
mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX3GCR0);
/* DDR_DX0GCR1 */
mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX0GCR1);
mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX0GCR1);
/* DDR_DX1GCR1 */
mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX1GCR1);
mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX1GCR1);
/* DDR_DX2GCR1 */
mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX2GCR1);
mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX2GCR1);
/* DDR_DX3GCR1 */
mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX3GCR1);
mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX3GCR1);
/* DDR_DX0GCR3 */
mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX0GCR3);
mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX0GCR3);
/* DDR_DX1GCR3 */
mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX1GCR3);
mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX1GCR3);
/* DDR_DX2GCR3 */
mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX2GCR3);
mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX2GCR3);
/* DDR_DX3GCR3 */
mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX3GCR3);
mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX3GCR3);
/* Write disable */
mmio_write_32(DBSC4_REG_DBSYSCNT0, DBSC4_SET_DBSYSCNT0_WRITE_DISABLE);
}
void __attribute__ ((section(".system_ram"))) __attribute__ ((noinline))
rcar_pwrc_go_suspend_to_ram(void)
{
#if PMIC_ROHM_BD9571
int32_t rc = -1, qllm = -1;
uint8_t mode;
uint32_t i;
#endif
uint32_t reg, product;
reg = mmio_read_32(RCAR_PRR);
product = reg & RCAR_PRODUCT_MASK;
if (product != RCAR_PRODUCT_E3)
rcar_pwrc_set_self_refresh();
else
rcar_pwrc_set_self_refresh_e3();
#if PMIC_ROHM_BD9571
/* Set QLLM Cnt Disable */
for (i = 0; (i < PMIC_RETRY_MAX) && (qllm != 0); i++)
qllm = rcar_iic_dvfs_send(PMIC, PMIC_QLLM_CNT, 0);
/* Set trigger of power down to PMIV */
for (i = 0; (i < PMIC_RETRY_MAX) && (rc != 0) && (qllm == 0); i++) {
rc = rcar_iic_dvfs_receive(PMIC, PMIC_BKUP_MODE_CNT, &mode);
if (rc == 0) {
mode |= BIT_BKUP_CTRL_OUT;
rc = rcar_iic_dvfs_send(PMIC, PMIC_BKUP_MODE_CNT, mode);
}
}
#endif
wfi();
while (1)
;
}
void rcar_pwrc_set_suspend_to_ram(void)
{
uintptr_t jump = (uintptr_t) &rcar_pwrc_go_suspend_to_ram;
uintptr_t stack = (uintptr_t) (DEVICE_SRAM_STACK_BASE +
DEVICE_SRAM_STACK_SIZE);
uint32_t sctlr;
rcar_pwrc_code_copy_to_system_ram();
rcar_pwrc_save_generic_timer(rcar_stack_generic_timer);
/* disable MMU */
sctlr = (uint32_t) read_sctlr_el3();
sctlr &= (uint32_t) ~SCTLR_EL3_M_BIT;
write_sctlr_el3((uint64_t) sctlr);
rcar_pwrc_switch_stack(jump, stack, NULL);
}
void rcar_pwrc_init_suspend_to_ram(void)
{
#if PMIC_ROHM_BD9571
uint8_t mode;
#endif
rcar_pwrc_code_copy_to_system_ram();
#if PMIC_ROHM_BD9571
if (rcar_iic_dvfs_receive(PMIC, PMIC_BKUP_MODE_CNT, &mode))
panic();
mode &= (uint8_t) (~BIT_BKUP_CTRL_OUT);
if (rcar_iic_dvfs_send(PMIC, PMIC_BKUP_MODE_CNT, mode))
panic();
#endif
}
void rcar_pwrc_suspend_to_ram(void)
{
#if RCAR_SYSTEM_RESET_KEEPON_DDR
int32_t error;
rcar_pwrc_code_copy_to_system_ram();
error = rcar_iic_dvfs_send(PMIC, REG_KEEP10, 0);
if (error) {
ERROR("Failed send KEEP10 init ret=%d \n", error);
return;
}
#endif
rcar_pwrc_set_suspend_to_ram();
}
#endif
void rcar_pwrc_code_copy_to_system_ram(void)
{
int ret __attribute__ ((unused)); /* in assert */
uint32_t attr;
struct device_sram_t {
uintptr_t base;
size_t len;
} sram = {
.base = (uintptr_t) DEVICE_SRAM_BASE,
.len = DEVICE_SRAM_SIZE,
};
struct ddr_code_t {
void *base;
size_t len;
} code = {
.base = (void *) SRAM_COPY_START,
.len = SYSTEM_RAM_END - SYSTEM_RAM_START,
};
attr = MT_MEMORY | MT_RW | MT_SECURE | MT_EXECUTE_NEVER;
ret = xlat_change_mem_attributes(sram.base, sram.len, attr);
assert(ret == 0);
memcpy((void *)sram.base, code.base, code.len);
flush_dcache_range((uint64_t) sram.base, code.len);
/* Invalidate instruction cache */
plat_invalidate_icache();
dsb();
isb();
attr = MT_MEMORY | MT_RO | MT_SECURE | MT_EXECUTE;
ret = xlat_change_mem_attributes(sram.base, sram.len, attr);
assert(ret == 0);
}
uint32_t rcar_pwrc_get_cluster(void)
{
uint32_t reg;
reg = mmio_read_32(RCAR_PRR);
if (reg & (1 << (STATE_CA53_CPU + RCAR_CA53CPU_NUM_MAX)))
return RCAR_CLUSTER_CA57;
if (reg & (1 << (STATE_CA57_CPU + RCAR_CA57CPU_NUM_MAX)))
return RCAR_CLUSTER_CA53;
return RCAR_CLUSTER_A53A57;
}
uint32_t rcar_pwrc_get_mpidr_cluster(uint64_t mpidr)
{
uint32_t c = rcar_pwrc_get_cluster();
if (IS_A53A57(c)) {
if (mpidr & MPIDR_CLUSTER_MASK)
return RCAR_CLUSTER_CA53;
return RCAR_CLUSTER_CA57;
}
return c;
}
uint32_t rcar_pwrc_get_cpu_num(uint32_t c)
{
uint32_t reg = mmio_read_32(RCAR_PRR);
uint32_t count = 0, i;
if (IS_A53A57(c) || IS_CA53(c)) {
if (reg & (1 << (STATE_CA53_CPU + RCAR_CA53CPU_NUM_MAX)))
goto count_ca57;
for (i = 0; i < RCAR_CA53CPU_NUM_MAX; i++) {
if (reg & (1 << (STATE_CA53_CPU + i)))
continue;
count++;
}
}
count_ca57:
if (IS_A53A57(c) || IS_CA57(c)) {
if (reg & (1 << (STATE_CA57_CPU + RCAR_CA57CPU_NUM_MAX)))
goto done;
for (i = 0; i < RCAR_CA57CPU_NUM_MAX; i++) {
if (reg & (1 << (STATE_CA57_CPU + i)))
continue;
count++;
}
}
done:
return count;
}
/*
* Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef RCAR_PWRC_H__
#define RCAR_PWRC_H__
#define PPOFFR_OFF 0x0
#define PPONR_OFF 0x4
#define PCOFFR_OFF 0x8
#define PWKUPR_OFF 0xc
#define PSYSR_OFF 0x10
#define PWKUPR_WEN (1ull << 31)
#define PSYSR_AFF_L2 (1 << 31)
#define PSYSR_AFF_L1 (1 << 30)
#define PSYSR_AFF_L0 (1 << 29)
#define PSYSR_WEN (1 << 28)
#define PSYSR_PC (1 << 27)
#define PSYSR_PP (1 << 26)
#define PSYSR_WK_SHIFT (24)
#define PSYSR_WK_MASK (0x3)
#define PSYSR_WK(x) (((x) >> PSYSR_WK_SHIFT) & PSYSR_WK_MASK)
#define WKUP_COLD 0x0
#define WKUP_RESET 0x1
#define WKUP_PPONR 0x2
#define WKUP_GICREQ 0x3
#define RCAR_INVALID (0xffffffffU)
#define PSYSR_INVALID 0xffffffff
#define RCAR_CLUSTER_A53A57 (0U)
#define RCAR_CLUSTER_CA53 (1U)
#define RCAR_CLUSTER_CA57 (2U)
#ifndef __ASSEMBLY__
void rcar_pwrc_disable_interrupt_wakeup(uint64_t mpidr);
void rcar_pwrc_enable_interrupt_wakeup(uint64_t mpidr);
void rcar_pwrc_clusteroff(uint64_t mpidr);
void rcar_pwrc_cpuoff(uint64_t mpidr);
void rcar_pwrc_cpuon(uint64_t mpidr);
void rcar_pwrc_setup(void);
uint32_t rcar_pwrc_get_cpu_wkr(uint64_t mpidr);
uint32_t rcar_pwrc_status(uint64_t mpidr);
uint32_t rcar_pwrc_get_cluster(void);
uint32_t rcar_pwrc_get_mpidr_cluster(uint64_t mpidr);
uint32_t rcar_pwrc_get_cpu_num(uint32_t cluster_type);
void plat_secondary_reset(void);
void rcar_pwrc_code_copy_to_system_ram(void);
#if !PMIC_ROHM_BD9571
void rcar_pwrc_system_reset(void);
#endif
#if RCAR_SYSTEM_SUSPEND
void rcar_pwrc_go_suspend_to_ram(void);
void rcar_pwrc_set_suspend_to_ram(void);
void rcar_pwrc_init_suspend_to_ram(void);
void rcar_pwrc_suspend_to_ram(void);
#endif
extern void rcar_pwrc_save_generic_timer(uint64_t *rcar_stack_generic_timer);
extern uint32_t rcar_pwrc_switch_stack(uintptr_t jump, uintptr_t stack,
void *arg);
extern uint64_t rcar_stack_generic_timer[5];
#endif
#endif
/*
* Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <mmio.h>
#include <stdint.h>
#include "rcar_def.h"
#include "rom_api.h"
typedef uint32_t(*rom_secure_boot_api_f) (uint32_t *key, uint32_t *cert,
rom_read_flash_f pFuncReadFlash);
typedef uint32_t(*rom_get_lcs_api_f) (uint32_t *lcs);
#define OLD_API_TABLE1 (0U) /* H3 Ver.1.0/Ver.1.1 */
#define OLD_API_TABLE2 (1U) /* H3 Ver.2.0 */
#define OLD_API_TABLE3 (2U) /* M3 Ver.1.0 */
#define NEW_API_TABLE (3U) /* H3 Ver.3.0, M3 Ver.1.1 or later, M3N, E3 */
#define API_TABLE_MAX (4U) /* table max */
/* Later than H3 Ver.2.0 */
static uint32_t get_table_index(void)
{
uint32_t product;
uint32_t cut_ver;
uint32_t index;
product = mmio_read_32(RCAR_PRR) & RCAR_PRODUCT_MASK;
cut_ver = mmio_read_32(RCAR_PRR) & RCAR_CUT_MASK;
switch (product) {
case RCAR_PRODUCT_H3:
if (cut_ver == RCAR_CUT_VER10)
index = OLD_API_TABLE1;
else if (cut_ver == RCAR_CUT_VER11)
index = OLD_API_TABLE1;
else if (cut_ver == RCAR_CUT_VER20)
index = OLD_API_TABLE2;
else
/* Later than H3 Ver.2.0 */
index = NEW_API_TABLE;
break;
case RCAR_PRODUCT_M3:
if (cut_ver == RCAR_CUT_VER10)
index = OLD_API_TABLE3;
else
/* M3 Ver.1.1 or later */
index = NEW_API_TABLE;
break;
default:
index = NEW_API_TABLE;
break;
}
return index;
}
uint32_t rcar_rom_secure_boot_api(uint32_t *key, uint32_t *cert,
rom_read_flash_f read_flash)
{
static const uintptr_t rom_api_table[API_TABLE_MAX] = {
0xEB10DD64U, /* H3 Ver.1.0/Ver.1.1 */
0xEB116ED4U, /* H3 Ver.2.0 */
0xEB1102FCU, /* M3 Ver.1.0 */
0xEB100180U /* H3 Ver.3.0, M3 Ver.1.1 or later, M3N, E3 */
};
rom_secure_boot_api_f secure_boot;
uint32_t index;
index = get_table_index();
secure_boot = (rom_secure_boot_api_f) rom_api_table[index];
return secure_boot(key, cert, read_flash);
}
uint32_t rcar_rom_get_lcs(uint32_t *lcs)
{
static const uintptr_t rom_get_lcs_table[API_TABLE_MAX] = {
0xEB10DFE0U, /* H3 Ver.1.0/Ver.1.1 */
0xEB117150U, /* H3 Ver.2.0 */
0xEB110578U, /* M3 Ver.1.0 */
0xEB10018CU /* H3 Ver.3.0, M3 Ver.1.1 or later, M3N, E3 */
};
rom_get_lcs_api_f get_lcs;
uint32_t index;
index = get_table_index();
get_lcs = (rom_get_lcs_api_f) rom_get_lcs_table[index];
return get_lcs(lcs);
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment