1 /* 2 * (C) Copyright 2007-2011 3 * Allwinner Technology Co., Ltd. <www.allwinnertech.com> 4 * Aaron <leafy.myeh@allwinnertech.com> 5 * 6 * MMC driver for allwinner sunxi platform. 7 * 8 * SPDX-License-Identifier: GPL-2.0+ 9 */ 10 11 #include <common.h> 12 #include <malloc.h> 13 #include <mmc.h> 14 #include <asm/io.h> 15 #include <asm/arch/clock.h> 16 #include <asm/arch/cpu.h> 17 #include <asm/arch/mmc.h> 18 19 struct sunxi_mmc_host { 20 unsigned mmc_no; 21 uint32_t *mclkreg; 22 unsigned fatal_err; 23 unsigned mod_clk; 24 struct sunxi_mmc *reg; 25 struct mmc_config cfg; 26 }; 27 28 /* support 4 mmc hosts */ 29 struct sunxi_mmc_host mmc_host[4]; 30 31 static int mmc_resource_init(int sdc_no) 32 { 33 struct sunxi_mmc_host *mmchost = &mmc_host[sdc_no]; 34 struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; 35 36 debug("init mmc %d resource\n", sdc_no); 37 38 switch (sdc_no) { 39 case 0: 40 mmchost->reg = (struct sunxi_mmc *)SUNXI_MMC0_BASE; 41 mmchost->mclkreg = &ccm->sd0_clk_cfg; 42 break; 43 case 1: 44 mmchost->reg = (struct sunxi_mmc *)SUNXI_MMC1_BASE; 45 mmchost->mclkreg = &ccm->sd1_clk_cfg; 46 break; 47 case 2: 48 mmchost->reg = (struct sunxi_mmc *)SUNXI_MMC2_BASE; 49 mmchost->mclkreg = &ccm->sd2_clk_cfg; 50 break; 51 case 3: 52 mmchost->reg = (struct sunxi_mmc *)SUNXI_MMC3_BASE; 53 mmchost->mclkreg = &ccm->sd3_clk_cfg; 54 break; 55 default: 56 printf("Wrong mmc number %d\n", sdc_no); 57 return -1; 58 } 59 mmchost->mmc_no = sdc_no; 60 61 return 0; 62 } 63 64 static int mmc_clk_io_on(int sdc_no) 65 { 66 unsigned int pll_clk; 67 unsigned int divider; 68 struct sunxi_mmc_host *mmchost = &mmc_host[sdc_no]; 69 struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; 70 71 debug("init mmc %d clock and io\n", sdc_no); 72 73 /* config ahb clock */ 74 setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MMC(sdc_no)); 75 76 #if defined(CONFIG_SUN6I) 77 /* unassert reset */ 78 setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MMC(sdc_no)); 79 #endif 80 81 /* config mod clock */ 82 pll_clk = clock_get_pll6(); 83 /* should be close to 100 MHz but no more, so round up */ 84 divider = ((pll_clk + 99999999) / 100000000) - 1; 85 writel(CCM_MMC_CTRL_ENABLE | CCM_MMC_CTRL_PLL6 | divider, 86 mmchost->mclkreg); 87 mmchost->mod_clk = pll_clk / (divider + 1); 88 89 return 0; 90 } 91 92 static int mmc_update_clk(struct mmc *mmc) 93 { 94 struct sunxi_mmc_host *mmchost = mmc->priv; 95 unsigned int cmd; 96 unsigned timeout_msecs = 2000; 97 98 cmd = SUNXI_MMC_CMD_START | 99 SUNXI_MMC_CMD_UPCLK_ONLY | 100 SUNXI_MMC_CMD_WAIT_PRE_OVER; 101 writel(cmd, &mmchost->reg->cmd); 102 while (readl(&mmchost->reg->cmd) & SUNXI_MMC_CMD_START) { 103 if (!timeout_msecs--) 104 return -1; 105 udelay(1000); 106 } 107 108 /* clock update sets various irq status bits, clear these */ 109 writel(readl(&mmchost->reg->rint), &mmchost->reg->rint); 110 111 return 0; 112 } 113 114 static int mmc_config_clock(struct mmc *mmc, unsigned div) 115 { 116 struct sunxi_mmc_host *mmchost = mmc->priv; 117 unsigned rval = readl(&mmchost->reg->clkcr); 118 119 /* Disable Clock */ 120 rval &= ~SUNXI_MMC_CLK_ENABLE; 121 writel(rval, &mmchost->reg->clkcr); 122 if (mmc_update_clk(mmc)) 123 return -1; 124 125 /* Change Divider Factor */ 126 rval &= ~SUNXI_MMC_CLK_DIVIDER_MASK; 127 rval |= div; 128 writel(rval, &mmchost->reg->clkcr); 129 if (mmc_update_clk(mmc)) 130 return -1; 131 /* Re-enable Clock */ 132 rval |= SUNXI_MMC_CLK_ENABLE; 133 writel(rval, &mmchost->reg->clkcr); 134 135 if (mmc_update_clk(mmc)) 136 return -1; 137 138 return 0; 139 } 140 141 static void mmc_set_ios(struct mmc *mmc) 142 { 143 struct sunxi_mmc_host *mmchost = mmc->priv; 144 unsigned int clkdiv = 0; 145 146 debug("set ios: bus_width: %x, clock: %d, mod_clk: %d\n", 147 mmc->bus_width, mmc->clock, mmchost->mod_clk); 148 149 /* Change clock first */ 150 clkdiv = (mmchost->mod_clk + (mmc->clock >> 1)) / mmc->clock / 2; 151 if (mmc->clock) { 152 if (mmc_config_clock(mmc, clkdiv)) { 153 mmchost->fatal_err = 1; 154 return; 155 } 156 } 157 158 /* Change bus width */ 159 if (mmc->bus_width == 8) 160 writel(0x2, &mmchost->reg->width); 161 else if (mmc->bus_width == 4) 162 writel(0x1, &mmchost->reg->width); 163 else 164 writel(0x0, &mmchost->reg->width); 165 } 166 167 static int mmc_core_init(struct mmc *mmc) 168 { 169 struct sunxi_mmc_host *mmchost = mmc->priv; 170 171 /* Reset controller */ 172 writel(SUNXI_MMC_GCTRL_RESET, &mmchost->reg->gctrl); 173 udelay(1000); 174 175 return 0; 176 } 177 178 static int mmc_trans_data_by_cpu(struct mmc *mmc, struct mmc_data *data) 179 { 180 struct sunxi_mmc_host *mmchost = mmc->priv; 181 const int reading = !!(data->flags & MMC_DATA_READ); 182 const uint32_t status_bit = reading ? SUNXI_MMC_STATUS_FIFO_EMPTY : 183 SUNXI_MMC_STATUS_FIFO_FULL; 184 unsigned i; 185 unsigned byte_cnt = data->blocksize * data->blocks; 186 unsigned timeout_msecs = 2000; 187 unsigned *buff = (unsigned int *)(reading ? data->dest : data->src); 188 189 /* Always read / write data through the CPU */ 190 setbits_le32(&mmchost->reg->gctrl, SUNXI_MMC_GCTRL_ACCESS_BY_AHB); 191 192 for (i = 0; i < (byte_cnt >> 2); i++) { 193 while (readl(&mmchost->reg->status) & status_bit) { 194 if (!timeout_msecs--) 195 return -1; 196 udelay(1000); 197 } 198 199 if (reading) 200 buff[i] = readl(&mmchost->reg->fifo); 201 else 202 writel(buff[i], &mmchost->reg->fifo); 203 } 204 205 return 0; 206 } 207 208 static int mmc_rint_wait(struct mmc *mmc, unsigned int timeout_msecs, 209 unsigned int done_bit, const char *what) 210 { 211 struct sunxi_mmc_host *mmchost = mmc->priv; 212 unsigned int status; 213 214 do { 215 status = readl(&mmchost->reg->rint); 216 if (!timeout_msecs-- || 217 (status & SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT)) { 218 debug("%s timeout %x\n", what, 219 status & SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT); 220 return TIMEOUT; 221 } 222 udelay(1000); 223 } while (!(status & done_bit)); 224 225 return 0; 226 } 227 228 static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, 229 struct mmc_data *data) 230 { 231 struct sunxi_mmc_host *mmchost = mmc->priv; 232 unsigned int cmdval = SUNXI_MMC_CMD_START; 233 unsigned int timeout_msecs; 234 int error = 0; 235 unsigned int status = 0; 236 unsigned int bytecnt = 0; 237 238 if (mmchost->fatal_err) 239 return -1; 240 if (cmd->resp_type & MMC_RSP_BUSY) 241 debug("mmc cmd %d check rsp busy\n", cmd->cmdidx); 242 if (cmd->cmdidx == 12) 243 return 0; 244 245 if (!cmd->cmdidx) 246 cmdval |= SUNXI_MMC_CMD_SEND_INIT_SEQ; 247 if (cmd->resp_type & MMC_RSP_PRESENT) 248 cmdval |= SUNXI_MMC_CMD_RESP_EXPIRE; 249 if (cmd->resp_type & MMC_RSP_136) 250 cmdval |= SUNXI_MMC_CMD_LONG_RESPONSE; 251 if (cmd->resp_type & MMC_RSP_CRC) 252 cmdval |= SUNXI_MMC_CMD_CHK_RESPONSE_CRC; 253 254 if (data) { 255 if ((u32) data->dest & 0x3) { 256 error = -1; 257 goto out; 258 } 259 260 cmdval |= SUNXI_MMC_CMD_DATA_EXPIRE|SUNXI_MMC_CMD_WAIT_PRE_OVER; 261 if (data->flags & MMC_DATA_WRITE) 262 cmdval |= SUNXI_MMC_CMD_WRITE; 263 if (data->blocks > 1) 264 cmdval |= SUNXI_MMC_CMD_AUTO_STOP; 265 writel(data->blocksize, &mmchost->reg->blksz); 266 writel(data->blocks * data->blocksize, &mmchost->reg->bytecnt); 267 } 268 269 debug("mmc %d, cmd %d(0x%08x), arg 0x%08x\n", mmchost->mmc_no, 270 cmd->cmdidx, cmdval | cmd->cmdidx, cmd->cmdarg); 271 writel(cmd->cmdarg, &mmchost->reg->arg); 272 273 if (!data) 274 writel(cmdval | cmd->cmdidx, &mmchost->reg->cmd); 275 276 /* 277 * transfer data and check status 278 * STATREG[2] : FIFO empty 279 * STATREG[3] : FIFO full 280 */ 281 if (data) { 282 int ret = 0; 283 284 bytecnt = data->blocksize * data->blocks; 285 debug("trans data %d bytes\n", bytecnt); 286 writel(cmdval | cmd->cmdidx, &mmchost->reg->cmd); 287 ret = mmc_trans_data_by_cpu(mmc, data); 288 if (ret) { 289 error = readl(&mmchost->reg->rint) & \ 290 SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT; 291 error = TIMEOUT; 292 goto out; 293 } 294 } 295 296 error = mmc_rint_wait(mmc, 0xfffff, SUNXI_MMC_RINT_COMMAND_DONE, "cmd"); 297 if (error) 298 goto out; 299 300 if (data) { 301 timeout_msecs = 120; 302 debug("cacl timeout %x msec\n", timeout_msecs); 303 error = mmc_rint_wait(mmc, timeout_msecs, 304 data->blocks > 1 ? 305 SUNXI_MMC_RINT_AUTO_COMMAND_DONE : 306 SUNXI_MMC_RINT_DATA_OVER, 307 "data"); 308 if (error) 309 goto out; 310 } 311 312 if (cmd->resp_type & MMC_RSP_BUSY) { 313 timeout_msecs = 2000; 314 do { 315 status = readl(&mmchost->reg->status); 316 if (!timeout_msecs--) { 317 debug("busy timeout\n"); 318 error = TIMEOUT; 319 goto out; 320 } 321 udelay(1000); 322 } while (status & SUNXI_MMC_STATUS_CARD_DATA_BUSY); 323 } 324 325 if (cmd->resp_type & MMC_RSP_136) { 326 cmd->response[0] = readl(&mmchost->reg->resp3); 327 cmd->response[1] = readl(&mmchost->reg->resp2); 328 cmd->response[2] = readl(&mmchost->reg->resp1); 329 cmd->response[3] = readl(&mmchost->reg->resp0); 330 debug("mmc resp 0x%08x 0x%08x 0x%08x 0x%08x\n", 331 cmd->response[3], cmd->response[2], 332 cmd->response[1], cmd->response[0]); 333 } else { 334 cmd->response[0] = readl(&mmchost->reg->resp0); 335 debug("mmc resp 0x%08x\n", cmd->response[0]); 336 } 337 out: 338 if (error < 0) { 339 writel(SUNXI_MMC_GCTRL_RESET, &mmchost->reg->gctrl); 340 mmc_update_clk(mmc); 341 } 342 writel(0xffffffff, &mmchost->reg->rint); 343 writel(readl(&mmchost->reg->gctrl) | SUNXI_MMC_GCTRL_FIFO_RESET, 344 &mmchost->reg->gctrl); 345 346 return error; 347 } 348 349 static const struct mmc_ops sunxi_mmc_ops = { 350 .send_cmd = mmc_send_cmd, 351 .set_ios = mmc_set_ios, 352 .init = mmc_core_init, 353 }; 354 355 int sunxi_mmc_init(int sdc_no) 356 { 357 struct mmc_config *cfg = &mmc_host[sdc_no].cfg; 358 359 memset(&mmc_host[sdc_no], 0, sizeof(struct sunxi_mmc_host)); 360 361 cfg->name = "SUNXI SD/MMC"; 362 cfg->ops = &sunxi_mmc_ops; 363 364 cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; 365 cfg->host_caps = MMC_MODE_4BIT; 366 cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; 367 #if defined(CONFIG_SUN6I) || defined(CONFIG_SUN7I) || defined(CONFIG_SUN8I) 368 cfg->host_caps |= MMC_MODE_HC; 369 #endif 370 cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; 371 372 cfg->f_min = 400000; 373 cfg->f_max = 52000000; 374 375 mmc_resource_init(sdc_no); 376 mmc_clk_io_on(sdc_no); 377 378 if (mmc_create(cfg, &mmc_host[sdc_no]) == NULL) 379 return -1; 380 381 return 0; 382 } 383