1 /* 2 * ARM PrimeCell MultiMedia Card Interface - PL180 3 * 4 * Copyright (C) ST-Ericsson SA 2010 5 * 6 * Author: Ulf Hansson <ulf.hansson@stericsson.com> 7 * Author: Martin Lundholm <martin.xa.lundholm@stericsson.com> 8 * Ported to drivers/mmc/ by: Matt Waddel <matt.waddel@linaro.org> 9 * 10 * This program is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU General Public License as 12 * published by the Free Software Foundation; either version 2 of 13 * the License, or (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 23 * MA 02111-1307 USA 24 */ 25 26 /* #define DEBUG */ 27 28 #include <asm/io.h> 29 #include "common.h" 30 #include <errno.h> 31 #include <mmc.h> 32 #include "arm_pl180_mmci.h" 33 #include <malloc.h> 34 35 struct mmc_host { 36 struct sdi_registers *base; 37 }; 38 39 static int wait_for_command_end(struct mmc *dev, struct mmc_cmd *cmd) 40 { 41 u32 hoststatus, statusmask; 42 struct mmc_host *host = dev->priv; 43 44 statusmask = SDI_STA_CTIMEOUT | SDI_STA_CCRCFAIL; 45 if ((cmd->resp_type & MMC_RSP_PRESENT)) 46 statusmask |= SDI_STA_CMDREND; 47 else 48 statusmask |= SDI_STA_CMDSENT; 49 50 do 51 hoststatus = readl(&host->base->status) & statusmask; 52 while (!hoststatus); 53 54 writel(statusmask, &host->base->status_clear); 55 if (hoststatus & SDI_STA_CTIMEOUT) { 56 printf("CMD%d time out\n", cmd->cmdidx); 57 return -ETIMEDOUT; 58 } else if ((hoststatus & SDI_STA_CCRCFAIL) && 59 (cmd->flags & MMC_RSP_CRC)) { 60 printf("CMD%d CRC error\n", cmd->cmdidx); 61 return -EILSEQ; 62 } 63 64 if (cmd->resp_type & MMC_RSP_PRESENT) { 65 cmd->response[0] = readl(&host->base->response0); 66 cmd->response[1] = readl(&host->base->response1); 67 cmd->response[2] = readl(&host->base->response2); 68 cmd->response[3] = readl(&host->base->response3); 69 debug("CMD%d response[0]:0x%08X, response[1]:0x%08X, " 70 "response[2]:0x%08X, response[3]:0x%08X\n", 71 cmd->cmdidx, cmd->response[0], cmd->response[1], 72 cmd->response[2], cmd->response[3]); 73 } 74 75 return 0; 76 } 77 78 /* send command to the mmc card and wait for results */ 79 static int do_command(struct mmc *dev, struct mmc_cmd *cmd) 80 { 81 int result; 82 u32 sdi_cmd = 0; 83 struct mmc_host *host = dev->priv; 84 85 sdi_cmd = ((cmd->cmdidx & SDI_CMD_CMDINDEX_MASK) | SDI_CMD_CPSMEN); 86 87 if (cmd->resp_type) { 88 sdi_cmd |= SDI_CMD_WAITRESP; 89 if (cmd->resp_type & MMC_RSP_136) 90 sdi_cmd |= SDI_CMD_LONGRESP; 91 } 92 93 writel((u32)cmd->cmdarg, &host->base->argument); 94 udelay(COMMAND_REG_DELAY); 95 writel(sdi_cmd, &host->base->command); 96 result = wait_for_command_end(dev, cmd); 97 98 /* After CMD2 set RCA to a none zero value. */ 99 if ((result == 0) && (cmd->cmdidx == MMC_CMD_ALL_SEND_CID)) 100 dev->rca = 10; 101 102 /* After CMD3 open drain is switched off and push pull is used. */ 103 if ((result == 0) && (cmd->cmdidx == MMC_CMD_SET_RELATIVE_ADDR)) { 104 u32 sdi_pwr = readl(&host->base->power) & ~SDI_PWR_OPD; 105 writel(sdi_pwr, &host->base->power); 106 } 107 108 return result; 109 } 110 111 static int read_bytes(struct mmc *dev, u32 *dest, u32 blkcount, u32 blksize) 112 { 113 u32 *tempbuff = dest; 114 int i; 115 u64 xfercount = blkcount * blksize; 116 struct mmc_host *host = dev->priv; 117 u32 status, status_err; 118 119 debug("read_bytes: blkcount=%u blksize=%u\n", blkcount, blksize); 120 121 status = readl(&host->base->status); 122 status_err = status & (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | 123 SDI_STA_RXOVERR); 124 while (!status_err && 125 (xfercount >= SDI_FIFO_BURST_SIZE * sizeof(u32))) { 126 if (status & SDI_STA_RXFIFOBR) { 127 for (i = 0; i < SDI_FIFO_BURST_SIZE; i++) 128 *(tempbuff + i) = readl(&host->base->fifo); 129 tempbuff += SDI_FIFO_BURST_SIZE; 130 xfercount -= SDI_FIFO_BURST_SIZE * sizeof(u32); 131 } 132 status = readl(&host->base->status); 133 status_err = status & 134 (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | SDI_STA_RXOVERR); 135 } 136 137 if (status & SDI_STA_DTIMEOUT) { 138 printf("Read data timed out, xfercount: %llu, status: 0x%08X\n", 139 xfercount, status); 140 return -ETIMEDOUT; 141 } else if (status & SDI_STA_DCRCFAIL) { 142 printf("Read data blk CRC error: 0x%x\n", status); 143 return -EILSEQ; 144 } else if (status & SDI_STA_RXOVERR) { 145 printf("Read data RX overflow error\n"); 146 return -EIO; 147 } 148 149 while ((!status_err) && (xfercount >= sizeof(u32))) { 150 if (status & SDI_STA_RXDAVL) { 151 *(tempbuff) = readl(&host->base->fifo); 152 tempbuff++; 153 xfercount -= sizeof(u32); 154 } 155 status = readl(&host->base->status); 156 status_err = status & (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | 157 SDI_STA_RXOVERR); 158 } 159 160 status_err = status & 161 (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | SDI_STA_DBCKEND | 162 SDI_STA_RXOVERR); 163 while (!status_err) { 164 status = readl(&host->base->status); 165 status_err = status & 166 (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | SDI_STA_DBCKEND | 167 SDI_STA_RXOVERR); 168 } 169 170 if (status & SDI_STA_DTIMEOUT) { 171 printf("Read data timed out, xfercount: %llu, status: 0x%08X\n", 172 xfercount, status); 173 return -ETIMEDOUT; 174 } else if (status & SDI_STA_DCRCFAIL) { 175 printf("Read data bytes CRC error: 0x%x\n", status); 176 return -EILSEQ; 177 } else if (status & SDI_STA_RXOVERR) { 178 printf("Read data RX overflow error\n"); 179 return -EIO; 180 } 181 182 writel(SDI_ICR_MASK, &host->base->status_clear); 183 184 if (xfercount) { 185 printf("Read data error, xfercount: %llu\n", xfercount); 186 return -ENOBUFS; 187 } 188 189 return 0; 190 } 191 192 static int write_bytes(struct mmc *dev, u32 *src, u32 blkcount, u32 blksize) 193 { 194 u32 *tempbuff = src; 195 int i; 196 u64 xfercount = blkcount * blksize; 197 struct mmc_host *host = dev->priv; 198 u32 status, status_err; 199 200 debug("write_bytes: blkcount=%u blksize=%u\n", blkcount, blksize); 201 202 status = readl(&host->base->status); 203 status_err = status & (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT); 204 while (!status_err && xfercount) { 205 if (status & SDI_STA_TXFIFOBW) { 206 if (xfercount >= SDI_FIFO_BURST_SIZE * sizeof(u32)) { 207 for (i = 0; i < SDI_FIFO_BURST_SIZE; i++) 208 writel(*(tempbuff + i), 209 &host->base->fifo); 210 tempbuff += SDI_FIFO_BURST_SIZE; 211 xfercount -= SDI_FIFO_BURST_SIZE * sizeof(u32); 212 } else { 213 while (xfercount >= sizeof(u32)) { 214 writel(*(tempbuff), &host->base->fifo); 215 tempbuff++; 216 xfercount -= sizeof(u32); 217 } 218 } 219 } 220 status = readl(&host->base->status); 221 status_err = status & (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT); 222 } 223 224 status_err = status & 225 (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | SDI_STA_DBCKEND); 226 while (!status_err) { 227 status = readl(&host->base->status); 228 status_err = status & 229 (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | SDI_STA_DBCKEND); 230 } 231 232 if (status & SDI_STA_DTIMEOUT) { 233 printf("Write data timed out, xfercount:%llu,status:0x%08X\n", 234 xfercount, status); 235 return -ETIMEDOUT; 236 } else if (status & SDI_STA_DCRCFAIL) { 237 printf("Write data CRC error\n"); 238 return -EILSEQ; 239 } 240 241 writel(SDI_ICR_MASK, &host->base->status_clear); 242 243 if (xfercount) { 244 printf("Write data error, xfercount:%llu", xfercount); 245 return -ENOBUFS; 246 } 247 248 return 0; 249 } 250 251 static int do_data_transfer(struct mmc *dev, 252 struct mmc_cmd *cmd, 253 struct mmc_data *data) 254 { 255 int error = -ETIMEDOUT; 256 struct mmc_host *host = dev->priv; 257 u32 blksz = 0; 258 u32 data_ctrl = 0; 259 u32 data_len = (u32) (data->blocks * data->blocksize); 260 261 blksz = (ffs(data->blocksize) - 1); 262 data_ctrl |= ((blksz << 4) & SDI_DCTRL_DBLKSIZE_MASK); 263 data_ctrl |= SDI_DCTRL_DTEN; 264 265 writel(SDI_DTIMER_DEFAULT, &host->base->datatimer); 266 writel(data_len, &host->base->datalength); 267 udelay(DATA_REG_DELAY); 268 269 if (data->flags & MMC_DATA_READ) { 270 data_ctrl |= SDI_DCTRL_DTDIR_IN; 271 writel(data_ctrl, &host->base->datactrl); 272 273 error = do_command(dev, cmd); 274 if (error) 275 return error; 276 277 error = read_bytes(dev, (u32 *)data->dest, (u32)data->blocks, 278 (u32)data->blocksize); 279 } else if (data->flags & MMC_DATA_WRITE) { 280 error = do_command(dev, cmd); 281 if (error) 282 return error; 283 284 writel(data_ctrl, &host->base->datactrl); 285 error = write_bytes(dev, (u32 *)data->src, (u32)data->blocks, 286 (u32)data->blocksize); 287 } 288 289 return error; 290 } 291 292 static int host_request(struct mmc *dev, 293 struct mmc_cmd *cmd, 294 struct mmc_data *data) 295 { 296 int result; 297 298 if (data) 299 result = do_data_transfer(dev, cmd, data); 300 else 301 result = do_command(dev, cmd); 302 303 return result; 304 } 305 306 /* MMC uses open drain drivers in the enumeration phase */ 307 static int mmc_host_reset(struct mmc *dev) 308 { 309 struct mmc_host *host = dev->priv; 310 u32 sdi_u32 = SDI_PWR_OPD | SDI_PWR_PWRCTRL_ON; 311 312 writel(sdi_u32, &host->base->power); 313 314 return 0; 315 } 316 317 static void host_set_ios(struct mmc *dev) 318 { 319 struct mmc_host *host = dev->priv; 320 u32 sdi_clkcr; 321 322 sdi_clkcr = readl(&host->base->clock); 323 324 /* Ramp up the clock rate */ 325 if (dev->clock) { 326 u32 clkdiv = 0; 327 328 if (dev->clock >= dev->f_max) 329 dev->clock = dev->f_max; 330 331 clkdiv = ((ARM_MCLK / dev->clock) / 2) - 1; 332 333 if (clkdiv > SDI_CLKCR_CLKDIV_MASK) 334 clkdiv = SDI_CLKCR_CLKDIV_MASK; 335 336 sdi_clkcr &= ~(SDI_CLKCR_CLKDIV_MASK); 337 sdi_clkcr |= clkdiv; 338 } 339 340 /* Set the bus width */ 341 if (dev->bus_width) { 342 u32 buswidth = 0; 343 344 switch (dev->bus_width) { 345 case 1: 346 buswidth |= SDI_CLKCR_WIDBUS_1; 347 break; 348 case 4: 349 buswidth |= SDI_CLKCR_WIDBUS_4; 350 break; 351 default: 352 printf("Invalid bus width\n"); 353 break; 354 } 355 sdi_clkcr &= ~(SDI_CLKCR_WIDBUS_MASK); 356 sdi_clkcr |= buswidth; 357 } 358 359 writel(sdi_clkcr, &host->base->clock); 360 udelay(CLK_CHANGE_DELAY); 361 } 362 363 struct mmc *alloc_mmc_struct(void) 364 { 365 struct mmc_host *host = NULL; 366 struct mmc *mmc_device = NULL; 367 368 host = malloc(sizeof(struct mmc_host)); 369 if (!host) 370 return NULL; 371 372 mmc_device = malloc(sizeof(struct mmc)); 373 if (!mmc_device) 374 goto err; 375 376 mmc_device->priv = host; 377 return mmc_device; 378 379 err: 380 free(host); 381 return NULL; 382 } 383 384 /* 385 * mmc_host_init - initialize the mmc controller. 386 * Set initial clock and power for mmc slot. 387 * Initialize mmc struct and register with mmc framework. 388 */ 389 static int arm_pl180_mmci_host_init(struct mmc *dev) 390 { 391 struct mmc_host *host = dev->priv; 392 u32 sdi_u32; 393 394 host->base = (struct sdi_registers *)CONFIG_ARM_PL180_MMCI_BASE; 395 396 /* Initially set power-on, full voltage & MMCI read */ 397 sdi_u32 = INIT_PWR; 398 writel(sdi_u32, &host->base->power); 399 400 /* setting clk freq 505KHz */ 401 sdi_u32 = SDI_CLKCR_CLKDIV_INIT | SDI_CLKCR_CLKEN; 402 writel(sdi_u32, &host->base->clock); 403 udelay(CLK_CHANGE_DELAY); 404 405 /* Disable mmc interrupts */ 406 sdi_u32 = readl(&host->base->mask0) & ~SDI_MASK0_MASK; 407 writel(sdi_u32, &host->base->mask0); 408 409 sprintf(dev->name, "MMC"); 410 dev->clock = ARM_MCLK / (2 * (SDI_CLKCR_CLKDIV_INIT + 1)); 411 dev->send_cmd = host_request; 412 dev->set_ios = host_set_ios; 413 dev->init = mmc_host_reset; 414 dev->host_caps = 0; 415 dev->voltages = VOLTAGE_WINDOW_MMC; 416 dev->f_min = dev->clock; 417 dev->f_max = CONFIG_ARM_PL180_MMCI_CLOCK_FREQ; 418 419 return 0; 420 } 421 422 int arm_pl180_mmci_init(void) 423 { 424 int error; 425 struct mmc *dev; 426 427 dev = alloc_mmc_struct(); 428 if (!dev) 429 return -1; 430 431 error = arm_pl180_mmci_host_init(dev); 432 if (error) { 433 printf("mmci_host_init error - %d\n", error); 434 return -1; 435 } 436 437 dev->b_max = 0; 438 439 mmc_register(dev); 440 debug("registered mmc interface number is:%d\n", dev->block_dev.dev); 441 442 return 0; 443 } 444