1*ddaf02d1SJit Loon Lim /* 2*ddaf02d1SJit Loon Lim * Copyright (c) 2022-2023, Intel Corporation. All rights reserved. 3*ddaf02d1SJit Loon Lim * 4*ddaf02d1SJit Loon Lim * SPDX-License-Identifier: BSD-3-Clause 5*ddaf02d1SJit Loon Lim */ 6*ddaf02d1SJit Loon Lim 7*ddaf02d1SJit Loon Lim #include <assert.h> 8*ddaf02d1SJit Loon Lim #include <errno.h> 9*ddaf02d1SJit Loon Lim #include <stdbool.h> 10*ddaf02d1SJit Loon Lim #include <stddef.h> 11*ddaf02d1SJit Loon Lim #include <string.h> 12*ddaf02d1SJit Loon Lim 13*ddaf02d1SJit Loon Lim #include <arch_helpers.h> 14*ddaf02d1SJit Loon Lim #include <common/debug.h> 15*ddaf02d1SJit Loon Lim #include <drivers/cadence/cdns_sdmmc.h> 16*ddaf02d1SJit Loon Lim #include <drivers/delay_timer.h> 17*ddaf02d1SJit Loon Lim #include <drivers/mmc.h> 18*ddaf02d1SJit Loon Lim #include <lib/mmio.h> 19*ddaf02d1SJit Loon Lim #include <lib/utils.h> 20*ddaf02d1SJit Loon Lim 21*ddaf02d1SJit Loon Lim /* Card busy and present */ 22*ddaf02d1SJit Loon Lim #define CARD_BUSY 1 23*ddaf02d1SJit Loon Lim #define CARD_NOT_BUSY 0 24*ddaf02d1SJit Loon Lim 25*ddaf02d1SJit Loon Lim /* 500 ms delay to read the RINST register */ 26*ddaf02d1SJit Loon Lim #define DELAY_MS_SRS_READ 500 27*ddaf02d1SJit Loon Lim #define DELAY_RES 10 28*ddaf02d1SJit Loon Lim 29*ddaf02d1SJit Loon Lim /* SRS12 error mask */ 30*ddaf02d1SJit Loon Lim #define SRS12_ERR_MASK 0xFFFF8000 31*ddaf02d1SJit Loon Lim 32*ddaf02d1SJit Loon Lim /* Check DV dfi_init val=0 */ 33*ddaf02d1SJit Loon Lim #define IO_MASK_END_DATA 0x0 34*ddaf02d1SJit Loon Lim 35*ddaf02d1SJit Loon Lim /* Check DV dfi_init val=2; DDR Mode */ 36*ddaf02d1SJit Loon Lim #define IO_MASK_END_DATA_DDR 0x2 37*ddaf02d1SJit Loon Lim #define IO_MASK_START_DATA 0x0 38*ddaf02d1SJit Loon Lim #define DATA_SELECT_OE_END_DATA 0x1 39*ddaf02d1SJit Loon Lim 40*ddaf02d1SJit Loon Lim #define TIMEOUT 100000 41*ddaf02d1SJit Loon Lim 42*ddaf02d1SJit Loon Lim /* General define */ 43*ddaf02d1SJit Loon Lim #define SDHC_REG_MASK UINT_MAX 44*ddaf02d1SJit Loon Lim #define SD_HOST_BLOCK_SIZE 0x200 45*ddaf02d1SJit Loon Lim #define DTCVVAL_DEFAULT_VAL 0xE 46*ddaf02d1SJit Loon Lim #define CDMMC_DMA_MAX_BUFFER_SIZE 64*1024 47*ddaf02d1SJit Loon Lim #define CDNSMMC_ADDRESS_MASK U(0x0f) 48*ddaf02d1SJit Loon Lim #define CONFIG_CDNS_DESC_COUNT 8 49*ddaf02d1SJit Loon Lim 50*ddaf02d1SJit Loon Lim void cdns_init(void); 51*ddaf02d1SJit Loon Lim int cdns_send_cmd(struct mmc_cmd *cmd); 52*ddaf02d1SJit Loon Lim int cdns_set_ios(unsigned int clk, unsigned int width); 53*ddaf02d1SJit Loon Lim int cdns_prepare(int lba, uintptr_t buf, size_t size); 54*ddaf02d1SJit Loon Lim int cdns_read(int lba, uintptr_t buf, size_t size); 55*ddaf02d1SJit Loon Lim int cdns_write(int lba, uintptr_t buf, size_t size); 56*ddaf02d1SJit Loon Lim 57*ddaf02d1SJit Loon Lim const struct mmc_ops cdns_sdmmc_ops = { 58*ddaf02d1SJit Loon Lim .init = cdns_init, 59*ddaf02d1SJit Loon Lim .send_cmd = cdns_send_cmd, 60*ddaf02d1SJit Loon Lim .set_ios = cdns_set_ios, 61*ddaf02d1SJit Loon Lim .prepare = cdns_prepare, 62*ddaf02d1SJit Loon Lim .read = cdns_read, 63*ddaf02d1SJit Loon Lim .write = cdns_write, 64*ddaf02d1SJit Loon Lim }; 65*ddaf02d1SJit Loon Lim 66*ddaf02d1SJit Loon Lim struct cdns_sdmmc_params cdns_params; 67*ddaf02d1SJit Loon Lim struct cdns_sdmmc_combo_phy sdmmc_combo_phy_reg; 68*ddaf02d1SJit Loon Lim struct cdns_sdmmc_sdhc sdmmc_sdhc_reg; 69*ddaf02d1SJit Loon Lim #ifdef CONFIG_DMA_ADDR_T_64BIT 70*ddaf02d1SJit Loon Lim struct cdns_idmac_desc cdns_desc[CONFIG_CDNS_DESC_COUNT]; 71*ddaf02d1SJit Loon Lim #else 72*ddaf02d1SJit Loon Lim struct cdns_idmac_desc cdns_desc[CONFIG_CDNS_DESC_COUNT] __aligned(32); 73*ddaf02d1SJit Loon Lim #endif 74*ddaf02d1SJit Loon Lim 75*ddaf02d1SJit Loon Lim bool data_cmd; 76*ddaf02d1SJit Loon Lim 77*ddaf02d1SJit Loon Lim int cdns_wait_ics(uint16_t timeout, uint32_t cdn_srs_res) 78*ddaf02d1SJit Loon Lim { 79*ddaf02d1SJit Loon Lim /* Clock for sdmclk and sdclk */ 80*ddaf02d1SJit Loon Lim uint32_t count = 0; 81*ddaf02d1SJit Loon Lim uint32_t data = 0; 82*ddaf02d1SJit Loon Lim 83*ddaf02d1SJit Loon Lim /* Wait status command response ready */ 84*ddaf02d1SJit Loon Lim do { 85*ddaf02d1SJit Loon Lim data = mmio_read_32(cdn_srs_res); 86*ddaf02d1SJit Loon Lim count++; 87*ddaf02d1SJit Loon Lim if (count >= timeout) { 88*ddaf02d1SJit Loon Lim return -ETIMEDOUT; 89*ddaf02d1SJit Loon Lim } 90*ddaf02d1SJit Loon Lim } while ((data & (1 << SDMMC_CDN_ICS)) == 0); 91*ddaf02d1SJit Loon Lim 92*ddaf02d1SJit Loon Lim return 0; 93*ddaf02d1SJit Loon Lim } 94*ddaf02d1SJit Loon Lim 95*ddaf02d1SJit Loon Lim int cdns_busy(void) 96*ddaf02d1SJit Loon Lim { 97*ddaf02d1SJit Loon Lim unsigned int data; 98*ddaf02d1SJit Loon Lim 99*ddaf02d1SJit Loon Lim data = mmio_read_32(MMC_REG_BASE + SDHC_CDNS_SRS09); 100*ddaf02d1SJit Loon Lim return (data & STATUS_DATA_BUSY) ? CARD_BUSY : CARD_NOT_BUSY; 101*ddaf02d1SJit Loon Lim } 102*ddaf02d1SJit Loon Lim 103*ddaf02d1SJit Loon Lim int cdns_vol_reset(void) 104*ddaf02d1SJit Loon Lim { 105*ddaf02d1SJit Loon Lim /* Reset embedded card */ 106*ddaf02d1SJit Loon Lim mmio_write_32((MMC_REG_BASE + SDHC_CDNS_SRS10), (7 << SDMMC_CDN_BVS) | (1 << SDMMC_CDN_BP)); 107*ddaf02d1SJit Loon Lim udelay(250); 108*ddaf02d1SJit Loon Lim mmio_write_32((MMC_REG_BASE + SDHC_CDNS_SRS10), (7 << SDMMC_CDN_BVS) | (0 << SDMMC_CDN_BP)); 109*ddaf02d1SJit Loon Lim udelay(500); 110*ddaf02d1SJit Loon Lim 111*ddaf02d1SJit Loon Lim /* Turn on supply voltage */ 112*ddaf02d1SJit Loon Lim /* BVS = 7, BP = 1, BP2 only in UHS2 mode */ 113*ddaf02d1SJit Loon Lim mmio_write_32((MMC_REG_BASE + SDHC_CDNS_SRS10), (7 << SDMMC_CDN_BVS) | (1 << SDMMC_CDN_BP)); 114*ddaf02d1SJit Loon Lim udelay(250); 115*ddaf02d1SJit Loon Lim return 0; 116*ddaf02d1SJit Loon Lim } 117*ddaf02d1SJit Loon Lim 118*ddaf02d1SJit Loon Lim void cdns_set_sdmmc_var(struct cdns_sdmmc_combo_phy *combo_phy_reg, 119*ddaf02d1SJit Loon Lim struct cdns_sdmmc_sdhc *sdhc_reg) 120*ddaf02d1SJit Loon Lim { 121*ddaf02d1SJit Loon Lim /* Values are taken by the reference of cadence IP documents */ 122*ddaf02d1SJit Loon Lim combo_phy_reg->cp_clk_wr_delay = 0; 123*ddaf02d1SJit Loon Lim combo_phy_reg->cp_clk_wrdqs_delay = 0; 124*ddaf02d1SJit Loon Lim combo_phy_reg->cp_data_select_oe_end = 0; 125*ddaf02d1SJit Loon Lim combo_phy_reg->cp_dll_bypass_mode = 1; 126*ddaf02d1SJit Loon Lim combo_phy_reg->cp_dll_locked_mode = 0; 127*ddaf02d1SJit Loon Lim combo_phy_reg->cp_dll_start_point = 0; 128*ddaf02d1SJit Loon Lim combo_phy_reg->cp_gate_cfg_always_on = 1; 129*ddaf02d1SJit Loon Lim combo_phy_reg->cp_io_mask_always_on = 0; 130*ddaf02d1SJit Loon Lim combo_phy_reg->cp_io_mask_end = 0; 131*ddaf02d1SJit Loon Lim combo_phy_reg->cp_io_mask_start = 0; 132*ddaf02d1SJit Loon Lim combo_phy_reg->cp_rd_del_sel = 52; 133*ddaf02d1SJit Loon Lim combo_phy_reg->cp_read_dqs_cmd_delay = 0; 134*ddaf02d1SJit Loon Lim combo_phy_reg->cp_read_dqs_delay = 0; 135*ddaf02d1SJit Loon Lim combo_phy_reg->cp_sw_half_cycle_shift = 0; 136*ddaf02d1SJit Loon Lim combo_phy_reg->cp_sync_method = 1; 137*ddaf02d1SJit Loon Lim combo_phy_reg->cp_underrun_suppress = 1; 138*ddaf02d1SJit Loon Lim combo_phy_reg->cp_use_ext_lpbk_dqs = 1; 139*ddaf02d1SJit Loon Lim combo_phy_reg->cp_use_lpbk_dqs = 1; 140*ddaf02d1SJit Loon Lim combo_phy_reg->cp_use_phony_dqs = 1; 141*ddaf02d1SJit Loon Lim combo_phy_reg->cp_use_phony_dqs_cmd = 1; 142*ddaf02d1SJit Loon Lim 143*ddaf02d1SJit Loon Lim sdhc_reg->sdhc_extended_rd_mode = 1; 144*ddaf02d1SJit Loon Lim sdhc_reg->sdhc_extended_wr_mode = 1; 145*ddaf02d1SJit Loon Lim sdhc_reg->sdhc_hcsdclkadj = 0; 146*ddaf02d1SJit Loon Lim sdhc_reg->sdhc_idelay_val = 0; 147*ddaf02d1SJit Loon Lim sdhc_reg->sdhc_rdcmd_en = 1; 148*ddaf02d1SJit Loon Lim sdhc_reg->sdhc_rddata_en = 1; 149*ddaf02d1SJit Loon Lim sdhc_reg->sdhc_rw_compensate = 9; 150*ddaf02d1SJit Loon Lim sdhc_reg->sdhc_sdcfsh = 0; 151*ddaf02d1SJit Loon Lim sdhc_reg->sdhc_sdcfsl = 1; 152*ddaf02d1SJit Loon Lim sdhc_reg->sdhc_wrcmd0_dly = 1; 153*ddaf02d1SJit Loon Lim sdhc_reg->sdhc_wrcmd0_sdclk_dly = 0; 154*ddaf02d1SJit Loon Lim sdhc_reg->sdhc_wrcmd1_dly = 0; 155*ddaf02d1SJit Loon Lim sdhc_reg->sdhc_wrcmd1_sdclk_dly = 0; 156*ddaf02d1SJit Loon Lim sdhc_reg->sdhc_wrdata0_dly = 1; 157*ddaf02d1SJit Loon Lim sdhc_reg->sdhc_wrdata0_sdclk_dly = 0; 158*ddaf02d1SJit Loon Lim sdhc_reg->sdhc_wrdata1_dly = 0; 159*ddaf02d1SJit Loon Lim sdhc_reg->sdhc_wrdata1_sdclk_dly = 0; 160*ddaf02d1SJit Loon Lim } 161*ddaf02d1SJit Loon Lim 162*ddaf02d1SJit Loon Lim static int cdns_program_phy_reg(struct cdns_sdmmc_combo_phy *combo_phy_reg, 163*ddaf02d1SJit Loon Lim struct cdns_sdmmc_sdhc *sdhc_reg) 164*ddaf02d1SJit Loon Lim { 165*ddaf02d1SJit Loon Lim uint32_t value = 0; 166*ddaf02d1SJit Loon Lim int ret = 0; 167*ddaf02d1SJit Loon Lim 168*ddaf02d1SJit Loon Lim /* program PHY_DQS_TIMING_REG */ 169*ddaf02d1SJit Loon Lim value = (CP_USE_EXT_LPBK_DQS(combo_phy_reg->cp_use_ext_lpbk_dqs)) | 170*ddaf02d1SJit Loon Lim (CP_USE_LPBK_DQS(combo_phy_reg->cp_use_lpbk_dqs)) | 171*ddaf02d1SJit Loon Lim (CP_USE_PHONY_DQS(combo_phy_reg->cp_use_phony_dqs)) | 172*ddaf02d1SJit Loon Lim (CP_USE_PHONY_DQS_CMD(combo_phy_reg->cp_use_phony_dqs_cmd)); 173*ddaf02d1SJit Loon Lim ret = cdns_sdmmc_write_phy_reg(MMC_REG_BASE + SDHC_CDNS_HRS04, 174*ddaf02d1SJit Loon Lim COMBO_PHY_REG + PHY_DQS_TIMING_REG, MMC_REG_BASE + 175*ddaf02d1SJit Loon Lim SDHC_CDNS_HRS05, value); 176*ddaf02d1SJit Loon Lim if (ret != 0) { 177*ddaf02d1SJit Loon Lim return ret; 178*ddaf02d1SJit Loon Lim } 179*ddaf02d1SJit Loon Lim 180*ddaf02d1SJit Loon Lim /* program PHY_GATE_LPBK_CTRL_REG */ 181*ddaf02d1SJit Loon Lim value = (CP_SYNC_METHOD(combo_phy_reg->cp_sync_method)) | 182*ddaf02d1SJit Loon Lim (CP_SW_HALF_CYCLE_SHIFT(combo_phy_reg->cp_sw_half_cycle_shift)) | 183*ddaf02d1SJit Loon Lim (CP_RD_DEL_SEL(combo_phy_reg->cp_rd_del_sel)) | 184*ddaf02d1SJit Loon Lim (CP_UNDERRUN_SUPPRESS(combo_phy_reg->cp_underrun_suppress)) | 185*ddaf02d1SJit Loon Lim (CP_GATE_CFG_ALWAYS_ON(combo_phy_reg->cp_gate_cfg_always_on)); 186*ddaf02d1SJit Loon Lim ret = cdns_sdmmc_write_phy_reg(MMC_REG_BASE + SDHC_CDNS_HRS04, 187*ddaf02d1SJit Loon Lim COMBO_PHY_REG + PHY_GATE_LPBK_CTRL_REG, MMC_REG_BASE + 188*ddaf02d1SJit Loon Lim SDHC_CDNS_HRS05, value); 189*ddaf02d1SJit Loon Lim if (ret != 0) { 190*ddaf02d1SJit Loon Lim return ret; 191*ddaf02d1SJit Loon Lim } 192*ddaf02d1SJit Loon Lim 193*ddaf02d1SJit Loon Lim /* program PHY_DLL_MASTER_CTRL_REG */ 194*ddaf02d1SJit Loon Lim value = (CP_DLL_BYPASS_MODE(combo_phy_reg->cp_dll_bypass_mode)) 195*ddaf02d1SJit Loon Lim | (CP_DLL_START_POINT(combo_phy_reg->cp_dll_start_point)); 196*ddaf02d1SJit Loon Lim ret = cdns_sdmmc_write_phy_reg(MMC_REG_BASE + SDHC_CDNS_HRS04, 197*ddaf02d1SJit Loon Lim COMBO_PHY_REG + PHY_DLL_MASTER_CTRL_REG, MMC_REG_BASE 198*ddaf02d1SJit Loon Lim + SDHC_CDNS_HRS05, value); 199*ddaf02d1SJit Loon Lim if (ret != 0) { 200*ddaf02d1SJit Loon Lim return ret; 201*ddaf02d1SJit Loon Lim } 202*ddaf02d1SJit Loon Lim 203*ddaf02d1SJit Loon Lim /* program PHY_DLL_SLAVE_CTRL_REG */ 204*ddaf02d1SJit Loon Lim value = (CP_READ_DQS_CMD_DELAY(combo_phy_reg->cp_read_dqs_cmd_delay)) 205*ddaf02d1SJit Loon Lim | (CP_CLK_WRDQS_DELAY(combo_phy_reg->cp_clk_wrdqs_delay)) 206*ddaf02d1SJit Loon Lim | (CP_CLK_WR_DELAY(combo_phy_reg->cp_clk_wr_delay)) 207*ddaf02d1SJit Loon Lim | (CP_READ_DQS_DELAY(combo_phy_reg->cp_read_dqs_delay)); 208*ddaf02d1SJit Loon Lim ret = cdns_sdmmc_write_phy_reg(MMC_REG_BASE + SDHC_CDNS_HRS04, 209*ddaf02d1SJit Loon Lim COMBO_PHY_REG + PHY_DLL_SLAVE_CTRL_REG, MMC_REG_BASE 210*ddaf02d1SJit Loon Lim + SDHC_CDNS_HRS05, value); 211*ddaf02d1SJit Loon Lim if (ret != 0) { 212*ddaf02d1SJit Loon Lim return ret; 213*ddaf02d1SJit Loon Lim } 214*ddaf02d1SJit Loon Lim 215*ddaf02d1SJit Loon Lim /* program PHY_CTRL_REG */ 216*ddaf02d1SJit Loon Lim mmio_write_32(MMC_REG_BASE + SDHC_CDNS_HRS04, COMBO_PHY_REG 217*ddaf02d1SJit Loon Lim + PHY_CTRL_REG); 218*ddaf02d1SJit Loon Lim value = mmio_read_32(MMC_REG_BASE + SDHC_CDNS_HRS05); 219*ddaf02d1SJit Loon Lim 220*ddaf02d1SJit Loon Lim /* phony_dqs_timing=0 */ 221*ddaf02d1SJit Loon Lim value &= ~(CP_PHONY_DQS_TIMING_MASK << CP_PHONY_DQS_TIMING_SHIFT); 222*ddaf02d1SJit Loon Lim mmio_write_32(MMC_REG_BASE + SDHC_CDNS_HRS05, value); 223*ddaf02d1SJit Loon Lim 224*ddaf02d1SJit Loon Lim /* switch off DLL_RESET */ 225*ddaf02d1SJit Loon Lim do { 226*ddaf02d1SJit Loon Lim value = mmio_read_32(MMC_REG_BASE + SDHC_CDNS_HRS09); 227*ddaf02d1SJit Loon Lim value |= SDHC_PHY_SW_RESET; 228*ddaf02d1SJit Loon Lim mmio_write_32(MMC_REG_BASE + SDHC_CDNS_HRS09, value); 229*ddaf02d1SJit Loon Lim value = mmio_read_32(MMC_REG_BASE + SDHC_CDNS_HRS09); 230*ddaf02d1SJit Loon Lim /* polling PHY_INIT_COMPLETE */ 231*ddaf02d1SJit Loon Lim } while ((value & SDHC_PHY_INIT_COMPLETE) != SDHC_PHY_INIT_COMPLETE); 232*ddaf02d1SJit Loon Lim 233*ddaf02d1SJit Loon Lim /* program PHY_DQ_TIMING_REG */ 234*ddaf02d1SJit Loon Lim combo_phy_reg->cp_io_mask_end = 0U; 235*ddaf02d1SJit Loon Lim value = (CP_IO_MASK_ALWAYS_ON(combo_phy_reg->cp_io_mask_always_on)) 236*ddaf02d1SJit Loon Lim | (CP_IO_MASK_END(combo_phy_reg->cp_io_mask_end)) 237*ddaf02d1SJit Loon Lim | (CP_IO_MASK_START(combo_phy_reg->cp_io_mask_start)) 238*ddaf02d1SJit Loon Lim | (CP_DATA_SELECT_OE_END(combo_phy_reg->cp_data_select_oe_end)); 239*ddaf02d1SJit Loon Lim 240*ddaf02d1SJit Loon Lim ret = cdns_sdmmc_write_phy_reg(MMC_REG_BASE + SDHC_CDNS_HRS04, 241*ddaf02d1SJit Loon Lim COMBO_PHY_REG + PHY_DQ_TIMING_REG, MMC_REG_BASE 242*ddaf02d1SJit Loon Lim + SDHC_CDNS_HRS05, value); 243*ddaf02d1SJit Loon Lim if (ret != 0) { 244*ddaf02d1SJit Loon Lim return ret; 245*ddaf02d1SJit Loon Lim } 246*ddaf02d1SJit Loon Lim return 0; 247*ddaf02d1SJit Loon Lim } 248*ddaf02d1SJit Loon Lim 249*ddaf02d1SJit Loon Lim int cdns_read(int lba, uintptr_t buf, size_t size) 250*ddaf02d1SJit Loon Lim { 251*ddaf02d1SJit Loon Lim inv_dcache_range(buf, size); 252*ddaf02d1SJit Loon Lim 253*ddaf02d1SJit Loon Lim return 0; 254*ddaf02d1SJit Loon Lim } 255*ddaf02d1SJit Loon Lim 256*ddaf02d1SJit Loon Lim void cdns_init(void) 257*ddaf02d1SJit Loon Lim { 258*ddaf02d1SJit Loon Lim /* Dummy function pointer for cdns_init. */ 259*ddaf02d1SJit Loon Lim } 260*ddaf02d1SJit Loon Lim 261*ddaf02d1SJit Loon Lim int cdns_prepare(int dma_start_addr, uintptr_t dma_buff, size_t size) 262*ddaf02d1SJit Loon Lim { 263*ddaf02d1SJit Loon Lim data_cmd = true; 264*ddaf02d1SJit Loon Lim struct cdns_idmac_desc *desc; 265*ddaf02d1SJit Loon Lim uint32_t desc_cnt, i; 266*ddaf02d1SJit Loon Lim uint64_t desc_base; 267*ddaf02d1SJit Loon Lim 268*ddaf02d1SJit Loon Lim assert(((dma_buff & CDNSMMC_ADDRESS_MASK) == 0) && 269*ddaf02d1SJit Loon Lim (cdns_params.desc_size > 0) && 270*ddaf02d1SJit Loon Lim ((MMC_REG_BASE & MMC_BLOCK_MASK) == 0) && 271*ddaf02d1SJit Loon Lim ((cdns_params.desc_base & MMC_BLOCK_MASK) == 0) && 272*ddaf02d1SJit Loon Lim ((cdns_params.desc_size & MMC_BLOCK_MASK) == 0)); 273*ddaf02d1SJit Loon Lim 274*ddaf02d1SJit Loon Lim flush_dcache_range(dma_buff, size); 275*ddaf02d1SJit Loon Lim 276*ddaf02d1SJit Loon Lim desc_cnt = (size + (CDMMC_DMA_MAX_BUFFER_SIZE) - 1) / (CDMMC_DMA_MAX_BUFFER_SIZE); 277*ddaf02d1SJit Loon Lim assert(desc_cnt * sizeof(struct cdns_idmac_desc) < cdns_params.desc_size); 278*ddaf02d1SJit Loon Lim 279*ddaf02d1SJit Loon Lim if (desc_cnt > CONFIG_CDNS_DESC_COUNT) { 280*ddaf02d1SJit Loon Lim ERROR("Requested data transfer length %ld is greater than configured length %d", 281*ddaf02d1SJit Loon Lim size, (CONFIG_CDNS_DESC_COUNT * CDMMC_DMA_MAX_BUFFER_SIZE)); 282*ddaf02d1SJit Loon Lim return -EINVAL; 283*ddaf02d1SJit Loon Lim } 284*ddaf02d1SJit Loon Lim 285*ddaf02d1SJit Loon Lim desc = (struct cdns_idmac_desc *)cdns_params.desc_base; 286*ddaf02d1SJit Loon Lim desc_base = (uint64_t)desc; 287*ddaf02d1SJit Loon Lim i = 0; 288*ddaf02d1SJit Loon Lim 289*ddaf02d1SJit Loon Lim while ((i + 1) < desc_cnt) { 290*ddaf02d1SJit Loon Lim desc->attr = ADMA_DESC_ATTR_VALID | ADMA_DESC_TRANSFER_DATA; 291*ddaf02d1SJit Loon Lim desc->reserved = 0; 292*ddaf02d1SJit Loon Lim desc->len = MAX_64KB_PAGE; 293*ddaf02d1SJit Loon Lim desc->addr_lo = (dma_buff & UINT_MAX) + (CDMMC_DMA_MAX_BUFFER_SIZE * i); 294*ddaf02d1SJit Loon Lim #if CONFIG_DMA_ADDR_T_64BIT == 1 295*ddaf02d1SJit Loon Lim desc->addr_hi = (dma_buff >> 32) & 0xffffffff; 296*ddaf02d1SJit Loon Lim #endif 297*ddaf02d1SJit Loon Lim size -= CDMMC_DMA_MAX_BUFFER_SIZE; 298*ddaf02d1SJit Loon Lim desc++; 299*ddaf02d1SJit Loon Lim i++; 300*ddaf02d1SJit Loon Lim } 301*ddaf02d1SJit Loon Lim 302*ddaf02d1SJit Loon Lim desc->attr = ADMA_DESC_ATTR_VALID | ADMA_DESC_TRANSFER_DATA | 303*ddaf02d1SJit Loon Lim ADMA_DESC_ATTR_END; 304*ddaf02d1SJit Loon Lim desc->reserved = 0; 305*ddaf02d1SJit Loon Lim desc->len = size; 306*ddaf02d1SJit Loon Lim #if CONFIG_DMA_ADDR_T_64BIT == 1 307*ddaf02d1SJit Loon Lim desc->addr_lo = (dma_buff & UINT_MAX) + (CDMMC_DMA_MAX_BUFFER_SIZE * i); 308*ddaf02d1SJit Loon Lim desc->addr_hi = (dma_buff >> 32) & UINT_MAX; 309*ddaf02d1SJit Loon Lim #else 310*ddaf02d1SJit Loon Lim desc->addr_lo = (dma_buff & UINT_MAX); 311*ddaf02d1SJit Loon Lim #endif 312*ddaf02d1SJit Loon Lim 313*ddaf02d1SJit Loon Lim mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS22, (uint32_t)desc_base); 314*ddaf02d1SJit Loon Lim mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS23, (uint32_t)(desc_base >> 32)); 315*ddaf02d1SJit Loon Lim flush_dcache_range(cdns_params.desc_base, 316*ddaf02d1SJit Loon Lim desc_cnt * CDMMC_DMA_MAX_BUFFER_SIZE); 317*ddaf02d1SJit Loon Lim 318*ddaf02d1SJit Loon Lim mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS01, 319*ddaf02d1SJit Loon Lim ((512 << BLOCK_SIZE) | ((size/512) << BLK_COUNT_CT) | SDMA_BUF)); 320*ddaf02d1SJit Loon Lim return 0; 321*ddaf02d1SJit Loon Lim } 322*ddaf02d1SJit Loon Lim 323*ddaf02d1SJit Loon Lim static void cdns_host_set_clk(int clk) 324*ddaf02d1SJit Loon Lim { 325*ddaf02d1SJit Loon Lim uint32_t ret = 0; 326*ddaf02d1SJit Loon Lim uint32_t sdclkfsval = 0; 327*ddaf02d1SJit Loon Lim uint32_t dtcvval = DTCVVAL_DEFAULT_VAL; 328*ddaf02d1SJit Loon Lim 329*ddaf02d1SJit Loon Lim sdclkfsval = (cdns_params.clk_rate / 2000) / clk; 330*ddaf02d1SJit Loon Lim mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS11, 0); 331*ddaf02d1SJit Loon Lim mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS11, (dtcvval << SDMMC_CDN_DTCV) | 332*ddaf02d1SJit Loon Lim (sdclkfsval << SDMMC_CDN_SDCLKFS) | (1 << SDMMC_CDN_ICE)); 333*ddaf02d1SJit Loon Lim 334*ddaf02d1SJit Loon Lim ret = cdns_wait_ics(5000, MMC_REG_BASE + SDHC_CDNS_SRS11); 335*ddaf02d1SJit Loon Lim if (ret != 0U) { 336*ddaf02d1SJit Loon Lim ERROR("Waiting SDMMC_CDN_ICS timeout"); 337*ddaf02d1SJit Loon Lim } 338*ddaf02d1SJit Loon Lim 339*ddaf02d1SJit Loon Lim /* Enable DLL reset */ 340*ddaf02d1SJit Loon Lim mmio_write_32(MMC_REG_BASE + SDHC_CDNS_HRS09, mmio_read_32(MMC_REG_BASE + SDHC_CDNS_HRS09) & 341*ddaf02d1SJit Loon Lim ~SDHC_DLL_RESET_MASK); 342*ddaf02d1SJit Loon Lim /* Set extended_wr_mode */ 343*ddaf02d1SJit Loon Lim mmio_write_32(MMC_REG_BASE + SDHC_CDNS_HRS09, (mmio_read_32(MMC_REG_BASE + SDHC_CDNS_HRS09) 344*ddaf02d1SJit Loon Lim & SDHC_EXTENDED_WR_MODE_MASK) | (1 << EXTENDED_WR_MODE)); 345*ddaf02d1SJit Loon Lim /* Release DLL reset */ 346*ddaf02d1SJit Loon Lim mmio_write_32(MMC_REG_BASE + SDHC_CDNS_HRS09, mmio_read_32(MMC_REG_BASE 347*ddaf02d1SJit Loon Lim + SDHC_CDNS_HRS09) | 1); 348*ddaf02d1SJit Loon Lim mmio_write_32(MMC_REG_BASE + SDHC_CDNS_HRS09, mmio_read_32(MMC_REG_BASE 349*ddaf02d1SJit Loon Lim + SDHC_CDNS_HRS09) | (3 << RDCMD_EN)); 350*ddaf02d1SJit Loon Lim 351*ddaf02d1SJit Loon Lim do { 352*ddaf02d1SJit Loon Lim mmio_read_32(MMC_REG_BASE + SDHC_CDNS_HRS09); 353*ddaf02d1SJit Loon Lim } while (~mmio_read_32(MMC_REG_BASE + SDHC_CDNS_HRS09) & (1 << 1)); 354*ddaf02d1SJit Loon Lim 355*ddaf02d1SJit Loon Lim mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS11, (dtcvval << SDMMC_CDN_DTCV) | 356*ddaf02d1SJit Loon Lim (sdclkfsval << SDMMC_CDN_SDCLKFS) | (1 << SDMMC_CDN_ICE) | (1 << SDMMC_CDN_SDCE)); 357*ddaf02d1SJit Loon Lim mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS13, UINT_MAX); 358*ddaf02d1SJit Loon Lim } 359*ddaf02d1SJit Loon Lim 360*ddaf02d1SJit Loon Lim int cdns_set_ios(unsigned int clk, unsigned int width) 361*ddaf02d1SJit Loon Lim { 362*ddaf02d1SJit Loon Lim 363*ddaf02d1SJit Loon Lim switch (width) { 364*ddaf02d1SJit Loon Lim case MMC_BUS_WIDTH_1: 365*ddaf02d1SJit Loon Lim mmio_write_32((MMC_REG_BASE + SDHC_CDNS_SRS10), LEDC_OFF); 366*ddaf02d1SJit Loon Lim break; 367*ddaf02d1SJit Loon Lim case MMC_BUS_WIDTH_4: 368*ddaf02d1SJit Loon Lim mmio_write_32((MMC_REG_BASE + SDHC_CDNS_SRS10), DTW_4BIT); 369*ddaf02d1SJit Loon Lim break; 370*ddaf02d1SJit Loon Lim case MMC_BUS_WIDTH_8: 371*ddaf02d1SJit Loon Lim mmio_write_32((MMC_REG_BASE + SDHC_CDNS_SRS10), EDTW_8BIT); 372*ddaf02d1SJit Loon Lim break; 373*ddaf02d1SJit Loon Lim default: 374*ddaf02d1SJit Loon Lim assert(0); 375*ddaf02d1SJit Loon Lim break; 376*ddaf02d1SJit Loon Lim } 377*ddaf02d1SJit Loon Lim cdns_host_set_clk(clk); 378*ddaf02d1SJit Loon Lim 379*ddaf02d1SJit Loon Lim return 0; 380*ddaf02d1SJit Loon Lim } 381*ddaf02d1SJit Loon Lim 382*ddaf02d1SJit Loon Lim int cdns_sdmmc_write_sd_host_reg(uint32_t addr, uint32_t data) 383*ddaf02d1SJit Loon Lim { 384*ddaf02d1SJit Loon Lim uint32_t value = 0; 385*ddaf02d1SJit Loon Lim 386*ddaf02d1SJit Loon Lim value = mmio_read_32(addr); 387*ddaf02d1SJit Loon Lim value &= ~SDHC_REG_MASK; 388*ddaf02d1SJit Loon Lim value |= data; 389*ddaf02d1SJit Loon Lim mmio_write_32(addr, value); 390*ddaf02d1SJit Loon Lim value = mmio_read_32(addr); 391*ddaf02d1SJit Loon Lim if (value != data) { 392*ddaf02d1SJit Loon Lim ERROR("SD host address is not set properly\n"); 393*ddaf02d1SJit Loon Lim return -ENXIO; 394*ddaf02d1SJit Loon Lim } 395*ddaf02d1SJit Loon Lim 396*ddaf02d1SJit Loon Lim return 0; 397*ddaf02d1SJit Loon Lim } 398*ddaf02d1SJit Loon Lim 399*ddaf02d1SJit Loon Lim int cdns_write(int lba, uintptr_t buf, size_t size) 400*ddaf02d1SJit Loon Lim { 401*ddaf02d1SJit Loon Lim return 0; 402*ddaf02d1SJit Loon Lim } 403*ddaf02d1SJit Loon Lim 404*ddaf02d1SJit Loon Lim static int cdns_init_hrs_io(struct cdns_sdmmc_combo_phy *combo_phy_reg, 405*ddaf02d1SJit Loon Lim struct cdns_sdmmc_sdhc *sdhc_reg) 406*ddaf02d1SJit Loon Lim { 407*ddaf02d1SJit Loon Lim uint32_t value = 0; 408*ddaf02d1SJit Loon Lim int ret = 0; 409*ddaf02d1SJit Loon Lim 410*ddaf02d1SJit Loon Lim /* program HRS09, register 42 */ 411*ddaf02d1SJit Loon Lim value = (SDHC_RDDATA_EN(sdhc_reg->sdhc_rddata_en)) 412*ddaf02d1SJit Loon Lim | (SDHC_RDCMD_EN(sdhc_reg->sdhc_rdcmd_en)) 413*ddaf02d1SJit Loon Lim | (SDHC_EXTENDED_WR_MODE(sdhc_reg->sdhc_extended_wr_mode)) 414*ddaf02d1SJit Loon Lim | (SDHC_EXTENDED_RD_MODE(sdhc_reg->sdhc_extended_rd_mode)); 415*ddaf02d1SJit Loon Lim ret = cdns_sdmmc_write_sd_host_reg(MMC_REG_BASE + SDHC_CDNS_HRS09, value); 416*ddaf02d1SJit Loon Lim if (ret != 0) { 417*ddaf02d1SJit Loon Lim ERROR("Program HRS09 failed"); 418*ddaf02d1SJit Loon Lim return ret; 419*ddaf02d1SJit Loon Lim } 420*ddaf02d1SJit Loon Lim 421*ddaf02d1SJit Loon Lim /* program HRS10, register 43 */ 422*ddaf02d1SJit Loon Lim value = (SDHC_HCSDCLKADJ(sdhc_reg->sdhc_hcsdclkadj)); 423*ddaf02d1SJit Loon Lim ret = cdns_sdmmc_write_sd_host_reg(MMC_REG_BASE + SDHC_CDNS_HRS10, value); 424*ddaf02d1SJit Loon Lim if (ret != 0) { 425*ddaf02d1SJit Loon Lim ERROR("Program HRS10 failed"); 426*ddaf02d1SJit Loon Lim return ret; 427*ddaf02d1SJit Loon Lim } 428*ddaf02d1SJit Loon Lim 429*ddaf02d1SJit Loon Lim /* program HRS16, register 48 */ 430*ddaf02d1SJit Loon Lim value = (SDHC_WRDATA1_SDCLK_DLY(sdhc_reg->sdhc_wrdata1_sdclk_dly)) 431*ddaf02d1SJit Loon Lim | (SDHC_WRDATA0_SDCLK_DLY(sdhc_reg->sdhc_wrdata0_sdclk_dly)) 432*ddaf02d1SJit Loon Lim | (SDHC_WRCMD1_SDCLK_DLY(sdhc_reg->sdhc_wrcmd1_sdclk_dly)) 433*ddaf02d1SJit Loon Lim | (SDHC_WRCMD0_SDCLK_DLY(sdhc_reg->sdhc_wrcmd0_sdclk_dly)) 434*ddaf02d1SJit Loon Lim | (SDHC_WRDATA1_DLY(sdhc_reg->sdhc_wrdata1_dly)) 435*ddaf02d1SJit Loon Lim | (SDHC_WRDATA0_DLY(sdhc_reg->sdhc_wrdata0_dly)) 436*ddaf02d1SJit Loon Lim | (SDHC_WRCMD1_DLY(sdhc_reg->sdhc_wrcmd1_dly)) 437*ddaf02d1SJit Loon Lim | (SDHC_WRCMD0_DLY(sdhc_reg->sdhc_wrcmd0_dly)); 438*ddaf02d1SJit Loon Lim ret = cdns_sdmmc_write_sd_host_reg(MMC_REG_BASE + SDHC_CDNS_HRS16, value); 439*ddaf02d1SJit Loon Lim if (ret != 0) { 440*ddaf02d1SJit Loon Lim ERROR("Program HRS16 failed"); 441*ddaf02d1SJit Loon Lim return ret; 442*ddaf02d1SJit Loon Lim } 443*ddaf02d1SJit Loon Lim 444*ddaf02d1SJit Loon Lim /* program HRS07, register 40 */ 445*ddaf02d1SJit Loon Lim value = (SDHC_RW_COMPENSATE(sdhc_reg->sdhc_rw_compensate)) 446*ddaf02d1SJit Loon Lim | (SDHC_IDELAY_VAL(sdhc_reg->sdhc_idelay_val)); 447*ddaf02d1SJit Loon Lim ret = cdns_sdmmc_write_sd_host_reg(MMC_REG_BASE + SDHC_CDNS_HRS07, value); 448*ddaf02d1SJit Loon Lim if (ret != 0) { 449*ddaf02d1SJit Loon Lim ERROR("Program HRS07 failed"); 450*ddaf02d1SJit Loon Lim return ret; 451*ddaf02d1SJit Loon Lim } 452*ddaf02d1SJit Loon Lim 453*ddaf02d1SJit Loon Lim return ret; 454*ddaf02d1SJit Loon Lim } 455*ddaf02d1SJit Loon Lim 456*ddaf02d1SJit Loon Lim static int cdns_hc_set_clk(struct cdns_sdmmc_params *cdn_sdmmc_dev_mode_params) 457*ddaf02d1SJit Loon Lim { 458*ddaf02d1SJit Loon Lim uint32_t ret = 0; 459*ddaf02d1SJit Loon Lim uint32_t dtcvval, sdclkfsval; 460*ddaf02d1SJit Loon Lim 461*ddaf02d1SJit Loon Lim dtcvval = DTC_VAL; 462*ddaf02d1SJit Loon Lim sdclkfsval = 0; 463*ddaf02d1SJit Loon Lim 464*ddaf02d1SJit Loon Lim if ((cdn_sdmmc_dev_mode_params->cdn_sdmmc_dev_mode == SD_DS) || 465*ddaf02d1SJit Loon Lim (cdn_sdmmc_dev_mode_params->cdn_sdmmc_dev_mode == SD_UHS_SDR12) || 466*ddaf02d1SJit Loon Lim (cdn_sdmmc_dev_mode_params->cdn_sdmmc_dev_mode == EMMC_SDR_BC)) { 467*ddaf02d1SJit Loon Lim sdclkfsval = 4; 468*ddaf02d1SJit Loon Lim } else if ((cdn_sdmmc_dev_mode_params->cdn_sdmmc_dev_mode == SD_HS) || 469*ddaf02d1SJit Loon Lim (cdn_sdmmc_dev_mode_params->cdn_sdmmc_dev_mode == SD_UHS_SDR25) || 470*ddaf02d1SJit Loon Lim (cdn_sdmmc_dev_mode_params->cdn_sdmmc_dev_mode == SD_UHS_DDR50) || 471*ddaf02d1SJit Loon Lim (cdn_sdmmc_dev_mode_params->cdn_sdmmc_dev_mode == EMMC_SDR)) { 472*ddaf02d1SJit Loon Lim sdclkfsval = 2; 473*ddaf02d1SJit Loon Lim } else if ((cdn_sdmmc_dev_mode_params->cdn_sdmmc_dev_mode == SD_UHS_SDR50) || 474*ddaf02d1SJit Loon Lim (cdn_sdmmc_dev_mode_params->cdn_sdmmc_dev_mode == EMMC_DDR) || 475*ddaf02d1SJit Loon Lim (cdn_sdmmc_dev_mode_params->cdn_sdmmc_dev_mode == EMMC_HS400) || 476*ddaf02d1SJit Loon Lim (cdn_sdmmc_dev_mode_params->cdn_sdmmc_dev_mode == EMMC_HS400es)) { 477*ddaf02d1SJit Loon Lim sdclkfsval = 1; 478*ddaf02d1SJit Loon Lim } else if ((cdn_sdmmc_dev_mode_params->cdn_sdmmc_dev_mode == SD_UHS_SDR104) || 479*ddaf02d1SJit Loon Lim (cdn_sdmmc_dev_mode_params->cdn_sdmmc_dev_mode == EMMC_HS200)) { 480*ddaf02d1SJit Loon Lim sdclkfsval = 0; 481*ddaf02d1SJit Loon Lim } 482*ddaf02d1SJit Loon Lim 483*ddaf02d1SJit Loon Lim mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS11, 0); 484*ddaf02d1SJit Loon Lim mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS11, (dtcvval << SDMMC_CDN_DTCV) | 485*ddaf02d1SJit Loon Lim (sdclkfsval << SDMMC_CDN_SDCLKFS) | (1 << SDMMC_CDN_ICE)); 486*ddaf02d1SJit Loon Lim ret = cdns_wait_ics(5000, MMC_REG_BASE + SDHC_CDNS_SRS11); 487*ddaf02d1SJit Loon Lim if (ret != 0U) { 488*ddaf02d1SJit Loon Lim ERROR("Waiting SDMMC_CDN_ICS timeout"); 489*ddaf02d1SJit Loon Lim return ret; 490*ddaf02d1SJit Loon Lim } 491*ddaf02d1SJit Loon Lim 492*ddaf02d1SJit Loon Lim /* Enable DLL reset */ 493*ddaf02d1SJit Loon Lim mmio_write_32((MMC_REG_BASE + SDHC_CDNS_HRS09), mmio_read_32(MMC_REG_BASE 494*ddaf02d1SJit Loon Lim + SDHC_CDNS_HRS09) & ~SDHC_DLL_RESET_MASK); 495*ddaf02d1SJit Loon Lim /* Set extended_wr_mode */ 496*ddaf02d1SJit Loon Lim mmio_write_32((MMC_REG_BASE + SDHC_CDNS_HRS09), 497*ddaf02d1SJit Loon Lim (mmio_read_32(MMC_REG_BASE + SDHC_CDNS_HRS09) & SDHC_EXTENDED_WR_MODE_MASK) | 498*ddaf02d1SJit Loon Lim (1 << EXTENDED_WR_MODE)); 499*ddaf02d1SJit Loon Lim /* Release DLL reset */ 500*ddaf02d1SJit Loon Lim mmio_write_32(MMC_REG_BASE + SDHC_CDNS_HRS09, mmio_read_32(MMC_REG_BASE 501*ddaf02d1SJit Loon Lim + SDHC_CDNS_HRS09) | 1); 502*ddaf02d1SJit Loon Lim mmio_write_32(MMC_REG_BASE + SDHC_CDNS_HRS09, mmio_read_32(MMC_REG_BASE 503*ddaf02d1SJit Loon Lim + SDHC_CDNS_HRS09) | (3 << RDCMD_EN)); 504*ddaf02d1SJit Loon Lim do { 505*ddaf02d1SJit Loon Lim mmio_read_32(MMC_REG_BASE + SDHC_CDNS_HRS09); 506*ddaf02d1SJit Loon Lim } while (~mmio_read_32(MMC_REG_BASE + SDHC_CDNS_HRS09) & (1 << 1)); 507*ddaf02d1SJit Loon Lim 508*ddaf02d1SJit Loon Lim mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS11, (dtcvval << SDMMC_CDN_DTCV) | 509*ddaf02d1SJit Loon Lim (sdclkfsval << SDMMC_CDN_SDCLKFS) | (1 << SDMMC_CDN_ICE) | (1 << SDMMC_CDN_SDCE)); 510*ddaf02d1SJit Loon Lim 511*ddaf02d1SJit Loon Lim mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS13, UINT_MAX); 512*ddaf02d1SJit Loon Lim return 0; 513*ddaf02d1SJit Loon Lim } 514*ddaf02d1SJit Loon Lim 515*ddaf02d1SJit Loon Lim int cdns_reset(void) 516*ddaf02d1SJit Loon Lim { 517*ddaf02d1SJit Loon Lim uint32_t data = 0; 518*ddaf02d1SJit Loon Lim uint32_t count = 0; 519*ddaf02d1SJit Loon Lim uint32_t value = 0; 520*ddaf02d1SJit Loon Lim 521*ddaf02d1SJit Loon Lim value = mmio_read_32(MMC_REG_BASE + SDHC_CDNS_SRS11); 522*ddaf02d1SJit Loon Lim value &= ~(0xFFFF); 523*ddaf02d1SJit Loon Lim value |= 0x0; 524*ddaf02d1SJit Loon Lim mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS11, value); 525*ddaf02d1SJit Loon Lim udelay(500); 526*ddaf02d1SJit Loon Lim 527*ddaf02d1SJit Loon Lim /* Software reset */ 528*ddaf02d1SJit Loon Lim mmio_write_32(MMC_REG_BASE + SDHC_CDNS_HRS00, 1); 529*ddaf02d1SJit Loon Lim /* Wait status command response ready */ 530*ddaf02d1SJit Loon Lim do { 531*ddaf02d1SJit Loon Lim data = mmio_read_32(MMC_REG_BASE + SDHC_CDNS_HRS00); 532*ddaf02d1SJit Loon Lim count++; 533*ddaf02d1SJit Loon Lim if (count >= 5000) { 534*ddaf02d1SJit Loon Lim return -ETIMEDOUT; 535*ddaf02d1SJit Loon Lim } 536*ddaf02d1SJit Loon Lim /* Wait for HRS00.SWR */ 537*ddaf02d1SJit Loon Lim } while ((data & 1) == 1); 538*ddaf02d1SJit Loon Lim 539*ddaf02d1SJit Loon Lim /* Step 1, switch on DLL_RESET */ 540*ddaf02d1SJit Loon Lim value = mmio_read_32(MMC_REG_BASE + SDHC_CDNS_HRS09); 541*ddaf02d1SJit Loon Lim value &= ~SDHC_PHY_SW_RESET; 542*ddaf02d1SJit Loon Lim mmio_write_32(MMC_REG_BASE + SDHC_CDNS_HRS09, value); 543*ddaf02d1SJit Loon Lim 544*ddaf02d1SJit Loon Lim return 0; 545*ddaf02d1SJit Loon Lim } 546*ddaf02d1SJit Loon Lim 547*ddaf02d1SJit Loon Lim int cdns_sd_host_init(struct cdns_sdmmc_combo_phy *mmc_combo_phy_reg, 548*ddaf02d1SJit Loon Lim struct cdns_sdmmc_sdhc *mmc_sdhc_reg) 549*ddaf02d1SJit Loon Lim { 550*ddaf02d1SJit Loon Lim int ret = 0; 551*ddaf02d1SJit Loon Lim 552*ddaf02d1SJit Loon Lim ret = cdns_reset(); 553*ddaf02d1SJit Loon Lim if (ret != 0) { 554*ddaf02d1SJit Loon Lim ERROR("Program phy reg init failed"); 555*ddaf02d1SJit Loon Lim return ret; 556*ddaf02d1SJit Loon Lim } 557*ddaf02d1SJit Loon Lim 558*ddaf02d1SJit Loon Lim ret = cdns_program_phy_reg(&sdmmc_combo_phy_reg, &sdmmc_sdhc_reg); 559*ddaf02d1SJit Loon Lim if (ret != 0) { 560*ddaf02d1SJit Loon Lim ERROR("Program phy reg init failed"); 561*ddaf02d1SJit Loon Lim return ret; 562*ddaf02d1SJit Loon Lim } 563*ddaf02d1SJit Loon Lim 564*ddaf02d1SJit Loon Lim ret = cdns_init_hrs_io(&sdmmc_combo_phy_reg, &sdmmc_sdhc_reg); 565*ddaf02d1SJit Loon Lim if (ret != 0) { 566*ddaf02d1SJit Loon Lim ERROR("Program init for HRS reg is failed"); 567*ddaf02d1SJit Loon Lim return ret; 568*ddaf02d1SJit Loon Lim } 569*ddaf02d1SJit Loon Lim 570*ddaf02d1SJit Loon Lim ret = cdns_sd_card_detect(); 571*ddaf02d1SJit Loon Lim if (ret != 0) { 572*ddaf02d1SJit Loon Lim ERROR("SD card does not detect"); 573*ddaf02d1SJit Loon Lim return ret; 574*ddaf02d1SJit Loon Lim } 575*ddaf02d1SJit Loon Lim 576*ddaf02d1SJit Loon Lim ret = cdns_vol_reset(); 577*ddaf02d1SJit Loon Lim if (ret != 0) { 578*ddaf02d1SJit Loon Lim ERROR("eMMC card reset failed"); 579*ddaf02d1SJit Loon Lim return ret; 580*ddaf02d1SJit Loon Lim } 581*ddaf02d1SJit Loon Lim 582*ddaf02d1SJit Loon Lim ret = cdns_hc_set_clk(&cdns_params); 583*ddaf02d1SJit Loon Lim if (ret != 0) { 584*ddaf02d1SJit Loon Lim ERROR("hc set clk failed"); 585*ddaf02d1SJit Loon Lim return ret; 586*ddaf02d1SJit Loon Lim } 587*ddaf02d1SJit Loon Lim 588*ddaf02d1SJit Loon Lim return 0; 589*ddaf02d1SJit Loon Lim } 590*ddaf02d1SJit Loon Lim 591*ddaf02d1SJit Loon Lim void cdns_srs10_value_toggle(uint8_t write_val, uint8_t prev_val) 592*ddaf02d1SJit Loon Lim { 593*ddaf02d1SJit Loon Lim uint32_t data_op = 0U; 594*ddaf02d1SJit Loon Lim 595*ddaf02d1SJit Loon Lim data_op = mmio_read_32(MMC_REG_BASE + SDHC_CDNS_SRS10); 596*ddaf02d1SJit Loon Lim mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS10, (data_op & (prev_val << 0))); 597*ddaf02d1SJit Loon Lim mmio_read_32(MMC_REG_BASE + SDHC_CDNS_SRS10); 598*ddaf02d1SJit Loon Lim mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS10, data_op | (write_val << 0)); 599*ddaf02d1SJit Loon Lim } 600*ddaf02d1SJit Loon Lim 601*ddaf02d1SJit Loon Lim void cdns_srs11_srs15_config(uint32_t srs11_val, uint32_t srs15_val) 602*ddaf02d1SJit Loon Lim { 603*ddaf02d1SJit Loon Lim uint32_t data = 0U; 604*ddaf02d1SJit Loon Lim 605*ddaf02d1SJit Loon Lim data = mmio_read_32(MMC_REG_BASE + SDHC_CDNS_SRS11); 606*ddaf02d1SJit Loon Lim mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS11, (data | srs11_val)); 607*ddaf02d1SJit Loon Lim data = mmio_read_32(MMC_REG_BASE + SDHC_CDNS_SRS15); 608*ddaf02d1SJit Loon Lim mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS15, (data | srs15_val)); 609*ddaf02d1SJit Loon Lim } 610*ddaf02d1SJit Loon Lim 611*ddaf02d1SJit Loon Lim int cdns_send_cmd(struct mmc_cmd *cmd) 612*ddaf02d1SJit Loon Lim { 613*ddaf02d1SJit Loon Lim uint32_t op = 0, ret = 0; 614*ddaf02d1SJit Loon Lim uint8_t write_value = 0, prev_val = 0; 615*ddaf02d1SJit Loon Lim uint32_t value; 616*ddaf02d1SJit Loon Lim int32_t timeout; 617*ddaf02d1SJit Loon Lim uint32_t cmd_indx; 618*ddaf02d1SJit Loon Lim uint32_t status = 0, srs15_val = 0, srs11_val = 0; 619*ddaf02d1SJit Loon Lim uint32_t status_check = 0; 620*ddaf02d1SJit Loon Lim 621*ddaf02d1SJit Loon Lim assert(cmd); 622*ddaf02d1SJit Loon Lim cmd_indx = (cmd->cmd_idx) << COM_IDX; 623*ddaf02d1SJit Loon Lim 624*ddaf02d1SJit Loon Lim if (data_cmd) { 625*ddaf02d1SJit Loon Lim switch (cmd->cmd_idx) { 626*ddaf02d1SJit Loon Lim case SD_SWITCH: 627*ddaf02d1SJit Loon Lim op = DATA_PRESENT; 628*ddaf02d1SJit Loon Lim write_value = ADMA2_32 | DT_WIDTH; 629*ddaf02d1SJit Loon Lim prev_val = ADMA2_32 | DT_WIDTH; 630*ddaf02d1SJit Loon Lim cdns_srs10_value_toggle(write_value, prev_val); 631*ddaf02d1SJit Loon Lim srs11_val = READ_CLK | SDMMC_CDN_ICE | SDMMC_CDN_ICS | SDMMC_CDN_SDCE; 632*ddaf02d1SJit Loon Lim srs15_val = BIT_AD_64 | HV4E | V18SE; 633*ddaf02d1SJit Loon Lim cdns_srs11_srs15_config(srs11_val, srs15_val); 634*ddaf02d1SJit Loon Lim break; 635*ddaf02d1SJit Loon Lim 636*ddaf02d1SJit Loon Lim case SD_WRITE_SINGLE_BLOCK: 637*ddaf02d1SJit Loon Lim case SD_READ_SINGLE_BLOCK: 638*ddaf02d1SJit Loon Lim op = DATA_PRESENT; 639*ddaf02d1SJit Loon Lim write_value = ADMA2_32 | HS_EN | DT_WIDTH | LEDC; 640*ddaf02d1SJit Loon Lim prev_val = ADMA2_32 | HS_EN | DT_WIDTH; 641*ddaf02d1SJit Loon Lim cdns_srs10_value_toggle(write_value, prev_val); 642*ddaf02d1SJit Loon Lim srs15_val = PVE | BIT_AD_64 | HV4E | SDR104_MODE | V18SE; 643*ddaf02d1SJit Loon Lim srs11_val = READ_CLK | SDMMC_CDN_ICE | SDMMC_CDN_ICS | SDMMC_CDN_SDCE; 644*ddaf02d1SJit Loon Lim cdns_srs11_srs15_config(srs11_val, srs15_val); 645*ddaf02d1SJit Loon Lim mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS00, SAAR); 646*ddaf02d1SJit Loon Lim break; 647*ddaf02d1SJit Loon Lim 648*ddaf02d1SJit Loon Lim case SD_WRITE_MULTIPLE_BLOCK: 649*ddaf02d1SJit Loon Lim case SD_READ_MULTIPLE_BLOCK: 650*ddaf02d1SJit Loon Lim op = DATA_PRESENT | AUTO_CMD_EN | MULTI_BLK_READ; 651*ddaf02d1SJit Loon Lim write_value = ADMA2_32 | HS_EN | DT_WIDTH | LEDC; 652*ddaf02d1SJit Loon Lim prev_val = ADMA2_32 | HS_EN | DT_WIDTH; 653*ddaf02d1SJit Loon Lim cdns_srs10_value_toggle(write_value, prev_val); 654*ddaf02d1SJit Loon Lim srs15_val = PVE | BIT_AD_64 | HV4E | SDR104_MODE | V18SE; 655*ddaf02d1SJit Loon Lim srs11_val = READ_CLK | SDMMC_CDN_ICE | SDMMC_CDN_ICS | SDMMC_CDN_SDCE; 656*ddaf02d1SJit Loon Lim cdns_srs11_srs15_config(srs11_val, srs15_val); 657*ddaf02d1SJit Loon Lim mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS00, SAAR); 658*ddaf02d1SJit Loon Lim break; 659*ddaf02d1SJit Loon Lim 660*ddaf02d1SJit Loon Lim case SD_APP_SEND_SCR: 661*ddaf02d1SJit Loon Lim op = DATA_PRESENT; 662*ddaf02d1SJit Loon Lim write_value = ADMA2_32 | LEDC; 663*ddaf02d1SJit Loon Lim prev_val = LEDC; 664*ddaf02d1SJit Loon Lim cdns_srs10_value_toggle(write_value, prev_val); 665*ddaf02d1SJit Loon Lim srs15_val = BIT_AD_64 | HV4E | V18SE; 666*ddaf02d1SJit Loon Lim srs11_val = READ_CLK | SDMMC_CDN_ICE | SDMMC_CDN_ICS | SDMMC_CDN_SDCE; 667*ddaf02d1SJit Loon Lim cdns_srs11_srs15_config(srs11_val, srs15_val); 668*ddaf02d1SJit Loon Lim break; 669*ddaf02d1SJit Loon Lim 670*ddaf02d1SJit Loon Lim case SD_SEND_IF_COND: 671*ddaf02d1SJit Loon Lim op = DATA_PRESENT | CMD_IDX_CHK_ENABLE; 672*ddaf02d1SJit Loon Lim write_value = LEDC; 673*ddaf02d1SJit Loon Lim prev_val = 0x0; 674*ddaf02d1SJit Loon Lim cdns_srs10_value_toggle(write_value, prev_val); 675*ddaf02d1SJit Loon Lim srs15_val = HV4E; 676*ddaf02d1SJit Loon Lim srs11_val = READ_CLK | SDMMC_CDN_ICE | SDMMC_CDN_ICS | SDMMC_CDN_SDCE; 677*ddaf02d1SJit Loon Lim cdns_srs11_srs15_config(srs11_val, srs15_val); 678*ddaf02d1SJit Loon Lim break; 679*ddaf02d1SJit Loon Lim 680*ddaf02d1SJit Loon Lim default: 681*ddaf02d1SJit Loon Lim write_value = LEDC; 682*ddaf02d1SJit Loon Lim prev_val = 0x0; 683*ddaf02d1SJit Loon Lim cdns_srs10_value_toggle(write_value, prev_val); 684*ddaf02d1SJit Loon Lim op = 0; 685*ddaf02d1SJit Loon Lim break; 686*ddaf02d1SJit Loon Lim } 687*ddaf02d1SJit Loon Lim } else { 688*ddaf02d1SJit Loon Lim switch (cmd->cmd_idx) { 689*ddaf02d1SJit Loon Lim case SD_GO_IDLE_STATE: 690*ddaf02d1SJit Loon Lim write_value = LEDC; 691*ddaf02d1SJit Loon Lim prev_val = 0x0; 692*ddaf02d1SJit Loon Lim cdns_srs10_value_toggle(write_value, prev_val); 693*ddaf02d1SJit Loon Lim srs15_val = HV4E; 694*ddaf02d1SJit Loon Lim srs11_val = SDMMC_CDN_ICE | SDMMC_CDN_ICS | SDMMC_CDN_SDCE; 695*ddaf02d1SJit Loon Lim cdns_srs11_srs15_config(srs11_val, srs15_val); 696*ddaf02d1SJit Loon Lim break; 697*ddaf02d1SJit Loon Lim 698*ddaf02d1SJit Loon Lim case SD_ALL_SEND_CID: 699*ddaf02d1SJit Loon Lim write_value = LEDC; 700*ddaf02d1SJit Loon Lim prev_val = 0x0; 701*ddaf02d1SJit Loon Lim cdns_srs10_value_toggle(write_value, prev_val); 702*ddaf02d1SJit Loon Lim srs15_val = HV4E | V18SE; 703*ddaf02d1SJit Loon Lim srs11_val = SDMMC_CDN_ICE | SDMMC_CDN_ICS | SDMMC_CDN_SDCE; 704*ddaf02d1SJit Loon Lim cdns_srs11_srs15_config(srs11_val, srs15_val); 705*ddaf02d1SJit Loon Lim break; 706*ddaf02d1SJit Loon Lim 707*ddaf02d1SJit Loon Lim case SD_SEND_IF_COND: 708*ddaf02d1SJit Loon Lim op = CMD_IDX_CHK_ENABLE; 709*ddaf02d1SJit Loon Lim write_value = LEDC; 710*ddaf02d1SJit Loon Lim prev_val = 0x0; 711*ddaf02d1SJit Loon Lim cdns_srs10_value_toggle(write_value, prev_val); 712*ddaf02d1SJit Loon Lim srs15_val = HV4E; 713*ddaf02d1SJit Loon Lim srs11_val = READ_CLK | SDMMC_CDN_ICE | SDMMC_CDN_ICS | SDMMC_CDN_SDCE; 714*ddaf02d1SJit Loon Lim cdns_srs11_srs15_config(srs11_val, srs15_val); 715*ddaf02d1SJit Loon Lim break; 716*ddaf02d1SJit Loon Lim 717*ddaf02d1SJit Loon Lim case SD_STOP_TRANSMISSION: 718*ddaf02d1SJit Loon Lim op = CMD_STOP_ABORT_CMD; 719*ddaf02d1SJit Loon Lim break; 720*ddaf02d1SJit Loon Lim 721*ddaf02d1SJit Loon Lim case SD_SEND_STATUS: 722*ddaf02d1SJit Loon Lim break; 723*ddaf02d1SJit Loon Lim 724*ddaf02d1SJit Loon Lim case 1: 725*ddaf02d1SJit Loon Lim cmd->cmd_arg = 0; 726*ddaf02d1SJit Loon Lim break; 727*ddaf02d1SJit Loon Lim 728*ddaf02d1SJit Loon Lim case SD_SELECT_CARD: 729*ddaf02d1SJit Loon Lim op = MULTI_BLK_READ; 730*ddaf02d1SJit Loon Lim break; 731*ddaf02d1SJit Loon Lim 732*ddaf02d1SJit Loon Lim case SD_APP_CMD: 733*ddaf02d1SJit Loon Lim default: 734*ddaf02d1SJit Loon Lim write_value = LEDC; 735*ddaf02d1SJit Loon Lim prev_val = 0x0; 736*ddaf02d1SJit Loon Lim cdns_srs10_value_toggle(write_value, prev_val); 737*ddaf02d1SJit Loon Lim op = 0; 738*ddaf02d1SJit Loon Lim break; 739*ddaf02d1SJit Loon Lim } 740*ddaf02d1SJit Loon Lim } 741*ddaf02d1SJit Loon Lim 742*ddaf02d1SJit Loon Lim switch (cmd->resp_type) { 743*ddaf02d1SJit Loon Lim case MMC_RESPONSE_NONE: 744*ddaf02d1SJit Loon Lim op |= CMD_READ | MULTI_BLK_READ | DMA_ENABLED | BLK_CNT_EN; 745*ddaf02d1SJit Loon Lim break; 746*ddaf02d1SJit Loon Lim 747*ddaf02d1SJit Loon Lim case MMC_RESPONSE_R2: 748*ddaf02d1SJit Loon Lim op |= CMD_READ | MULTI_BLK_READ | DMA_ENABLED | BLK_CNT_EN | 749*ddaf02d1SJit Loon Lim RES_TYPE_SEL_136 | CMD_CHECK_RESP_CRC; 750*ddaf02d1SJit Loon Lim break; 751*ddaf02d1SJit Loon Lim 752*ddaf02d1SJit Loon Lim case MMC_RESPONSE_R3: 753*ddaf02d1SJit Loon Lim op |= CMD_READ | MULTI_BLK_READ | DMA_ENABLED | BLK_CNT_EN | 754*ddaf02d1SJit Loon Lim RES_TYPE_SEL_48; 755*ddaf02d1SJit Loon Lim break; 756*ddaf02d1SJit Loon Lim 757*ddaf02d1SJit Loon Lim case MMC_RESPONSE_R1: 758*ddaf02d1SJit Loon Lim if ((cmd->cmd_idx == SD_WRITE_SINGLE_BLOCK) || (cmd->cmd_idx 759*ddaf02d1SJit Loon Lim == SD_WRITE_MULTIPLE_BLOCK)) { 760*ddaf02d1SJit Loon Lim op |= DMA_ENABLED | BLK_CNT_EN | RES_TYPE_SEL_48 761*ddaf02d1SJit Loon Lim | CMD_CHECK_RESP_CRC | CMD_IDX_CHK_ENABLE; 762*ddaf02d1SJit Loon Lim } else { 763*ddaf02d1SJit Loon Lim op |= DMA_ENABLED | BLK_CNT_EN | CMD_READ | RES_TYPE_SEL_48 764*ddaf02d1SJit Loon Lim | CMD_CHECK_RESP_CRC | CMD_IDX_CHK_ENABLE; 765*ddaf02d1SJit Loon Lim } 766*ddaf02d1SJit Loon Lim break; 767*ddaf02d1SJit Loon Lim 768*ddaf02d1SJit Loon Lim default: 769*ddaf02d1SJit Loon Lim op |= DMA_ENABLED | BLK_CNT_EN | CMD_READ | MULTI_BLK_READ | 770*ddaf02d1SJit Loon Lim RES_TYPE_SEL_48 | CMD_CHECK_RESP_CRC | CMD_IDX_CHK_ENABLE; 771*ddaf02d1SJit Loon Lim break; 772*ddaf02d1SJit Loon Lim } 773*ddaf02d1SJit Loon Lim 774*ddaf02d1SJit Loon Lim timeout = TIMEOUT; 775*ddaf02d1SJit Loon Lim do { 776*ddaf02d1SJit Loon Lim udelay(100); 777*ddaf02d1SJit Loon Lim ret = cdns_busy(); 778*ddaf02d1SJit Loon Lim if (--timeout <= 0) { 779*ddaf02d1SJit Loon Lim udelay(50); 780*ddaf02d1SJit Loon Lim panic(); 781*ddaf02d1SJit Loon Lim } 782*ddaf02d1SJit Loon Lim } while (ret); 783*ddaf02d1SJit Loon Lim 784*ddaf02d1SJit Loon Lim mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS12, UINT_MAX); 785*ddaf02d1SJit Loon Lim 786*ddaf02d1SJit Loon Lim mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS02, cmd->cmd_arg); 787*ddaf02d1SJit Loon Lim mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS14, 0x00000000); 788*ddaf02d1SJit Loon Lim if (cmd_indx == 1) 789*ddaf02d1SJit Loon Lim mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS03, SDHC_CDNS_SRS03_VALUE); 790*ddaf02d1SJit Loon Lim else 791*ddaf02d1SJit Loon Lim mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS03, op | cmd_indx); 792*ddaf02d1SJit Loon Lim 793*ddaf02d1SJit Loon Lim timeout = TIMEOUT; 794*ddaf02d1SJit Loon Lim do { 795*ddaf02d1SJit Loon Lim udelay(500); 796*ddaf02d1SJit Loon Lim value = mmio_read_32(MMC_REG_BASE + SDHC_CDNS_SRS12); 797*ddaf02d1SJit Loon Lim } while (((value & (INT_CMD_DONE | ERROR_INT)) == 0) && (timeout-- > 0)); 798*ddaf02d1SJit Loon Lim 799*ddaf02d1SJit Loon Lim timeout = TIMEOUT; 800*ddaf02d1SJit Loon Lim 801*ddaf02d1SJit Loon Lim if (data_cmd) { 802*ddaf02d1SJit Loon Lim data_cmd = false; 803*ddaf02d1SJit Loon Lim do { 804*ddaf02d1SJit Loon Lim udelay(250); 805*ddaf02d1SJit Loon Lim } while (((value & TRAN_COMP) == 0) && (timeout-- > 0)); 806*ddaf02d1SJit Loon Lim } 807*ddaf02d1SJit Loon Lim 808*ddaf02d1SJit Loon Lim status_check = value & SRS12_ERR_MASK; 809*ddaf02d1SJit Loon Lim if (status_check != 0U) { 810*ddaf02d1SJit Loon Lim ERROR("SD host controller send command failed, SRS12 = %x", status); 811*ddaf02d1SJit Loon Lim return -1; 812*ddaf02d1SJit Loon Lim } 813*ddaf02d1SJit Loon Lim 814*ddaf02d1SJit Loon Lim if ((op & RES_TYPE_SEL_48) || (op & RES_TYPE_SEL_136)) { 815*ddaf02d1SJit Loon Lim cmd->resp_data[0] = mmio_read_32(MMC_REG_BASE + SDHC_CDNS_SRS04); 816*ddaf02d1SJit Loon Lim if (op & RES_TYPE_SEL_136) { 817*ddaf02d1SJit Loon Lim cmd->resp_data[1] = mmio_read_32(MMC_REG_BASE + SDHC_CDNS_SRS05); 818*ddaf02d1SJit Loon Lim cmd->resp_data[2] = mmio_read_32(MMC_REG_BASE + SDHC_CDNS_SRS06); 819*ddaf02d1SJit Loon Lim cmd->resp_data[3] = mmio_read_32(MMC_REG_BASE + SDHC_CDNS_SRS07); 820*ddaf02d1SJit Loon Lim } 821*ddaf02d1SJit Loon Lim } 822*ddaf02d1SJit Loon Lim 823*ddaf02d1SJit Loon Lim return 0; 824*ddaf02d1SJit Loon Lim } 825