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 * 7*1a459660SWolfgang 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 { 588635ff9eSMarek Vasut struct mmc_data backup; 595db2fe3aSRaffaele Recalcati int ret; 608635ff9eSMarek Vasut 618635ff9eSMarek Vasut memset(&backup, 0, sizeof(backup)); 628635ff9eSMarek Vasut 638635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE 645db2fe3aSRaffaele Recalcati int i; 655db2fe3aSRaffaele Recalcati u8 *ptr; 665db2fe3aSRaffaele Recalcati 675db2fe3aSRaffaele Recalcati printf("CMD_SEND:%d\n", cmd->cmdidx); 685db2fe3aSRaffaele Recalcati printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg); 695db2fe3aSRaffaele Recalcati ret = mmc->send_cmd(mmc, cmd, data); 705db2fe3aSRaffaele Recalcati switch (cmd->resp_type) { 715db2fe3aSRaffaele Recalcati case MMC_RSP_NONE: 725db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_NONE\n"); 735db2fe3aSRaffaele Recalcati break; 745db2fe3aSRaffaele Recalcati case MMC_RSP_R1: 755db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n", 765db2fe3aSRaffaele Recalcati cmd->response[0]); 775db2fe3aSRaffaele Recalcati break; 785db2fe3aSRaffaele Recalcati case MMC_RSP_R1b: 795db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n", 805db2fe3aSRaffaele Recalcati cmd->response[0]); 815db2fe3aSRaffaele Recalcati break; 825db2fe3aSRaffaele Recalcati case MMC_RSP_R2: 835db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R2\t\t 0x%08X \n", 845db2fe3aSRaffaele Recalcati cmd->response[0]); 855db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 865db2fe3aSRaffaele Recalcati cmd->response[1]); 875db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 885db2fe3aSRaffaele Recalcati cmd->response[2]); 895db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 905db2fe3aSRaffaele Recalcati cmd->response[3]); 915db2fe3aSRaffaele Recalcati printf("\n"); 925db2fe3aSRaffaele Recalcati printf("\t\t\t\t\tDUMPING DATA\n"); 935db2fe3aSRaffaele Recalcati for (i = 0; i < 4; i++) { 945db2fe3aSRaffaele Recalcati int j; 955db2fe3aSRaffaele Recalcati printf("\t\t\t\t\t%03d - ", i*4); 96146bec79SDirk Behme ptr = (u8 *)&cmd->response[i]; 975db2fe3aSRaffaele Recalcati ptr += 3; 985db2fe3aSRaffaele Recalcati for (j = 0; j < 4; j++) 995db2fe3aSRaffaele Recalcati printf("%02X ", *ptr--); 1005db2fe3aSRaffaele Recalcati printf("\n"); 1015db2fe3aSRaffaele Recalcati } 1025db2fe3aSRaffaele Recalcati break; 1035db2fe3aSRaffaele Recalcati case MMC_RSP_R3: 1045db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n", 1055db2fe3aSRaffaele Recalcati cmd->response[0]); 1065db2fe3aSRaffaele Recalcati break; 1075db2fe3aSRaffaele Recalcati default: 1085db2fe3aSRaffaele Recalcati printf("\t\tERROR MMC rsp not supported\n"); 1095db2fe3aSRaffaele Recalcati break; 1105db2fe3aSRaffaele Recalcati } 1115db2fe3aSRaffaele Recalcati #else 1128635ff9eSMarek Vasut ret = mmc->send_cmd(mmc, cmd, data); 1135db2fe3aSRaffaele Recalcati #endif 1148635ff9eSMarek Vasut return ret; 115272cc70bSAndy Fleming } 116272cc70bSAndy Fleming 117fdbb873eSKim Phillips static int mmc_send_status(struct mmc *mmc, int timeout) 1185d4fc8d9SRaffaele Recalcati { 1195d4fc8d9SRaffaele Recalcati struct mmc_cmd cmd; 120d617c426SJan Kloetzke int err, retries = 5; 1215d4fc8d9SRaffaele Recalcati #ifdef CONFIG_MMC_TRACE 1225d4fc8d9SRaffaele Recalcati int status; 1235d4fc8d9SRaffaele Recalcati #endif 1245d4fc8d9SRaffaele Recalcati 1255d4fc8d9SRaffaele Recalcati cmd.cmdidx = MMC_CMD_SEND_STATUS; 1265d4fc8d9SRaffaele Recalcati cmd.resp_type = MMC_RSP_R1; 127aaf3d41aSMarek Vasut if (!mmc_host_is_spi(mmc)) 128aaf3d41aSMarek Vasut cmd.cmdarg = mmc->rca << 16; 1295d4fc8d9SRaffaele Recalcati 1305d4fc8d9SRaffaele Recalcati do { 1315d4fc8d9SRaffaele Recalcati err = mmc_send_cmd(mmc, &cmd, NULL); 132d617c426SJan Kloetzke if (!err) { 133d617c426SJan Kloetzke if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) && 134d617c426SJan Kloetzke (cmd.response[0] & MMC_STATUS_CURR_STATE) != 135d617c426SJan Kloetzke MMC_STATE_PRG) 1365d4fc8d9SRaffaele Recalcati break; 137d617c426SJan Kloetzke else if (cmd.response[0] & MMC_STATUS_MASK) { 138d617c426SJan Kloetzke printf("Status Error: 0x%08X\n", 139d617c426SJan Kloetzke cmd.response[0]); 140d617c426SJan Kloetzke return COMM_ERR; 141d617c426SJan Kloetzke } 142d617c426SJan Kloetzke } else if (--retries < 0) 143d617c426SJan Kloetzke return err; 1445d4fc8d9SRaffaele Recalcati 1455d4fc8d9SRaffaele Recalcati udelay(1000); 1465d4fc8d9SRaffaele Recalcati 1475d4fc8d9SRaffaele Recalcati } while (timeout--); 1485d4fc8d9SRaffaele Recalcati 1495db2fe3aSRaffaele Recalcati #ifdef CONFIG_MMC_TRACE 1505db2fe3aSRaffaele Recalcati status = (cmd.response[0] & MMC_STATUS_CURR_STATE) >> 9; 1515db2fe3aSRaffaele Recalcati printf("CURR STATE:%d\n", status); 1525db2fe3aSRaffaele Recalcati #endif 1535b0c942fSJongman Heo if (timeout <= 0) { 1545d4fc8d9SRaffaele Recalcati printf("Timeout waiting card ready\n"); 1555d4fc8d9SRaffaele Recalcati return TIMEOUT; 1565d4fc8d9SRaffaele Recalcati } 1575d4fc8d9SRaffaele Recalcati 1585d4fc8d9SRaffaele Recalcati return 0; 1595d4fc8d9SRaffaele Recalcati } 1605d4fc8d9SRaffaele Recalcati 161fdbb873eSKim Phillips static int mmc_set_blocklen(struct mmc *mmc, int len) 162272cc70bSAndy Fleming { 163272cc70bSAndy Fleming struct mmc_cmd cmd; 164272cc70bSAndy Fleming 165272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SET_BLOCKLEN; 166272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 167272cc70bSAndy Fleming cmd.cmdarg = len; 168272cc70bSAndy Fleming 169272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, NULL); 170272cc70bSAndy Fleming } 171272cc70bSAndy Fleming 172272cc70bSAndy Fleming struct mmc *find_mmc_device(int dev_num) 173272cc70bSAndy Fleming { 174272cc70bSAndy Fleming struct mmc *m; 175272cc70bSAndy Fleming struct list_head *entry; 176272cc70bSAndy Fleming 177272cc70bSAndy Fleming list_for_each(entry, &mmc_devices) { 178272cc70bSAndy Fleming m = list_entry(entry, struct mmc, link); 179272cc70bSAndy Fleming 180272cc70bSAndy Fleming if (m->block_dev.dev == dev_num) 181272cc70bSAndy Fleming return m; 182272cc70bSAndy Fleming } 183272cc70bSAndy Fleming 184272cc70bSAndy Fleming printf("MMC Device %d not found\n", dev_num); 185272cc70bSAndy Fleming 186272cc70bSAndy Fleming return NULL; 187272cc70bSAndy Fleming } 188272cc70bSAndy Fleming 189e6f99a56SLei Wen static ulong mmc_erase_t(struct mmc *mmc, ulong start, lbaint_t blkcnt) 190e6f99a56SLei Wen { 191e6f99a56SLei Wen struct mmc_cmd cmd; 192e6f99a56SLei Wen ulong end; 193e6f99a56SLei Wen int err, start_cmd, end_cmd; 194e6f99a56SLei Wen 195e6f99a56SLei Wen if (mmc->high_capacity) 196e6f99a56SLei Wen end = start + blkcnt - 1; 197e6f99a56SLei Wen else { 198e6f99a56SLei Wen end = (start + blkcnt - 1) * mmc->write_bl_len; 199e6f99a56SLei Wen start *= mmc->write_bl_len; 200e6f99a56SLei Wen } 201e6f99a56SLei Wen 202e6f99a56SLei Wen if (IS_SD(mmc)) { 203e6f99a56SLei Wen start_cmd = SD_CMD_ERASE_WR_BLK_START; 204e6f99a56SLei Wen end_cmd = SD_CMD_ERASE_WR_BLK_END; 205e6f99a56SLei Wen } else { 206e6f99a56SLei Wen start_cmd = MMC_CMD_ERASE_GROUP_START; 207e6f99a56SLei Wen end_cmd = MMC_CMD_ERASE_GROUP_END; 208e6f99a56SLei Wen } 209e6f99a56SLei Wen 210e6f99a56SLei Wen cmd.cmdidx = start_cmd; 211e6f99a56SLei Wen cmd.cmdarg = start; 212e6f99a56SLei Wen cmd.resp_type = MMC_RSP_R1; 213e6f99a56SLei Wen 214e6f99a56SLei Wen err = mmc_send_cmd(mmc, &cmd, NULL); 215e6f99a56SLei Wen if (err) 216e6f99a56SLei Wen goto err_out; 217e6f99a56SLei Wen 218e6f99a56SLei Wen cmd.cmdidx = end_cmd; 219e6f99a56SLei Wen cmd.cmdarg = end; 220e6f99a56SLei Wen 221e6f99a56SLei Wen err = mmc_send_cmd(mmc, &cmd, NULL); 222e6f99a56SLei Wen if (err) 223e6f99a56SLei Wen goto err_out; 224e6f99a56SLei Wen 225e6f99a56SLei Wen cmd.cmdidx = MMC_CMD_ERASE; 226e6f99a56SLei Wen cmd.cmdarg = SECURE_ERASE; 227e6f99a56SLei Wen cmd.resp_type = MMC_RSP_R1b; 228e6f99a56SLei Wen 229e6f99a56SLei Wen err = mmc_send_cmd(mmc, &cmd, NULL); 230e6f99a56SLei Wen if (err) 231e6f99a56SLei Wen goto err_out; 232e6f99a56SLei Wen 233e6f99a56SLei Wen return 0; 234e6f99a56SLei Wen 235e6f99a56SLei Wen err_out: 236e6f99a56SLei Wen puts("mmc erase failed\n"); 237e6f99a56SLei Wen return err; 238e6f99a56SLei Wen } 239e6f99a56SLei Wen 240e6f99a56SLei Wen static unsigned long 241ff8fef56SSascha Silbe mmc_berase(int dev_num, lbaint_t start, lbaint_t blkcnt) 242e6f99a56SLei Wen { 243e6f99a56SLei Wen int err = 0; 244e6f99a56SLei Wen struct mmc *mmc = find_mmc_device(dev_num); 245e6f99a56SLei Wen lbaint_t blk = 0, blk_r = 0; 246d2d8afaeSJerry Huang int timeout = 1000; 247e6f99a56SLei Wen 248e6f99a56SLei Wen if (!mmc) 249e6f99a56SLei Wen return -1; 250e6f99a56SLei Wen 251e6f99a56SLei Wen if ((start % mmc->erase_grp_size) || (blkcnt % mmc->erase_grp_size)) 252e6f99a56SLei Wen printf("\n\nCaution! Your devices Erase group is 0x%x\n" 253ff8fef56SSascha Silbe "The erase range would be change to " 254ff8fef56SSascha Silbe "0x" LBAF "~0x" LBAF "\n\n", 255e6f99a56SLei Wen mmc->erase_grp_size, start & ~(mmc->erase_grp_size - 1), 256e6f99a56SLei Wen ((start + blkcnt + mmc->erase_grp_size) 257e6f99a56SLei Wen & ~(mmc->erase_grp_size - 1)) - 1); 258e6f99a56SLei Wen 259e6f99a56SLei Wen while (blk < blkcnt) { 260e6f99a56SLei Wen blk_r = ((blkcnt - blk) > mmc->erase_grp_size) ? 261e6f99a56SLei Wen mmc->erase_grp_size : (blkcnt - blk); 262e6f99a56SLei Wen err = mmc_erase_t(mmc, start + blk, blk_r); 263e6f99a56SLei Wen if (err) 264e6f99a56SLei Wen break; 265e6f99a56SLei Wen 266e6f99a56SLei Wen blk += blk_r; 267d2d8afaeSJerry Huang 268d2d8afaeSJerry Huang /* Waiting for the ready status */ 269d2d8afaeSJerry Huang if (mmc_send_status(mmc, timeout)) 270d2d8afaeSJerry Huang return 0; 271e6f99a56SLei Wen } 272e6f99a56SLei Wen 273e6f99a56SLei Wen return blk; 274e6f99a56SLei Wen } 275e6f99a56SLei Wen 276272cc70bSAndy Fleming static ulong 277ff8fef56SSascha Silbe mmc_write_blocks(struct mmc *mmc, lbaint_t start, lbaint_t blkcnt, const void*src) 278272cc70bSAndy Fleming { 279272cc70bSAndy Fleming struct mmc_cmd cmd; 280272cc70bSAndy Fleming struct mmc_data data; 2815d4fc8d9SRaffaele Recalcati int timeout = 1000; 282272cc70bSAndy Fleming 283d2bf29e3SLei Wen if ((start + blkcnt) > mmc->block_dev.lba) { 284ff8fef56SSascha Silbe printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n", 285d2bf29e3SLei Wen start + blkcnt, mmc->block_dev.lba); 286d2bf29e3SLei Wen return 0; 287d2bf29e3SLei Wen } 288272cc70bSAndy Fleming 289a586c0aaSRuud Commandeur if (blkcnt == 0) 290a586c0aaSRuud Commandeur return 0; 291a586c0aaSRuud Commandeur else if (blkcnt == 1) 292272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_WRITE_SINGLE_BLOCK; 293a586c0aaSRuud Commandeur else 294a586c0aaSRuud Commandeur cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK; 295272cc70bSAndy Fleming 296272cc70bSAndy Fleming if (mmc->high_capacity) 297272cc70bSAndy Fleming cmd.cmdarg = start; 298272cc70bSAndy Fleming else 299def412b6SSteve Sakoman cmd.cmdarg = start * mmc->write_bl_len; 300272cc70bSAndy Fleming 301272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 302272cc70bSAndy Fleming 303272cc70bSAndy Fleming data.src = src; 304272cc70bSAndy Fleming data.blocks = blkcnt; 305def412b6SSteve Sakoman data.blocksize = mmc->write_bl_len; 306272cc70bSAndy Fleming data.flags = MMC_DATA_WRITE; 307272cc70bSAndy Fleming 308def412b6SSteve Sakoman if (mmc_send_cmd(mmc, &cmd, &data)) { 309def412b6SSteve Sakoman printf("mmc write failed\n"); 310def412b6SSteve Sakoman return 0; 311272cc70bSAndy Fleming } 312272cc70bSAndy Fleming 313d52ebf10SThomas Chou /* SPI multiblock writes terminate using a special 314d52ebf10SThomas Chou * token, not a STOP_TRANSMISSION request. 315d52ebf10SThomas Chou */ 316d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc) && blkcnt > 1) { 317272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; 318272cc70bSAndy Fleming cmd.cmdarg = 0; 319272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1b; 320def412b6SSteve Sakoman if (mmc_send_cmd(mmc, &cmd, NULL)) { 321def412b6SSteve Sakoman printf("mmc fail to send stop cmd\n"); 322def412b6SSteve Sakoman return 0; 323272cc70bSAndy Fleming } 32493ad0d18SJan Kloetzke } 3255d4fc8d9SRaffaele Recalcati 3265d4fc8d9SRaffaele Recalcati /* Waiting for the ready status */ 32793ad0d18SJan Kloetzke if (mmc_send_status(mmc, timeout)) 32893ad0d18SJan Kloetzke return 0; 3290158126eSLei Wen 3300158126eSLei Wen return blkcnt; 3310158126eSLei Wen } 3320158126eSLei Wen 3330158126eSLei Wen static ulong 334ff8fef56SSascha Silbe mmc_bwrite(int dev_num, lbaint_t start, lbaint_t blkcnt, const void*src) 3350158126eSLei Wen { 3360158126eSLei Wen lbaint_t cur, blocks_todo = blkcnt; 3370158126eSLei Wen 338def412b6SSteve Sakoman struct mmc *mmc = find_mmc_device(dev_num); 3390158126eSLei Wen if (!mmc) 340def412b6SSteve Sakoman return 0; 3410158126eSLei Wen 342def412b6SSteve Sakoman if (mmc_set_blocklen(mmc, mmc->write_bl_len)) 343def412b6SSteve Sakoman return 0; 3440158126eSLei Wen 3450158126eSLei Wen do { 3468feafcc4SJohn Rigby cur = (blocks_todo > mmc->b_max) ? mmc->b_max : blocks_todo; 3470158126eSLei Wen if(mmc_write_blocks(mmc, start, cur, src) != cur) 348def412b6SSteve Sakoman return 0; 3490158126eSLei Wen blocks_todo -= cur; 3500158126eSLei Wen start += cur; 3510158126eSLei Wen src += cur * mmc->write_bl_len; 3520158126eSLei Wen } while (blocks_todo > 0); 353272cc70bSAndy Fleming 354272cc70bSAndy Fleming return blkcnt; 355272cc70bSAndy Fleming } 356272cc70bSAndy Fleming 357ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start, 358fdbb873eSKim Phillips lbaint_t blkcnt) 359272cc70bSAndy Fleming { 360272cc70bSAndy Fleming struct mmc_cmd cmd; 361272cc70bSAndy Fleming struct mmc_data data; 362272cc70bSAndy Fleming 3634a1a06bcSAlagu Sankar if (blkcnt > 1) 3644a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; 3654a1a06bcSAlagu Sankar else 366272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK; 367272cc70bSAndy Fleming 368272cc70bSAndy Fleming if (mmc->high_capacity) 3694a1a06bcSAlagu Sankar cmd.cmdarg = start; 370272cc70bSAndy Fleming else 3714a1a06bcSAlagu Sankar cmd.cmdarg = start * mmc->read_bl_len; 372272cc70bSAndy Fleming 373272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 374272cc70bSAndy Fleming 375272cc70bSAndy Fleming data.dest = dst; 3764a1a06bcSAlagu Sankar data.blocks = blkcnt; 377272cc70bSAndy Fleming data.blocksize = mmc->read_bl_len; 378272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 379272cc70bSAndy Fleming 3804a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, &data)) 3814a1a06bcSAlagu Sankar return 0; 3824a1a06bcSAlagu Sankar 3834a1a06bcSAlagu Sankar if (blkcnt > 1) { 3844a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; 3854a1a06bcSAlagu Sankar cmd.cmdarg = 0; 3864a1a06bcSAlagu Sankar cmd.resp_type = MMC_RSP_R1b; 3874a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, NULL)) { 3884a1a06bcSAlagu Sankar printf("mmc fail to send stop cmd\n"); 3894a1a06bcSAlagu Sankar return 0; 3904a1a06bcSAlagu Sankar } 391272cc70bSAndy Fleming } 392272cc70bSAndy Fleming 3934a1a06bcSAlagu Sankar return blkcnt; 394272cc70bSAndy Fleming } 395272cc70bSAndy Fleming 396ff8fef56SSascha Silbe static ulong mmc_bread(int dev_num, lbaint_t start, lbaint_t blkcnt, void *dst) 397272cc70bSAndy Fleming { 3984a1a06bcSAlagu Sankar lbaint_t cur, blocks_todo = blkcnt; 399272cc70bSAndy Fleming 4004a1a06bcSAlagu Sankar if (blkcnt == 0) 4014a1a06bcSAlagu Sankar return 0; 4024a1a06bcSAlagu Sankar 4034a1a06bcSAlagu Sankar struct mmc *mmc = find_mmc_device(dev_num); 404272cc70bSAndy Fleming if (!mmc) 405272cc70bSAndy Fleming return 0; 406272cc70bSAndy Fleming 407d2bf29e3SLei Wen if ((start + blkcnt) > mmc->block_dev.lba) { 408ff8fef56SSascha Silbe printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n", 409d2bf29e3SLei Wen start + blkcnt, mmc->block_dev.lba); 410d2bf29e3SLei Wen return 0; 411d2bf29e3SLei Wen } 412272cc70bSAndy Fleming 4134a1a06bcSAlagu Sankar if (mmc_set_blocklen(mmc, mmc->read_bl_len)) 414272cc70bSAndy Fleming return 0; 415272cc70bSAndy Fleming 4164a1a06bcSAlagu Sankar do { 4178feafcc4SJohn Rigby cur = (blocks_todo > mmc->b_max) ? mmc->b_max : blocks_todo; 4184a1a06bcSAlagu Sankar if(mmc_read_blocks(mmc, dst, start, cur) != cur) 4194a1a06bcSAlagu Sankar return 0; 4204a1a06bcSAlagu Sankar blocks_todo -= cur; 4214a1a06bcSAlagu Sankar start += cur; 4224a1a06bcSAlagu Sankar dst += cur * mmc->read_bl_len; 4234a1a06bcSAlagu Sankar } while (blocks_todo > 0); 424272cc70bSAndy Fleming 425272cc70bSAndy Fleming return blkcnt; 426272cc70bSAndy Fleming } 427272cc70bSAndy Fleming 428fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc) 429272cc70bSAndy Fleming { 430272cc70bSAndy Fleming struct mmc_cmd cmd; 431272cc70bSAndy Fleming int err; 432272cc70bSAndy Fleming 433272cc70bSAndy Fleming udelay(1000); 434272cc70bSAndy Fleming 435272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_GO_IDLE_STATE; 436272cc70bSAndy Fleming cmd.cmdarg = 0; 437272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_NONE; 438272cc70bSAndy Fleming 439272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 440272cc70bSAndy Fleming 441272cc70bSAndy Fleming if (err) 442272cc70bSAndy Fleming return err; 443272cc70bSAndy Fleming 444272cc70bSAndy Fleming udelay(2000); 445272cc70bSAndy Fleming 446272cc70bSAndy Fleming return 0; 447272cc70bSAndy Fleming } 448272cc70bSAndy Fleming 449fdbb873eSKim Phillips static int sd_send_op_cond(struct mmc *mmc) 450272cc70bSAndy Fleming { 451272cc70bSAndy Fleming int timeout = 1000; 452272cc70bSAndy Fleming int err; 453272cc70bSAndy Fleming struct mmc_cmd cmd; 454272cc70bSAndy Fleming 455272cc70bSAndy Fleming do { 456272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 457272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 458272cc70bSAndy Fleming cmd.cmdarg = 0; 459272cc70bSAndy Fleming 460272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 461272cc70bSAndy Fleming 462272cc70bSAndy Fleming if (err) 463272cc70bSAndy Fleming return err; 464272cc70bSAndy Fleming 465272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_OP_COND; 466272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R3; 467250de12bSStefano Babic 468250de12bSStefano Babic /* 469250de12bSStefano Babic * Most cards do not answer if some reserved bits 470250de12bSStefano Babic * in the ocr are set. However, Some controller 471250de12bSStefano Babic * can set bit 7 (reserved for low voltages), but 472250de12bSStefano Babic * how to manage low voltages SD card is not yet 473250de12bSStefano Babic * specified. 474250de12bSStefano Babic */ 475d52ebf10SThomas Chou cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 : 476d52ebf10SThomas Chou (mmc->voltages & 0xff8000); 477272cc70bSAndy Fleming 478272cc70bSAndy Fleming if (mmc->version == SD_VERSION_2) 479272cc70bSAndy Fleming cmd.cmdarg |= OCR_HCS; 480272cc70bSAndy Fleming 481272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 482272cc70bSAndy Fleming 483272cc70bSAndy Fleming if (err) 484272cc70bSAndy Fleming return err; 485272cc70bSAndy Fleming 486272cc70bSAndy Fleming udelay(1000); 487272cc70bSAndy Fleming } while ((!(cmd.response[0] & OCR_BUSY)) && timeout--); 488272cc70bSAndy Fleming 489272cc70bSAndy Fleming if (timeout <= 0) 490272cc70bSAndy Fleming return UNUSABLE_ERR; 491272cc70bSAndy Fleming 492272cc70bSAndy Fleming if (mmc->version != SD_VERSION_2) 493272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 494272cc70bSAndy Fleming 495d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 496d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 497d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 498d52ebf10SThomas Chou cmd.cmdarg = 0; 499d52ebf10SThomas Chou 500d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 501d52ebf10SThomas Chou 502d52ebf10SThomas Chou if (err) 503d52ebf10SThomas Chou return err; 504d52ebf10SThomas Chou } 505d52ebf10SThomas Chou 506998be3ddSRabin Vincent mmc->ocr = cmd.response[0]; 507272cc70bSAndy Fleming 508272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 509272cc70bSAndy Fleming mmc->rca = 0; 510272cc70bSAndy Fleming 511272cc70bSAndy Fleming return 0; 512272cc70bSAndy Fleming } 513272cc70bSAndy Fleming 514e9550449SChe-Liang Chiou /* We pass in the cmd since otherwise the init seems to fail */ 515e9550449SChe-Liang Chiou static int mmc_send_op_cond_iter(struct mmc *mmc, struct mmc_cmd *cmd, 516e9550449SChe-Liang Chiou int use_arg) 517272cc70bSAndy Fleming { 518272cc70bSAndy Fleming int err; 519272cc70bSAndy Fleming 520e9550449SChe-Liang Chiou cmd->cmdidx = MMC_CMD_SEND_OP_COND; 521e9550449SChe-Liang Chiou cmd->resp_type = MMC_RSP_R3; 522e9550449SChe-Liang Chiou cmd->cmdarg = 0; 523e9550449SChe-Liang Chiou if (use_arg && !mmc_host_is_spi(mmc)) { 524e9550449SChe-Liang Chiou cmd->cmdarg = 525e9550449SChe-Liang Chiou (mmc->voltages & 526e9550449SChe-Liang Chiou (mmc->op_cond_response & OCR_VOLTAGE_MASK)) | 527e9550449SChe-Liang Chiou (mmc->op_cond_response & OCR_ACCESS_MODE); 528e9550449SChe-Liang Chiou 529e9550449SChe-Liang Chiou if (mmc->host_caps & MMC_MODE_HC) 530e9550449SChe-Liang Chiou cmd->cmdarg |= OCR_HCS; 531e9550449SChe-Liang Chiou } 532e9550449SChe-Liang Chiou err = mmc_send_cmd(mmc, cmd, NULL); 533e9550449SChe-Liang Chiou if (err) 534e9550449SChe-Liang Chiou return err; 535e9550449SChe-Liang Chiou mmc->op_cond_response = cmd->response[0]; 536e9550449SChe-Liang Chiou return 0; 537e9550449SChe-Liang Chiou } 538e9550449SChe-Liang Chiou 539e9550449SChe-Liang Chiou int mmc_send_op_cond(struct mmc *mmc) 540e9550449SChe-Liang Chiou { 541e9550449SChe-Liang Chiou struct mmc_cmd cmd; 542e9550449SChe-Liang Chiou int err, i; 543e9550449SChe-Liang Chiou 544272cc70bSAndy Fleming /* Some cards seem to need this */ 545272cc70bSAndy Fleming mmc_go_idle(mmc); 546272cc70bSAndy Fleming 54731cacbabSRaffaele Recalcati /* Asking to the card its capabilities */ 548e9550449SChe-Liang Chiou mmc->op_cond_pending = 1; 549e9550449SChe-Liang Chiou for (i = 0; i < 2; i++) { 550e9550449SChe-Liang Chiou err = mmc_send_op_cond_iter(mmc, &cmd, i != 0); 55131cacbabSRaffaele Recalcati if (err) 55231cacbabSRaffaele Recalcati return err; 55331cacbabSRaffaele Recalcati 554e9550449SChe-Liang Chiou /* exit if not busy (flag seems to be inverted) */ 555e9550449SChe-Liang Chiou if (mmc->op_cond_response & OCR_BUSY) 556e9550449SChe-Liang Chiou return 0; 557e9550449SChe-Liang Chiou } 558e9550449SChe-Liang Chiou return IN_PROGRESS; 559e9550449SChe-Liang Chiou } 56031cacbabSRaffaele Recalcati 561e9550449SChe-Liang Chiou int mmc_complete_op_cond(struct mmc *mmc) 562e9550449SChe-Liang Chiou { 563e9550449SChe-Liang Chiou struct mmc_cmd cmd; 564e9550449SChe-Liang Chiou int timeout = 1000; 565e9550449SChe-Liang Chiou uint start; 566e9550449SChe-Liang Chiou int err; 567e9550449SChe-Liang Chiou 568e9550449SChe-Liang Chiou mmc->op_cond_pending = 0; 569e9550449SChe-Liang Chiou start = get_timer(0); 570272cc70bSAndy Fleming do { 571e9550449SChe-Liang Chiou err = mmc_send_op_cond_iter(mmc, &cmd, 1); 572272cc70bSAndy Fleming if (err) 573272cc70bSAndy Fleming return err; 574e9550449SChe-Liang Chiou if (get_timer(start) > timeout) 575272cc70bSAndy Fleming return UNUSABLE_ERR; 576e9550449SChe-Liang Chiou udelay(100); 577e9550449SChe-Liang Chiou } while (!(mmc->op_cond_response & OCR_BUSY)); 578272cc70bSAndy Fleming 579d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 580d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 581d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 582d52ebf10SThomas Chou cmd.cmdarg = 0; 583d52ebf10SThomas Chou 584d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 585d52ebf10SThomas Chou 586d52ebf10SThomas Chou if (err) 587d52ebf10SThomas Chou return err; 588d52ebf10SThomas Chou } 589d52ebf10SThomas Chou 590272cc70bSAndy Fleming mmc->version = MMC_VERSION_UNKNOWN; 591998be3ddSRabin Vincent mmc->ocr = cmd.response[0]; 592272cc70bSAndy Fleming 593272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 594272cc70bSAndy Fleming mmc->rca = 0; 595272cc70bSAndy Fleming 596272cc70bSAndy Fleming return 0; 597272cc70bSAndy Fleming } 598272cc70bSAndy Fleming 599272cc70bSAndy Fleming 600fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd) 601272cc70bSAndy Fleming { 602272cc70bSAndy Fleming struct mmc_cmd cmd; 603272cc70bSAndy Fleming struct mmc_data data; 604272cc70bSAndy Fleming int err; 605272cc70bSAndy Fleming 606272cc70bSAndy Fleming /* Get the Card Status Register */ 607272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_EXT_CSD; 608272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 609272cc70bSAndy Fleming cmd.cmdarg = 0; 610272cc70bSAndy Fleming 611cdfd1ac6SYoshihiro Shimoda data.dest = (char *)ext_csd; 612272cc70bSAndy Fleming data.blocks = 1; 6138bfa195eSSimon Glass data.blocksize = MMC_MAX_BLOCK_LEN; 614272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 615272cc70bSAndy Fleming 616272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 617272cc70bSAndy Fleming 618272cc70bSAndy Fleming return err; 619272cc70bSAndy Fleming } 620272cc70bSAndy Fleming 621272cc70bSAndy Fleming 622fdbb873eSKim Phillips static int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) 623272cc70bSAndy Fleming { 624272cc70bSAndy Fleming struct mmc_cmd cmd; 6255d4fc8d9SRaffaele Recalcati int timeout = 1000; 6265d4fc8d9SRaffaele Recalcati int ret; 627272cc70bSAndy Fleming 628272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SWITCH; 629272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1b; 630272cc70bSAndy Fleming cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | 631272cc70bSAndy Fleming (index << 16) | 632272cc70bSAndy Fleming (value << 8); 633272cc70bSAndy Fleming 6345d4fc8d9SRaffaele Recalcati ret = mmc_send_cmd(mmc, &cmd, NULL); 6355d4fc8d9SRaffaele Recalcati 6365d4fc8d9SRaffaele Recalcati /* Waiting for the ready status */ 63793ad0d18SJan Kloetzke if (!ret) 63893ad0d18SJan Kloetzke ret = mmc_send_status(mmc, timeout); 6395d4fc8d9SRaffaele Recalcati 6405d4fc8d9SRaffaele Recalcati return ret; 6415d4fc8d9SRaffaele Recalcati 642272cc70bSAndy Fleming } 643272cc70bSAndy Fleming 644fdbb873eSKim Phillips static int mmc_change_freq(struct mmc *mmc) 645272cc70bSAndy Fleming { 6468bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 647272cc70bSAndy Fleming char cardtype; 648272cc70bSAndy Fleming int err; 649272cc70bSAndy Fleming 650272cc70bSAndy Fleming mmc->card_caps = 0; 651272cc70bSAndy Fleming 652d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 653d52ebf10SThomas Chou return 0; 654d52ebf10SThomas Chou 655272cc70bSAndy Fleming /* Only version 4 supports high-speed */ 656272cc70bSAndy Fleming if (mmc->version < MMC_VERSION_4) 657272cc70bSAndy Fleming return 0; 658272cc70bSAndy Fleming 659272cc70bSAndy Fleming err = mmc_send_ext_csd(mmc, ext_csd); 660272cc70bSAndy Fleming 661272cc70bSAndy Fleming if (err) 662272cc70bSAndy Fleming return err; 663272cc70bSAndy Fleming 6640560db18SLei Wen cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf; 665272cc70bSAndy Fleming 666272cc70bSAndy Fleming err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1); 667272cc70bSAndy Fleming 668272cc70bSAndy Fleming if (err) 669272cc70bSAndy Fleming return err; 670272cc70bSAndy Fleming 671272cc70bSAndy Fleming /* Now check to see that it worked */ 672272cc70bSAndy Fleming err = mmc_send_ext_csd(mmc, ext_csd); 673272cc70bSAndy Fleming 674272cc70bSAndy Fleming if (err) 675272cc70bSAndy Fleming return err; 676272cc70bSAndy Fleming 677272cc70bSAndy Fleming /* No high-speed support */ 6780560db18SLei Wen if (!ext_csd[EXT_CSD_HS_TIMING]) 679272cc70bSAndy Fleming return 0; 680272cc70bSAndy Fleming 681272cc70bSAndy Fleming /* High Speed is set, there are two types: 52MHz and 26MHz */ 682272cc70bSAndy Fleming if (cardtype & MMC_HS_52MHZ) 683272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; 684272cc70bSAndy Fleming else 685272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS; 686272cc70bSAndy Fleming 687272cc70bSAndy Fleming return 0; 688272cc70bSAndy Fleming } 689272cc70bSAndy Fleming 690f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num) 691f866a46dSStephen Warren { 692f866a46dSStephen Warren switch (part_num) { 693f866a46dSStephen Warren case 0: 694f866a46dSStephen Warren mmc->capacity = mmc->capacity_user; 695f866a46dSStephen Warren break; 696f866a46dSStephen Warren case 1: 697f866a46dSStephen Warren case 2: 698f866a46dSStephen Warren mmc->capacity = mmc->capacity_boot; 699f866a46dSStephen Warren break; 700f866a46dSStephen Warren case 3: 701f866a46dSStephen Warren mmc->capacity = mmc->capacity_rpmb; 702f866a46dSStephen Warren break; 703f866a46dSStephen Warren case 4: 704f866a46dSStephen Warren case 5: 705f866a46dSStephen Warren case 6: 706f866a46dSStephen Warren case 7: 707f866a46dSStephen Warren mmc->capacity = mmc->capacity_gp[part_num - 4]; 708f866a46dSStephen Warren break; 709f866a46dSStephen Warren default: 710f866a46dSStephen Warren return -1; 711f866a46dSStephen Warren } 712f866a46dSStephen Warren 713f866a46dSStephen Warren mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len); 714f866a46dSStephen Warren 715f866a46dSStephen Warren return 0; 716f866a46dSStephen Warren } 717f866a46dSStephen Warren 718bc897b1dSLei Wen int mmc_switch_part(int dev_num, unsigned int part_num) 719bc897b1dSLei Wen { 720bc897b1dSLei Wen struct mmc *mmc = find_mmc_device(dev_num); 721f866a46dSStephen Warren int ret; 722bc897b1dSLei Wen 723bc897b1dSLei Wen if (!mmc) 724bc897b1dSLei Wen return -1; 725bc897b1dSLei Wen 726f866a46dSStephen Warren ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, 727bc897b1dSLei Wen (mmc->part_config & ~PART_ACCESS_MASK) 728bc897b1dSLei Wen | (part_num & PART_ACCESS_MASK)); 729f866a46dSStephen Warren if (ret) 730f866a46dSStephen Warren return ret; 731f866a46dSStephen Warren 732f866a46dSStephen Warren return mmc_set_capacity(mmc, part_num); 733bc897b1dSLei Wen } 734bc897b1dSLei Wen 73548972d90SThierry Reding int mmc_getcd(struct mmc *mmc) 73648972d90SThierry Reding { 73748972d90SThierry Reding int cd; 73848972d90SThierry Reding 73948972d90SThierry Reding cd = board_mmc_getcd(mmc); 74048972d90SThierry Reding 741d4e1da4eSPeter Korsgaard if (cd < 0) { 742d4e1da4eSPeter Korsgaard if (mmc->getcd) 74348972d90SThierry Reding cd = mmc->getcd(mmc); 744d4e1da4eSPeter Korsgaard else 745d4e1da4eSPeter Korsgaard cd = 1; 746d4e1da4eSPeter Korsgaard } 74748972d90SThierry Reding 74848972d90SThierry Reding return cd; 74948972d90SThierry Reding } 75048972d90SThierry Reding 751fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) 752272cc70bSAndy Fleming { 753272cc70bSAndy Fleming struct mmc_cmd cmd; 754272cc70bSAndy Fleming struct mmc_data data; 755272cc70bSAndy Fleming 756272cc70bSAndy Fleming /* Switch the frequency */ 757272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SWITCH_FUNC; 758272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 759272cc70bSAndy Fleming cmd.cmdarg = (mode << 31) | 0xffffff; 760272cc70bSAndy Fleming cmd.cmdarg &= ~(0xf << (group * 4)); 761272cc70bSAndy Fleming cmd.cmdarg |= value << (group * 4); 762272cc70bSAndy Fleming 763272cc70bSAndy Fleming data.dest = (char *)resp; 764272cc70bSAndy Fleming data.blocksize = 64; 765272cc70bSAndy Fleming data.blocks = 1; 766272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 767272cc70bSAndy Fleming 768272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, &data); 769272cc70bSAndy Fleming } 770272cc70bSAndy Fleming 771272cc70bSAndy Fleming 772fdbb873eSKim Phillips static int sd_change_freq(struct mmc *mmc) 773272cc70bSAndy Fleming { 774272cc70bSAndy Fleming int err; 775272cc70bSAndy Fleming struct mmc_cmd cmd; 776f781dd38SAnton staaf ALLOC_CACHE_ALIGN_BUFFER(uint, scr, 2); 777f781dd38SAnton staaf ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16); 778272cc70bSAndy Fleming struct mmc_data data; 779272cc70bSAndy Fleming int timeout; 780272cc70bSAndy Fleming 781272cc70bSAndy Fleming mmc->card_caps = 0; 782272cc70bSAndy Fleming 783d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 784d52ebf10SThomas Chou return 0; 785d52ebf10SThomas Chou 786272cc70bSAndy Fleming /* Read the SCR to find out if this card supports higher speeds */ 787272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 788272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 789272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 790272cc70bSAndy Fleming 791272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 792272cc70bSAndy Fleming 793272cc70bSAndy Fleming if (err) 794272cc70bSAndy Fleming return err; 795272cc70bSAndy Fleming 796272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_SCR; 797272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 798272cc70bSAndy Fleming cmd.cmdarg = 0; 799272cc70bSAndy Fleming 800272cc70bSAndy Fleming timeout = 3; 801272cc70bSAndy Fleming 802272cc70bSAndy Fleming retry_scr: 803f781dd38SAnton staaf data.dest = (char *)scr; 804272cc70bSAndy Fleming data.blocksize = 8; 805272cc70bSAndy Fleming data.blocks = 1; 806272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 807272cc70bSAndy Fleming 808272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 809272cc70bSAndy Fleming 810272cc70bSAndy Fleming if (err) { 811272cc70bSAndy Fleming if (timeout--) 812272cc70bSAndy Fleming goto retry_scr; 813272cc70bSAndy Fleming 814272cc70bSAndy Fleming return err; 815272cc70bSAndy Fleming } 816272cc70bSAndy Fleming 8174e3d89baSYauhen Kharuzhy mmc->scr[0] = __be32_to_cpu(scr[0]); 8184e3d89baSYauhen Kharuzhy mmc->scr[1] = __be32_to_cpu(scr[1]); 819272cc70bSAndy Fleming 820272cc70bSAndy Fleming switch ((mmc->scr[0] >> 24) & 0xf) { 821272cc70bSAndy Fleming case 0: 822272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 823272cc70bSAndy Fleming break; 824272cc70bSAndy Fleming case 1: 825272cc70bSAndy Fleming mmc->version = SD_VERSION_1_10; 826272cc70bSAndy Fleming break; 827272cc70bSAndy Fleming case 2: 828272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 8291741c64dSJaehoon Chung if ((mmc->scr[0] >> 15) & 0x1) 8301741c64dSJaehoon Chung mmc->version = SD_VERSION_3; 831272cc70bSAndy Fleming break; 832272cc70bSAndy Fleming default: 833272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 834272cc70bSAndy Fleming break; 835272cc70bSAndy Fleming } 836272cc70bSAndy Fleming 837b44c7083SAlagu Sankar if (mmc->scr[0] & SD_DATA_4BIT) 838b44c7083SAlagu Sankar mmc->card_caps |= MMC_MODE_4BIT; 839b44c7083SAlagu Sankar 840272cc70bSAndy Fleming /* Version 1.0 doesn't support switching */ 841272cc70bSAndy Fleming if (mmc->version == SD_VERSION_1_0) 842272cc70bSAndy Fleming return 0; 843272cc70bSAndy Fleming 844272cc70bSAndy Fleming timeout = 4; 845272cc70bSAndy Fleming while (timeout--) { 846272cc70bSAndy Fleming err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1, 847f781dd38SAnton staaf (u8 *)switch_status); 848272cc70bSAndy Fleming 849272cc70bSAndy Fleming if (err) 850272cc70bSAndy Fleming return err; 851272cc70bSAndy Fleming 852272cc70bSAndy Fleming /* The high-speed function is busy. Try again */ 8534e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY)) 854272cc70bSAndy Fleming break; 855272cc70bSAndy Fleming } 856272cc70bSAndy Fleming 857272cc70bSAndy Fleming /* If high-speed isn't supported, we return */ 8584e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)) 859272cc70bSAndy Fleming return 0; 860272cc70bSAndy Fleming 8612c3fbf4cSMacpaul Lin /* 8622c3fbf4cSMacpaul Lin * If the host doesn't support SD_HIGHSPEED, do not switch card to 8632c3fbf4cSMacpaul Lin * HIGHSPEED mode even if the card support SD_HIGHSPPED. 8642c3fbf4cSMacpaul Lin * This can avoid furthur problem when the card runs in different 8652c3fbf4cSMacpaul Lin * mode between the host. 8662c3fbf4cSMacpaul Lin */ 8672c3fbf4cSMacpaul Lin if (!((mmc->host_caps & MMC_MODE_HS_52MHz) && 8682c3fbf4cSMacpaul Lin (mmc->host_caps & MMC_MODE_HS))) 8692c3fbf4cSMacpaul Lin return 0; 8702c3fbf4cSMacpaul Lin 871f781dd38SAnton staaf err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status); 872272cc70bSAndy Fleming 873272cc70bSAndy Fleming if (err) 874272cc70bSAndy Fleming return err; 875272cc70bSAndy Fleming 8764e3d89baSYauhen Kharuzhy if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000) 877272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS; 878272cc70bSAndy Fleming 879272cc70bSAndy Fleming return 0; 880272cc70bSAndy Fleming } 881272cc70bSAndy Fleming 882272cc70bSAndy Fleming /* frequency bases */ 883272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */ 8845f837c2cSMike Frysinger static const int fbase[] = { 885272cc70bSAndy Fleming 10000, 886272cc70bSAndy Fleming 100000, 887272cc70bSAndy Fleming 1000000, 888272cc70bSAndy Fleming 10000000, 889272cc70bSAndy Fleming }; 890272cc70bSAndy Fleming 891272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice 892272cc70bSAndy Fleming * to platforms without floating point. 893272cc70bSAndy Fleming */ 8945f837c2cSMike Frysinger static const int multipliers[] = { 895272cc70bSAndy Fleming 0, /* reserved */ 896272cc70bSAndy Fleming 10, 897272cc70bSAndy Fleming 12, 898272cc70bSAndy Fleming 13, 899272cc70bSAndy Fleming 15, 900272cc70bSAndy Fleming 20, 901272cc70bSAndy Fleming 25, 902272cc70bSAndy Fleming 30, 903272cc70bSAndy Fleming 35, 904272cc70bSAndy Fleming 40, 905272cc70bSAndy Fleming 45, 906272cc70bSAndy Fleming 50, 907272cc70bSAndy Fleming 55, 908272cc70bSAndy Fleming 60, 909272cc70bSAndy Fleming 70, 910272cc70bSAndy Fleming 80, 911272cc70bSAndy Fleming }; 912272cc70bSAndy Fleming 913fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc) 914272cc70bSAndy Fleming { 915272cc70bSAndy Fleming mmc->set_ios(mmc); 916272cc70bSAndy Fleming } 917272cc70bSAndy Fleming 918272cc70bSAndy Fleming void mmc_set_clock(struct mmc *mmc, uint clock) 919272cc70bSAndy Fleming { 920272cc70bSAndy Fleming if (clock > mmc->f_max) 921272cc70bSAndy Fleming clock = mmc->f_max; 922272cc70bSAndy Fleming 923272cc70bSAndy Fleming if (clock < mmc->f_min) 924272cc70bSAndy Fleming clock = mmc->f_min; 925272cc70bSAndy Fleming 926272cc70bSAndy Fleming mmc->clock = clock; 927272cc70bSAndy Fleming 928272cc70bSAndy Fleming mmc_set_ios(mmc); 929272cc70bSAndy Fleming } 930272cc70bSAndy Fleming 931fdbb873eSKim Phillips static void mmc_set_bus_width(struct mmc *mmc, uint width) 932272cc70bSAndy Fleming { 933272cc70bSAndy Fleming mmc->bus_width = width; 934272cc70bSAndy Fleming 935272cc70bSAndy Fleming mmc_set_ios(mmc); 936272cc70bSAndy Fleming } 937272cc70bSAndy Fleming 938fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc) 939272cc70bSAndy Fleming { 940f866a46dSStephen Warren int err, i; 941272cc70bSAndy Fleming uint mult, freq; 942639b7827SYoshihiro Shimoda u64 cmult, csize, capacity; 943272cc70bSAndy Fleming struct mmc_cmd cmd; 9448bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 9458bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 9465d4fc8d9SRaffaele Recalcati int timeout = 1000; 947272cc70bSAndy Fleming 948d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON 949d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */ 950d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF; 951d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R1; 952d52ebf10SThomas Chou cmd.cmdarg = 1; 953d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 954d52ebf10SThomas Chou 955d52ebf10SThomas Chou if (err) 956d52ebf10SThomas Chou return err; 957d52ebf10SThomas Chou } 958d52ebf10SThomas Chou #endif 959d52ebf10SThomas Chou 960272cc70bSAndy Fleming /* Put the Card in Identify Mode */ 961d52ebf10SThomas Chou cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID : 962d52ebf10SThomas Chou MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */ 963272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 964272cc70bSAndy Fleming cmd.cmdarg = 0; 965272cc70bSAndy Fleming 966272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 967272cc70bSAndy Fleming 968272cc70bSAndy Fleming if (err) 969272cc70bSAndy Fleming return err; 970272cc70bSAndy Fleming 971272cc70bSAndy Fleming memcpy(mmc->cid, cmd.response, 16); 972272cc70bSAndy Fleming 973272cc70bSAndy Fleming /* 974272cc70bSAndy Fleming * For MMC cards, set the Relative Address. 975272cc70bSAndy Fleming * For SD cards, get the Relatvie Address. 976272cc70bSAndy Fleming * This also puts the cards into Standby State 977272cc70bSAndy Fleming */ 978d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 979272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR; 980272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 981272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R6; 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 if (IS_SD(mmc)) 989998be3ddSRabin Vincent mmc->rca = (cmd.response[0] >> 16) & 0xffff; 990d52ebf10SThomas Chou } 991272cc70bSAndy Fleming 992272cc70bSAndy Fleming /* Get the Card-Specific Data */ 993272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_CSD; 994272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 995272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 996272cc70bSAndy Fleming 997272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 998272cc70bSAndy Fleming 9995d4fc8d9SRaffaele Recalcati /* Waiting for the ready status */ 10005d4fc8d9SRaffaele Recalcati mmc_send_status(mmc, timeout); 10015d4fc8d9SRaffaele Recalcati 1002272cc70bSAndy Fleming if (err) 1003272cc70bSAndy Fleming return err; 1004272cc70bSAndy Fleming 1005998be3ddSRabin Vincent mmc->csd[0] = cmd.response[0]; 1006998be3ddSRabin Vincent mmc->csd[1] = cmd.response[1]; 1007998be3ddSRabin Vincent mmc->csd[2] = cmd.response[2]; 1008998be3ddSRabin Vincent mmc->csd[3] = cmd.response[3]; 1009272cc70bSAndy Fleming 1010272cc70bSAndy Fleming if (mmc->version == MMC_VERSION_UNKNOWN) { 10110b453ffeSRabin Vincent int version = (cmd.response[0] >> 26) & 0xf; 1012272cc70bSAndy Fleming 1013272cc70bSAndy Fleming switch (version) { 1014272cc70bSAndy Fleming case 0: 1015272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1016272cc70bSAndy Fleming break; 1017272cc70bSAndy Fleming case 1: 1018272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_4; 1019272cc70bSAndy Fleming break; 1020272cc70bSAndy Fleming case 2: 1021272cc70bSAndy Fleming mmc->version = MMC_VERSION_2_2; 1022272cc70bSAndy Fleming break; 1023272cc70bSAndy Fleming case 3: 1024272cc70bSAndy Fleming mmc->version = MMC_VERSION_3; 1025272cc70bSAndy Fleming break; 1026272cc70bSAndy Fleming case 4: 1027272cc70bSAndy Fleming mmc->version = MMC_VERSION_4; 1028272cc70bSAndy Fleming break; 1029272cc70bSAndy Fleming default: 1030272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1031272cc70bSAndy Fleming break; 1032272cc70bSAndy Fleming } 1033272cc70bSAndy Fleming } 1034272cc70bSAndy Fleming 1035272cc70bSAndy Fleming /* divide frequency by 10, since the mults are 10x bigger */ 10360b453ffeSRabin Vincent freq = fbase[(cmd.response[0] & 0x7)]; 10370b453ffeSRabin Vincent mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; 1038272cc70bSAndy Fleming 1039272cc70bSAndy Fleming mmc->tran_speed = freq * mult; 1040272cc70bSAndy Fleming 1041998be3ddSRabin Vincent mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf); 1042272cc70bSAndy Fleming 1043272cc70bSAndy Fleming if (IS_SD(mmc)) 1044272cc70bSAndy Fleming mmc->write_bl_len = mmc->read_bl_len; 1045272cc70bSAndy Fleming else 1046998be3ddSRabin Vincent mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf); 1047272cc70bSAndy Fleming 1048272cc70bSAndy Fleming if (mmc->high_capacity) { 1049272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3f) << 16 1050272cc70bSAndy Fleming | (mmc->csd[2] & 0xffff0000) >> 16; 1051272cc70bSAndy Fleming cmult = 8; 1052272cc70bSAndy Fleming } else { 1053272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3ff) << 2 1054272cc70bSAndy Fleming | (mmc->csd[2] & 0xc0000000) >> 30; 1055272cc70bSAndy Fleming cmult = (mmc->csd[2] & 0x00038000) >> 15; 1056272cc70bSAndy Fleming } 1057272cc70bSAndy Fleming 1058f866a46dSStephen Warren mmc->capacity_user = (csize + 1) << (cmult + 2); 1059f866a46dSStephen Warren mmc->capacity_user *= mmc->read_bl_len; 1060f866a46dSStephen Warren mmc->capacity_boot = 0; 1061f866a46dSStephen Warren mmc->capacity_rpmb = 0; 1062f866a46dSStephen Warren for (i = 0; i < 4; i++) 1063f866a46dSStephen Warren mmc->capacity_gp[i] = 0; 1064272cc70bSAndy Fleming 10658bfa195eSSimon Glass if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN) 10668bfa195eSSimon Glass mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 1067272cc70bSAndy Fleming 10688bfa195eSSimon Glass if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN) 10698bfa195eSSimon Glass mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 1070272cc70bSAndy Fleming 1071272cc70bSAndy Fleming /* Select the card, and put it into Transfer Mode */ 1072d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1073272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SELECT_CARD; 1074fe8f7066SAjay Bhargav cmd.resp_type = MMC_RSP_R1; 1075272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1076272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1077272cc70bSAndy Fleming 1078272cc70bSAndy Fleming if (err) 1079272cc70bSAndy Fleming return err; 1080d52ebf10SThomas Chou } 1081272cc70bSAndy Fleming 1082e6f99a56SLei Wen /* 1083e6f99a56SLei Wen * For SD, its erase group is always one sector 1084e6f99a56SLei Wen */ 1085e6f99a56SLei Wen mmc->erase_grp_size = 1; 1086bc897b1dSLei Wen mmc->part_config = MMCPART_NOAVAILABLE; 1087d23e2c09SSukumar Ghorai if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) { 1088d23e2c09SSukumar Ghorai /* check ext_csd version and capacity */ 1089d23e2c09SSukumar Ghorai err = mmc_send_ext_csd(mmc, ext_csd); 1090fdbb873eSKim Phillips if (!err && (ext_csd[EXT_CSD_REV] >= 2)) { 1091639b7827SYoshihiro Shimoda /* 1092639b7827SYoshihiro Shimoda * According to the JEDEC Standard, the value of 1093639b7827SYoshihiro Shimoda * ext_csd's capacity is valid if the value is more 1094639b7827SYoshihiro Shimoda * than 2GB 1095639b7827SYoshihiro Shimoda */ 10960560db18SLei Wen capacity = ext_csd[EXT_CSD_SEC_CNT] << 0 10970560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 10980560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 10990560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; 11008bfa195eSSimon Glass capacity *= MMC_MAX_BLOCK_LEN; 1101b1f1e821SŁukasz Majewski if ((capacity >> 20) > 2 * 1024) 1102f866a46dSStephen Warren mmc->capacity_user = capacity; 1103d23e2c09SSukumar Ghorai } 1104bc897b1dSLei Wen 110564f4a619SJaehoon Chung switch (ext_csd[EXT_CSD_REV]) { 110664f4a619SJaehoon Chung case 1: 110764f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_1; 110864f4a619SJaehoon Chung break; 110964f4a619SJaehoon Chung case 2: 111064f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_2; 111164f4a619SJaehoon Chung break; 111264f4a619SJaehoon Chung case 3: 111364f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_3; 111464f4a619SJaehoon Chung break; 111564f4a619SJaehoon Chung case 5: 111664f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_41; 111764f4a619SJaehoon Chung break; 111864f4a619SJaehoon Chung case 6: 111964f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_5; 112064f4a619SJaehoon Chung break; 112164f4a619SJaehoon Chung } 112264f4a619SJaehoon Chung 1123e6f99a56SLei Wen /* 1124e6f99a56SLei Wen * Check whether GROUP_DEF is set, if yes, read out 1125e6f99a56SLei Wen * group size from ext_csd directly, or calculate 1126e6f99a56SLei Wen * the group size from the csd value. 1127e6f99a56SLei Wen */ 11288bfa195eSSimon Glass if (ext_csd[EXT_CSD_ERASE_GROUP_DEF]) { 11290560db18SLei Wen mmc->erase_grp_size = 11308bfa195eSSimon Glass ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 11318bfa195eSSimon Glass MMC_MAX_BLOCK_LEN * 1024; 11328bfa195eSSimon Glass } else { 1133e6f99a56SLei Wen int erase_gsz, erase_gmul; 1134e6f99a56SLei Wen erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10; 1135e6f99a56SLei Wen erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5; 1136e6f99a56SLei Wen mmc->erase_grp_size = (erase_gsz + 1) 1137e6f99a56SLei Wen * (erase_gmul + 1); 1138e6f99a56SLei Wen } 1139e6f99a56SLei Wen 1140bc897b1dSLei Wen /* store the partition info of emmc */ 11418948ea83SStephen Warren if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || 11428948ea83SStephen Warren ext_csd[EXT_CSD_BOOT_MULT]) 11430560db18SLei Wen mmc->part_config = ext_csd[EXT_CSD_PART_CONF]; 1144f866a46dSStephen Warren 1145f866a46dSStephen Warren mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17; 1146f866a46dSStephen Warren 1147f866a46dSStephen Warren mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17; 1148f866a46dSStephen Warren 1149f866a46dSStephen Warren for (i = 0; i < 4; i++) { 1150f866a46dSStephen Warren int idx = EXT_CSD_GP_SIZE_MULT + i * 3; 1151f866a46dSStephen Warren mmc->capacity_gp[i] = (ext_csd[idx + 2] << 16) + 1152f866a46dSStephen Warren (ext_csd[idx + 1] << 8) + ext_csd[idx]; 1153f866a46dSStephen Warren mmc->capacity_gp[i] *= 1154f866a46dSStephen Warren ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 1155f866a46dSStephen Warren mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1156d23e2c09SSukumar Ghorai } 1157f866a46dSStephen Warren } 1158f866a46dSStephen Warren 1159f866a46dSStephen Warren err = mmc_set_capacity(mmc, mmc->part_num); 1160f866a46dSStephen Warren if (err) 1161f866a46dSStephen Warren return err; 1162d23e2c09SSukumar Ghorai 1163272cc70bSAndy Fleming if (IS_SD(mmc)) 1164272cc70bSAndy Fleming err = sd_change_freq(mmc); 1165272cc70bSAndy Fleming else 1166272cc70bSAndy Fleming err = mmc_change_freq(mmc); 1167272cc70bSAndy Fleming 1168272cc70bSAndy Fleming if (err) 1169272cc70bSAndy Fleming return err; 1170272cc70bSAndy Fleming 1171272cc70bSAndy Fleming /* Restrict card's capabilities by what the host can do */ 1172272cc70bSAndy Fleming mmc->card_caps &= mmc->host_caps; 1173272cc70bSAndy Fleming 1174272cc70bSAndy Fleming if (IS_SD(mmc)) { 1175272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_4BIT) { 1176272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 1177272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1178272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1179272cc70bSAndy Fleming 1180272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1181272cc70bSAndy Fleming if (err) 1182272cc70bSAndy Fleming return err; 1183272cc70bSAndy Fleming 1184272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH; 1185272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1186272cc70bSAndy Fleming cmd.cmdarg = 2; 1187272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1188272cc70bSAndy Fleming if (err) 1189272cc70bSAndy Fleming return err; 1190272cc70bSAndy Fleming 1191272cc70bSAndy Fleming mmc_set_bus_width(mmc, 4); 1192272cc70bSAndy Fleming } 1193272cc70bSAndy Fleming 1194272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_HS) 1195ad5fd922SJaehoon Chung mmc->tran_speed = 50000000; 1196272cc70bSAndy Fleming else 1197ad5fd922SJaehoon Chung mmc->tran_speed = 25000000; 1198272cc70bSAndy Fleming } else { 11997798f6dbSAndy Fleming int idx; 12007798f6dbSAndy Fleming 12017798f6dbSAndy Fleming /* An array of possible bus widths in order of preference */ 12027798f6dbSAndy Fleming static unsigned ext_csd_bits[] = { 12037798f6dbSAndy Fleming EXT_CSD_BUS_WIDTH_8, 12047798f6dbSAndy Fleming EXT_CSD_BUS_WIDTH_4, 12057798f6dbSAndy Fleming EXT_CSD_BUS_WIDTH_1, 12067798f6dbSAndy Fleming }; 12077798f6dbSAndy Fleming 12087798f6dbSAndy Fleming /* An array to map CSD bus widths to host cap bits */ 12097798f6dbSAndy Fleming static unsigned ext_to_hostcaps[] = { 12107798f6dbSAndy Fleming [EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT, 12117798f6dbSAndy Fleming [EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT, 12127798f6dbSAndy Fleming }; 12137798f6dbSAndy Fleming 12147798f6dbSAndy Fleming /* An array to map chosen bus width to an integer */ 12157798f6dbSAndy Fleming static unsigned widths[] = { 12167798f6dbSAndy Fleming 8, 4, 1, 12177798f6dbSAndy Fleming }; 12187798f6dbSAndy Fleming 12197798f6dbSAndy Fleming for (idx=0; idx < ARRAY_SIZE(ext_csd_bits); idx++) { 12207798f6dbSAndy Fleming unsigned int extw = ext_csd_bits[idx]; 12217798f6dbSAndy Fleming 12227798f6dbSAndy Fleming /* 12237798f6dbSAndy Fleming * Check to make sure the controller supports 12247798f6dbSAndy Fleming * this bus width, if it's more than 1 12257798f6dbSAndy Fleming */ 12267798f6dbSAndy Fleming if (extw != EXT_CSD_BUS_WIDTH_1 && 12277798f6dbSAndy Fleming !(mmc->host_caps & ext_to_hostcaps[extw])) 12287798f6dbSAndy Fleming continue; 12297798f6dbSAndy Fleming 1230272cc70bSAndy Fleming err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 12317798f6dbSAndy Fleming EXT_CSD_BUS_WIDTH, extw); 1232272cc70bSAndy Fleming 1233272cc70bSAndy Fleming if (err) 12344137894eSLei Wen continue; 1235272cc70bSAndy Fleming 12367798f6dbSAndy Fleming mmc_set_bus_width(mmc, widths[idx]); 1237272cc70bSAndy Fleming 12384137894eSLei Wen err = mmc_send_ext_csd(mmc, test_csd); 12394137894eSLei Wen if (!err && ext_csd[EXT_CSD_PARTITIONING_SUPPORT] \ 12404137894eSLei Wen == test_csd[EXT_CSD_PARTITIONING_SUPPORT] 12414137894eSLei Wen && ext_csd[EXT_CSD_ERASE_GROUP_DEF] \ 12424137894eSLei Wen == test_csd[EXT_CSD_ERASE_GROUP_DEF] \ 12434137894eSLei Wen && ext_csd[EXT_CSD_REV] \ 12444137894eSLei Wen == test_csd[EXT_CSD_REV] 12454137894eSLei Wen && ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] \ 12464137894eSLei Wen == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 12474137894eSLei Wen && memcmp(&ext_csd[EXT_CSD_SEC_CNT], \ 12484137894eSLei Wen &test_csd[EXT_CSD_SEC_CNT], 4) == 0) { 1249272cc70bSAndy Fleming 12507798f6dbSAndy Fleming mmc->card_caps |= ext_to_hostcaps[extw]; 12514137894eSLei Wen break; 12524137894eSLei Wen } 1253272cc70bSAndy Fleming } 1254272cc70bSAndy Fleming 1255272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_HS) { 1256272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_HS_52MHz) 1257ad5fd922SJaehoon Chung mmc->tran_speed = 52000000; 1258272cc70bSAndy Fleming else 1259ad5fd922SJaehoon Chung mmc->tran_speed = 26000000; 1260272cc70bSAndy Fleming } 1261ad5fd922SJaehoon Chung } 1262ad5fd922SJaehoon Chung 1263ad5fd922SJaehoon Chung mmc_set_clock(mmc, mmc->tran_speed); 1264272cc70bSAndy Fleming 1265272cc70bSAndy Fleming /* fill in device description */ 1266272cc70bSAndy Fleming mmc->block_dev.lun = 0; 1267272cc70bSAndy Fleming mmc->block_dev.type = 0; 1268272cc70bSAndy Fleming mmc->block_dev.blksz = mmc->read_bl_len; 12690472fbfdSEgbert Eich mmc->block_dev.log2blksz = LOG2(mmc->block_dev.blksz); 12709b1f942cSRabin Vincent mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len); 1271babce5f6STaylor Hutt sprintf(mmc->block_dev.vendor, "Man %06x Snr %04x%04x", 1272babce5f6STaylor Hutt mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff), 1273babce5f6STaylor Hutt (mmc->cid[3] >> 16) & 0xffff); 1274babce5f6STaylor Hutt sprintf(mmc->block_dev.product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff, 12750b453ffeSRabin Vincent (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, 1276babce5f6STaylor Hutt (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff, 1277babce5f6STaylor Hutt (mmc->cid[2] >> 24) & 0xff); 1278babce5f6STaylor Hutt sprintf(mmc->block_dev.revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf, 1279babce5f6STaylor Hutt (mmc->cid[2] >> 16) & 0xf); 1280122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT) 1281272cc70bSAndy Fleming init_part(&mmc->block_dev); 1282122efd43SMikhail Kshevetskiy #endif 1283272cc70bSAndy Fleming 1284272cc70bSAndy Fleming return 0; 1285272cc70bSAndy Fleming } 1286272cc70bSAndy Fleming 1287fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc) 1288272cc70bSAndy Fleming { 1289272cc70bSAndy Fleming struct mmc_cmd cmd; 1290272cc70bSAndy Fleming int err; 1291272cc70bSAndy Fleming 1292272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_IF_COND; 1293272cc70bSAndy Fleming /* We set the bit if the host supports voltages between 2.7 and 3.6 V */ 1294272cc70bSAndy Fleming cmd.cmdarg = ((mmc->voltages & 0xff8000) != 0) << 8 | 0xaa; 1295272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R7; 1296272cc70bSAndy Fleming 1297272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1298272cc70bSAndy Fleming 1299272cc70bSAndy Fleming if (err) 1300272cc70bSAndy Fleming return err; 1301272cc70bSAndy Fleming 1302998be3ddSRabin Vincent if ((cmd.response[0] & 0xff) != 0xaa) 1303272cc70bSAndy Fleming return UNUSABLE_ERR; 1304272cc70bSAndy Fleming else 1305272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 1306272cc70bSAndy Fleming 1307272cc70bSAndy Fleming return 0; 1308272cc70bSAndy Fleming } 1309272cc70bSAndy Fleming 1310272cc70bSAndy Fleming int mmc_register(struct mmc *mmc) 1311272cc70bSAndy Fleming { 1312272cc70bSAndy Fleming /* Setup the universal parts of the block interface just once */ 1313272cc70bSAndy Fleming mmc->block_dev.if_type = IF_TYPE_MMC; 1314272cc70bSAndy Fleming mmc->block_dev.dev = cur_dev_num++; 1315272cc70bSAndy Fleming mmc->block_dev.removable = 1; 1316272cc70bSAndy Fleming mmc->block_dev.block_read = mmc_bread; 1317272cc70bSAndy Fleming mmc->block_dev.block_write = mmc_bwrite; 1318e6f99a56SLei Wen mmc->block_dev.block_erase = mmc_berase; 13198feafcc4SJohn Rigby if (!mmc->b_max) 13208feafcc4SJohn Rigby mmc->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; 1321272cc70bSAndy Fleming 1322272cc70bSAndy Fleming INIT_LIST_HEAD (&mmc->link); 1323272cc70bSAndy Fleming 1324272cc70bSAndy Fleming list_add_tail (&mmc->link, &mmc_devices); 1325272cc70bSAndy Fleming 1326272cc70bSAndy Fleming return 0; 1327272cc70bSAndy Fleming } 1328272cc70bSAndy Fleming 1329df3fc526SMatthew McClintock #ifdef CONFIG_PARTITIONS 1330272cc70bSAndy Fleming block_dev_desc_t *mmc_get_dev(int dev) 1331272cc70bSAndy Fleming { 1332272cc70bSAndy Fleming struct mmc *mmc = find_mmc_device(dev); 13336bb4b4bcSBenoît Thébaudeau if (!mmc || mmc_init(mmc)) 133440242bc3SŁukasz Majewski return NULL; 1335272cc70bSAndy Fleming 133640242bc3SŁukasz Majewski return &mmc->block_dev; 1337272cc70bSAndy Fleming } 1338df3fc526SMatthew McClintock #endif 1339272cc70bSAndy Fleming 1340e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc) 1341272cc70bSAndy Fleming { 1342afd5932bSMacpaul Lin int err; 1343272cc70bSAndy Fleming 134448972d90SThierry Reding if (mmc_getcd(mmc) == 0) { 134548972d90SThierry Reding mmc->has_init = 0; 134648972d90SThierry Reding printf("MMC: no card present\n"); 134748972d90SThierry Reding return NO_CARD_ERR; 134848972d90SThierry Reding } 134948972d90SThierry Reding 1350bc897b1dSLei Wen if (mmc->has_init) 1351bc897b1dSLei Wen return 0; 1352bc897b1dSLei Wen 1353272cc70bSAndy Fleming err = mmc->init(mmc); 1354272cc70bSAndy Fleming 1355272cc70bSAndy Fleming if (err) 1356272cc70bSAndy Fleming return err; 1357272cc70bSAndy Fleming 1358b86b85e2SIlya Yanok mmc_set_bus_width(mmc, 1); 1359b86b85e2SIlya Yanok mmc_set_clock(mmc, 1); 1360b86b85e2SIlya Yanok 1361272cc70bSAndy Fleming /* Reset the Card */ 1362272cc70bSAndy Fleming err = mmc_go_idle(mmc); 1363272cc70bSAndy Fleming 1364272cc70bSAndy Fleming if (err) 1365272cc70bSAndy Fleming return err; 1366272cc70bSAndy Fleming 1367bc897b1dSLei Wen /* The internal partition reset to user partition(0) at every CMD0*/ 1368bc897b1dSLei Wen mmc->part_num = 0; 1369bc897b1dSLei Wen 1370272cc70bSAndy Fleming /* Test for SD version 2 */ 1371272cc70bSAndy Fleming err = mmc_send_if_cond(mmc); 1372272cc70bSAndy Fleming 1373272cc70bSAndy Fleming /* Now try to get the SD card's operating condition */ 1374272cc70bSAndy Fleming err = sd_send_op_cond(mmc); 1375272cc70bSAndy Fleming 1376272cc70bSAndy Fleming /* If the command timed out, we check for an MMC card */ 1377272cc70bSAndy Fleming if (err == TIMEOUT) { 1378272cc70bSAndy Fleming err = mmc_send_op_cond(mmc); 1379272cc70bSAndy Fleming 1380e9550449SChe-Liang Chiou if (err && err != IN_PROGRESS) { 1381272cc70bSAndy Fleming printf("Card did not respond to voltage select!\n"); 1382272cc70bSAndy Fleming return UNUSABLE_ERR; 1383272cc70bSAndy Fleming } 1384272cc70bSAndy Fleming } 1385272cc70bSAndy Fleming 1386e9550449SChe-Liang Chiou if (err == IN_PROGRESS) 1387e9550449SChe-Liang Chiou mmc->init_in_progress = 1; 1388e9550449SChe-Liang Chiou 1389e9550449SChe-Liang Chiou return err; 1390e9550449SChe-Liang Chiou } 1391e9550449SChe-Liang Chiou 1392e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc) 1393e9550449SChe-Liang Chiou { 1394e9550449SChe-Liang Chiou int err = 0; 1395e9550449SChe-Liang Chiou 1396e9550449SChe-Liang Chiou if (mmc->op_cond_pending) 1397e9550449SChe-Liang Chiou err = mmc_complete_op_cond(mmc); 1398e9550449SChe-Liang Chiou 1399e9550449SChe-Liang Chiou if (!err) 1400bc897b1dSLei Wen err = mmc_startup(mmc); 1401bc897b1dSLei Wen if (err) 1402bc897b1dSLei Wen mmc->has_init = 0; 1403bc897b1dSLei Wen else 1404bc897b1dSLei Wen mmc->has_init = 1; 1405e9550449SChe-Liang Chiou mmc->init_in_progress = 0; 1406e9550449SChe-Liang Chiou return err; 1407e9550449SChe-Liang Chiou } 1408e9550449SChe-Liang Chiou 1409e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc) 1410e9550449SChe-Liang Chiou { 1411e9550449SChe-Liang Chiou int err = IN_PROGRESS; 1412e9550449SChe-Liang Chiou unsigned start = get_timer(0); 1413e9550449SChe-Liang Chiou 1414e9550449SChe-Liang Chiou if (mmc->has_init) 1415e9550449SChe-Liang Chiou return 0; 1416e9550449SChe-Liang Chiou if (!mmc->init_in_progress) 1417e9550449SChe-Liang Chiou err = mmc_start_init(mmc); 1418e9550449SChe-Liang Chiou 1419e9550449SChe-Liang Chiou if (!err || err == IN_PROGRESS) 1420e9550449SChe-Liang Chiou err = mmc_complete_init(mmc); 1421e9550449SChe-Liang Chiou debug("%s: %d, time %lu\n", __func__, err, get_timer(start)); 1422bc897b1dSLei Wen return err; 1423272cc70bSAndy Fleming } 1424272cc70bSAndy Fleming 1425272cc70bSAndy Fleming /* 1426272cc70bSAndy Fleming * CPU and board-specific MMC initializations. Aliased function 1427272cc70bSAndy Fleming * signals caller to move on 1428272cc70bSAndy Fleming */ 1429272cc70bSAndy Fleming static int __def_mmc_init(bd_t *bis) 1430272cc70bSAndy Fleming { 1431272cc70bSAndy Fleming return -1; 1432272cc70bSAndy Fleming } 1433272cc70bSAndy Fleming 1434f9a109b3SPeter Tyser int cpu_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init"))); 1435f9a109b3SPeter Tyser int board_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init"))); 1436272cc70bSAndy Fleming 1437272cc70bSAndy Fleming void print_mmc_devices(char separator) 1438272cc70bSAndy Fleming { 1439272cc70bSAndy Fleming struct mmc *m; 1440272cc70bSAndy Fleming struct list_head *entry; 1441272cc70bSAndy Fleming 1442272cc70bSAndy Fleming list_for_each(entry, &mmc_devices) { 1443272cc70bSAndy Fleming m = list_entry(entry, struct mmc, link); 1444272cc70bSAndy Fleming 1445272cc70bSAndy Fleming printf("%s: %d", m->name, m->block_dev.dev); 1446272cc70bSAndy Fleming 1447272cc70bSAndy Fleming if (entry->next != &mmc_devices) 1448272cc70bSAndy Fleming printf("%c ", separator); 1449272cc70bSAndy Fleming } 1450272cc70bSAndy Fleming 1451272cc70bSAndy Fleming printf("\n"); 1452272cc70bSAndy Fleming } 1453272cc70bSAndy Fleming 1454ea6ebe21SLei Wen int get_mmc_num(void) 1455ea6ebe21SLei Wen { 1456ea6ebe21SLei Wen return cur_dev_num; 1457ea6ebe21SLei Wen } 1458ea6ebe21SLei Wen 1459e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit) 1460e9550449SChe-Liang Chiou { 1461e9550449SChe-Liang Chiou mmc->preinit = preinit; 1462e9550449SChe-Liang Chiou } 1463e9550449SChe-Liang Chiou 1464e9550449SChe-Liang Chiou static void do_preinit(void) 1465e9550449SChe-Liang Chiou { 1466e9550449SChe-Liang Chiou struct mmc *m; 1467e9550449SChe-Liang Chiou struct list_head *entry; 1468e9550449SChe-Liang Chiou 1469e9550449SChe-Liang Chiou list_for_each(entry, &mmc_devices) { 1470e9550449SChe-Liang Chiou m = list_entry(entry, struct mmc, link); 1471e9550449SChe-Liang Chiou 1472e9550449SChe-Liang Chiou if (m->preinit) 1473e9550449SChe-Liang Chiou mmc_start_init(m); 1474e9550449SChe-Liang Chiou } 1475e9550449SChe-Liang Chiou } 1476e9550449SChe-Liang Chiou 1477e9550449SChe-Liang Chiou 1478272cc70bSAndy Fleming int mmc_initialize(bd_t *bis) 1479272cc70bSAndy Fleming { 1480272cc70bSAndy Fleming INIT_LIST_HEAD (&mmc_devices); 1481272cc70bSAndy Fleming cur_dev_num = 0; 1482272cc70bSAndy Fleming 1483272cc70bSAndy Fleming if (board_mmc_init(bis) < 0) 1484272cc70bSAndy Fleming cpu_mmc_init(bis); 1485272cc70bSAndy Fleming 1486272cc70bSAndy Fleming print_mmc_devices(','); 1487272cc70bSAndy Fleming 1488e9550449SChe-Liang Chiou do_preinit(); 1489272cc70bSAndy Fleming return 0; 1490272cc70bSAndy Fleming } 14913690d6d6SAmar 14923690d6d6SAmar #ifdef CONFIG_SUPPORT_EMMC_BOOT 14933690d6d6SAmar /* 14943690d6d6SAmar * This function changes the size of boot partition and the size of rpmb 14953690d6d6SAmar * partition present on EMMC devices. 14963690d6d6SAmar * 14973690d6d6SAmar * Input Parameters: 14983690d6d6SAmar * struct *mmc: pointer for the mmc device strcuture 14993690d6d6SAmar * bootsize: size of boot partition 15003690d6d6SAmar * rpmbsize: size of rpmb partition 15013690d6d6SAmar * 15023690d6d6SAmar * Returns 0 on success. 15033690d6d6SAmar */ 15043690d6d6SAmar 15053690d6d6SAmar int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize, 15063690d6d6SAmar unsigned long rpmbsize) 15073690d6d6SAmar { 15083690d6d6SAmar int err; 15093690d6d6SAmar struct mmc_cmd cmd; 15103690d6d6SAmar 15113690d6d6SAmar /* Only use this command for raw EMMC moviNAND. Enter backdoor mode */ 15123690d6d6SAmar cmd.cmdidx = MMC_CMD_RES_MAN; 15133690d6d6SAmar cmd.resp_type = MMC_RSP_R1b; 15143690d6d6SAmar cmd.cmdarg = MMC_CMD62_ARG1; 15153690d6d6SAmar 15163690d6d6SAmar err = mmc_send_cmd(mmc, &cmd, NULL); 15173690d6d6SAmar if (err) { 15183690d6d6SAmar debug("mmc_boot_partition_size_change: Error1 = %d\n", err); 15193690d6d6SAmar return err; 15203690d6d6SAmar } 15213690d6d6SAmar 15223690d6d6SAmar /* Boot partition changing mode */ 15233690d6d6SAmar cmd.cmdidx = MMC_CMD_RES_MAN; 15243690d6d6SAmar cmd.resp_type = MMC_RSP_R1b; 15253690d6d6SAmar cmd.cmdarg = MMC_CMD62_ARG2; 15263690d6d6SAmar 15273690d6d6SAmar err = mmc_send_cmd(mmc, &cmd, NULL); 15283690d6d6SAmar if (err) { 15293690d6d6SAmar debug("mmc_boot_partition_size_change: Error2 = %d\n", err); 15303690d6d6SAmar return err; 15313690d6d6SAmar } 15323690d6d6SAmar /* boot partition size is multiple of 128KB */ 15333690d6d6SAmar bootsize = (bootsize * 1024) / 128; 15343690d6d6SAmar 15353690d6d6SAmar /* Arg: boot partition size */ 15363690d6d6SAmar cmd.cmdidx = MMC_CMD_RES_MAN; 15373690d6d6SAmar cmd.resp_type = MMC_RSP_R1b; 15383690d6d6SAmar cmd.cmdarg = bootsize; 15393690d6d6SAmar 15403690d6d6SAmar err = mmc_send_cmd(mmc, &cmd, NULL); 15413690d6d6SAmar if (err) { 15423690d6d6SAmar debug("mmc_boot_partition_size_change: Error3 = %d\n", err); 15433690d6d6SAmar return err; 15443690d6d6SAmar } 15453690d6d6SAmar /* RPMB partition size is multiple of 128KB */ 15463690d6d6SAmar rpmbsize = (rpmbsize * 1024) / 128; 15473690d6d6SAmar /* Arg: RPMB partition size */ 15483690d6d6SAmar cmd.cmdidx = MMC_CMD_RES_MAN; 15493690d6d6SAmar cmd.resp_type = MMC_RSP_R1b; 15503690d6d6SAmar cmd.cmdarg = rpmbsize; 15513690d6d6SAmar 15523690d6d6SAmar err = mmc_send_cmd(mmc, &cmd, NULL); 15533690d6d6SAmar if (err) { 15543690d6d6SAmar debug("mmc_boot_partition_size_change: Error4 = %d\n", err); 15553690d6d6SAmar return err; 15563690d6d6SAmar } 15573690d6d6SAmar return 0; 15583690d6d6SAmar } 15593690d6d6SAmar 15603690d6d6SAmar /* 15613690d6d6SAmar * This function shall form and send the commands to open / close the 15623690d6d6SAmar * boot partition specified by user. 15633690d6d6SAmar * 15643690d6d6SAmar * Input Parameters: 15653690d6d6SAmar * ack: 0x0 - No boot acknowledge sent (default) 15663690d6d6SAmar * 0x1 - Boot acknowledge sent during boot operation 15673690d6d6SAmar * part_num: User selects boot data that will be sent to master 15683690d6d6SAmar * 0x0 - Device not boot enabled (default) 15693690d6d6SAmar * 0x1 - Boot partition 1 enabled for boot 15703690d6d6SAmar * 0x2 - Boot partition 2 enabled for boot 15713690d6d6SAmar * access: User selects partitions to access 15723690d6d6SAmar * 0x0 : No access to boot partition (default) 15733690d6d6SAmar * 0x1 : R/W boot partition 1 15743690d6d6SAmar * 0x2 : R/W boot partition 2 15753690d6d6SAmar * 0x3 : R/W Replay Protected Memory Block (RPMB) 15763690d6d6SAmar * 15773690d6d6SAmar * Returns 0 on success. 15783690d6d6SAmar */ 15793690d6d6SAmar int mmc_boot_part_access(struct mmc *mmc, u8 ack, u8 part_num, u8 access) 15803690d6d6SAmar { 15813690d6d6SAmar int err; 15823690d6d6SAmar struct mmc_cmd cmd; 15833690d6d6SAmar 15843690d6d6SAmar /* Boot ack enable, boot partition enable , boot partition access */ 15853690d6d6SAmar cmd.cmdidx = MMC_CMD_SWITCH; 15863690d6d6SAmar cmd.resp_type = MMC_RSP_R1b; 15873690d6d6SAmar 15883690d6d6SAmar cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | 15893690d6d6SAmar (EXT_CSD_PART_CONF << 16) | 15903690d6d6SAmar ((EXT_CSD_BOOT_ACK(ack) | 15913690d6d6SAmar EXT_CSD_BOOT_PART_NUM(part_num) | 15923690d6d6SAmar EXT_CSD_PARTITION_ACCESS(access)) << 8); 15933690d6d6SAmar 15943690d6d6SAmar err = mmc_send_cmd(mmc, &cmd, NULL); 15953690d6d6SAmar if (err) { 15963690d6d6SAmar if (access) { 15973690d6d6SAmar debug("mmc boot partition#%d open fail:Error1 = %d\n", 15983690d6d6SAmar part_num, err); 15993690d6d6SAmar } else { 16003690d6d6SAmar debug("mmc boot partition#%d close fail:Error = %d\n", 16013690d6d6SAmar part_num, err); 16023690d6d6SAmar } 16033690d6d6SAmar return err; 16043690d6d6SAmar } 16053690d6d6SAmar 16063690d6d6SAmar if (access) { 16073690d6d6SAmar /* 4bit transfer mode at booting time. */ 16083690d6d6SAmar cmd.cmdidx = MMC_CMD_SWITCH; 16093690d6d6SAmar cmd.resp_type = MMC_RSP_R1b; 16103690d6d6SAmar 16113690d6d6SAmar cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | 16123690d6d6SAmar (EXT_CSD_BOOT_BUS_WIDTH << 16) | 16133690d6d6SAmar ((1 << 0) << 8); 16143690d6d6SAmar 16153690d6d6SAmar err = mmc_send_cmd(mmc, &cmd, NULL); 16163690d6d6SAmar if (err) { 16173690d6d6SAmar debug("mmc boot partition#%d open fail:Error2 = %d\n", 16183690d6d6SAmar part_num, err); 16193690d6d6SAmar return err; 16203690d6d6SAmar } 16213690d6d6SAmar } 16223690d6d6SAmar return 0; 16233690d6d6SAmar } 16243690d6d6SAmar #endif 1625