| /* |
| * Copyright (c) 2016 - 2020, Broadcom |
| * |
| * SPDX-License-Identifier: BSD-3-Clause |
| */ |
| |
| #include <assert.h> |
| #include <string.h> |
| |
| #include <lib/mmio.h> |
| |
| #include <platform_def.h> |
| |
| #include "bcm_emmc.h" |
| #include "emmc_chal_types.h" |
| #include "emmc_chal_sd.h" |
| #include "emmc_pboot_hal_memory_drv.h" |
| |
| extern void emmc_soft_reset(void); |
| |
| #define SD_VDD_WINDOW_1_6_TO_1_7 0x00000010 // 1.6 V to 1.7 Volts |
| #define SD_VDD_WINDOW_1_7_TO_1_8 0x00000020 // 1.7 V to 1.8 Volts |
| #define SD_VDD_WINDOW_1_8_TO_1_9 0x00000040 // 1.8 V to 1.9 Volts |
| #define SD_VDD_WINDOW_1_9_TO_2_0 0x00000080 // 1.9 V to 2.0 Volts |
| #define SD_VDD_WINDOW_2_0_TO_2_1 0x00000100 // 2.0 V to 2.1 Volts |
| #define SD_VDD_WINDOW_2_1_TO_2_2 0x00000200 // 2.1 V to 2.2 Volts |
| #define SD_VDD_WINDOW_2_2_TO_2_3 0x00000400 // 2.2 V to 2.3 Volts |
| #define SD_VDD_WINDOW_2_3_TO_2_4 0x00000800 // 2.3 V to 2.4 Volts |
| #define SD_VDD_WINDOW_2_4_TO_2_5 0x00001000 // 2.4 V to 2.5 Volts |
| #define SD_VDD_WINDOW_2_5_TO_2_6 0x00002000 // 2.5 V to 2.6 Volts |
| #define SD_VDD_WINDOW_2_6_TO_2_7 0x00004000 // 2.6 V to 2.7 Volts |
| #define SD_VDD_WINDOW_2_7_TO_2_8 0x00008000 // 2.7 V to 2.8 Volts |
| #define SD_VDD_WINDOW_2_8_TO_2_9 0x00010000 // 2.8 V to 2.9 Volts |
| #define SD_VDD_WINDOW_2_9_TO_3_0 0x00020000 // 2.9 V to 3.0 Volts |
| #define SD_VDD_WINDOW_3_0_TO_3_1 0x00040000 // 3.0 V to 3.1 Volts |
| #define SD_VDD_WINDOW_3_1_TO_3_2 0x00080000 // 3.1 V to 3.2 Volts |
| #define SD_VDD_WINDOW_3_2_TO_3_3 0x00100000 // 3.2 V to 3.3 Volts |
| #define SD_VDD_WINDOW_3_3_TO_3_4 0x00200000 // 3.3 V to 3.4 Volts |
| #define SD_VDD_WINDOW_3_4_TO_3_5 0x00400000 // 3.4 V to 3.5 Volts |
| #define SD_VDD_WINDOW_3_5_TO_3_6 0x00800000 // 3.5 V to 3.6 Volts |
| |
| #define SD_VDD_WINDOW_1_6_TO_2_6 (SD_VDD_WINDOW_1_6_TO_1_7 | \ |
| SD_VDD_WINDOW_1_7_TO_1_8 | \ |
| SD_VDD_WINDOW_1_8_TO_1_9 | \ |
| SD_VDD_WINDOW_1_9_TO_2_0 | \ |
| SD_VDD_WINDOW_2_0_TO_2_1 | \ |
| SD_VDD_WINDOW_2_1_TO_2_2 | \ |
| SD_VDD_WINDOW_2_2_TO_2_3 | \ |
| SD_VDD_WINDOW_2_3_TO_2_4 | \ |
| SD_VDD_WINDOW_2_4_TO_2_5 | \ |
| SD_VDD_WINDOW_2_5_TO_2_6) |
| |
| #define SD_VDD_WINDOW_2_6_TO_3_2 (SD_VDD_WINDOW_2_6_TO_2_7 | \ |
| SD_VDD_WINDOW_2_7_TO_2_8 | \ |
| SD_VDD_WINDOW_2_8_TO_2_9 | \ |
| SD_VDD_WINDOW_2_9_TO_3_0 | \ |
| SD_VDD_WINDOW_3_0_TO_3_1 | \ |
| SD_VDD_WINDOW_3_1_TO_3_2) |
| |
| #define SD_VDD_WINDOW_3_2_TO_3_6 (SD_VDD_WINDOW_3_2_TO_3_3 | \ |
| SD_VDD_WINDOW_3_3_TO_3_4 | \ |
| SD_VDD_WINDOW_3_4_TO_3_5 | \ |
| SD_VDD_WINDOW_3_5_TO_3_6) |
| |
| |
| static int32_t chal_sd_set_power(struct sd_dev *handle, |
| uint32_t voltage, uint32_t state); |
| |
| static void chal_sd_set_dma_boundary(struct sd_dev *handle, uint32_t boundary); |
| |
| static int32_t chal_sd_setup_handler(struct sd_dev *handle, |
| uint32_t sdBbase, uint32_t hostBase); |
| |
| /* |
| * Configure host controller pwr settings, |
| * to match voltage requirements by SD Card |
| */ |
| static int32_t chal_sd_set_power(struct sd_dev *handle, |
| uint32_t voltage, uint32_t state) |
| { |
| int32_t rc, rval = SD_FAIL; |
| uint32_t time = 0; |
| |
| if (handle == NULL) |
| return SD_INVALID_HANDLE; |
| |
| mmio_clrsetbits_32(handle->ctrl.sdRegBaseAddr + |
| SD4_EMMC_TOP_CTRL_OFFSET, |
| (SD4_EMMC_TOP_CTRL_SDVSELVDD1_MASK | |
| SD4_EMMC_TOP_CTRL_SDPWR_MASK), |
| (voltage << 9)); |
| |
| /* |
| * Long delay is required here in emulation. Without this, the initial |
| * commands sent to the eMMC card timeout. We don't know if this |
| * delay is necessary with silicon, leaving in for safety. |
| * It is observed that 403ms on emulation system and as per the clock |
| * calculations it is expected to complete with in 1ms on chip |
| */ |
| do { |
| rc = mmio_read_32(handle->ctrl.sdRegBaseAddr + |
| SD4_EMMC_TOP_INTR_OFFSET); |
| |
| if ((rc & SD4_EMMC_TOP_INTR_CRDINS_MASK) == |
| SD4_EMMC_TOP_INTR_CRDINS_MASK) |
| break; |
| |
| mdelay(1); |
| } while (time++ < EMMC_CARD_DETECT_TIMEOUT_MS); |
| |
| if (time >= EMMC_CARD_DETECT_TIMEOUT_MS) { |
| ERROR("EMMC: Card insert event detection timeout\n"); |
| return rval; |
| } |
| |
| VERBOSE("EMMC: Card detection delay: %dms\n", time); |
| |
| if (state) |
| mmio_setbits_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_CTRL_OFFSET, |
| SD4_EMMC_TOP_CTRL_SDPWR_MASK); |
| |
| /* dummy write & ack to verify if the sdio is ready to send commads */ |
| mmio_write_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_ARG_OFFSET, 0); |
| mmio_write_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_CMD_OFFSET, 0); |
| |
| /* |
| * 63ms observed on emulation system, As per clock calculations |
| * it will complete < 1ms on chip. |
| */ |
| time = 0; |
| do { |
| rc = mmio_read_32(handle->ctrl.sdRegBaseAddr + |
| SD4_EMMC_TOP_INTR_OFFSET); |
| |
| if (rc & SD4_EMMC_TOP_INTR_ERRIRQ_MASK) |
| break; |
| |
| if ((rc & SD4_EMMC_TOP_INTR_CMDDONE_MASK) == |
| SD4_EMMC_TOP_INTR_CMDDONE_MASK) |
| break; |
| |
| mdelay(1); |
| } while (time++ < EMMC_CMD_TIMEOUT_MS); |
| |
| if (time >= EMMC_CMD_TIMEOUT_MS) { |
| WARN("%s %d Initial dummy command timeout is happened\n", |
| __func__, __LINE__); |
| return rval; |
| } |
| |
| VERBOSE("EMMC: Dummy Command delay: %dms\n", time); |
| |
| return SD_OK; |
| } |
| |
| /* |
| * Configure DMA Boundaries |
| */ |
| static void chal_sd_set_dma_boundary(struct sd_dev *handle, uint32_t boundary) |
| { |
| if (handle == NULL) |
| return; |
| |
| mmio_clrsetbits_32(handle->ctrl.sdRegBaseAddr + |
| SD4_EMMC_TOP_BLOCK_OFFSET, |
| SD4_EMMC_TOP_BLOCK_HSBS_MASK, boundary); |
| } |
| |
| static int32_t chal_sd_setup_handler(struct sd_dev *handle, uint32_t sdBase, |
| uint32_t hostBase) |
| { |
| if (handle == NULL) |
| return SD_INVALID_HANDLE; |
| |
| handle->ctrl.sdRegBaseAddr = sdBase; |
| handle->ctrl.hostRegBaseAddr = hostBase; |
| handle->ctrl.present = 0; |
| handle->ctrl.rca = 0; |
| handle->ctrl.blkGapEnable = 0; |
| handle->ctrl.cmdStatus = 0; |
| |
| return SD_OK; |
| } |
| |
| /* |
| * Initialize SD Host controller |
| */ |
| int32_t chal_sd_init(CHAL_HANDLE *sd_handle) |
| { |
| uint32_t cap_val_l = 0; |
| uint32_t ctl_val, voltage; |
| uint32_t timeout_val; |
| struct sd_dev *handle; |
| uint32_t reg_val; |
| int32_t rval = SD_FAIL; |
| |
| if (sd_handle == NULL) |
| return SD_INVALID_HANDLE; |
| |
| handle = (struct sd_dev *)sd_handle; |
| |
| /* |
| * Set SDIO Host Controller capabilities register |
| */ |
| EMMC_TRACE("Set Host Controller Capabilities register\n"); |
| |
| reg_val = 0; |
| reg_val |= (1 << ICFG_SDIO0_CAP0__SLOT_TYPE_R); |
| reg_val |= (0 << ICFG_SDIO0_CAP0__INT_MODE_R); |
| reg_val |= (0 << ICFG_SDIO0_CAP0__SYS_BUS_64BIT_R); |
| reg_val |= (1 << ICFG_SDIO0_CAP0__VOLTAGE_1P8V_R); |
| reg_val |= (1 << ICFG_SDIO0_CAP0__VOLTAGE_3P0V_R); |
| reg_val |= (1 << ICFG_SDIO0_CAP0__VOLTAGE_3P3V_R); |
| reg_val |= (1 << ICFG_SDIO0_CAP0__SUSPEND_RESUME_R); |
| reg_val |= (1 << ICFG_SDIO0_CAP0__SDMA_R); |
| reg_val |= (1 << ICFG_SDIO0_CAP0__HIGH_SPEED_R); |
| reg_val |= (1 << ICFG_SDIO0_CAP0__ADMA2_R); |
| reg_val |= (1 << ICFG_SDIO0_CAP0__EXTENDED_MEDIA_R); |
| reg_val |= (2 << ICFG_SDIO0_CAP0__MAX_BLOCK_LEN_R); |
| reg_val |= (0xd0 << ICFG_SDIO0_CAP0__BASE_CLK_FREQ_R); |
| reg_val |= (1 << ICFG_SDIO0_CAP0__TIMEOUT_UNIT_R); |
| reg_val |= (0x30 << ICFG_SDIO0_CAP0__TIMEOUT_CLK_FREQ_R); |
| |
| mmio_write_32(ICFG_SDIO0_CAP0, reg_val); |
| |
| reg_val = 0; |
| reg_val |= (1 << ICFG_SDIO0_CAP1__SPI_BLOCK_MODE_R); |
| reg_val |= (1 << ICFG_SDIO0_CAP1__SPI_MODE_R); |
| reg_val |= (0 << ICFG_SDIO0_CAP1__CLK_MULT_R); |
| reg_val |= (0 << ICFG_SDIO0_CAP1__RETUNING_MODE_R); |
| reg_val |= (1 << ICFG_SDIO0_CAP1__TUNE_SDR50_R); |
| reg_val |= (1 << ICFG_SDIO0_CAP1__TIME_RETUNE_R); |
| reg_val |= (1 << ICFG_SDIO0_CAP1__DRIVER_D_R); |
| reg_val |= (1 << ICFG_SDIO0_CAP1__DRIVER_C_R); |
| reg_val |= (1 << ICFG_SDIO0_CAP1__DRIVER_A_R); |
| reg_val |= (1 << ICFG_SDIO0_CAP1__DDR50_R); |
| reg_val |= (1 << ICFG_SDIO0_CAP1__SDR104_R); |
| reg_val |= (1 << ICFG_SDIO0_CAP1__SDR50_R); |
| |
| mmio_write_32(ICFG_SDIO0_CAP1, reg_val); |
| |
| /* Reset the SDIO controller */ |
| chal_sd_stop(); |
| |
| /* Turn on SD clock */ |
| chal_sd_set_clock(sd_handle, |
| chal_sd_freq_2_div_ctrl_setting(INIT_CLK_FREQ), 1); |
| |
| /* program data time out value to the max */ |
| timeout_val = SD_HOST_CORE_TIMEOUT; |
| |
| ctl_val = mmio_read_32(handle->ctrl.sdRegBaseAddr + |
| SD4_EMMC_TOP_CTRL1_OFFSET); |
| ctl_val |= ((timeout_val & 0xf) << SD4_EMMC_TOP_CTRL1_DTCNT_SHIFT); |
| |
| mmio_write_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_CTRL1_OFFSET, |
| ctl_val); |
| |
| /* enable all interrupt status */ |
| mmio_write_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_INTREN1_OFFSET, |
| 0); |
| mmio_write_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_INTREN2_OFFSET, |
| 0); |
| |
| SD_US_DELAY(100); |
| |
| mmio_write_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_INTREN1_OFFSET, |
| SD_NOR_INTERRUPTS | SD_ERR_INTERRUPTS); |
| mmio_write_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_INTREN2_OFFSET, |
| SD_NOR_INTERRUPTS | SD_ERR_INTERRUPTS); |
| |
| /* Select SD bus voltage */ |
| cap_val_l = mmio_read_32(handle->ctrl.sdRegBaseAddr + |
| SD4_EMMC_TOP_CAPABILITIES1_OFFSET); |
| handle->cfg.voltage = 0; |
| voltage = 0x7; |
| |
| if (cap_val_l & SD4_EMMC_TOP_CAPABILITIES1_V33_MASK) { |
| handle->cfg.voltage |= SD_VDD_WINDOW_3_3_TO_3_4; |
| voltage = 0x7; |
| } else if (cap_val_l & SD4_EMMC_TOP_CAPABILITIES1_V3_MASK) { |
| handle->cfg.voltage |= SD_VDD_WINDOW_3_0_TO_3_1; |
| voltage = 0x6; |
| } else if (cap_val_l & SD4_EMMC_TOP_CAPABILITIES1_V18_MASK) { |
| handle->cfg.voltage |= SD_VDD_WINDOW_1_8_TO_1_9; |
| voltage = 0x5; |
| } |
| |
| rval = chal_sd_set_power(handle, voltage, SD4_EMMC_TOP_CTRL_SDPWR_MASK); |
| |
| ctl_val = mmio_read_32(handle->ctrl.sdRegBaseAddr + |
| SD4_EMMC_TOP_HCVERSIRQ_OFFSET); |
| handle->ctrl.version = ((ctl_val >> 16) & 0xFF); |
| |
| return rval; |
| } |
| |
| void chal_sd_set_speed(CHAL_HANDLE *sd_handle, uint32_t speed) |
| { |
| struct sd_dev *handle; |
| |
| if (sd_handle == NULL) |
| return; |
| |
| handle = (struct sd_dev *) sd_handle; |
| |
| if (speed) { |
| EMMC_TRACE("enable HighSpeed\n"); |
| mmio_setbits_32(handle->ctrl.sdRegBaseAddr + |
| SD4_EMMC_TOP_CTRL_OFFSET, |
| SD4_EMMC_TOP_CTRL_HSEN_MASK); |
| } else { |
| EMMC_TRACE("disable HighSpeed\n"); |
| mmio_clrbits_32(handle->ctrl.sdRegBaseAddr + |
| SD4_EMMC_TOP_CTRL_OFFSET, |
| SD4_EMMC_TOP_CTRL_HSEN_MASK); |
| } |
| } |
| |
| int32_t chal_sd_stop(void) |
| { |
| uintptr_t idm_rst_ctrl_addr = EMMC_IDM_RESET_CTRL_ADDR; |
| |
| /* Configure IO pins */ |
| emmc_soft_reset(); |
| |
| /* Reset the SDIO controller */ |
| mmio_write_32(idm_rst_ctrl_addr, 1); |
| SD_US_DELAY(100); |
| mmio_write_32(idm_rst_ctrl_addr, 0); |
| SD_US_DELAY(100); |
| |
| return SD_OK; |
| } |
| |
| /* |
| * Check if host supports specified capability |
| * returns -ve val on error, 0 if capability not supported else 1. |
| */ |
| int32_t chal_sd_check_cap(CHAL_HANDLE *sd_handle, uint32_t caps) |
| { |
| struct sd_dev *handle; |
| |
| if (sd_handle == NULL) |
| return SD_INVALID_HANDLE; |
| |
| handle = (struct sd_dev *) sd_handle; |
| |
| if (caps & mmio_read_32(handle->ctrl.sdRegBaseAddr + |
| SD4_EMMC_TOP_CAPABILITIES1_OFFSET)) |
| return 1; |
| else |
| return 0; |
| } |
| |
| int32_t chal_sd_start(CHAL_HANDLE *sd_handle, |
| uint32_t mode, uint32_t sd_base, uint32_t host_base) |
| { |
| |
| struct sd_dev *handle; |
| int32_t rval = SD_FAIL; |
| |
| if (sd_handle == NULL) |
| return SD_INVALID_HANDLE; |
| |
| handle = (struct sd_dev *) sd_handle; |
| |
| handle->cfg.mode = SD_PIO_MODE; /* set to PIO mode first for init */ |
| handle->cfg.dma = SD_DMA_OFF; |
| |
| chal_sd_setup_handler(handle, sd_base, host_base); |
| |
| /* init and start hw */ |
| rval = chal_sd_init(sd_handle); |
| if (rval != SD_OK) |
| return rval; |
| |
| chal_sd_clear_pending_irq(sd_handle); |
| |
| handle->ctrl.eventList = 0; |
| handle->cfg.mode = mode; |
| |
| return SD_OK; |
| } |
| |
| /* |
| * Function to check 8bits of err generated from auto CMD12 |
| */ |
| int32_t chal_sd_get_atuo12_error(CHAL_HANDLE *sd_handle) |
| { |
| struct sd_dev *handle; |
| |
| if (sd_handle == NULL) |
| return SD_INVALID_HANDLE; |
| |
| handle = (struct sd_dev *) sd_handle; |
| |
| return (mmio_read_32(handle->ctrl.sdRegBaseAddr + |
| SD4_EMMC_TOP_ERRSTAT_OFFSET) & 0xFF); |
| } |
| |
| /* |
| * Read present state register |
| */ |
| uint32_t chal_sd_get_present_status(CHAL_HANDLE *sd_handle) |
| { |
| struct sd_dev *handle; |
| |
| if (sd_handle == NULL) |
| return SD_INVALID_HANDLE; |
| |
| handle = (struct sd_dev *) sd_handle; |
| |
| return mmio_read_32(handle->ctrl.sdRegBaseAddr + |
| SD4_EMMC_TOP_PSTATE_OFFSET); |
| } |
| |
| /* |
| * Set SD bus width |
| */ |
| int32_t chal_sd_config_bus_width(CHAL_HANDLE *sd_handle, int32_t width) |
| { |
| uint32_t ctl_val; |
| struct sd_dev *handle; |
| |
| if (sd_handle == NULL) |
| return SD_INVALID_HANDLE; |
| |
| handle = (struct sd_dev *)sd_handle; |
| |
| ctl_val = mmio_read_32(handle->ctrl.sdRegBaseAddr + |
| SD4_EMMC_TOP_CTRL_OFFSET); |
| |
| switch (width) { |
| #ifdef DRIVER_EMMC_ENABLE_DATA_WIDTH_8BIT |
| case SD_BUS_DATA_WIDTH_8BIT: |
| ctl_val &= ~SD_BUS_DATA_WIDTH_4BIT; |
| ctl_val |= SD_BUS_DATA_WIDTH_8BIT; |
| break; |
| #endif |
| case SD_BUS_DATA_WIDTH_4BIT: |
| ctl_val &= ~SD_BUS_DATA_WIDTH_8BIT; |
| ctl_val |= SD_BUS_DATA_WIDTH_4BIT; |
| break; |
| case SD_BUS_DATA_WIDTH_1BIT: |
| ctl_val &= ~(SD_BUS_DATA_WIDTH_4BIT | SD_BUS_DATA_WIDTH_8BIT); |
| break; |
| default: |
| return SD_INV_DATA_WIDTH; |
| }; |
| |
| mmio_write_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_CTRL_OFFSET, |
| ctl_val); |
| |
| return SD_OK; |
| } |
| |
| /* |
| * Function to enable or disable DMA control. |
| */ |
| int32_t chal_sd_set_dma(CHAL_HANDLE *sd_handle, uint32_t mode) |
| { |
| uint32_t val; |
| struct sd_dev *handle; |
| int32_t rc; |
| |
| if (sd_handle == NULL) |
| return SD_INVALID_HANDLE; |
| |
| handle = (struct sd_dev *)sd_handle; |
| |
| if (mode) { |
| rc = chal_sd_check_cap(sd_handle, |
| SD4_EMMC_TOP_CAPABILITIES1_SDMA_MASK | |
| SD4_EMMC_TOP_CAPABILITIES1_ADMA2_MASK); |
| if (rc < 0) |
| return rc; |
| |
| if (rc) { |
| |
| handle->cfg.dma = mode; |
| val = mmio_read_32(handle->ctrl.sdRegBaseAddr + |
| SD4_EMMC_TOP_CTRL_OFFSET); |
| val &= ~(SD4_EMMC_TOP_CTRL_DMASEL_MASK); |
| val |= handle->cfg.dma - 1; |
| mmio_write_32(handle->ctrl.sdRegBaseAddr + |
| SD4_EMMC_TOP_CTRL_OFFSET, val); |
| return SD_OK; |
| } |
| } |
| handle->cfg.dma = 0; |
| |
| return SD_FAIL; |
| } |
| |
| /* |
| * Get current DMA address. |
| * Called only when there is no data transaction activity. |
| */ |
| uintptr_t chal_sd_get_dma_addr(CHAL_HANDLE *sd_handle) |
| { |
| struct sd_dev *handle; |
| |
| if (sd_handle == NULL) |
| return SD_INVALID_HANDLE; |
| |
| handle = (struct sd_dev *) sd_handle; |
| |
| if (handle->cfg.dma == SD_DMA_OFF) |
| return 0; |
| |
| return (uintptr_t)mmio_read_32(handle->ctrl.sdRegBaseAddr + |
| SD4_EMMC_TOP_SYSADDR_OFFSET); |
| } |
| |
| int32_t chal_sd_send_cmd(CHAL_HANDLE *sd_handle, uint32_t cmd_idx, |
| uint32_t argument, uint32_t options) |
| { |
| uint32_t cmd_mode_reg = 0; |
| struct sd_dev *handle; |
| |
| if (sd_handle == NULL) |
| return SD_INVALID_HANDLE; |
| |
| handle = (struct sd_dev *) sd_handle; |
| |
| EMMC_TRACE("%s %d cmd:%d argReg:%x options:%x\n", |
| __func__, __LINE__, cmd_idx, argument, options); |
| |
| /* Configure the value for command and mode registers */ |
| cmd_mode_reg = (cmd_idx << 24) | options; |
| |
| /* |
| * 1. Write block size reg & block count reg, |
| * this is done in the tx or rx setup |
| */ |
| mmio_write_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_BLOCK_OFFSET, |
| handle->ctrl.blkReg); |
| |
| /* 2. Write argument reg */ |
| mmio_write_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_ARG_OFFSET, |
| argument); |
| handle->ctrl.argReg = argument; |
| |
| /* |
| * 3. Write transfer mode reg & command reg, check the DMA bit which is |
| * set before this function call if it is selected. |
| */ |
| if (cmd_idx == 24 || cmd_idx == 25 || cmd_idx == 18 || cmd_idx == 17 || |
| cmd_idx == 42 || cmd_idx == 51 || cmd_idx == 53) |
| cmd_mode_reg |= ((handle->cfg.dma) ? 1 : 0); |
| |
| mmio_write_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_CMD_OFFSET, |
| cmd_mode_reg); |
| |
| handle->ctrl.cmdIndex = cmd_idx; |
| |
| return SD_OK; |
| } |
| |
| int32_t chal_sd_set_dma_addr(CHAL_HANDLE *sd_handle, uintptr_t address) |
| { |
| struct sd_dev *handle; |
| |
| if (sd_handle == NULL) |
| return SD_INVALID_HANDLE; |
| |
| handle = (struct sd_dev *) sd_handle; |
| |
| if (handle->cfg.dma == SD_DMA_OFF) |
| return SD_FAIL; |
| |
| mmio_write_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_SYSADDR_OFFSET, |
| address); |
| return SD_OK; |
| } |
| |
| uint32_t chal_sd_freq_2_div_ctrl_setting(uint32_t desired_freq) |
| { |
| /* |
| * Divider control setting represents 1/2 of the actual divider value. |
| * |
| * DesiredFreq = BaseClockFreq / (2 * div_ctrl_setting) |
| * |
| * ==> div_ctrl_setting = BaseClockFreq / (2 * DesiredFreq) |
| */ |
| uint32_t div_ctrl_setting; |
| uint32_t actual_freq; |
| |
| assert(desired_freq != 0); |
| |
| /* Special case, 0 = divider of 1. */ |
| if (desired_freq >= BASE_CLK_FREQ) |
| return 0; |
| |
| /* Normal case, desired_freq < BASE_CLK_FREQ */ |
| div_ctrl_setting = BASE_CLK_FREQ / (2 * desired_freq); |
| |
| actual_freq = BASE_CLK_FREQ / (2 * div_ctrl_setting); |
| |
| if (actual_freq > desired_freq) { |
| /* |
| * Division does not result in exact freqency match. |
| * Make sure resulting frequency does not exceed requested freq. |
| */ |
| div_ctrl_setting++; |
| } |
| |
| return div_ctrl_setting; |
| } |
| |
| int32_t chal_sd_set_clock(CHAL_HANDLE *sd_handle, uint32_t div_ctrl_setting, |
| uint32_t on) |
| { |
| uint32_t value; |
| struct sd_dev *handle; |
| uint32_t time; |
| uint32_t clk_sel_high_byte = 0xFF & (div_ctrl_setting >> 8); |
| uint32_t clk_sel_low_byte = 0xFF & div_ctrl_setting; |
| |
| if (sd_handle == NULL) |
| return SD_INVALID_HANDLE; |
| |
| EMMC_TRACE("set_clock(div_ctrl_setting=%d,on=%d)\n", |
| div_ctrl_setting, on); |
| |
| handle = (struct sd_dev *) sd_handle; |
| |
| /* Read control register content. */ |
| value = mmio_read_32(handle->ctrl.sdRegBaseAddr + |
| SD4_EMMC_TOP_CTRL1_OFFSET); |
| |
| /* Disable Clock */ |
| value &= ~(SD4_EMMC_TOP_CTRL1_SDCLKEN_MASK); |
| |
| mmio_write_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_CTRL1_OFFSET, |
| value); |
| |
| /* Clear bits of interest. */ |
| value &= ~(SD4_EMMC_TOP_CTRL1_SDCLKSEL_MASK | |
| SD4_EMMC_TOP_CTRL1_SDCLKSEL_UP_MASK); |
| |
| /* Set bits of interest to new value. */ |
| value |= (SD4_EMMC_TOP_CTRL1_SDCLKSEL_MASK & |
| (clk_sel_low_byte << SD4_EMMC_TOP_CTRL1_SDCLKSEL_SHIFT)); |
| value |= (SD4_EMMC_TOP_CTRL1_SDCLKSEL_UP_MASK & |
| (clk_sel_high_byte << SD4_EMMC_TOP_CTRL1_SDCLKSEL_UP_SHIFT)); |
| value |= SD4_EMMC_TOP_CTRL1_ICLKEN_MASK; |
| |
| /* Write updated value back to control register. */ |
| mmio_write_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_CTRL1_OFFSET, |
| value); |
| |
| time = 0; |
| do { |
| value = mmio_read_32(handle->ctrl.sdRegBaseAddr + |
| SD4_EMMC_TOP_CTRL1_OFFSET); |
| |
| if ((value & SD4_EMMC_TOP_CTRL1_ICLKSTB_MASK) == |
| SD4_EMMC_TOP_CTRL1_ICLKSTB_MASK) |
| break; |
| |
| mdelay(1); |
| } while (time++ < EMMC_CLOCK_SETTING_TIMEOUT_MS); |
| |
| if (time >= EMMC_CLOCK_SETTING_TIMEOUT_MS) |
| WARN("%s %d clock settings timeout happenedi (%dms)\n", |
| __func__, __LINE__, time); |
| |
| VERBOSE("EMMC: clock settings delay: %dms\n", time); |
| |
| value = mmio_read_32(handle->ctrl.sdRegBaseAddr + |
| SD4_EMMC_TOP_CTRL1_OFFSET); |
| |
| if (on) |
| value |= SD4_EMMC_TOP_CTRL1_SDCLKEN_MASK; |
| |
| mmio_write_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_CTRL1_OFFSET, |
| value); |
| |
| return SD_OK; |
| } |
| |
| /* |
| * function to setup DMA buffer and data length, calculates block |
| * size and the number of blocks to be transferred and return |
| * the DMA buffer address. |
| */ |
| int32_t chal_sd_setup_xfer(CHAL_HANDLE *sd_handle, |
| uint8_t *data, uint32_t length, int32_t dir) |
| { |
| uint32_t blocks = 0; |
| struct sd_dev *handle; |
| |
| if (sd_handle == NULL) |
| return SD_INVALID_HANDLE; |
| |
| handle = (struct sd_dev *) sd_handle; |
| |
| if (length <= handle->cfg.blockSize) { |
| handle->ctrl.blkReg = length | handle->cfg.dmaBoundary; |
| } else { |
| blocks = length / handle->cfg.blockSize; |
| handle->ctrl.blkReg = (blocks << 16) | handle->cfg.blockSize | |
| handle->cfg.dmaBoundary; |
| } |
| |
| if (handle->cfg.dma != SD_DMA_OFF) { |
| /* For DMA target address setting, physical address should be used */ |
| mmio_write_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_SYSADDR_OFFSET, |
| (uintptr_t)data); |
| } |
| |
| return SD_OK; |
| } |
| |
| #ifdef INCLUDE_EMMC_DRIVER_WRITE_CODE |
| /* |
| * function to write one block data directly to the |
| * host controller's FIFO which is 1K uint8_t or |
| * 2K uint8_t in size. |
| * It is used in Non-DMA mode for data transmission. |
| */ |
| int32_t chal_sd_write_buffer(CHAL_HANDLE *sd_handle, uint32_t length, |
| uint8_t *data) |
| { |
| uint32_t i, leftOver = 0, blockSize, size, value = 0; |
| struct sd_dev *handle; |
| |
| if (sd_handle == NULL) |
| return SD_INVALID_HANDLE; |
| |
| handle = (struct sd_dev *) sd_handle; |
| |
| blockSize = handle->cfg.blockSize; |
| |
| if (length == 0) |
| return SD_OK; |
| |
| /* PIO mode, push into fifo word by word */ |
| if (length >= blockSize) { |
| size = blockSize; |
| } else { |
| size = ((length >> 2) << 2); |
| leftOver = length % 4; |
| } |
| |
| for (i = 0; i < size; i += 4) { |
| value = *(uint32_t *)(data + i); |
| mmio_write_32(handle->ctrl.sdRegBaseAddr + |
| SD4_EMMC_TOP_BUFDAT_OFFSET, value); |
| } |
| /* |
| * BUG ALERT: |
| * This implementation has TWO issues that must be addressed before you |
| * can safely INCLUDE_EMMC_DRIVER_WRITE_CODE. |
| * |
| * (1) For the last leftOver bytes, driver writes full word, which means |
| * some of the eMMC content (i.e. "4 - leftOver" will be erroneously |
| * overwritten). |
| * (2) eMMC is a block device. What happens when less than a full block of |
| * data is submitted??? |
| */ |
| if (leftOver > 0) { |
| value = ((*(uint32_t *)(data + i)) << (4 - leftOver)); |
| mmio_write_32(handle->ctrl.sdRegBaseAddr + |
| SD4_EMMC_TOP_BUFDAT_OFFSET, value); |
| } |
| |
| return SD_OK; |
| } |
| #endif /* INCLUDE_EMMC_DRIVER_WRITE_CODE */ |
| |
| /* |
| * Function to read maximal one block data directly |
| * from the data port of the host controller (FIFO). It is used |
| * in Non-DMA mode for data transmission. |
| */ |
| int32_t chal_sd_read_buffer(CHAL_HANDLE *sd_handle, uint32_t length, |
| uint8_t *data) |
| { |
| uint32_t i, size, leftOver, blockSize, value; |
| struct sd_dev *handle; |
| |
| if (sd_handle == NULL) |
| return SD_INVALID_HANDLE; |
| |
| handle = (struct sd_dev *)sd_handle; |
| |
| value = 0; |
| |
| blockSize = handle->cfg.blockSize; |
| |
| /* PIO mode, extract fifo word by word */ |
| if (length >= blockSize) { |
| size = blockSize; |
| leftOver = 0; |
| } else { |
| leftOver = length % 4; |
| size = ((length >> 2) << 2); |
| } |
| |
| for (i = 0; i < size; i += 4) { |
| value = |
| mmio_read_32(handle->ctrl.sdRegBaseAddr + |
| SD4_EMMC_TOP_BUFDAT_OFFSET); |
| memcpy((void *)(data + i), &value, sizeof(uint32_t)); |
| } |
| |
| if (leftOver > 0) { |
| value = mmio_read_32(handle->ctrl.sdRegBaseAddr + |
| SD4_EMMC_TOP_BUFDAT_OFFSET); |
| |
| /* |
| * Copy remaining non-full word bytes. |
| * (We run ARM as Little Endian) |
| */ |
| uint8_t j = 0; |
| |
| for (j = 0; j < leftOver; j++) { |
| data[i + j] = (value >> (j * 8)) & 0xFF; |
| } |
| } |
| |
| return SD_OK; |
| } |
| |
| /* |
| * Resets both DAT or CMD line. |
| */ |
| int32_t chal_sd_reset_line(CHAL_HANDLE *sd_handle, uint32_t line) |
| { |
| uint32_t control, flag; |
| struct sd_dev *handle; |
| |
| if (sd_handle == NULL) |
| return SD_INVALID_HANDLE; |
| |
| handle = (struct sd_dev *) sd_handle; |
| |
| flag = SD4_EMMC_TOP_CTRL1_CMDRST_MASK | SD4_EMMC_TOP_CTRL1_DATRST_MASK; |
| |
| if (flag != (line | flag)) |
| return SD_FAIL; |
| |
| control = mmio_read_32(handle->ctrl.sdRegBaseAddr + |
| SD4_EMMC_TOP_CTRL1_OFFSET); |
| control |= line; |
| mmio_write_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_CTRL1_OFFSET, |
| control); |
| |
| /* reset CMD and DATA line should always work, no need to timed out */ |
| do { |
| control = mmio_read_32(handle->ctrl.sdRegBaseAddr + |
| SD4_EMMC_TOP_CTRL1_OFFSET); |
| } while (control & line); |
| |
| return SD_OK; |
| } |
| |
| /* |
| * Function to be called once a SD command is done to read |
| * back it's response data. |
| */ |
| int32_t chal_sd_get_response(CHAL_HANDLE *sd_handle, uint32_t *resp) |
| { |
| struct sd_dev *handle; |
| |
| if (sd_handle == NULL) |
| return SD_INVALID_HANDLE; |
| |
| handle = (struct sd_dev *) sd_handle; |
| resp[0] = mmio_read_32(handle->ctrl.sdRegBaseAddr + |
| SD4_EMMC_TOP_RESP0_OFFSET); |
| resp[1] = mmio_read_32(handle->ctrl.sdRegBaseAddr + |
| SD4_EMMC_TOP_RESP2_OFFSET); |
| resp[2] = mmio_read_32(handle->ctrl.sdRegBaseAddr + |
| SD4_EMMC_TOP_RESP4_OFFSET); |
| resp[3] = mmio_read_32(handle->ctrl.sdRegBaseAddr + |
| SD4_EMMC_TOP_RESP6_OFFSET); |
| |
| return SD_OK; |
| } |
| |
| /* |
| * The function is called to clean all the pending interrupts. |
| */ |
| int32_t chal_sd_clear_pending_irq(CHAL_HANDLE *sd_handle) |
| { |
| uint32_t status = SD_OK; |
| struct sd_dev *handle; |
| |
| if (sd_handle == NULL) |
| return SD_INVALID_HANDLE; |
| |
| handle = (struct sd_dev *)sd_handle; |
| |
| /* Make sure clean all interrupts */ |
| do { |
| mmio_write_32(handle->ctrl.sdRegBaseAddr + |
| SD4_EMMC_TOP_INTR_OFFSET, 0xFFFFFFFF); |
| SD_US_DELAY(10); |
| } while (mmio_read_32(handle->ctrl.sdRegBaseAddr + |
| SD4_EMMC_TOP_INTR_OFFSET)); |
| |
| return status; |
| } |
| |
| /* |
| * The function returns interrupt status register value. |
| */ |
| int32_t chal_sd_get_irq_status(CHAL_HANDLE *sd_handle) |
| { |
| struct sd_dev *handle; |
| |
| if (sd_handle == NULL) |
| return SD_INVALID_HANDLE; |
| |
| handle = (struct sd_dev *) sd_handle; |
| |
| return (mmio_read_32(handle->ctrl.sdRegBaseAddr + |
| SD4_EMMC_TOP_INTR_OFFSET)); |
| } |
| |
| /* |
| * The function clears interrupt(s) specified in the mask. |
| */ |
| int32_t chal_sd_clear_irq(CHAL_HANDLE *sd_handle, uint32_t mask) |
| { |
| struct sd_dev *handle; |
| |
| if (sd_handle == NULL) |
| return SD_INVALID_HANDLE; |
| |
| handle = (struct sd_dev *) sd_handle; |
| |
| /* Make sure clean masked interrupts */ |
| do { |
| mmio_write_32(handle->ctrl.sdRegBaseAddr + |
| SD4_EMMC_TOP_INTR_OFFSET, mask); |
| SD_US_DELAY(10); |
| } while (mask & |
| mmio_read_32(handle->ctrl.sdRegBaseAddr + |
| SD4_EMMC_TOP_INTR_OFFSET)); |
| |
| return SD_OK; |
| } |
| |
| /* |
| * Description: The function configures the SD host controller. |
| */ |
| int32_t chal_sd_config(CHAL_HANDLE *sd_handle, uint32_t speed, uint32_t retry, |
| uint32_t boundary, uint32_t blkSize, uint32_t dma) |
| { |
| struct sd_dev *handle; |
| |
| if (sd_handle == NULL) |
| return SD_INVALID_HANDLE; |
| |
| handle = (struct sd_dev *) sd_handle; |
| |
| handle->cfg.speedMode = speed; |
| handle->cfg.retryLimit = retry; |
| handle->cfg.dmaBoundary = boundary; |
| handle->cfg.blockSize = blkSize; |
| |
| chal_sd_set_dma(sd_handle, dma); |
| SD_US_DELAY(100); |
| chal_sd_set_dma_boundary(handle, boundary); |
| SD_US_DELAY(100); |
| |
| chal_sd_set_speed(sd_handle, speed); |
| |
| SD_US_DELAY(100); |
| return SD_OK; |
| } |
| |
| /* |
| * Cleans up HC FIFO. |
| */ |
| void chal_sd_dump_fifo(CHAL_HANDLE *sd_handle) |
| { |
| struct sd_dev *handle; |
| |
| if (sd_handle == NULL) |
| return; |
| |
| handle = (struct sd_dev *)sd_handle; |
| |
| /* in case there still data in the host buffer */ |
| while (mmio_read_32(handle->ctrl.sdRegBaseAddr + |
| SD4_EMMC_TOP_PSTATE_OFFSET) & 0x800) { |
| mmio_read_32(handle->ctrl.sdRegBaseAddr + |
| SD4_EMMC_TOP_BUFDAT_OFFSET); |
| }; |
| } |
| |
| /* |
| * Enable or disable a SD interrupt signal. |
| */ |
| void chal_sd_set_irq_signal(CHAL_HANDLE *sd_handle, uint32_t mask, |
| uint32_t state) |
| { |
| struct sd_dev *handle; |
| |
| if (sd_handle == NULL) |
| return; |
| |
| handle = (struct sd_dev *)sd_handle; |
| |
| if (state) |
| mmio_setbits_32(handle->ctrl.sdRegBaseAddr + |
| SD4_EMMC_TOP_INTREN2_OFFSET, mask); |
| else |
| mmio_clrbits_32(handle->ctrl.sdRegBaseAddr + |
| SD4_EMMC_TOP_INTREN2_OFFSET, mask); |
| } |