xref: /rk3399_ARM-atf/drivers/cadence/emmc/cdns_sdmmc.c (revision ddaf02d17142187d9f17acd4900aafa598666317)
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