18b659130SJun Nie /* 28b659130SJun Nie * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. 3a59d43fcSGhennadi Procopciuc * Copyright 2025 NXP 48b659130SJun Nie * 58b659130SJun Nie * SPDX-License-Identifier: BSD-3-Clause 68b659130SJun Nie */ 78b659130SJun Nie 809d40e0eSAntonio Nino Diaz #include <assert.h> 909d40e0eSAntonio Nino Diaz #include <errno.h> 1009d40e0eSAntonio Nino Diaz #include <string.h> 1109d40e0eSAntonio Nino Diaz 128b659130SJun Nie #include <arch.h> 138b659130SJun Nie #include <arch_helpers.h> 1409d40e0eSAntonio Nino Diaz #include <common/debug.h> 1509d40e0eSAntonio Nino Diaz #include <drivers/delay_timer.h> 1609d40e0eSAntonio Nino Diaz #include <drivers/mmc.h> 1709d40e0eSAntonio Nino Diaz #include <lib/mmio.h> 18*cdf002deSGhennadi Procopciuc #include <lib/xlat_tables/xlat_tables_v2.h> 1909d40e0eSAntonio Nino Diaz 208b659130SJun Nie #include <imx_usdhc.h> 218b659130SJun Nie 22a59d43fcSGhennadi Procopciuc /* These masks represent the commands which involve a data transfer. */ 23a59d43fcSGhennadi Procopciuc #define ADTC_MASK_SD (BIT_32(6U) | BIT_32(17U) | BIT_32(18U) |\ 24a59d43fcSGhennadi Procopciuc BIT_32(24U) | BIT_32(25U)) 25a59d43fcSGhennadi Procopciuc #define ADTC_MASK_ACMD (BIT_64(51U)) 26a59d43fcSGhennadi Procopciuc 27b61379fbSGhennadi Procopciuc struct imx_usdhc_device_data { 28b61379fbSGhennadi Procopciuc uint32_t addr; 29b61379fbSGhennadi Procopciuc uint32_t blk_size; 30b61379fbSGhennadi Procopciuc uint32_t blks; 31b61379fbSGhennadi Procopciuc bool valid; 32b61379fbSGhennadi Procopciuc }; 33b61379fbSGhennadi Procopciuc 348b659130SJun Nie static void imx_usdhc_initialize(void); 358b659130SJun Nie static int imx_usdhc_send_cmd(struct mmc_cmd *cmd); 368b659130SJun Nie static int imx_usdhc_set_ios(unsigned int clk, unsigned int width); 378b659130SJun Nie static int imx_usdhc_prepare(int lba, uintptr_t buf, size_t size); 388b659130SJun Nie static int imx_usdhc_read(int lba, uintptr_t buf, size_t size); 398b659130SJun Nie static int imx_usdhc_write(int lba, uintptr_t buf, size_t size); 408b659130SJun Nie 418b659130SJun Nie static const struct mmc_ops imx_usdhc_ops = { 428b659130SJun Nie .init = imx_usdhc_initialize, 438b659130SJun Nie .send_cmd = imx_usdhc_send_cmd, 448b659130SJun Nie .set_ios = imx_usdhc_set_ios, 458b659130SJun Nie .prepare = imx_usdhc_prepare, 468b659130SJun Nie .read = imx_usdhc_read, 478b659130SJun Nie .write = imx_usdhc_write, 488b659130SJun Nie }; 498b659130SJun Nie 508b659130SJun Nie static imx_usdhc_params_t imx_usdhc_params; 51b61379fbSGhennadi Procopciuc static struct imx_usdhc_device_data imx_usdhc_data; 52b61379fbSGhennadi Procopciuc 53b61379fbSGhennadi Procopciuc static bool imx_usdhc_is_buf_valid(void) 54b61379fbSGhennadi Procopciuc { 55b61379fbSGhennadi Procopciuc return imx_usdhc_data.valid; 56b61379fbSGhennadi Procopciuc } 57b61379fbSGhennadi Procopciuc 58b61379fbSGhennadi Procopciuc static bool imx_usdhc_is_buf_multiblk(void) 59b61379fbSGhennadi Procopciuc { 60b61379fbSGhennadi Procopciuc return imx_usdhc_data.blks > 1U; 61b61379fbSGhennadi Procopciuc } 62b61379fbSGhennadi Procopciuc 63b61379fbSGhennadi Procopciuc static void imx_usdhc_inval_buf_data(void) 64b61379fbSGhennadi Procopciuc { 65b61379fbSGhennadi Procopciuc imx_usdhc_data.valid = false; 66b61379fbSGhennadi Procopciuc } 67b61379fbSGhennadi Procopciuc 68b61379fbSGhennadi Procopciuc static int imx_usdhc_save_buf_data(uintptr_t buf, size_t size) 69b61379fbSGhennadi Procopciuc { 70b61379fbSGhennadi Procopciuc uint32_t block_size; 71b61379fbSGhennadi Procopciuc uint64_t blks; 72b61379fbSGhennadi Procopciuc 73b61379fbSGhennadi Procopciuc if (size <= MMC_BLOCK_SIZE) { 74b61379fbSGhennadi Procopciuc block_size = (uint32_t)size; 75b61379fbSGhennadi Procopciuc } else { 76b61379fbSGhennadi Procopciuc block_size = MMC_BLOCK_SIZE; 77b61379fbSGhennadi Procopciuc } 78b61379fbSGhennadi Procopciuc 79b61379fbSGhennadi Procopciuc if (buf > UINT32_MAX) { 80b61379fbSGhennadi Procopciuc return -EOVERFLOW; 81b61379fbSGhennadi Procopciuc } 82b61379fbSGhennadi Procopciuc 83b61379fbSGhennadi Procopciuc imx_usdhc_data.addr = (uint32_t)buf; 84b61379fbSGhennadi Procopciuc imx_usdhc_data.blk_size = block_size; 85b61379fbSGhennadi Procopciuc blks = size / block_size; 86b61379fbSGhennadi Procopciuc imx_usdhc_data.blks = (uint32_t)blks; 87b61379fbSGhennadi Procopciuc 88b61379fbSGhennadi Procopciuc imx_usdhc_data.valid = true; 89b61379fbSGhennadi Procopciuc 90b61379fbSGhennadi Procopciuc return 0; 91b61379fbSGhennadi Procopciuc } 92b61379fbSGhennadi Procopciuc 93b61379fbSGhennadi Procopciuc static void imx_usdhc_write_buf_data(void) 94b61379fbSGhennadi Procopciuc { 95b61379fbSGhennadi Procopciuc uintptr_t reg_base = imx_usdhc_params.reg_base; 96b61379fbSGhennadi Procopciuc uint32_t addr, blks, blk_size; 97b61379fbSGhennadi Procopciuc 98b61379fbSGhennadi Procopciuc addr = imx_usdhc_data.addr; 99b61379fbSGhennadi Procopciuc blks = imx_usdhc_data.blks; 100b61379fbSGhennadi Procopciuc blk_size = imx_usdhc_data.blk_size; 101b61379fbSGhennadi Procopciuc 102b61379fbSGhennadi Procopciuc mmio_write_32(reg_base + DSADDR, addr); 103b61379fbSGhennadi Procopciuc mmio_write_32(reg_base + BLKATT, BLKATT_BLKCNT(blks) | 104b61379fbSGhennadi Procopciuc BLKATT_BLKSIZE(blk_size)); 105b61379fbSGhennadi Procopciuc } 1068b659130SJun Nie 1078b659130SJun Nie #define IMX7_MMC_SRC_CLK_RATE (200 * 1000 * 1000) 1082e90f3e6SGhennadi Procopciuc static void imx_usdhc_set_clk(unsigned int clk) 1098b659130SJun Nie { 1108b659130SJun Nie unsigned int sdhc_clk = IMX7_MMC_SRC_CLK_RATE; 1118b659130SJun Nie uintptr_t reg_base = imx_usdhc_params.reg_base; 1122e90f3e6SGhennadi Procopciuc unsigned int pre_div = 1U, div = 1U; 1138b659130SJun Nie 1148b659130SJun Nie assert(clk > 0); 1158b659130SJun Nie 1168b659130SJun Nie while (sdhc_clk / (16 * pre_div) > clk && pre_div < 256) 1178b659130SJun Nie pre_div *= 2; 1188b659130SJun Nie 1192e90f3e6SGhennadi Procopciuc while (((sdhc_clk / (div * pre_div)) > clk) && (div < 16U)) { 1208b659130SJun Nie div++; 1212e90f3e6SGhennadi Procopciuc } 1228b659130SJun Nie 1238b659130SJun Nie pre_div >>= 1; 1248b659130SJun Nie div -= 1; 1258b659130SJun Nie clk = (pre_div << 8) | (div << 4); 1268b659130SJun Nie 127583a544cSGhennadi Procopciuc while ((mmio_read_32(reg_base + PSTATE) & PSTATE_SDSTB) == 0U) { 128583a544cSGhennadi Procopciuc } 129583a544cSGhennadi Procopciuc 1308b659130SJun Nie mmio_clrbits32(reg_base + VENDSPEC, VENDSPEC_CARD_CLKEN); 1318b659130SJun Nie mmio_clrsetbits32(reg_base + SYSCTRL, SYSCTRL_CLOCK_MASK, clk); 1328b659130SJun Nie udelay(10000); 1338b659130SJun Nie 1348b659130SJun Nie mmio_setbits32(reg_base + VENDSPEC, VENDSPEC_PER_CLKEN | VENDSPEC_CARD_CLKEN); 1358b659130SJun Nie } 1368b659130SJun Nie 1378b659130SJun Nie static void imx_usdhc_initialize(void) 1388b659130SJun Nie { 1398b659130SJun Nie unsigned int timeout = 10000; 1408b659130SJun Nie uintptr_t reg_base = imx_usdhc_params.reg_base; 1418b659130SJun Nie 1428b659130SJun Nie assert((imx_usdhc_params.reg_base & MMC_BLOCK_MASK) == 0); 1438b659130SJun Nie 1448b659130SJun Nie /* reset the controller */ 1458b659130SJun Nie mmio_setbits32(reg_base + SYSCTRL, SYSCTRL_RSTA); 1468b659130SJun Nie 1478b659130SJun Nie /* wait for reset done */ 1488b659130SJun Nie while ((mmio_read_32(reg_base + SYSCTRL) & SYSCTRL_RSTA)) { 1498b659130SJun Nie if (!timeout) 1508b659130SJun Nie ERROR("IMX MMC reset timeout.\n"); 1518b659130SJun Nie timeout--; 1528b659130SJun Nie } 1538b659130SJun Nie 1548b659130SJun Nie mmio_write_32(reg_base + MMCBOOT, 0); 1558b659130SJun Nie mmio_write_32(reg_base + MIXCTRL, 0); 1568b659130SJun Nie mmio_write_32(reg_base + CLKTUNECTRLSTS, 0); 1578b659130SJun Nie 1588b659130SJun Nie mmio_write_32(reg_base + VENDSPEC, VENDSPEC_INIT); 1598b659130SJun Nie mmio_write_32(reg_base + DLLCTRL, 0); 1608b659130SJun Nie mmio_setbits32(reg_base + VENDSPEC, VENDSPEC_IPG_CLKEN | VENDSPEC_PER_CLKEN); 1618b659130SJun Nie 1628b659130SJun Nie /* Set the initial boot clock rate */ 1638b659130SJun Nie imx_usdhc_set_clk(MMC_BOOT_CLK_RATE); 1648b659130SJun Nie udelay(100); 1658b659130SJun Nie 1668b659130SJun Nie /* Clear read/write ready status */ 1678b659130SJun Nie mmio_clrbits32(reg_base + INTSTATEN, INTSTATEN_BRR | INTSTATEN_BWR); 1688b659130SJun Nie 1698b659130SJun Nie /* configure as little endian */ 1708b659130SJun Nie mmio_write_32(reg_base + PROTCTRL, PROTCTRL_LE); 1718b659130SJun Nie 1728b659130SJun Nie /* Set timeout to the maximum value */ 1738b659130SJun Nie mmio_clrsetbits32(reg_base + SYSCTRL, SYSCTRL_TIMEOUT_MASK, 1748b659130SJun Nie SYSCTRL_TIMEOUT(15)); 1758b659130SJun Nie 1768b659130SJun Nie /* set wartermark level as 16 for safe for MMC */ 1778b659130SJun Nie mmio_clrsetbits32(reg_base + WATERMARKLEV, WMKLV_MASK, 16 | (16 << 16)); 1788b659130SJun Nie } 1798b659130SJun Nie 1808b659130SJun Nie #define FSL_CMD_RETRIES 1000 1818b659130SJun Nie 18213a839a7SGhennadi Procopciuc static bool is_data_transfer_to_card(const struct mmc_cmd *cmd) 18313a839a7SGhennadi Procopciuc { 18413a839a7SGhennadi Procopciuc unsigned int cmd_idx = cmd->cmd_idx; 18513a839a7SGhennadi Procopciuc 18613a839a7SGhennadi Procopciuc return (cmd_idx == MMC_CMD(24)) || (cmd_idx == MMC_CMD(25)); 18713a839a7SGhennadi Procopciuc } 18813a839a7SGhennadi Procopciuc 189a59d43fcSGhennadi Procopciuc static bool is_data_transfer_cmd(const struct mmc_cmd *cmd) 190a59d43fcSGhennadi Procopciuc { 191a59d43fcSGhennadi Procopciuc uintptr_t reg_base = imx_usdhc_params.reg_base; 192a59d43fcSGhennadi Procopciuc unsigned int cmd_idx = cmd->cmd_idx; 193a59d43fcSGhennadi Procopciuc uint32_t xfer_type; 194a59d43fcSGhennadi Procopciuc 195a59d43fcSGhennadi Procopciuc xfer_type = mmio_read_32(reg_base + XFERTYPE); 196a59d43fcSGhennadi Procopciuc 197a59d43fcSGhennadi Procopciuc if (XFERTYPE_GET_CMD(xfer_type) == MMC_CMD(55)) { 198a59d43fcSGhennadi Procopciuc return (ADTC_MASK_ACMD & BIT_64(cmd_idx)) != 0ULL; 199a59d43fcSGhennadi Procopciuc } 200a59d43fcSGhennadi Procopciuc 201a59d43fcSGhennadi Procopciuc if ((ADTC_MASK_SD & BIT_32(cmd->cmd_idx)) != 0U) { 202a59d43fcSGhennadi Procopciuc return true; 203a59d43fcSGhennadi Procopciuc } 204a59d43fcSGhennadi Procopciuc 205a59d43fcSGhennadi Procopciuc return false; 206a59d43fcSGhennadi Procopciuc } 207a59d43fcSGhennadi Procopciuc 208a59d43fcSGhennadi Procopciuc static int get_xfr_type(const struct mmc_cmd *cmd, bool data, uint32_t *xfertype) 209a59d43fcSGhennadi Procopciuc { 210a59d43fcSGhennadi Procopciuc *xfertype = XFERTYPE_CMD(cmd->cmd_idx); 211a59d43fcSGhennadi Procopciuc 212a59d43fcSGhennadi Procopciuc switch (cmd->resp_type) { 213a59d43fcSGhennadi Procopciuc case MMC_RESPONSE_R2: 214a59d43fcSGhennadi Procopciuc *xfertype |= XFERTYPE_RSPTYP_136; 215a59d43fcSGhennadi Procopciuc *xfertype |= XFERTYPE_CCCEN; 216a59d43fcSGhennadi Procopciuc break; 217a59d43fcSGhennadi Procopciuc case MMC_RESPONSE_R4: 218a59d43fcSGhennadi Procopciuc *xfertype |= XFERTYPE_RSPTYP_48; 219a59d43fcSGhennadi Procopciuc break; 220a59d43fcSGhennadi Procopciuc case MMC_RESPONSE_R6: 221a59d43fcSGhennadi Procopciuc *xfertype |= XFERTYPE_RSPTYP_48; 222a59d43fcSGhennadi Procopciuc *xfertype |= XFERTYPE_CICEN; 223a59d43fcSGhennadi Procopciuc *xfertype |= XFERTYPE_CCCEN; 224a59d43fcSGhennadi Procopciuc break; 225a59d43fcSGhennadi Procopciuc case MMC_RESPONSE_R1B: 226a59d43fcSGhennadi Procopciuc *xfertype |= XFERTYPE_RSPTYP_48_BUSY; 227a59d43fcSGhennadi Procopciuc *xfertype |= XFERTYPE_CICEN; 228a59d43fcSGhennadi Procopciuc *xfertype |= XFERTYPE_CCCEN; 229a59d43fcSGhennadi Procopciuc break; 230a59d43fcSGhennadi Procopciuc default: 231a59d43fcSGhennadi Procopciuc ERROR("Invalid CMD response: %u\n", cmd->resp_type); 232a59d43fcSGhennadi Procopciuc return -EINVAL; 233a59d43fcSGhennadi Procopciuc } 234a59d43fcSGhennadi Procopciuc 235a59d43fcSGhennadi Procopciuc if (data) { 236a59d43fcSGhennadi Procopciuc *xfertype |= XFERTYPE_DPSEL; 237a59d43fcSGhennadi Procopciuc } 238a59d43fcSGhennadi Procopciuc 239a59d43fcSGhennadi Procopciuc return 0; 240a59d43fcSGhennadi Procopciuc } 241a59d43fcSGhennadi Procopciuc 2428b659130SJun Nie static int imx_usdhc_send_cmd(struct mmc_cmd *cmd) 2438b659130SJun Nie { 2448b659130SJun Nie uintptr_t reg_base = imx_usdhc_params.reg_base; 2458b659130SJun Nie unsigned int state, flags = INTSTATEN_CC | INTSTATEN_CTOE; 246f9ed855bSGhennadi Procopciuc unsigned int mixctl = 0; 2478b659130SJun Nie unsigned int cmd_retries = 0; 248a59d43fcSGhennadi Procopciuc uint32_t xfertype; 249a59d43fcSGhennadi Procopciuc bool data; 250a59d43fcSGhennadi Procopciuc int err = 0; 2518b659130SJun Nie 2528b659130SJun Nie assert(cmd); 2538b659130SJun Nie 254a59d43fcSGhennadi Procopciuc data = is_data_transfer_cmd(cmd); 255a59d43fcSGhennadi Procopciuc 256a59d43fcSGhennadi Procopciuc err = get_xfr_type(cmd, data, &xfertype); 257a59d43fcSGhennadi Procopciuc if (err != 0) { 258a59d43fcSGhennadi Procopciuc return err; 259a59d43fcSGhennadi Procopciuc } 260a59d43fcSGhennadi Procopciuc 2618b659130SJun Nie /* clear all irq status */ 2628b659130SJun Nie mmio_write_32(reg_base + INTSTAT, 0xffffffff); 2638b659130SJun Nie 2648b659130SJun Nie /* Wait for the bus to be idle */ 2658b659130SJun Nie do { 2668b659130SJun Nie state = mmio_read_32(reg_base + PSTATE); 2678b659130SJun Nie } while (state & (PSTATE_CDIHB | PSTATE_CIHB)); 2688b659130SJun Nie 2698b659130SJun Nie while (mmio_read_32(reg_base + PSTATE) & PSTATE_DLA) 2708b659130SJun Nie ; 2718b659130SJun Nie 2728b659130SJun Nie mmio_write_32(reg_base + INTSIGEN, 0); 2738b659130SJun Nie 2748b659130SJun Nie if (data) { 2758b659130SJun Nie mixctl |= MIXCTRL_DMAEN; 2768b659130SJun Nie } 2778b659130SJun Nie 27813a839a7SGhennadi Procopciuc if (!is_data_transfer_to_card(cmd)) { 27913a839a7SGhennadi Procopciuc mixctl |= MIXCTRL_DTDSEL; 28013a839a7SGhennadi Procopciuc } 28113a839a7SGhennadi Procopciuc 282b61379fbSGhennadi Procopciuc if ((cmd->cmd_idx != MMC_CMD(55)) && imx_usdhc_is_buf_valid()) { 283b61379fbSGhennadi Procopciuc if (imx_usdhc_is_buf_multiblk()) { 284b61379fbSGhennadi Procopciuc mixctl |= MIXCTRL_MSBSEL | MIXCTRL_BCEN; 285b61379fbSGhennadi Procopciuc } 286b61379fbSGhennadi Procopciuc 287b61379fbSGhennadi Procopciuc imx_usdhc_write_buf_data(); 288b61379fbSGhennadi Procopciuc imx_usdhc_inval_buf_data(); 289b61379fbSGhennadi Procopciuc } 290b61379fbSGhennadi Procopciuc 2918b659130SJun Nie /* Send the command */ 2928b659130SJun Nie mmio_write_32(reg_base + CMDARG, cmd->cmd_arg); 2938b659130SJun Nie mmio_clrsetbits32(reg_base + MIXCTRL, MIXCTRL_DATMASK, mixctl); 2948b659130SJun Nie mmio_write_32(reg_base + XFERTYPE, xfertype); 2958b659130SJun Nie 2968b659130SJun Nie /* Wait for the command done */ 2978b659130SJun Nie do { 2988b659130SJun Nie state = mmio_read_32(reg_base + INTSTAT); 2998b659130SJun Nie if (cmd_retries) 3008b659130SJun Nie udelay(1); 3018b659130SJun Nie } while ((!(state & flags)) && ++cmd_retries < FSL_CMD_RETRIES); 3028b659130SJun Nie 3038b659130SJun Nie if ((state & (INTSTATEN_CTOE | CMD_ERR)) || cmd_retries == FSL_CMD_RETRIES) { 3048b659130SJun Nie if (cmd_retries == FSL_CMD_RETRIES) 3058b659130SJun Nie err = -ETIMEDOUT; 3068b659130SJun Nie else 3078b659130SJun Nie err = -EIO; 3088b659130SJun Nie ERROR("imx_usdhc mmc cmd %d state 0x%x errno=%d\n", 3098b659130SJun Nie cmd->cmd_idx, state, err); 3108b659130SJun Nie goto out; 3118b659130SJun Nie } 3128b659130SJun Nie 3138b659130SJun Nie /* Copy the response to the response buffer */ 3148b659130SJun Nie if (cmd->resp_type & MMC_RSP_136) { 3158b659130SJun Nie unsigned int cmdrsp3, cmdrsp2, cmdrsp1, cmdrsp0; 3168b659130SJun Nie 3178b659130SJun Nie cmdrsp3 = mmio_read_32(reg_base + CMDRSP3); 3188b659130SJun Nie cmdrsp2 = mmio_read_32(reg_base + CMDRSP2); 3198b659130SJun Nie cmdrsp1 = mmio_read_32(reg_base + CMDRSP1); 3208b659130SJun Nie cmdrsp0 = mmio_read_32(reg_base + CMDRSP0); 3218b659130SJun Nie cmd->resp_data[3] = (cmdrsp3 << 8) | (cmdrsp2 >> 24); 3228b659130SJun Nie cmd->resp_data[2] = (cmdrsp2 << 8) | (cmdrsp1 >> 24); 3238b659130SJun Nie cmd->resp_data[1] = (cmdrsp1 << 8) | (cmdrsp0 >> 24); 3248b659130SJun Nie cmd->resp_data[0] = (cmdrsp0 << 8); 3258b659130SJun Nie } else { 3268b659130SJun Nie cmd->resp_data[0] = mmio_read_32(reg_base + CMDRSP0); 3278b659130SJun Nie } 3288b659130SJun Nie 3298b659130SJun Nie /* Wait until all of the blocks are transferred */ 3308b659130SJun Nie if (data) { 3318b659130SJun Nie flags = DATA_COMPLETE; 3328b659130SJun Nie do { 3338b659130SJun Nie state = mmio_read_32(reg_base + INTSTAT); 3348b659130SJun Nie 3358b659130SJun Nie if (state & (INTSTATEN_DTOE | DATA_ERR)) { 3368b659130SJun Nie err = -EIO; 3378b659130SJun Nie ERROR("imx_usdhc mmc data state 0x%x\n", state); 3388b659130SJun Nie goto out; 3398b659130SJun Nie } 3408b659130SJun Nie } while ((state & flags) != flags); 3418b659130SJun Nie } 3428b659130SJun Nie 3438b659130SJun Nie out: 3448b659130SJun Nie /* Reset CMD and DATA on error */ 3458b659130SJun Nie if (err) { 3468b659130SJun Nie mmio_setbits32(reg_base + SYSCTRL, SYSCTRL_RSTC); 3478b659130SJun Nie while (mmio_read_32(reg_base + SYSCTRL) & SYSCTRL_RSTC) 3488b659130SJun Nie ; 3498b659130SJun Nie 3508b659130SJun Nie if (data) { 3518b659130SJun Nie mmio_setbits32(reg_base + SYSCTRL, SYSCTRL_RSTD); 3528b659130SJun Nie while (mmio_read_32(reg_base + SYSCTRL) & SYSCTRL_RSTD) 3538b659130SJun Nie ; 3548b659130SJun Nie } 3558b659130SJun Nie } 3568b659130SJun Nie 3578b659130SJun Nie /* clear all irq status */ 3588b659130SJun Nie mmio_write_32(reg_base + INTSTAT, 0xffffffff); 3598b659130SJun Nie 3608b659130SJun Nie return err; 3618b659130SJun Nie } 3628b659130SJun Nie 3638b659130SJun Nie static int imx_usdhc_set_ios(unsigned int clk, unsigned int width) 3648b659130SJun Nie { 3658b659130SJun Nie uintptr_t reg_base = imx_usdhc_params.reg_base; 3668b659130SJun Nie 3678b659130SJun Nie imx_usdhc_set_clk(clk); 3688b659130SJun Nie 3698b659130SJun Nie if (width == MMC_BUS_WIDTH_4) 3708b659130SJun Nie mmio_clrsetbits32(reg_base + PROTCTRL, PROTCTRL_WIDTH_MASK, 3718b659130SJun Nie PROTCTRL_WIDTH_4); 3728b659130SJun Nie else if (width == MMC_BUS_WIDTH_8) 3738b659130SJun Nie mmio_clrsetbits32(reg_base + PROTCTRL, PROTCTRL_WIDTH_MASK, 3748b659130SJun Nie PROTCTRL_WIDTH_8); 3758b659130SJun Nie 3768b659130SJun Nie return 0; 3778b659130SJun Nie } 3788b659130SJun Nie 3798b659130SJun Nie static int imx_usdhc_prepare(int lba, uintptr_t buf, size_t size) 3808b659130SJun Nie { 3817e2a4347SGhennadi Procopciuc flush_dcache_range(buf, size); 382b61379fbSGhennadi Procopciuc return imx_usdhc_save_buf_data(buf, size); 3838b659130SJun Nie } 3848b659130SJun Nie 3858b659130SJun Nie static int imx_usdhc_read(int lba, uintptr_t buf, size_t size) 3868b659130SJun Nie { 3877e2a4347SGhennadi Procopciuc inv_dcache_range(buf, size); 3888b659130SJun Nie return 0; 3898b659130SJun Nie } 3908b659130SJun Nie 3918b659130SJun Nie static int imx_usdhc_write(int lba, uintptr_t buf, size_t size) 3928b659130SJun Nie { 3938b659130SJun Nie return 0; 3948b659130SJun Nie } 3958b659130SJun Nie 3968b659130SJun Nie void imx_usdhc_init(imx_usdhc_params_t *params, 3978b659130SJun Nie struct mmc_device_info *mmc_dev_info) 3988b659130SJun Nie { 399*cdf002deSGhennadi Procopciuc int ret __maybe_unused; 400*cdf002deSGhennadi Procopciuc 4018b659130SJun Nie assert((params != 0) && 4028b659130SJun Nie ((params->reg_base & MMC_BLOCK_MASK) == 0) && 4038b659130SJun Nie ((params->bus_width == MMC_BUS_WIDTH_1) || 4048b659130SJun Nie (params->bus_width == MMC_BUS_WIDTH_4) || 4058b659130SJun Nie (params->bus_width == MMC_BUS_WIDTH_8))); 4068b659130SJun Nie 407*cdf002deSGhennadi Procopciuc #if PLAT_XLAT_TABLES_DYNAMIC 408*cdf002deSGhennadi Procopciuc ret = mmap_add_dynamic_region(params->reg_base, params->reg_base, 409*cdf002deSGhennadi Procopciuc PAGE_SIZE, 410*cdf002deSGhennadi Procopciuc MT_DEVICE | MT_RW | MT_SECURE); 411*cdf002deSGhennadi Procopciuc if (ret != 0) { 412*cdf002deSGhennadi Procopciuc ERROR("Failed to map the uSDHC registers\n"); 413*cdf002deSGhennadi Procopciuc panic(); 414*cdf002deSGhennadi Procopciuc } 415*cdf002deSGhennadi Procopciuc #endif 416*cdf002deSGhennadi Procopciuc 4178b659130SJun Nie memcpy(&imx_usdhc_params, params, sizeof(imx_usdhc_params_t)); 4188b659130SJun Nie mmc_init(&imx_usdhc_ops, params->clk_rate, params->bus_width, 4198b659130SJun Nie params->flags, mmc_dev_info); 4208b659130SJun Nie } 421