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