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