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