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