1272cc70bSAndy Fleming /* 2272cc70bSAndy Fleming * Copyright 2008, Freescale Semiconductor, Inc 3272cc70bSAndy Fleming * Andy Fleming 4272cc70bSAndy Fleming * 5272cc70bSAndy Fleming * Based vaguely on the Linux code 6272cc70bSAndy Fleming * 71a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 8272cc70bSAndy Fleming */ 9272cc70bSAndy Fleming 10272cc70bSAndy Fleming #include <config.h> 11272cc70bSAndy Fleming #include <common.h> 12272cc70bSAndy Fleming #include <command.h> 13272cc70bSAndy Fleming #include <mmc.h> 14272cc70bSAndy Fleming #include <part.h> 15272cc70bSAndy Fleming #include <malloc.h> 16272cc70bSAndy Fleming #include <linux/list.h> 179b1f942cSRabin Vincent #include <div64.h> 18272cc70bSAndy Fleming 19ce0fbcd2SMatt Waddel /* Set block count limit because of 16 bit register limit on some hardware*/ 20ce0fbcd2SMatt Waddel #ifndef CONFIG_SYS_MMC_MAX_BLK_COUNT 21ce0fbcd2SMatt Waddel #define CONFIG_SYS_MMC_MAX_BLK_COUNT 65535 22ce0fbcd2SMatt Waddel #endif 23ce0fbcd2SMatt Waddel 24272cc70bSAndy Fleming static struct list_head mmc_devices; 25272cc70bSAndy Fleming static int cur_dev_num = -1; 26272cc70bSAndy Fleming 27d23d8d7eSNikita Kiryanov int __weak board_mmc_getwp(struct mmc *mmc) 28d23d8d7eSNikita Kiryanov { 29d23d8d7eSNikita Kiryanov return -1; 30d23d8d7eSNikita Kiryanov } 31d23d8d7eSNikita Kiryanov 32d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc) 33d23d8d7eSNikita Kiryanov { 34d23d8d7eSNikita Kiryanov int wp; 35d23d8d7eSNikita Kiryanov 36d23d8d7eSNikita Kiryanov wp = board_mmc_getwp(mmc); 37d23d8d7eSNikita Kiryanov 38d4e1da4eSPeter Korsgaard if (wp < 0) { 39d4e1da4eSPeter Korsgaard if (mmc->getwp) 40d23d8d7eSNikita Kiryanov wp = mmc->getwp(mmc); 41d4e1da4eSPeter Korsgaard else 42d4e1da4eSPeter Korsgaard wp = 0; 43d4e1da4eSPeter Korsgaard } 44d23d8d7eSNikita Kiryanov 45d23d8d7eSNikita Kiryanov return wp; 46d23d8d7eSNikita Kiryanov } 47d23d8d7eSNikita Kiryanov 48314284b1SThierry Reding int __board_mmc_getcd(struct mmc *mmc) { 4911fdade2SStefano Babic return -1; 5011fdade2SStefano Babic } 5111fdade2SStefano Babic 52314284b1SThierry Reding int board_mmc_getcd(struct mmc *mmc)__attribute__((weak, 5311fdade2SStefano Babic alias("__board_mmc_getcd"))); 5411fdade2SStefano Babic 55fdbb873eSKim Phillips static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, 56fdbb873eSKim Phillips struct mmc_data *data) 57272cc70bSAndy Fleming { 585db2fe3aSRaffaele Recalcati int ret; 598635ff9eSMarek Vasut 608635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE 615db2fe3aSRaffaele Recalcati int i; 625db2fe3aSRaffaele Recalcati u8 *ptr; 635db2fe3aSRaffaele Recalcati 645db2fe3aSRaffaele Recalcati printf("CMD_SEND:%d\n", cmd->cmdidx); 655db2fe3aSRaffaele Recalcati printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg); 665db2fe3aSRaffaele Recalcati ret = mmc->send_cmd(mmc, cmd, data); 675db2fe3aSRaffaele Recalcati switch (cmd->resp_type) { 685db2fe3aSRaffaele Recalcati case MMC_RSP_NONE: 695db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_NONE\n"); 705db2fe3aSRaffaele Recalcati break; 715db2fe3aSRaffaele Recalcati case MMC_RSP_R1: 725db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n", 735db2fe3aSRaffaele Recalcati cmd->response[0]); 745db2fe3aSRaffaele Recalcati break; 755db2fe3aSRaffaele Recalcati case MMC_RSP_R1b: 765db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n", 775db2fe3aSRaffaele Recalcati cmd->response[0]); 785db2fe3aSRaffaele Recalcati break; 795db2fe3aSRaffaele Recalcati case MMC_RSP_R2: 805db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R2\t\t 0x%08X \n", 815db2fe3aSRaffaele Recalcati cmd->response[0]); 825db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 835db2fe3aSRaffaele Recalcati cmd->response[1]); 845db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 855db2fe3aSRaffaele Recalcati cmd->response[2]); 865db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 875db2fe3aSRaffaele Recalcati cmd->response[3]); 885db2fe3aSRaffaele Recalcati printf("\n"); 895db2fe3aSRaffaele Recalcati printf("\t\t\t\t\tDUMPING DATA\n"); 905db2fe3aSRaffaele Recalcati for (i = 0; i < 4; i++) { 915db2fe3aSRaffaele Recalcati int j; 925db2fe3aSRaffaele Recalcati printf("\t\t\t\t\t%03d - ", i*4); 93146bec79SDirk Behme ptr = (u8 *)&cmd->response[i]; 945db2fe3aSRaffaele Recalcati ptr += 3; 955db2fe3aSRaffaele Recalcati for (j = 0; j < 4; j++) 965db2fe3aSRaffaele Recalcati printf("%02X ", *ptr--); 975db2fe3aSRaffaele Recalcati printf("\n"); 985db2fe3aSRaffaele Recalcati } 995db2fe3aSRaffaele Recalcati break; 1005db2fe3aSRaffaele Recalcati case MMC_RSP_R3: 1015db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n", 1025db2fe3aSRaffaele Recalcati cmd->response[0]); 1035db2fe3aSRaffaele Recalcati break; 1045db2fe3aSRaffaele Recalcati default: 1055db2fe3aSRaffaele Recalcati printf("\t\tERROR MMC rsp not supported\n"); 1065db2fe3aSRaffaele Recalcati break; 1075db2fe3aSRaffaele Recalcati } 1085db2fe3aSRaffaele Recalcati #else 1098635ff9eSMarek Vasut ret = mmc->send_cmd(mmc, cmd, data); 1105db2fe3aSRaffaele Recalcati #endif 1118635ff9eSMarek Vasut return ret; 112272cc70bSAndy Fleming } 113272cc70bSAndy Fleming 114fdbb873eSKim Phillips static int mmc_send_status(struct mmc *mmc, int timeout) 1155d4fc8d9SRaffaele Recalcati { 1165d4fc8d9SRaffaele Recalcati struct mmc_cmd cmd; 117d617c426SJan Kloetzke int err, retries = 5; 1185d4fc8d9SRaffaele Recalcati #ifdef CONFIG_MMC_TRACE 1195d4fc8d9SRaffaele Recalcati int status; 1205d4fc8d9SRaffaele Recalcati #endif 1215d4fc8d9SRaffaele Recalcati 1225d4fc8d9SRaffaele Recalcati cmd.cmdidx = MMC_CMD_SEND_STATUS; 1235d4fc8d9SRaffaele Recalcati cmd.resp_type = MMC_RSP_R1; 124aaf3d41aSMarek Vasut if (!mmc_host_is_spi(mmc)) 125aaf3d41aSMarek Vasut cmd.cmdarg = mmc->rca << 16; 1265d4fc8d9SRaffaele Recalcati 1275d4fc8d9SRaffaele Recalcati do { 1285d4fc8d9SRaffaele Recalcati err = mmc_send_cmd(mmc, &cmd, NULL); 129d617c426SJan Kloetzke if (!err) { 130d617c426SJan Kloetzke if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) && 131d617c426SJan Kloetzke (cmd.response[0] & MMC_STATUS_CURR_STATE) != 132d617c426SJan Kloetzke MMC_STATE_PRG) 1335d4fc8d9SRaffaele Recalcati break; 134d617c426SJan Kloetzke else if (cmd.response[0] & MMC_STATUS_MASK) { 135*56196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 136d617c426SJan Kloetzke printf("Status Error: 0x%08X\n", 137d617c426SJan Kloetzke cmd.response[0]); 138*56196826SPaul Burton #endif 139d617c426SJan Kloetzke return COMM_ERR; 140d617c426SJan Kloetzke } 141d617c426SJan Kloetzke } else if (--retries < 0) 142d617c426SJan Kloetzke return err; 1435d4fc8d9SRaffaele Recalcati 1445d4fc8d9SRaffaele Recalcati udelay(1000); 1455d4fc8d9SRaffaele Recalcati 1465d4fc8d9SRaffaele Recalcati } while (timeout--); 1475d4fc8d9SRaffaele Recalcati 1485db2fe3aSRaffaele Recalcati #ifdef CONFIG_MMC_TRACE 1495db2fe3aSRaffaele Recalcati status = (cmd.response[0] & MMC_STATUS_CURR_STATE) >> 9; 1505db2fe3aSRaffaele Recalcati printf("CURR STATE:%d\n", status); 1515db2fe3aSRaffaele Recalcati #endif 1525b0c942fSJongman Heo if (timeout <= 0) { 153*56196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 1545d4fc8d9SRaffaele Recalcati printf("Timeout waiting card ready\n"); 155*56196826SPaul Burton #endif 1565d4fc8d9SRaffaele Recalcati return TIMEOUT; 1575d4fc8d9SRaffaele Recalcati } 1585d4fc8d9SRaffaele Recalcati 1595d4fc8d9SRaffaele Recalcati return 0; 1605d4fc8d9SRaffaele Recalcati } 1615d4fc8d9SRaffaele Recalcati 162fdbb873eSKim Phillips static int mmc_set_blocklen(struct mmc *mmc, int len) 163272cc70bSAndy Fleming { 164272cc70bSAndy Fleming struct mmc_cmd cmd; 165272cc70bSAndy Fleming 166272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SET_BLOCKLEN; 167272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 168272cc70bSAndy Fleming cmd.cmdarg = len; 169272cc70bSAndy Fleming 170272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, NULL); 171272cc70bSAndy Fleming } 172272cc70bSAndy Fleming 173272cc70bSAndy Fleming struct mmc *find_mmc_device(int dev_num) 174272cc70bSAndy Fleming { 175272cc70bSAndy Fleming struct mmc *m; 176272cc70bSAndy Fleming struct list_head *entry; 177272cc70bSAndy Fleming 178272cc70bSAndy Fleming list_for_each(entry, &mmc_devices) { 179272cc70bSAndy Fleming m = list_entry(entry, struct mmc, link); 180272cc70bSAndy Fleming 181272cc70bSAndy Fleming if (m->block_dev.dev == dev_num) 182272cc70bSAndy Fleming return m; 183272cc70bSAndy Fleming } 184272cc70bSAndy Fleming 185*56196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 186272cc70bSAndy Fleming printf("MMC Device %d not found\n", dev_num); 187*56196826SPaul Burton #endif 188272cc70bSAndy Fleming 189272cc70bSAndy Fleming return NULL; 190272cc70bSAndy Fleming } 191272cc70bSAndy Fleming 192e6f99a56SLei Wen static ulong mmc_erase_t(struct mmc *mmc, ulong start, lbaint_t blkcnt) 193e6f99a56SLei Wen { 194e6f99a56SLei Wen struct mmc_cmd cmd; 195e6f99a56SLei Wen ulong end; 196e6f99a56SLei Wen int err, start_cmd, end_cmd; 197e6f99a56SLei Wen 198e6f99a56SLei Wen if (mmc->high_capacity) 199e6f99a56SLei Wen end = start + blkcnt - 1; 200e6f99a56SLei Wen else { 201e6f99a56SLei Wen end = (start + blkcnt - 1) * mmc->write_bl_len; 202e6f99a56SLei Wen start *= mmc->write_bl_len; 203e6f99a56SLei Wen } 204e6f99a56SLei Wen 205e6f99a56SLei Wen if (IS_SD(mmc)) { 206e6f99a56SLei Wen start_cmd = SD_CMD_ERASE_WR_BLK_START; 207e6f99a56SLei Wen end_cmd = SD_CMD_ERASE_WR_BLK_END; 208e6f99a56SLei Wen } else { 209e6f99a56SLei Wen start_cmd = MMC_CMD_ERASE_GROUP_START; 210e6f99a56SLei Wen end_cmd = MMC_CMD_ERASE_GROUP_END; 211e6f99a56SLei Wen } 212e6f99a56SLei Wen 213e6f99a56SLei Wen cmd.cmdidx = start_cmd; 214e6f99a56SLei Wen cmd.cmdarg = start; 215e6f99a56SLei Wen cmd.resp_type = MMC_RSP_R1; 216e6f99a56SLei Wen 217e6f99a56SLei Wen err = mmc_send_cmd(mmc, &cmd, NULL); 218e6f99a56SLei Wen if (err) 219e6f99a56SLei Wen goto err_out; 220e6f99a56SLei Wen 221e6f99a56SLei Wen cmd.cmdidx = end_cmd; 222e6f99a56SLei Wen cmd.cmdarg = end; 223e6f99a56SLei Wen 224e6f99a56SLei Wen err = mmc_send_cmd(mmc, &cmd, NULL); 225e6f99a56SLei Wen if (err) 226e6f99a56SLei Wen goto err_out; 227e6f99a56SLei Wen 228e6f99a56SLei Wen cmd.cmdidx = MMC_CMD_ERASE; 229e6f99a56SLei Wen cmd.cmdarg = SECURE_ERASE; 230e6f99a56SLei Wen cmd.resp_type = MMC_RSP_R1b; 231e6f99a56SLei Wen 232e6f99a56SLei Wen err = mmc_send_cmd(mmc, &cmd, NULL); 233e6f99a56SLei Wen if (err) 234e6f99a56SLei Wen goto err_out; 235e6f99a56SLei Wen 236e6f99a56SLei Wen return 0; 237e6f99a56SLei Wen 238e6f99a56SLei Wen err_out: 239*56196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 240e6f99a56SLei Wen puts("mmc erase failed\n"); 241*56196826SPaul Burton #endif 242e6f99a56SLei Wen return err; 243e6f99a56SLei Wen } 244e6f99a56SLei Wen 245e6f99a56SLei Wen static unsigned long 246ff8fef56SSascha Silbe mmc_berase(int dev_num, lbaint_t start, lbaint_t blkcnt) 247e6f99a56SLei Wen { 248e6f99a56SLei Wen int err = 0; 249e6f99a56SLei Wen struct mmc *mmc = find_mmc_device(dev_num); 250e6f99a56SLei Wen lbaint_t blk = 0, blk_r = 0; 251d2d8afaeSJerry Huang int timeout = 1000; 252e6f99a56SLei Wen 253e6f99a56SLei Wen if (!mmc) 254e6f99a56SLei Wen return -1; 255e6f99a56SLei Wen 256*56196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 257e6f99a56SLei Wen if ((start % mmc->erase_grp_size) || (blkcnt % mmc->erase_grp_size)) 258e6f99a56SLei Wen printf("\n\nCaution! Your devices Erase group is 0x%x\n" 259ff8fef56SSascha Silbe "The erase range would be change to " 260ff8fef56SSascha Silbe "0x" LBAF "~0x" LBAF "\n\n", 261e6f99a56SLei Wen mmc->erase_grp_size, start & ~(mmc->erase_grp_size - 1), 262e6f99a56SLei Wen ((start + blkcnt + mmc->erase_grp_size) 263e6f99a56SLei Wen & ~(mmc->erase_grp_size - 1)) - 1); 264*56196826SPaul Burton #endif 265e6f99a56SLei Wen 266e6f99a56SLei Wen while (blk < blkcnt) { 267e6f99a56SLei Wen blk_r = ((blkcnt - blk) > mmc->erase_grp_size) ? 268e6f99a56SLei Wen mmc->erase_grp_size : (blkcnt - blk); 269e6f99a56SLei Wen err = mmc_erase_t(mmc, start + blk, blk_r); 270e6f99a56SLei Wen if (err) 271e6f99a56SLei Wen break; 272e6f99a56SLei Wen 273e6f99a56SLei Wen blk += blk_r; 274d2d8afaeSJerry Huang 275d2d8afaeSJerry Huang /* Waiting for the ready status */ 276d2d8afaeSJerry Huang if (mmc_send_status(mmc, timeout)) 277d2d8afaeSJerry Huang return 0; 278e6f99a56SLei Wen } 279e6f99a56SLei Wen 280e6f99a56SLei Wen return blk; 281e6f99a56SLei Wen } 282e6f99a56SLei Wen 283272cc70bSAndy Fleming static ulong 284ff8fef56SSascha Silbe mmc_write_blocks(struct mmc *mmc, lbaint_t start, lbaint_t blkcnt, const void*src) 285272cc70bSAndy Fleming { 286272cc70bSAndy Fleming struct mmc_cmd cmd; 287272cc70bSAndy Fleming struct mmc_data data; 2885d4fc8d9SRaffaele Recalcati int timeout = 1000; 289272cc70bSAndy Fleming 290d2bf29e3SLei Wen if ((start + blkcnt) > mmc->block_dev.lba) { 291*56196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 292ff8fef56SSascha Silbe printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n", 293d2bf29e3SLei Wen start + blkcnt, mmc->block_dev.lba); 294*56196826SPaul Burton #endif 295d2bf29e3SLei Wen return 0; 296d2bf29e3SLei Wen } 297272cc70bSAndy Fleming 298a586c0aaSRuud Commandeur if (blkcnt == 0) 299a586c0aaSRuud Commandeur return 0; 300a586c0aaSRuud Commandeur else if (blkcnt == 1) 301272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_WRITE_SINGLE_BLOCK; 302a586c0aaSRuud Commandeur else 303a586c0aaSRuud Commandeur cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK; 304272cc70bSAndy Fleming 305272cc70bSAndy Fleming if (mmc->high_capacity) 306272cc70bSAndy Fleming cmd.cmdarg = start; 307272cc70bSAndy Fleming else 308def412b6SSteve Sakoman cmd.cmdarg = start * mmc->write_bl_len; 309272cc70bSAndy Fleming 310272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 311272cc70bSAndy Fleming 312272cc70bSAndy Fleming data.src = src; 313272cc70bSAndy Fleming data.blocks = blkcnt; 314def412b6SSteve Sakoman data.blocksize = mmc->write_bl_len; 315272cc70bSAndy Fleming data.flags = MMC_DATA_WRITE; 316272cc70bSAndy Fleming 317def412b6SSteve Sakoman if (mmc_send_cmd(mmc, &cmd, &data)) { 318*56196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 319def412b6SSteve Sakoman printf("mmc write failed\n"); 320*56196826SPaul Burton #endif 321def412b6SSteve Sakoman return 0; 322272cc70bSAndy Fleming } 323272cc70bSAndy Fleming 324d52ebf10SThomas Chou /* SPI multiblock writes terminate using a special 325d52ebf10SThomas Chou * token, not a STOP_TRANSMISSION request. 326d52ebf10SThomas Chou */ 327d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc) && blkcnt > 1) { 328272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; 329272cc70bSAndy Fleming cmd.cmdarg = 0; 330272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1b; 331def412b6SSteve Sakoman if (mmc_send_cmd(mmc, &cmd, NULL)) { 332*56196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 333def412b6SSteve Sakoman printf("mmc fail to send stop cmd\n"); 334*56196826SPaul Burton #endif 335def412b6SSteve Sakoman return 0; 336272cc70bSAndy Fleming } 33793ad0d18SJan Kloetzke } 3385d4fc8d9SRaffaele Recalcati 3395d4fc8d9SRaffaele Recalcati /* Waiting for the ready status */ 34093ad0d18SJan Kloetzke if (mmc_send_status(mmc, timeout)) 34193ad0d18SJan Kloetzke return 0; 3420158126eSLei Wen 3430158126eSLei Wen return blkcnt; 3440158126eSLei Wen } 3450158126eSLei Wen 3460158126eSLei Wen static ulong 347ff8fef56SSascha Silbe mmc_bwrite(int dev_num, lbaint_t start, lbaint_t blkcnt, const void*src) 3480158126eSLei Wen { 3490158126eSLei Wen lbaint_t cur, blocks_todo = blkcnt; 3500158126eSLei Wen 351def412b6SSteve Sakoman struct mmc *mmc = find_mmc_device(dev_num); 3520158126eSLei Wen if (!mmc) 353def412b6SSteve Sakoman return 0; 3540158126eSLei Wen 355def412b6SSteve Sakoman if (mmc_set_blocklen(mmc, mmc->write_bl_len)) 356def412b6SSteve Sakoman return 0; 3570158126eSLei Wen 3580158126eSLei Wen do { 3598feafcc4SJohn Rigby cur = (blocks_todo > mmc->b_max) ? mmc->b_max : blocks_todo; 3600158126eSLei Wen if(mmc_write_blocks(mmc, start, cur, src) != cur) 361def412b6SSteve Sakoman return 0; 3620158126eSLei Wen blocks_todo -= cur; 3630158126eSLei Wen start += cur; 3640158126eSLei Wen src += cur * mmc->write_bl_len; 3650158126eSLei Wen } while (blocks_todo > 0); 366272cc70bSAndy Fleming 367272cc70bSAndy Fleming return blkcnt; 368272cc70bSAndy Fleming } 369272cc70bSAndy Fleming 370ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start, 371fdbb873eSKim Phillips lbaint_t blkcnt) 372272cc70bSAndy Fleming { 373272cc70bSAndy Fleming struct mmc_cmd cmd; 374272cc70bSAndy Fleming struct mmc_data data; 375272cc70bSAndy Fleming 3764a1a06bcSAlagu Sankar if (blkcnt > 1) 3774a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; 3784a1a06bcSAlagu Sankar else 379272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK; 380272cc70bSAndy Fleming 381272cc70bSAndy Fleming if (mmc->high_capacity) 3824a1a06bcSAlagu Sankar cmd.cmdarg = start; 383272cc70bSAndy Fleming else 3844a1a06bcSAlagu Sankar cmd.cmdarg = start * mmc->read_bl_len; 385272cc70bSAndy Fleming 386272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 387272cc70bSAndy Fleming 388272cc70bSAndy Fleming data.dest = dst; 3894a1a06bcSAlagu Sankar data.blocks = blkcnt; 390272cc70bSAndy Fleming data.blocksize = mmc->read_bl_len; 391272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 392272cc70bSAndy Fleming 3934a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, &data)) 3944a1a06bcSAlagu Sankar return 0; 3954a1a06bcSAlagu Sankar 3964a1a06bcSAlagu Sankar if (blkcnt > 1) { 3974a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; 3984a1a06bcSAlagu Sankar cmd.cmdarg = 0; 3994a1a06bcSAlagu Sankar cmd.resp_type = MMC_RSP_R1b; 4004a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, NULL)) { 401*56196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 4024a1a06bcSAlagu Sankar printf("mmc fail to send stop cmd\n"); 403*56196826SPaul Burton #endif 4044a1a06bcSAlagu Sankar return 0; 4054a1a06bcSAlagu Sankar } 406272cc70bSAndy Fleming } 407272cc70bSAndy Fleming 4084a1a06bcSAlagu Sankar return blkcnt; 409272cc70bSAndy Fleming } 410272cc70bSAndy Fleming 411ff8fef56SSascha Silbe static ulong mmc_bread(int dev_num, lbaint_t start, lbaint_t blkcnt, void *dst) 412272cc70bSAndy Fleming { 4134a1a06bcSAlagu Sankar lbaint_t cur, blocks_todo = blkcnt; 414272cc70bSAndy Fleming 4154a1a06bcSAlagu Sankar if (blkcnt == 0) 4164a1a06bcSAlagu Sankar return 0; 4174a1a06bcSAlagu Sankar 4184a1a06bcSAlagu Sankar struct mmc *mmc = find_mmc_device(dev_num); 419272cc70bSAndy Fleming if (!mmc) 420272cc70bSAndy Fleming return 0; 421272cc70bSAndy Fleming 422d2bf29e3SLei Wen if ((start + blkcnt) > mmc->block_dev.lba) { 423*56196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 424ff8fef56SSascha Silbe printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n", 425d2bf29e3SLei Wen start + blkcnt, mmc->block_dev.lba); 426*56196826SPaul Burton #endif 427d2bf29e3SLei Wen return 0; 428d2bf29e3SLei Wen } 429272cc70bSAndy Fleming 4304a1a06bcSAlagu Sankar if (mmc_set_blocklen(mmc, mmc->read_bl_len)) 431272cc70bSAndy Fleming return 0; 432272cc70bSAndy Fleming 4334a1a06bcSAlagu Sankar do { 4348feafcc4SJohn Rigby cur = (blocks_todo > mmc->b_max) ? mmc->b_max : blocks_todo; 4354a1a06bcSAlagu Sankar if(mmc_read_blocks(mmc, dst, start, cur) != cur) 4364a1a06bcSAlagu Sankar return 0; 4374a1a06bcSAlagu Sankar blocks_todo -= cur; 4384a1a06bcSAlagu Sankar start += cur; 4394a1a06bcSAlagu Sankar dst += cur * mmc->read_bl_len; 4404a1a06bcSAlagu Sankar } while (blocks_todo > 0); 441272cc70bSAndy Fleming 442272cc70bSAndy Fleming return blkcnt; 443272cc70bSAndy Fleming } 444272cc70bSAndy Fleming 445fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc) 446272cc70bSAndy Fleming { 447272cc70bSAndy Fleming struct mmc_cmd cmd; 448272cc70bSAndy Fleming int err; 449272cc70bSAndy Fleming 450272cc70bSAndy Fleming udelay(1000); 451272cc70bSAndy Fleming 452272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_GO_IDLE_STATE; 453272cc70bSAndy Fleming cmd.cmdarg = 0; 454272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_NONE; 455272cc70bSAndy Fleming 456272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 457272cc70bSAndy Fleming 458272cc70bSAndy Fleming if (err) 459272cc70bSAndy Fleming return err; 460272cc70bSAndy Fleming 461272cc70bSAndy Fleming udelay(2000); 462272cc70bSAndy Fleming 463272cc70bSAndy Fleming return 0; 464272cc70bSAndy Fleming } 465272cc70bSAndy Fleming 466fdbb873eSKim Phillips static int sd_send_op_cond(struct mmc *mmc) 467272cc70bSAndy Fleming { 468272cc70bSAndy Fleming int timeout = 1000; 469272cc70bSAndy Fleming int err; 470272cc70bSAndy Fleming struct mmc_cmd cmd; 471272cc70bSAndy Fleming 472272cc70bSAndy Fleming do { 473272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 474272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 475272cc70bSAndy Fleming cmd.cmdarg = 0; 476272cc70bSAndy Fleming 477272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 478272cc70bSAndy Fleming 479272cc70bSAndy Fleming if (err) 480272cc70bSAndy Fleming return err; 481272cc70bSAndy Fleming 482272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_OP_COND; 483272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R3; 484250de12bSStefano Babic 485250de12bSStefano Babic /* 486250de12bSStefano Babic * Most cards do not answer if some reserved bits 487250de12bSStefano Babic * in the ocr are set. However, Some controller 488250de12bSStefano Babic * can set bit 7 (reserved for low voltages), but 489250de12bSStefano Babic * how to manage low voltages SD card is not yet 490250de12bSStefano Babic * specified. 491250de12bSStefano Babic */ 492d52ebf10SThomas Chou cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 : 493d52ebf10SThomas Chou (mmc->voltages & 0xff8000); 494272cc70bSAndy Fleming 495272cc70bSAndy Fleming if (mmc->version == SD_VERSION_2) 496272cc70bSAndy Fleming cmd.cmdarg |= OCR_HCS; 497272cc70bSAndy Fleming 498272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 499272cc70bSAndy Fleming 500272cc70bSAndy Fleming if (err) 501272cc70bSAndy Fleming return err; 502272cc70bSAndy Fleming 503272cc70bSAndy Fleming udelay(1000); 504272cc70bSAndy Fleming } while ((!(cmd.response[0] & OCR_BUSY)) && timeout--); 505272cc70bSAndy Fleming 506272cc70bSAndy Fleming if (timeout <= 0) 507272cc70bSAndy Fleming return UNUSABLE_ERR; 508272cc70bSAndy Fleming 509272cc70bSAndy Fleming if (mmc->version != SD_VERSION_2) 510272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 511272cc70bSAndy Fleming 512d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 513d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 514d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 515d52ebf10SThomas Chou cmd.cmdarg = 0; 516d52ebf10SThomas Chou 517d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 518d52ebf10SThomas Chou 519d52ebf10SThomas Chou if (err) 520d52ebf10SThomas Chou return err; 521d52ebf10SThomas Chou } 522d52ebf10SThomas Chou 523998be3ddSRabin Vincent mmc->ocr = cmd.response[0]; 524272cc70bSAndy Fleming 525272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 526272cc70bSAndy Fleming mmc->rca = 0; 527272cc70bSAndy Fleming 528272cc70bSAndy Fleming return 0; 529272cc70bSAndy Fleming } 530272cc70bSAndy Fleming 531e9550449SChe-Liang Chiou /* We pass in the cmd since otherwise the init seems to fail */ 532e9550449SChe-Liang Chiou static int mmc_send_op_cond_iter(struct mmc *mmc, struct mmc_cmd *cmd, 533e9550449SChe-Liang Chiou int use_arg) 534272cc70bSAndy Fleming { 535272cc70bSAndy Fleming int err; 536272cc70bSAndy Fleming 537e9550449SChe-Liang Chiou cmd->cmdidx = MMC_CMD_SEND_OP_COND; 538e9550449SChe-Liang Chiou cmd->resp_type = MMC_RSP_R3; 539e9550449SChe-Liang Chiou cmd->cmdarg = 0; 540e9550449SChe-Liang Chiou if (use_arg && !mmc_host_is_spi(mmc)) { 541e9550449SChe-Liang Chiou cmd->cmdarg = 542e9550449SChe-Liang Chiou (mmc->voltages & 543e9550449SChe-Liang Chiou (mmc->op_cond_response & OCR_VOLTAGE_MASK)) | 544e9550449SChe-Liang Chiou (mmc->op_cond_response & OCR_ACCESS_MODE); 545e9550449SChe-Liang Chiou 546e9550449SChe-Liang Chiou if (mmc->host_caps & MMC_MODE_HC) 547e9550449SChe-Liang Chiou cmd->cmdarg |= OCR_HCS; 548e9550449SChe-Liang Chiou } 549e9550449SChe-Liang Chiou err = mmc_send_cmd(mmc, cmd, NULL); 550e9550449SChe-Liang Chiou if (err) 551e9550449SChe-Liang Chiou return err; 552e9550449SChe-Liang Chiou mmc->op_cond_response = cmd->response[0]; 553e9550449SChe-Liang Chiou return 0; 554e9550449SChe-Liang Chiou } 555e9550449SChe-Liang Chiou 556e9550449SChe-Liang Chiou int mmc_send_op_cond(struct mmc *mmc) 557e9550449SChe-Liang Chiou { 558e9550449SChe-Liang Chiou struct mmc_cmd cmd; 559e9550449SChe-Liang Chiou int err, i; 560e9550449SChe-Liang Chiou 561272cc70bSAndy Fleming /* Some cards seem to need this */ 562272cc70bSAndy Fleming mmc_go_idle(mmc); 563272cc70bSAndy Fleming 56431cacbabSRaffaele Recalcati /* Asking to the card its capabilities */ 565e9550449SChe-Liang Chiou mmc->op_cond_pending = 1; 566e9550449SChe-Liang Chiou for (i = 0; i < 2; i++) { 567e9550449SChe-Liang Chiou err = mmc_send_op_cond_iter(mmc, &cmd, i != 0); 56831cacbabSRaffaele Recalcati if (err) 56931cacbabSRaffaele Recalcati return err; 57031cacbabSRaffaele Recalcati 571e9550449SChe-Liang Chiou /* exit if not busy (flag seems to be inverted) */ 572e9550449SChe-Liang Chiou if (mmc->op_cond_response & OCR_BUSY) 573e9550449SChe-Liang Chiou return 0; 574e9550449SChe-Liang Chiou } 575e9550449SChe-Liang Chiou return IN_PROGRESS; 576e9550449SChe-Liang Chiou } 57731cacbabSRaffaele Recalcati 578e9550449SChe-Liang Chiou int mmc_complete_op_cond(struct mmc *mmc) 579e9550449SChe-Liang Chiou { 580e9550449SChe-Liang Chiou struct mmc_cmd cmd; 581e9550449SChe-Liang Chiou int timeout = 1000; 582e9550449SChe-Liang Chiou uint start; 583e9550449SChe-Liang Chiou int err; 584e9550449SChe-Liang Chiou 585e9550449SChe-Liang Chiou mmc->op_cond_pending = 0; 586e9550449SChe-Liang Chiou start = get_timer(0); 587272cc70bSAndy Fleming do { 588e9550449SChe-Liang Chiou err = mmc_send_op_cond_iter(mmc, &cmd, 1); 589272cc70bSAndy Fleming if (err) 590272cc70bSAndy Fleming return err; 591e9550449SChe-Liang Chiou if (get_timer(start) > timeout) 592272cc70bSAndy Fleming return UNUSABLE_ERR; 593e9550449SChe-Liang Chiou udelay(100); 594e9550449SChe-Liang Chiou } while (!(mmc->op_cond_response & OCR_BUSY)); 595272cc70bSAndy Fleming 596d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 597d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 598d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 599d52ebf10SThomas Chou cmd.cmdarg = 0; 600d52ebf10SThomas Chou 601d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 602d52ebf10SThomas Chou 603d52ebf10SThomas Chou if (err) 604d52ebf10SThomas Chou return err; 605d52ebf10SThomas Chou } 606d52ebf10SThomas Chou 607272cc70bSAndy Fleming mmc->version = MMC_VERSION_UNKNOWN; 608998be3ddSRabin Vincent mmc->ocr = cmd.response[0]; 609272cc70bSAndy Fleming 610272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 611272cc70bSAndy Fleming mmc->rca = 0; 612272cc70bSAndy Fleming 613272cc70bSAndy Fleming return 0; 614272cc70bSAndy Fleming } 615272cc70bSAndy Fleming 616272cc70bSAndy Fleming 617fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd) 618272cc70bSAndy Fleming { 619272cc70bSAndy Fleming struct mmc_cmd cmd; 620272cc70bSAndy Fleming struct mmc_data data; 621272cc70bSAndy Fleming int err; 622272cc70bSAndy Fleming 623272cc70bSAndy Fleming /* Get the Card Status Register */ 624272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_EXT_CSD; 625272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 626272cc70bSAndy Fleming cmd.cmdarg = 0; 627272cc70bSAndy Fleming 628cdfd1ac6SYoshihiro Shimoda data.dest = (char *)ext_csd; 629272cc70bSAndy Fleming data.blocks = 1; 6308bfa195eSSimon Glass data.blocksize = MMC_MAX_BLOCK_LEN; 631272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 632272cc70bSAndy Fleming 633272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 634272cc70bSAndy Fleming 635272cc70bSAndy Fleming return err; 636272cc70bSAndy Fleming } 637272cc70bSAndy Fleming 638272cc70bSAndy Fleming 639fdbb873eSKim Phillips static int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) 640272cc70bSAndy Fleming { 641272cc70bSAndy Fleming struct mmc_cmd cmd; 6425d4fc8d9SRaffaele Recalcati int timeout = 1000; 6435d4fc8d9SRaffaele Recalcati int ret; 644272cc70bSAndy Fleming 645272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SWITCH; 646272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1b; 647272cc70bSAndy Fleming cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | 648272cc70bSAndy Fleming (index << 16) | 649272cc70bSAndy Fleming (value << 8); 650272cc70bSAndy Fleming 6515d4fc8d9SRaffaele Recalcati ret = mmc_send_cmd(mmc, &cmd, NULL); 6525d4fc8d9SRaffaele Recalcati 6535d4fc8d9SRaffaele Recalcati /* Waiting for the ready status */ 65493ad0d18SJan Kloetzke if (!ret) 65593ad0d18SJan Kloetzke ret = mmc_send_status(mmc, timeout); 6565d4fc8d9SRaffaele Recalcati 6575d4fc8d9SRaffaele Recalcati return ret; 6585d4fc8d9SRaffaele Recalcati 659272cc70bSAndy Fleming } 660272cc70bSAndy Fleming 661fdbb873eSKim Phillips static int mmc_change_freq(struct mmc *mmc) 662272cc70bSAndy Fleming { 6638bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 664272cc70bSAndy Fleming char cardtype; 665272cc70bSAndy Fleming int err; 666272cc70bSAndy Fleming 667272cc70bSAndy Fleming mmc->card_caps = 0; 668272cc70bSAndy Fleming 669d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 670d52ebf10SThomas Chou return 0; 671d52ebf10SThomas Chou 672272cc70bSAndy Fleming /* Only version 4 supports high-speed */ 673272cc70bSAndy Fleming if (mmc->version < MMC_VERSION_4) 674272cc70bSAndy Fleming return 0; 675272cc70bSAndy Fleming 676272cc70bSAndy Fleming err = mmc_send_ext_csd(mmc, ext_csd); 677272cc70bSAndy Fleming 678272cc70bSAndy Fleming if (err) 679272cc70bSAndy Fleming return err; 680272cc70bSAndy Fleming 6810560db18SLei Wen cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf; 682272cc70bSAndy Fleming 683272cc70bSAndy Fleming err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1); 684272cc70bSAndy Fleming 685272cc70bSAndy Fleming if (err) 686272cc70bSAndy Fleming return err; 687272cc70bSAndy Fleming 688272cc70bSAndy Fleming /* Now check to see that it worked */ 689272cc70bSAndy Fleming err = mmc_send_ext_csd(mmc, ext_csd); 690272cc70bSAndy Fleming 691272cc70bSAndy Fleming if (err) 692272cc70bSAndy Fleming return err; 693272cc70bSAndy Fleming 694272cc70bSAndy Fleming /* No high-speed support */ 6950560db18SLei Wen if (!ext_csd[EXT_CSD_HS_TIMING]) 696272cc70bSAndy Fleming return 0; 697272cc70bSAndy Fleming 698272cc70bSAndy Fleming /* High Speed is set, there are two types: 52MHz and 26MHz */ 699272cc70bSAndy Fleming if (cardtype & MMC_HS_52MHZ) 700272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; 701272cc70bSAndy Fleming else 702272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS; 703272cc70bSAndy Fleming 704272cc70bSAndy Fleming return 0; 705272cc70bSAndy Fleming } 706272cc70bSAndy Fleming 707f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num) 708f866a46dSStephen Warren { 709f866a46dSStephen Warren switch (part_num) { 710f866a46dSStephen Warren case 0: 711f866a46dSStephen Warren mmc->capacity = mmc->capacity_user; 712f866a46dSStephen Warren break; 713f866a46dSStephen Warren case 1: 714f866a46dSStephen Warren case 2: 715f866a46dSStephen Warren mmc->capacity = mmc->capacity_boot; 716f866a46dSStephen Warren break; 717f866a46dSStephen Warren case 3: 718f866a46dSStephen Warren mmc->capacity = mmc->capacity_rpmb; 719f866a46dSStephen Warren break; 720f866a46dSStephen Warren case 4: 721f866a46dSStephen Warren case 5: 722f866a46dSStephen Warren case 6: 723f866a46dSStephen Warren case 7: 724f866a46dSStephen Warren mmc->capacity = mmc->capacity_gp[part_num - 4]; 725f866a46dSStephen Warren break; 726f866a46dSStephen Warren default: 727f866a46dSStephen Warren return -1; 728f866a46dSStephen Warren } 729f866a46dSStephen Warren 730f866a46dSStephen Warren mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len); 731f866a46dSStephen Warren 732f866a46dSStephen Warren return 0; 733f866a46dSStephen Warren } 734f866a46dSStephen Warren 735bc897b1dSLei Wen int mmc_switch_part(int dev_num, unsigned int part_num) 736bc897b1dSLei Wen { 737bc897b1dSLei Wen struct mmc *mmc = find_mmc_device(dev_num); 738f866a46dSStephen Warren int ret; 739bc897b1dSLei Wen 740bc897b1dSLei Wen if (!mmc) 741bc897b1dSLei Wen return -1; 742bc897b1dSLei Wen 743f866a46dSStephen Warren ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, 744bc897b1dSLei Wen (mmc->part_config & ~PART_ACCESS_MASK) 745bc897b1dSLei Wen | (part_num & PART_ACCESS_MASK)); 746f866a46dSStephen Warren if (ret) 747f866a46dSStephen Warren return ret; 748f866a46dSStephen Warren 749f866a46dSStephen Warren return mmc_set_capacity(mmc, part_num); 750bc897b1dSLei Wen } 751bc897b1dSLei Wen 75248972d90SThierry Reding int mmc_getcd(struct mmc *mmc) 75348972d90SThierry Reding { 75448972d90SThierry Reding int cd; 75548972d90SThierry Reding 75648972d90SThierry Reding cd = board_mmc_getcd(mmc); 75748972d90SThierry Reding 758d4e1da4eSPeter Korsgaard if (cd < 0) { 759d4e1da4eSPeter Korsgaard if (mmc->getcd) 76048972d90SThierry Reding cd = mmc->getcd(mmc); 761d4e1da4eSPeter Korsgaard else 762d4e1da4eSPeter Korsgaard cd = 1; 763d4e1da4eSPeter Korsgaard } 76448972d90SThierry Reding 76548972d90SThierry Reding return cd; 76648972d90SThierry Reding } 76748972d90SThierry Reding 768fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) 769272cc70bSAndy Fleming { 770272cc70bSAndy Fleming struct mmc_cmd cmd; 771272cc70bSAndy Fleming struct mmc_data data; 772272cc70bSAndy Fleming 773272cc70bSAndy Fleming /* Switch the frequency */ 774272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SWITCH_FUNC; 775272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 776272cc70bSAndy Fleming cmd.cmdarg = (mode << 31) | 0xffffff; 777272cc70bSAndy Fleming cmd.cmdarg &= ~(0xf << (group * 4)); 778272cc70bSAndy Fleming cmd.cmdarg |= value << (group * 4); 779272cc70bSAndy Fleming 780272cc70bSAndy Fleming data.dest = (char *)resp; 781272cc70bSAndy Fleming data.blocksize = 64; 782272cc70bSAndy Fleming data.blocks = 1; 783272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 784272cc70bSAndy Fleming 785272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, &data); 786272cc70bSAndy Fleming } 787272cc70bSAndy Fleming 788272cc70bSAndy Fleming 789fdbb873eSKim Phillips static int sd_change_freq(struct mmc *mmc) 790272cc70bSAndy Fleming { 791272cc70bSAndy Fleming int err; 792272cc70bSAndy Fleming struct mmc_cmd cmd; 793f781dd38SAnton staaf ALLOC_CACHE_ALIGN_BUFFER(uint, scr, 2); 794f781dd38SAnton staaf ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16); 795272cc70bSAndy Fleming struct mmc_data data; 796272cc70bSAndy Fleming int timeout; 797272cc70bSAndy Fleming 798272cc70bSAndy Fleming mmc->card_caps = 0; 799272cc70bSAndy Fleming 800d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 801d52ebf10SThomas Chou return 0; 802d52ebf10SThomas Chou 803272cc70bSAndy Fleming /* Read the SCR to find out if this card supports higher speeds */ 804272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 805272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 806272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 807272cc70bSAndy Fleming 808272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 809272cc70bSAndy Fleming 810272cc70bSAndy Fleming if (err) 811272cc70bSAndy Fleming return err; 812272cc70bSAndy Fleming 813272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_SCR; 814272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 815272cc70bSAndy Fleming cmd.cmdarg = 0; 816272cc70bSAndy Fleming 817272cc70bSAndy Fleming timeout = 3; 818272cc70bSAndy Fleming 819272cc70bSAndy Fleming retry_scr: 820f781dd38SAnton staaf data.dest = (char *)scr; 821272cc70bSAndy Fleming data.blocksize = 8; 822272cc70bSAndy Fleming data.blocks = 1; 823272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 824272cc70bSAndy Fleming 825272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 826272cc70bSAndy Fleming 827272cc70bSAndy Fleming if (err) { 828272cc70bSAndy Fleming if (timeout--) 829272cc70bSAndy Fleming goto retry_scr; 830272cc70bSAndy Fleming 831272cc70bSAndy Fleming return err; 832272cc70bSAndy Fleming } 833272cc70bSAndy Fleming 8344e3d89baSYauhen Kharuzhy mmc->scr[0] = __be32_to_cpu(scr[0]); 8354e3d89baSYauhen Kharuzhy mmc->scr[1] = __be32_to_cpu(scr[1]); 836272cc70bSAndy Fleming 837272cc70bSAndy Fleming switch ((mmc->scr[0] >> 24) & 0xf) { 838272cc70bSAndy Fleming case 0: 839272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 840272cc70bSAndy Fleming break; 841272cc70bSAndy Fleming case 1: 842272cc70bSAndy Fleming mmc->version = SD_VERSION_1_10; 843272cc70bSAndy Fleming break; 844272cc70bSAndy Fleming case 2: 845272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 8461741c64dSJaehoon Chung if ((mmc->scr[0] >> 15) & 0x1) 8471741c64dSJaehoon Chung mmc->version = SD_VERSION_3; 848272cc70bSAndy Fleming break; 849272cc70bSAndy Fleming default: 850272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 851272cc70bSAndy Fleming break; 852272cc70bSAndy Fleming } 853272cc70bSAndy Fleming 854b44c7083SAlagu Sankar if (mmc->scr[0] & SD_DATA_4BIT) 855b44c7083SAlagu Sankar mmc->card_caps |= MMC_MODE_4BIT; 856b44c7083SAlagu Sankar 857272cc70bSAndy Fleming /* Version 1.0 doesn't support switching */ 858272cc70bSAndy Fleming if (mmc->version == SD_VERSION_1_0) 859272cc70bSAndy Fleming return 0; 860272cc70bSAndy Fleming 861272cc70bSAndy Fleming timeout = 4; 862272cc70bSAndy Fleming while (timeout--) { 863272cc70bSAndy Fleming err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1, 864f781dd38SAnton staaf (u8 *)switch_status); 865272cc70bSAndy Fleming 866272cc70bSAndy Fleming if (err) 867272cc70bSAndy Fleming return err; 868272cc70bSAndy Fleming 869272cc70bSAndy Fleming /* The high-speed function is busy. Try again */ 8704e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY)) 871272cc70bSAndy Fleming break; 872272cc70bSAndy Fleming } 873272cc70bSAndy Fleming 874272cc70bSAndy Fleming /* If high-speed isn't supported, we return */ 8754e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)) 876272cc70bSAndy Fleming return 0; 877272cc70bSAndy Fleming 8782c3fbf4cSMacpaul Lin /* 8792c3fbf4cSMacpaul Lin * If the host doesn't support SD_HIGHSPEED, do not switch card to 8802c3fbf4cSMacpaul Lin * HIGHSPEED mode even if the card support SD_HIGHSPPED. 8812c3fbf4cSMacpaul Lin * This can avoid furthur problem when the card runs in different 8822c3fbf4cSMacpaul Lin * mode between the host. 8832c3fbf4cSMacpaul Lin */ 8842c3fbf4cSMacpaul Lin if (!((mmc->host_caps & MMC_MODE_HS_52MHz) && 8852c3fbf4cSMacpaul Lin (mmc->host_caps & MMC_MODE_HS))) 8862c3fbf4cSMacpaul Lin return 0; 8872c3fbf4cSMacpaul Lin 888f781dd38SAnton staaf err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status); 889272cc70bSAndy Fleming 890272cc70bSAndy Fleming if (err) 891272cc70bSAndy Fleming return err; 892272cc70bSAndy Fleming 8934e3d89baSYauhen Kharuzhy if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000) 894272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS; 895272cc70bSAndy Fleming 896272cc70bSAndy Fleming return 0; 897272cc70bSAndy Fleming } 898272cc70bSAndy Fleming 899272cc70bSAndy Fleming /* frequency bases */ 900272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */ 9015f837c2cSMike Frysinger static const int fbase[] = { 902272cc70bSAndy Fleming 10000, 903272cc70bSAndy Fleming 100000, 904272cc70bSAndy Fleming 1000000, 905272cc70bSAndy Fleming 10000000, 906272cc70bSAndy Fleming }; 907272cc70bSAndy Fleming 908272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice 909272cc70bSAndy Fleming * to platforms without floating point. 910272cc70bSAndy Fleming */ 9115f837c2cSMike Frysinger static const int multipliers[] = { 912272cc70bSAndy Fleming 0, /* reserved */ 913272cc70bSAndy Fleming 10, 914272cc70bSAndy Fleming 12, 915272cc70bSAndy Fleming 13, 916272cc70bSAndy Fleming 15, 917272cc70bSAndy Fleming 20, 918272cc70bSAndy Fleming 25, 919272cc70bSAndy Fleming 30, 920272cc70bSAndy Fleming 35, 921272cc70bSAndy Fleming 40, 922272cc70bSAndy Fleming 45, 923272cc70bSAndy Fleming 50, 924272cc70bSAndy Fleming 55, 925272cc70bSAndy Fleming 60, 926272cc70bSAndy Fleming 70, 927272cc70bSAndy Fleming 80, 928272cc70bSAndy Fleming }; 929272cc70bSAndy Fleming 930fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc) 931272cc70bSAndy Fleming { 932272cc70bSAndy Fleming mmc->set_ios(mmc); 933272cc70bSAndy Fleming } 934272cc70bSAndy Fleming 935272cc70bSAndy Fleming void mmc_set_clock(struct mmc *mmc, uint clock) 936272cc70bSAndy Fleming { 937272cc70bSAndy Fleming if (clock > mmc->f_max) 938272cc70bSAndy Fleming clock = mmc->f_max; 939272cc70bSAndy Fleming 940272cc70bSAndy Fleming if (clock < mmc->f_min) 941272cc70bSAndy Fleming clock = mmc->f_min; 942272cc70bSAndy Fleming 943272cc70bSAndy Fleming mmc->clock = clock; 944272cc70bSAndy Fleming 945272cc70bSAndy Fleming mmc_set_ios(mmc); 946272cc70bSAndy Fleming } 947272cc70bSAndy Fleming 948fdbb873eSKim Phillips static void mmc_set_bus_width(struct mmc *mmc, uint width) 949272cc70bSAndy Fleming { 950272cc70bSAndy Fleming mmc->bus_width = width; 951272cc70bSAndy Fleming 952272cc70bSAndy Fleming mmc_set_ios(mmc); 953272cc70bSAndy Fleming } 954272cc70bSAndy Fleming 955fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc) 956272cc70bSAndy Fleming { 957f866a46dSStephen Warren int err, i; 958272cc70bSAndy Fleming uint mult, freq; 959639b7827SYoshihiro Shimoda u64 cmult, csize, capacity; 960272cc70bSAndy Fleming struct mmc_cmd cmd; 9618bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 9628bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 9635d4fc8d9SRaffaele Recalcati int timeout = 1000; 964272cc70bSAndy Fleming 965d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON 966d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */ 967d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF; 968d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R1; 969d52ebf10SThomas Chou cmd.cmdarg = 1; 970d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 971d52ebf10SThomas Chou 972d52ebf10SThomas Chou if (err) 973d52ebf10SThomas Chou return err; 974d52ebf10SThomas Chou } 975d52ebf10SThomas Chou #endif 976d52ebf10SThomas Chou 977272cc70bSAndy Fleming /* Put the Card in Identify Mode */ 978d52ebf10SThomas Chou cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID : 979d52ebf10SThomas Chou MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */ 980272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 981272cc70bSAndy Fleming cmd.cmdarg = 0; 982272cc70bSAndy Fleming 983272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 984272cc70bSAndy Fleming 985272cc70bSAndy Fleming if (err) 986272cc70bSAndy Fleming return err; 987272cc70bSAndy Fleming 988272cc70bSAndy Fleming memcpy(mmc->cid, cmd.response, 16); 989272cc70bSAndy Fleming 990272cc70bSAndy Fleming /* 991272cc70bSAndy Fleming * For MMC cards, set the Relative Address. 992272cc70bSAndy Fleming * For SD cards, get the Relatvie Address. 993272cc70bSAndy Fleming * This also puts the cards into Standby State 994272cc70bSAndy Fleming */ 995d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 996272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR; 997272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 998272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R6; 999272cc70bSAndy Fleming 1000272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1001272cc70bSAndy Fleming 1002272cc70bSAndy Fleming if (err) 1003272cc70bSAndy Fleming return err; 1004272cc70bSAndy Fleming 1005272cc70bSAndy Fleming if (IS_SD(mmc)) 1006998be3ddSRabin Vincent mmc->rca = (cmd.response[0] >> 16) & 0xffff; 1007d52ebf10SThomas Chou } 1008272cc70bSAndy Fleming 1009272cc70bSAndy Fleming /* Get the Card-Specific Data */ 1010272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_CSD; 1011272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1012272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1013272cc70bSAndy Fleming 1014272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1015272cc70bSAndy Fleming 10165d4fc8d9SRaffaele Recalcati /* Waiting for the ready status */ 10175d4fc8d9SRaffaele Recalcati mmc_send_status(mmc, timeout); 10185d4fc8d9SRaffaele Recalcati 1019272cc70bSAndy Fleming if (err) 1020272cc70bSAndy Fleming return err; 1021272cc70bSAndy Fleming 1022998be3ddSRabin Vincent mmc->csd[0] = cmd.response[0]; 1023998be3ddSRabin Vincent mmc->csd[1] = cmd.response[1]; 1024998be3ddSRabin Vincent mmc->csd[2] = cmd.response[2]; 1025998be3ddSRabin Vincent mmc->csd[3] = cmd.response[3]; 1026272cc70bSAndy Fleming 1027272cc70bSAndy Fleming if (mmc->version == MMC_VERSION_UNKNOWN) { 10280b453ffeSRabin Vincent int version = (cmd.response[0] >> 26) & 0xf; 1029272cc70bSAndy Fleming 1030272cc70bSAndy Fleming switch (version) { 1031272cc70bSAndy Fleming case 0: 1032272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1033272cc70bSAndy Fleming break; 1034272cc70bSAndy Fleming case 1: 1035272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_4; 1036272cc70bSAndy Fleming break; 1037272cc70bSAndy Fleming case 2: 1038272cc70bSAndy Fleming mmc->version = MMC_VERSION_2_2; 1039272cc70bSAndy Fleming break; 1040272cc70bSAndy Fleming case 3: 1041272cc70bSAndy Fleming mmc->version = MMC_VERSION_3; 1042272cc70bSAndy Fleming break; 1043272cc70bSAndy Fleming case 4: 1044272cc70bSAndy Fleming mmc->version = MMC_VERSION_4; 1045272cc70bSAndy Fleming break; 1046272cc70bSAndy Fleming default: 1047272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1048272cc70bSAndy Fleming break; 1049272cc70bSAndy Fleming } 1050272cc70bSAndy Fleming } 1051272cc70bSAndy Fleming 1052272cc70bSAndy Fleming /* divide frequency by 10, since the mults are 10x bigger */ 10530b453ffeSRabin Vincent freq = fbase[(cmd.response[0] & 0x7)]; 10540b453ffeSRabin Vincent mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; 1055272cc70bSAndy Fleming 1056272cc70bSAndy Fleming mmc->tran_speed = freq * mult; 1057272cc70bSAndy Fleming 1058998be3ddSRabin Vincent mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf); 1059272cc70bSAndy Fleming 1060272cc70bSAndy Fleming if (IS_SD(mmc)) 1061272cc70bSAndy Fleming mmc->write_bl_len = mmc->read_bl_len; 1062272cc70bSAndy Fleming else 1063998be3ddSRabin Vincent mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf); 1064272cc70bSAndy Fleming 1065272cc70bSAndy Fleming if (mmc->high_capacity) { 1066272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3f) << 16 1067272cc70bSAndy Fleming | (mmc->csd[2] & 0xffff0000) >> 16; 1068272cc70bSAndy Fleming cmult = 8; 1069272cc70bSAndy Fleming } else { 1070272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3ff) << 2 1071272cc70bSAndy Fleming | (mmc->csd[2] & 0xc0000000) >> 30; 1072272cc70bSAndy Fleming cmult = (mmc->csd[2] & 0x00038000) >> 15; 1073272cc70bSAndy Fleming } 1074272cc70bSAndy Fleming 1075f866a46dSStephen Warren mmc->capacity_user = (csize + 1) << (cmult + 2); 1076f866a46dSStephen Warren mmc->capacity_user *= mmc->read_bl_len; 1077f866a46dSStephen Warren mmc->capacity_boot = 0; 1078f866a46dSStephen Warren mmc->capacity_rpmb = 0; 1079f866a46dSStephen Warren for (i = 0; i < 4; i++) 1080f866a46dSStephen Warren mmc->capacity_gp[i] = 0; 1081272cc70bSAndy Fleming 10828bfa195eSSimon Glass if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN) 10838bfa195eSSimon Glass mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 1084272cc70bSAndy Fleming 10858bfa195eSSimon Glass if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN) 10868bfa195eSSimon Glass mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 1087272cc70bSAndy Fleming 1088272cc70bSAndy Fleming /* Select the card, and put it into Transfer Mode */ 1089d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1090272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SELECT_CARD; 1091fe8f7066SAjay Bhargav cmd.resp_type = MMC_RSP_R1; 1092272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1093272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1094272cc70bSAndy Fleming 1095272cc70bSAndy Fleming if (err) 1096272cc70bSAndy Fleming return err; 1097d52ebf10SThomas Chou } 1098272cc70bSAndy Fleming 1099e6f99a56SLei Wen /* 1100e6f99a56SLei Wen * For SD, its erase group is always one sector 1101e6f99a56SLei Wen */ 1102e6f99a56SLei Wen mmc->erase_grp_size = 1; 1103bc897b1dSLei Wen mmc->part_config = MMCPART_NOAVAILABLE; 1104d23e2c09SSukumar Ghorai if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) { 1105d23e2c09SSukumar Ghorai /* check ext_csd version and capacity */ 1106d23e2c09SSukumar Ghorai err = mmc_send_ext_csd(mmc, ext_csd); 1107fdbb873eSKim Phillips if (!err && (ext_csd[EXT_CSD_REV] >= 2)) { 1108639b7827SYoshihiro Shimoda /* 1109639b7827SYoshihiro Shimoda * According to the JEDEC Standard, the value of 1110639b7827SYoshihiro Shimoda * ext_csd's capacity is valid if the value is more 1111639b7827SYoshihiro Shimoda * than 2GB 1112639b7827SYoshihiro Shimoda */ 11130560db18SLei Wen capacity = ext_csd[EXT_CSD_SEC_CNT] << 0 11140560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 11150560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 11160560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; 11178bfa195eSSimon Glass capacity *= MMC_MAX_BLOCK_LEN; 1118b1f1e821SŁukasz Majewski if ((capacity >> 20) > 2 * 1024) 1119f866a46dSStephen Warren mmc->capacity_user = capacity; 1120d23e2c09SSukumar Ghorai } 1121bc897b1dSLei Wen 112264f4a619SJaehoon Chung switch (ext_csd[EXT_CSD_REV]) { 112364f4a619SJaehoon Chung case 1: 112464f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_1; 112564f4a619SJaehoon Chung break; 112664f4a619SJaehoon Chung case 2: 112764f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_2; 112864f4a619SJaehoon Chung break; 112964f4a619SJaehoon Chung case 3: 113064f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_3; 113164f4a619SJaehoon Chung break; 113264f4a619SJaehoon Chung case 5: 113364f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_41; 113464f4a619SJaehoon Chung break; 113564f4a619SJaehoon Chung case 6: 113664f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_5; 113764f4a619SJaehoon Chung break; 113864f4a619SJaehoon Chung } 113964f4a619SJaehoon Chung 1140e6f99a56SLei Wen /* 1141e6f99a56SLei Wen * Check whether GROUP_DEF is set, if yes, read out 1142e6f99a56SLei Wen * group size from ext_csd directly, or calculate 1143e6f99a56SLei Wen * the group size from the csd value. 1144e6f99a56SLei Wen */ 11458bfa195eSSimon Glass if (ext_csd[EXT_CSD_ERASE_GROUP_DEF]) { 11460560db18SLei Wen mmc->erase_grp_size = 11478bfa195eSSimon Glass ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 11488bfa195eSSimon Glass MMC_MAX_BLOCK_LEN * 1024; 11498bfa195eSSimon Glass } else { 1150e6f99a56SLei Wen int erase_gsz, erase_gmul; 1151e6f99a56SLei Wen erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10; 1152e6f99a56SLei Wen erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5; 1153e6f99a56SLei Wen mmc->erase_grp_size = (erase_gsz + 1) 1154e6f99a56SLei Wen * (erase_gmul + 1); 1155e6f99a56SLei Wen } 1156e6f99a56SLei Wen 1157bc897b1dSLei Wen /* store the partition info of emmc */ 11588948ea83SStephen Warren if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || 11598948ea83SStephen Warren ext_csd[EXT_CSD_BOOT_MULT]) 11600560db18SLei Wen mmc->part_config = ext_csd[EXT_CSD_PART_CONF]; 1161f866a46dSStephen Warren 1162f866a46dSStephen Warren mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17; 1163f866a46dSStephen Warren 1164f866a46dSStephen Warren mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17; 1165f866a46dSStephen Warren 1166f866a46dSStephen Warren for (i = 0; i < 4; i++) { 1167f866a46dSStephen Warren int idx = EXT_CSD_GP_SIZE_MULT + i * 3; 1168f866a46dSStephen Warren mmc->capacity_gp[i] = (ext_csd[idx + 2] << 16) + 1169f866a46dSStephen Warren (ext_csd[idx + 1] << 8) + ext_csd[idx]; 1170f866a46dSStephen Warren mmc->capacity_gp[i] *= 1171f866a46dSStephen Warren ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 1172f866a46dSStephen Warren mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1173d23e2c09SSukumar Ghorai } 1174f866a46dSStephen Warren } 1175f866a46dSStephen Warren 1176f866a46dSStephen Warren err = mmc_set_capacity(mmc, mmc->part_num); 1177f866a46dSStephen Warren if (err) 1178f866a46dSStephen Warren return err; 1179d23e2c09SSukumar Ghorai 1180272cc70bSAndy Fleming if (IS_SD(mmc)) 1181272cc70bSAndy Fleming err = sd_change_freq(mmc); 1182272cc70bSAndy Fleming else 1183272cc70bSAndy Fleming err = mmc_change_freq(mmc); 1184272cc70bSAndy Fleming 1185272cc70bSAndy Fleming if (err) 1186272cc70bSAndy Fleming return err; 1187272cc70bSAndy Fleming 1188272cc70bSAndy Fleming /* Restrict card's capabilities by what the host can do */ 1189272cc70bSAndy Fleming mmc->card_caps &= mmc->host_caps; 1190272cc70bSAndy Fleming 1191272cc70bSAndy Fleming if (IS_SD(mmc)) { 1192272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_4BIT) { 1193272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 1194272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1195272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1196272cc70bSAndy Fleming 1197272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1198272cc70bSAndy Fleming if (err) 1199272cc70bSAndy Fleming return err; 1200272cc70bSAndy Fleming 1201272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH; 1202272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1203272cc70bSAndy Fleming cmd.cmdarg = 2; 1204272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1205272cc70bSAndy Fleming if (err) 1206272cc70bSAndy Fleming return err; 1207272cc70bSAndy Fleming 1208272cc70bSAndy Fleming mmc_set_bus_width(mmc, 4); 1209272cc70bSAndy Fleming } 1210272cc70bSAndy Fleming 1211272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_HS) 1212ad5fd922SJaehoon Chung mmc->tran_speed = 50000000; 1213272cc70bSAndy Fleming else 1214ad5fd922SJaehoon Chung mmc->tran_speed = 25000000; 1215272cc70bSAndy Fleming } else { 12167798f6dbSAndy Fleming int idx; 12177798f6dbSAndy Fleming 12187798f6dbSAndy Fleming /* An array of possible bus widths in order of preference */ 12197798f6dbSAndy Fleming static unsigned ext_csd_bits[] = { 12207798f6dbSAndy Fleming EXT_CSD_BUS_WIDTH_8, 12217798f6dbSAndy Fleming EXT_CSD_BUS_WIDTH_4, 12227798f6dbSAndy Fleming EXT_CSD_BUS_WIDTH_1, 12237798f6dbSAndy Fleming }; 12247798f6dbSAndy Fleming 12257798f6dbSAndy Fleming /* An array to map CSD bus widths to host cap bits */ 12267798f6dbSAndy Fleming static unsigned ext_to_hostcaps[] = { 12277798f6dbSAndy Fleming [EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT, 12287798f6dbSAndy Fleming [EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT, 12297798f6dbSAndy Fleming }; 12307798f6dbSAndy Fleming 12317798f6dbSAndy Fleming /* An array to map chosen bus width to an integer */ 12327798f6dbSAndy Fleming static unsigned widths[] = { 12337798f6dbSAndy Fleming 8, 4, 1, 12347798f6dbSAndy Fleming }; 12357798f6dbSAndy Fleming 12367798f6dbSAndy Fleming for (idx=0; idx < ARRAY_SIZE(ext_csd_bits); idx++) { 12377798f6dbSAndy Fleming unsigned int extw = ext_csd_bits[idx]; 12387798f6dbSAndy Fleming 12397798f6dbSAndy Fleming /* 12407798f6dbSAndy Fleming * Check to make sure the controller supports 12417798f6dbSAndy Fleming * this bus width, if it's more than 1 12427798f6dbSAndy Fleming */ 12437798f6dbSAndy Fleming if (extw != EXT_CSD_BUS_WIDTH_1 && 12447798f6dbSAndy Fleming !(mmc->host_caps & ext_to_hostcaps[extw])) 12457798f6dbSAndy Fleming continue; 12467798f6dbSAndy Fleming 1247272cc70bSAndy Fleming err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 12487798f6dbSAndy Fleming EXT_CSD_BUS_WIDTH, extw); 1249272cc70bSAndy Fleming 1250272cc70bSAndy Fleming if (err) 12514137894eSLei Wen continue; 1252272cc70bSAndy Fleming 12537798f6dbSAndy Fleming mmc_set_bus_width(mmc, widths[idx]); 1254272cc70bSAndy Fleming 12554137894eSLei Wen err = mmc_send_ext_csd(mmc, test_csd); 12564137894eSLei Wen if (!err && ext_csd[EXT_CSD_PARTITIONING_SUPPORT] \ 12574137894eSLei Wen == test_csd[EXT_CSD_PARTITIONING_SUPPORT] 12584137894eSLei Wen && ext_csd[EXT_CSD_ERASE_GROUP_DEF] \ 12594137894eSLei Wen == test_csd[EXT_CSD_ERASE_GROUP_DEF] \ 12604137894eSLei Wen && ext_csd[EXT_CSD_REV] \ 12614137894eSLei Wen == test_csd[EXT_CSD_REV] 12624137894eSLei Wen && ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] \ 12634137894eSLei Wen == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 12644137894eSLei Wen && memcmp(&ext_csd[EXT_CSD_SEC_CNT], \ 12654137894eSLei Wen &test_csd[EXT_CSD_SEC_CNT], 4) == 0) { 1266272cc70bSAndy Fleming 12677798f6dbSAndy Fleming mmc->card_caps |= ext_to_hostcaps[extw]; 12684137894eSLei Wen break; 12694137894eSLei Wen } 1270272cc70bSAndy Fleming } 1271272cc70bSAndy Fleming 1272272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_HS) { 1273272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_HS_52MHz) 1274ad5fd922SJaehoon Chung mmc->tran_speed = 52000000; 1275272cc70bSAndy Fleming else 1276ad5fd922SJaehoon Chung mmc->tran_speed = 26000000; 1277272cc70bSAndy Fleming } 1278ad5fd922SJaehoon Chung } 1279ad5fd922SJaehoon Chung 1280ad5fd922SJaehoon Chung mmc_set_clock(mmc, mmc->tran_speed); 1281272cc70bSAndy Fleming 1282272cc70bSAndy Fleming /* fill in device description */ 1283272cc70bSAndy Fleming mmc->block_dev.lun = 0; 1284272cc70bSAndy Fleming mmc->block_dev.type = 0; 1285272cc70bSAndy Fleming mmc->block_dev.blksz = mmc->read_bl_len; 12860472fbfdSEgbert Eich mmc->block_dev.log2blksz = LOG2(mmc->block_dev.blksz); 12879b1f942cSRabin Vincent mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len); 1288*56196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 1289babce5f6STaylor Hutt sprintf(mmc->block_dev.vendor, "Man %06x Snr %04x%04x", 1290babce5f6STaylor Hutt mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff), 1291babce5f6STaylor Hutt (mmc->cid[3] >> 16) & 0xffff); 1292babce5f6STaylor Hutt sprintf(mmc->block_dev.product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff, 12930b453ffeSRabin Vincent (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, 1294babce5f6STaylor Hutt (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff, 1295babce5f6STaylor Hutt (mmc->cid[2] >> 24) & 0xff); 1296babce5f6STaylor Hutt sprintf(mmc->block_dev.revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf, 1297babce5f6STaylor Hutt (mmc->cid[2] >> 16) & 0xf); 1298*56196826SPaul Burton #else 1299*56196826SPaul Burton mmc->block_dev.vendor[0] = 0; 1300*56196826SPaul Burton mmc->block_dev.product[0] = 0; 1301*56196826SPaul Burton mmc->block_dev.revision[0] = 0; 1302*56196826SPaul Burton #endif 1303122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT) 1304272cc70bSAndy Fleming init_part(&mmc->block_dev); 1305122efd43SMikhail Kshevetskiy #endif 1306272cc70bSAndy Fleming 1307272cc70bSAndy Fleming return 0; 1308272cc70bSAndy Fleming } 1309272cc70bSAndy Fleming 1310fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc) 1311272cc70bSAndy Fleming { 1312272cc70bSAndy Fleming struct mmc_cmd cmd; 1313272cc70bSAndy Fleming int err; 1314272cc70bSAndy Fleming 1315272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_IF_COND; 1316272cc70bSAndy Fleming /* We set the bit if the host supports voltages between 2.7 and 3.6 V */ 1317272cc70bSAndy Fleming cmd.cmdarg = ((mmc->voltages & 0xff8000) != 0) << 8 | 0xaa; 1318272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R7; 1319272cc70bSAndy Fleming 1320272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1321272cc70bSAndy Fleming 1322272cc70bSAndy Fleming if (err) 1323272cc70bSAndy Fleming return err; 1324272cc70bSAndy Fleming 1325998be3ddSRabin Vincent if ((cmd.response[0] & 0xff) != 0xaa) 1326272cc70bSAndy Fleming return UNUSABLE_ERR; 1327272cc70bSAndy Fleming else 1328272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 1329272cc70bSAndy Fleming 1330272cc70bSAndy Fleming return 0; 1331272cc70bSAndy Fleming } 1332272cc70bSAndy Fleming 1333272cc70bSAndy Fleming int mmc_register(struct mmc *mmc) 1334272cc70bSAndy Fleming { 1335272cc70bSAndy Fleming /* Setup the universal parts of the block interface just once */ 1336272cc70bSAndy Fleming mmc->block_dev.if_type = IF_TYPE_MMC; 1337272cc70bSAndy Fleming mmc->block_dev.dev = cur_dev_num++; 1338272cc70bSAndy Fleming mmc->block_dev.removable = 1; 1339272cc70bSAndy Fleming mmc->block_dev.block_read = mmc_bread; 1340272cc70bSAndy Fleming mmc->block_dev.block_write = mmc_bwrite; 1341e6f99a56SLei Wen mmc->block_dev.block_erase = mmc_berase; 13428feafcc4SJohn Rigby if (!mmc->b_max) 13438feafcc4SJohn Rigby mmc->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; 1344272cc70bSAndy Fleming 1345272cc70bSAndy Fleming INIT_LIST_HEAD (&mmc->link); 1346272cc70bSAndy Fleming 1347272cc70bSAndy Fleming list_add_tail (&mmc->link, &mmc_devices); 1348272cc70bSAndy Fleming 1349272cc70bSAndy Fleming return 0; 1350272cc70bSAndy Fleming } 1351272cc70bSAndy Fleming 1352df3fc526SMatthew McClintock #ifdef CONFIG_PARTITIONS 1353272cc70bSAndy Fleming block_dev_desc_t *mmc_get_dev(int dev) 1354272cc70bSAndy Fleming { 1355272cc70bSAndy Fleming struct mmc *mmc = find_mmc_device(dev); 13566bb4b4bcSBenoît Thébaudeau if (!mmc || mmc_init(mmc)) 135740242bc3SŁukasz Majewski return NULL; 1358272cc70bSAndy Fleming 135940242bc3SŁukasz Majewski return &mmc->block_dev; 1360272cc70bSAndy Fleming } 1361df3fc526SMatthew McClintock #endif 1362272cc70bSAndy Fleming 1363e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc) 1364272cc70bSAndy Fleming { 1365afd5932bSMacpaul Lin int err; 1366272cc70bSAndy Fleming 136748972d90SThierry Reding if (mmc_getcd(mmc) == 0) { 136848972d90SThierry Reding mmc->has_init = 0; 1369*56196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 137048972d90SThierry Reding printf("MMC: no card present\n"); 1371*56196826SPaul Burton #endif 137248972d90SThierry Reding return NO_CARD_ERR; 137348972d90SThierry Reding } 137448972d90SThierry Reding 1375bc897b1dSLei Wen if (mmc->has_init) 1376bc897b1dSLei Wen return 0; 1377bc897b1dSLei Wen 1378272cc70bSAndy Fleming err = mmc->init(mmc); 1379272cc70bSAndy Fleming 1380272cc70bSAndy Fleming if (err) 1381272cc70bSAndy Fleming return err; 1382272cc70bSAndy Fleming 1383b86b85e2SIlya Yanok mmc_set_bus_width(mmc, 1); 1384b86b85e2SIlya Yanok mmc_set_clock(mmc, 1); 1385b86b85e2SIlya Yanok 1386272cc70bSAndy Fleming /* Reset the Card */ 1387272cc70bSAndy Fleming err = mmc_go_idle(mmc); 1388272cc70bSAndy Fleming 1389272cc70bSAndy Fleming if (err) 1390272cc70bSAndy Fleming return err; 1391272cc70bSAndy Fleming 1392bc897b1dSLei Wen /* The internal partition reset to user partition(0) at every CMD0*/ 1393bc897b1dSLei Wen mmc->part_num = 0; 1394bc897b1dSLei Wen 1395272cc70bSAndy Fleming /* Test for SD version 2 */ 1396272cc70bSAndy Fleming err = mmc_send_if_cond(mmc); 1397272cc70bSAndy Fleming 1398272cc70bSAndy Fleming /* Now try to get the SD card's operating condition */ 1399272cc70bSAndy Fleming err = sd_send_op_cond(mmc); 1400272cc70bSAndy Fleming 1401272cc70bSAndy Fleming /* If the command timed out, we check for an MMC card */ 1402272cc70bSAndy Fleming if (err == TIMEOUT) { 1403272cc70bSAndy Fleming err = mmc_send_op_cond(mmc); 1404272cc70bSAndy Fleming 1405e9550449SChe-Liang Chiou if (err && err != IN_PROGRESS) { 1406*56196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 1407272cc70bSAndy Fleming printf("Card did not respond to voltage select!\n"); 1408*56196826SPaul Burton #endif 1409272cc70bSAndy Fleming return UNUSABLE_ERR; 1410272cc70bSAndy Fleming } 1411272cc70bSAndy Fleming } 1412272cc70bSAndy Fleming 1413e9550449SChe-Liang Chiou if (err == IN_PROGRESS) 1414e9550449SChe-Liang Chiou mmc->init_in_progress = 1; 1415e9550449SChe-Liang Chiou 1416e9550449SChe-Liang Chiou return err; 1417e9550449SChe-Liang Chiou } 1418e9550449SChe-Liang Chiou 1419e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc) 1420e9550449SChe-Liang Chiou { 1421e9550449SChe-Liang Chiou int err = 0; 1422e9550449SChe-Liang Chiou 1423e9550449SChe-Liang Chiou if (mmc->op_cond_pending) 1424e9550449SChe-Liang Chiou err = mmc_complete_op_cond(mmc); 1425e9550449SChe-Liang Chiou 1426e9550449SChe-Liang Chiou if (!err) 1427bc897b1dSLei Wen err = mmc_startup(mmc); 1428bc897b1dSLei Wen if (err) 1429bc897b1dSLei Wen mmc->has_init = 0; 1430bc897b1dSLei Wen else 1431bc897b1dSLei Wen mmc->has_init = 1; 1432e9550449SChe-Liang Chiou mmc->init_in_progress = 0; 1433e9550449SChe-Liang Chiou return err; 1434e9550449SChe-Liang Chiou } 1435e9550449SChe-Liang Chiou 1436e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc) 1437e9550449SChe-Liang Chiou { 1438e9550449SChe-Liang Chiou int err = IN_PROGRESS; 1439e9550449SChe-Liang Chiou unsigned start = get_timer(0); 1440e9550449SChe-Liang Chiou 1441e9550449SChe-Liang Chiou if (mmc->has_init) 1442e9550449SChe-Liang Chiou return 0; 1443e9550449SChe-Liang Chiou if (!mmc->init_in_progress) 1444e9550449SChe-Liang Chiou err = mmc_start_init(mmc); 1445e9550449SChe-Liang Chiou 1446e9550449SChe-Liang Chiou if (!err || err == IN_PROGRESS) 1447e9550449SChe-Liang Chiou err = mmc_complete_init(mmc); 1448e9550449SChe-Liang Chiou debug("%s: %d, time %lu\n", __func__, err, get_timer(start)); 1449bc897b1dSLei Wen return err; 1450272cc70bSAndy Fleming } 1451272cc70bSAndy Fleming 1452272cc70bSAndy Fleming /* 1453272cc70bSAndy Fleming * CPU and board-specific MMC initializations. Aliased function 1454272cc70bSAndy Fleming * signals caller to move on 1455272cc70bSAndy Fleming */ 1456272cc70bSAndy Fleming static int __def_mmc_init(bd_t *bis) 1457272cc70bSAndy Fleming { 1458272cc70bSAndy Fleming return -1; 1459272cc70bSAndy Fleming } 1460272cc70bSAndy Fleming 1461f9a109b3SPeter Tyser int cpu_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init"))); 1462f9a109b3SPeter Tyser int board_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init"))); 1463272cc70bSAndy Fleming 1464*56196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 1465*56196826SPaul Burton 1466272cc70bSAndy Fleming void print_mmc_devices(char separator) 1467272cc70bSAndy Fleming { 1468272cc70bSAndy Fleming struct mmc *m; 1469272cc70bSAndy Fleming struct list_head *entry; 1470272cc70bSAndy Fleming 1471272cc70bSAndy Fleming list_for_each(entry, &mmc_devices) { 1472272cc70bSAndy Fleming m = list_entry(entry, struct mmc, link); 1473272cc70bSAndy Fleming 1474272cc70bSAndy Fleming printf("%s: %d", m->name, m->block_dev.dev); 1475272cc70bSAndy Fleming 1476272cc70bSAndy Fleming if (entry->next != &mmc_devices) 1477272cc70bSAndy Fleming printf("%c ", separator); 1478272cc70bSAndy Fleming } 1479272cc70bSAndy Fleming 1480272cc70bSAndy Fleming printf("\n"); 1481272cc70bSAndy Fleming } 1482272cc70bSAndy Fleming 1483*56196826SPaul Burton #else 1484*56196826SPaul Burton void print_mmc_devices(char separator) { } 1485*56196826SPaul Burton #endif 1486*56196826SPaul Burton 1487ea6ebe21SLei Wen int get_mmc_num(void) 1488ea6ebe21SLei Wen { 1489ea6ebe21SLei Wen return cur_dev_num; 1490ea6ebe21SLei Wen } 1491ea6ebe21SLei Wen 1492e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit) 1493e9550449SChe-Liang Chiou { 1494e9550449SChe-Liang Chiou mmc->preinit = preinit; 1495e9550449SChe-Liang Chiou } 1496e9550449SChe-Liang Chiou 1497e9550449SChe-Liang Chiou static void do_preinit(void) 1498e9550449SChe-Liang Chiou { 1499e9550449SChe-Liang Chiou struct mmc *m; 1500e9550449SChe-Liang Chiou struct list_head *entry; 1501e9550449SChe-Liang Chiou 1502e9550449SChe-Liang Chiou list_for_each(entry, &mmc_devices) { 1503e9550449SChe-Liang Chiou m = list_entry(entry, struct mmc, link); 1504e9550449SChe-Liang Chiou 1505e9550449SChe-Liang Chiou if (m->preinit) 1506e9550449SChe-Liang Chiou mmc_start_init(m); 1507e9550449SChe-Liang Chiou } 1508e9550449SChe-Liang Chiou } 1509e9550449SChe-Liang Chiou 1510e9550449SChe-Liang Chiou 1511272cc70bSAndy Fleming int mmc_initialize(bd_t *bis) 1512272cc70bSAndy Fleming { 1513272cc70bSAndy Fleming INIT_LIST_HEAD (&mmc_devices); 1514272cc70bSAndy Fleming cur_dev_num = 0; 1515272cc70bSAndy Fleming 1516272cc70bSAndy Fleming if (board_mmc_init(bis) < 0) 1517272cc70bSAndy Fleming cpu_mmc_init(bis); 1518272cc70bSAndy Fleming 1519bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD 1520272cc70bSAndy Fleming print_mmc_devices(','); 1521bb0dc108SYing Zhang #endif 1522272cc70bSAndy Fleming 1523e9550449SChe-Liang Chiou do_preinit(); 1524272cc70bSAndy Fleming return 0; 1525272cc70bSAndy Fleming } 15263690d6d6SAmar 15273690d6d6SAmar #ifdef CONFIG_SUPPORT_EMMC_BOOT 15283690d6d6SAmar /* 15293690d6d6SAmar * This function changes the size of boot partition and the size of rpmb 15303690d6d6SAmar * partition present on EMMC devices. 15313690d6d6SAmar * 15323690d6d6SAmar * Input Parameters: 15333690d6d6SAmar * struct *mmc: pointer for the mmc device strcuture 15343690d6d6SAmar * bootsize: size of boot partition 15353690d6d6SAmar * rpmbsize: size of rpmb partition 15363690d6d6SAmar * 15373690d6d6SAmar * Returns 0 on success. 15383690d6d6SAmar */ 15393690d6d6SAmar 15403690d6d6SAmar int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize, 15413690d6d6SAmar unsigned long rpmbsize) 15423690d6d6SAmar { 15433690d6d6SAmar int err; 15443690d6d6SAmar struct mmc_cmd cmd; 15453690d6d6SAmar 15463690d6d6SAmar /* Only use this command for raw EMMC moviNAND. Enter backdoor mode */ 15473690d6d6SAmar cmd.cmdidx = MMC_CMD_RES_MAN; 15483690d6d6SAmar cmd.resp_type = MMC_RSP_R1b; 15493690d6d6SAmar cmd.cmdarg = MMC_CMD62_ARG1; 15503690d6d6SAmar 15513690d6d6SAmar err = mmc_send_cmd(mmc, &cmd, NULL); 15523690d6d6SAmar if (err) { 15533690d6d6SAmar debug("mmc_boot_partition_size_change: Error1 = %d\n", err); 15543690d6d6SAmar return err; 15553690d6d6SAmar } 15563690d6d6SAmar 15573690d6d6SAmar /* Boot partition changing mode */ 15583690d6d6SAmar cmd.cmdidx = MMC_CMD_RES_MAN; 15593690d6d6SAmar cmd.resp_type = MMC_RSP_R1b; 15603690d6d6SAmar cmd.cmdarg = MMC_CMD62_ARG2; 15613690d6d6SAmar 15623690d6d6SAmar err = mmc_send_cmd(mmc, &cmd, NULL); 15633690d6d6SAmar if (err) { 15643690d6d6SAmar debug("mmc_boot_partition_size_change: Error2 = %d\n", err); 15653690d6d6SAmar return err; 15663690d6d6SAmar } 15673690d6d6SAmar /* boot partition size is multiple of 128KB */ 15683690d6d6SAmar bootsize = (bootsize * 1024) / 128; 15693690d6d6SAmar 15703690d6d6SAmar /* Arg: boot partition size */ 15713690d6d6SAmar cmd.cmdidx = MMC_CMD_RES_MAN; 15723690d6d6SAmar cmd.resp_type = MMC_RSP_R1b; 15733690d6d6SAmar cmd.cmdarg = bootsize; 15743690d6d6SAmar 15753690d6d6SAmar err = mmc_send_cmd(mmc, &cmd, NULL); 15763690d6d6SAmar if (err) { 15773690d6d6SAmar debug("mmc_boot_partition_size_change: Error3 = %d\n", err); 15783690d6d6SAmar return err; 15793690d6d6SAmar } 15803690d6d6SAmar /* RPMB partition size is multiple of 128KB */ 15813690d6d6SAmar rpmbsize = (rpmbsize * 1024) / 128; 15823690d6d6SAmar /* Arg: RPMB partition size */ 15833690d6d6SAmar cmd.cmdidx = MMC_CMD_RES_MAN; 15843690d6d6SAmar cmd.resp_type = MMC_RSP_R1b; 15853690d6d6SAmar cmd.cmdarg = rpmbsize; 15863690d6d6SAmar 15873690d6d6SAmar err = mmc_send_cmd(mmc, &cmd, NULL); 15883690d6d6SAmar if (err) { 15893690d6d6SAmar debug("mmc_boot_partition_size_change: Error4 = %d\n", err); 15903690d6d6SAmar return err; 15913690d6d6SAmar } 15923690d6d6SAmar return 0; 15933690d6d6SAmar } 15943690d6d6SAmar 15953690d6d6SAmar /* 15963690d6d6SAmar * This function shall form and send the commands to open / close the 15973690d6d6SAmar * boot partition specified by user. 15983690d6d6SAmar * 15993690d6d6SAmar * Input Parameters: 16003690d6d6SAmar * ack: 0x0 - No boot acknowledge sent (default) 16013690d6d6SAmar * 0x1 - Boot acknowledge sent during boot operation 16023690d6d6SAmar * part_num: User selects boot data that will be sent to master 16033690d6d6SAmar * 0x0 - Device not boot enabled (default) 16043690d6d6SAmar * 0x1 - Boot partition 1 enabled for boot 16053690d6d6SAmar * 0x2 - Boot partition 2 enabled for boot 16063690d6d6SAmar * access: User selects partitions to access 16073690d6d6SAmar * 0x0 : No access to boot partition (default) 16083690d6d6SAmar * 0x1 : R/W boot partition 1 16093690d6d6SAmar * 0x2 : R/W boot partition 2 16103690d6d6SAmar * 0x3 : R/W Replay Protected Memory Block (RPMB) 16113690d6d6SAmar * 16123690d6d6SAmar * Returns 0 on success. 16133690d6d6SAmar */ 16143690d6d6SAmar int mmc_boot_part_access(struct mmc *mmc, u8 ack, u8 part_num, u8 access) 16153690d6d6SAmar { 16163690d6d6SAmar int err; 16173690d6d6SAmar struct mmc_cmd cmd; 16183690d6d6SAmar 16193690d6d6SAmar /* Boot ack enable, boot partition enable , boot partition access */ 16203690d6d6SAmar cmd.cmdidx = MMC_CMD_SWITCH; 16213690d6d6SAmar cmd.resp_type = MMC_RSP_R1b; 16223690d6d6SAmar 16233690d6d6SAmar cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | 16243690d6d6SAmar (EXT_CSD_PART_CONF << 16) | 16253690d6d6SAmar ((EXT_CSD_BOOT_ACK(ack) | 16263690d6d6SAmar EXT_CSD_BOOT_PART_NUM(part_num) | 16273690d6d6SAmar EXT_CSD_PARTITION_ACCESS(access)) << 8); 16283690d6d6SAmar 16293690d6d6SAmar err = mmc_send_cmd(mmc, &cmd, NULL); 16303690d6d6SAmar if (err) { 16313690d6d6SAmar if (access) { 16323690d6d6SAmar debug("mmc boot partition#%d open fail:Error1 = %d\n", 16333690d6d6SAmar part_num, err); 16343690d6d6SAmar } else { 16353690d6d6SAmar debug("mmc boot partition#%d close fail:Error = %d\n", 16363690d6d6SAmar part_num, err); 16373690d6d6SAmar } 16383690d6d6SAmar return err; 16393690d6d6SAmar } 16403690d6d6SAmar 16413690d6d6SAmar if (access) { 16423690d6d6SAmar /* 4bit transfer mode at booting time. */ 16433690d6d6SAmar cmd.cmdidx = MMC_CMD_SWITCH; 16443690d6d6SAmar cmd.resp_type = MMC_RSP_R1b; 16453690d6d6SAmar 16463690d6d6SAmar cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | 16473690d6d6SAmar (EXT_CSD_BOOT_BUS_WIDTH << 16) | 16483690d6d6SAmar ((1 << 0) << 8); 16493690d6d6SAmar 16503690d6d6SAmar err = mmc_send_cmd(mmc, &cmd, NULL); 16513690d6d6SAmar if (err) { 16523690d6d6SAmar debug("mmc boot partition#%d open fail:Error2 = %d\n", 16533690d6d6SAmar part_num, err); 16543690d6d6SAmar return err; 16553690d6d6SAmar } 16563690d6d6SAmar } 16573690d6d6SAmar return 0; 16583690d6d6SAmar } 16593690d6d6SAmar #endif 1660