diff options
| author | Soby Mathew <soby.mathew@arm.com> | 2018-10-18 09:54:55 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-10-18 09:54:55 +0100 |
| commit | a51443fa7e50346d167a93efb556f290eb63bd5c (patch) | |
| tree | 5941b70aae91a19f1ac4f120df9d51643d862691 /drivers/renesas | |
| parent | 0059be2d95174949f027195da0f1902a3c2722d6 (diff) | |
| parent | 84433c5096ead796dc580eee92728b9888a8b01b (diff) | |
Merge pull request #1582 from ldts/rcar_gen3/upstream
rcar_gen3: initial support
Diffstat (limited to 'drivers/renesas')
43 files changed, 7897 insertions, 0 deletions
diff --git a/drivers/renesas/rcar/auth/auth_mod.c b/drivers/renesas/rcar/auth/auth_mod.c new file mode 100644 index 00000000..04ed2792 --- /dev/null +++ b/drivers/renesas/rcar/auth/auth_mod.c @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights + * reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch_helpers.h> +#include <debug.h> +#include <mmio.h> +#include <platform.h> +#include <platform_def.h> +#include <stddef.h> + +#include "rom_api.h" + +typedef int32_t(*secure_boot_api_f) (uint32_t a, uint32_t b, void *c); +extern int32_t rcar_get_certificate(const int32_t name, uint32_t *cert_addr); + +#define RCAR_IMAGE_ID_MAX (10) +#define RCAR_CERT_MAGIC_NUM (0xE291F358U) +#define RCAR_BOOT_KEY_CERT (0xE6300C00U) +#define RCAR_BOOT_KEY_CERT_NEW (0xE6300F00U) +#define RST_BASE (0xE6160000U) +#define RST_MODEMR (RST_BASE + 0x0060U) +#define MFISSOFTMDR (0xE6260600U) +#define MODEMR_MD5_MASK (0x00000020U) +#define MODEMR_MD5_SHIFT (5U) +#define SOFTMD_BOOTMODE_MASK (0x00000001U) +#define SOFTMD_NORMALBOOT (0x1U) + +static secure_boot_api_f secure_boot_api; + +int auth_mod_get_parent_id(unsigned int img_id, unsigned int *parent_id) +{ + return 1; +} + +int auth_mod_verify_img(unsigned int img_id, void *ptr, unsigned int len) +{ + int32_t ret = 0, index = 0; + uint32_t cert_addr = 0U; + static const struct img_to_cert_t { + uint32_t id; + int32_t cert; + const char *name; + } image[RCAR_IMAGE_ID_MAX] = { + { BL31_IMAGE_ID, SOC_FW_CONTENT_CERT_ID, "BL31" }, + { BL32_IMAGE_ID, TRUSTED_OS_FW_CONTENT_CERT_ID, "BL32" }, + { BL33_IMAGE_ID, NON_TRUSTED_FW_CONTENT_CERT_ID, "BL33" }, + { BL332_IMAGE_ID, BL332_CERT_ID, "BL332" }, + { BL333_IMAGE_ID, BL333_CERT_ID, "BL333" }, + { BL334_IMAGE_ID, BL334_CERT_ID, "BL334" }, + { BL335_IMAGE_ID, BL335_CERT_ID, "BL335" }, + { BL336_IMAGE_ID, BL336_CERT_ID, "BL336" }, + { BL337_IMAGE_ID, BL337_CERT_ID, "BL337" }, + { BL338_IMAGE_ID, BL338_CERT_ID, "BL338" }, + }; + +#if IMAGE_BL2 + switch (img_id) { + case TRUSTED_KEY_CERT_ID: + case SOC_FW_KEY_CERT_ID: + case TRUSTED_OS_FW_KEY_CERT_ID: + case NON_TRUSTED_FW_KEY_CERT_ID: + case BL332_KEY_CERT_ID: + case BL333_KEY_CERT_ID: + case BL334_KEY_CERT_ID: + case BL335_KEY_CERT_ID: + case BL336_KEY_CERT_ID: + case BL337_KEY_CERT_ID: + case BL338_KEY_CERT_ID: + case SOC_FW_CONTENT_CERT_ID: + case TRUSTED_OS_FW_CONTENT_CERT_ID: + case NON_TRUSTED_FW_CONTENT_CERT_ID: + case BL332_CERT_ID: + case BL333_CERT_ID: + case BL334_CERT_ID: + case BL335_CERT_ID: + case BL336_CERT_ID: + case BL337_CERT_ID: + case BL338_CERT_ID: + return ret; + case BL31_IMAGE_ID: + case BL32_IMAGE_ID: + case BL33_IMAGE_ID: + case BL332_IMAGE_ID: + case BL333_IMAGE_ID: + case BL334_IMAGE_ID: + case BL335_IMAGE_ID: + case BL336_IMAGE_ID: + case BL337_IMAGE_ID: + case BL338_IMAGE_ID: + goto verify_image; + default: + return -1; + } + +verify_image: + for (index = 0; index < RCAR_IMAGE_ID_MAX; index++) { + if (img_id != image[index].id) + continue; + + ret = rcar_get_certificate(image[index].cert, &cert_addr); + break; + } + + if (ret || (index == RCAR_IMAGE_ID_MAX)) { + ERROR("Verification Failed for image id = %d\n", img_id); + return ret; + } +#if RCAR_BL2_DCACHE == 1 + /* clean and disable */ + write_sctlr_el1(read_sctlr_el1() & ~SCTLR_C_BIT); + dcsw_op_all(DCCISW); +#endif + ret = (mmio_read_32(RCAR_BOOT_KEY_CERT_NEW) == RCAR_CERT_MAGIC_NUM) ? + secure_boot_api(RCAR_BOOT_KEY_CERT_NEW, cert_addr, NULL) : + secure_boot_api(RCAR_BOOT_KEY_CERT, cert_addr, NULL); + if (ret) + ERROR("Verification Failed 0x%x, %s\n", ret, image[index].name); + +#if RCAR_BL2_DCACHE == 1 + /* enable */ + write_sctlr_el1(read_sctlr_el1() | SCTLR_C_BIT); +#endif + +#endif + return ret; +} + +static int32_t normal_boot_verify(uint32_t a, uint32_t b, void *c) +{ + return 0; +} + +void auth_mod_init(void) +{ +#if RCAR_SECURE_BOOT + uint32_t soft_md = mmio_read_32(MFISSOFTMDR) & SOFTMD_BOOTMODE_MASK; + uint32_t md = mmio_read_32(RST_MODEMR) & MODEMR_MD5_MASK; + uint32_t lcs, ret; + + secure_boot_api = (secure_boot_api_f) &rcar_rom_secure_boot_api; + + ret = rcar_rom_get_lcs(&lcs); + if (ret) { + ERROR("BL2: Failed to get the LCS. (%d)\n", ret); + panic(); + } + + switch (lcs) { + case LCS_SE: + if (soft_md == SOFTMD_NORMALBOOT) + secure_boot_api = &normal_boot_verify; + break; + case LCS_SD: + secure_boot_api = &normal_boot_verify; + break; + default: + if (md >> MODEMR_MD5_SHIFT) + secure_boot_api = &normal_boot_verify; + } + + NOTICE("BL2: %s boot\n", + secure_boot_api == &normal_boot_verify ? "Normal" : "Secure"); +#else + NOTICE("BL2: Normal boot\n"); + secure_boot_api = &normal_boot_verify; +#endif +} diff --git a/drivers/renesas/rcar/avs/avs_driver.c b/drivers/renesas/rcar/avs/avs_driver.c new file mode 100644 index 00000000..80a7c919 --- /dev/null +++ b/drivers/renesas/rcar/avs/avs_driver.c @@ -0,0 +1,623 @@ +/* + * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <mmio.h> +#include <debug.h> +#include <utils_def.h> +#include "cpg_registers.h" +#include "avs_driver.h" +#include "rcar_def.h" +#include "rcar_private.h" + +#if (AVS_SETTING_ENABLE == 1) +#if PMIC_ROHM_BD9571 +/* Read PMIC register for debug. 1:enable / 0:disable */ +#define AVS_READ_PMIC_REG_ENABLE 0 +/* The re-try number of times of the AVS setting. */ +#define AVS_RETRY_NUM (1U) +#endif /* PMIC_ROHM_BD9571 */ + +/* Base address of Adaptive Voltage Scaling module registers*/ +#define AVS_BASE (0xE60A0000U) +/* Adaptive Dynamic Voltage ADJust Parameter2 registers */ +#define ADVADJP2 (AVS_BASE + 0x013CU) + +/* Mask VOLCOND bit in ADVADJP2 registers */ +#define ADVADJP2_VOLCOND_MASK (0x000001FFU) /* VOLCOND[8:0] */ + +#if PMIC_ROHM_BD9571 +/* I2C for DVFS bit in CPG registers for module standby and software reset*/ +#define CPG_SYS_DVFS_BIT (0x04000000U) +#endif /* PMIC_ROHM_BD9571 */ +/* ADVFS Module bit in CPG registers for module standby and software reset*/ +#define CPG_SYS_ADVFS_BIT (0x02000000U) + +#if PMIC_ROHM_BD9571 +/* Base address of IICDVFS registers*/ +#define IIC_DVFS_BASE (0xE60B0000U) +/* IIC bus data register */ +#define IIC_ICDR (IIC_DVFS_BASE + 0x0000U) +/* IIC bus control register */ +#define IIC_ICCR (IIC_DVFS_BASE + 0x0004U) +/* IIC bus status register */ +#define IIC_ICSR (IIC_DVFS_BASE + 0x0008U) +/* IIC interrupt control register */ +#define IIC_ICIC (IIC_DVFS_BASE + 0x000CU) +/* IIC clock control register low */ +#define IIC_ICCL (IIC_DVFS_BASE + 0x0010U) +/* IIC clock control register high */ +#define IIC_ICCH (IIC_DVFS_BASE + 0x0014U) + +/* Bit in ICSR register */ +#define ICSR_BUSY (0x10U) +#define ICSR_AL (0x08U) +#define ICSR_TACK (0x04U) +#define ICSR_WAIT (0x02U) +#define ICSR_DTE (0x01U) + +/* Bit in ICIC register */ +#define ICIC_TACKE (0x04U) +#define ICIC_WAITE (0x02U) +#define ICIC_DTEE (0x01U) + +/* I2C bus interface enable */ +#define ICCR_ENABLE (0x80U) +/* Start condition */ +#define ICCR_START (0x94U) +/* Stop condition */ +#define ICCR_STOP (0x90U) +/* Restart condition with change to receive mode change */ +#define ICCR_START_RECV (0x81U) +/* Stop condition for receive mode */ +#define ICCR_STOP_RECV (0xC0U) + +/* Low-level period of SCL */ +#define ICCL_FREQ_8p33M (0x07U) /* for CP Phy 8.3333MHz */ +#define ICCL_FREQ_10M (0x09U) /* for CP Phy 10MHz */ +#define ICCL_FREQ_12p5M (0x0BU) /* for CP Phy 12.5MHz */ +#define ICCL_FREQ_16p66M (0x0EU) /* for CP Phy 16.6666MHz */ +/* High-level period of SCL */ +#define ICCH_FREQ_8p33M (0x01U) /* for CP Phy 8.3333MHz */ +#define ICCH_FREQ_10M (0x02U) /* for CP Phy 10MHz */ +#define ICCH_FREQ_12p5M (0x03U) /* for CP Phy 12.5MHz */ +#define ICCH_FREQ_16p66M (0x05U) /* for CP Phy 16.6666MHz */ + +/* PMIC */ +#define PMIC_W_SLAVE_ADDRESS (0x60U) /* ROHM BD9571 slave address + (W) */ +#define PMIC_R_SLAVE_ADDRESS (0x61U) /* ROHM BD9571 slave address + (R) */ +#define PMIC_DVFS_SETVID (0x54U) /* ROHM BD9571 DVFS SetVID register */ +#endif /* PMIC_ROHM_BD9571 */ + +/* Individual information */ +#define EFUSE_AVS0 (0U) +#define EFUSE_AVS_NUM ARRAY_SIZE(init_vol_tbl) + +typedef struct { + uint32_t avs; /* AVS code */ + uint8_t vol; /* Voltage */ +} initial_voltage_t; + +static const initial_voltage_t init_vol_tbl[] = { + /* AVS code, RHOM BD9571 DVFS SetVID register */ + {0x00U, 0x53U}, /* AVS0, 0.83V */ + {0x01U, 0x52U}, /* AVS1, 0.82V */ + {0x02U, 0x51U}, /* AVS2, 0.81V */ + {0x04U, 0x50U}, /* AVS3, 0.80V */ + {0x08U, 0x4FU}, /* AVS4, 0.79V */ + {0x10U, 0x4EU}, /* AVS5, 0.78V */ + {0x20U, 0x4DU}, /* AVS6, 0.77V */ + {0x40U, 0x4CU} /* AVS7, 0.76V */ +}; + +#if PMIC_ROHM_BD9571 +/* Kind of AVS settings status */ +typedef enum { + avs_status_none = 0, + avs_status_init, + avs_status_start_condition, + avs_status_set_slave_addr, + avs_status_write_reg_addr, + avs_status_write_reg_data, + avs_status_stop_condition, + avs_status_end, + avs_status_complete, + avs_status_al_start, + avs_status_al_transfer, + avs_status_nack, + avs_status_error_stop, + ave_status_error_end +} avs_status_t; + +/* Kind of AVS error */ +typedef enum { + avs_error_none = 0, + avs_error_al, + avs_error_nack +} avs_error_t; + +static avs_status_t avs_status; +static uint32_t avs_retry; +#endif /* PMIC_ROHM_BD9571 */ +static uint32_t efuse_avs = EFUSE_AVS0; + +#if PMIC_ROHM_BD9571 +/* prototype */ +static avs_error_t avs_check_error(void); +static void avs_set_iic_clock(void); +#if AVS_READ_PMIC_REG_ENABLE == 1 +static uint8_t avs_read_pmic_reg(uint8_t addr); +static void avs_poll(uint8_t bit_pos, uint8_t val); +#endif +#endif /* PMIC_ROHM_BD9571 */ +#endif /* (AVS_SETTING_ENABLE==1) */ + +/* + * Initialize to enable the AVS setting. + */ +void rcar_avs_init(void) +{ +#if (AVS_SETTING_ENABLE == 1) + uint32_t val; + +#if PMIC_ROHM_BD9571 + /* Initialize AVS status */ + avs_status = avs_status_init; +#endif /* PMIC_ROHM_BD9571 */ + + /* Enable clock supply to ADVFS. */ + mstpcr_write(CPG_SMSTPCR9, CPG_MSTPSR9, CPG_SYS_ADVFS_BIT); + + /* Read AVS code (Initial values are derived from eFuse) */ + val = mmio_read_32(ADVADJP2) & ADVADJP2_VOLCOND_MASK; + + for (efuse_avs = 0U; efuse_avs < EFUSE_AVS_NUM; efuse_avs++) { + if (val == init_vol_tbl[efuse_avs].avs) + break; + } + + if (efuse_avs >= EFUSE_AVS_NUM) + efuse_avs = EFUSE_AVS0; /* Not applicable */ +#if PMIC_ROHM_BD9571 + /* Enable clock supply to DVFS. */ + mstpcr_write(CPG_SMSTPCR9, CPG_MSTPSR9, CPG_SYS_DVFS_BIT); + + /* Disable I2C module and All internal registers initialized. */ + mmio_write_8(IIC_ICCR, 0x00U); + while ((mmio_read_8(IIC_ICCR) & ICCR_ENABLE) != 0U) { + /* Disable I2C module and All internal registers initialized. */ + mmio_write_8(IIC_ICCR, 0x00U); + } + + /* Set next status */ + avs_status = avs_status_start_condition; + +#endif /* PMIC_ROHM_BD9571 */ +#endif /* (AVS_SETTING_ENABLE==1) */ +} + +/* + * Set the value of register corresponding to the voltage + * by transfer of I2C to PIMC. + */ +void rcar_avs_setting(void) +{ +#if (AVS_SETTING_ENABLE == 1) +#if PMIC_ROHM_BD9571 + avs_error_t err; + + switch (avs_status) { + case avs_status_start_condition: + /* Set ICCR.ICE=1 to activate the I2C module. */ + mmio_write_8(IIC_ICCR, mmio_read_8(IIC_ICCR) | ICCR_ENABLE); + /* Set frequency of 400kHz */ + avs_set_iic_clock(); + /* Set ICIC.TACKE=1, ICIC.WAITE=1, ICIC.DTEE=1 to */ + /* enable interrupt control. */ + mmio_write_8(IIC_ICIC, mmio_read_8(IIC_ICIC) + | ICIC_TACKE | ICIC_WAITE | ICIC_DTEE); + /* Write H'94 in ICCR to issue start condition */ + mmio_write_8(IIC_ICCR, ICCR_START); + /* Set next status */ + avs_status = avs_status_set_slave_addr; + break; + case avs_status_set_slave_addr: + /* Check error. */ + err = avs_check_error(); + if (err == avs_error_al) { + /* Recovery sequence of just after start. */ + avs_status = avs_status_al_start; + } else if (err == avs_error_nack) { + /* Recovery sequence of detected NACK */ + avs_status = avs_status_nack; + } else { + /* Was data transmission enabled ? */ + if ((mmio_read_8(IIC_ICSR) & ICSR_DTE) == ICSR_DTE) { + /* Clear ICIC.DTEE to disable a DTE interrupt */ + mmio_write_8(IIC_ICIC, mmio_read_8(IIC_ICIC) + & (uint8_t) (~ICIC_DTEE)); + /* Send PMIC slave address + (W) */ + mmio_write_8(IIC_ICDR, PMIC_W_SLAVE_ADDRESS); + /* Set next status */ + avs_status = avs_status_write_reg_addr; + } + } + break; + case avs_status_write_reg_addr: + /* Check error. */ + err = avs_check_error(); + if (err == avs_error_al) { + /* Recovery sequence of during data transfer. */ + avs_status = avs_status_al_transfer; + } else if (err == avs_error_nack) { + /* Recovery sequence of detected NACK */ + avs_status = avs_status_nack; + } else { + /* If wait state after data transmission. */ + if ((mmio_read_8(IIC_ICSR) & ICSR_WAIT) == ICSR_WAIT) { + /* Write PMIC DVFS_SetVID address */ + mmio_write_8(IIC_ICDR, PMIC_DVFS_SETVID); + /* Clear ICSR.WAIT to exit from wait state. */ + mmio_write_8(IIC_ICSR, mmio_read_8(IIC_ICSR) + & (uint8_t) (~ICSR_WAIT)); + /* Set next status */ + avs_status = avs_status_write_reg_data; + } + } + break; + case avs_status_write_reg_data: + /* Check error. */ + err = avs_check_error(); + if (err == avs_error_al) { + /* Recovery sequence of during data transfer. */ + avs_status = avs_status_al_transfer; + } else if (err == avs_error_nack) { + /* Recovery sequence of detected NACK */ + avs_status = avs_status_nack; + } else { + /* If wait state after data transmission. */ + if ((mmio_read_8(IIC_ICSR) & ICSR_WAIT) == ICSR_WAIT) { + /* Dose efuse_avs exceed the number of */ + /* the tables? */ + if (efuse_avs >= EFUSE_AVS_NUM) { + ERROR("AVS number of eFuse is out " + "of a range. number=%u\n", + efuse_avs); + /* Infinite loop */ + panic(); + } + /* Write PMIC DVFS_SetVID value */ + mmio_write_8(IIC_ICDR, + init_vol_tbl[efuse_avs].vol); + /* Clear ICSR.WAIT to exit from wait state. */ + mmio_write_8(IIC_ICSR, mmio_read_8(IIC_ICSR) + & (uint8_t) (~ICSR_WAIT)); + /* Set next status */ + avs_status = avs_status_stop_condition; + } + } + break; + case avs_status_stop_condition: + err = avs_check_error(); + if (err == avs_error_al) { + /* Recovery sequence of during data transfer. */ + avs_status = avs_status_al_transfer; + } else if (err == avs_error_nack) { + /* Recovery sequence of detected NACK */ + avs_status = avs_status_nack; + } else { + /* If wait state after data transmission. */ + if ((mmio_read_8(IIC_ICSR) & ICSR_WAIT) == ICSR_WAIT) { + /* Write H'90 in ICCR to issue stop condition */ + mmio_write_8(IIC_ICCR, ICCR_STOP); + /* Clear ICSR.WAIT to exit from wait state. */ + mmio_write_8(IIC_ICSR, mmio_read_8(IIC_ICSR) + & (uint8_t) (~ICSR_WAIT)); + /* Set next status */ + avs_status = avs_status_end; + } + } + break; + case avs_status_end: + /* Is this module not busy?. */ + if ((mmio_read_8(IIC_ICSR) & ICSR_BUSY) == 0U) { + /* Set ICCR=H'00 to disable the I2C module. */ + mmio_write_8(IIC_ICCR, 0x00U); + /* Set next status */ + avs_status = avs_status_complete; + } + break; + case avs_status_al_start: + /* Clear ICSR.AL bit */ + mmio_write_8(IIC_ICSR, (mmio_read_8(IIC_ICSR) + & (uint8_t) (~ICSR_AL))); + /* Transmit a clock pulse */ + mmio_write_8(IIC_ICDR, init_vol_tbl[EFUSE_AVS0].vol); + /* Set next status */ + avs_status = avs_status_error_stop; + break; + case avs_status_al_transfer: + /* Clear ICSR.AL bit */ + mmio_write_8(IIC_ICSR, (mmio_read_8(IIC_ICSR) + & (uint8_t) (~ICSR_AL))); + /* Set next status */ + avs_status = avs_status_error_stop; + break; + case avs_status_nack: + /* Write H'90 in ICCR to issue stop condition */ + mmio_write_8(IIC_ICCR, ICCR_STOP); + /* Disable a WAIT and DTEE interrupt. */ + mmio_write_8(IIC_ICIC, mmio_read_8(IIC_ICIC) + & (uint8_t) (~(ICIC_WAITE | ICIC_DTEE))); + /* Clear ICSR.TACK bit */ + mmio_write_8(IIC_ICSR, mmio_read_8(IIC_ICSR) + & (uint8_t) (~ICSR_TACK)); + /* Set next status */ + avs_status = ave_status_error_end; + break; + case avs_status_error_stop: + /* If wait state after data transmission. */ + if ((mmio_read_8(IIC_ICSR) & ICSR_WAIT) == ICSR_WAIT) { + /* Write H'90 in ICCR to issue stop condition */ + mmio_write_8(IIC_ICCR, ICCR_STOP); + /* Clear ICSR.WAIT to exit from wait state. */ + mmio_write_8(IIC_ICSR, mmio_read_8(IIC_ICSR) + & (uint8_t) (~ICSR_WAIT)); + /* Set next status */ + avs_status = ave_status_error_end; + } + break; + case ave_status_error_end: + /* Is this module not busy?. */ + if ((mmio_read_8(IIC_ICSR) & ICSR_BUSY) == 0U) { + /* Set ICCR=H'00 to disable the I2C module. */ + mmio_write_8(IIC_ICCR, 0x00U); + /* Increment the re-try number of times. */ + avs_retry++; + /* Set start a re-try to status. */ + avs_status = avs_status_start_condition; + } + break; + case avs_status_complete: + /* After "avs_status" became the "avs_status_complete", */ + /* "avs_setting()" function may be called. */ + break; + default: + /* This case is not possible. */ + ERROR("AVS setting is in invalid status. status=%u\n", + avs_status); + /* Infinite loop */ + panic(); + break; + } +#endif /* PMIC_ROHM_BD9571 */ +#endif /* (AVS_SETTING_ENABLE==1) */ +} + +/* + * Finish the AVS setting. + */ +void rcar_avs_end(void) +{ +#if (AVS_SETTING_ENABLE == 1) + uint32_t mstp; + +#if PMIC_ROHM_BD9571 + /* While status is not completion, be repeated. */ + while (avs_status != avs_status_complete) + rcar_avs_setting(); + + NOTICE("AVS setting succeeded. DVFS_SetVID=0x%x\n", + init_vol_tbl[efuse_avs].vol); + +#if AVS_READ_PMIC_REG_ENABLE == 1 + { + uint8_t addr = PMIC_DVFS_SETVID; + uint8_t value = avs_read_pmic_reg(addr); + NOTICE("Read PMIC register. address=0x%x value=0x%x \n", + addr, value); + } +#endif + + /* Bit of the module which wants to disable clock supply. */ + mstp = CPG_SYS_DVFS_BIT; + /* Disables the supply of clock signal to a module. */ + cpg_write(CPG_SMSTPCR9, mmio_read_32(CPG_SMSTPCR9) | mstp); +#endif /* PMIC_ROHM_BD9571 */ + + /* Bit of the module which wants to disable clock supply. */ + mstp = CPG_SYS_ADVFS_BIT; + /* Disables the supply of clock signal to a module. */ + cpg_write(CPG_SMSTPCR9, mmio_read_32(CPG_SMSTPCR9) | mstp); + +#endif /* (AVS_SETTING_ENABLE==1) */ +} + +#if (AVS_SETTING_ENABLE == 1) +#if PMIC_ROHM_BD9571 +/* + * Check error and judge re-try. + */ +static avs_error_t avs_check_error(void) +{ + avs_error_t ret; + + if ((mmio_read_8(IIC_ICSR) & ICSR_AL) == ICSR_AL) { + NOTICE("Loss of arbitration is detected. " + "AVS status=%d Retry=%u\n", avs_status, avs_retry); + /* Check of retry number of times */ + if (avs_retry >= AVS_RETRY_NUM) { + ERROR("AVS setting failed in retry. max=%u\n", + AVS_RETRY_NUM); + /* Infinite loop */ + panic(); + } + /* Set the error detected to error status. */ + ret = avs_error_al; + } else if ((mmio_read_8(IIC_ICSR) & ICSR_TACK) == ICSR_TACK) { + NOTICE("Non-acknowledge is detected. " + "AVS status=%d Retry=%u\n", avs_status, avs_retry); + /* Check of retry number of times */ + if (avs_retry >= AVS_RETRY_NUM) { + ERROR("AVS setting failed in retry. max=%u\n", + AVS_RETRY_NUM); + /* Infinite loop */ + panic(); + } + /* Set the error detected to error status. */ + ret = avs_error_nack; + } else { + /* Not error. */ + ret = avs_error_none; + } + return ret; +} + +/* + * Set I2C for DVFS clock. + */ +static void avs_set_iic_clock(void) +{ + uint32_t md_pin; + + /* Read Mode pin register. */ + md_pin = mmio_read_32(RCAR_MODEMR) & CHECK_MD13_MD14; + /* Set the module clock (CP phy) for the IIC-DVFS. */ + /* CP phy is EXTAL / 2. */ + switch (md_pin) { + case MD14_MD13_TYPE_0: /* EXTAL = 16.6666MHz */ + mmio_write_8(IIC_ICCL, ICCL_FREQ_8p33M); + mmio_write_8(IIC_ICCH, ICCH_FREQ_8p33M); + break; + case MD14_MD13_TYPE_1: /* EXTAL = 20MHz */ + mmio_write_8(IIC_ICCL, ICCL_FREQ_10M); + mmio_write_8(IIC_ICCH, ICCH_FREQ_10M); + break; + case MD14_MD13_TYPE_2: /* EXTAL = 25MHz (H3/M3) */ + mmio_write_8(IIC_ICCL, ICCL_FREQ_12p5M); + mmio_write_8(IIC_ICCH, ICCH_FREQ_12p5M); + break; + case MD14_MD13_TYPE_3: /* EXTAL = 33.3333MHz */ + mmio_write_8(IIC_ICCL, ICCL_FREQ_16p66M); + mmio_write_8(IIC_ICCH, ICCH_FREQ_16p66M); + break; + default: /* This case is not possible. */ + /* CP Phy frequency is to be set for the 16.66MHz */ + mmio_write_8(IIC_ICCL, ICCL_FREQ_16p66M); + mmio_write_8(IIC_ICCH, ICCH_FREQ_16p66M); + break; + } +} + +#if AVS_READ_PMIC_REG_ENABLE == 1 +/* + * Read the value of the register of PMIC. + */ +static uint8_t avs_read_pmic_reg(uint8_t addr) +{ + uint8_t reg; + + /* Set ICCR.ICE=1 to activate the I2C module. */ + mmio_write_8(IIC_ICCR, mmio_read_8(IIC_ICCR) | ICCR_ENABLE); + + /* Set frequency of 400kHz */ + avs_set_iic_clock(); + + /* Set ICIC.WAITE=1, ICIC.DTEE=1 to enable data transmission */ + /* interrupt and wait interrupt. */ + mmio_write_8(IIC_ICIC, mmio_read_8(IIC_ICIC) | ICIC_WAITE | ICIC_DTEE); + + /* Write H'94 in ICCR to issue start condition */ + mmio_write_8(IIC_ICCR, ICCR_START); + + /* Wait for a until ICSR.DTE becomes 1. */ + avs_poll(ICSR_DTE, 1U); + + /* Clear ICIC.DTEE to disable a DTE interrupt. */ + mmio_write_8(IIC_ICIC, mmio_read_8(IIC_ICIC) & (uint8_t) (~ICIC_DTEE)); + /* Send slave address of PMIC */ + mmio_write_8(IIC_ICDR, PMIC_W_SLAVE_ADDRESS); + + /* Wait for a until ICSR.WAIT becomes 1. */ + avs_poll(ICSR_WAIT, 1U); + + /* write PMIC address */ + mmio_write_8(IIC_ICDR, addr); + /* Clear ICSR.WAIT to exit from WAIT status. */ + mmio_write_8(IIC_ICSR, mmio_read_8(IIC_ICSR) & (uint8_t) (~ICSR_WAIT)); + + /* Wait for a until ICSR.WAIT becomes 1. */ + avs_poll(ICSR_WAIT, 1U); + + /* Write H'94 in ICCR to issue restart condition */ + mmio_write_8(IIC_ICCR, ICCR_START); + /* Clear ICSR.WAIT to exit from WAIT status. */ + mmio_write_8(IIC_ICSR, mmio_read_8(IIC_ICSR) & (uint8_t) (~ICSR_WAIT)); + /* Set ICIC.DTEE=1 to enable data transmission interrupt. */ + mmio_write_8(IIC_ICIC, mmio_read_8(IIC_ICIC) | ICIC_DTEE); + + /* Wait for a until ICSR.DTE becomes 1. */ + avs_poll(ICSR_DTE, 1U); + + /* Clear ICIC.DTEE to disable a DTE interrupt. */ + mmio_write_8(IIC_ICIC, mmio_read_8(IIC_ICIC) & (uint8_t) (~ICIC_DTEE)); + /* Send slave address of PMIC */ + mmio_write_8(IIC_ICDR, PMIC_R_SLAVE_ADDRESS); + + /* Wait for a until ICSR.WAIT becomes 1. */ + avs_poll(ICSR_WAIT, 1U); + + /* Write H'81 to ICCR to issue the repeated START condition */ + /* for changing the transmission mode to the receive mode. */ + mmio_write_8(IIC_ICCR, ICCR_START_RECV); + /* Clear ICSR.WAIT to exit from WAIT status. */ + mmio_write_8(IIC_ICSR, mmio_read_8(IIC_ICSR) & (uint8_t) (~ICSR_WAIT)); + + /* Wait for a until ICSR.WAIT becomes 1. */ + avs_poll(ICSR_WAIT, 1U); + + /* Set ICCR to H'C0 for the STOP condition */ + mmio_write_8(IIC_ICCR, ICCR_STOP_RECV); + /* Clear ICSR.WAIT to exit from WAIT status. */ + mmio_write_8(IIC_ICSR, mmio_read_8(IIC_ICSR) & (uint8_t) (~ICSR_WAIT)); + /* Set ICIC.DTEE=1 to enable data transmission interrupt. */ + mmio_write_8(IIC_ICIC, mmio_read_8(IIC_ICIC) | ICIC_DTEE); + + /* Wait for a until ICSR.DTE becomes 1. */ + avs_poll(ICSR_DTE, 1U); + + /* Receive DVFS SetVID register */ + /* Clear ICIC.DTEE to disable a DTE interrupt. */ + mmio_write_8(IIC_ICIC, mmio_read_8(IIC_ICIC) & (uint8_t) (~ICIC_DTEE)); + /* Receive DVFS SetVID register */ + reg = mmio_read_8(IIC_ICDR); + + /* Wait until ICSR.BUSY is cleared. */ + avs_poll(ICSR_BUSY, 0U); + + /* Set ICCR=H'00 to disable the I2C module. */ + mmio_write_8(IIC_ICCR, 0x00U); + + return reg; +} + +/* + * Wait processing by the polling. + */ +static void avs_poll(uint8_t bit_pos, uint8_t val) +{ + uint8_t bit_val = 0U; + + if (val != 0U) + bit_val = bit_pos; + + while (1) { + if ((mmio_read_8(IIC_ICSR) & bit_pos) == bit_val) + break; + } +} +#endif /* AVS_READ_PMIC_REG_ENABLE */ +#endif /* PMIC_ROHM_BD9571 */ +#endif /* (AVS_SETTING_ENABLE==1) */ diff --git a/drivers/renesas/rcar/avs/avs_driver.h b/drivers/renesas/rcar/avs/avs_driver.h new file mode 100644 index 00000000..e8689287 --- /dev/null +++ b/drivers/renesas/rcar/avs/avs_driver.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights + * reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef AVS_DRIVER_H__ +#define AVS_DRIVER_H__ + +/* AVS Setting. 1:enable / 0:disable */ +#ifndef AVS_SETTING_ENABLE +#define AVS_SETTING_ENABLE 1 +#endif /* AVS_SETTING_ENABLE */ + +void rcar_avs_init(void); +void rcar_avs_setting(void); +void rcar_avs_end(void); + +#endif /* AVS_DRIVER_H__ */ diff --git a/drivers/renesas/rcar/board/board.c b/drivers/renesas/rcar/board/board.c new file mode 100644 index 00000000..147a0b0c --- /dev/null +++ b/drivers/renesas/rcar/board/board.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights + * reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <stdint.h> +#include <iic_dvfs.h> +#include "board.h" +#include "utils_def.h" + +#ifndef BOARD_DEFAULT +#if (RCAR_LSI == RCAR_E3) +#define BOARD_DEFAULT (BOARD_EBISU << BOARD_CODE_SHIFT) +#else +#define BOARD_DEFAULT (BOARD_SALVATOR_X << BOARD_CODE_SHIFT) +#endif +#endif + +#define BOARD_CODE_MASK (0xF8) +#define BOARD_REV_MASK (0x07) +#define BOARD_CODE_SHIFT (0x03) +#define BOARD_ID_UNKNOWN (0xFF) + +#define SXS_ID { 0x10U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU } +#define SX_ID { 0x10U, 0x11U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU } +#define SKP_ID { 0x10U, 0x10U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU } +#define SK_ID { 0x10U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU } +#define EB4_ID { 0x10U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU } +#define EB_ID { 0x10U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU } +#define KK_ID { 0x10U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU } + +const char *g_board_tbl[] = { + [BOARD_STARTER_KIT_PRE] = "Starter Kit Premier", + [BOARD_STARTER_KIT] = "Starter Kit", + [BOARD_SALVATOR_XS] = "Salvator-XS", + [BOARD_SALVATOR_X] = "Salvator-X", + [BOARD_EBISU_4D] = "Ebisu-4D", + [BOARD_KRIEK] = "Kriek", + [BOARD_EBISU] = "Ebisu", + [BOARD_UNKNOWN] = "unknown" +}; + +int32_t rcar_get_board_type(uint32_t *type, uint32_t *rev) +{ + int32_t ret = 0; + const uint8_t board_tbl[][8] = { + [BOARD_STARTER_KIT_PRE] = SKP_ID, + [BOARD_SALVATOR_XS] = SXS_ID, + [BOARD_STARTER_KIT] = SK_ID, + [BOARD_SALVATOR_X] = SX_ID, + [BOARD_EBISU_4D] = EB4_ID, + [BOARD_EBISU] = EB_ID, + [BOARD_KRIEK] = KK_ID, + }; + static uint8_t board_id = BOARD_ID_UNKNOWN; + + if (board_id != BOARD_ID_UNKNOWN) + goto get_type; + +#if PMIC_ROHM_BD9571 + /* Board ID detection from EEPROM */ + ret = rcar_iic_dvfs_receive(EEPROM, BOARD_ID, &board_id); + if (ret) { + board_id = BOARD_ID_UNKNOWN; + goto get_type; + } + + if (board_id == BOARD_ID_UNKNOWN) + board_id = BOARD_DEFAULT; +#else + board_id = BOARD_DEFAULT; +#endif + +get_type: + *type = ((uint32_t) board_id & BOARD_CODE_MASK) >> BOARD_CODE_SHIFT; + + if (*type >= ARRAY_SIZE(board_tbl)) { + /* no revision information, set Rev0.0. */ + *rev = 0; + return ret; + } + + *rev = board_tbl[*type][(uint8_t) (board_id & BOARD_REV_MASK)]; + + return ret; +} diff --git a/drivers/renesas/rcar/board/board.h b/drivers/renesas/rcar/board/board.h new file mode 100644 index 00000000..15d80b9b --- /dev/null +++ b/drivers/renesas/rcar/board/board.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights + * reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef BOARD_H_ +#define BOARD_H_ + +#define BOARD_SALVATOR_X (0x00) +#define BOARD_KRIEK (0x01) +#define BOARD_STARTER_KIT (0x02) +#define BOARD_SALVATOR_XS (0x04) +#define BOARD_EBISU (0x08) +#define BOARD_STARTER_KIT_PRE (0x0B) +#define BOARD_EBISU_4D (0x0DU) +#define BOARD_UNKNOWN (BOARD_EBISU_4D + 1U) + +#define BOARD_REV_UNKNOWN (0xFF) + +extern const char *g_board_tbl[]; + +/************************************************************************ + * Revisions are expressed in 8 bits. + * The upper 4 bits are major version. + * The lower 4 bits are minor version. + ************************************************************************/ +#define GET_BOARD_MAJOR(a) ((uint32_t)(a) >> 0x4) +#define GET_BOARD_MINOR(a) ((uint32_t)(a) & 0xF) +#define GET_BOARD_NAME(a) (g_board_tbl[(a)]) + +int32_t rcar_get_board_type(uint32_t *type, uint32_t *rev); + +#endif diff --git a/drivers/renesas/rcar/common.c b/drivers/renesas/rcar/common.c new file mode 100644 index 00000000..e82e8b52 --- /dev/null +++ b/drivers/renesas/rcar/common.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <mmio.h> +#include "rcar_private.h" + +void +#if IMAGE_BL31 + __attribute__ ((section(".system_ram"))) +#endif + cpg_write(uintptr_t regadr, uint32_t regval) +{ + uint32_t value = (regval); + mmio_write_32((uintptr_t) RCAR_CPGWPR, ~value); + mmio_write_32(regadr, value); +} + +void +#if IMAGE_BL31 + __attribute__ ((section(".system_ram"))) +#endif + mstpcr_write(uint32_t mstpcr, uint32_t mstpsr, uint32_t target_bit) +{ + uint32_t reg; + reg = mmio_read_32(mstpcr); + reg &= ~target_bit; + cpg_write(mstpcr, reg); + while ((mmio_read_32(mstpsr) & target_bit) != 0U) { + } +} diff --git a/drivers/renesas/rcar/console/rcar_console.S b/drivers/renesas/rcar/console/rcar_console.S new file mode 100644 index 00000000..e3c73636 --- /dev/null +++ b/drivers/renesas/rcar/console/rcar_console.S @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <asm_macros.S> + + .globl console_init + .globl console_putc + .globl console_uninit + .globl console_core_init + .globl console_core_putc + .globl console_core_getc + .globl console_flush + + .extern rcar_log_init + .extern rcar_set_log_data + + /* ----------------------------------------------- + * int console_core_init(unsigned long base_addr, + * unsigned int uart_clk, unsigned int baud_rate) + * Function to initialize the log area. This + * function will be accessed by console_init and + * crash reporting. + * Return 1 on SUCCESS, 0 on error + * In: x0 - Not used + * w1 - Not used + * w2 - Not used + * ----------------------------------------------- + */ +func console_core_init + b rcar_log_init +endfunc console_core_init +func console_init + b console_core_init +endfunc console_init + + /* -------------------------------------------------------- + * int console_core_putc(int c, unsigned long base_addr) + * Function to output a character over the log area. + * Return 1 on SUCCESS, 0 on error + * In : w0 - Not used + * x1 - Not used + * -------------------------------------------------------- + */ +func console_core_putc + b rcar_set_log_data +endfunc console_core_putc +func console_putc + b console_core_putc +endfunc console_putc + + /* --------------------------------------------- + * int console_core_getc(unsigned long base_addr) + * Function to get a character from the console. + * It returns the character grabbed on success + * or -1 on error. + * In : x0 - console base address + * Clobber list : x0, x1 + * --------------------------------------------- + */ +func console_core_getc + ret +endfunc console_core_getc + + /* ----------------------------------------------- + * void console_uninit(void) + * Function to finish the use of console driver. + * ----------------------------------------------- + */ +func console_uninit + ret +endfunc console_uninit + + /* --------------------------------------------- + * int console_flush(void) + * Function to force a write of all buffered + * data that hasn't been output. It returns 0 + * upon successful completion, otherwise it + * returns -1. + * Clobber list : x0, x1 + * --------------------------------------------- + */ +func console_flush + mov w0, #0 + ret +endfunc console_flush diff --git a/drivers/renesas/rcar/console/rcar_printf.c b/drivers/renesas/rcar/console/rcar_printf.c new file mode 100644 index 00000000..9321b584 --- /dev/null +++ b/drivers/renesas/rcar/console/rcar_printf.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <debug.h> +#include <stdarg.h> +#include <stdint.h> + +#include <arch_helpers.h> +#include <platform_def.h> +#include <bakery_lock.h> +#include "rcar_def.h" +#include "rcar_private.h" +#include "rcar_printf.h" + +#define INDEX_TIMER_COUNT (4U) + +extern RCAR_INSTANTIATE_LOCK typedef struct log_head { + uint8_t head[4]; + uint32_t index; + uint32_t size; + uint8_t res[4]; +} loghead_t; + +typedef struct log_map { + loghead_t header; + uint8_t log_data[RCAR_BL31_LOG_MAX]; + uint8_t res_data[RCAR_LOG_RES_SIZE]; +} logmap_t; + +int32_t rcar_set_log_data(int32_t c) +{ + logmap_t *t_log; + + t_log = (logmap_t *) RCAR_BL31_LOG_BASE; + + rcar_lock_get(); + + /* + * If index is broken, then index and size initialize + */ + if (t_log->header.index >= (uint32_t) RCAR_BL31_LOG_MAX) { + t_log->header.index = 0U; + t_log->header.size = 0U; + } + /* + * data store to log area then index and size renewal + */ + t_log->log_data[t_log->header.index] = (uint8_t) c; + t_log->header.index++; + if (t_log->header.size < t_log->header.index) { + t_log->header.size = t_log->header.index; + } + if (t_log->header.index >= (uint32_t) RCAR_BL31_LOG_MAX) { + t_log->header.index = 0U; + } + + rcar_lock_release(); + + return 1; +} + +int32_t rcar_log_init(void) +{ + + static const uint8_t const_header[] = "TLOG"; + logmap_t *t_log; + int16_t init_flag = 0; + + t_log = (logmap_t *) RCAR_BL31_LOG_BASE; + if (memcmp + ((const void *)t_log->header.head, (const void *)const_header, + sizeof(t_log->header.head)) != 0) { + /* + * Log header is not "TLOG", then log area initialize + */ + init_flag = 1; + } + if (t_log->header.index >= (uint32_t) RCAR_BL31_LOG_MAX) { + /* + * index is broken, then log area initialize + */ + init_flag = 1; + } + if (init_flag == 1) { + (void)memset((void *)t_log->log_data, 0, + (size_t) RCAR_BL31_LOG_MAX); + (void)memcpy((void *)t_log->header.head, + (const void *)const_header, + sizeof(t_log->header.head)); + t_log->header.index = 0U; + t_log->header.size = 0U; +#ifndef IMAGE_BL2 + rcar_stack_generic_timer[INDEX_TIMER_COUNT] = 0U; +#endif + } + rcar_lock_init(); + + return 1; +} diff --git a/drivers/renesas/rcar/console/rcar_printf.h b/drivers/renesas/rcar/console/rcar_printf.h new file mode 100644 index 00000000..dd7a61b0 --- /dev/null +++ b/drivers/renesas/rcar/console/rcar_printf.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef RCAR_PRINTF_H__ +#define RCAR_PRINTF_H__ + +#include <string.h> + +int32_t rcar_set_log_data(int32_t c); +int32_t rcar_log_init(void); + +#if IMAGE_BL31 +extern uint64_t rcar_stack_generic_timer[5]; +#endif + +#endif diff --git a/drivers/renesas/rcar/cpld/ulcb_cpld.c b/drivers/renesas/rcar/cpld/ulcb_cpld.c new file mode 100644 index 00000000..92e438a4 --- /dev/null +++ b/drivers/renesas/rcar/cpld/ulcb_cpld.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <mmio.h> + +#define SCLK 8 /* GP_6_8 */ +#define SSTBZ 3 /* GP_2_3 */ +#define MOSI 7 /* GP_6_7 */ + +#define CPLD_ADDR_RESET 0x80 /* RW */ + +/* LSI Multiplexed Pin Setting Mask Register */ +#define PFC_PMMR 0xE6060000 + +/* General output registers */ +#define GPIO_OUTDT2 0xE6052008 +#define GPIO_OUTDT6 0xE6055408 + +/* General input/output switching registers */ +#define GPIO_INOUTSEL2 0xE6052004 +#define GPIO_INOUTSEL6 0xE6055404 + +/* GPIO/perihperal function select */ +#define PFC_GPSR2 0xE6060108 +#define PFC_GPSR6 0xE6060118 + +static void gpio_set_value(uint32_t addr, uint8_t gpio, uint32_t val) +{ + uint32_t reg; + + reg = mmio_read_32(addr); + if (val) + reg |= (1 << gpio); + else + reg &= ~(1 << gpio); + mmio_write_32(addr, reg); +} + +static void gpio_direction_output(uint32_t addr, uint8_t gpio) +{ + uint32_t reg; + + reg = mmio_read_32(addr); + reg |= (1 << gpio); + mmio_write_32(addr, reg); +} + +static void gpio_pfc(uint32_t addr, uint8_t gpio) +{ + uint32_t reg; + + reg = mmio_read_32(addr); + reg &= ~(1 << gpio); + mmio_write_32(PFC_PMMR, ~reg); + mmio_write_32(addr, reg); +} + +static void cpld_write(uint8_t addr, uint32_t data) +{ + int i; + + for (i = 0; i < 32; i++) { + /* MSB first */ + gpio_set_value(GPIO_OUTDT6, MOSI, data & (1 << 31)); + gpio_set_value(GPIO_OUTDT6, SCLK, 1); + data <<= 1; + gpio_set_value(GPIO_OUTDT6, SCLK, 0); + } + + for (i = 0; i < 8; i++) { + /* MSB first */ + gpio_set_value(GPIO_OUTDT6, MOSI, addr & 0x80); + gpio_set_value(GPIO_OUTDT6, SCLK, 1); + addr <<= 1; + gpio_set_value(GPIO_OUTDT6, SCLK, 0); + } + + /* WRITE */ + gpio_set_value(GPIO_OUTDT6, MOSI, 1); + gpio_set_value(GPIO_OUTDT2, SSTBZ, 0); + gpio_set_value(GPIO_OUTDT6, SCLK, 1); + gpio_set_value(GPIO_OUTDT6, SCLK, 0); + gpio_set_value(GPIO_OUTDT2, SSTBZ, 1); +} + +static void cpld_init(void) +{ + gpio_pfc(PFC_GPSR6, SCLK); + gpio_pfc(PFC_GPSR2, SSTBZ); + gpio_pfc(PFC_GPSR6, MOSI); + + gpio_set_value(GPIO_OUTDT6, SCLK, 0); + gpio_set_value(GPIO_OUTDT2, SSTBZ, 1); + gpio_set_value(GPIO_OUTDT6, MOSI, 0); + + gpio_direction_output(GPIO_INOUTSEL6, SCLK); + gpio_direction_output(GPIO_INOUTSEL2, SSTBZ); + gpio_direction_output(GPIO_INOUTSEL6, MOSI); +} + +void rcar_cpld_reset_cpu(void) +{ + cpld_init(); + + cpld_write(CPLD_ADDR_RESET, 1); +} diff --git a/drivers/renesas/rcar/delay/micro_delay.S b/drivers/renesas/rcar/delay/micro_delay.S new file mode 100644 index 00000000..978973c2 --- /dev/null +++ b/drivers/renesas/rcar/delay/micro_delay.S @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <asm_macros.S> +#include "micro_delay.h" + +#define CPG_BASE (0xE6150000) +#define CPG_SMSTPCR1 (0x0134) +#define CPG_CPGWPR (0x0900) + +/* Module bit for TMU ch3-5 */ +#define MSTPCR1_TMU1 (1 << 24) + +#define TMU3_BASE (0xE6FC0000) +#define TMU_TSTR (0x0004) +#define TMU_TCOR (0x0008) +#define TMU_TCNT (0x000C) +#define TMU_TCR (0x0010) +/* Start bit for TMU ch3 */ +#define TSTR1_TMU3 (1 << 0) + +#define MIDR_CA57 (0x0D07 << MIDR_PN_SHIFT) +#define MIDR_CA53 (0x0D03 << MIDR_PN_SHIFT) + + .globl rcar_micro_delay +#if (TMU3_MEASUREMENT == 1) + .globl tmu3_init + .globl tmu3_start + .globl tmu3_stop + .globl tcnt3_snapshot +#endif + /* Aligned with the cache line */ + .align 6 + +func rcar_micro_delay + cbz x0, micro_delay_e + mrs x1, midr_el1 + and x1, x1, #MIDR_PN_MASK << MIDR_PN_SHIFT + mov w2, #MIDR_CA53 + cmp w1, w2 + b.eq micro_delay_ca53 + b micro_delay_ca57 +micro_delay_e: + ret +endfunc rcar_micro_delay + +func micro_delay_ca57 +ca57_loop_1: + mov x1, #185 +ca57_loop_2: + subs x1, x1, #1 + b.ne ca57_loop_2 + subs x0, x0, #1 + b.ne ca57_loop_1 + ret +endfunc micro_delay_ca57 + +func micro_delay_ca53 +ca53_loop_1: + mov x1, #134 +ca53_loop_2: + subs x1, x1, #1 + b.ne ca53_loop_2 + subs x0, x0, #1 + b.ne ca53_loop_1 + ret +endfunc micro_delay_ca53 + +#if (TMU3_MEASUREMENT == 1) +func tmu3_init + ldr x2, =CPG_BASE + ldr w0, [x2, #CPG_SMSTPCR1] + ldr w1, [x2, #CPG_MSTPSR1] + ldr w2, #MSTPCR1_TMU1 + bl mstpcr_write + ret +endfunc tmu3_init + +func tmu3_start + ldr x0, =TMU3_BASE + mov w1, #0xFFFFFFFF + str w1, [x0, TMU_TCNT] + + ldr x0, =TMU3_BASE + ldrb w1, [x0, TMU_TSTR] + orr w1, w1, #TSTR1_TMU3 + strb w1, [x0, TMU_TSTR] + ret +endfunc tmu3_start + +func tcnt3_snapshot + ldr x0, =TMU3_BASE + ldr w0, [x0, TMU_TCNT] + ret +endfunc tcnt3_snapshot + + +func tmu3_stop + ldr x0, =TMU3_BASE + ldrb w1, [x0, TMU_TSTR] + and w1, w1, #~TSTR1_TMU3 + strb w1, [x0, TMU_TSTR] + ret +endfunc tmu3_stop +#endif diff --git a/drivers/renesas/rcar/delay/micro_delay.h b/drivers/renesas/rcar/delay/micro_delay.h new file mode 100644 index 00000000..f5983949 --- /dev/null +++ b/drivers/renesas/rcar/delay/micro_delay.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef MICRO_DELAY_H__ +#define MICRO_DELAY_H__ + +#define TMU3_MEASUREMENT (0) + +#ifndef __ASSEMBLY__ +#include "stdint.h" +void rcar_micro_delay(uint32_t count_us); + +#if (TMU3_MEASUREMENT == 1) +void tmu3_start(void); +void tmu3_init(void); +void tmu3_stop(void); + +uint32_t tcnt3_snapshot(void); +#endif + +#endif + +#endif diff --git a/drivers/renesas/rcar/dma/dma_driver.c b/drivers/renesas/rcar/dma/dma_driver.c new file mode 100644 index 00000000..d4fa65d2 --- /dev/null +++ b/drivers/renesas/rcar/dma/dma_driver.c @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <stdint.h> +#include <arch_helpers.h> +#include <string.h> +#include <mmio.h> +#include "rcar_def.h" +#include "cpg_registers.h" +#include "debug.h" +#include "rcar_private.h" + +/* DMA CHANNEL setting (0/16/32) */ +#define DMA_CH 0 + +#if (DMA_CH == 0) +#define SYS_DMAC_BIT ((uint32_t)1U << 19U) +#define DMA_BASE (0xE6700000U) +#elif (DMA_CH == 16) +#define SYS_DMAC_BIT ((uint32_t)1U << 18U) +#define DMA_BASE (0xE7300000U) +#elif (DMA_CH == 32) +#define SYS_DMAC_BIT ((uint32_t)1U << 17U) +#define DMA_BASE (0xE7320000U) +#else +#define SYS_DMAC_BIT ((uint32_t)1U << 19U) +#define DMA_BASE (0xE6700000U) +#endif + +/* DMA operation */ +#define DMA_DMAOR (DMA_BASE + 0x0060U) +/* DMA secure control */ +#define DMA_DMASEC (DMA_BASE + 0x0030U) +/* DMA channel clear */ +#define DMA_DMACHCLR (DMA_BASE + 0x0080U) +/* DMA source address */ +#define DMA_DMASAR (DMA_BASE + 0x8000U) +/* DMA destination address */ +#define DMA_DMADAR (DMA_BASE + 0x8004U) +/* DMA transfer count */ +#define DMA_DMATCR (DMA_BASE + 0x8008U) +/* DMA channel control */ +#define DMA_DMACHCR (DMA_BASE + 0x800CU) +/* DMA fixed destination address */ +#define DMA_DMAFIXDAR (DMA_BASE + 0x8014U) + +#define DMA_USE_CHANNEL (0x00000001U) +#define DMAOR_INITIAL (0x0301U) +#define DMACHCLR_CH_ALL (0x0000FFFFU) +#define DMAFIXDAR_32BIT_SHIFT (32U) +#define DMAFIXDAR_DAR_MASK (0x000000FFU) +#define DMADAR_BOUNDARY_ADDR (0x100000000ULL) +#define DMATCR_CNT_SHIFT (6U) +#define DMATCR_MAX (0x00FFFFFFU) +#define DMACHCR_TRN_MODE (0x00105409U) +#define DMACHCR_DE_BIT (0x00000001U) +#define DMACHCR_TE_BIT (0x00000002U) +#define DMACHCR_CHE_BIT (0x80000000U) + +#define DMA_SIZE_UNIT FLASH_TRANS_SIZE_UNIT +#define DMA_FRACTION_MASK (0xFFU) +#define DMA_DST_LIMIT (0x10000000000ULL) + +/* transfer length limit */ +#define DMA_LENGTH_LIMIT ((DMATCR_MAX * (1U << DMATCR_CNT_SHIFT)) \ + & ~DMA_FRACTION_MASK) + +static void dma_enable(void) +{ + mstpcr_write(CPG_SMSTPCR2, CPG_MSTPSR2, SYS_DMAC_BIT); +} + +static void dma_setup(void) +{ + mmio_write_16(DMA_DMAOR, 0); + mmio_write_32(DMA_DMACHCLR, DMACHCLR_CH_ALL); +} + +static void dma_start(uintptr_t dst, uint32_t src, uint32_t len) +{ + mmio_write_16(DMA_DMAOR, DMAOR_INITIAL); + mmio_write_32(DMA_DMAFIXDAR, (dst >> DMAFIXDAR_32BIT_SHIFT) & + DMAFIXDAR_DAR_MASK); + mmio_write_32(DMA_DMADAR, dst & UINT32_MAX); + mmio_write_32(DMA_DMASAR, src); + mmio_write_32(DMA_DMATCR, len >> DMATCR_CNT_SHIFT); + mmio_write_32(DMA_DMASEC, DMA_USE_CHANNEL); + mmio_write_32(DMA_DMACHCR, DMACHCR_TRN_MODE); +} + +static void dma_end(void) +{ + while ((mmio_read_32(DMA_DMACHCR) & DMACHCR_TE_BIT) == 0) { + if ((mmio_read_32(DMA_DMACHCR) & DMACHCR_CHE_BIT) != 0U) { + ERROR("BL2: DMA - Channel Address Error\n"); + panic(); + break; + } + } + /* DMA transfer Disable */ + mmio_clrbits_32(DMA_DMACHCR, DMACHCR_DE_BIT); + while ((mmio_read_32(DMA_DMACHCR) & DMACHCR_DE_BIT) != 0) + ; + + mmio_write_32(DMA_DMASEC, 0); + mmio_write_16(DMA_DMAOR, 0); + mmio_write_32(DMA_DMACHCLR, DMA_USE_CHANNEL); +} + +void rcar_dma_exec(uintptr_t dst, uint32_t src, uint32_t len) +{ + uint32_t dma_len = len; + + if (len & DMA_FRACTION_MASK) + dma_len = (len + DMA_SIZE_UNIT) & ~DMA_FRACTION_MASK; + + if (!dma_len || dma_len > DMA_LENGTH_LIMIT) { + ERROR("BL2: DMA - size invalid, length (0x%x)\n", dma_len); + panic(); + } + + if (src & DMA_FRACTION_MASK) { + ERROR("BL2: DMA - source address invalid (0x%x), " + "length (0x%x)\n", src, dma_len); + panic(); + } + + if ((dst & UINT32_MAX) + dma_len > DMADAR_BOUNDARY_ADDR || + (dst + dma_len > DMA_DST_LIMIT) || + (dst & DMA_FRACTION_MASK)) { + ERROR("BL2: DMA - destination address invalid (0x%lx), " + "length (0x%x)\n", dst, dma_len); + panic(); + } + + dma_start(dst, src, dma_len); + dma_end(); +} + +void rcar_dma_init(void) +{ + dma_enable(); + dma_setup(); +} diff --git a/drivers/renesas/rcar/emmc/emmc_cmd.c b/drivers/renesas/rcar/emmc/emmc_cmd.c new file mode 100644 index 00000000..0f393490 --- /dev/null +++ b/drivers/renesas/rcar/emmc/emmc_cmd.c @@ -0,0 +1,491 @@ +/* + * 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" +#include "micro_delay.h" + +static void emmc_little_to_big(uint8_t *p, uint32_t value) +{ + if (p == NULL) + return; + + p[0] = (uint8_t) (value >> 24); + p[1] = (uint8_t) (value >> 16); + p[2] = (uint8_t) (value >> 8); + p[3] = (uint8_t) value; +} + +static void emmc_softreset(void) +{ + int32_t loop = 10000; + int32_t retry = 1000; + + /* flag clear */ + mmc_drv_obj.during_cmd_processing = FALSE; + mmc_drv_obj.during_transfer = FALSE; + mmc_drv_obj.during_dma_transfer = FALSE; + mmc_drv_obj.state_machine_blocking = FALSE; + mmc_drv_obj.force_terminate = FALSE; + mmc_drv_obj.dma_error_flag = FALSE; + + /* during operation ? */ + if ((GETR_32(SD_INFO2) & SD_INFO2_CBSY) == 0) + goto reset; + + /* wait CMDSEQ = 0 */ + while (loop > 0) { + if ((GETR_32(SD_INFO2) & SD_INFO2_CBSY) == 0) + break; /* ready */ + + loop--; + if ((loop == 0) && (retry > 0)) { + rcar_micro_delay(1000U); /* wait 1ms */ + loop = 10000; + retry--; + } + } + +reset: + /* reset */ + SETR_32(SOFT_RST, (GETR_32(SOFT_RST) & (~SOFT_RST_SDRST))); + SETR_32(SOFT_RST, (GETR_32(SOFT_RST) | SOFT_RST_SDRST)); + + /* initialize */ + SETR_32(SD_INFO1, 0x00000000U); + SETR_32(SD_INFO2, SD_INFO2_CLEAR); + SETR_32(SD_INFO1_MASK, 0x00000000U); /* all interrupt disable */ + SETR_32(SD_INFO2_MASK, SD_INFO2_CLEAR); /* all interrupt disable */ + +} + +static void emmc_read_response(uint32_t *response) +{ + uint8_t *p; + + if (response == NULL) + return; + + /* read response */ + if (mmc_drv_obj.response_length != EMMC_MAX_RESPONSE_LENGTH) { + *response = GETR_32(SD_RSP10); /* [39:8] */ + return; + } + + /* CSD or CID */ + p = (uint8_t *) (response); + emmc_little_to_big(p, ((GETR_32(SD_RSP76) << 8) + | (GETR_32(SD_RSP54) >> 24))); /* [127:96] */ + emmc_little_to_big(p + 4, ((GETR_32(SD_RSP54) << 8) + | (GETR_32(SD_RSP32) >> 24))); /* [95:64] */ + emmc_little_to_big(p + 8, ((GETR_32(SD_RSP32) << 8) + | (GETR_32(SD_RSP10) >> 24))); /* [63:32] */ + emmc_little_to_big(p + 12, (GETR_32(SD_RSP10) << 8)); +} + +static EMMC_ERROR_CODE emmc_response_check(uint32_t *response, + uint32_t error_mask) +{ + + HAL_MEMCARD_RESPONSE_TYPE response_type = + (HAL_MEMCARD_RESPONSE_TYPE) (mmc_drv_obj.cmd_info. + cmd & HAL_MEMCARD_RESPONSE_TYPE_MASK); + + if (response == NULL) + return EMMC_ERR_PARAM; + + if (response_type == HAL_MEMCARD_RESPONSE_NONE) + return EMMC_SUCCESS; + + + if (response_type <= HAL_MEMCARD_RESPONSE_R1b) { + /* R1 or R1b */ + mmc_drv_obj.current_state = + (EMMC_R1_STATE) ((*response & EMMC_R1_STATE_MASK) >> + EMMC_R1_STATE_SHIFT); + if ((*response & error_mask) != 0) { + if ((0x80 & *response) != 0) { + ERROR("BL2: emmc SWITCH_ERROR\n"); + } + return EMMC_ERR_CARD_STATUS_BIT; + } + return EMMC_SUCCESS;; + } + + if (response_type == HAL_MEMCARD_RESPONSE_R4) { + if ((*response & EMMC_R4_STATUS) != 0) + return EMMC_ERR_CARD_STATUS_BIT; + } + + return EMMC_SUCCESS; +} + +static void emmc_WaitCmd2Cmd_8Cycle(void) +{ + uint32_t dataL, wait = 0; + + dataL = GETR_32(SD_CLK_CTRL); + dataL &= 0x000000FF; + + switch (dataL) { + case 0xFF: + case 0x00: + case 0x01: + case 0x02: + case 0x04: + case 0x08: + case 0x10: + case 0x20: + wait = 10U; + break; + case 0x40: + wait = 20U; + break; + case 0x80: + wait = 30U; + break; + } + + rcar_micro_delay(wait); +} + +static void cmdErrSdInfo2Log(void) +{ + ERROR("BL2: emmc ERR SD_INFO2 = 0x%x\n", mmc_drv_obj.error_info.info2); +} + +static void emmc_data_transfer_dma(void) +{ + mmc_drv_obj.during_dma_transfer = TRUE; + mmc_drv_obj.dma_error_flag = FALSE; + + SETR_32(SD_INFO1_MASK, 0x00000000U); + SETR_32(SD_INFO2_MASK, (SD_INFO2_ALL_ERR | SD_INFO2_CLEAR)); + + /* DMAC setting */ + if (mmc_drv_obj.cmd_info.dir == HAL_MEMCARD_WRITE) { + /* transfer complete interrupt enable */ + SETR_32(DM_CM_INFO1_MASK, + (DM_CM_INFO_MASK_CLEAR | DM_CM_INFO_CH0_ENABLE)); + SETR_32(DM_CM_INFO2_MASK, + (DM_CM_INFO_MASK_CLEAR | DM_CM_INFO_CH0_ENABLE)); + /* BUFF --> FIFO */ + SETR_32(DM_CM_DTRAN_MODE, (DM_CM_DTRAN_MODE_CH0 | + DM_CM_DTRAN_MODE_BIT_WIDTH)); + } else { + /* transfer complete interrupt enable */ + SETR_32(DM_CM_INFO1_MASK, + (DM_CM_INFO_MASK_CLEAR | DM_CM_INFO_CH1_ENABLE)); + SETR_32(DM_CM_INFO2_MASK, + (DM_CM_INFO_MASK_CLEAR | DM_CM_INFO_CH1_ENABLE)); + /* FIFO --> BUFF */ + SETR_32(DM_CM_DTRAN_MODE, (DM_CM_DTRAN_MODE_CH1 + | DM_CM_DTRAN_MODE_BIT_WIDTH)); + } + SETR_32(DM_DTRAN_ADDR, (((uintptr_t) mmc_drv_obj.buff_address_virtual & + DM_DTRAN_ADDR_WRITE_MASK))); + + SETR_32(DM_CM_DTRAN_CTRL, DM_CM_DTRAN_CTRL_START); +} + +EMMC_ERROR_CODE emmc_exec_cmd(uint32_t error_mask, uint32_t *response) +{ + EMMC_ERROR_CODE rtn_code = EMMC_SUCCESS; + HAL_MEMCARD_RESPONSE_TYPE response_type; + HAL_MEMCARD_COMMAND_TYPE cmd_type; + EMMC_INT_STATE state; + uint32_t err_not_care_flag = FALSE; + + /* parameter check */ + if (response == NULL) { + emmc_write_error_info(EMMC_FUNCNO_EXEC_CMD, EMMC_ERR_PARAM); + return EMMC_ERR_PARAM; + } + + /* state check */ + if (mmc_drv_obj.clock_enable != TRUE) { + emmc_write_error_info(EMMC_FUNCNO_EXEC_CMD, EMMC_ERR_STATE); + return EMMC_ERR_STATE; + } + + if (mmc_drv_obj.state_machine_blocking == TRUE) { + emmc_write_error_info(EMMC_FUNCNO_EXEC_CMD, EMMC_ERR); + return EMMC_ERR; + } + + state = ESTATE_BEGIN; + response_type = + (HAL_MEMCARD_RESPONSE_TYPE) (mmc_drv_obj.cmd_info. + cmd & HAL_MEMCARD_RESPONSE_TYPE_MASK); + cmd_type = + (HAL_MEMCARD_COMMAND_TYPE) (mmc_drv_obj.cmd_info. + cmd & HAL_MEMCARD_COMMAND_TYPE_MASK); + + /* state machine */ + while ((mmc_drv_obj.force_terminate != TRUE) && (state != ESTATE_END)) { + /* The interrupt factor flag is observed. */ + emmc_interrupt(); + + /* wait interrupt */ + if (mmc_drv_obj.state_machine_blocking == TRUE) + continue; + + switch (state) { + case ESTATE_BEGIN: + /* Busy check */ + if ((mmc_drv_obj.error_info.info2 & SD_INFO2_CBSY) != 0) { + emmc_write_error_info(EMMC_FUNCNO_EXEC_CMD, + EMMC_ERR_CARD_BUSY); + return EMMC_ERR_CARD_BUSY; + } + + /* clear register */ + SETR_32(SD_INFO1, 0x00000000U); + SETR_32(SD_INFO2, SD_INFO2_CLEAR); + SETR_32(SD_INFO1_MASK, SD_INFO1_INFO0); + SETR_32(SD_INFO2_MASK, + (SD_INFO2_ALL_ERR | SD_INFO2_CLEAR)); + + state = ESTATE_ISSUE_CMD; + /* through */ + + case ESTATE_ISSUE_CMD: + /* ARG */ + SETR_32(SD_ARG, mmc_drv_obj.cmd_info.arg); + /* issue cmd */ + SETR_32(SD_CMD, mmc_drv_obj.cmd_info.hw); + /* Set driver flag */ + mmc_drv_obj.during_cmd_processing = TRUE; + mmc_drv_obj.state_machine_blocking = TRUE; + + if (response_type == HAL_MEMCARD_RESPONSE_NONE) { + state = ESTATE_NON_RESP_CMD; + } else { + state = ESTATE_RCV_RESP; + } + + break; + + case ESTATE_NON_RESP_CMD: + /* interrupt disable */ + SETR_32(SD_INFO1_MASK, 0x00000000U); + SETR_32(SD_INFO2_MASK, SD_INFO2_CLEAR); + + /* check interrupt */ + if ((mmc_drv_obj.int_event2 & SD_INFO2_ALL_ERR) != 0) { + /* error interrupt */ + cmdErrSdInfo2Log(); + rtn_code = EMMC_ERR_INFO2; + state = ESTATE_ERROR; + } else if ((mmc_drv_obj.int_event1 & SD_INFO1_INFO0) == + 0) { + /* not receive expected interrupt */ + rtn_code = EMMC_ERR_RESPONSE; + state = ESTATE_ERROR; + } else { + emmc_WaitCmd2Cmd_8Cycle(); + state = ESTATE_END; + } + break; + + case ESTATE_RCV_RESP: + /* interrupt disable */ + SETR_32(SD_INFO1_MASK, 0x00000000U); + SETR_32(SD_INFO2_MASK, SD_INFO2_CLEAR); + + /* check interrupt */ + if ((mmc_drv_obj.int_event2 & SD_INFO2_ALL_ERR) != 0) { + if ((mmc_drv_obj.get_partition_access_flag == + TRUE) + && ((mmc_drv_obj.int_event2 & SD_INFO2_ERR6) + != 0U)) { + err_not_care_flag = TRUE; + rtn_code = EMMC_ERR_CMD_TIMEOUT; + } else { + /* error interrupt */ + cmdErrSdInfo2Log(); + rtn_code = EMMC_ERR_INFO2; + } + state = ESTATE_ERROR; + break; + } else if ((mmc_drv_obj.int_event1 & SD_INFO1_INFO0) == + 0) { + /* not receive expected interrupt */ + rtn_code = EMMC_ERR_RESPONSE; + state = ESTATE_ERROR; + break; + } + + /* read response */ + emmc_read_response(response); + + /* check response */ + rtn_code = emmc_response_check(response, error_mask); + if (rtn_code != EMMC_SUCCESS) { + state = ESTATE_ERROR; + break; + } + + if (response_type == HAL_MEMCARD_RESPONSE_R1b) { + /* R1b */ + SETR_32(SD_INFO2_MASK, + (SD_INFO2_ALL_ERR | SD_INFO2_CLEAR)); + state = ESTATE_RCV_RESPONSE_BUSY; + } else { + state = ESTATE_CHECK_RESPONSE_COMPLETE; + } + break; + + case ESTATE_RCV_RESPONSE_BUSY: + /* check interrupt */ + if ((mmc_drv_obj.int_event2 & SD_INFO2_ALL_ERR) != 0) { + /* error interrupt */ + cmdErrSdInfo2Log(); + rtn_code = EMMC_ERR_INFO2; + state = ESTATE_ERROR; + break; + } + /* DAT0 not Busy */ + if ((SD_INFO2_DAT0 & mmc_drv_obj.error_info.info2) != 0) { + state = ESTATE_CHECK_RESPONSE_COMPLETE; + break; + } + break; + + case ESTATE_CHECK_RESPONSE_COMPLETE: + if (cmd_type >= HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE) { + state = ESTATE_DATA_TRANSFER; + } else { + emmc_WaitCmd2Cmd_8Cycle(); + state = ESTATE_END; + } + break; + + case ESTATE_DATA_TRANSFER: + /* ADTC command */ + mmc_drv_obj.during_transfer = TRUE; + mmc_drv_obj.state_machine_blocking = TRUE; + + if (mmc_drv_obj.transfer_mode == HAL_MEMCARD_DMA) { + /* DMA */ + emmc_data_transfer_dma(); + } else { + /* PIO */ + /* interrupt enable (FIFO read/write enable) */ + if (mmc_drv_obj.cmd_info.dir == + HAL_MEMCARD_WRITE) { + SETR_32(SD_INFO2_MASK, + (SD_INFO2_BWE | SD_INFO2_ALL_ERR + | SD_INFO2_CLEAR)); + } else { + SETR_32(SD_INFO2_MASK, + (SD_INFO2_BRE | SD_INFO2_ALL_ERR + | SD_INFO2_CLEAR)); + } + } + state = ESTATE_DATA_TRANSFER_COMPLETE; + break; + + case ESTATE_DATA_TRANSFER_COMPLETE: + /* check interrupt */ + if ((mmc_drv_obj.int_event2 & SD_INFO2_ALL_ERR) != 0) { + /* error interrupt */ + cmdErrSdInfo2Log(); + rtn_code = EMMC_ERR_INFO2; + state = ESTATE_TRANSFER_ERROR; + break; + } + + /* DMAC error ? */ + if (mmc_drv_obj.dma_error_flag == TRUE) { + /* Error occurred in DMAC driver. */ + rtn_code = EMMC_ERR_FROM_DMAC_TRANSFER; + state = ESTATE_TRANSFER_ERROR; + } else if (mmc_drv_obj.during_dma_transfer == TRUE) { + /* DMAC not finished. unknown error */ + rtn_code = EMMC_ERR; + state = ESTATE_TRANSFER_ERROR; + } else { + SETR_32(SD_INFO1_MASK, SD_INFO1_INFO2); + SETR_32(SD_INFO2_MASK, + (SD_INFO2_ALL_ERR | SD_INFO2_CLEAR)); + + mmc_drv_obj.state_machine_blocking = TRUE; + + state = ESTATE_ACCESS_END; + } + break; + + case ESTATE_ACCESS_END: + + /* clear flag */ + if (HAL_MEMCARD_DMA == mmc_drv_obj.transfer_mode) { + SETR_32(CC_EXT_MODE, CC_EXT_MODE_CLEAR); /* W (CC_EXT_MODE, H'0000_1010) SD_BUF DMA transfer disabled */ + SETR_32(SD_STOP, 0x00000000U); + mmc_drv_obj.during_dma_transfer = FALSE; + } + + SETR_32(SD_INFO1_MASK, 0x00000000U); + SETR_32(SD_INFO2_MASK, SD_INFO2_CLEAR); + SETR_32(SD_INFO1, 0x00000000U); + SETR_32(SD_INFO2, SD_INFO2_CLEAR); + + if ((mmc_drv_obj.int_event1 & SD_INFO1_INFO2) != 0) { + emmc_WaitCmd2Cmd_8Cycle(); + state = ESTATE_END; + } else { + state = ESTATE_ERROR; + } + break; + + case ESTATE_TRANSFER_ERROR: + /* The error occurred in the Data transfer. */ + if (HAL_MEMCARD_DMA == mmc_drv_obj.transfer_mode) { + SETR_32(CC_EXT_MODE, CC_EXT_MODE_CLEAR); /* W (CC_EXT_MODE, H'0000_1010) SD_BUF DMA transfer disabled */ + SETR_32(SD_STOP, 0x00000000U); + mmc_drv_obj.during_dma_transfer = FALSE; + } + /* through */ + + case ESTATE_ERROR: + if (err_not_care_flag == TRUE) { + mmc_drv_obj.during_cmd_processing = FALSE; + } else { + emmc_softreset(); + emmc_write_error_info(EMMC_FUNCNO_EXEC_CMD, + rtn_code); + } + return rtn_code; + + default: + state = ESTATE_END; + break; + } /* switch (state) */ + } /* while ( (mmc_drv_obj.force_terminate != TRUE) && (state != ESTATE_END) ) */ + + /* force terminate */ + if (mmc_drv_obj.force_terminate == TRUE) { + /* timeout timer is expired. Or, PIO data transfer error. */ + /* Timeout occurred in the DMA transfer. */ + if (mmc_drv_obj.during_dma_transfer == TRUE) { + mmc_drv_obj.during_dma_transfer = FALSE; + } + ERROR("BL2: emmc exec_cmd:EMMC_ERR_FORCE_TERMINATE\n"); + emmc_softreset(); + + return EMMC_ERR_FORCE_TERMINATE; /* error information has already been written. */ + } + + /* success */ + mmc_drv_obj.during_cmd_processing = FALSE; + mmc_drv_obj.during_transfer = FALSE; + + return EMMC_SUCCESS; +} diff --git a/drivers/renesas/rcar/emmc/emmc_config.h b/drivers/renesas/rcar/emmc/emmc_config.h new file mode 100644 index 00000000..16dcea19 --- /dev/null +++ b/drivers/renesas/rcar/emmc/emmc_config.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file emmc_config.h + * @brief Configuration file + * + */ + +#ifndef __EMMC_CONFIG_H__ +#define __EMMC_CONFIG_H__ + +/* ************************ HEADER (INCLUDE) SECTION *********************** */ + +/* ***************** MACROS, CONSTANTS, COMPILATION FLAGS ****************** */ + +/** @brief MMC driver config + */ +#define EMMC_RCA 1UL /* RCA */ +#define EMMC_RW_DATA_TIMEOUT 0x40UL /* 314ms (freq = 400KHz, timeout Counter = 0x04(SDCLK * 2^17) */ +#define EMMC_RETRY_COUNT 0 /* how many times to try after fail. Don't change. */ +#define EMMC_CMD_MAX 60UL /* Don't change. */ + +/** @brief etc + */ +#define LOADIMAGE_FLAGS_DMA_ENABLE 0x00000001UL + +/* ********************** STRUCTURES, TYPE DEFINITIONS ********************* */ + +/* ********************** DECLARATION OF EXTERNAL DATA ********************* */ + +/* ************************** FUNCTION PROTOTYPES ************************** */ + +/* ********************************* CODE ********************************** */ + +#endif /* #ifndef __EMMC_CONFIG_H__ */ +/* ******************************** END ************************************ */ diff --git a/drivers/renesas/rcar/emmc/emmc_def.h b/drivers/renesas/rcar/emmc/emmc_def.h new file mode 100644 index 00000000..2944515e --- /dev/null +++ b/drivers/renesas/rcar/emmc/emmc_def.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file emmc_def.h + * @brief eMMC boot is expecting this header file + * + */ + +#ifndef __EMMC_DEF_H__ +#define __EMMC_DEF_H__ + +#include "emmc_std.h" + +/* ************************ HEADER (INCLUDE) SECTION *********************** */ + +/* ***************** MACROS, CONSTANTS, COMPILATION FLAGS ****************** */ +#define EMMC_POWER_ON (1U) + +/* ********************** STRUCTURES, TYPE DEFINITIONS ********************* */ + +/* ********************** DECLARATION OF EXTERNAL DATA ********************* */ +extern st_mmc_base mmc_drv_obj; + +/* ************************** FUNCTION PROTOTYPES ************************** */ + +/** @brief for assembler program + */ +uint32_t _rom_emmc_finalize(void); + +/** @brief eMMC driver API + */ +EMMC_ERROR_CODE rcar_emmc_init(void); +EMMC_ERROR_CODE emmc_terminate(void); +EMMC_ERROR_CODE rcar_emmc_memcard_power(uint8_t mode); +EMMC_ERROR_CODE rcar_emmc_mount(void); +EMMC_ERROR_CODE emmc_set_request_mmc_clock(uint32_t *freq); +EMMC_ERROR_CODE emmc_send_idle_cmd(uint32_t arg); +EMMC_ERROR_CODE emmc_select_partition(EMMC_PARTITION_ID id); +EMMC_ERROR_CODE emmc_read_sector(uint32_t *buff_address_virtual, + uint32_t sector_number, uint32_t count, + uint32_t feature_flags); +EMMC_ERROR_CODE emmc_write_sector(uint32_t *buff_address_virtual, + uint32_t sector_number, uint32_t count, + uint32_t feature_flags); +EMMC_ERROR_CODE emmc_erase_sector(uint32_t *start_address, + uint32_t *end_address); +uint32_t emmc_bit_field(uint8_t *data, uint32_t top, uint32_t bottom); + +/** @brief interrupt service + */ +uint32_t emmc_interrupt(void); + +/** @brief DMA + */ + +/** @brief send command API + */ +EMMC_ERROR_CODE emmc_exec_cmd(uint32_t error_mask, uint32_t *response); +void emmc_make_nontrans_cmd(HAL_MEMCARD_COMMAND cmd, uint32_t arg); +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_ERROR_CODE emmc_set_ext_csd(uint32_t arg); + +/** @brief for error information + */ +void emmc_write_error_info(uint16_t func_no, EMMC_ERROR_CODE error_code); +void emmc_write_error_info_func_no(uint16_t func_no); + +/* ********************************* CODE ********************************** */ + +#endif /* #define __EMMC_DEF_H__ */ +/* ******************************** END ************************************ */ diff --git a/drivers/renesas/rcar/emmc/emmc_hal.h b/drivers/renesas/rcar/emmc/emmc_hal.h new file mode 100644 index 00000000..633446c9 --- /dev/null +++ b/drivers/renesas/rcar/emmc/emmc_hal.h @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file emmc_hal.h + * @brief emmc boot driver is expecting this header file + * + */ + +#ifndef __EMMC_HAL_H__ +#define __EMMC_HAL_H__ +/* ************************ HEADER (INCLUDE) SECTION *********************** */ +#include <stdint.h> +/* ***************** MACROS, CONSTANTS, COMPILATION FLAGS ****************** */ + +/** @brief memory card error/status types + */ +#define HAL_MEMCARD_OUT_OF_RANGE 0x80000000L +#define HAL_MEMCARD_ADDRESS_ERROR 0x40000000L +#define HAL_MEMCARD_BLOCK_LEN_ERROR 0x20000000L +#define HAL_MEMCARD_ERASE_SEQ_ERROR 0x10000000L +#define HAL_MEMCARD_ERASE_PARAM 0x08000000L +#define HAL_MEMCARD_WP_VIOLATION 0x04000000L +#define HAL_MEMCARD_CARD_IS_LOCKED 0x02000000L +#define HAL_MEMCARD_LOCK_UNLOCK_FAILED 0x01000000L +#define HAL_MEMCARD_COM_CRC_ERROR 0x00800000L +#define HAL_MEMCARD_ILEGAL_COMMAND 0x00400000L +#define HAL_MEMCARD_CARD_ECC_FAILED 0x00200000L +#define HAL_MEMCARD_CC_ERROR 0x00100000L +#define HAL_MEMCARD_ERROR 0x00080000L +#define HAL_MEMCARD_UNDERRUN 0x00040000L +#define HAL_MEMCARD_OVERRUN 0x00020000L +#define HAL_MEMCARD_CIDCSD_OVERWRITE 0x00010000L +#define HAL_MEMCARD_WP_ERASE_SKIP 0x00008000L +#define HAL_MEMCARD_CARD_ECC_DISABLED 0x00004000L +#define HAL_MEMCARD_ERASE_RESET 0x00002000L +#define HAL_MEMCARD_CARD_STATE 0x00001E00L +#define HAL_MEMCARD_CARD_READY_FOR_DATA 0x00000100L +#define HAL_MEMCARD_APP_CMD 0x00000020L +#define HAL_MEMCARD_SWITCH_ERROR 0x00000080L +#define HAL_MEMCARD_AKE_SEQ_ERROR 0x00000008L +#define HAL_MEMCARD_NO_ERRORS 0x00000000L + +/** @brief Memory card response types + */ +#define HAL_MEMCARD_COMMAND_INDEX_MASK 0x0003f + +/* ********************** STRUCTURES, TYPE DEFINITIONS ********************* */ + +/** @brief Type of the return value. + */ +typedef enum { + HAL_MEMCARD_FAIL = 0U, + HAL_MEMCARD_OK = 1U, + HAL_MEMCARD_DMA_ALLOC_FAIL = 2U, /**< DMA channel allocation failed */ + HAL_MEMCARD_DMA_TRANSFER_FAIL = 3U, /**< DMA transfer failed */ + HAL_MEMCARD_CARD_STATUS_ERROR = 4U, /**< A non-masked error bit was set in the card status */ + HAL_MEMCARD_CMD_TIMEOUT = 5U, /**< Command timeout occurred */ + HAL_MEMCARD_DATA_TIMEOUT = 6U, /**< Data timeout occurred */ + HAL_MEMCARD_CMD_CRC_ERROR = 7U, /**< Command CRC error occurred */ + HAL_MEMCARD_DATA_CRC_ERROR = 8U /**< Data CRC error occurred */ +} HAL_MEMCARD_RETURN; + +/** @brief memory access operation + */ +typedef enum { + HAL_MEMCARD_READ = 0U, /**< read */ + HAL_MEMCARD_WRITE = 1U /**< write */ +} HAL_MEMCARD_OPERATION; + +/** @brief Type of data width on memorycard bus + */ +typedef enum { + HAL_MEMCARD_DATA_WIDTH_1_BIT = 0U, + HAL_MEMCARD_DATA_WIDTH_4_BIT = 1U, + HAL_MEMCARD_DATA_WIDTH_8_BIT = 2U +} HAL_MEMCARD_DATA_WIDTH; /**< data (bus) width types */ + +/** @brief Presence of the memory card + */ +typedef enum { + HAL_MEMCARD_CARD_IS_IN = 0U, + HAL_MEMCARD_CARD_IS_OUT = 1U +} HAL_MEMCARD_PRESENCE_STATUS; /* presence status of the memory card */ + +/** @brief mode of data transfer + */ +typedef enum { + HAL_MEMCARD_DMA = 0U, + HAL_MEMCARD_NOT_DMA = 1U +} HAL_MEMCARD_DATA_TRANSFER_MODE; + +/** @brief Memory card response types. + */ +typedef enum hal_memcard_response_type { + HAL_MEMCARD_RESPONSE_NONE = 0x00000U, + HAL_MEMCARD_RESPONSE_R1 = 0x00100U, + HAL_MEMCARD_RESPONSE_R1b = 0x00200U, + HAL_MEMCARD_RESPONSE_R2 = 0x00300U, + HAL_MEMCARD_RESPONSE_R3 = 0x00400U, + HAL_MEMCARD_RESPONSE_R4 = 0x00500U, + HAL_MEMCARD_RESPONSE_R5 = 0x00600U, + HAL_MEMCARD_RESPONSE_R6 = 0x00700U, + HAL_MEMCARD_RESPONSE_R7 = 0x00800U, + HAL_MEMCARD_RESPONSE_TYPE_MASK = 0x00f00U +} HAL_MEMCARD_RESPONSE_TYPE; + +/** @brief Memory card command types. + */ +typedef enum hal_memcard_command_type { + HAL_MEMCARD_COMMAND_TYPE_BC = 0x00000U, + HAL_MEMCARD_COMMAND_TYPE_BCR = 0x01000U, + HAL_MEMCARD_COMMAND_TYPE_AC = 0x02000U, + HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE = 0x03000U, + HAL_MEMCARD_COMMAND_TYPE_ADTC_READ = 0x04000U, + HAL_MEMCARD_COMMAND_TYPE_MASK = 0x07000U +} HAL_MEMCARD_COMMAND_TYPE; + +/** @brief Type of memory card + */ +typedef enum hal_memcard_command_card_type { + HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON = 0x00000U, + HAL_MEMCARD_COMMAND_CARD_TYPE_MMC = 0x08000U, + HAL_MEMCARD_COMMAND_CARD_TYPE_SD = 0x10000U, + HAL_MEMCARD_COMMAND_CARD_TYPE_MASK = 0x18000U +} HAL_MEMCARD_COMMAND_CARD_TYPE; + +/** @brief Memory card application command. + */ +typedef enum hal_memcard_command_app_norm { + HAL_MEMCARD_COMMAND_NORMAL = 0x00000U, + HAL_MEMCARD_COMMAND_APP = 0x20000U, + HAL_MEMCARD_COMMAND_APP_NORM_MASK = 0x20000U +} HAL_MEMCARD_COMMAND_APP_NORM; + +/** @brief Memory card command codes. + */ +typedef enum { +/* class 0 and class 1 */ + CMD0_GO_IDLE_STATE = 0 | HAL_MEMCARD_RESPONSE_NONE | HAL_MEMCARD_COMMAND_TYPE_BC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD0 */ + CMD1_SEND_OP_COND = 1 | HAL_MEMCARD_RESPONSE_R3 | HAL_MEMCARD_COMMAND_TYPE_BCR | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL, /* CMD1 */ + CMD2_ALL_SEND_CID_MMC = 2 | HAL_MEMCARD_RESPONSE_R2 | HAL_MEMCARD_COMMAND_TYPE_BCR | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL, /* CMD2 */ + CMD2_ALL_SEND_CID_SD = + 2 | HAL_MEMCARD_RESPONSE_R2 | HAL_MEMCARD_COMMAND_TYPE_BCR | + HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_NORMAL, + CMD3_SET_RELATIVE_ADDR = 3 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL, /* CMD3 */ + CMD3_SEND_RELATIVE_ADDR = + 3 | HAL_MEMCARD_RESPONSE_R6 | HAL_MEMCARD_COMMAND_TYPE_AC | + HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_NORMAL, + CMD4_SET_DSR = 4 | HAL_MEMCARD_RESPONSE_NONE | HAL_MEMCARD_COMMAND_TYPE_BC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD4 */ + CMD5_SLEEP_AWAKE = 5 | HAL_MEMCARD_RESPONSE_R1b | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL, /* CMD5 */ + CMD6_SWITCH = 6 | HAL_MEMCARD_RESPONSE_R1b | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL, /* CMD6 */ + CMD6_SWITCH_FUNC = + 6 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | + HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_NORMAL, + ACMD6_SET_BUS_WIDTH = + 6 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | + HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_APP, + CMD7_SELECT_CARD = 7 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD7 */ + CMD7_SELECT_CARD_PROG = 7 | HAL_MEMCARD_RESPONSE_R1b | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD7(from Disconnected State to Programming State) */ + CMD7_DESELECT_CARD = + 7 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | + HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, + CMD8_SEND_EXT_CSD = 8 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_READ | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL, /* CMD8 */ + CMD8_SEND_IF_COND = + 8 | HAL_MEMCARD_RESPONSE_R7 | HAL_MEMCARD_COMMAND_TYPE_BCR | + HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_NORMAL, + CMD9_SEND_CSD = 9 | HAL_MEMCARD_RESPONSE_R2 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD9 */ + CMD10_SEND_CID = 10 | HAL_MEMCARD_RESPONSE_R2 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD10 */ + CMD11_READ_DAT_UNTIL_STOP = 11 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_READ | HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_NORMAL, /* CMD11 */ + CMD12_STOP_TRANSMISSION = 12 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD12 */ + CMD12_STOP_TRANSMISSION_WRITE = 12 | HAL_MEMCARD_RESPONSE_R1b | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD12(R1b : write case) */ + CMD13_SEND_STATUS = 13 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD13 */ + ACMD13_SD_STATUS = + 13 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_READ | + HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_APP, + CMD14_BUSTEST_R = 14 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_READ | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL, /* CMD14 */ + CMD15_GO_INACTIVE_STATE = 15 | HAL_MEMCARD_RESPONSE_NONE | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD15 */ + +/* class 2 */ + CMD16_SET_BLOCKLEN = 16 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD16 */ + CMD17_READ_SINGLE_BLOCK = 17 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_READ | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD17 */ + CMD18_READ_MULTIPLE_BLOCK = 18 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_READ | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD18 */ + CMD19_BUS_TEST_W = 19 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL, /* CMD19 */ + +/* class 3 */ + CMD20_WRITE_DAT_UNTIL_STOP = 20 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL, /* CMD20 */ + CMD21 = 21, /* CMD21 */ + CMD22 = 22, /* CMD22 */ + ACMD22_SEND_NUM_WR_BLOCKS = + 22 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | + HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_APP, + +/* class 4 */ + CMD23_SET_BLOCK_COUNT = 23 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL, /* CMD23 */ + ACMD23_SET_WR_BLK_ERASE_COUNT = + 23 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | + HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_APP, + CMD24_WRITE_BLOCK = 24 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD24 */ + CMD25_WRITE_MULTIPLE_BLOCK = 25 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD25 */ + CMD26_PROGRAM_CID = 26 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL, /* CMD26 */ + CMD27_PROGRAM_CSD = 27 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD27 */ + +/* class 6 */ + CMD28_SET_WRITE_PROT = 28 | HAL_MEMCARD_RESPONSE_R1b | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD28 */ + CMD29_CLR_WRITE_PROT = 29 | HAL_MEMCARD_RESPONSE_R1b | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD29 */ + CMD30_SEND_WRITE_PROT = 30 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_READ | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD30 */ + CMD30_SEND_WRITE_PROT_TYPE = 31 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_READ | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD31 */ + +/* class 5 */ + CMD32_ERASE_WR_BLK_START = 32 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_NORMAL, /* CMD32 */ + CMD33_ERASE_WR_BLK_END = 33 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_NORMAL, /* CMD33 */ + CMD34 = 34, /* CMD34 */ + CMD35_ERASE_GROUP_START = 35 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL, /* CMD35 */ + CMD36_ERASE_GROUP_END = 36 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL, /* CMD36 */ + CMD37 = 37, /* CMD37 */ + CMD38_ERASE = 38 | HAL_MEMCARD_RESPONSE_R1b | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD38 */ + +/* class 9 */ + CMD39_FASTIO = 39 | HAL_MEMCARD_RESPONSE_R4 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL, /* CMD39 */ + CMD40_GO_IRQSTATE = 40 | HAL_MEMCARD_RESPONSE_R5 | HAL_MEMCARD_COMMAND_TYPE_BCR | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL, /* CMD40 */ + CMD41 = 41, /* CMD41 */ + ACMD41_SD_SEND_OP_COND = + 41 | HAL_MEMCARD_RESPONSE_R3 | HAL_MEMCARD_COMMAND_TYPE_BCR | + HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_APP, + +/* class 7 */ + CMD42_LOCK_UNLOCK = 42 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD42 */ + ACMD42_SET_CLR_CARD_DETECT = + 42 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | + HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_APP, + CMD43 = 43, /* CMD43 */ + CMD44 = 44, /* CMD44 */ + CMD45 = 45, /* CMD45 */ + CMD46 = 46, /* CMD46 */ + CMD47 = 47, /* CMD47 */ + CMD48 = 48, /* CMD48 */ + CMD49 = 49, /* CMD49 */ + CMD50 = 50, /* CMD50 */ + CMD51 = 51, /* CMD51 */ + ACMD51_SEND_SCR = + 51 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_READ | + HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_APP, + CMD52 = 52, /* CMD52 */ + CMD53 = 53, /* CMD53 */ + CMD54 = 54, /* CMD54 */ + +/* class 8 */ + CMD55_APP_CMD = 55 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD55 */ + CMD56_GEN_CMD = 56 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD56 */ + CMD57 = 57, /* CMD57 */ + CMD58 = 58, /* CMD58 */ + CMD59 = 59, /* CMD59 */ + CMD60 = 60, /* CMD60 */ + CMD61 = 61, /* CMD61 */ + CMD62 = 62, /* CMD62 */ + CMD63 = 63 /* CMD63 */ +} HAL_MEMCARD_COMMAND; + +/** @brief Configuration structure from HAL layer. + * + * If some field is not available it should be filled with 0xFF. + * The API version is 32-bit unsigned integer telling the version of the API. The integer is divided to four sections which each can be treated as a 8-bit unsigned number: + * Bits 31-24 make the most significant part of the version number. This number starts from 1 i.e. the second version of the API will be 0x02xxxxxx. This number changes only, if the API itself changes so much that it is not compatible anymore with older releases. + * Bits 23-16 API minor version number. For example API version 2.1 would be 0x0201xxxx. + * Bits 15-8 are the number of the year when release is done. The 0 is year 2000, 1 is year 2001 and so on + * Bits 7- are the week number when release is done. First full week of the year is 1 + * + * @note Example: let's assume that release 2.1 is done on week 10 year 2008 the version will get the value 0x0201080A + */ +typedef struct { + /** + * Version of the chipset API implementation + * + * bits [31:24] API specification major version number.<br> + * bits [23:16] API specification minor version number.<br> + * bits [15:8] API implemention year. (2000 = 0, 2001 = 1, ...)<br> + * bits [7:0] API implemention week.<br> + * Example: API specification version 4.0, implementation w46 2008 => 0x0400082E + */ + uint32_t api_version; + + /** maximum block count which can be transferred at once */ + uint32_t max_block_count; + + /** maximum clock frequence in Hz supported by HW */ + uint32_t max_clock_freq; + + /** maximum data bus width supported by HW */ + uint16_t max_data_width; + + /** Is high-speed mode supported by HW (yes=1, no=0) */ + uint8_t hs_mode_supported; + + /** Is memory card removable (yes=1, no=0) */ + uint8_t card_removable; + +} HAL_MEMCARD_HW_CONF; + +/** @brief Configuration structure to HAL layer. + */ +typedef struct { + /** how many times to try after fail, for instance sending command */ + uint32_t retries_after_fail; +} HAL_MEMCARD_INIT_CONF; + +/* ********************** DECLARATION OF EXTERNAL DATA ********************* */ + +/* ************************** FUNCTION PROTOTYPES ************************** */ + +/* ********************************* CODE ********************************** */ + +#endif /* __EMMC_HAL_H__ */ + +/* ******************************** END ************************************ */ diff --git a/drivers/renesas/rcar/emmc/emmc_init.c b/drivers/renesas/rcar/emmc/emmc_init.c new file mode 100644 index 00000000..386fb1e4 --- /dev/null +++ b/drivers/renesas/rcar/emmc/emmc_init.c @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <stddef.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 "rcar_private.h" + +st_mmc_base mmc_drv_obj; + +EMMC_ERROR_CODE rcar_emmc_memcard_power(uint8_t mode) +{ + + if (mode == TRUE) { + /* power on (Vcc&Vccq is always power on) */ + mmc_drv_obj.card_power_enable = TRUE; + } else { + /* power off (Vcc&Vccq is always power on) */ + mmc_drv_obj.card_power_enable = FALSE; + mmc_drv_obj.mount = FALSE; + mmc_drv_obj.selected = FALSE; + } + + return EMMC_SUCCESS; +} +static __inline void emmc_set_retry_count(uint32_t retry) +{ + mmc_drv_obj.retries_after_fail = retry; +} + +static __inline void emmc_set_data_timeout(uint32_t data_timeout) +{ + mmc_drv_obj.data_timeout = data_timeout; +} + +static void emmc_memset(uint8_t *buff, uint8_t data, uint32_t cnt) +{ + if (buff == NULL) { + return; + } + + while (cnt > 0) { + *buff++ = data; + cnt--; + } +} + +static void emmc_driver_config(void) +{ + emmc_set_retry_count(EMMC_RETRY_COUNT); + emmc_set_data_timeout(EMMC_RW_DATA_TIMEOUT); +} + +static void emmc_drv_init(void) +{ + emmc_memset((uint8_t *) (&mmc_drv_obj), 0, sizeof(st_mmc_base)); + mmc_drv_obj.card_present = HAL_MEMCARD_CARD_IS_IN; + mmc_drv_obj.data_timeout = EMMC_RW_DATA_TIMEOUT; + mmc_drv_obj.bus_width = HAL_MEMCARD_DATA_WIDTH_1_BIT; +} + +static EMMC_ERROR_CODE emmc_dev_finalize(void) +{ + EMMC_ERROR_CODE result; + uint32_t dataL; + + /* MMC power off + * the power supply of eMMC device is always turning on. + * RST_n : Hi --> Low level. + */ + result = rcar_emmc_memcard_power(FALSE); + + /* host controller reset */ + SETR_32(SD_INFO1, 0x00000000U); /* all interrupt clear */ + SETR_32(SD_INFO2, SD_INFO2_CLEAR); /* all interrupt clear */ + SETR_32(SD_INFO1_MASK, 0x00000000U); /* all interrupt disable */ + SETR_32(SD_INFO2_MASK, SD_INFO2_CLEAR); /* all interrupt disable */ + SETR_32(SD_CLK_CTRL, 0x00000000U); /* MMC clock stop */ + + dataL = mmio_read_32(CPG_SMSTPCR3); + if ((dataL & CPG_MSTP_MMC) == 0U) { + dataL |= (CPG_MSTP_MMC); + mmio_write_32(CPG_CPGWPR, (~dataL)); + mmio_write_32(CPG_SMSTPCR3, dataL); + } + + return result; +} + +static EMMC_ERROR_CODE emmc_dev_init(void) +{ + /* Enable clock supply to eMMC. */ + mstpcr_write(CPG_SMSTPCR3, CPG_MSTPSR3, CPG_MSTP_MMC); + + /* Set SD clock */ + mmio_write_32(CPG_CPGWPR, ~((uint32_t) (BIT9 | BIT0))); /* SD phy 200MHz */ + + /* Stop SDnH clock & SDn=200MHz */ + mmio_write_32(CPG_SDxCKCR, (BIT9 | BIT0)); + + /* MMCIF initialize */ + SETR_32(SD_INFO1, 0x00000000U); /* all interrupt clear */ + SETR_32(SD_INFO2, SD_INFO2_CLEAR); /* all interrupt clear */ + SETR_32(SD_INFO1_MASK, 0x00000000U); /* all interrupt disable */ + SETR_32(SD_INFO2_MASK, SD_INFO2_CLEAR); /* all interrupt disable */ + + SETR_32(HOST_MODE, 0x00000000U); /* SD_BUF access width = 64-bit */ + SETR_32(SD_OPTION, 0x0000C0EEU); /* Bus width = 1bit, timeout=MAX */ + SETR_32(SD_CLK_CTRL, 0x00000000U); /* Automatic Control=Disable, Clock Output=Disable */ + + return EMMC_SUCCESS; +} + +static EMMC_ERROR_CODE emmc_reset_controller(void) +{ + EMMC_ERROR_CODE retult; + + /* initialize mmc driver */ + emmc_drv_init(); + + /* initialize H/W */ + retult = emmc_dev_init(); + if (EMMC_SUCCESS != retult) { + return retult; + } + + mmc_drv_obj.initialize = TRUE; + + return retult; + +} + +EMMC_ERROR_CODE emmc_terminate(void) +{ + EMMC_ERROR_CODE result; + + result = emmc_dev_finalize(); + + emmc_memset((uint8_t *) (&mmc_drv_obj), 0, sizeof(st_mmc_base)); + + return result; +} + +EMMC_ERROR_CODE rcar_emmc_init(void) +{ + EMMC_ERROR_CODE retult; + + retult = emmc_reset_controller(); + if (EMMC_SUCCESS != retult) { + return retult; + } + + emmc_driver_config(); + + return EMMC_SUCCESS; +} diff --git a/drivers/renesas/rcar/emmc/emmc_interrupt.c b/drivers/renesas/rcar/emmc/emmc_interrupt.c new file mode 100644 index 00000000..3077db4c --- /dev/null +++ b/drivers/renesas/rcar/emmc/emmc_interrupt.c @@ -0,0 +1,217 @@ +/* + * 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; +} diff --git a/drivers/renesas/rcar/emmc/emmc_mount.c b/drivers/renesas/rcar/emmc/emmc_mount.c new file mode 100644 index 00000000..9a7d2cad --- /dev/null +++ b/drivers/renesas/rcar/emmc/emmc_mount.c @@ -0,0 +1,680 @@ +/* + * 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; +} diff --git a/drivers/renesas/rcar/emmc/emmc_read.c b/drivers/renesas/rcar/emmc/emmc_read.c new file mode 100644 index 00000000..b11c2c43 --- /dev/null +++ b/drivers/renesas/rcar/emmc/emmc_read.c @@ -0,0 +1,127 @@ +/* + * 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; +} diff --git a/drivers/renesas/rcar/emmc/emmc_registers.h b/drivers/renesas/rcar/emmc/emmc_registers.h new file mode 100644 index 00000000..a670ab7e --- /dev/null +++ b/drivers/renesas/rcar/emmc/emmc_registers.h @@ -0,0 +1,260 @@ +/* + * 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 ************************************ */ diff --git a/drivers/renesas/rcar/emmc/emmc_std.h b/drivers/renesas/rcar/emmc/emmc_std.h new file mode 100644 index 00000000..f4ce1981 --- /dev/null +++ b/drivers/renesas/rcar/emmc/emmc_std.h @@ -0,0 +1,474 @@ +/* + * 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__ */ diff --git a/drivers/renesas/rcar/emmc/emmc_utility.c b/drivers/renesas/rcar/emmc/emmc_utility.c new file mode 100644 index 00000000..e64947dd --- /dev/null +++ b/drivers/renesas/rcar/emmc/emmc_utility.c @@ -0,0 +1,225 @@ +/* + * 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; +} diff --git a/drivers/renesas/rcar/iic_dvfs/iic_dvfs.c b/drivers/renesas/rcar/iic_dvfs/iic_dvfs.c new file mode 100644 index 00000000..11d52bf7 --- /dev/null +++ b/drivers/renesas/rcar/iic_dvfs/iic_dvfs.c @@ -0,0 +1,568 @@ +/* + * 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; +} diff --git a/drivers/renesas/rcar/iic_dvfs/iic_dvfs.h b/drivers/renesas/rcar/iic_dvfs/iic_dvfs.h new file mode 100644 index 00000000..3c4a9a55 --- /dev/null +++ b/drivers/renesas/rcar/iic_dvfs/iic_dvfs.h @@ -0,0 +1,23 @@ +/* + * 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 diff --git a/drivers/renesas/rcar/io/io_common.h b/drivers/renesas/rcar/io/io_common.h new file mode 100644 index 00000000..c5729b89 --- /dev/null +++ b/drivers/renesas/rcar/io/io_common.h @@ -0,0 +1,16 @@ +/* + * 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 diff --git a/drivers/renesas/rcar/io/io_emmcdrv.c b/drivers/renesas/rcar/io/io_emmcdrv.c new file mode 100644 index 00000000..f74bd5f4 --- /dev/null +++ b/drivers/renesas/rcar/io/io_emmcdrv.c @@ -0,0 +1,172 @@ +/* + * 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) ¤t_file; + + return IO_SUCCESS; +} + +static int32_t emmcdrv_block_close(io_entity_t *entity) +{ + memset((void *)¤t_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; +} diff --git a/drivers/renesas/rcar/io/io_emmcdrv.h b/drivers/renesas/rcar/io/io_emmcdrv.h new file mode 100644 index 00000000..82c6c516 --- /dev/null +++ b/drivers/renesas/rcar/io/io_emmcdrv.h @@ -0,0 +1,13 @@ +/* + * 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 diff --git a/drivers/renesas/rcar/io/io_memdrv.c b/drivers/renesas/rcar/io/io_memdrv.c new file mode 100644 index 00000000..e55fd646 --- /dev/null +++ b/drivers/renesas/rcar/io/io_memdrv.c @@ -0,0 +1,147 @@ +/* + * 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) ¤t_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 *)¤t_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; +} diff --git a/drivers/renesas/rcar/io/io_memdrv.h b/drivers/renesas/rcar/io/io_memdrv.h new file mode 100644 index 00000000..41727d3a --- /dev/null +++ b/drivers/renesas/rcar/io/io_memdrv.h @@ -0,0 +1,13 @@ +/* + * 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 diff --git a/drivers/renesas/rcar/io/io_private.h b/drivers/renesas/rcar/io/io_private.h new file mode 100644 index 00000000..d0e66c01 --- /dev/null +++ b/drivers/renesas/rcar/io/io_private.h @@ -0,0 +1,20 @@ +/* + * 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 diff --git a/drivers/renesas/rcar/io/io_rcar.c b/drivers/renesas/rcar/io/io_rcar.c new file mode 100644 index 00000000..4293c51c --- /dev/null +++ b/drivers/renesas/rcar/io/io_rcar.c @@ -0,0 +1,640 @@ +/* + * 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) ¤t_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) ¤t_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(¤t_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; +} diff --git a/drivers/renesas/rcar/io/io_rcar.h b/drivers/renesas/rcar/io/io_rcar.h new file mode 100644 index 00000000..24209024 --- /dev/null +++ b/drivers/renesas/rcar/io/io_rcar.h @@ -0,0 +1,14 @@ +/* + * 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 diff --git a/drivers/renesas/rcar/pwrc/call_sram.S b/drivers/renesas/rcar/pwrc/call_sram.S new file mode 100644 index 00000000..7c96b7ee --- /dev/null +++ b/drivers/renesas/rcar/pwrc/call_sram.S @@ -0,0 +1,90 @@ +/* + * 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 diff --git a/drivers/renesas/rcar/pwrc/pwrc.c b/drivers/renesas/rcar/pwrc/pwrc.c new file mode 100644 index 00000000..6dfc0b69 --- /dev/null +++ b/drivers/renesas/rcar/pwrc/pwrc.c @@ -0,0 +1,790 @@ +/* + * 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; +} diff --git a/drivers/renesas/rcar/pwrc/pwrc.h b/drivers/renesas/rcar/pwrc/pwrc.h new file mode 100644 index 00000000..166886ec --- /dev/null +++ b/drivers/renesas/rcar/pwrc/pwrc.h @@ -0,0 +1,77 @@ +/* + * 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 diff --git a/drivers/renesas/rcar/rom/rom_api.c b/drivers/renesas/rcar/rom/rom_api.c new file mode 100644 index 00000000..c14de55b --- /dev/null +++ b/drivers/renesas/rcar/rom/rom_api.c @@ -0,0 +1,93 @@ +/* + * 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); +} diff --git a/drivers/renesas/rcar/rom/rom_api.h b/drivers/renesas/rcar/rom/rom_api.h new file mode 100644 index 00000000..85105ef5 --- /dev/null +++ b/drivers/renesas/rcar/rom/rom_api.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef ROM_API_H__ +#define ROM_API_H__ + +#include <stdint.h> + +#define SBROM_OK (0x00000000U) +#define SBROM_ILLEGAL_INPUT_PARAM_ERR (0x0B000001U) +#define SBROM_ILLEGAL_OEM_HASH_VALUE_ERR (0x0B000008U) +#define SBROM_ILLEGAL_LCS_FOR_OPERATION_ERR (0x0B000010U) +#define SBROM_HASH_NOT_PROGRAMMED_ERR (0x0B000100U) +#define SBROM_PUB_KEY_HASH_VALIDATION_FAILURE (0xF1000006U) +#define SBROM_RSA_SIG_VERIFICATION_FAILED (0xF1000007U) + +#define LCS_CM (0x0U) +#define LCS_DM (0x1U) +#define LCS_SD (0x3U) +#define LCS_SE (0x5U) +#define LCS_FA (0x7U) + +typedef uint32_t(*rom_read_flash_f) (uint64_t src, uint8_t *dst, uint32_t len); +uint32_t rcar_rom_secure_boot_api(uint32_t *key, uint32_t *cert, + rom_read_flash_f f); +uint32_t rcar_rom_get_lcs(uint32_t *lcs); + +#endif diff --git a/drivers/renesas/rcar/rpc/rpc_driver.c b/drivers/renesas/rcar/rpc/rpc_driver.c new file mode 100644 index 00000000..bc7424ac --- /dev/null +++ b/drivers/renesas/rcar/rpc/rpc_driver.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <mmio.h> +#include <stdint.h> +#include <string.h> +#include "cpg_registers.h" +#include "rpc_registers.h" +#include "debug.h" +#include "rcar_private.h" + +#define MSTPSR9_RPC_BIT (0x00020000U) +#define RPC_CMNCR_MD_BIT (0x80000000U) + +static void rpc_enable(void) +{ + /* Enable clock supply to RPC. */ + mstpcr_write(CPG_SMSTPCR9, CPG_MSTPSR9, MSTPSR9_RPC_BIT); +} + +static void rpc_setup(void) +{ + if (mmio_read_32(RPC_CMNCR) & RPC_CMNCR_MD_BIT) + mmio_clrbits_32(RPC_CMNCR, RPC_CMNCR_MD_BIT); +} + +void rcar_rpc_init(void) +{ + rpc_enable(); + rpc_setup(); +} diff --git a/drivers/renesas/rcar/rpc/rpc_registers.h b/drivers/renesas/rcar/rpc/rpc_registers.h new file mode 100644 index 00000000..326519d7 --- /dev/null +++ b/drivers/renesas/rcar/rpc/rpc_registers.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef RPC_REGISTER_H__ +#define RPC_REGISTER_H__ + +#define RPC_BASE (0xEE200000U) +#define RPC_CMNCR (RPC_BASE + 0x0000U) +#define RPC_SSLDR (RPC_BASE + 0x0004U) +#define RPC_DRCR (RPC_BASE + 0x000CU) +#define RPC_DRCMR (RPC_BASE + 0x0010U) +#define RPC_DRENR (RPC_BASE + 0x001CU) +#define RPC_SMCR (RPC_BASE + 0x0020U) +#define RPC_SMCMR (RPC_BASE + 0x0024U) +#define RPC_SMENR (RPC_BASE + 0x0030U) +#define RPC_CMNSR (RPC_BASE + 0x0048U) +#define RPC_DRDMCR (RPC_BASE + 0x0058U) +#define RPC_DRDRENR (RPC_BASE + 0x005CU) +#define RPC_PHYCNT (RPC_BASE + 0x007CU) +#define RPC_PHYINT (RPC_BASE + 0x0088U) + +#endif diff --git a/drivers/renesas/rcar/scif/scif.S b/drivers/renesas/rcar/scif/scif.S new file mode 100644 index 00000000..1cc0d590 --- /dev/null +++ b/drivers/renesas/rcar/scif/scif.S @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <asm_macros.S> + +#define SCIF_INTERNAL_CLK 0 +#define SCIF_EXTARNAL_CLK 1 +#define SCIF_CLK SCIF_INTERNAL_CLK + +/* product register */ +#define PRR (0xFFF00044) +#define PRR_PRODUCT_MASK (0x00007F00) +#define PRR_CUT_MASK (0x000000FF) +#define PRR_PRODUCT_H3_VER_10 (0x00004F00) +#define PRR_PRODUCT_E3 (0x00005700) + +/* module stop */ +#define CPG_BASE (0xE6150000) +#define CPG_SMSTPCR3 (0x013C) +#define CPG_MSTPSR3 (0x0048) +#define MSTP310 (1 << 10) +#define CPG_CPGWPR (0x0900) + +/* scif */ +#define SCIF2_BASE (0xE6E88000) +#define SCIF_SCSMR (0x00) +#define SCIF_SCBRR (0x04) +#define SCIF_SCSCR (0x08) +#define SCIF_SCFTDR (0x0C) +#define SCIF_SCFSR (0x10) +#define SCIF_SCFRDR (0x14) +#define SCIF_SCFCR (0x18) +#define SCIF_SCFDR (0x1C) +#define SCIF_SCSPTR (0x20) +#define SCIF_SCLSR (0x24) +#define SCIF_DL (0x30) +#define SCIF_CKS (0x34) + +/* mode pin */ +#define RST_MODEMR (0xE6160060) +#define MODEMR_MD12 (0x00001000) + +#define SCSMR_CA_MASK (1 << 7) +#define SCSMR_CA_ASYNC (0x0000) +#define SCSMR_CHR_MASK (1 << 6) +#define SCSMR_CHR_8 (0x0000) +#define SCSMR_PE_MASK (1 << 5) +#define SCSMR_PE_DIS (0x0000) +#define SCSMR_STOP_MASK (1 << 3) +#define SCSMR_STOP_1 (0x0000) +#define SCSMR_CKS_MASK (3 << 0) +#define SCSMR_CKS_DIV1 (0x0000) +#define SCSMR_INIT_DATA (SCSMR_CA_ASYNC + \ + SCSMR_CHR_8 + \ + SCSMR_PE_DIS + \ + SCSMR_STOP_1 + \ + SCSMR_CKS_DIV1) +#define SCBRR_115200BPS (17) +#define SCBRR_115200BPS_E3_SSCG (15) +#define SCBRR_230400BPS (8) + +#define SCSCR_TE_MASK (1 << 5) +#define SCSCR_TE_DIS (0x0000) +#define SCSCR_TE_EN (0x0020) +#define SCSCR_RE_MASK (1 << 4) +#define SCSCR_RE_DIS (0x0000) +#define SCSCR_RE_EN (0x0010) +#define SCSCR_CKE_MASK (3 << 0) +#define SCSCR_CKE_INT (0x0000) +#define SCSCR_CKE_BRG (0x0002) +#if SCIF_CLK == SCIF_EXTARNAL_CLK +#define SCSCR_CKE_INT_CLK (SCSCR_CKE_BRG) +#else +#define SCSCR_CKE_INT_CLK (SCSCR_CKE_INT) +#endif +#define SCFSR_INIT_DATA (0x0000) +#define SCFCR_TTRG_MASK (3 << 4) +#define SCFCR_TTRG_8 (0x0000) +#define SCFCR_TTRG_0 (0x0030) +#define SCFCR_TFRST_MASK (1 << 2) +#define SCFCR_TFRST_DIS (0x0000) +#define SCFCR_TFRST_EN (0x0004) +#define SCFCR_RFRS_MASK (1 << 1) +#define SCFCR_RFRS_DIS (0x0000) +#define SCFCR_RFRS_EN (0x0002) +#define SCFCR_INIT_DATA (SCFCR_TTRG_8) +#define SCFDR_T_MASK (0x1f << 8) +#define DL_INIT_DATA (8) +#define CKS_CKS_DIV_MASK (1 << 15) +#define CKS_CKS_DIV_CLK (0x0000) +#define CKS_XIN_MASK (1 << 14) +#define CKS_XIN_SCIF_CLK (0x0000) +#define CKS_INIT_DATA (CKS_CKS_DIV_CLK + CKS_XIN_SCIF_CLK) + + .globl console_init + .globl console_uninit + .globl console_putc + .globl console_core_init + .globl console_core_putc + .globl console_getc + .globl console_flush + + /* + * The console base is in the data section and not in .bss + * even though it is zero-init. In particular, this allows + * the console functions to start using this variable before + * the runtime memory is initialized for images which do not + * need to copy the .data section from ROM to RAM. + */ + /* ----------------------------------------------- + * int console_init(unsigned long base_addr, + * unsigned int uart_clk, unsigned int baud_rate) + * Function to initialize the console without a + * C Runtime to print debug information. It saves + * the console base to the data section. + * In: x0 - console base address + * w1 - Uart clock in Hz + * w2 - Baud rate + * out: return 1 on success. + * Clobber list : x1 - x3 + * ----------------------------------------------- + */ +func console_init + b console_core_init +endfunc console_init + +func console_uninit + ret +endfunc console_uninit + + /* ----------------------------------------------- + * int console_core_init(unsigned long base_addr, + * unsigned int uart_clk, unsigned int baud_rate) + * Function to initialize the console without a + * C Runtime to print debug information. This + * function will be accessed by console_init and + * crash reporting. + * In: x0 - console base address + * w1 - Uart clock in Hz + * w2 - Baud rate + * Out: return 1 on success + * Clobber list : x1, x2 + * ----------------------------------------------- + */ +func console_core_init + ldr x0, =CPG_BASE + ldr w1, [x0, #CPG_SMSTPCR3] + and w1, w1, #~MSTP310 /* MSTP310=0 */ + mvn w2, w1 + str w2, [x0, #CPG_CPGWPR] + str w1, [x0, #CPG_SMSTPCR3] +5: + ldr w1, [x0, #CPG_MSTPSR3] + and w1, w1, #MSTP310 + cbnz w1, 5b + + ldr x0, =SCIF2_BASE + /* Clear bits TE and RE in SCSCR to 0 */ + mov w1, #(SCSCR_TE_DIS + SCSCR_RE_DIS) + strh w1, [x0, #SCIF_SCSCR] + /* Set bits TFRST and RFRST in SCFCR to 1 */ + ldrh w1, [x0, #SCIF_SCFCR] + orr w1, w1, #(SCFCR_TFRST_EN + SCFCR_RFRS_EN) + strh w1, [x0, #SCIF_SCFCR] + /* Read flags of ER, DR, BRK, and RDF in SCFSR and those of TO and ORER + in SCLSR, then clear them to 0 */ + mov w1, #SCFSR_INIT_DATA + strh w1, [x0, #SCIF_SCFSR] + mov w1, #0 + strh w1, [x0, #SCIF_SCLSR] + /* Set bits CKE[1:0] in SCSCR */ + ldrh w1, [x0, #SCIF_SCSCR] + and w1, w1, #~SCSCR_CKE_MASK + mov w2, #SCSCR_CKE_INT_CLK + orr w1, w1, w2 + strh w1, [x0, #SCIF_SCSCR] + /* Set data transfer format in SCSMR */ + mov w1, #SCSMR_INIT_DATA + strh w1, [x0, #SCIF_SCSMR] + /* Set value in SCBRR */ +#if SCIF_CLK == SCIF_INTERNAL_CLK + ldr x1, =PRR + ldr w1, [x1] + and w1, w1, #(PRR_PRODUCT_MASK | PRR_CUT_MASK) + mov w2, #PRR_PRODUCT_H3_VER_10 + cmp w1, w2 + beq 3f + and w1, w1, #PRR_PRODUCT_MASK + mov w2, #PRR_PRODUCT_E3 + cmp w1, w2 + bne 4f + + ldr x1, =RST_MODEMR + ldr w1, [x1] + and w1, w1, #MODEMR_MD12 + mov w2, #MODEMR_MD12 + cmp w1, w2 + bne 4f + + mov w1, #SCBRR_115200BPS_E3_SSCG + b 2f +4: + mov w1, #SCBRR_115200BPS + b 2f +3: + mov w1, #SCBRR_230400BPS +2: + strb w1, [x0, SCIF_SCBRR] +#else + mov w1, #DL_INIT_DATA + strh w1, [x0, #SCIF_DL] + mov w1, #CKS_INIT_DATA + strh w1, [x0, #SCIF_CKS] +#endif + /* 1-bit interval elapsed */ + mov w1, #100 +1: + subs w1, w1, #1 + cbnz w1, 1b + /* + * Set bits RTRG[1:0], TTRG[1:0], and MCE in SCFCR + * Clear bits FRST and RFRST to 0 + */ + mov w1, #SCFCR_INIT_DATA + strh w1, [x0, #SCIF_SCFCR] + /* Set bits TE and RE in SCSCR to 1 */ + ldrh w1, [x0, #SCIF_SCSCR] + orr w1, w1, #(SCSCR_TE_EN + SCSCR_RE_EN) + strh w1, [x0, #SCIF_SCSCR] + mov x0, #1 + + ret +endfunc console_core_init + + /* --------------------------------------------- + * int console_putc(int c) + * Function to output a character over the + * console. It returns the character printed on + * success or -1 on error. + * In : x0 - character to be printed + * Out : return -1 on error else return character. + * Clobber list : x1, x2 + * --------------------------------------------- + */ +func console_putc + b console_core_putc +endfunc console_putc + + /* -------------------------------------------------------- + * int console_core_putc(int c, unsigned int base_addr) + * Function to output a character over the console. It + * returns the character printed on success or -1 on error. + * In : w0 - character to be printed + * x1 - console base address + * Out : return -1 on error else return character. + * Clobber list : x2 + * -------------------------------------------------------- + */ +func console_core_putc + ldr x1, =SCIF2_BASE + cmp w0, #0xA + /* Prepend '\r' to '\n' */ + bne 2f +1: + /* Check if the transmit FIFO is full */ + ldrh w2, [x1, #SCIF_SCFDR] + ubfx w2, w2, #8, #5 + cmp w2, #16 + bcs 1b + mov w2, #0x0D + strb w2, [x1, #SCIF_SCFTDR] +2: + /* Check if the transmit FIFO is full */ + ldrh w2, [x1, #SCIF_SCFDR] + ubfx w2, w2, #8, #5 + cmp w2, #16 + bcs 2b + strb w0, [x1, #SCIF_SCFTDR] + + ret +endfunc console_core_putc + + /* --------------------------------------------- + * int console_getc(void) + * Function to get a character from the console. + * It returns the character grabbed on success + * or -1 on error. + * Clobber list : x0, x1 + * --------------------------------------------- + */ +func console_getc + mov w0, #-1 + ret +endfunc console_getc + + /* --------------------------------------------- + * int console_flush(void) + * Function to force a write of all buffered + * data that hasn't been output. It returns 0 + * upon successful completion, otherwise it + * returns -1. + * Clobber list : x0, x1 + * --------------------------------------------- + */ +func console_flush + ldr x0, =SCIF2_BASE +1: + ldrh w1, [x0, #SCIF_SCFDR] + ubfx w1, w1, #8, #5 + cmp w1, #0 + bne 1b + + mov x0, #100 + mov x3, x30 + bl rcar_micro_delay + mov x30, x3 + + ldr x0, =SCIF2_BASE + ldrh w1, [x0, #SCIF_SCSCR] + and w1, w1, #~(SCSCR_TE_EN + SCSCR_RE_EN) + strh w1, [x0, #SCIF_SCSCR] + + mov w0, #0 + ret +endfunc console_flush diff --git a/drivers/renesas/rcar/watchdog/swdt.c b/drivers/renesas/rcar/watchdog/swdt.c new file mode 100644 index 00000000..6df47b9b --- /dev/null +++ b/drivers/renesas/rcar/watchdog/swdt.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch_helpers.h> +#include <debug.h> +#include <gicv2.h> +#include <mmio.h> +#include "rcar_def.h" + +extern void gicd_set_icenabler(uintptr_t base, unsigned int id); + +#define RST_BASE (0xE6160000U) +#define RST_WDTRSTCR (RST_BASE + 0x0054U) +#define SWDT_BASE (0xE6030000U) +#define SWDT_WTCNT (SWDT_BASE + 0x0000U) +#define SWDT_WTCSRA (SWDT_BASE + 0x0004U) +#define SWDT_WTCSRB (SWDT_BASE + 0x0008U) +#define SWDT_GICD_BASE (0xF1010000U) +#define SWDT_GICC_BASE (0xF1020000U) +#define SWDT_GICD_CTLR (SWDT_GICD_BASE + 0x0000U) +#define SWDT_GICD_IGROUPR (SWDT_GICD_BASE + 0x0080U) +#define SWDT_GICD_ISPRIORITYR (SWDT_GICD_BASE + 0x0400U) +#define SWDT_GICC_CTLR (SWDT_GICC_BASE + 0x0000U) +#define SWDT_GICC_PMR (SWDT_GICC_BASE + 0x0004U) +#define SWDT_GICD_ITARGETSR (SWDT_GICD_BASE + 0x0800U) +#define IGROUPR_NUM (16U) +#define ISPRIORITY_NUM (128U) +#define ITARGET_MASK (0x03U) + +#define WDTRSTCR_UPPER_BYTE (0xA55A0000U) +#define WTCSRA_UPPER_BYTE (0xA5A5A500U) +#define WTCSRB_UPPER_BYTE (0xA5A5A500U) +#define WTCNT_UPPER_BYTE (0x5A5A0000U) +#define WTCNT_RESET_VALUE (0xF488U) +#define WTCSRA_BIT_CKS (0x0007U) +#define WTCSRB_BIT_CKS (0x003FU) +#define SWDT_RSTMSK (1U << 1U) +#define WTCSRA_WOVFE (1U << 3U) +#define WTCSRA_WRFLG (1U << 5U) +#define SWDT_ENABLE (1U << 7U) + +#define WDTRSTCR_MASK_ALL (0x0000FFFFU) +#define WTCSRA_MASK_ALL (0x000000FFU) +#define WTCNT_INIT_DATA (WTCNT_UPPER_BYTE + WTCNT_RESET_VALUE) +#define WTCSRA_INIT_DATA (WTCSRA_UPPER_BYTE + 0x0FU) +#define WTCSRB_INIT_DATA (WTCSRB_UPPER_BYTE + 0x21U) + +#define WTCNT_COUNT_8p13k (0x10000U - 40687U) +#define WTCNT_COUNT_8p13k_H3VER10 (0x10000U - 20343U) +#define WTCNT_COUNT_8p22k (0x10000U - 41115U) +#define WTCNT_COUNT_7p81k (0x10000U - 39062U) +#define WTCSRA_CKS_DIV16 (0x00000002U) + +static void swdt_disable(void) +{ + uint32_t rmsk; + + rmsk = mmio_read_32(RST_WDTRSTCR) & WDTRSTCR_MASK_ALL; + rmsk |= SWDT_RSTMSK; + mmio_write_32(RST_WDTRSTCR, WDTRSTCR_UPPER_BYTE | rmsk); + + mmio_write_32(SWDT_WTCNT, WTCNT_INIT_DATA); + mmio_write_32(SWDT_WTCSRA, WTCSRA_INIT_DATA); + mmio_write_32(SWDT_WTCSRB, WTCSRB_INIT_DATA); + + /* Set the interrupt clear enable register */ + gicd_set_icenabler(RCAR_GICD_BASE, ARM_IRQ_SEC_WDT); +} + +void rcar_swdt_init(void) +{ + uint32_t rmsk, val, sr; +#if (RCAR_LSI != RCAR_E3) + uint32_t reg, product_cut, chk_data; + + reg = mmio_read_32(RCAR_PRR); + product_cut = reg & (RCAR_PRODUCT_MASK | RCAR_CUT_MASK); + + reg = mmio_read_32(RCAR_MODEMR); + chk_data = reg & CHECK_MD13_MD14; +#endif + /* stop watchdog */ + if (mmio_read_32(SWDT_WTCSRA) & SWDT_ENABLE) + mmio_write_32(SWDT_WTCSRA, WTCSRA_UPPER_BYTE); + + mmio_write_32(SWDT_WTCSRA, WTCSRA_UPPER_BYTE | + WTCSRA_WOVFE | WTCSRA_CKS_DIV16); + +#if (RCAR_LSI == RCAR_E3) + mmio_write_32(SWDT_WTCNT, WTCNT_UPPER_BYTE | WTCNT_COUNT_7p81k); +#else + val = WTCNT_UPPER_BYTE; + + switch (chk_data) { + case MD14_MD13_TYPE_0: + case MD14_MD13_TYPE_2: + val |= WTCNT_COUNT_8p13k; + break; + case MD14_MD13_TYPE_1: + val |= WTCNT_COUNT_8p22k; + break; + case MD14_MD13_TYPE_3: + val |= product_cut == (RCAR_PRODUCT_H3 | RCAR_CUT_VER10) ? + WTCNT_COUNT_8p13k_H3VER10 : WTCNT_COUNT_8p13k; + break; + default: + ERROR("MODEMR ERROR value = %x\n", chk_data); + panic(); + break; + } + + mmio_write_32(SWDT_WTCNT, val); +#endif + rmsk = mmio_read_32(RST_WDTRSTCR) & WDTRSTCR_MASK_ALL; + rmsk |= SWDT_RSTMSK | WDTRSTCR_UPPER_BYTE; + mmio_write_32(RST_WDTRSTCR, rmsk); + + while ((mmio_read_8(SWDT_WTCSRA) & WTCSRA_WRFLG) != 0U) + ; + + /* Start the System WatchDog Timer */ + sr = mmio_read_32(SWDT_WTCSRA) & WTCSRA_MASK_ALL; + mmio_write_32(SWDT_WTCSRA, (WTCSRA_UPPER_BYTE | sr | SWDT_ENABLE)); +} + +void rcar_swdt_release(void) +{ + uintptr_t itarget = SWDT_GICD_ITARGETSR + + (ARM_IRQ_SEC_WDT & ~ITARGET_MASK); + uint32_t i; + + write_daifset(DAIF_FIQ_BIT); + swdt_disable(); + gicv2_cpuif_disable(); + + for (i = 0; i < IGROUPR_NUM; i++) + mmio_write_32(SWDT_GICD_IGROUPR + i * 4, 0U); + + for (i = 0; i < ISPRIORITY_NUM; i++) + mmio_write_32(SWDT_GICD_ISPRIORITYR + i * 4, 0U); + + mmio_write_32(itarget, 0U); + mmio_write_32(SWDT_GICD_CTLR, 0U); + mmio_write_32(SWDT_GICC_CTLR, 0U); + mmio_write_32(SWDT_GICC_PMR, 0U); +} + +void rcar_swdt_exec(uint64_t p) +{ + gicv2_end_of_interrupt(ARM_IRQ_SEC_WDT); + rcar_swdt_release(); + ERROR("\n"); + ERROR("System WDT overflow, occured address is %p\n", (void *)p); + panic(); +} |
