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 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 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 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 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 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