1*8b659130SJun Nie /* 2*8b659130SJun Nie * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. 3*8b659130SJun Nie * 4*8b659130SJun Nie * SPDX-License-Identifier: BSD-3-Clause 5*8b659130SJun Nie */ 6*8b659130SJun Nie 7*8b659130SJun Nie #include <arch.h> 8*8b659130SJun Nie #include <arch_helpers.h> 9*8b659130SJun Nie #include <assert.h> 10*8b659130SJun Nie #include <debug.h> 11*8b659130SJun Nie #include <delay_timer.h> 12*8b659130SJun Nie #include <imx_usdhc.h> 13*8b659130SJun Nie #include <mmc.h> 14*8b659130SJun Nie #include <errno.h> 15*8b659130SJun Nie #include <mmio.h> 16*8b659130SJun Nie #include <string.h> 17*8b659130SJun Nie 18*8b659130SJun Nie static void imx_usdhc_initialize(void); 19*8b659130SJun Nie static int imx_usdhc_send_cmd(struct mmc_cmd *cmd); 20*8b659130SJun Nie static int imx_usdhc_set_ios(unsigned int clk, unsigned int width); 21*8b659130SJun Nie static int imx_usdhc_prepare(int lba, uintptr_t buf, size_t size); 22*8b659130SJun Nie static int imx_usdhc_read(int lba, uintptr_t buf, size_t size); 23*8b659130SJun Nie static int imx_usdhc_write(int lba, uintptr_t buf, size_t size); 24*8b659130SJun Nie 25*8b659130SJun Nie static const struct mmc_ops imx_usdhc_ops = { 26*8b659130SJun Nie .init = imx_usdhc_initialize, 27*8b659130SJun Nie .send_cmd = imx_usdhc_send_cmd, 28*8b659130SJun Nie .set_ios = imx_usdhc_set_ios, 29*8b659130SJun Nie .prepare = imx_usdhc_prepare, 30*8b659130SJun Nie .read = imx_usdhc_read, 31*8b659130SJun Nie .write = imx_usdhc_write, 32*8b659130SJun Nie }; 33*8b659130SJun Nie 34*8b659130SJun Nie static imx_usdhc_params_t imx_usdhc_params; 35*8b659130SJun Nie 36*8b659130SJun Nie #define IMX7_MMC_SRC_CLK_RATE (200 * 1000 * 1000) 37*8b659130SJun Nie static void imx_usdhc_set_clk(int clk) 38*8b659130SJun Nie { 39*8b659130SJun Nie int div = 1; 40*8b659130SJun Nie int pre_div = 1; 41*8b659130SJun Nie unsigned int sdhc_clk = IMX7_MMC_SRC_CLK_RATE; 42*8b659130SJun Nie uintptr_t reg_base = imx_usdhc_params.reg_base; 43*8b659130SJun Nie 44*8b659130SJun Nie assert(clk > 0); 45*8b659130SJun Nie 46*8b659130SJun Nie while (sdhc_clk / (16 * pre_div) > clk && pre_div < 256) 47*8b659130SJun Nie pre_div *= 2; 48*8b659130SJun Nie 49*8b659130SJun Nie while (sdhc_clk / div > clk && div < 16) 50*8b659130SJun Nie div++; 51*8b659130SJun Nie 52*8b659130SJun Nie pre_div >>= 1; 53*8b659130SJun Nie div -= 1; 54*8b659130SJun Nie clk = (pre_div << 8) | (div << 4); 55*8b659130SJun Nie 56*8b659130SJun Nie mmio_clrbits32(reg_base + VENDSPEC, VENDSPEC_CARD_CLKEN); 57*8b659130SJun Nie mmio_clrsetbits32(reg_base + SYSCTRL, SYSCTRL_CLOCK_MASK, clk); 58*8b659130SJun Nie udelay(10000); 59*8b659130SJun Nie 60*8b659130SJun Nie mmio_setbits32(reg_base + VENDSPEC, VENDSPEC_PER_CLKEN | VENDSPEC_CARD_CLKEN); 61*8b659130SJun Nie } 62*8b659130SJun Nie 63*8b659130SJun Nie static void imx_usdhc_initialize(void) 64*8b659130SJun Nie { 65*8b659130SJun Nie unsigned int timeout = 10000; 66*8b659130SJun Nie uintptr_t reg_base = imx_usdhc_params.reg_base; 67*8b659130SJun Nie 68*8b659130SJun Nie assert((imx_usdhc_params.reg_base & MMC_BLOCK_MASK) == 0); 69*8b659130SJun Nie 70*8b659130SJun Nie /* reset the controller */ 71*8b659130SJun Nie mmio_setbits32(reg_base + SYSCTRL, SYSCTRL_RSTA); 72*8b659130SJun Nie 73*8b659130SJun Nie /* wait for reset done */ 74*8b659130SJun Nie while ((mmio_read_32(reg_base + SYSCTRL) & SYSCTRL_RSTA)) { 75*8b659130SJun Nie if (!timeout) 76*8b659130SJun Nie ERROR("IMX MMC reset timeout.\n"); 77*8b659130SJun Nie timeout--; 78*8b659130SJun Nie } 79*8b659130SJun Nie 80*8b659130SJun Nie mmio_write_32(reg_base + MMCBOOT, 0); 81*8b659130SJun Nie mmio_write_32(reg_base + MIXCTRL, 0); 82*8b659130SJun Nie mmio_write_32(reg_base + CLKTUNECTRLSTS, 0); 83*8b659130SJun Nie 84*8b659130SJun Nie mmio_write_32(reg_base + VENDSPEC, VENDSPEC_INIT); 85*8b659130SJun Nie mmio_write_32(reg_base + DLLCTRL, 0); 86*8b659130SJun Nie mmio_setbits32(reg_base + VENDSPEC, VENDSPEC_IPG_CLKEN | VENDSPEC_PER_CLKEN); 87*8b659130SJun Nie 88*8b659130SJun Nie /* Set the initial boot clock rate */ 89*8b659130SJun Nie imx_usdhc_set_clk(MMC_BOOT_CLK_RATE); 90*8b659130SJun Nie udelay(100); 91*8b659130SJun Nie 92*8b659130SJun Nie /* Clear read/write ready status */ 93*8b659130SJun Nie mmio_clrbits32(reg_base + INTSTATEN, INTSTATEN_BRR | INTSTATEN_BWR); 94*8b659130SJun Nie 95*8b659130SJun Nie /* configure as little endian */ 96*8b659130SJun Nie mmio_write_32(reg_base + PROTCTRL, PROTCTRL_LE); 97*8b659130SJun Nie 98*8b659130SJun Nie /* Set timeout to the maximum value */ 99*8b659130SJun Nie mmio_clrsetbits32(reg_base + SYSCTRL, SYSCTRL_TIMEOUT_MASK, 100*8b659130SJun Nie SYSCTRL_TIMEOUT(15)); 101*8b659130SJun Nie 102*8b659130SJun Nie /* set wartermark level as 16 for safe for MMC */ 103*8b659130SJun Nie mmio_clrsetbits32(reg_base + WATERMARKLEV, WMKLV_MASK, 16 | (16 << 16)); 104*8b659130SJun Nie } 105*8b659130SJun Nie 106*8b659130SJun Nie #define FSL_CMD_RETRIES 1000 107*8b659130SJun Nie 108*8b659130SJun Nie static int imx_usdhc_send_cmd(struct mmc_cmd *cmd) 109*8b659130SJun Nie { 110*8b659130SJun Nie uintptr_t reg_base = imx_usdhc_params.reg_base; 111*8b659130SJun Nie unsigned int xfertype = 0, mixctl = 0, multiple = 0, data = 0, err = 0; 112*8b659130SJun Nie unsigned int state, flags = INTSTATEN_CC | INTSTATEN_CTOE; 113*8b659130SJun Nie unsigned int cmd_retries = 0; 114*8b659130SJun Nie 115*8b659130SJun Nie assert(cmd); 116*8b659130SJun Nie 117*8b659130SJun Nie /* clear all irq status */ 118*8b659130SJun Nie mmio_write_32(reg_base + INTSTAT, 0xffffffff); 119*8b659130SJun Nie 120*8b659130SJun Nie /* Wait for the bus to be idle */ 121*8b659130SJun Nie do { 122*8b659130SJun Nie state = mmio_read_32(reg_base + PSTATE); 123*8b659130SJun Nie } while (state & (PSTATE_CDIHB | PSTATE_CIHB)); 124*8b659130SJun Nie 125*8b659130SJun Nie while (mmio_read_32(reg_base + PSTATE) & PSTATE_DLA) 126*8b659130SJun Nie ; 127*8b659130SJun Nie 128*8b659130SJun Nie mmio_write_32(reg_base + INTSIGEN, 0); 129*8b659130SJun Nie udelay(1000); 130*8b659130SJun Nie 131*8b659130SJun Nie switch (cmd->cmd_idx) { 132*8b659130SJun Nie case MMC_CMD(12): 133*8b659130SJun Nie xfertype |= XFERTYPE_CMDTYP_ABORT; 134*8b659130SJun Nie break; 135*8b659130SJun Nie case MMC_CMD(18): 136*8b659130SJun Nie multiple = 1; 137*8b659130SJun Nie /* fall thru for read op */ 138*8b659130SJun Nie case MMC_CMD(17): 139*8b659130SJun Nie case MMC_CMD(8): 140*8b659130SJun Nie mixctl |= MIXCTRL_DTDSEL; 141*8b659130SJun Nie data = 1; 142*8b659130SJun Nie break; 143*8b659130SJun Nie case MMC_CMD(25): 144*8b659130SJun Nie multiple = 1; 145*8b659130SJun Nie /* fall thru for data op flag */ 146*8b659130SJun Nie case MMC_CMD(24): 147*8b659130SJun Nie data = 1; 148*8b659130SJun Nie break; 149*8b659130SJun Nie default: 150*8b659130SJun Nie break; 151*8b659130SJun Nie } 152*8b659130SJun Nie 153*8b659130SJun Nie if (multiple) { 154*8b659130SJun Nie mixctl |= MIXCTRL_MSBSEL; 155*8b659130SJun Nie mixctl |= MIXCTRL_BCEN; 156*8b659130SJun Nie } 157*8b659130SJun Nie 158*8b659130SJun Nie if (data) { 159*8b659130SJun Nie xfertype |= XFERTYPE_DPSEL; 160*8b659130SJun Nie mixctl |= MIXCTRL_DMAEN; 161*8b659130SJun Nie } 162*8b659130SJun Nie 163*8b659130SJun Nie if (cmd->resp_type & MMC_RSP_48) 164*8b659130SJun Nie xfertype |= XFERTYPE_RSPTYP_48; 165*8b659130SJun Nie else if (cmd->resp_type & MMC_RSP_136) 166*8b659130SJun Nie xfertype |= XFERTYPE_RSPTYP_136; 167*8b659130SJun Nie else if (cmd->resp_type & MMC_RSP_BUSY) 168*8b659130SJun Nie xfertype |= XFERTYPE_RSPTYP_48_BUSY; 169*8b659130SJun Nie 170*8b659130SJun Nie if (cmd->resp_type & MMC_RSP_CMD_IDX) 171*8b659130SJun Nie xfertype |= XFERTYPE_CICEN; 172*8b659130SJun Nie 173*8b659130SJun Nie if (cmd->resp_type & MMC_RSP_CRC) 174*8b659130SJun Nie xfertype |= XFERTYPE_CCCEN; 175*8b659130SJun Nie 176*8b659130SJun Nie xfertype |= XFERTYPE_CMD(cmd->cmd_idx); 177*8b659130SJun Nie 178*8b659130SJun Nie /* Send the command */ 179*8b659130SJun Nie mmio_write_32(reg_base + CMDARG, cmd->cmd_arg); 180*8b659130SJun Nie mmio_clrsetbits32(reg_base + MIXCTRL, MIXCTRL_DATMASK, mixctl); 181*8b659130SJun Nie mmio_write_32(reg_base + XFERTYPE, xfertype); 182*8b659130SJun Nie 183*8b659130SJun Nie /* Wait for the command done */ 184*8b659130SJun Nie do { 185*8b659130SJun Nie state = mmio_read_32(reg_base + INTSTAT); 186*8b659130SJun Nie if (cmd_retries) 187*8b659130SJun Nie udelay(1); 188*8b659130SJun Nie } while ((!(state & flags)) && ++cmd_retries < FSL_CMD_RETRIES); 189*8b659130SJun Nie 190*8b659130SJun Nie if ((state & (INTSTATEN_CTOE | CMD_ERR)) || cmd_retries == FSL_CMD_RETRIES) { 191*8b659130SJun Nie if (cmd_retries == FSL_CMD_RETRIES) 192*8b659130SJun Nie err = -ETIMEDOUT; 193*8b659130SJun Nie else 194*8b659130SJun Nie err = -EIO; 195*8b659130SJun Nie ERROR("imx_usdhc mmc cmd %d state 0x%x errno=%d\n", 196*8b659130SJun Nie cmd->cmd_idx, state, err); 197*8b659130SJun Nie goto out; 198*8b659130SJun Nie } 199*8b659130SJun Nie 200*8b659130SJun Nie /* Copy the response to the response buffer */ 201*8b659130SJun Nie if (cmd->resp_type & MMC_RSP_136) { 202*8b659130SJun Nie unsigned int cmdrsp3, cmdrsp2, cmdrsp1, cmdrsp0; 203*8b659130SJun Nie 204*8b659130SJun Nie cmdrsp3 = mmio_read_32(reg_base + CMDRSP3); 205*8b659130SJun Nie cmdrsp2 = mmio_read_32(reg_base + CMDRSP2); 206*8b659130SJun Nie cmdrsp1 = mmio_read_32(reg_base + CMDRSP1); 207*8b659130SJun Nie cmdrsp0 = mmio_read_32(reg_base + CMDRSP0); 208*8b659130SJun Nie cmd->resp_data[3] = (cmdrsp3 << 8) | (cmdrsp2 >> 24); 209*8b659130SJun Nie cmd->resp_data[2] = (cmdrsp2 << 8) | (cmdrsp1 >> 24); 210*8b659130SJun Nie cmd->resp_data[1] = (cmdrsp1 << 8) | (cmdrsp0 >> 24); 211*8b659130SJun Nie cmd->resp_data[0] = (cmdrsp0 << 8); 212*8b659130SJun Nie } else { 213*8b659130SJun Nie cmd->resp_data[0] = mmio_read_32(reg_base + CMDRSP0); 214*8b659130SJun Nie } 215*8b659130SJun Nie 216*8b659130SJun Nie /* Wait until all of the blocks are transferred */ 217*8b659130SJun Nie if (data) { 218*8b659130SJun Nie flags = DATA_COMPLETE; 219*8b659130SJun Nie do { 220*8b659130SJun Nie state = mmio_read_32(reg_base + INTSTAT); 221*8b659130SJun Nie 222*8b659130SJun Nie if (state & (INTSTATEN_DTOE | DATA_ERR)) { 223*8b659130SJun Nie err = -EIO; 224*8b659130SJun Nie ERROR("imx_usdhc mmc data state 0x%x\n", state); 225*8b659130SJun Nie goto out; 226*8b659130SJun Nie } 227*8b659130SJun Nie } while ((state & flags) != flags); 228*8b659130SJun Nie } 229*8b659130SJun Nie 230*8b659130SJun Nie out: 231*8b659130SJun Nie /* Reset CMD and DATA on error */ 232*8b659130SJun Nie if (err) { 233*8b659130SJun Nie mmio_setbits32(reg_base + SYSCTRL, SYSCTRL_RSTC); 234*8b659130SJun Nie while (mmio_read_32(reg_base + SYSCTRL) & SYSCTRL_RSTC) 235*8b659130SJun Nie ; 236*8b659130SJun Nie 237*8b659130SJun Nie if (data) { 238*8b659130SJun Nie mmio_setbits32(reg_base + SYSCTRL, SYSCTRL_RSTD); 239*8b659130SJun Nie while (mmio_read_32(reg_base + SYSCTRL) & SYSCTRL_RSTD) 240*8b659130SJun Nie ; 241*8b659130SJun Nie } 242*8b659130SJun Nie } 243*8b659130SJun Nie 244*8b659130SJun Nie /* clear all irq status */ 245*8b659130SJun Nie mmio_write_32(reg_base + INTSTAT, 0xffffffff); 246*8b659130SJun Nie 247*8b659130SJun Nie return err; 248*8b659130SJun Nie } 249*8b659130SJun Nie 250*8b659130SJun Nie static int imx_usdhc_set_ios(unsigned int clk, unsigned int width) 251*8b659130SJun Nie { 252*8b659130SJun Nie uintptr_t reg_base = imx_usdhc_params.reg_base; 253*8b659130SJun Nie 254*8b659130SJun Nie imx_usdhc_set_clk(clk); 255*8b659130SJun Nie 256*8b659130SJun Nie if (width == MMC_BUS_WIDTH_4) 257*8b659130SJun Nie mmio_clrsetbits32(reg_base + PROTCTRL, PROTCTRL_WIDTH_MASK, 258*8b659130SJun Nie PROTCTRL_WIDTH_4); 259*8b659130SJun Nie else if (width == MMC_BUS_WIDTH_8) 260*8b659130SJun Nie mmio_clrsetbits32(reg_base + PROTCTRL, PROTCTRL_WIDTH_MASK, 261*8b659130SJun Nie PROTCTRL_WIDTH_8); 262*8b659130SJun Nie 263*8b659130SJun Nie return 0; 264*8b659130SJun Nie } 265*8b659130SJun Nie 266*8b659130SJun Nie static int imx_usdhc_prepare(int lba, uintptr_t buf, size_t size) 267*8b659130SJun Nie { 268*8b659130SJun Nie uintptr_t reg_base = imx_usdhc_params.reg_base; 269*8b659130SJun Nie 270*8b659130SJun Nie mmio_write_32(reg_base + DSADDR, buf); 271*8b659130SJun Nie mmio_write_32(reg_base + BLKATT, 272*8b659130SJun Nie (size / MMC_BLOCK_SIZE) << 16 | MMC_BLOCK_SIZE); 273*8b659130SJun Nie 274*8b659130SJun Nie return 0; 275*8b659130SJun Nie } 276*8b659130SJun Nie 277*8b659130SJun Nie static int imx_usdhc_read(int lba, uintptr_t buf, size_t size) 278*8b659130SJun Nie { 279*8b659130SJun Nie return 0; 280*8b659130SJun Nie } 281*8b659130SJun Nie 282*8b659130SJun Nie static int imx_usdhc_write(int lba, uintptr_t buf, size_t size) 283*8b659130SJun Nie { 284*8b659130SJun Nie return 0; 285*8b659130SJun Nie } 286*8b659130SJun Nie 287*8b659130SJun Nie void imx_usdhc_init(imx_usdhc_params_t *params, 288*8b659130SJun Nie struct mmc_device_info *mmc_dev_info) 289*8b659130SJun Nie { 290*8b659130SJun Nie assert((params != 0) && 291*8b659130SJun Nie ((params->reg_base & MMC_BLOCK_MASK) == 0) && 292*8b659130SJun Nie (params->clk_rate > 0) && 293*8b659130SJun Nie ((params->bus_width == MMC_BUS_WIDTH_1) || 294*8b659130SJun Nie (params->bus_width == MMC_BUS_WIDTH_4) || 295*8b659130SJun Nie (params->bus_width == MMC_BUS_WIDTH_8))); 296*8b659130SJun Nie 297*8b659130SJun Nie memcpy(&imx_usdhc_params, params, sizeof(imx_usdhc_params_t)); 298*8b659130SJun Nie mmc_init(&imx_usdhc_ops, params->clk_rate, params->bus_width, 299*8b659130SJun Nie params->flags, mmc_dev_info); 300*8b659130SJun Nie } 301