xref: /rk3399_ARM-atf/plat/intel/soc/common/drivers/sdmmc/sdmmc.c (revision 02711885d7efcf396947900efbbebcd58613a3b7)
1ddaf02d1SJit Loon Lim /*
2ddaf02d1SJit Loon Lim  * Copyright (c) 2022-2023, Intel Corporation. All rights reserved.
3e264b557SSieu Mun Tang  * Copyright (c) 2024, Altera Corporation. All rights reserved.
4ddaf02d1SJit Loon Lim  *
5ddaf02d1SJit Loon Lim  * SPDX-License-Identifier: BSD-3-Clause
6ddaf02d1SJit Loon Lim  */
7ddaf02d1SJit Loon Lim 
8ddaf02d1SJit Loon Lim #include <assert.h>
9ddaf02d1SJit Loon Lim #include <errno.h>
10ddaf02d1SJit Loon Lim #include <stdbool.h>
11ddaf02d1SJit Loon Lim #include <string.h>
12ddaf02d1SJit Loon Lim 
13ddaf02d1SJit Loon Lim #include <arch_helpers.h>
14ddaf02d1SJit Loon Lim #include <common/debug.h>
15ddaf02d1SJit Loon Lim #include <drivers/cadence/cdns_combo_phy.h>
16ddaf02d1SJit Loon Lim #include <drivers/cadence/cdns_sdmmc.h>
17ddaf02d1SJit Loon Lim #include <drivers/delay_timer.h>
18ddaf02d1SJit Loon Lim #include <lib/mmio.h>
19ddaf02d1SJit Loon Lim #include <lib/utils.h>
20ddaf02d1SJit Loon Lim 
21ddaf02d1SJit Loon Lim #include "sdmmc.h"
22e264b557SSieu Mun Tang #include "socfpga_mailbox.h"
23*beba2040SSieu Mun Tang #include "wdt/watchdog.h"
24ddaf02d1SJit Loon Lim 
25ddaf02d1SJit Loon Lim static const struct mmc_ops *ops;
26ddaf02d1SJit Loon Lim static unsigned int mmc_ocr_value;
27ddaf02d1SJit Loon Lim static unsigned int mmc_flags;
28ddaf02d1SJit Loon Lim static unsigned int rca;
29ddaf02d1SJit Loon Lim 
30ddaf02d1SJit Loon Lim extern const struct mmc_ops cdns_sdmmc_ops;
31ddaf02d1SJit Loon Lim extern struct cdns_sdmmc_params cdns_params;
32ddaf02d1SJit Loon Lim extern struct cdns_sdmmc_combo_phy sdmmc_combo_phy_reg;
33ddaf02d1SJit Loon Lim extern struct cdns_sdmmc_sdhc sdmmc_sdhc_reg;
34ddaf02d1SJit Loon Lim 
is_cmd23_enabled(void)35*beba2040SSieu Mun Tang bool is_cmd23_enabled(void)
36ddaf02d1SJit Loon Lim {
37ddaf02d1SJit Loon Lim 	return ((mmc_flags & MMC_FLAG_CMD23) != 0U);
38ddaf02d1SJit Loon Lim }
39ddaf02d1SJit Loon Lim 
sdmmc_send_cmd(unsigned int idx,unsigned int arg,unsigned int r_type,unsigned int * r_data)40*beba2040SSieu Mun Tang int sdmmc_send_cmd(unsigned int idx, unsigned int arg,
41ddaf02d1SJit Loon Lim 			unsigned int r_type, unsigned int *r_data)
42ddaf02d1SJit Loon Lim {
43ddaf02d1SJit Loon Lim 	struct mmc_cmd cmd;
44ddaf02d1SJit Loon Lim 	int ret;
45ddaf02d1SJit Loon Lim 
46ddaf02d1SJit Loon Lim 	zeromem(&cmd, sizeof(struct mmc_cmd));
47ddaf02d1SJit Loon Lim 
48ddaf02d1SJit Loon Lim 	cmd.cmd_idx = idx;
49ddaf02d1SJit Loon Lim 	cmd.cmd_arg = arg;
50ddaf02d1SJit Loon Lim 	cmd.resp_type = r_type;
51ddaf02d1SJit Loon Lim 
52ddaf02d1SJit Loon Lim 	ret = ops->send_cmd(&cmd);
53ddaf02d1SJit Loon Lim 
54ddaf02d1SJit Loon Lim 	if ((ret == 0) && (r_data != NULL)) {
55ddaf02d1SJit Loon Lim 		int i;
56ddaf02d1SJit Loon Lim 
57ddaf02d1SJit Loon Lim 		for (i = 0; i < 4; i++) {
58ddaf02d1SJit Loon Lim 			*r_data = cmd.resp_data[i];
59ddaf02d1SJit Loon Lim 			r_data++;
60ddaf02d1SJit Loon Lim 		}
61ddaf02d1SJit Loon Lim 	}
62ddaf02d1SJit Loon Lim 
63ddaf02d1SJit Loon Lim 	if (ret != 0) {
64ddaf02d1SJit Loon Lim 		VERBOSE("Send command %u error: %d\n", idx, ret);
65ddaf02d1SJit Loon Lim 	}
66ddaf02d1SJit Loon Lim 
67ddaf02d1SJit Loon Lim 	return ret;
68ddaf02d1SJit Loon Lim }
69ddaf02d1SJit Loon Lim 
sdmmc_device_state(void)70*beba2040SSieu Mun Tang int sdmmc_device_state(void)
71ddaf02d1SJit Loon Lim {
72ddaf02d1SJit Loon Lim 	int retries = DEFAULT_SDMMC_MAX_RETRIES;
73ddaf02d1SJit Loon Lim 	unsigned int resp_data[4];
74ddaf02d1SJit Loon Lim 
75ddaf02d1SJit Loon Lim 	do {
76ddaf02d1SJit Loon Lim 		int ret;
77ddaf02d1SJit Loon Lim 
78ddaf02d1SJit Loon Lim 		if (retries == 0) {
79ddaf02d1SJit Loon Lim 			ERROR("CMD13 failed after %d retries\n",
80ddaf02d1SJit Loon Lim 			      DEFAULT_SDMMC_MAX_RETRIES);
81ddaf02d1SJit Loon Lim 			return -EIO;
82ddaf02d1SJit Loon Lim 		}
83ddaf02d1SJit Loon Lim 
84ddaf02d1SJit Loon Lim 		ret = sdmmc_send_cmd(MMC_CMD(13), rca << RCA_SHIFT_OFFSET,
85ddaf02d1SJit Loon Lim 				   MMC_RESPONSE_R1, &resp_data[0]);
86ddaf02d1SJit Loon Lim 		if (ret != 0) {
87ddaf02d1SJit Loon Lim 			retries--;
88ddaf02d1SJit Loon Lim 			continue;
89ddaf02d1SJit Loon Lim 		}
90ddaf02d1SJit Loon Lim 
91ddaf02d1SJit Loon Lim 		if ((resp_data[0] & STATUS_SWITCH_ERROR) != 0U) {
92ddaf02d1SJit Loon Lim 			return -EIO;
93ddaf02d1SJit Loon Lim 		}
94ddaf02d1SJit Loon Lim 
95ddaf02d1SJit Loon Lim 		retries--;
96ddaf02d1SJit Loon Lim 	} while ((resp_data[0] & STATUS_READY_FOR_DATA) == 0U);
97ddaf02d1SJit Loon Lim 
98ddaf02d1SJit Loon Lim 	return MMC_GET_STATE(resp_data[0]);
99ddaf02d1SJit Loon Lim }
100ddaf02d1SJit Loon Lim 
sdmmc_read_blocks(int lba,uintptr_t buf,size_t size)101ddaf02d1SJit Loon Lim size_t sdmmc_read_blocks(int lba, uintptr_t buf, size_t size)
102ddaf02d1SJit Loon Lim {
103*beba2040SSieu Mun Tang 	mmc_read_blocks(lba, buf, size);
104ddaf02d1SJit Loon Lim 
105*beba2040SSieu Mun Tang 	/* Restart watchdog for reading each chunk byte */
106*beba2040SSieu Mun Tang 	watchdog_sw_rst();
107ddaf02d1SJit Loon Lim 
108ddaf02d1SJit Loon Lim 	return size;
109ddaf02d1SJit Loon Lim }
110ddaf02d1SJit Loon Lim 
sdmmc_write_blocks(int lba,const uintptr_t buf,size_t size)111ddaf02d1SJit Loon Lim size_t sdmmc_write_blocks(int lba, const uintptr_t buf, size_t size)
112ddaf02d1SJit Loon Lim {
113ddaf02d1SJit Loon Lim 	int ret;
114ddaf02d1SJit Loon Lim 	unsigned int cmd_idx, cmd_arg;
115ddaf02d1SJit Loon Lim 
116ddaf02d1SJit Loon Lim 	assert((ops != NULL) &&
117ddaf02d1SJit Loon Lim 	       (ops->write != NULL) &&
118ddaf02d1SJit Loon Lim 	       (size != 0U) &&
119ddaf02d1SJit Loon Lim 	       ((buf & MMC_BLOCK_MASK) == 0U) &&
120ddaf02d1SJit Loon Lim 	       ((size & MMC_BLOCK_MASK) == 0U));
121ddaf02d1SJit Loon Lim 
122ddaf02d1SJit Loon Lim 	ret = ops->prepare(lba, buf, size);
123ddaf02d1SJit Loon Lim 	if (ret != 0) {
124ddaf02d1SJit Loon Lim 		return 0;
125ddaf02d1SJit Loon Lim 	}
126ddaf02d1SJit Loon Lim 
127ddaf02d1SJit Loon Lim 	if (is_cmd23_enabled()) {
128ddaf02d1SJit Loon Lim 		/* Set block count */
129ddaf02d1SJit Loon Lim 		ret = sdmmc_send_cmd(MMC_CMD(23), size / MMC_BLOCK_SIZE,
130ddaf02d1SJit Loon Lim 				   MMC_RESPONSE_R1, NULL);
131ddaf02d1SJit Loon Lim 		if (ret != 0) {
132ddaf02d1SJit Loon Lim 			return 0;
133ddaf02d1SJit Loon Lim 		}
134ddaf02d1SJit Loon Lim 
135ddaf02d1SJit Loon Lim 		cmd_idx = MMC_CMD(25);
136ddaf02d1SJit Loon Lim 	} else {
137ddaf02d1SJit Loon Lim 		if (size > MMC_BLOCK_SIZE) {
138ddaf02d1SJit Loon Lim 			cmd_idx = MMC_CMD(25);
139ddaf02d1SJit Loon Lim 		} else {
140ddaf02d1SJit Loon Lim 			cmd_idx = MMC_CMD(24);
141ddaf02d1SJit Loon Lim 		}
142ddaf02d1SJit Loon Lim 	}
143ddaf02d1SJit Loon Lim 
144ddaf02d1SJit Loon Lim 	if ((mmc_ocr_value & OCR_ACCESS_MODE_MASK) == OCR_BYTE_MODE) {
145ddaf02d1SJit Loon Lim 		cmd_arg = lba * MMC_BLOCK_SIZE;
146ddaf02d1SJit Loon Lim 	} else {
147ddaf02d1SJit Loon Lim 		cmd_arg = lba;
148ddaf02d1SJit Loon Lim 	}
149ddaf02d1SJit Loon Lim 
150ddaf02d1SJit Loon Lim 	ret = sdmmc_send_cmd(cmd_idx, cmd_arg, MMC_RESPONSE_R1, NULL);
151ddaf02d1SJit Loon Lim 	if (ret != 0) {
152ddaf02d1SJit Loon Lim 		return 0;
153ddaf02d1SJit Loon Lim 	}
154ddaf02d1SJit Loon Lim 
155ddaf02d1SJit Loon Lim 	ret = ops->write(lba, buf, size);
156ddaf02d1SJit Loon Lim 	if (ret != 0) {
157ddaf02d1SJit Loon Lim 		return 0;
158ddaf02d1SJit Loon Lim 	}
159ddaf02d1SJit Loon Lim 
160ddaf02d1SJit Loon Lim 	/* Wait buffer empty */
161ddaf02d1SJit Loon Lim 	do {
162ddaf02d1SJit Loon Lim 		ret = sdmmc_device_state();
163ddaf02d1SJit Loon Lim 		if (ret < 0) {
164ddaf02d1SJit Loon Lim 			return 0;
165ddaf02d1SJit Loon Lim 		}
166ddaf02d1SJit Loon Lim 	} while ((ret != MMC_STATE_TRAN) && (ret != MMC_STATE_RCV));
167ddaf02d1SJit Loon Lim 
168ddaf02d1SJit Loon Lim 	if (!is_cmd23_enabled() && (size > MMC_BLOCK_SIZE)) {
169ddaf02d1SJit Loon Lim 		ret = sdmmc_send_cmd(MMC_CMD(12), 0, MMC_RESPONSE_R1B, NULL);
170ddaf02d1SJit Loon Lim 		if (ret != 0) {
171ddaf02d1SJit Loon Lim 			return 0;
172ddaf02d1SJit Loon Lim 		}
173ddaf02d1SJit Loon Lim 	}
174ddaf02d1SJit Loon Lim 
175ddaf02d1SJit Loon Lim 	return size;
176ddaf02d1SJit Loon Lim }
177