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> 18da61fa5fSPaul Burton #include "mmc_private.h" 19272cc70bSAndy Fleming 20ce0fbcd2SMatt Waddel /* Set block count limit because of 16 bit register limit on some hardware*/ 21ce0fbcd2SMatt Waddel #ifndef CONFIG_SYS_MMC_MAX_BLK_COUNT 22ce0fbcd2SMatt Waddel #define CONFIG_SYS_MMC_MAX_BLK_COUNT 65535 23ce0fbcd2SMatt Waddel #endif 24ce0fbcd2SMatt Waddel 25272cc70bSAndy Fleming static struct list_head mmc_devices; 26272cc70bSAndy Fleming static int cur_dev_num = -1; 27272cc70bSAndy Fleming 28d23d8d7eSNikita Kiryanov int __weak board_mmc_getwp(struct mmc *mmc) 29d23d8d7eSNikita Kiryanov { 30d23d8d7eSNikita Kiryanov return -1; 31d23d8d7eSNikita Kiryanov } 32d23d8d7eSNikita Kiryanov 33d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc) 34d23d8d7eSNikita Kiryanov { 35d23d8d7eSNikita Kiryanov int wp; 36d23d8d7eSNikita Kiryanov 37d23d8d7eSNikita Kiryanov wp = board_mmc_getwp(mmc); 38d23d8d7eSNikita Kiryanov 39d4e1da4eSPeter Korsgaard if (wp < 0) { 40*ab769f22SPantelis Antoniou if (mmc->ops->getwp) 41*ab769f22SPantelis Antoniou wp = mmc->ops->getwp(mmc); 42d4e1da4eSPeter Korsgaard else 43d4e1da4eSPeter Korsgaard wp = 0; 44d4e1da4eSPeter Korsgaard } 45d23d8d7eSNikita Kiryanov 46d23d8d7eSNikita Kiryanov return wp; 47d23d8d7eSNikita Kiryanov } 48d23d8d7eSNikita Kiryanov 49314284b1SThierry Reding int __board_mmc_getcd(struct mmc *mmc) { 5011fdade2SStefano Babic return -1; 5111fdade2SStefano Babic } 5211fdade2SStefano Babic 53314284b1SThierry Reding int board_mmc_getcd(struct mmc *mmc)__attribute__((weak, 5411fdade2SStefano Babic alias("__board_mmc_getcd"))); 5511fdade2SStefano Babic 56da61fa5fSPaul Burton int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, 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); 66*ab769f22SPantelis Antoniou ret = mmc->ops->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 109*ab769f22SPantelis Antoniou ret = mmc->ops->send_cmd(mmc, cmd, data); 1105db2fe3aSRaffaele Recalcati #endif 1118635ff9eSMarek Vasut return ret; 112272cc70bSAndy Fleming } 113272cc70bSAndy Fleming 114da61fa5fSPaul Burton 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) { 13556196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 136d617c426SJan Kloetzke printf("Status Error: 0x%08X\n", 137d617c426SJan Kloetzke cmd.response[0]); 13856196826SPaul 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) { 15356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 1545d4fc8d9SRaffaele Recalcati printf("Timeout waiting card ready\n"); 15556196826SPaul Burton #endif 1565d4fc8d9SRaffaele Recalcati return TIMEOUT; 1575d4fc8d9SRaffaele Recalcati } 1585d4fc8d9SRaffaele Recalcati 1595d4fc8d9SRaffaele Recalcati return 0; 1605d4fc8d9SRaffaele Recalcati } 1615d4fc8d9SRaffaele Recalcati 162da61fa5fSPaul Burton 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 18556196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 186272cc70bSAndy Fleming printf("MMC Device %d not found\n", dev_num); 18756196826SPaul Burton #endif 188272cc70bSAndy Fleming 189272cc70bSAndy Fleming return NULL; 190272cc70bSAndy Fleming } 191272cc70bSAndy Fleming 192ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start, 193fdbb873eSKim Phillips lbaint_t blkcnt) 194272cc70bSAndy Fleming { 195272cc70bSAndy Fleming struct mmc_cmd cmd; 196272cc70bSAndy Fleming struct mmc_data data; 197272cc70bSAndy Fleming 1984a1a06bcSAlagu Sankar if (blkcnt > 1) 1994a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; 2004a1a06bcSAlagu Sankar else 201272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK; 202272cc70bSAndy Fleming 203272cc70bSAndy Fleming if (mmc->high_capacity) 2044a1a06bcSAlagu Sankar cmd.cmdarg = start; 205272cc70bSAndy Fleming else 2064a1a06bcSAlagu Sankar cmd.cmdarg = start * mmc->read_bl_len; 207272cc70bSAndy Fleming 208272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 209272cc70bSAndy Fleming 210272cc70bSAndy Fleming data.dest = dst; 2114a1a06bcSAlagu Sankar data.blocks = blkcnt; 212272cc70bSAndy Fleming data.blocksize = mmc->read_bl_len; 213272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 214272cc70bSAndy Fleming 2154a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, &data)) 2164a1a06bcSAlagu Sankar return 0; 2174a1a06bcSAlagu Sankar 2184a1a06bcSAlagu Sankar if (blkcnt > 1) { 2194a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; 2204a1a06bcSAlagu Sankar cmd.cmdarg = 0; 2214a1a06bcSAlagu Sankar cmd.resp_type = MMC_RSP_R1b; 2224a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, NULL)) { 22356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2244a1a06bcSAlagu Sankar printf("mmc fail to send stop cmd\n"); 22556196826SPaul Burton #endif 2264a1a06bcSAlagu Sankar return 0; 2274a1a06bcSAlagu Sankar } 228272cc70bSAndy Fleming } 229272cc70bSAndy Fleming 2304a1a06bcSAlagu Sankar return blkcnt; 231272cc70bSAndy Fleming } 232272cc70bSAndy Fleming 233ff8fef56SSascha Silbe static ulong mmc_bread(int dev_num, lbaint_t start, lbaint_t blkcnt, void *dst) 234272cc70bSAndy Fleming { 2354a1a06bcSAlagu Sankar lbaint_t cur, blocks_todo = blkcnt; 236272cc70bSAndy Fleming 2374a1a06bcSAlagu Sankar if (blkcnt == 0) 2384a1a06bcSAlagu Sankar return 0; 2394a1a06bcSAlagu Sankar 2404a1a06bcSAlagu Sankar struct mmc *mmc = find_mmc_device(dev_num); 241272cc70bSAndy Fleming if (!mmc) 242272cc70bSAndy Fleming return 0; 243272cc70bSAndy Fleming 244d2bf29e3SLei Wen if ((start + blkcnt) > mmc->block_dev.lba) { 24556196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 246ff8fef56SSascha Silbe printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n", 247d2bf29e3SLei Wen start + blkcnt, mmc->block_dev.lba); 24856196826SPaul Burton #endif 249d2bf29e3SLei Wen return 0; 250d2bf29e3SLei Wen } 251272cc70bSAndy Fleming 2524a1a06bcSAlagu Sankar if (mmc_set_blocklen(mmc, mmc->read_bl_len)) 253272cc70bSAndy Fleming return 0; 254272cc70bSAndy Fleming 2554a1a06bcSAlagu Sankar do { 2568feafcc4SJohn Rigby cur = (blocks_todo > mmc->b_max) ? mmc->b_max : blocks_todo; 2574a1a06bcSAlagu Sankar if(mmc_read_blocks(mmc, dst, start, cur) != cur) 2584a1a06bcSAlagu Sankar return 0; 2594a1a06bcSAlagu Sankar blocks_todo -= cur; 2604a1a06bcSAlagu Sankar start += cur; 2614a1a06bcSAlagu Sankar dst += cur * mmc->read_bl_len; 2624a1a06bcSAlagu Sankar } while (blocks_todo > 0); 263272cc70bSAndy Fleming 264272cc70bSAndy Fleming return blkcnt; 265272cc70bSAndy Fleming } 266272cc70bSAndy Fleming 267fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc) 268272cc70bSAndy Fleming { 269272cc70bSAndy Fleming struct mmc_cmd cmd; 270272cc70bSAndy Fleming int err; 271272cc70bSAndy Fleming 272272cc70bSAndy Fleming udelay(1000); 273272cc70bSAndy Fleming 274272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_GO_IDLE_STATE; 275272cc70bSAndy Fleming cmd.cmdarg = 0; 276272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_NONE; 277272cc70bSAndy Fleming 278272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 279272cc70bSAndy Fleming 280272cc70bSAndy Fleming if (err) 281272cc70bSAndy Fleming return err; 282272cc70bSAndy Fleming 283272cc70bSAndy Fleming udelay(2000); 284272cc70bSAndy Fleming 285272cc70bSAndy Fleming return 0; 286272cc70bSAndy Fleming } 287272cc70bSAndy Fleming 288fdbb873eSKim Phillips static int sd_send_op_cond(struct mmc *mmc) 289272cc70bSAndy Fleming { 290272cc70bSAndy Fleming int timeout = 1000; 291272cc70bSAndy Fleming int err; 292272cc70bSAndy Fleming struct mmc_cmd cmd; 293272cc70bSAndy Fleming 294272cc70bSAndy Fleming do { 295272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 296272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 297272cc70bSAndy Fleming cmd.cmdarg = 0; 298272cc70bSAndy Fleming 299272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 300272cc70bSAndy Fleming 301272cc70bSAndy Fleming if (err) 302272cc70bSAndy Fleming return err; 303272cc70bSAndy Fleming 304272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_OP_COND; 305272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R3; 306250de12bSStefano Babic 307250de12bSStefano Babic /* 308250de12bSStefano Babic * Most cards do not answer if some reserved bits 309250de12bSStefano Babic * in the ocr are set. However, Some controller 310250de12bSStefano Babic * can set bit 7 (reserved for low voltages), but 311250de12bSStefano Babic * how to manage low voltages SD card is not yet 312250de12bSStefano Babic * specified. 313250de12bSStefano Babic */ 314d52ebf10SThomas Chou cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 : 315d52ebf10SThomas Chou (mmc->voltages & 0xff8000); 316272cc70bSAndy Fleming 317272cc70bSAndy Fleming if (mmc->version == SD_VERSION_2) 318272cc70bSAndy Fleming cmd.cmdarg |= OCR_HCS; 319272cc70bSAndy Fleming 320272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 321272cc70bSAndy Fleming 322272cc70bSAndy Fleming if (err) 323272cc70bSAndy Fleming return err; 324272cc70bSAndy Fleming 325272cc70bSAndy Fleming udelay(1000); 326272cc70bSAndy Fleming } while ((!(cmd.response[0] & OCR_BUSY)) && timeout--); 327272cc70bSAndy Fleming 328272cc70bSAndy Fleming if (timeout <= 0) 329272cc70bSAndy Fleming return UNUSABLE_ERR; 330272cc70bSAndy Fleming 331272cc70bSAndy Fleming if (mmc->version != SD_VERSION_2) 332272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 333272cc70bSAndy Fleming 334d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 335d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 336d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 337d52ebf10SThomas Chou cmd.cmdarg = 0; 338d52ebf10SThomas Chou 339d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 340d52ebf10SThomas Chou 341d52ebf10SThomas Chou if (err) 342d52ebf10SThomas Chou return err; 343d52ebf10SThomas Chou } 344d52ebf10SThomas Chou 345998be3ddSRabin Vincent mmc->ocr = cmd.response[0]; 346272cc70bSAndy Fleming 347272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 348272cc70bSAndy Fleming mmc->rca = 0; 349272cc70bSAndy Fleming 350272cc70bSAndy Fleming return 0; 351272cc70bSAndy Fleming } 352272cc70bSAndy Fleming 353e9550449SChe-Liang Chiou /* We pass in the cmd since otherwise the init seems to fail */ 354e9550449SChe-Liang Chiou static int mmc_send_op_cond_iter(struct mmc *mmc, struct mmc_cmd *cmd, 355e9550449SChe-Liang Chiou int use_arg) 356272cc70bSAndy Fleming { 357272cc70bSAndy Fleming int err; 358272cc70bSAndy Fleming 359e9550449SChe-Liang Chiou cmd->cmdidx = MMC_CMD_SEND_OP_COND; 360e9550449SChe-Liang Chiou cmd->resp_type = MMC_RSP_R3; 361e9550449SChe-Liang Chiou cmd->cmdarg = 0; 362e9550449SChe-Liang Chiou if (use_arg && !mmc_host_is_spi(mmc)) { 363e9550449SChe-Liang Chiou cmd->cmdarg = 364e9550449SChe-Liang Chiou (mmc->voltages & 365e9550449SChe-Liang Chiou (mmc->op_cond_response & OCR_VOLTAGE_MASK)) | 366e9550449SChe-Liang Chiou (mmc->op_cond_response & OCR_ACCESS_MODE); 367e9550449SChe-Liang Chiou 368e9550449SChe-Liang Chiou if (mmc->host_caps & MMC_MODE_HC) 369e9550449SChe-Liang Chiou cmd->cmdarg |= OCR_HCS; 370e9550449SChe-Liang Chiou } 371e9550449SChe-Liang Chiou err = mmc_send_cmd(mmc, cmd, NULL); 372e9550449SChe-Liang Chiou if (err) 373e9550449SChe-Liang Chiou return err; 374e9550449SChe-Liang Chiou mmc->op_cond_response = cmd->response[0]; 375e9550449SChe-Liang Chiou return 0; 376e9550449SChe-Liang Chiou } 377e9550449SChe-Liang Chiou 378e9550449SChe-Liang Chiou int mmc_send_op_cond(struct mmc *mmc) 379e9550449SChe-Liang Chiou { 380e9550449SChe-Liang Chiou struct mmc_cmd cmd; 381e9550449SChe-Liang Chiou int err, i; 382e9550449SChe-Liang Chiou 383272cc70bSAndy Fleming /* Some cards seem to need this */ 384272cc70bSAndy Fleming mmc_go_idle(mmc); 385272cc70bSAndy Fleming 38631cacbabSRaffaele Recalcati /* Asking to the card its capabilities */ 387e9550449SChe-Liang Chiou mmc->op_cond_pending = 1; 388e9550449SChe-Liang Chiou for (i = 0; i < 2; i++) { 389e9550449SChe-Liang Chiou err = mmc_send_op_cond_iter(mmc, &cmd, i != 0); 39031cacbabSRaffaele Recalcati if (err) 39131cacbabSRaffaele Recalcati return err; 39231cacbabSRaffaele Recalcati 393e9550449SChe-Liang Chiou /* exit if not busy (flag seems to be inverted) */ 394e9550449SChe-Liang Chiou if (mmc->op_cond_response & OCR_BUSY) 395e9550449SChe-Liang Chiou return 0; 396e9550449SChe-Liang Chiou } 397e9550449SChe-Liang Chiou return IN_PROGRESS; 398e9550449SChe-Liang Chiou } 39931cacbabSRaffaele Recalcati 400e9550449SChe-Liang Chiou int mmc_complete_op_cond(struct mmc *mmc) 401e9550449SChe-Liang Chiou { 402e9550449SChe-Liang Chiou struct mmc_cmd cmd; 403e9550449SChe-Liang Chiou int timeout = 1000; 404e9550449SChe-Liang Chiou uint start; 405e9550449SChe-Liang Chiou int err; 406e9550449SChe-Liang Chiou 407e9550449SChe-Liang Chiou mmc->op_cond_pending = 0; 408e9550449SChe-Liang Chiou start = get_timer(0); 409272cc70bSAndy Fleming do { 410e9550449SChe-Liang Chiou err = mmc_send_op_cond_iter(mmc, &cmd, 1); 411272cc70bSAndy Fleming if (err) 412272cc70bSAndy Fleming return err; 413e9550449SChe-Liang Chiou if (get_timer(start) > timeout) 414272cc70bSAndy Fleming return UNUSABLE_ERR; 415e9550449SChe-Liang Chiou udelay(100); 416e9550449SChe-Liang Chiou } while (!(mmc->op_cond_response & OCR_BUSY)); 417272cc70bSAndy Fleming 418d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 419d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 420d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 421d52ebf10SThomas Chou cmd.cmdarg = 0; 422d52ebf10SThomas Chou 423d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 424d52ebf10SThomas Chou 425d52ebf10SThomas Chou if (err) 426d52ebf10SThomas Chou return err; 427d52ebf10SThomas Chou } 428d52ebf10SThomas Chou 429272cc70bSAndy Fleming mmc->version = MMC_VERSION_UNKNOWN; 430998be3ddSRabin Vincent mmc->ocr = cmd.response[0]; 431272cc70bSAndy Fleming 432272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 433def816a2SStephen Warren mmc->rca = 1; 434272cc70bSAndy Fleming 435272cc70bSAndy Fleming return 0; 436272cc70bSAndy Fleming } 437272cc70bSAndy Fleming 438272cc70bSAndy Fleming 439fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd) 440272cc70bSAndy Fleming { 441272cc70bSAndy Fleming struct mmc_cmd cmd; 442272cc70bSAndy Fleming struct mmc_data data; 443272cc70bSAndy Fleming int err; 444272cc70bSAndy Fleming 445272cc70bSAndy Fleming /* Get the Card Status Register */ 446272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_EXT_CSD; 447272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 448272cc70bSAndy Fleming cmd.cmdarg = 0; 449272cc70bSAndy Fleming 450cdfd1ac6SYoshihiro Shimoda data.dest = (char *)ext_csd; 451272cc70bSAndy Fleming data.blocks = 1; 4528bfa195eSSimon Glass data.blocksize = MMC_MAX_BLOCK_LEN; 453272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 454272cc70bSAndy Fleming 455272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 456272cc70bSAndy Fleming 457272cc70bSAndy Fleming return err; 458272cc70bSAndy Fleming } 459272cc70bSAndy Fleming 460272cc70bSAndy Fleming 461fdbb873eSKim Phillips static int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) 462272cc70bSAndy Fleming { 463272cc70bSAndy Fleming struct mmc_cmd cmd; 4645d4fc8d9SRaffaele Recalcati int timeout = 1000; 4655d4fc8d9SRaffaele Recalcati int ret; 466272cc70bSAndy Fleming 467272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SWITCH; 468272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1b; 469272cc70bSAndy Fleming cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | 470272cc70bSAndy Fleming (index << 16) | 471272cc70bSAndy Fleming (value << 8); 472272cc70bSAndy Fleming 4735d4fc8d9SRaffaele Recalcati ret = mmc_send_cmd(mmc, &cmd, NULL); 4745d4fc8d9SRaffaele Recalcati 4755d4fc8d9SRaffaele Recalcati /* Waiting for the ready status */ 47693ad0d18SJan Kloetzke if (!ret) 47793ad0d18SJan Kloetzke ret = mmc_send_status(mmc, timeout); 4785d4fc8d9SRaffaele Recalcati 4795d4fc8d9SRaffaele Recalcati return ret; 4805d4fc8d9SRaffaele Recalcati 481272cc70bSAndy Fleming } 482272cc70bSAndy Fleming 483fdbb873eSKim Phillips static int mmc_change_freq(struct mmc *mmc) 484272cc70bSAndy Fleming { 4858bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 486272cc70bSAndy Fleming char cardtype; 487272cc70bSAndy Fleming int err; 488272cc70bSAndy Fleming 489272cc70bSAndy Fleming mmc->card_caps = 0; 490272cc70bSAndy Fleming 491d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 492d52ebf10SThomas Chou return 0; 493d52ebf10SThomas Chou 494272cc70bSAndy Fleming /* Only version 4 supports high-speed */ 495272cc70bSAndy Fleming if (mmc->version < MMC_VERSION_4) 496272cc70bSAndy Fleming return 0; 497272cc70bSAndy Fleming 498272cc70bSAndy Fleming err = mmc_send_ext_csd(mmc, ext_csd); 499272cc70bSAndy Fleming 500272cc70bSAndy Fleming if (err) 501272cc70bSAndy Fleming return err; 502272cc70bSAndy Fleming 5030560db18SLei Wen cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf; 504272cc70bSAndy Fleming 505272cc70bSAndy Fleming err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1); 506272cc70bSAndy Fleming 507272cc70bSAndy Fleming if (err) 508272cc70bSAndy Fleming return err; 509272cc70bSAndy Fleming 510272cc70bSAndy Fleming /* Now check to see that it worked */ 511272cc70bSAndy Fleming err = mmc_send_ext_csd(mmc, ext_csd); 512272cc70bSAndy Fleming 513272cc70bSAndy Fleming if (err) 514272cc70bSAndy Fleming return err; 515272cc70bSAndy Fleming 516272cc70bSAndy Fleming /* No high-speed support */ 5170560db18SLei Wen if (!ext_csd[EXT_CSD_HS_TIMING]) 518272cc70bSAndy Fleming return 0; 519272cc70bSAndy Fleming 520272cc70bSAndy Fleming /* High Speed is set, there are two types: 52MHz and 26MHz */ 521272cc70bSAndy Fleming if (cardtype & MMC_HS_52MHZ) 522272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; 523272cc70bSAndy Fleming else 524272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS; 525272cc70bSAndy Fleming 526272cc70bSAndy Fleming return 0; 527272cc70bSAndy Fleming } 528272cc70bSAndy Fleming 529f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num) 530f866a46dSStephen Warren { 531f866a46dSStephen Warren switch (part_num) { 532f866a46dSStephen Warren case 0: 533f866a46dSStephen Warren mmc->capacity = mmc->capacity_user; 534f866a46dSStephen Warren break; 535f866a46dSStephen Warren case 1: 536f866a46dSStephen Warren case 2: 537f866a46dSStephen Warren mmc->capacity = mmc->capacity_boot; 538f866a46dSStephen Warren break; 539f866a46dSStephen Warren case 3: 540f866a46dSStephen Warren mmc->capacity = mmc->capacity_rpmb; 541f866a46dSStephen Warren break; 542f866a46dSStephen Warren case 4: 543f866a46dSStephen Warren case 5: 544f866a46dSStephen Warren case 6: 545f866a46dSStephen Warren case 7: 546f866a46dSStephen Warren mmc->capacity = mmc->capacity_gp[part_num - 4]; 547f866a46dSStephen Warren break; 548f866a46dSStephen Warren default: 549f866a46dSStephen Warren return -1; 550f866a46dSStephen Warren } 551f866a46dSStephen Warren 552f866a46dSStephen Warren mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len); 553f866a46dSStephen Warren 554f866a46dSStephen Warren return 0; 555f866a46dSStephen Warren } 556f866a46dSStephen Warren 557bc897b1dSLei Wen int mmc_switch_part(int dev_num, unsigned int part_num) 558bc897b1dSLei Wen { 559bc897b1dSLei Wen struct mmc *mmc = find_mmc_device(dev_num); 560f866a46dSStephen Warren int ret; 561bc897b1dSLei Wen 562bc897b1dSLei Wen if (!mmc) 563bc897b1dSLei Wen return -1; 564bc897b1dSLei Wen 565f866a46dSStephen Warren ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, 566bc897b1dSLei Wen (mmc->part_config & ~PART_ACCESS_MASK) 567bc897b1dSLei Wen | (part_num & PART_ACCESS_MASK)); 568f866a46dSStephen Warren if (ret) 569f866a46dSStephen Warren return ret; 570f866a46dSStephen Warren 571f866a46dSStephen Warren return mmc_set_capacity(mmc, part_num); 572bc897b1dSLei Wen } 573bc897b1dSLei Wen 57448972d90SThierry Reding int mmc_getcd(struct mmc *mmc) 57548972d90SThierry Reding { 57648972d90SThierry Reding int cd; 57748972d90SThierry Reding 57848972d90SThierry Reding cd = board_mmc_getcd(mmc); 57948972d90SThierry Reding 580d4e1da4eSPeter Korsgaard if (cd < 0) { 581*ab769f22SPantelis Antoniou if (mmc->ops->getcd) 582*ab769f22SPantelis Antoniou cd = mmc->ops->getcd(mmc); 583d4e1da4eSPeter Korsgaard else 584d4e1da4eSPeter Korsgaard cd = 1; 585d4e1da4eSPeter Korsgaard } 58648972d90SThierry Reding 58748972d90SThierry Reding return cd; 58848972d90SThierry Reding } 58948972d90SThierry Reding 590fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) 591272cc70bSAndy Fleming { 592272cc70bSAndy Fleming struct mmc_cmd cmd; 593272cc70bSAndy Fleming struct mmc_data data; 594272cc70bSAndy Fleming 595272cc70bSAndy Fleming /* Switch the frequency */ 596272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SWITCH_FUNC; 597272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 598272cc70bSAndy Fleming cmd.cmdarg = (mode << 31) | 0xffffff; 599272cc70bSAndy Fleming cmd.cmdarg &= ~(0xf << (group * 4)); 600272cc70bSAndy Fleming cmd.cmdarg |= value << (group * 4); 601272cc70bSAndy Fleming 602272cc70bSAndy Fleming data.dest = (char *)resp; 603272cc70bSAndy Fleming data.blocksize = 64; 604272cc70bSAndy Fleming data.blocks = 1; 605272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 606272cc70bSAndy Fleming 607272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, &data); 608272cc70bSAndy Fleming } 609272cc70bSAndy Fleming 610272cc70bSAndy Fleming 611fdbb873eSKim Phillips static int sd_change_freq(struct mmc *mmc) 612272cc70bSAndy Fleming { 613272cc70bSAndy Fleming int err; 614272cc70bSAndy Fleming struct mmc_cmd cmd; 615f781dd38SAnton staaf ALLOC_CACHE_ALIGN_BUFFER(uint, scr, 2); 616f781dd38SAnton staaf ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16); 617272cc70bSAndy Fleming struct mmc_data data; 618272cc70bSAndy Fleming int timeout; 619272cc70bSAndy Fleming 620272cc70bSAndy Fleming mmc->card_caps = 0; 621272cc70bSAndy Fleming 622d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 623d52ebf10SThomas Chou return 0; 624d52ebf10SThomas Chou 625272cc70bSAndy Fleming /* Read the SCR to find out if this card supports higher speeds */ 626272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 627272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 628272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 629272cc70bSAndy Fleming 630272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 631272cc70bSAndy Fleming 632272cc70bSAndy Fleming if (err) 633272cc70bSAndy Fleming return err; 634272cc70bSAndy Fleming 635272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_SCR; 636272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 637272cc70bSAndy Fleming cmd.cmdarg = 0; 638272cc70bSAndy Fleming 639272cc70bSAndy Fleming timeout = 3; 640272cc70bSAndy Fleming 641272cc70bSAndy Fleming retry_scr: 642f781dd38SAnton staaf data.dest = (char *)scr; 643272cc70bSAndy Fleming data.blocksize = 8; 644272cc70bSAndy Fleming data.blocks = 1; 645272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 646272cc70bSAndy Fleming 647272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 648272cc70bSAndy Fleming 649272cc70bSAndy Fleming if (err) { 650272cc70bSAndy Fleming if (timeout--) 651272cc70bSAndy Fleming goto retry_scr; 652272cc70bSAndy Fleming 653272cc70bSAndy Fleming return err; 654272cc70bSAndy Fleming } 655272cc70bSAndy Fleming 6564e3d89baSYauhen Kharuzhy mmc->scr[0] = __be32_to_cpu(scr[0]); 6574e3d89baSYauhen Kharuzhy mmc->scr[1] = __be32_to_cpu(scr[1]); 658272cc70bSAndy Fleming 659272cc70bSAndy Fleming switch ((mmc->scr[0] >> 24) & 0xf) { 660272cc70bSAndy Fleming case 0: 661272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 662272cc70bSAndy Fleming break; 663272cc70bSAndy Fleming case 1: 664272cc70bSAndy Fleming mmc->version = SD_VERSION_1_10; 665272cc70bSAndy Fleming break; 666272cc70bSAndy Fleming case 2: 667272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 6681741c64dSJaehoon Chung if ((mmc->scr[0] >> 15) & 0x1) 6691741c64dSJaehoon Chung mmc->version = SD_VERSION_3; 670272cc70bSAndy Fleming break; 671272cc70bSAndy Fleming default: 672272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 673272cc70bSAndy Fleming break; 674272cc70bSAndy Fleming } 675272cc70bSAndy Fleming 676b44c7083SAlagu Sankar if (mmc->scr[0] & SD_DATA_4BIT) 677b44c7083SAlagu Sankar mmc->card_caps |= MMC_MODE_4BIT; 678b44c7083SAlagu Sankar 679272cc70bSAndy Fleming /* Version 1.0 doesn't support switching */ 680272cc70bSAndy Fleming if (mmc->version == SD_VERSION_1_0) 681272cc70bSAndy Fleming return 0; 682272cc70bSAndy Fleming 683272cc70bSAndy Fleming timeout = 4; 684272cc70bSAndy Fleming while (timeout--) { 685272cc70bSAndy Fleming err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1, 686f781dd38SAnton staaf (u8 *)switch_status); 687272cc70bSAndy Fleming 688272cc70bSAndy Fleming if (err) 689272cc70bSAndy Fleming return err; 690272cc70bSAndy Fleming 691272cc70bSAndy Fleming /* The high-speed function is busy. Try again */ 6924e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY)) 693272cc70bSAndy Fleming break; 694272cc70bSAndy Fleming } 695272cc70bSAndy Fleming 696272cc70bSAndy Fleming /* If high-speed isn't supported, we return */ 6974e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)) 698272cc70bSAndy Fleming return 0; 699272cc70bSAndy Fleming 7002c3fbf4cSMacpaul Lin /* 7012c3fbf4cSMacpaul Lin * If the host doesn't support SD_HIGHSPEED, do not switch card to 7022c3fbf4cSMacpaul Lin * HIGHSPEED mode even if the card support SD_HIGHSPPED. 7032c3fbf4cSMacpaul Lin * This can avoid furthur problem when the card runs in different 7042c3fbf4cSMacpaul Lin * mode between the host. 7052c3fbf4cSMacpaul Lin */ 7062c3fbf4cSMacpaul Lin if (!((mmc->host_caps & MMC_MODE_HS_52MHz) && 7072c3fbf4cSMacpaul Lin (mmc->host_caps & MMC_MODE_HS))) 7082c3fbf4cSMacpaul Lin return 0; 7092c3fbf4cSMacpaul Lin 710f781dd38SAnton staaf err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status); 711272cc70bSAndy Fleming 712272cc70bSAndy Fleming if (err) 713272cc70bSAndy Fleming return err; 714272cc70bSAndy Fleming 7154e3d89baSYauhen Kharuzhy if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000) 716272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS; 717272cc70bSAndy Fleming 718272cc70bSAndy Fleming return 0; 719272cc70bSAndy Fleming } 720272cc70bSAndy Fleming 721272cc70bSAndy Fleming /* frequency bases */ 722272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */ 7235f837c2cSMike Frysinger static const int fbase[] = { 724272cc70bSAndy Fleming 10000, 725272cc70bSAndy Fleming 100000, 726272cc70bSAndy Fleming 1000000, 727272cc70bSAndy Fleming 10000000, 728272cc70bSAndy Fleming }; 729272cc70bSAndy Fleming 730272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice 731272cc70bSAndy Fleming * to platforms without floating point. 732272cc70bSAndy Fleming */ 7335f837c2cSMike Frysinger static const int multipliers[] = { 734272cc70bSAndy Fleming 0, /* reserved */ 735272cc70bSAndy Fleming 10, 736272cc70bSAndy Fleming 12, 737272cc70bSAndy Fleming 13, 738272cc70bSAndy Fleming 15, 739272cc70bSAndy Fleming 20, 740272cc70bSAndy Fleming 25, 741272cc70bSAndy Fleming 30, 742272cc70bSAndy Fleming 35, 743272cc70bSAndy Fleming 40, 744272cc70bSAndy Fleming 45, 745272cc70bSAndy Fleming 50, 746272cc70bSAndy Fleming 55, 747272cc70bSAndy Fleming 60, 748272cc70bSAndy Fleming 70, 749272cc70bSAndy Fleming 80, 750272cc70bSAndy Fleming }; 751272cc70bSAndy Fleming 752fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc) 753272cc70bSAndy Fleming { 754*ab769f22SPantelis Antoniou if (mmc->ops->set_ios) 755*ab769f22SPantelis Antoniou mmc->ops->set_ios(mmc); 756272cc70bSAndy Fleming } 757272cc70bSAndy Fleming 758272cc70bSAndy Fleming void mmc_set_clock(struct mmc *mmc, uint clock) 759272cc70bSAndy Fleming { 760272cc70bSAndy Fleming if (clock > mmc->f_max) 761272cc70bSAndy Fleming clock = mmc->f_max; 762272cc70bSAndy Fleming 763272cc70bSAndy Fleming if (clock < mmc->f_min) 764272cc70bSAndy Fleming clock = mmc->f_min; 765272cc70bSAndy Fleming 766272cc70bSAndy Fleming mmc->clock = clock; 767272cc70bSAndy Fleming 768272cc70bSAndy Fleming mmc_set_ios(mmc); 769272cc70bSAndy Fleming } 770272cc70bSAndy Fleming 771fdbb873eSKim Phillips static void mmc_set_bus_width(struct mmc *mmc, uint width) 772272cc70bSAndy Fleming { 773272cc70bSAndy Fleming mmc->bus_width = width; 774272cc70bSAndy Fleming 775272cc70bSAndy Fleming mmc_set_ios(mmc); 776272cc70bSAndy Fleming } 777272cc70bSAndy Fleming 778fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc) 779272cc70bSAndy Fleming { 780f866a46dSStephen Warren int err, i; 781272cc70bSAndy Fleming uint mult, freq; 782639b7827SYoshihiro Shimoda u64 cmult, csize, capacity; 783272cc70bSAndy Fleming struct mmc_cmd cmd; 7848bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 7858bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 7865d4fc8d9SRaffaele Recalcati int timeout = 1000; 787272cc70bSAndy Fleming 788d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON 789d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */ 790d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF; 791d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R1; 792d52ebf10SThomas Chou cmd.cmdarg = 1; 793d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 794d52ebf10SThomas Chou 795d52ebf10SThomas Chou if (err) 796d52ebf10SThomas Chou return err; 797d52ebf10SThomas Chou } 798d52ebf10SThomas Chou #endif 799d52ebf10SThomas Chou 800272cc70bSAndy Fleming /* Put the Card in Identify Mode */ 801d52ebf10SThomas Chou cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID : 802d52ebf10SThomas Chou MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */ 803272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 804272cc70bSAndy Fleming cmd.cmdarg = 0; 805272cc70bSAndy Fleming 806272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 807272cc70bSAndy Fleming 808272cc70bSAndy Fleming if (err) 809272cc70bSAndy Fleming return err; 810272cc70bSAndy Fleming 811272cc70bSAndy Fleming memcpy(mmc->cid, cmd.response, 16); 812272cc70bSAndy Fleming 813272cc70bSAndy Fleming /* 814272cc70bSAndy Fleming * For MMC cards, set the Relative Address. 815272cc70bSAndy Fleming * For SD cards, get the Relatvie Address. 816272cc70bSAndy Fleming * This also puts the cards into Standby State 817272cc70bSAndy Fleming */ 818d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 819272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR; 820272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 821272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R6; 822272cc70bSAndy Fleming 823272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 824272cc70bSAndy Fleming 825272cc70bSAndy Fleming if (err) 826272cc70bSAndy Fleming return err; 827272cc70bSAndy Fleming 828272cc70bSAndy Fleming if (IS_SD(mmc)) 829998be3ddSRabin Vincent mmc->rca = (cmd.response[0] >> 16) & 0xffff; 830d52ebf10SThomas Chou } 831272cc70bSAndy Fleming 832272cc70bSAndy Fleming /* Get the Card-Specific Data */ 833272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_CSD; 834272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 835272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 836272cc70bSAndy Fleming 837272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 838272cc70bSAndy Fleming 8395d4fc8d9SRaffaele Recalcati /* Waiting for the ready status */ 8405d4fc8d9SRaffaele Recalcati mmc_send_status(mmc, timeout); 8415d4fc8d9SRaffaele Recalcati 842272cc70bSAndy Fleming if (err) 843272cc70bSAndy Fleming return err; 844272cc70bSAndy Fleming 845998be3ddSRabin Vincent mmc->csd[0] = cmd.response[0]; 846998be3ddSRabin Vincent mmc->csd[1] = cmd.response[1]; 847998be3ddSRabin Vincent mmc->csd[2] = cmd.response[2]; 848998be3ddSRabin Vincent mmc->csd[3] = cmd.response[3]; 849272cc70bSAndy Fleming 850272cc70bSAndy Fleming if (mmc->version == MMC_VERSION_UNKNOWN) { 8510b453ffeSRabin Vincent int version = (cmd.response[0] >> 26) & 0xf; 852272cc70bSAndy Fleming 853272cc70bSAndy Fleming switch (version) { 854272cc70bSAndy Fleming case 0: 855272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 856272cc70bSAndy Fleming break; 857272cc70bSAndy Fleming case 1: 858272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_4; 859272cc70bSAndy Fleming break; 860272cc70bSAndy Fleming case 2: 861272cc70bSAndy Fleming mmc->version = MMC_VERSION_2_2; 862272cc70bSAndy Fleming break; 863272cc70bSAndy Fleming case 3: 864272cc70bSAndy Fleming mmc->version = MMC_VERSION_3; 865272cc70bSAndy Fleming break; 866272cc70bSAndy Fleming case 4: 867272cc70bSAndy Fleming mmc->version = MMC_VERSION_4; 868272cc70bSAndy Fleming break; 869272cc70bSAndy Fleming default: 870272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 871272cc70bSAndy Fleming break; 872272cc70bSAndy Fleming } 873272cc70bSAndy Fleming } 874272cc70bSAndy Fleming 875272cc70bSAndy Fleming /* divide frequency by 10, since the mults are 10x bigger */ 8760b453ffeSRabin Vincent freq = fbase[(cmd.response[0] & 0x7)]; 8770b453ffeSRabin Vincent mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; 878272cc70bSAndy Fleming 879272cc70bSAndy Fleming mmc->tran_speed = freq * mult; 880272cc70bSAndy Fleming 881ab71188cSMarkus Niebel mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1); 882998be3ddSRabin Vincent mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf); 883272cc70bSAndy Fleming 884272cc70bSAndy Fleming if (IS_SD(mmc)) 885272cc70bSAndy Fleming mmc->write_bl_len = mmc->read_bl_len; 886272cc70bSAndy Fleming else 887998be3ddSRabin Vincent mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf); 888272cc70bSAndy Fleming 889272cc70bSAndy Fleming if (mmc->high_capacity) { 890272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3f) << 16 891272cc70bSAndy Fleming | (mmc->csd[2] & 0xffff0000) >> 16; 892272cc70bSAndy Fleming cmult = 8; 893272cc70bSAndy Fleming } else { 894272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3ff) << 2 895272cc70bSAndy Fleming | (mmc->csd[2] & 0xc0000000) >> 30; 896272cc70bSAndy Fleming cmult = (mmc->csd[2] & 0x00038000) >> 15; 897272cc70bSAndy Fleming } 898272cc70bSAndy Fleming 899f866a46dSStephen Warren mmc->capacity_user = (csize + 1) << (cmult + 2); 900f866a46dSStephen Warren mmc->capacity_user *= mmc->read_bl_len; 901f866a46dSStephen Warren mmc->capacity_boot = 0; 902f866a46dSStephen Warren mmc->capacity_rpmb = 0; 903f866a46dSStephen Warren for (i = 0; i < 4; i++) 904f866a46dSStephen Warren mmc->capacity_gp[i] = 0; 905272cc70bSAndy Fleming 9068bfa195eSSimon Glass if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN) 9078bfa195eSSimon Glass mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 908272cc70bSAndy Fleming 9098bfa195eSSimon Glass if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN) 9108bfa195eSSimon Glass mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 911272cc70bSAndy Fleming 912ab71188cSMarkus Niebel if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) { 913ab71188cSMarkus Niebel cmd.cmdidx = MMC_CMD_SET_DSR; 914ab71188cSMarkus Niebel cmd.cmdarg = (mmc->dsr & 0xffff) << 16; 915ab71188cSMarkus Niebel cmd.resp_type = MMC_RSP_NONE; 916ab71188cSMarkus Niebel if (mmc_send_cmd(mmc, &cmd, NULL)) 917ab71188cSMarkus Niebel printf("MMC: SET_DSR failed\n"); 918ab71188cSMarkus Niebel } 919ab71188cSMarkus Niebel 920272cc70bSAndy Fleming /* Select the card, and put it into Transfer Mode */ 921d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 922272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SELECT_CARD; 923fe8f7066SAjay Bhargav cmd.resp_type = MMC_RSP_R1; 924272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 925272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 926272cc70bSAndy Fleming 927272cc70bSAndy Fleming if (err) 928272cc70bSAndy Fleming return err; 929d52ebf10SThomas Chou } 930272cc70bSAndy Fleming 931e6f99a56SLei Wen /* 932e6f99a56SLei Wen * For SD, its erase group is always one sector 933e6f99a56SLei Wen */ 934e6f99a56SLei Wen mmc->erase_grp_size = 1; 935bc897b1dSLei Wen mmc->part_config = MMCPART_NOAVAILABLE; 936d23e2c09SSukumar Ghorai if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) { 937d23e2c09SSukumar Ghorai /* check ext_csd version and capacity */ 938d23e2c09SSukumar Ghorai err = mmc_send_ext_csd(mmc, ext_csd); 939fdbb873eSKim Phillips if (!err && (ext_csd[EXT_CSD_REV] >= 2)) { 940639b7827SYoshihiro Shimoda /* 941639b7827SYoshihiro Shimoda * According to the JEDEC Standard, the value of 942639b7827SYoshihiro Shimoda * ext_csd's capacity is valid if the value is more 943639b7827SYoshihiro Shimoda * than 2GB 944639b7827SYoshihiro Shimoda */ 9450560db18SLei Wen capacity = ext_csd[EXT_CSD_SEC_CNT] << 0 9460560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 9470560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 9480560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; 9498bfa195eSSimon Glass capacity *= MMC_MAX_BLOCK_LEN; 950b1f1e821SŁukasz Majewski if ((capacity >> 20) > 2 * 1024) 951f866a46dSStephen Warren mmc->capacity_user = capacity; 952d23e2c09SSukumar Ghorai } 953bc897b1dSLei Wen 95464f4a619SJaehoon Chung switch (ext_csd[EXT_CSD_REV]) { 95564f4a619SJaehoon Chung case 1: 95664f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_1; 95764f4a619SJaehoon Chung break; 95864f4a619SJaehoon Chung case 2: 95964f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_2; 96064f4a619SJaehoon Chung break; 96164f4a619SJaehoon Chung case 3: 96264f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_3; 96364f4a619SJaehoon Chung break; 96464f4a619SJaehoon Chung case 5: 96564f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_41; 96664f4a619SJaehoon Chung break; 96764f4a619SJaehoon Chung case 6: 96864f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_5; 96964f4a619SJaehoon Chung break; 97064f4a619SJaehoon Chung } 97164f4a619SJaehoon Chung 972e6f99a56SLei Wen /* 9731937e5aaSOliver Metz * Host needs to enable ERASE_GRP_DEF bit if device is 9741937e5aaSOliver Metz * partitioned. This bit will be lost every time after a reset 9751937e5aaSOliver Metz * or power off. This will affect erase size. 976e6f99a56SLei Wen */ 9771937e5aaSOliver Metz if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) && 9781937e5aaSOliver Metz (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) { 9791937e5aaSOliver Metz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 9801937e5aaSOliver Metz EXT_CSD_ERASE_GROUP_DEF, 1); 9811937e5aaSOliver Metz 9821937e5aaSOliver Metz if (err) 9831937e5aaSOliver Metz return err; 9841937e5aaSOliver Metz 9851937e5aaSOliver Metz /* Read out group size from ext_csd */ 9860560db18SLei Wen mmc->erase_grp_size = 9878bfa195eSSimon Glass ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 9888bfa195eSSimon Glass MMC_MAX_BLOCK_LEN * 1024; 9898bfa195eSSimon Glass } else { 9901937e5aaSOliver Metz /* Calculate the group size from the csd value. */ 991e6f99a56SLei Wen int erase_gsz, erase_gmul; 992e6f99a56SLei Wen erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10; 993e6f99a56SLei Wen erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5; 994e6f99a56SLei Wen mmc->erase_grp_size = (erase_gsz + 1) 995e6f99a56SLei Wen * (erase_gmul + 1); 996e6f99a56SLei Wen } 997e6f99a56SLei Wen 998bc897b1dSLei Wen /* store the partition info of emmc */ 9998948ea83SStephen Warren if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || 10008948ea83SStephen Warren ext_csd[EXT_CSD_BOOT_MULT]) 10010560db18SLei Wen mmc->part_config = ext_csd[EXT_CSD_PART_CONF]; 1002f866a46dSStephen Warren 1003f866a46dSStephen Warren mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17; 1004f866a46dSStephen Warren 1005f866a46dSStephen Warren mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17; 1006f866a46dSStephen Warren 1007f866a46dSStephen Warren for (i = 0; i < 4; i++) { 1008f866a46dSStephen Warren int idx = EXT_CSD_GP_SIZE_MULT + i * 3; 1009f866a46dSStephen Warren mmc->capacity_gp[i] = (ext_csd[idx + 2] << 16) + 1010f866a46dSStephen Warren (ext_csd[idx + 1] << 8) + ext_csd[idx]; 1011f866a46dSStephen Warren mmc->capacity_gp[i] *= 1012f866a46dSStephen Warren ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 1013f866a46dSStephen Warren mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1014d23e2c09SSukumar Ghorai } 1015f866a46dSStephen Warren } 1016f866a46dSStephen Warren 1017f866a46dSStephen Warren err = mmc_set_capacity(mmc, mmc->part_num); 1018f866a46dSStephen Warren if (err) 1019f866a46dSStephen Warren return err; 1020d23e2c09SSukumar Ghorai 1021272cc70bSAndy Fleming if (IS_SD(mmc)) 1022272cc70bSAndy Fleming err = sd_change_freq(mmc); 1023272cc70bSAndy Fleming else 1024272cc70bSAndy Fleming err = mmc_change_freq(mmc); 1025272cc70bSAndy Fleming 1026272cc70bSAndy Fleming if (err) 1027272cc70bSAndy Fleming return err; 1028272cc70bSAndy Fleming 1029272cc70bSAndy Fleming /* Restrict card's capabilities by what the host can do */ 1030272cc70bSAndy Fleming mmc->card_caps &= mmc->host_caps; 1031272cc70bSAndy Fleming 1032272cc70bSAndy Fleming if (IS_SD(mmc)) { 1033272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_4BIT) { 1034272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 1035272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1036272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1037272cc70bSAndy Fleming 1038272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1039272cc70bSAndy Fleming if (err) 1040272cc70bSAndy Fleming return err; 1041272cc70bSAndy Fleming 1042272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH; 1043272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1044272cc70bSAndy Fleming cmd.cmdarg = 2; 1045272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1046272cc70bSAndy Fleming if (err) 1047272cc70bSAndy Fleming return err; 1048272cc70bSAndy Fleming 1049272cc70bSAndy Fleming mmc_set_bus_width(mmc, 4); 1050272cc70bSAndy Fleming } 1051272cc70bSAndy Fleming 1052272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_HS) 1053ad5fd922SJaehoon Chung mmc->tran_speed = 50000000; 1054272cc70bSAndy Fleming else 1055ad5fd922SJaehoon Chung mmc->tran_speed = 25000000; 1056272cc70bSAndy Fleming } else { 10577798f6dbSAndy Fleming int idx; 10587798f6dbSAndy Fleming 10597798f6dbSAndy Fleming /* An array of possible bus widths in order of preference */ 10607798f6dbSAndy Fleming static unsigned ext_csd_bits[] = { 10617798f6dbSAndy Fleming EXT_CSD_BUS_WIDTH_8, 10627798f6dbSAndy Fleming EXT_CSD_BUS_WIDTH_4, 10637798f6dbSAndy Fleming EXT_CSD_BUS_WIDTH_1, 10647798f6dbSAndy Fleming }; 10657798f6dbSAndy Fleming 10667798f6dbSAndy Fleming /* An array to map CSD bus widths to host cap bits */ 10677798f6dbSAndy Fleming static unsigned ext_to_hostcaps[] = { 10687798f6dbSAndy Fleming [EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT, 10697798f6dbSAndy Fleming [EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT, 10707798f6dbSAndy Fleming }; 10717798f6dbSAndy Fleming 10727798f6dbSAndy Fleming /* An array to map chosen bus width to an integer */ 10737798f6dbSAndy Fleming static unsigned widths[] = { 10747798f6dbSAndy Fleming 8, 4, 1, 10757798f6dbSAndy Fleming }; 10767798f6dbSAndy Fleming 10777798f6dbSAndy Fleming for (idx=0; idx < ARRAY_SIZE(ext_csd_bits); idx++) { 10787798f6dbSAndy Fleming unsigned int extw = ext_csd_bits[idx]; 10797798f6dbSAndy Fleming 10807798f6dbSAndy Fleming /* 10817798f6dbSAndy Fleming * Check to make sure the controller supports 10827798f6dbSAndy Fleming * this bus width, if it's more than 1 10837798f6dbSAndy Fleming */ 10847798f6dbSAndy Fleming if (extw != EXT_CSD_BUS_WIDTH_1 && 10857798f6dbSAndy Fleming !(mmc->host_caps & ext_to_hostcaps[extw])) 10867798f6dbSAndy Fleming continue; 10877798f6dbSAndy Fleming 1088272cc70bSAndy Fleming err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 10897798f6dbSAndy Fleming EXT_CSD_BUS_WIDTH, extw); 1090272cc70bSAndy Fleming 1091272cc70bSAndy Fleming if (err) 10924137894eSLei Wen continue; 1093272cc70bSAndy Fleming 10947798f6dbSAndy Fleming mmc_set_bus_width(mmc, widths[idx]); 1095272cc70bSAndy Fleming 10964137894eSLei Wen err = mmc_send_ext_csd(mmc, test_csd); 10974137894eSLei Wen if (!err && ext_csd[EXT_CSD_PARTITIONING_SUPPORT] \ 10984137894eSLei Wen == test_csd[EXT_CSD_PARTITIONING_SUPPORT] 10994137894eSLei Wen && ext_csd[EXT_CSD_ERASE_GROUP_DEF] \ 11004137894eSLei Wen == test_csd[EXT_CSD_ERASE_GROUP_DEF] \ 11014137894eSLei Wen && ext_csd[EXT_CSD_REV] \ 11024137894eSLei Wen == test_csd[EXT_CSD_REV] 11034137894eSLei Wen && ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] \ 11044137894eSLei Wen == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 11054137894eSLei Wen && memcmp(&ext_csd[EXT_CSD_SEC_CNT], \ 11064137894eSLei Wen &test_csd[EXT_CSD_SEC_CNT], 4) == 0) { 1107272cc70bSAndy Fleming 11087798f6dbSAndy Fleming mmc->card_caps |= ext_to_hostcaps[extw]; 11094137894eSLei Wen break; 11104137894eSLei Wen } 1111272cc70bSAndy Fleming } 1112272cc70bSAndy Fleming 1113272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_HS) { 1114272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_HS_52MHz) 1115ad5fd922SJaehoon Chung mmc->tran_speed = 52000000; 1116272cc70bSAndy Fleming else 1117ad5fd922SJaehoon Chung mmc->tran_speed = 26000000; 1118272cc70bSAndy Fleming } 1119ad5fd922SJaehoon Chung } 1120ad5fd922SJaehoon Chung 1121ad5fd922SJaehoon Chung mmc_set_clock(mmc, mmc->tran_speed); 1122272cc70bSAndy Fleming 1123272cc70bSAndy Fleming /* fill in device description */ 1124272cc70bSAndy Fleming mmc->block_dev.lun = 0; 1125272cc70bSAndy Fleming mmc->block_dev.type = 0; 1126272cc70bSAndy Fleming mmc->block_dev.blksz = mmc->read_bl_len; 11270472fbfdSEgbert Eich mmc->block_dev.log2blksz = LOG2(mmc->block_dev.blksz); 11289b1f942cSRabin Vincent mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len); 112956196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 1130babce5f6STaylor Hutt sprintf(mmc->block_dev.vendor, "Man %06x Snr %04x%04x", 1131babce5f6STaylor Hutt mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff), 1132babce5f6STaylor Hutt (mmc->cid[3] >> 16) & 0xffff); 1133babce5f6STaylor Hutt sprintf(mmc->block_dev.product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff, 11340b453ffeSRabin Vincent (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, 1135babce5f6STaylor Hutt (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff, 1136babce5f6STaylor Hutt (mmc->cid[2] >> 24) & 0xff); 1137babce5f6STaylor Hutt sprintf(mmc->block_dev.revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf, 1138babce5f6STaylor Hutt (mmc->cid[2] >> 16) & 0xf); 113956196826SPaul Burton #else 114056196826SPaul Burton mmc->block_dev.vendor[0] = 0; 114156196826SPaul Burton mmc->block_dev.product[0] = 0; 114256196826SPaul Burton mmc->block_dev.revision[0] = 0; 114356196826SPaul Burton #endif 1144122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT) 1145272cc70bSAndy Fleming init_part(&mmc->block_dev); 1146122efd43SMikhail Kshevetskiy #endif 1147272cc70bSAndy Fleming 1148272cc70bSAndy Fleming return 0; 1149272cc70bSAndy Fleming } 1150272cc70bSAndy Fleming 1151fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc) 1152272cc70bSAndy Fleming { 1153272cc70bSAndy Fleming struct mmc_cmd cmd; 1154272cc70bSAndy Fleming int err; 1155272cc70bSAndy Fleming 1156272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_IF_COND; 1157272cc70bSAndy Fleming /* We set the bit if the host supports voltages between 2.7 and 3.6 V */ 1158272cc70bSAndy Fleming cmd.cmdarg = ((mmc->voltages & 0xff8000) != 0) << 8 | 0xaa; 1159272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R7; 1160272cc70bSAndy Fleming 1161272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1162272cc70bSAndy Fleming 1163272cc70bSAndy Fleming if (err) 1164272cc70bSAndy Fleming return err; 1165272cc70bSAndy Fleming 1166998be3ddSRabin Vincent if ((cmd.response[0] & 0xff) != 0xaa) 1167272cc70bSAndy Fleming return UNUSABLE_ERR; 1168272cc70bSAndy Fleming else 1169272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 1170272cc70bSAndy Fleming 1171272cc70bSAndy Fleming return 0; 1172272cc70bSAndy Fleming } 1173272cc70bSAndy Fleming 1174272cc70bSAndy Fleming int mmc_register(struct mmc *mmc) 1175272cc70bSAndy Fleming { 1176ab71188cSMarkus Niebel /* Setup dsr related values */ 1177ab71188cSMarkus Niebel mmc->dsr_imp = 0; 1178ab71188cSMarkus Niebel mmc->dsr = 0xffffffff; 1179272cc70bSAndy Fleming /* Setup the universal parts of the block interface just once */ 1180272cc70bSAndy Fleming mmc->block_dev.if_type = IF_TYPE_MMC; 1181272cc70bSAndy Fleming mmc->block_dev.dev = cur_dev_num++; 1182272cc70bSAndy Fleming mmc->block_dev.removable = 1; 1183272cc70bSAndy Fleming mmc->block_dev.block_read = mmc_bread; 1184272cc70bSAndy Fleming mmc->block_dev.block_write = mmc_bwrite; 1185e6f99a56SLei Wen mmc->block_dev.block_erase = mmc_berase; 11868feafcc4SJohn Rigby if (!mmc->b_max) 11878feafcc4SJohn Rigby mmc->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; 1188272cc70bSAndy Fleming 1189272cc70bSAndy Fleming INIT_LIST_HEAD (&mmc->link); 1190272cc70bSAndy Fleming 1191272cc70bSAndy Fleming list_add_tail (&mmc->link, &mmc_devices); 1192272cc70bSAndy Fleming 1193272cc70bSAndy Fleming return 0; 1194272cc70bSAndy Fleming } 1195272cc70bSAndy Fleming 1196df3fc526SMatthew McClintock #ifdef CONFIG_PARTITIONS 1197272cc70bSAndy Fleming block_dev_desc_t *mmc_get_dev(int dev) 1198272cc70bSAndy Fleming { 1199272cc70bSAndy Fleming struct mmc *mmc = find_mmc_device(dev); 12006bb4b4bcSBenoît Thébaudeau if (!mmc || mmc_init(mmc)) 120140242bc3SŁukasz Majewski return NULL; 1202272cc70bSAndy Fleming 120340242bc3SŁukasz Majewski return &mmc->block_dev; 1204272cc70bSAndy Fleming } 1205df3fc526SMatthew McClintock #endif 1206272cc70bSAndy Fleming 1207e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc) 1208272cc70bSAndy Fleming { 1209afd5932bSMacpaul Lin int err; 1210272cc70bSAndy Fleming 1211*ab769f22SPantelis Antoniou /* we pretend there's no card when init is NULL */ 1212*ab769f22SPantelis Antoniou if (mmc_getcd(mmc) == 0 || mmc->ops->init == NULL) { 121348972d90SThierry Reding mmc->has_init = 0; 121456196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 121548972d90SThierry Reding printf("MMC: no card present\n"); 121656196826SPaul Burton #endif 121748972d90SThierry Reding return NO_CARD_ERR; 121848972d90SThierry Reding } 121948972d90SThierry Reding 1220bc897b1dSLei Wen if (mmc->has_init) 1221bc897b1dSLei Wen return 0; 1222bc897b1dSLei Wen 1223*ab769f22SPantelis Antoniou /* made sure it's not NULL earlier */ 1224*ab769f22SPantelis Antoniou err = mmc->ops->init(mmc); 1225272cc70bSAndy Fleming 1226272cc70bSAndy Fleming if (err) 1227272cc70bSAndy Fleming return err; 1228272cc70bSAndy Fleming 1229b86b85e2SIlya Yanok mmc_set_bus_width(mmc, 1); 1230b86b85e2SIlya Yanok mmc_set_clock(mmc, 1); 1231b86b85e2SIlya Yanok 1232272cc70bSAndy Fleming /* Reset the Card */ 1233272cc70bSAndy Fleming err = mmc_go_idle(mmc); 1234272cc70bSAndy Fleming 1235272cc70bSAndy Fleming if (err) 1236272cc70bSAndy Fleming return err; 1237272cc70bSAndy Fleming 1238bc897b1dSLei Wen /* The internal partition reset to user partition(0) at every CMD0*/ 1239bc897b1dSLei Wen mmc->part_num = 0; 1240bc897b1dSLei Wen 1241272cc70bSAndy Fleming /* Test for SD version 2 */ 1242272cc70bSAndy Fleming err = mmc_send_if_cond(mmc); 1243272cc70bSAndy Fleming 1244272cc70bSAndy Fleming /* Now try to get the SD card's operating condition */ 1245272cc70bSAndy Fleming err = sd_send_op_cond(mmc); 1246272cc70bSAndy Fleming 1247272cc70bSAndy Fleming /* If the command timed out, we check for an MMC card */ 1248272cc70bSAndy Fleming if (err == TIMEOUT) { 1249272cc70bSAndy Fleming err = mmc_send_op_cond(mmc); 1250272cc70bSAndy Fleming 1251e9550449SChe-Liang Chiou if (err && err != IN_PROGRESS) { 125256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 1253272cc70bSAndy Fleming printf("Card did not respond to voltage select!\n"); 125456196826SPaul Burton #endif 1255272cc70bSAndy Fleming return UNUSABLE_ERR; 1256272cc70bSAndy Fleming } 1257272cc70bSAndy Fleming } 1258272cc70bSAndy Fleming 1259e9550449SChe-Liang Chiou if (err == IN_PROGRESS) 1260e9550449SChe-Liang Chiou mmc->init_in_progress = 1; 1261e9550449SChe-Liang Chiou 1262e9550449SChe-Liang Chiou return err; 1263e9550449SChe-Liang Chiou } 1264e9550449SChe-Liang Chiou 1265e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc) 1266e9550449SChe-Liang Chiou { 1267e9550449SChe-Liang Chiou int err = 0; 1268e9550449SChe-Liang Chiou 1269e9550449SChe-Liang Chiou if (mmc->op_cond_pending) 1270e9550449SChe-Liang Chiou err = mmc_complete_op_cond(mmc); 1271e9550449SChe-Liang Chiou 1272e9550449SChe-Liang Chiou if (!err) 1273bc897b1dSLei Wen err = mmc_startup(mmc); 1274bc897b1dSLei Wen if (err) 1275bc897b1dSLei Wen mmc->has_init = 0; 1276bc897b1dSLei Wen else 1277bc897b1dSLei Wen mmc->has_init = 1; 1278e9550449SChe-Liang Chiou mmc->init_in_progress = 0; 1279e9550449SChe-Liang Chiou return err; 1280e9550449SChe-Liang Chiou } 1281e9550449SChe-Liang Chiou 1282e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc) 1283e9550449SChe-Liang Chiou { 1284e9550449SChe-Liang Chiou int err = IN_PROGRESS; 1285e9550449SChe-Liang Chiou unsigned start = get_timer(0); 1286e9550449SChe-Liang Chiou 1287e9550449SChe-Liang Chiou if (mmc->has_init) 1288e9550449SChe-Liang Chiou return 0; 1289e9550449SChe-Liang Chiou if (!mmc->init_in_progress) 1290e9550449SChe-Liang Chiou err = mmc_start_init(mmc); 1291e9550449SChe-Liang Chiou 1292e9550449SChe-Liang Chiou if (!err || err == IN_PROGRESS) 1293e9550449SChe-Liang Chiou err = mmc_complete_init(mmc); 1294e9550449SChe-Liang Chiou debug("%s: %d, time %lu\n", __func__, err, get_timer(start)); 1295bc897b1dSLei Wen return err; 1296272cc70bSAndy Fleming } 1297272cc70bSAndy Fleming 1298ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val) 1299ab71188cSMarkus Niebel { 1300ab71188cSMarkus Niebel mmc->dsr = val; 1301ab71188cSMarkus Niebel return 0; 1302ab71188cSMarkus Niebel } 1303ab71188cSMarkus Niebel 1304272cc70bSAndy Fleming /* 1305272cc70bSAndy Fleming * CPU and board-specific MMC initializations. Aliased function 1306272cc70bSAndy Fleming * signals caller to move on 1307272cc70bSAndy Fleming */ 1308272cc70bSAndy Fleming static int __def_mmc_init(bd_t *bis) 1309272cc70bSAndy Fleming { 1310272cc70bSAndy Fleming return -1; 1311272cc70bSAndy Fleming } 1312272cc70bSAndy Fleming 1313f9a109b3SPeter Tyser int cpu_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init"))); 1314f9a109b3SPeter Tyser int board_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init"))); 1315272cc70bSAndy Fleming 131656196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 131756196826SPaul Burton 1318272cc70bSAndy Fleming void print_mmc_devices(char separator) 1319272cc70bSAndy Fleming { 1320272cc70bSAndy Fleming struct mmc *m; 1321272cc70bSAndy Fleming struct list_head *entry; 1322272cc70bSAndy Fleming 1323272cc70bSAndy Fleming list_for_each(entry, &mmc_devices) { 1324272cc70bSAndy Fleming m = list_entry(entry, struct mmc, link); 1325272cc70bSAndy Fleming 1326272cc70bSAndy Fleming printf("%s: %d", m->name, m->block_dev.dev); 1327272cc70bSAndy Fleming 1328272cc70bSAndy Fleming if (entry->next != &mmc_devices) 1329272cc70bSAndy Fleming printf("%c ", separator); 1330272cc70bSAndy Fleming } 1331272cc70bSAndy Fleming 1332272cc70bSAndy Fleming printf("\n"); 1333272cc70bSAndy Fleming } 1334272cc70bSAndy Fleming 133556196826SPaul Burton #else 133656196826SPaul Burton void print_mmc_devices(char separator) { } 133756196826SPaul Burton #endif 133856196826SPaul Burton 1339ea6ebe21SLei Wen int get_mmc_num(void) 1340ea6ebe21SLei Wen { 1341ea6ebe21SLei Wen return cur_dev_num; 1342ea6ebe21SLei Wen } 1343ea6ebe21SLei Wen 1344e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit) 1345e9550449SChe-Liang Chiou { 1346e9550449SChe-Liang Chiou mmc->preinit = preinit; 1347e9550449SChe-Liang Chiou } 1348e9550449SChe-Liang Chiou 1349e9550449SChe-Liang Chiou static void do_preinit(void) 1350e9550449SChe-Liang Chiou { 1351e9550449SChe-Liang Chiou struct mmc *m; 1352e9550449SChe-Liang Chiou struct list_head *entry; 1353e9550449SChe-Liang Chiou 1354e9550449SChe-Liang Chiou list_for_each(entry, &mmc_devices) { 1355e9550449SChe-Liang Chiou m = list_entry(entry, struct mmc, link); 1356e9550449SChe-Liang Chiou 1357e9550449SChe-Liang Chiou if (m->preinit) 1358e9550449SChe-Liang Chiou mmc_start_init(m); 1359e9550449SChe-Liang Chiou } 1360e9550449SChe-Liang Chiou } 1361e9550449SChe-Liang Chiou 1362e9550449SChe-Liang Chiou 1363272cc70bSAndy Fleming int mmc_initialize(bd_t *bis) 1364272cc70bSAndy Fleming { 1365272cc70bSAndy Fleming INIT_LIST_HEAD (&mmc_devices); 1366272cc70bSAndy Fleming cur_dev_num = 0; 1367272cc70bSAndy Fleming 1368272cc70bSAndy Fleming if (board_mmc_init(bis) < 0) 1369272cc70bSAndy Fleming cpu_mmc_init(bis); 1370272cc70bSAndy Fleming 1371bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD 1372272cc70bSAndy Fleming print_mmc_devices(','); 1373bb0dc108SYing Zhang #endif 1374272cc70bSAndy Fleming 1375e9550449SChe-Liang Chiou do_preinit(); 1376272cc70bSAndy Fleming return 0; 1377272cc70bSAndy Fleming } 13783690d6d6SAmar 13793690d6d6SAmar #ifdef CONFIG_SUPPORT_EMMC_BOOT 13803690d6d6SAmar /* 13813690d6d6SAmar * This function changes the size of boot partition and the size of rpmb 13823690d6d6SAmar * partition present on EMMC devices. 13833690d6d6SAmar * 13843690d6d6SAmar * Input Parameters: 13853690d6d6SAmar * struct *mmc: pointer for the mmc device strcuture 13863690d6d6SAmar * bootsize: size of boot partition 13873690d6d6SAmar * rpmbsize: size of rpmb partition 13883690d6d6SAmar * 13893690d6d6SAmar * Returns 0 on success. 13903690d6d6SAmar */ 13913690d6d6SAmar 13923690d6d6SAmar int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize, 13933690d6d6SAmar unsigned long rpmbsize) 13943690d6d6SAmar { 13953690d6d6SAmar int err; 13963690d6d6SAmar struct mmc_cmd cmd; 13973690d6d6SAmar 13983690d6d6SAmar /* Only use this command for raw EMMC moviNAND. Enter backdoor mode */ 13993690d6d6SAmar cmd.cmdidx = MMC_CMD_RES_MAN; 14003690d6d6SAmar cmd.resp_type = MMC_RSP_R1b; 14013690d6d6SAmar cmd.cmdarg = MMC_CMD62_ARG1; 14023690d6d6SAmar 14033690d6d6SAmar err = mmc_send_cmd(mmc, &cmd, NULL); 14043690d6d6SAmar if (err) { 14053690d6d6SAmar debug("mmc_boot_partition_size_change: Error1 = %d\n", err); 14063690d6d6SAmar return err; 14073690d6d6SAmar } 14083690d6d6SAmar 14093690d6d6SAmar /* Boot partition changing mode */ 14103690d6d6SAmar cmd.cmdidx = MMC_CMD_RES_MAN; 14113690d6d6SAmar cmd.resp_type = MMC_RSP_R1b; 14123690d6d6SAmar cmd.cmdarg = MMC_CMD62_ARG2; 14133690d6d6SAmar 14143690d6d6SAmar err = mmc_send_cmd(mmc, &cmd, NULL); 14153690d6d6SAmar if (err) { 14163690d6d6SAmar debug("mmc_boot_partition_size_change: Error2 = %d\n", err); 14173690d6d6SAmar return err; 14183690d6d6SAmar } 14193690d6d6SAmar /* boot partition size is multiple of 128KB */ 14203690d6d6SAmar bootsize = (bootsize * 1024) / 128; 14213690d6d6SAmar 14223690d6d6SAmar /* Arg: boot partition size */ 14233690d6d6SAmar cmd.cmdidx = MMC_CMD_RES_MAN; 14243690d6d6SAmar cmd.resp_type = MMC_RSP_R1b; 14253690d6d6SAmar cmd.cmdarg = bootsize; 14263690d6d6SAmar 14273690d6d6SAmar err = mmc_send_cmd(mmc, &cmd, NULL); 14283690d6d6SAmar if (err) { 14293690d6d6SAmar debug("mmc_boot_partition_size_change: Error3 = %d\n", err); 14303690d6d6SAmar return err; 14313690d6d6SAmar } 14323690d6d6SAmar /* RPMB partition size is multiple of 128KB */ 14333690d6d6SAmar rpmbsize = (rpmbsize * 1024) / 128; 14343690d6d6SAmar /* Arg: RPMB partition size */ 14353690d6d6SAmar cmd.cmdidx = MMC_CMD_RES_MAN; 14363690d6d6SAmar cmd.resp_type = MMC_RSP_R1b; 14373690d6d6SAmar cmd.cmdarg = rpmbsize; 14383690d6d6SAmar 14393690d6d6SAmar err = mmc_send_cmd(mmc, &cmd, NULL); 14403690d6d6SAmar if (err) { 14413690d6d6SAmar debug("mmc_boot_partition_size_change: Error4 = %d\n", err); 14423690d6d6SAmar return err; 14433690d6d6SAmar } 14443690d6d6SAmar return 0; 14453690d6d6SAmar } 14463690d6d6SAmar 14473690d6d6SAmar /* 14485a99b9deSTom Rini * Modify EXT_CSD[177] which is BOOT_BUS_WIDTH 14495a99b9deSTom Rini * based on the passed in values for BOOT_BUS_WIDTH, RESET_BOOT_BUS_WIDTH 14505a99b9deSTom Rini * and BOOT_MODE. 14515a99b9deSTom Rini * 14525a99b9deSTom Rini * Returns 0 on success. 14535a99b9deSTom Rini */ 14545a99b9deSTom Rini int mmc_set_boot_bus_width(struct mmc *mmc, u8 width, u8 reset, u8 mode) 14555a99b9deSTom Rini { 14565a99b9deSTom Rini int err; 14575a99b9deSTom Rini 14585a99b9deSTom Rini err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_BUS_WIDTH, 14595a99b9deSTom Rini EXT_CSD_BOOT_BUS_WIDTH_MODE(mode) | 14605a99b9deSTom Rini EXT_CSD_BOOT_BUS_WIDTH_RESET(reset) | 14615a99b9deSTom Rini EXT_CSD_BOOT_BUS_WIDTH_WIDTH(width)); 14625a99b9deSTom Rini 14635a99b9deSTom Rini if (err) 14645a99b9deSTom Rini return err; 14655a99b9deSTom Rini return 0; 14665a99b9deSTom Rini } 14675a99b9deSTom Rini 14685a99b9deSTom Rini /* 1469792970b0STom Rini * Modify EXT_CSD[179] which is PARTITION_CONFIG (formerly BOOT_CONFIG) 1470792970b0STom Rini * based on the passed in values for BOOT_ACK, BOOT_PARTITION_ENABLE and 1471792970b0STom Rini * PARTITION_ACCESS. 1472792970b0STom Rini * 1473792970b0STom Rini * Returns 0 on success. 1474792970b0STom Rini */ 1475792970b0STom Rini int mmc_set_part_conf(struct mmc *mmc, u8 ack, u8 part_num, u8 access) 1476792970b0STom Rini { 1477792970b0STom Rini int err; 1478792970b0STom Rini 1479792970b0STom Rini err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, 1480792970b0STom Rini EXT_CSD_BOOT_ACK(ack) | 1481792970b0STom Rini EXT_CSD_BOOT_PART_NUM(part_num) | 1482792970b0STom Rini EXT_CSD_PARTITION_ACCESS(access)); 1483792970b0STom Rini 1484792970b0STom Rini if (err) 1485792970b0STom Rini return err; 1486792970b0STom Rini return 0; 1487792970b0STom Rini } 14883690d6d6SAmar #endif 1489