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> 138e3332e2SSjoerd Simons #include <dm.h> 148e3332e2SSjoerd Simons #include <dm/device-internal.h> 15d4622df3SStephen Warren #include <errno.h> 16272cc70bSAndy Fleming #include <mmc.h> 17272cc70bSAndy Fleming #include <part.h> 18272cc70bSAndy Fleming #include <malloc.h> 19cf92e05cSSimon Glass #include <memalign.h> 20272cc70bSAndy Fleming #include <linux/list.h> 219b1f942cSRabin Vincent #include <div64.h> 22da61fa5fSPaul Burton #include "mmc_private.h" 23272cc70bSAndy Fleming 24750121c3SJeroen Hofstee __weak int board_mmc_getwp(struct mmc *mmc) 25d23d8d7eSNikita Kiryanov { 26d23d8d7eSNikita Kiryanov return -1; 27d23d8d7eSNikita Kiryanov } 28d23d8d7eSNikita Kiryanov 29d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc) 30d23d8d7eSNikita Kiryanov { 31d23d8d7eSNikita Kiryanov int wp; 32d23d8d7eSNikita Kiryanov 33d23d8d7eSNikita Kiryanov wp = board_mmc_getwp(mmc); 34d23d8d7eSNikita Kiryanov 35d4e1da4eSPeter Korsgaard if (wp < 0) { 3693bfd616SPantelis Antoniou if (mmc->cfg->ops->getwp) 3793bfd616SPantelis Antoniou wp = mmc->cfg->ops->getwp(mmc); 38d4e1da4eSPeter Korsgaard else 39d4e1da4eSPeter Korsgaard wp = 0; 40d4e1da4eSPeter Korsgaard } 41d23d8d7eSNikita Kiryanov 42d23d8d7eSNikita Kiryanov return wp; 43d23d8d7eSNikita Kiryanov } 44d23d8d7eSNikita Kiryanov 45cee9ab7cSJeroen Hofstee __weak int board_mmc_getcd(struct mmc *mmc) 46cee9ab7cSJeroen Hofstee { 4711fdade2SStefano Babic return -1; 4811fdade2SStefano Babic } 4911fdade2SStefano Babic 50da61fa5fSPaul Burton int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) 51272cc70bSAndy Fleming { 525db2fe3aSRaffaele Recalcati int ret; 538635ff9eSMarek Vasut 548635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE 555db2fe3aSRaffaele Recalcati int i; 565db2fe3aSRaffaele Recalcati u8 *ptr; 575db2fe3aSRaffaele Recalcati 585db2fe3aSRaffaele Recalcati printf("CMD_SEND:%d\n", cmd->cmdidx); 595db2fe3aSRaffaele Recalcati printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg); 6093bfd616SPantelis Antoniou ret = mmc->cfg->ops->send_cmd(mmc, cmd, data); 617863ce58SBin Meng if (ret) { 627863ce58SBin Meng printf("\t\tRET\t\t\t %d\n", ret); 637863ce58SBin Meng } else { 645db2fe3aSRaffaele Recalcati switch (cmd->resp_type) { 655db2fe3aSRaffaele Recalcati case MMC_RSP_NONE: 665db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_NONE\n"); 675db2fe3aSRaffaele Recalcati break; 685db2fe3aSRaffaele Recalcati case MMC_RSP_R1: 695db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n", 705db2fe3aSRaffaele Recalcati cmd->response[0]); 715db2fe3aSRaffaele Recalcati break; 725db2fe3aSRaffaele Recalcati case MMC_RSP_R1b: 735db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n", 745db2fe3aSRaffaele Recalcati cmd->response[0]); 755db2fe3aSRaffaele Recalcati break; 765db2fe3aSRaffaele Recalcati case MMC_RSP_R2: 775db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R2\t\t 0x%08X \n", 785db2fe3aSRaffaele Recalcati cmd->response[0]); 795db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 805db2fe3aSRaffaele Recalcati cmd->response[1]); 815db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 825db2fe3aSRaffaele Recalcati cmd->response[2]); 835db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 845db2fe3aSRaffaele Recalcati cmd->response[3]); 855db2fe3aSRaffaele Recalcati printf("\n"); 865db2fe3aSRaffaele Recalcati printf("\t\t\t\t\tDUMPING DATA\n"); 875db2fe3aSRaffaele Recalcati for (i = 0; i < 4; i++) { 885db2fe3aSRaffaele Recalcati int j; 895db2fe3aSRaffaele Recalcati printf("\t\t\t\t\t%03d - ", i*4); 90146bec79SDirk Behme ptr = (u8 *)&cmd->response[i]; 915db2fe3aSRaffaele Recalcati ptr += 3; 925db2fe3aSRaffaele Recalcati for (j = 0; j < 4; j++) 935db2fe3aSRaffaele Recalcati printf("%02X ", *ptr--); 945db2fe3aSRaffaele Recalcati printf("\n"); 955db2fe3aSRaffaele Recalcati } 965db2fe3aSRaffaele Recalcati break; 975db2fe3aSRaffaele Recalcati case MMC_RSP_R3: 985db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n", 995db2fe3aSRaffaele Recalcati cmd->response[0]); 1005db2fe3aSRaffaele Recalcati break; 1015db2fe3aSRaffaele Recalcati default: 1025db2fe3aSRaffaele Recalcati printf("\t\tERROR MMC rsp not supported\n"); 1035db2fe3aSRaffaele Recalcati break; 1045db2fe3aSRaffaele Recalcati } 1057863ce58SBin Meng } 1065db2fe3aSRaffaele Recalcati #else 10793bfd616SPantelis Antoniou ret = mmc->cfg->ops->send_cmd(mmc, cmd, data); 1085db2fe3aSRaffaele Recalcati #endif 1098635ff9eSMarek Vasut return ret; 110272cc70bSAndy Fleming } 111272cc70bSAndy Fleming 112da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout) 1135d4fc8d9SRaffaele Recalcati { 1145d4fc8d9SRaffaele Recalcati struct mmc_cmd cmd; 115d617c426SJan Kloetzke int err, retries = 5; 1165d4fc8d9SRaffaele Recalcati #ifdef CONFIG_MMC_TRACE 1175d4fc8d9SRaffaele Recalcati int status; 1185d4fc8d9SRaffaele Recalcati #endif 1195d4fc8d9SRaffaele Recalcati 1205d4fc8d9SRaffaele Recalcati cmd.cmdidx = MMC_CMD_SEND_STATUS; 1215d4fc8d9SRaffaele Recalcati cmd.resp_type = MMC_RSP_R1; 122aaf3d41aSMarek Vasut if (!mmc_host_is_spi(mmc)) 123aaf3d41aSMarek Vasut cmd.cmdarg = mmc->rca << 16; 1245d4fc8d9SRaffaele Recalcati 1251677eef4SAndrew Gabbasov while (1) { 1265d4fc8d9SRaffaele Recalcati err = mmc_send_cmd(mmc, &cmd, NULL); 127d617c426SJan Kloetzke if (!err) { 128d617c426SJan Kloetzke if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) && 129d617c426SJan Kloetzke (cmd.response[0] & MMC_STATUS_CURR_STATE) != 130d617c426SJan Kloetzke MMC_STATE_PRG) 1315d4fc8d9SRaffaele Recalcati break; 132d617c426SJan Kloetzke else if (cmd.response[0] & MMC_STATUS_MASK) { 13356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 134d617c426SJan Kloetzke printf("Status Error: 0x%08X\n", 135d617c426SJan Kloetzke cmd.response[0]); 13656196826SPaul Burton #endif 137d617c426SJan Kloetzke return COMM_ERR; 138d617c426SJan Kloetzke } 139d617c426SJan Kloetzke } else if (--retries < 0) 140d617c426SJan Kloetzke return err; 1415d4fc8d9SRaffaele Recalcati 1421677eef4SAndrew Gabbasov if (timeout-- <= 0) 1431677eef4SAndrew Gabbasov break; 1445d4fc8d9SRaffaele Recalcati 1451677eef4SAndrew Gabbasov udelay(1000); 1461677eef4SAndrew Gabbasov } 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 } 1586b2221b0SAndrew Gabbasov if (cmd.response[0] & MMC_STATUS_SWITCH_ERROR) 1596b2221b0SAndrew Gabbasov return SWITCH_ERR; 1605d4fc8d9SRaffaele Recalcati 1615d4fc8d9SRaffaele Recalcati return 0; 1625d4fc8d9SRaffaele Recalcati } 1635d4fc8d9SRaffaele Recalcati 164da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len) 165272cc70bSAndy Fleming { 166272cc70bSAndy Fleming struct mmc_cmd cmd; 167272cc70bSAndy Fleming 168786e8f81SAndrew Gabbasov if (mmc->ddr_mode) 169d22e3d46SJaehoon Chung return 0; 170d22e3d46SJaehoon Chung 171272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SET_BLOCKLEN; 172272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 173272cc70bSAndy Fleming cmd.cmdarg = len; 174272cc70bSAndy Fleming 175272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, NULL); 176272cc70bSAndy Fleming } 177272cc70bSAndy Fleming 178ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start, 179fdbb873eSKim Phillips lbaint_t blkcnt) 180272cc70bSAndy Fleming { 181272cc70bSAndy Fleming struct mmc_cmd cmd; 182272cc70bSAndy Fleming struct mmc_data data; 183272cc70bSAndy Fleming 1844a1a06bcSAlagu Sankar if (blkcnt > 1) 1854a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; 1864a1a06bcSAlagu Sankar else 187272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK; 188272cc70bSAndy Fleming 189272cc70bSAndy Fleming if (mmc->high_capacity) 1904a1a06bcSAlagu Sankar cmd.cmdarg = start; 191272cc70bSAndy Fleming else 1924a1a06bcSAlagu Sankar cmd.cmdarg = start * mmc->read_bl_len; 193272cc70bSAndy Fleming 194272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 195272cc70bSAndy Fleming 196272cc70bSAndy Fleming data.dest = dst; 1974a1a06bcSAlagu Sankar data.blocks = blkcnt; 198272cc70bSAndy Fleming data.blocksize = mmc->read_bl_len; 199272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 200272cc70bSAndy Fleming 2014a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, &data)) 2024a1a06bcSAlagu Sankar return 0; 2034a1a06bcSAlagu Sankar 2044a1a06bcSAlagu Sankar if (blkcnt > 1) { 2054a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; 2064a1a06bcSAlagu Sankar cmd.cmdarg = 0; 2074a1a06bcSAlagu Sankar cmd.resp_type = MMC_RSP_R1b; 2084a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, NULL)) { 20956196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2104a1a06bcSAlagu Sankar printf("mmc fail to send stop cmd\n"); 21156196826SPaul Burton #endif 2124a1a06bcSAlagu Sankar return 0; 2134a1a06bcSAlagu Sankar } 214272cc70bSAndy Fleming } 215272cc70bSAndy Fleming 2164a1a06bcSAlagu Sankar return blkcnt; 217272cc70bSAndy Fleming } 218272cc70bSAndy Fleming 21933fb211dSSimon Glass #ifdef CONFIG_BLK 22033fb211dSSimon Glass static ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, 22133fb211dSSimon Glass void *dst) 22233fb211dSSimon Glass #else 2234101f687SSimon Glass static ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, 2247c4213f6SStephen Warren lbaint_t blkcnt, void *dst) 22533fb211dSSimon Glass #endif 226272cc70bSAndy Fleming { 22733fb211dSSimon Glass #ifdef CONFIG_BLK 22833fb211dSSimon Glass struct blk_desc *block_dev = dev_get_uclass_platdata(dev); 22933fb211dSSimon Glass #endif 230bcce53d0SSimon Glass int dev_num = block_dev->devnum; 231873cc1d7SStephen Warren int err; 2324a1a06bcSAlagu Sankar lbaint_t cur, blocks_todo = blkcnt; 233272cc70bSAndy Fleming 2344a1a06bcSAlagu Sankar if (blkcnt == 0) 2354a1a06bcSAlagu Sankar return 0; 2364a1a06bcSAlagu Sankar 2374a1a06bcSAlagu Sankar struct mmc *mmc = find_mmc_device(dev_num); 238272cc70bSAndy Fleming if (!mmc) 239272cc70bSAndy Fleming return 0; 240272cc70bSAndy Fleming 24169f45cd5SSimon Glass err = blk_dselect_hwpart(block_dev, block_dev->hwpart); 242873cc1d7SStephen Warren if (err < 0) 243873cc1d7SStephen Warren return 0; 244873cc1d7SStephen Warren 245c40fdca6SSimon Glass if ((start + blkcnt) > block_dev->lba) { 24656196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 247ff8fef56SSascha Silbe printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n", 248c40fdca6SSimon Glass start + blkcnt, block_dev->lba); 24956196826SPaul Burton #endif 250d2bf29e3SLei Wen return 0; 251d2bf29e3SLei Wen } 252272cc70bSAndy Fleming 25311692991SSimon Glass if (mmc_set_blocklen(mmc, mmc->read_bl_len)) { 25411692991SSimon Glass debug("%s: Failed to set blocklen\n", __func__); 255272cc70bSAndy Fleming return 0; 25611692991SSimon Glass } 257272cc70bSAndy Fleming 2584a1a06bcSAlagu Sankar do { 25993bfd616SPantelis Antoniou cur = (blocks_todo > mmc->cfg->b_max) ? 26093bfd616SPantelis Antoniou mmc->cfg->b_max : blocks_todo; 26111692991SSimon Glass if (mmc_read_blocks(mmc, dst, start, cur) != cur) { 26211692991SSimon Glass debug("%s: Failed to read blocks\n", __func__); 2634a1a06bcSAlagu Sankar return 0; 26411692991SSimon Glass } 2654a1a06bcSAlagu Sankar blocks_todo -= cur; 2664a1a06bcSAlagu Sankar start += cur; 2674a1a06bcSAlagu Sankar dst += cur * mmc->read_bl_len; 2684a1a06bcSAlagu Sankar } while (blocks_todo > 0); 269272cc70bSAndy Fleming 270272cc70bSAndy Fleming return blkcnt; 271272cc70bSAndy Fleming } 272272cc70bSAndy Fleming 273fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc) 274272cc70bSAndy Fleming { 275272cc70bSAndy Fleming struct mmc_cmd cmd; 276272cc70bSAndy Fleming int err; 277272cc70bSAndy Fleming 278272cc70bSAndy Fleming udelay(1000); 279272cc70bSAndy Fleming 280272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_GO_IDLE_STATE; 281272cc70bSAndy Fleming cmd.cmdarg = 0; 282272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_NONE; 283272cc70bSAndy Fleming 284272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 285272cc70bSAndy Fleming 286272cc70bSAndy Fleming if (err) 287272cc70bSAndy Fleming return err; 288272cc70bSAndy Fleming 289272cc70bSAndy Fleming udelay(2000); 290272cc70bSAndy Fleming 291272cc70bSAndy Fleming return 0; 292272cc70bSAndy Fleming } 293272cc70bSAndy Fleming 294fdbb873eSKim Phillips static int sd_send_op_cond(struct mmc *mmc) 295272cc70bSAndy Fleming { 296272cc70bSAndy Fleming int timeout = 1000; 297272cc70bSAndy Fleming int err; 298272cc70bSAndy Fleming struct mmc_cmd cmd; 299272cc70bSAndy Fleming 3001677eef4SAndrew Gabbasov while (1) { 301272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 302272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 303272cc70bSAndy Fleming cmd.cmdarg = 0; 304272cc70bSAndy Fleming 305272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 306272cc70bSAndy Fleming 307272cc70bSAndy Fleming if (err) 308272cc70bSAndy Fleming return err; 309272cc70bSAndy Fleming 310272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_OP_COND; 311272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R3; 312250de12bSStefano Babic 313250de12bSStefano Babic /* 314250de12bSStefano Babic * Most cards do not answer if some reserved bits 315250de12bSStefano Babic * in the ocr are set. However, Some controller 316250de12bSStefano Babic * can set bit 7 (reserved for low voltages), but 317250de12bSStefano Babic * how to manage low voltages SD card is not yet 318250de12bSStefano Babic * specified. 319250de12bSStefano Babic */ 320d52ebf10SThomas Chou cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 : 32193bfd616SPantelis Antoniou (mmc->cfg->voltages & 0xff8000); 322272cc70bSAndy Fleming 323272cc70bSAndy Fleming if (mmc->version == SD_VERSION_2) 324272cc70bSAndy Fleming cmd.cmdarg |= OCR_HCS; 325272cc70bSAndy Fleming 326272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 327272cc70bSAndy Fleming 328272cc70bSAndy Fleming if (err) 329272cc70bSAndy Fleming return err; 330272cc70bSAndy Fleming 3311677eef4SAndrew Gabbasov if (cmd.response[0] & OCR_BUSY) 3321677eef4SAndrew Gabbasov break; 333272cc70bSAndy Fleming 3341677eef4SAndrew Gabbasov if (timeout-- <= 0) 335272cc70bSAndy Fleming return UNUSABLE_ERR; 336272cc70bSAndy Fleming 3371677eef4SAndrew Gabbasov udelay(1000); 3381677eef4SAndrew Gabbasov } 3391677eef4SAndrew Gabbasov 340272cc70bSAndy Fleming if (mmc->version != SD_VERSION_2) 341272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 342272cc70bSAndy Fleming 343d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 344d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 345d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 346d52ebf10SThomas Chou cmd.cmdarg = 0; 347d52ebf10SThomas Chou 348d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 349d52ebf10SThomas Chou 350d52ebf10SThomas Chou if (err) 351d52ebf10SThomas Chou return err; 352d52ebf10SThomas Chou } 353d52ebf10SThomas Chou 354998be3ddSRabin Vincent mmc->ocr = cmd.response[0]; 355272cc70bSAndy Fleming 356272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 357272cc70bSAndy Fleming mmc->rca = 0; 358272cc70bSAndy Fleming 359272cc70bSAndy Fleming return 0; 360272cc70bSAndy Fleming } 361272cc70bSAndy Fleming 3625289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg) 363272cc70bSAndy Fleming { 3645289b535SAndrew Gabbasov struct mmc_cmd cmd; 365272cc70bSAndy Fleming int err; 366272cc70bSAndy Fleming 3675289b535SAndrew Gabbasov cmd.cmdidx = MMC_CMD_SEND_OP_COND; 3685289b535SAndrew Gabbasov cmd.resp_type = MMC_RSP_R3; 3695289b535SAndrew Gabbasov cmd.cmdarg = 0; 3705a20397bSRob Herring if (use_arg && !mmc_host_is_spi(mmc)) 3715a20397bSRob Herring cmd.cmdarg = OCR_HCS | 37293bfd616SPantelis Antoniou (mmc->cfg->voltages & 373a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_VOLTAGE_MASK)) | 374a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_ACCESS_MODE); 375e9550449SChe-Liang Chiou 3765289b535SAndrew Gabbasov err = mmc_send_cmd(mmc, &cmd, NULL); 377e9550449SChe-Liang Chiou if (err) 378e9550449SChe-Liang Chiou return err; 3795289b535SAndrew Gabbasov mmc->ocr = cmd.response[0]; 380e9550449SChe-Liang Chiou return 0; 381e9550449SChe-Liang Chiou } 382e9550449SChe-Liang Chiou 383750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc) 384e9550449SChe-Liang Chiou { 385e9550449SChe-Liang Chiou int err, i; 386e9550449SChe-Liang Chiou 387272cc70bSAndy Fleming /* Some cards seem to need this */ 388272cc70bSAndy Fleming mmc_go_idle(mmc); 389272cc70bSAndy Fleming 39031cacbabSRaffaele Recalcati /* Asking to the card its capabilities */ 391e9550449SChe-Liang Chiou for (i = 0; i < 2; i++) { 3925289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, i != 0); 39331cacbabSRaffaele Recalcati if (err) 39431cacbabSRaffaele Recalcati return err; 39531cacbabSRaffaele Recalcati 396e9550449SChe-Liang Chiou /* exit if not busy (flag seems to be inverted) */ 397a626c8d4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 398bd47c135SAndrew Gabbasov break; 399e9550449SChe-Liang Chiou } 400bd47c135SAndrew Gabbasov mmc->op_cond_pending = 1; 401bd47c135SAndrew Gabbasov return 0; 402e9550449SChe-Liang Chiou } 40331cacbabSRaffaele Recalcati 404750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc) 405e9550449SChe-Liang Chiou { 406e9550449SChe-Liang Chiou struct mmc_cmd cmd; 407e9550449SChe-Liang Chiou int timeout = 1000; 408e9550449SChe-Liang Chiou uint start; 409e9550449SChe-Liang Chiou int err; 410e9550449SChe-Liang Chiou 411e9550449SChe-Liang Chiou mmc->op_cond_pending = 0; 412cc17c01fSAndrew Gabbasov if (!(mmc->ocr & OCR_BUSY)) { 413e9550449SChe-Liang Chiou start = get_timer(0); 4141677eef4SAndrew Gabbasov while (1) { 4155289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, 1); 416272cc70bSAndy Fleming if (err) 417272cc70bSAndy Fleming return err; 4181677eef4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 4191677eef4SAndrew Gabbasov break; 420e9550449SChe-Liang Chiou if (get_timer(start) > timeout) 421272cc70bSAndy Fleming return UNUSABLE_ERR; 422e9550449SChe-Liang Chiou udelay(100); 4231677eef4SAndrew Gabbasov } 424cc17c01fSAndrew Gabbasov } 425272cc70bSAndy Fleming 426d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 427d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 428d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 429d52ebf10SThomas Chou cmd.cmdarg = 0; 430d52ebf10SThomas Chou 431d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 432d52ebf10SThomas Chou 433d52ebf10SThomas Chou if (err) 434d52ebf10SThomas Chou return err; 435a626c8d4SAndrew Gabbasov 436a626c8d4SAndrew Gabbasov mmc->ocr = cmd.response[0]; 437d52ebf10SThomas Chou } 438d52ebf10SThomas Chou 439272cc70bSAndy Fleming mmc->version = MMC_VERSION_UNKNOWN; 440272cc70bSAndy Fleming 441272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 442def816a2SStephen Warren mmc->rca = 1; 443272cc70bSAndy Fleming 444272cc70bSAndy Fleming return 0; 445272cc70bSAndy Fleming } 446272cc70bSAndy Fleming 447272cc70bSAndy Fleming 448fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd) 449272cc70bSAndy Fleming { 450272cc70bSAndy Fleming struct mmc_cmd cmd; 451272cc70bSAndy Fleming struct mmc_data data; 452272cc70bSAndy Fleming int err; 453272cc70bSAndy Fleming 454272cc70bSAndy Fleming /* Get the Card Status Register */ 455272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_EXT_CSD; 456272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 457272cc70bSAndy Fleming cmd.cmdarg = 0; 458272cc70bSAndy Fleming 459cdfd1ac6SYoshihiro Shimoda data.dest = (char *)ext_csd; 460272cc70bSAndy Fleming data.blocks = 1; 4618bfa195eSSimon Glass data.blocksize = MMC_MAX_BLOCK_LEN; 462272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 463272cc70bSAndy Fleming 464272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 465272cc70bSAndy Fleming 466272cc70bSAndy Fleming return err; 467272cc70bSAndy Fleming } 468272cc70bSAndy Fleming 469272cc70bSAndy Fleming 470fdbb873eSKim Phillips static int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) 471272cc70bSAndy Fleming { 472272cc70bSAndy Fleming struct mmc_cmd cmd; 4735d4fc8d9SRaffaele Recalcati int timeout = 1000; 4745d4fc8d9SRaffaele Recalcati int ret; 475272cc70bSAndy Fleming 476272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SWITCH; 477272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1b; 478272cc70bSAndy Fleming cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | 479272cc70bSAndy Fleming (index << 16) | 480272cc70bSAndy Fleming (value << 8); 481272cc70bSAndy Fleming 4825d4fc8d9SRaffaele Recalcati ret = mmc_send_cmd(mmc, &cmd, NULL); 4835d4fc8d9SRaffaele Recalcati 4845d4fc8d9SRaffaele Recalcati /* Waiting for the ready status */ 48593ad0d18SJan Kloetzke if (!ret) 48693ad0d18SJan Kloetzke ret = mmc_send_status(mmc, timeout); 4875d4fc8d9SRaffaele Recalcati 4885d4fc8d9SRaffaele Recalcati return ret; 4895d4fc8d9SRaffaele Recalcati 490272cc70bSAndy Fleming } 491272cc70bSAndy Fleming 492fdbb873eSKim Phillips static int mmc_change_freq(struct mmc *mmc) 493272cc70bSAndy Fleming { 4948bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 495272cc70bSAndy Fleming char cardtype; 496272cc70bSAndy Fleming int err; 497272cc70bSAndy Fleming 498fc5b32fbSAndrew Gabbasov mmc->card_caps = 0; 499272cc70bSAndy Fleming 500d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 501d52ebf10SThomas Chou return 0; 502d52ebf10SThomas Chou 503272cc70bSAndy Fleming /* Only version 4 supports high-speed */ 504272cc70bSAndy Fleming if (mmc->version < MMC_VERSION_4) 505272cc70bSAndy Fleming return 0; 506272cc70bSAndy Fleming 507fc5b32fbSAndrew Gabbasov mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT; 508fc5b32fbSAndrew Gabbasov 509272cc70bSAndy Fleming err = mmc_send_ext_csd(mmc, ext_csd); 510272cc70bSAndy Fleming 511272cc70bSAndy Fleming if (err) 512272cc70bSAndy Fleming return err; 513272cc70bSAndy Fleming 5140560db18SLei Wen cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf; 515272cc70bSAndy Fleming 516272cc70bSAndy Fleming err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1); 517272cc70bSAndy Fleming 518272cc70bSAndy Fleming if (err) 5196b2221b0SAndrew Gabbasov return err == SWITCH_ERR ? 0 : err; 520272cc70bSAndy Fleming 521272cc70bSAndy Fleming /* Now check to see that it worked */ 522272cc70bSAndy Fleming err = mmc_send_ext_csd(mmc, ext_csd); 523272cc70bSAndy Fleming 524272cc70bSAndy Fleming if (err) 525272cc70bSAndy Fleming return err; 526272cc70bSAndy Fleming 527272cc70bSAndy Fleming /* No high-speed support */ 5280560db18SLei Wen if (!ext_csd[EXT_CSD_HS_TIMING]) 529272cc70bSAndy Fleming return 0; 530272cc70bSAndy Fleming 531272cc70bSAndy Fleming /* High Speed is set, there are two types: 52MHz and 26MHz */ 532d22e3d46SJaehoon Chung if (cardtype & EXT_CSD_CARD_TYPE_52) { 533201d5ac4SAndrew Gabbasov if (cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V) 534d22e3d46SJaehoon Chung mmc->card_caps |= MMC_MODE_DDR_52MHz; 535272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; 536d22e3d46SJaehoon Chung } else { 537272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS; 538d22e3d46SJaehoon Chung } 539272cc70bSAndy Fleming 540272cc70bSAndy Fleming return 0; 541272cc70bSAndy Fleming } 542272cc70bSAndy Fleming 543f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num) 544f866a46dSStephen Warren { 545f866a46dSStephen Warren switch (part_num) { 546f866a46dSStephen Warren case 0: 547f866a46dSStephen Warren mmc->capacity = mmc->capacity_user; 548f866a46dSStephen Warren break; 549f866a46dSStephen Warren case 1: 550f866a46dSStephen Warren case 2: 551f866a46dSStephen Warren mmc->capacity = mmc->capacity_boot; 552f866a46dSStephen Warren break; 553f866a46dSStephen Warren case 3: 554f866a46dSStephen Warren mmc->capacity = mmc->capacity_rpmb; 555f866a46dSStephen Warren break; 556f866a46dSStephen Warren case 4: 557f866a46dSStephen Warren case 5: 558f866a46dSStephen Warren case 6: 559f866a46dSStephen Warren case 7: 560f866a46dSStephen Warren mmc->capacity = mmc->capacity_gp[part_num - 4]; 561f866a46dSStephen Warren break; 562f866a46dSStephen Warren default: 563f866a46dSStephen Warren return -1; 564f866a46dSStephen Warren } 565f866a46dSStephen Warren 566c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len); 567f866a46dSStephen Warren 568f866a46dSStephen Warren return 0; 569f866a46dSStephen Warren } 570f866a46dSStephen Warren 571fdbb139fSSimon Glass static int mmc_switch_part(struct mmc *mmc, unsigned int part_num) 572bc897b1dSLei Wen { 573f866a46dSStephen Warren int ret; 574bc897b1dSLei Wen 575f866a46dSStephen Warren ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, 576bc897b1dSLei Wen (mmc->part_config & ~PART_ACCESS_MASK) 577bc897b1dSLei Wen | (part_num & PART_ACCESS_MASK)); 578f866a46dSStephen Warren 5796dc93e70SPeter Bigot /* 5806dc93e70SPeter Bigot * Set the capacity if the switch succeeded or was intended 5816dc93e70SPeter Bigot * to return to representing the raw device. 5826dc93e70SPeter Bigot */ 583873cc1d7SStephen Warren if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) { 5846dc93e70SPeter Bigot ret = mmc_set_capacity(mmc, part_num); 585fdbb139fSSimon Glass mmc_get_blk_desc(mmc)->hwpart = part_num; 586873cc1d7SStephen Warren } 5876dc93e70SPeter Bigot 5886dc93e70SPeter Bigot return ret; 589bc897b1dSLei Wen } 590bc897b1dSLei Wen 59133fb211dSSimon Glass #ifdef CONFIG_BLK 59233fb211dSSimon Glass static int mmc_select_hwpart(struct udevice *bdev, int hwpart) 59333fb211dSSimon Glass { 59433fb211dSSimon Glass struct udevice *mmc_dev = dev_get_parent(bdev); 59533fb211dSSimon Glass struct mmc *mmc = mmc_get_mmc_dev(mmc_dev); 59633fb211dSSimon Glass struct blk_desc *desc = dev_get_uclass_platdata(bdev); 59733fb211dSSimon Glass int ret; 59833fb211dSSimon Glass 59933fb211dSSimon Glass if (desc->hwpart == hwpart) 60033fb211dSSimon Glass return 0; 60133fb211dSSimon Glass 60233fb211dSSimon Glass if (mmc->part_config == MMCPART_NOAVAILABLE) 60333fb211dSSimon Glass return -EMEDIUMTYPE; 60433fb211dSSimon Glass 60533fb211dSSimon Glass ret = mmc_switch_part(mmc, hwpart); 60633fb211dSSimon Glass if (ret) 60733fb211dSSimon Glass return ret; 60833fb211dSSimon Glass 60933fb211dSSimon Glass return 0; 61033fb211dSSimon Glass } 61133fb211dSSimon Glass #else 612e17d1143SSimon Glass static int mmc_select_hwpartp(struct blk_desc *desc, int hwpart) 613e17d1143SSimon Glass { 614e17d1143SSimon Glass struct mmc *mmc = find_mmc_device(desc->devnum); 615e17d1143SSimon Glass int ret; 616e17d1143SSimon Glass 617e17d1143SSimon Glass if (!mmc) 618e17d1143SSimon Glass return -ENODEV; 619e17d1143SSimon Glass 620e17d1143SSimon Glass if (mmc->block_dev.hwpart == hwpart) 621e17d1143SSimon Glass return 0; 622e17d1143SSimon Glass 623e17d1143SSimon Glass if (mmc->part_config == MMCPART_NOAVAILABLE) 624e17d1143SSimon Glass return -EMEDIUMTYPE; 625e17d1143SSimon Glass 626fdbb139fSSimon Glass ret = mmc_switch_part(mmc, hwpart); 627e17d1143SSimon Glass if (ret) 628e17d1143SSimon Glass return ret; 629e17d1143SSimon Glass 630e17d1143SSimon Glass return 0; 631e17d1143SSimon Glass } 63233fb211dSSimon Glass #endif 633ff3882acSSimon Glass 634ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc, 635ac9da0e0SDiego Santa Cruz const struct mmc_hwpart_conf *conf, 636ac9da0e0SDiego Santa Cruz enum mmc_hwpart_conf_mode mode) 637ac9da0e0SDiego Santa Cruz { 638ac9da0e0SDiego Santa Cruz u8 part_attrs = 0; 639ac9da0e0SDiego Santa Cruz u32 enh_size_mult; 640ac9da0e0SDiego Santa Cruz u32 enh_start_addr; 641ac9da0e0SDiego Santa Cruz u32 gp_size_mult[4]; 642ac9da0e0SDiego Santa Cruz u32 max_enh_size_mult; 643ac9da0e0SDiego Santa Cruz u32 tot_enh_size_mult = 0; 6448dda5b0eSDiego Santa Cruz u8 wr_rel_set; 645ac9da0e0SDiego Santa Cruz int i, pidx, err; 646ac9da0e0SDiego Santa Cruz ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 647ac9da0e0SDiego Santa Cruz 648ac9da0e0SDiego Santa Cruz if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE) 649ac9da0e0SDiego Santa Cruz return -EINVAL; 650ac9da0e0SDiego Santa Cruz 651ac9da0e0SDiego Santa Cruz if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) { 652ac9da0e0SDiego Santa Cruz printf("eMMC >= 4.4 required for enhanced user data area\n"); 653ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 654ac9da0e0SDiego Santa Cruz } 655ac9da0e0SDiego Santa Cruz 656ac9da0e0SDiego Santa Cruz if (!(mmc->part_support & PART_SUPPORT)) { 657ac9da0e0SDiego Santa Cruz printf("Card does not support partitioning\n"); 658ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 659ac9da0e0SDiego Santa Cruz } 660ac9da0e0SDiego Santa Cruz 661ac9da0e0SDiego Santa Cruz if (!mmc->hc_wp_grp_size) { 662ac9da0e0SDiego Santa Cruz printf("Card does not define HC WP group size\n"); 663ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 664ac9da0e0SDiego Santa Cruz } 665ac9da0e0SDiego Santa Cruz 666ac9da0e0SDiego Santa Cruz /* check partition alignment and total enhanced size */ 667ac9da0e0SDiego Santa Cruz if (conf->user.enh_size) { 668ac9da0e0SDiego Santa Cruz if (conf->user.enh_size % mmc->hc_wp_grp_size || 669ac9da0e0SDiego Santa Cruz conf->user.enh_start % mmc->hc_wp_grp_size) { 670ac9da0e0SDiego Santa Cruz printf("User data enhanced area not HC WP group " 671ac9da0e0SDiego Santa Cruz "size aligned\n"); 672ac9da0e0SDiego Santa Cruz return -EINVAL; 673ac9da0e0SDiego Santa Cruz } 674ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_USR; 675ac9da0e0SDiego Santa Cruz enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size; 676ac9da0e0SDiego Santa Cruz if (mmc->high_capacity) { 677ac9da0e0SDiego Santa Cruz enh_start_addr = conf->user.enh_start; 678ac9da0e0SDiego Santa Cruz } else { 679ac9da0e0SDiego Santa Cruz enh_start_addr = (conf->user.enh_start << 9); 680ac9da0e0SDiego Santa Cruz } 681ac9da0e0SDiego Santa Cruz } else { 682ac9da0e0SDiego Santa Cruz enh_size_mult = 0; 683ac9da0e0SDiego Santa Cruz enh_start_addr = 0; 684ac9da0e0SDiego Santa Cruz } 685ac9da0e0SDiego Santa Cruz tot_enh_size_mult += enh_size_mult; 686ac9da0e0SDiego Santa Cruz 687ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 688ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) { 689ac9da0e0SDiego Santa Cruz printf("GP%i partition not HC WP group size " 690ac9da0e0SDiego Santa Cruz "aligned\n", pidx+1); 691ac9da0e0SDiego Santa Cruz return -EINVAL; 692ac9da0e0SDiego Santa Cruz } 693ac9da0e0SDiego Santa Cruz gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size; 694ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) { 695ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_GP(pidx); 696ac9da0e0SDiego Santa Cruz tot_enh_size_mult += gp_size_mult[pidx]; 697ac9da0e0SDiego Santa Cruz } 698ac9da0e0SDiego Santa Cruz } 699ac9da0e0SDiego Santa Cruz 700ac9da0e0SDiego Santa Cruz if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) { 701ac9da0e0SDiego Santa Cruz printf("Card does not support enhanced attribute\n"); 702ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 703ac9da0e0SDiego Santa Cruz } 704ac9da0e0SDiego Santa Cruz 705ac9da0e0SDiego Santa Cruz err = mmc_send_ext_csd(mmc, ext_csd); 706ac9da0e0SDiego Santa Cruz if (err) 707ac9da0e0SDiego Santa Cruz return err; 708ac9da0e0SDiego Santa Cruz 709ac9da0e0SDiego Santa Cruz max_enh_size_mult = 710ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) + 711ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) + 712ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT]; 713ac9da0e0SDiego Santa Cruz if (tot_enh_size_mult > max_enh_size_mult) { 714ac9da0e0SDiego Santa Cruz printf("Total enhanced size exceeds maximum (%u > %u)\n", 715ac9da0e0SDiego Santa Cruz tot_enh_size_mult, max_enh_size_mult); 716ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 717ac9da0e0SDiego Santa Cruz } 718ac9da0e0SDiego Santa Cruz 7198dda5b0eSDiego Santa Cruz /* The default value of EXT_CSD_WR_REL_SET is device 7208dda5b0eSDiego Santa Cruz * dependent, the values can only be changed if the 7218dda5b0eSDiego Santa Cruz * EXT_CSD_HS_CTRL_REL bit is set. The values can be 7228dda5b0eSDiego Santa Cruz * changed only once and before partitioning is completed. */ 7238dda5b0eSDiego Santa Cruz wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 7248dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_change) { 7258dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_set) 7268dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_USR; 7278dda5b0eSDiego Santa Cruz else 7288dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR; 7298dda5b0eSDiego Santa Cruz } 7308dda5b0eSDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 7318dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_change) { 7328dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_set) 7338dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx); 7348dda5b0eSDiego Santa Cruz else 7358dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx); 7368dda5b0eSDiego Santa Cruz } 7378dda5b0eSDiego Santa Cruz } 7388dda5b0eSDiego Santa Cruz 7398dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] && 7408dda5b0eSDiego Santa Cruz !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) { 7418dda5b0eSDiego Santa Cruz puts("Card does not support host controlled partition write " 7428dda5b0eSDiego Santa Cruz "reliability settings\n"); 7438dda5b0eSDiego Santa Cruz return -EMEDIUMTYPE; 7448dda5b0eSDiego Santa Cruz } 7458dda5b0eSDiego Santa Cruz 746ac9da0e0SDiego Santa Cruz if (ext_csd[EXT_CSD_PARTITION_SETTING] & 747ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED) { 748ac9da0e0SDiego Santa Cruz printf("Card already partitioned\n"); 749ac9da0e0SDiego Santa Cruz return -EPERM; 750ac9da0e0SDiego Santa Cruz } 751ac9da0e0SDiego Santa Cruz 752ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_CHECK) 753ac9da0e0SDiego Santa Cruz return 0; 754ac9da0e0SDiego Santa Cruz 755ac9da0e0SDiego Santa Cruz /* Partitioning requires high-capacity size definitions */ 756ac9da0e0SDiego Santa Cruz if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) { 757ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 758ac9da0e0SDiego Santa Cruz EXT_CSD_ERASE_GROUP_DEF, 1); 759ac9da0e0SDiego Santa Cruz 760ac9da0e0SDiego Santa Cruz if (err) 761ac9da0e0SDiego Santa Cruz return err; 762ac9da0e0SDiego Santa Cruz 763ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 764ac9da0e0SDiego Santa Cruz 765ac9da0e0SDiego Santa Cruz /* update erase group size to be high-capacity */ 766ac9da0e0SDiego Santa Cruz mmc->erase_grp_size = 767ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 768ac9da0e0SDiego Santa Cruz 769ac9da0e0SDiego Santa Cruz } 770ac9da0e0SDiego Santa Cruz 771ac9da0e0SDiego Santa Cruz /* all OK, write the configuration */ 772ac9da0e0SDiego Santa Cruz for (i = 0; i < 4; i++) { 773ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 774ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_START_ADDR+i, 775ac9da0e0SDiego Santa Cruz (enh_start_addr >> (i*8)) & 0xFF); 776ac9da0e0SDiego Santa Cruz if (err) 777ac9da0e0SDiego Santa Cruz return err; 778ac9da0e0SDiego Santa Cruz } 779ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 780ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 781ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_SIZE_MULT+i, 782ac9da0e0SDiego Santa Cruz (enh_size_mult >> (i*8)) & 0xFF); 783ac9da0e0SDiego Santa Cruz if (err) 784ac9da0e0SDiego Santa Cruz return err; 785ac9da0e0SDiego Santa Cruz } 786ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 787ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 788ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 789ac9da0e0SDiego Santa Cruz EXT_CSD_GP_SIZE_MULT+pidx*3+i, 790ac9da0e0SDiego Santa Cruz (gp_size_mult[pidx] >> (i*8)) & 0xFF); 791ac9da0e0SDiego Santa Cruz if (err) 792ac9da0e0SDiego Santa Cruz return err; 793ac9da0e0SDiego Santa Cruz } 794ac9da0e0SDiego Santa Cruz } 795ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 796ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs); 797ac9da0e0SDiego Santa Cruz if (err) 798ac9da0e0SDiego Santa Cruz return err; 799ac9da0e0SDiego Santa Cruz 800ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_SET) 801ac9da0e0SDiego Santa Cruz return 0; 802ac9da0e0SDiego Santa Cruz 8038dda5b0eSDiego Santa Cruz /* The WR_REL_SET is a write-once register but shall be 8048dda5b0eSDiego Santa Cruz * written before setting PART_SETTING_COMPLETED. As it is 8058dda5b0eSDiego Santa Cruz * write-once we can only write it when completing the 8068dda5b0eSDiego Santa Cruz * partitioning. */ 8078dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) { 8088dda5b0eSDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 8098dda5b0eSDiego Santa Cruz EXT_CSD_WR_REL_SET, wr_rel_set); 8108dda5b0eSDiego Santa Cruz if (err) 8118dda5b0eSDiego Santa Cruz return err; 8128dda5b0eSDiego Santa Cruz } 8138dda5b0eSDiego Santa Cruz 814ac9da0e0SDiego Santa Cruz /* Setting PART_SETTING_COMPLETED confirms the partition 815ac9da0e0SDiego Santa Cruz * configuration but it only becomes effective after power 816ac9da0e0SDiego Santa Cruz * cycle, so we do not adjust the partition related settings 817ac9da0e0SDiego Santa Cruz * in the mmc struct. */ 818ac9da0e0SDiego Santa Cruz 819ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 820ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING, 821ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED); 822ac9da0e0SDiego Santa Cruz if (err) 823ac9da0e0SDiego Santa Cruz return err; 824ac9da0e0SDiego Santa Cruz 825ac9da0e0SDiego Santa Cruz return 0; 826ac9da0e0SDiego Santa Cruz } 827ac9da0e0SDiego Santa Cruz 82848972d90SThierry Reding int mmc_getcd(struct mmc *mmc) 82948972d90SThierry Reding { 83048972d90SThierry Reding int cd; 83148972d90SThierry Reding 83248972d90SThierry Reding cd = board_mmc_getcd(mmc); 83348972d90SThierry Reding 834d4e1da4eSPeter Korsgaard if (cd < 0) { 83593bfd616SPantelis Antoniou if (mmc->cfg->ops->getcd) 83693bfd616SPantelis Antoniou cd = mmc->cfg->ops->getcd(mmc); 837d4e1da4eSPeter Korsgaard else 838d4e1da4eSPeter Korsgaard cd = 1; 839d4e1da4eSPeter Korsgaard } 84048972d90SThierry Reding 84148972d90SThierry Reding return cd; 84248972d90SThierry Reding } 84348972d90SThierry Reding 844fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) 845272cc70bSAndy Fleming { 846272cc70bSAndy Fleming struct mmc_cmd cmd; 847272cc70bSAndy Fleming struct mmc_data data; 848272cc70bSAndy Fleming 849272cc70bSAndy Fleming /* Switch the frequency */ 850272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SWITCH_FUNC; 851272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 852272cc70bSAndy Fleming cmd.cmdarg = (mode << 31) | 0xffffff; 853272cc70bSAndy Fleming cmd.cmdarg &= ~(0xf << (group * 4)); 854272cc70bSAndy Fleming cmd.cmdarg |= value << (group * 4); 855272cc70bSAndy Fleming 856272cc70bSAndy Fleming data.dest = (char *)resp; 857272cc70bSAndy Fleming data.blocksize = 64; 858272cc70bSAndy Fleming data.blocks = 1; 859272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 860272cc70bSAndy Fleming 861272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, &data); 862272cc70bSAndy Fleming } 863272cc70bSAndy Fleming 864272cc70bSAndy Fleming 865fdbb873eSKim Phillips static int sd_change_freq(struct mmc *mmc) 866272cc70bSAndy Fleming { 867272cc70bSAndy Fleming int err; 868272cc70bSAndy Fleming struct mmc_cmd cmd; 869f781dd38SAnton staaf ALLOC_CACHE_ALIGN_BUFFER(uint, scr, 2); 870f781dd38SAnton staaf ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16); 871272cc70bSAndy Fleming struct mmc_data data; 872272cc70bSAndy Fleming int timeout; 873272cc70bSAndy Fleming 874272cc70bSAndy Fleming mmc->card_caps = 0; 875272cc70bSAndy Fleming 876d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 877d52ebf10SThomas Chou return 0; 878d52ebf10SThomas Chou 879272cc70bSAndy Fleming /* Read the SCR to find out if this card supports higher speeds */ 880272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 881272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 882272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 883272cc70bSAndy Fleming 884272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 885272cc70bSAndy Fleming 886272cc70bSAndy Fleming if (err) 887272cc70bSAndy Fleming return err; 888272cc70bSAndy Fleming 889272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_SCR; 890272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 891272cc70bSAndy Fleming cmd.cmdarg = 0; 892272cc70bSAndy Fleming 893272cc70bSAndy Fleming timeout = 3; 894272cc70bSAndy Fleming 895272cc70bSAndy Fleming retry_scr: 896f781dd38SAnton staaf data.dest = (char *)scr; 897272cc70bSAndy Fleming data.blocksize = 8; 898272cc70bSAndy Fleming data.blocks = 1; 899272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 900272cc70bSAndy Fleming 901272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 902272cc70bSAndy Fleming 903272cc70bSAndy Fleming if (err) { 904272cc70bSAndy Fleming if (timeout--) 905272cc70bSAndy Fleming goto retry_scr; 906272cc70bSAndy Fleming 907272cc70bSAndy Fleming return err; 908272cc70bSAndy Fleming } 909272cc70bSAndy Fleming 9104e3d89baSYauhen Kharuzhy mmc->scr[0] = __be32_to_cpu(scr[0]); 9114e3d89baSYauhen Kharuzhy mmc->scr[1] = __be32_to_cpu(scr[1]); 912272cc70bSAndy Fleming 913272cc70bSAndy Fleming switch ((mmc->scr[0] >> 24) & 0xf) { 914272cc70bSAndy Fleming case 0: 915272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 916272cc70bSAndy Fleming break; 917272cc70bSAndy Fleming case 1: 918272cc70bSAndy Fleming mmc->version = SD_VERSION_1_10; 919272cc70bSAndy Fleming break; 920272cc70bSAndy Fleming case 2: 921272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 9221741c64dSJaehoon Chung if ((mmc->scr[0] >> 15) & 0x1) 9231741c64dSJaehoon Chung mmc->version = SD_VERSION_3; 924272cc70bSAndy Fleming break; 925272cc70bSAndy Fleming default: 926272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 927272cc70bSAndy Fleming break; 928272cc70bSAndy Fleming } 929272cc70bSAndy Fleming 930b44c7083SAlagu Sankar if (mmc->scr[0] & SD_DATA_4BIT) 931b44c7083SAlagu Sankar mmc->card_caps |= MMC_MODE_4BIT; 932b44c7083SAlagu Sankar 933272cc70bSAndy Fleming /* Version 1.0 doesn't support switching */ 934272cc70bSAndy Fleming if (mmc->version == SD_VERSION_1_0) 935272cc70bSAndy Fleming return 0; 936272cc70bSAndy Fleming 937272cc70bSAndy Fleming timeout = 4; 938272cc70bSAndy Fleming while (timeout--) { 939272cc70bSAndy Fleming err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1, 940f781dd38SAnton staaf (u8 *)switch_status); 941272cc70bSAndy Fleming 942272cc70bSAndy Fleming if (err) 943272cc70bSAndy Fleming return err; 944272cc70bSAndy Fleming 945272cc70bSAndy Fleming /* The high-speed function is busy. Try again */ 9464e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY)) 947272cc70bSAndy Fleming break; 948272cc70bSAndy Fleming } 949272cc70bSAndy Fleming 950272cc70bSAndy Fleming /* If high-speed isn't supported, we return */ 9514e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)) 952272cc70bSAndy Fleming return 0; 953272cc70bSAndy Fleming 9542c3fbf4cSMacpaul Lin /* 9552c3fbf4cSMacpaul Lin * If the host doesn't support SD_HIGHSPEED, do not switch card to 9562c3fbf4cSMacpaul Lin * HIGHSPEED mode even if the card support SD_HIGHSPPED. 9572c3fbf4cSMacpaul Lin * This can avoid furthur problem when the card runs in different 9582c3fbf4cSMacpaul Lin * mode between the host. 9592c3fbf4cSMacpaul Lin */ 96093bfd616SPantelis Antoniou if (!((mmc->cfg->host_caps & MMC_MODE_HS_52MHz) && 96193bfd616SPantelis Antoniou (mmc->cfg->host_caps & MMC_MODE_HS))) 9622c3fbf4cSMacpaul Lin return 0; 9632c3fbf4cSMacpaul Lin 964f781dd38SAnton staaf err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status); 965272cc70bSAndy Fleming 966272cc70bSAndy Fleming if (err) 967272cc70bSAndy Fleming return err; 968272cc70bSAndy Fleming 9694e3d89baSYauhen Kharuzhy if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000) 970272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS; 971272cc70bSAndy Fleming 972272cc70bSAndy Fleming return 0; 973272cc70bSAndy Fleming } 974272cc70bSAndy Fleming 975272cc70bSAndy Fleming /* frequency bases */ 976272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */ 9775f837c2cSMike Frysinger static const int fbase[] = { 978272cc70bSAndy Fleming 10000, 979272cc70bSAndy Fleming 100000, 980272cc70bSAndy Fleming 1000000, 981272cc70bSAndy Fleming 10000000, 982272cc70bSAndy Fleming }; 983272cc70bSAndy Fleming 984272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice 985272cc70bSAndy Fleming * to platforms without floating point. 986272cc70bSAndy Fleming */ 987*61fe076fSSimon Glass static const u8 multipliers[] = { 988272cc70bSAndy Fleming 0, /* reserved */ 989272cc70bSAndy Fleming 10, 990272cc70bSAndy Fleming 12, 991272cc70bSAndy Fleming 13, 992272cc70bSAndy Fleming 15, 993272cc70bSAndy Fleming 20, 994272cc70bSAndy Fleming 25, 995272cc70bSAndy Fleming 30, 996272cc70bSAndy Fleming 35, 997272cc70bSAndy Fleming 40, 998272cc70bSAndy Fleming 45, 999272cc70bSAndy Fleming 50, 1000272cc70bSAndy Fleming 55, 1001272cc70bSAndy Fleming 60, 1002272cc70bSAndy Fleming 70, 1003272cc70bSAndy Fleming 80, 1004272cc70bSAndy Fleming }; 1005272cc70bSAndy Fleming 1006fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc) 1007272cc70bSAndy Fleming { 100893bfd616SPantelis Antoniou if (mmc->cfg->ops->set_ios) 100993bfd616SPantelis Antoniou mmc->cfg->ops->set_ios(mmc); 1010272cc70bSAndy Fleming } 1011272cc70bSAndy Fleming 1012272cc70bSAndy Fleming void mmc_set_clock(struct mmc *mmc, uint clock) 1013272cc70bSAndy Fleming { 101493bfd616SPantelis Antoniou if (clock > mmc->cfg->f_max) 101593bfd616SPantelis Antoniou clock = mmc->cfg->f_max; 1016272cc70bSAndy Fleming 101793bfd616SPantelis Antoniou if (clock < mmc->cfg->f_min) 101893bfd616SPantelis Antoniou clock = mmc->cfg->f_min; 1019272cc70bSAndy Fleming 1020272cc70bSAndy Fleming mmc->clock = clock; 1021272cc70bSAndy Fleming 1022272cc70bSAndy Fleming mmc_set_ios(mmc); 1023272cc70bSAndy Fleming } 1024272cc70bSAndy Fleming 1025fdbb873eSKim Phillips static void mmc_set_bus_width(struct mmc *mmc, uint width) 1026272cc70bSAndy Fleming { 1027272cc70bSAndy Fleming mmc->bus_width = width; 1028272cc70bSAndy Fleming 1029272cc70bSAndy Fleming mmc_set_ios(mmc); 1030272cc70bSAndy Fleming } 1031272cc70bSAndy Fleming 1032fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc) 1033272cc70bSAndy Fleming { 1034f866a46dSStephen Warren int err, i; 1035272cc70bSAndy Fleming uint mult, freq; 1036639b7827SYoshihiro Shimoda u64 cmult, csize, capacity; 1037272cc70bSAndy Fleming struct mmc_cmd cmd; 10388bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 10398bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 10405d4fc8d9SRaffaele Recalcati int timeout = 1000; 10410c453bb7SDiego Santa Cruz bool has_parts = false; 10428a0cf490SDiego Santa Cruz bool part_completed; 1043c40fdca6SSimon Glass struct blk_desc *bdesc; 1044272cc70bSAndy Fleming 1045d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON 1046d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */ 1047d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF; 1048d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R1; 1049d52ebf10SThomas Chou cmd.cmdarg = 1; 1050d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 1051d52ebf10SThomas Chou 1052d52ebf10SThomas Chou if (err) 1053d52ebf10SThomas Chou return err; 1054d52ebf10SThomas Chou } 1055d52ebf10SThomas Chou #endif 1056d52ebf10SThomas Chou 1057272cc70bSAndy Fleming /* Put the Card in Identify Mode */ 1058d52ebf10SThomas Chou cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID : 1059d52ebf10SThomas Chou MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */ 1060272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1061272cc70bSAndy Fleming cmd.cmdarg = 0; 1062272cc70bSAndy Fleming 1063272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1064272cc70bSAndy Fleming 1065272cc70bSAndy Fleming if (err) 1066272cc70bSAndy Fleming return err; 1067272cc70bSAndy Fleming 1068272cc70bSAndy Fleming memcpy(mmc->cid, cmd.response, 16); 1069272cc70bSAndy Fleming 1070272cc70bSAndy Fleming /* 1071272cc70bSAndy Fleming * For MMC cards, set the Relative Address. 1072272cc70bSAndy Fleming * For SD cards, get the Relatvie Address. 1073272cc70bSAndy Fleming * This also puts the cards into Standby State 1074272cc70bSAndy Fleming */ 1075d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1076272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR; 1077272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1078272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R6; 1079272cc70bSAndy Fleming 1080272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1081272cc70bSAndy Fleming 1082272cc70bSAndy Fleming if (err) 1083272cc70bSAndy Fleming return err; 1084272cc70bSAndy Fleming 1085272cc70bSAndy Fleming if (IS_SD(mmc)) 1086998be3ddSRabin Vincent mmc->rca = (cmd.response[0] >> 16) & 0xffff; 1087d52ebf10SThomas Chou } 1088272cc70bSAndy Fleming 1089272cc70bSAndy Fleming /* Get the Card-Specific Data */ 1090272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_CSD; 1091272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1092272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1093272cc70bSAndy Fleming 1094272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1095272cc70bSAndy Fleming 10965d4fc8d9SRaffaele Recalcati /* Waiting for the ready status */ 10975d4fc8d9SRaffaele Recalcati mmc_send_status(mmc, timeout); 10985d4fc8d9SRaffaele Recalcati 1099272cc70bSAndy Fleming if (err) 1100272cc70bSAndy Fleming return err; 1101272cc70bSAndy Fleming 1102998be3ddSRabin Vincent mmc->csd[0] = cmd.response[0]; 1103998be3ddSRabin Vincent mmc->csd[1] = cmd.response[1]; 1104998be3ddSRabin Vincent mmc->csd[2] = cmd.response[2]; 1105998be3ddSRabin Vincent mmc->csd[3] = cmd.response[3]; 1106272cc70bSAndy Fleming 1107272cc70bSAndy Fleming if (mmc->version == MMC_VERSION_UNKNOWN) { 11080b453ffeSRabin Vincent int version = (cmd.response[0] >> 26) & 0xf; 1109272cc70bSAndy Fleming 1110272cc70bSAndy Fleming switch (version) { 1111272cc70bSAndy Fleming case 0: 1112272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1113272cc70bSAndy Fleming break; 1114272cc70bSAndy Fleming case 1: 1115272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_4; 1116272cc70bSAndy Fleming break; 1117272cc70bSAndy Fleming case 2: 1118272cc70bSAndy Fleming mmc->version = MMC_VERSION_2_2; 1119272cc70bSAndy Fleming break; 1120272cc70bSAndy Fleming case 3: 1121272cc70bSAndy Fleming mmc->version = MMC_VERSION_3; 1122272cc70bSAndy Fleming break; 1123272cc70bSAndy Fleming case 4: 1124272cc70bSAndy Fleming mmc->version = MMC_VERSION_4; 1125272cc70bSAndy Fleming break; 1126272cc70bSAndy Fleming default: 1127272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1128272cc70bSAndy Fleming break; 1129272cc70bSAndy Fleming } 1130272cc70bSAndy Fleming } 1131272cc70bSAndy Fleming 1132272cc70bSAndy Fleming /* divide frequency by 10, since the mults are 10x bigger */ 11330b453ffeSRabin Vincent freq = fbase[(cmd.response[0] & 0x7)]; 11340b453ffeSRabin Vincent mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; 1135272cc70bSAndy Fleming 1136272cc70bSAndy Fleming mmc->tran_speed = freq * mult; 1137272cc70bSAndy Fleming 1138ab71188cSMarkus Niebel mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1); 1139998be3ddSRabin Vincent mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf); 1140272cc70bSAndy Fleming 1141272cc70bSAndy Fleming if (IS_SD(mmc)) 1142272cc70bSAndy Fleming mmc->write_bl_len = mmc->read_bl_len; 1143272cc70bSAndy Fleming else 1144998be3ddSRabin Vincent mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf); 1145272cc70bSAndy Fleming 1146272cc70bSAndy Fleming if (mmc->high_capacity) { 1147272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3f) << 16 1148272cc70bSAndy Fleming | (mmc->csd[2] & 0xffff0000) >> 16; 1149272cc70bSAndy Fleming cmult = 8; 1150272cc70bSAndy Fleming } else { 1151272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3ff) << 2 1152272cc70bSAndy Fleming | (mmc->csd[2] & 0xc0000000) >> 30; 1153272cc70bSAndy Fleming cmult = (mmc->csd[2] & 0x00038000) >> 15; 1154272cc70bSAndy Fleming } 1155272cc70bSAndy Fleming 1156f866a46dSStephen Warren mmc->capacity_user = (csize + 1) << (cmult + 2); 1157f866a46dSStephen Warren mmc->capacity_user *= mmc->read_bl_len; 1158f866a46dSStephen Warren mmc->capacity_boot = 0; 1159f866a46dSStephen Warren mmc->capacity_rpmb = 0; 1160f866a46dSStephen Warren for (i = 0; i < 4; i++) 1161f866a46dSStephen Warren mmc->capacity_gp[i] = 0; 1162272cc70bSAndy Fleming 11638bfa195eSSimon Glass if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN) 11648bfa195eSSimon Glass mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 1165272cc70bSAndy Fleming 11668bfa195eSSimon Glass if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN) 11678bfa195eSSimon Glass mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 1168272cc70bSAndy Fleming 1169ab71188cSMarkus Niebel if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) { 1170ab71188cSMarkus Niebel cmd.cmdidx = MMC_CMD_SET_DSR; 1171ab71188cSMarkus Niebel cmd.cmdarg = (mmc->dsr & 0xffff) << 16; 1172ab71188cSMarkus Niebel cmd.resp_type = MMC_RSP_NONE; 1173ab71188cSMarkus Niebel if (mmc_send_cmd(mmc, &cmd, NULL)) 1174ab71188cSMarkus Niebel printf("MMC: SET_DSR failed\n"); 1175ab71188cSMarkus Niebel } 1176ab71188cSMarkus Niebel 1177272cc70bSAndy Fleming /* Select the card, and put it into Transfer Mode */ 1178d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1179272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SELECT_CARD; 1180fe8f7066SAjay Bhargav cmd.resp_type = MMC_RSP_R1; 1181272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1182272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1183272cc70bSAndy Fleming 1184272cc70bSAndy Fleming if (err) 1185272cc70bSAndy Fleming return err; 1186d52ebf10SThomas Chou } 1187272cc70bSAndy Fleming 1188e6f99a56SLei Wen /* 1189e6f99a56SLei Wen * For SD, its erase group is always one sector 1190e6f99a56SLei Wen */ 1191e6f99a56SLei Wen mmc->erase_grp_size = 1; 1192bc897b1dSLei Wen mmc->part_config = MMCPART_NOAVAILABLE; 1193d23e2c09SSukumar Ghorai if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) { 1194d23e2c09SSukumar Ghorai /* check ext_csd version and capacity */ 1195d23e2c09SSukumar Ghorai err = mmc_send_ext_csd(mmc, ext_csd); 11969cf199ebSDiego Santa Cruz if (err) 11979cf199ebSDiego Santa Cruz return err; 11989cf199ebSDiego Santa Cruz if (ext_csd[EXT_CSD_REV] >= 2) { 1199639b7827SYoshihiro Shimoda /* 1200639b7827SYoshihiro Shimoda * According to the JEDEC Standard, the value of 1201639b7827SYoshihiro Shimoda * ext_csd's capacity is valid if the value is more 1202639b7827SYoshihiro Shimoda * than 2GB 1203639b7827SYoshihiro Shimoda */ 12040560db18SLei Wen capacity = ext_csd[EXT_CSD_SEC_CNT] << 0 12050560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 12060560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 12070560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; 12088bfa195eSSimon Glass capacity *= MMC_MAX_BLOCK_LEN; 1209b1f1e821SŁukasz Majewski if ((capacity >> 20) > 2 * 1024) 1210f866a46dSStephen Warren mmc->capacity_user = capacity; 1211d23e2c09SSukumar Ghorai } 1212bc897b1dSLei Wen 121364f4a619SJaehoon Chung switch (ext_csd[EXT_CSD_REV]) { 121464f4a619SJaehoon Chung case 1: 121564f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_1; 121664f4a619SJaehoon Chung break; 121764f4a619SJaehoon Chung case 2: 121864f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_2; 121964f4a619SJaehoon Chung break; 122064f4a619SJaehoon Chung case 3: 122164f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_3; 122264f4a619SJaehoon Chung break; 122364f4a619SJaehoon Chung case 5: 122464f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_41; 122564f4a619SJaehoon Chung break; 122664f4a619SJaehoon Chung case 6: 122764f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_5; 122864f4a619SJaehoon Chung break; 1229edab723bSMarkus Niebel case 7: 1230edab723bSMarkus Niebel mmc->version = MMC_VERSION_5_0; 1231edab723bSMarkus Niebel break; 123264f4a619SJaehoon Chung } 123364f4a619SJaehoon Chung 12348a0cf490SDiego Santa Cruz /* The partition data may be non-zero but it is only 12358a0cf490SDiego Santa Cruz * effective if PARTITION_SETTING_COMPLETED is set in 12368a0cf490SDiego Santa Cruz * EXT_CSD, so ignore any data if this bit is not set, 12378a0cf490SDiego Santa Cruz * except for enabling the high-capacity group size 12388a0cf490SDiego Santa Cruz * definition (see below). */ 12398a0cf490SDiego Santa Cruz part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] & 12408a0cf490SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED); 12418a0cf490SDiego Santa Cruz 12420c453bb7SDiego Santa Cruz /* store the partition info of emmc */ 12430c453bb7SDiego Santa Cruz mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT]; 12440c453bb7SDiego Santa Cruz if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || 12450c453bb7SDiego Santa Cruz ext_csd[EXT_CSD_BOOT_MULT]) 12460c453bb7SDiego Santa Cruz mmc->part_config = ext_csd[EXT_CSD_PART_CONF]; 12478a0cf490SDiego Santa Cruz if (part_completed && 12488a0cf490SDiego Santa Cruz (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT)) 12490c453bb7SDiego Santa Cruz mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]; 12500c453bb7SDiego Santa Cruz 12510c453bb7SDiego Santa Cruz mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17; 12520c453bb7SDiego Santa Cruz 12530c453bb7SDiego Santa Cruz mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17; 12540c453bb7SDiego Santa Cruz 12550c453bb7SDiego Santa Cruz for (i = 0; i < 4; i++) { 12560c453bb7SDiego Santa Cruz int idx = EXT_CSD_GP_SIZE_MULT + i * 3; 12578a0cf490SDiego Santa Cruz uint mult = (ext_csd[idx + 2] << 16) + 12580c453bb7SDiego Santa Cruz (ext_csd[idx + 1] << 8) + ext_csd[idx]; 12598a0cf490SDiego Santa Cruz if (mult) 12608a0cf490SDiego Santa Cruz has_parts = true; 12618a0cf490SDiego Santa Cruz if (!part_completed) 12628a0cf490SDiego Santa Cruz continue; 12638a0cf490SDiego Santa Cruz mmc->capacity_gp[i] = mult; 12640c453bb7SDiego Santa Cruz mmc->capacity_gp[i] *= 12650c453bb7SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 12660c453bb7SDiego Santa Cruz mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1267f8e89d67SDiego Santa Cruz mmc->capacity_gp[i] <<= 19; 12680c453bb7SDiego Santa Cruz } 12690c453bb7SDiego Santa Cruz 12708a0cf490SDiego Santa Cruz if (part_completed) { 1271a7f852b6SDiego Santa Cruz mmc->enh_user_size = 1272a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_SIZE_MULT+2] << 16) + 1273a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_SIZE_MULT+1] << 8) + 1274a7f852b6SDiego Santa Cruz ext_csd[EXT_CSD_ENH_SIZE_MULT]; 1275a7f852b6SDiego Santa Cruz mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 1276a7f852b6SDiego Santa Cruz mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1277a7f852b6SDiego Santa Cruz mmc->enh_user_size <<= 19; 1278a7f852b6SDiego Santa Cruz mmc->enh_user_start = 1279a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_START_ADDR+3] << 24) + 1280a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_START_ADDR+2] << 16) + 1281a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_START_ADDR+1] << 8) + 1282a7f852b6SDiego Santa Cruz ext_csd[EXT_CSD_ENH_START_ADDR]; 1283a7f852b6SDiego Santa Cruz if (mmc->high_capacity) 1284a7f852b6SDiego Santa Cruz mmc->enh_user_start <<= 9; 12858a0cf490SDiego Santa Cruz } 1286a7f852b6SDiego Santa Cruz 1287e6f99a56SLei Wen /* 12881937e5aaSOliver Metz * Host needs to enable ERASE_GRP_DEF bit if device is 12891937e5aaSOliver Metz * partitioned. This bit will be lost every time after a reset 12901937e5aaSOliver Metz * or power off. This will affect erase size. 1291e6f99a56SLei Wen */ 12928a0cf490SDiego Santa Cruz if (part_completed) 12930c453bb7SDiego Santa Cruz has_parts = true; 12941937e5aaSOliver Metz if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) && 12950c453bb7SDiego Santa Cruz (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) 12960c453bb7SDiego Santa Cruz has_parts = true; 12970c453bb7SDiego Santa Cruz if (has_parts) { 12981937e5aaSOliver Metz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 12991937e5aaSOliver Metz EXT_CSD_ERASE_GROUP_DEF, 1); 13001937e5aaSOliver Metz 13011937e5aaSOliver Metz if (err) 13021937e5aaSOliver Metz return err; 1303021a8055SHannes Petermaier else 1304021a8055SHannes Petermaier ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 1305037dc0abSDiego Santa Cruz } 13061937e5aaSOliver Metz 1307037dc0abSDiego Santa Cruz if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) { 13081937e5aaSOliver Metz /* Read out group size from ext_csd */ 13090560db18SLei Wen mmc->erase_grp_size = 1310a4ff9f83SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 1311d7b29129SMarkus Niebel /* 1312d7b29129SMarkus Niebel * if high capacity and partition setting completed 1313d7b29129SMarkus Niebel * SEC_COUNT is valid even if it is smaller than 2 GiB 1314d7b29129SMarkus Niebel * JEDEC Standard JESD84-B45, 6.2.4 1315d7b29129SMarkus Niebel */ 13168a0cf490SDiego Santa Cruz if (mmc->high_capacity && part_completed) { 1317d7b29129SMarkus Niebel capacity = (ext_csd[EXT_CSD_SEC_CNT]) | 1318d7b29129SMarkus Niebel (ext_csd[EXT_CSD_SEC_CNT + 1] << 8) | 1319d7b29129SMarkus Niebel (ext_csd[EXT_CSD_SEC_CNT + 2] << 16) | 1320d7b29129SMarkus Niebel (ext_csd[EXT_CSD_SEC_CNT + 3] << 24); 1321d7b29129SMarkus Niebel capacity *= MMC_MAX_BLOCK_LEN; 1322d7b29129SMarkus Niebel mmc->capacity_user = capacity; 1323d7b29129SMarkus Niebel } 13248bfa195eSSimon Glass } else { 13251937e5aaSOliver Metz /* Calculate the group size from the csd value. */ 1326e6f99a56SLei Wen int erase_gsz, erase_gmul; 1327e6f99a56SLei Wen erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10; 1328e6f99a56SLei Wen erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5; 1329e6f99a56SLei Wen mmc->erase_grp_size = (erase_gsz + 1) 1330e6f99a56SLei Wen * (erase_gmul + 1); 1331e6f99a56SLei Wen } 1332037dc0abSDiego Santa Cruz 1333037dc0abSDiego Santa Cruz mmc->hc_wp_grp_size = 1024 1334037dc0abSDiego Santa Cruz * ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 1335037dc0abSDiego Santa Cruz * ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 13369e41a00bSDiego Santa Cruz 13379e41a00bSDiego Santa Cruz mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 1338f866a46dSStephen Warren } 1339f866a46dSStephen Warren 1340c40fdca6SSimon Glass err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart); 1341f866a46dSStephen Warren if (err) 1342f866a46dSStephen Warren return err; 1343d23e2c09SSukumar Ghorai 1344272cc70bSAndy Fleming if (IS_SD(mmc)) 1345272cc70bSAndy Fleming err = sd_change_freq(mmc); 1346272cc70bSAndy Fleming else 1347272cc70bSAndy Fleming err = mmc_change_freq(mmc); 1348272cc70bSAndy Fleming 1349272cc70bSAndy Fleming if (err) 1350272cc70bSAndy Fleming return err; 1351272cc70bSAndy Fleming 1352272cc70bSAndy Fleming /* Restrict card's capabilities by what the host can do */ 135393bfd616SPantelis Antoniou mmc->card_caps &= mmc->cfg->host_caps; 1354272cc70bSAndy Fleming 1355272cc70bSAndy Fleming if (IS_SD(mmc)) { 1356272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_4BIT) { 1357272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 1358272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1359272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1360272cc70bSAndy Fleming 1361272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1362272cc70bSAndy Fleming if (err) 1363272cc70bSAndy Fleming return err; 1364272cc70bSAndy Fleming 1365272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH; 1366272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1367272cc70bSAndy Fleming cmd.cmdarg = 2; 1368272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1369272cc70bSAndy Fleming if (err) 1370272cc70bSAndy Fleming return err; 1371272cc70bSAndy Fleming 1372272cc70bSAndy Fleming mmc_set_bus_width(mmc, 4); 1373272cc70bSAndy Fleming } 1374272cc70bSAndy Fleming 1375272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_HS) 1376ad5fd922SJaehoon Chung mmc->tran_speed = 50000000; 1377272cc70bSAndy Fleming else 1378ad5fd922SJaehoon Chung mmc->tran_speed = 25000000; 1379fc5b32fbSAndrew Gabbasov } else if (mmc->version >= MMC_VERSION_4) { 1380fc5b32fbSAndrew Gabbasov /* Only version 4 of MMC supports wider bus widths */ 13817798f6dbSAndy Fleming int idx; 13827798f6dbSAndy Fleming 13837798f6dbSAndy Fleming /* An array of possible bus widths in order of preference */ 13847798f6dbSAndy Fleming static unsigned ext_csd_bits[] = { 1385d22e3d46SJaehoon Chung EXT_CSD_DDR_BUS_WIDTH_8, 1386d22e3d46SJaehoon Chung EXT_CSD_DDR_BUS_WIDTH_4, 13877798f6dbSAndy Fleming EXT_CSD_BUS_WIDTH_8, 13887798f6dbSAndy Fleming EXT_CSD_BUS_WIDTH_4, 13897798f6dbSAndy Fleming EXT_CSD_BUS_WIDTH_1, 13907798f6dbSAndy Fleming }; 13917798f6dbSAndy Fleming 13927798f6dbSAndy Fleming /* An array to map CSD bus widths to host cap bits */ 13937798f6dbSAndy Fleming static unsigned ext_to_hostcaps[] = { 1394786e8f81SAndrew Gabbasov [EXT_CSD_DDR_BUS_WIDTH_4] = 1395786e8f81SAndrew Gabbasov MMC_MODE_DDR_52MHz | MMC_MODE_4BIT, 1396786e8f81SAndrew Gabbasov [EXT_CSD_DDR_BUS_WIDTH_8] = 1397786e8f81SAndrew Gabbasov MMC_MODE_DDR_52MHz | MMC_MODE_8BIT, 13987798f6dbSAndy Fleming [EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT, 13997798f6dbSAndy Fleming [EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT, 14007798f6dbSAndy Fleming }; 14017798f6dbSAndy Fleming 14027798f6dbSAndy Fleming /* An array to map chosen bus width to an integer */ 14037798f6dbSAndy Fleming static unsigned widths[] = { 1404d22e3d46SJaehoon Chung 8, 4, 8, 4, 1, 14057798f6dbSAndy Fleming }; 14067798f6dbSAndy Fleming 14077798f6dbSAndy Fleming for (idx=0; idx < ARRAY_SIZE(ext_csd_bits); idx++) { 14087798f6dbSAndy Fleming unsigned int extw = ext_csd_bits[idx]; 1409786e8f81SAndrew Gabbasov unsigned int caps = ext_to_hostcaps[extw]; 14107798f6dbSAndy Fleming 14117798f6dbSAndy Fleming /* 1412bf477073SAndrew Gabbasov * If the bus width is still not changed, 1413bf477073SAndrew Gabbasov * don't try to set the default again. 1414bf477073SAndrew Gabbasov * Otherwise, recover from switch attempts 1415bf477073SAndrew Gabbasov * by switching to 1-bit bus width. 1416bf477073SAndrew Gabbasov */ 1417bf477073SAndrew Gabbasov if (extw == EXT_CSD_BUS_WIDTH_1 && 1418bf477073SAndrew Gabbasov mmc->bus_width == 1) { 1419bf477073SAndrew Gabbasov err = 0; 1420bf477073SAndrew Gabbasov break; 1421bf477073SAndrew Gabbasov } 1422bf477073SAndrew Gabbasov 1423bf477073SAndrew Gabbasov /* 1424786e8f81SAndrew Gabbasov * Check to make sure the card and controller support 1425786e8f81SAndrew Gabbasov * these capabilities 14267798f6dbSAndy Fleming */ 1427786e8f81SAndrew Gabbasov if ((mmc->card_caps & caps) != caps) 14287798f6dbSAndy Fleming continue; 14297798f6dbSAndy Fleming 1430272cc70bSAndy Fleming err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 14317798f6dbSAndy Fleming EXT_CSD_BUS_WIDTH, extw); 1432272cc70bSAndy Fleming 1433272cc70bSAndy Fleming if (err) 14344137894eSLei Wen continue; 1435272cc70bSAndy Fleming 1436786e8f81SAndrew Gabbasov mmc->ddr_mode = (caps & MMC_MODE_DDR_52MHz) ? 1 : 0; 14377798f6dbSAndy Fleming mmc_set_bus_width(mmc, widths[idx]); 1438272cc70bSAndy Fleming 14394137894eSLei Wen err = mmc_send_ext_csd(mmc, test_csd); 1440272cc70bSAndy Fleming 1441786e8f81SAndrew Gabbasov if (err) 1442786e8f81SAndrew Gabbasov continue; 1443786e8f81SAndrew Gabbasov 1444786e8f81SAndrew Gabbasov /* Only compare read only fields */ 1445786e8f81SAndrew Gabbasov if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] 1446786e8f81SAndrew Gabbasov == test_csd[EXT_CSD_PARTITIONING_SUPPORT] && 1447786e8f81SAndrew Gabbasov ext_csd[EXT_CSD_HC_WP_GRP_SIZE] 1448786e8f81SAndrew Gabbasov == test_csd[EXT_CSD_HC_WP_GRP_SIZE] && 1449786e8f81SAndrew Gabbasov ext_csd[EXT_CSD_REV] 1450786e8f81SAndrew Gabbasov == test_csd[EXT_CSD_REV] && 1451786e8f81SAndrew Gabbasov ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 1452786e8f81SAndrew Gabbasov == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] && 1453786e8f81SAndrew Gabbasov memcmp(&ext_csd[EXT_CSD_SEC_CNT], 1454786e8f81SAndrew Gabbasov &test_csd[EXT_CSD_SEC_CNT], 4) == 0) 14554137894eSLei Wen break; 1456786e8f81SAndrew Gabbasov else 1457786e8f81SAndrew Gabbasov err = SWITCH_ERR; 14584137894eSLei Wen } 1459786e8f81SAndrew Gabbasov 1460786e8f81SAndrew Gabbasov if (err) 1461786e8f81SAndrew Gabbasov return err; 1462272cc70bSAndy Fleming 1463272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_HS) { 1464272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_HS_52MHz) 1465ad5fd922SJaehoon Chung mmc->tran_speed = 52000000; 1466272cc70bSAndy Fleming else 1467ad5fd922SJaehoon Chung mmc->tran_speed = 26000000; 1468272cc70bSAndy Fleming } 1469ad5fd922SJaehoon Chung } 1470ad5fd922SJaehoon Chung 1471ad5fd922SJaehoon Chung mmc_set_clock(mmc, mmc->tran_speed); 1472272cc70bSAndy Fleming 14735af8f45cSAndrew Gabbasov /* Fix the block length for DDR mode */ 14745af8f45cSAndrew Gabbasov if (mmc->ddr_mode) { 14755af8f45cSAndrew Gabbasov mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 14765af8f45cSAndrew Gabbasov mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 14775af8f45cSAndrew Gabbasov } 14785af8f45cSAndrew Gabbasov 1479272cc70bSAndy Fleming /* fill in device description */ 1480c40fdca6SSimon Glass bdesc = mmc_get_blk_desc(mmc); 1481c40fdca6SSimon Glass bdesc->lun = 0; 1482c40fdca6SSimon Glass bdesc->hwpart = 0; 1483c40fdca6SSimon Glass bdesc->type = 0; 1484c40fdca6SSimon Glass bdesc->blksz = mmc->read_bl_len; 1485c40fdca6SSimon Glass bdesc->log2blksz = LOG2(bdesc->blksz); 1486c40fdca6SSimon Glass bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len); 1487fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \ 1488fc011f64SSjoerd Simons (defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \ 1489fc011f64SSjoerd Simons !defined(CONFIG_USE_TINY_PRINTF)) 1490c40fdca6SSimon Glass sprintf(bdesc->vendor, "Man %06x Snr %04x%04x", 1491babce5f6STaylor Hutt mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff), 1492babce5f6STaylor Hutt (mmc->cid[3] >> 16) & 0xffff); 1493c40fdca6SSimon Glass sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff, 14940b453ffeSRabin Vincent (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, 1495babce5f6STaylor Hutt (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff, 1496babce5f6STaylor Hutt (mmc->cid[2] >> 24) & 0xff); 1497c40fdca6SSimon Glass sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf, 1498babce5f6STaylor Hutt (mmc->cid[2] >> 16) & 0xf); 149956196826SPaul Burton #else 1500c40fdca6SSimon Glass bdesc->vendor[0] = 0; 1501c40fdca6SSimon Glass bdesc->product[0] = 0; 1502c40fdca6SSimon Glass bdesc->revision[0] = 0; 150356196826SPaul Burton #endif 1504122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT) 1505c40fdca6SSimon Glass part_init(bdesc); 1506122efd43SMikhail Kshevetskiy #endif 1507272cc70bSAndy Fleming 1508272cc70bSAndy Fleming return 0; 1509272cc70bSAndy Fleming } 1510272cc70bSAndy Fleming 1511fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc) 1512272cc70bSAndy Fleming { 1513272cc70bSAndy Fleming struct mmc_cmd cmd; 1514272cc70bSAndy Fleming int err; 1515272cc70bSAndy Fleming 1516272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_IF_COND; 1517272cc70bSAndy Fleming /* We set the bit if the host supports voltages between 2.7 and 3.6 V */ 151893bfd616SPantelis Antoniou cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa; 1519272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R7; 1520272cc70bSAndy Fleming 1521272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1522272cc70bSAndy Fleming 1523272cc70bSAndy Fleming if (err) 1524272cc70bSAndy Fleming return err; 1525272cc70bSAndy Fleming 1526998be3ddSRabin Vincent if ((cmd.response[0] & 0xff) != 0xaa) 1527272cc70bSAndy Fleming return UNUSABLE_ERR; 1528272cc70bSAndy Fleming else 1529272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 1530272cc70bSAndy Fleming 1531272cc70bSAndy Fleming return 0; 1532272cc70bSAndy Fleming } 1533272cc70bSAndy Fleming 1534ad27dd5eSSimon Glass #ifdef CONFIG_BLK 1535ad27dd5eSSimon Glass int mmc_bind(struct udevice *dev, struct mmc *mmc, const struct mmc_config *cfg) 1536ad27dd5eSSimon Glass { 1537ad27dd5eSSimon Glass struct blk_desc *bdesc; 1538ad27dd5eSSimon Glass struct udevice *bdev; 1539ad27dd5eSSimon Glass int ret; 1540ad27dd5eSSimon Glass 1541ad27dd5eSSimon Glass ret = blk_create_devicef(dev, "mmc_blk", "blk", IF_TYPE_MMC, -1, 512, 1542ad27dd5eSSimon Glass 0, &bdev); 1543ad27dd5eSSimon Glass if (ret) { 1544ad27dd5eSSimon Glass debug("Cannot create block device\n"); 1545ad27dd5eSSimon Glass return ret; 1546ad27dd5eSSimon Glass } 1547ad27dd5eSSimon Glass bdesc = dev_get_uclass_platdata(bdev); 1548ad27dd5eSSimon Glass mmc->cfg = cfg; 1549ad27dd5eSSimon Glass mmc->priv = dev; 1550ad27dd5eSSimon Glass 1551ad27dd5eSSimon Glass /* the following chunk was from mmc_register() */ 1552ad27dd5eSSimon Glass 1553ad27dd5eSSimon Glass /* Setup dsr related values */ 1554ad27dd5eSSimon Glass mmc->dsr_imp = 0; 1555ad27dd5eSSimon Glass mmc->dsr = 0xffffffff; 1556ad27dd5eSSimon Glass /* Setup the universal parts of the block interface just once */ 1557ad27dd5eSSimon Glass bdesc->removable = 1; 1558ad27dd5eSSimon Glass 1559ad27dd5eSSimon Glass /* setup initial part type */ 1560ad27dd5eSSimon Glass bdesc->part_type = mmc->cfg->part_type; 1561ad27dd5eSSimon Glass mmc->dev = dev; 1562ad27dd5eSSimon Glass 1563ad27dd5eSSimon Glass return 0; 1564ad27dd5eSSimon Glass } 1565ad27dd5eSSimon Glass 1566ad27dd5eSSimon Glass int mmc_unbind(struct udevice *dev) 1567ad27dd5eSSimon Glass { 1568ad27dd5eSSimon Glass struct udevice *bdev; 1569ad27dd5eSSimon Glass 1570ad27dd5eSSimon Glass device_find_first_child(dev, &bdev); 1571ad27dd5eSSimon Glass if (bdev) { 1572ad27dd5eSSimon Glass device_remove(bdev); 1573ad27dd5eSSimon Glass device_unbind(bdev); 1574ad27dd5eSSimon Glass } 1575ad27dd5eSSimon Glass 1576ad27dd5eSSimon Glass return 0; 1577ad27dd5eSSimon Glass } 1578ad27dd5eSSimon Glass 1579ad27dd5eSSimon Glass #else 158093bfd616SPantelis Antoniou struct mmc *mmc_create(const struct mmc_config *cfg, void *priv) 158193bfd616SPantelis Antoniou { 1582c40fdca6SSimon Glass struct blk_desc *bdesc; 158393bfd616SPantelis Antoniou struct mmc *mmc; 158493bfd616SPantelis Antoniou 158593bfd616SPantelis Antoniou /* quick validation */ 158693bfd616SPantelis Antoniou if (cfg == NULL || cfg->ops == NULL || cfg->ops->send_cmd == NULL || 158793bfd616SPantelis Antoniou cfg->f_min == 0 || cfg->f_max == 0 || cfg->b_max == 0) 158893bfd616SPantelis Antoniou return NULL; 158993bfd616SPantelis Antoniou 159093bfd616SPantelis Antoniou mmc = calloc(1, sizeof(*mmc)); 159193bfd616SPantelis Antoniou if (mmc == NULL) 159293bfd616SPantelis Antoniou return NULL; 159393bfd616SPantelis Antoniou 159493bfd616SPantelis Antoniou mmc->cfg = cfg; 159593bfd616SPantelis Antoniou mmc->priv = priv; 159693bfd616SPantelis Antoniou 159793bfd616SPantelis Antoniou /* the following chunk was mmc_register() */ 159893bfd616SPantelis Antoniou 1599ab71188cSMarkus Niebel /* Setup dsr related values */ 1600ab71188cSMarkus Niebel mmc->dsr_imp = 0; 1601ab71188cSMarkus Niebel mmc->dsr = 0xffffffff; 1602272cc70bSAndy Fleming /* Setup the universal parts of the block interface just once */ 1603c40fdca6SSimon Glass bdesc = mmc_get_blk_desc(mmc); 1604c40fdca6SSimon Glass bdesc->if_type = IF_TYPE_MMC; 1605c40fdca6SSimon Glass bdesc->removable = 1; 1606c40fdca6SSimon Glass bdesc->devnum = mmc_get_next_devnum(); 1607c40fdca6SSimon Glass bdesc->block_read = mmc_bread; 1608c40fdca6SSimon Glass bdesc->block_write = mmc_bwrite; 1609c40fdca6SSimon Glass bdesc->block_erase = mmc_berase; 161093bfd616SPantelis Antoniou 161193bfd616SPantelis Antoniou /* setup initial part type */ 1612c40fdca6SSimon Glass bdesc->part_type = mmc->cfg->part_type; 1613c40fdca6SSimon Glass mmc_list_add(mmc); 1614272cc70bSAndy Fleming 161593bfd616SPantelis Antoniou return mmc; 161693bfd616SPantelis Antoniou } 161793bfd616SPantelis Antoniou 161893bfd616SPantelis Antoniou void mmc_destroy(struct mmc *mmc) 161993bfd616SPantelis Antoniou { 162093bfd616SPantelis Antoniou /* only freeing memory for now */ 162193bfd616SPantelis Antoniou free(mmc); 1622272cc70bSAndy Fleming } 1623ad27dd5eSSimon Glass #endif 1624272cc70bSAndy Fleming 162533fb211dSSimon Glass #ifndef CONFIG_BLK 16263c457f4dSSimon Glass static int mmc_get_dev(int dev, struct blk_desc **descp) 1627663acabdSSimon Glass { 1628663acabdSSimon Glass struct mmc *mmc = find_mmc_device(dev); 1629663acabdSSimon Glass int ret; 1630663acabdSSimon Glass 1631663acabdSSimon Glass if (!mmc) 1632663acabdSSimon Glass return -ENODEV; 1633663acabdSSimon Glass ret = mmc_init(mmc); 1634663acabdSSimon Glass if (ret) 1635663acabdSSimon Glass return ret; 1636663acabdSSimon Glass 1637663acabdSSimon Glass *descp = &mmc->block_dev; 1638663acabdSSimon Glass 1639663acabdSSimon Glass return 0; 1640663acabdSSimon Glass } 164133fb211dSSimon Glass #endif 1642663acabdSSimon Glass 164395de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */ 164495de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void) 164595de9ab2SPaul Kocialkowski { 164695de9ab2SPaul Kocialkowski } 164795de9ab2SPaul Kocialkowski 1648e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc) 1649272cc70bSAndy Fleming { 1650afd5932bSMacpaul Lin int err; 1651272cc70bSAndy Fleming 1652ab769f22SPantelis Antoniou /* we pretend there's no card when init is NULL */ 165393bfd616SPantelis Antoniou if (mmc_getcd(mmc) == 0 || mmc->cfg->ops->init == NULL) { 165448972d90SThierry Reding mmc->has_init = 0; 165556196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 165648972d90SThierry Reding printf("MMC: no card present\n"); 165756196826SPaul Burton #endif 165848972d90SThierry Reding return NO_CARD_ERR; 165948972d90SThierry Reding } 166048972d90SThierry Reding 1661bc897b1dSLei Wen if (mmc->has_init) 1662bc897b1dSLei Wen return 0; 1663bc897b1dSLei Wen 16645a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 16655a8dbdc6SYangbo Lu mmc_adapter_card_type_ident(); 16665a8dbdc6SYangbo Lu #endif 166795de9ab2SPaul Kocialkowski board_mmc_power_init(); 166895de9ab2SPaul Kocialkowski 1669ab769f22SPantelis Antoniou /* made sure it's not NULL earlier */ 167093bfd616SPantelis Antoniou err = mmc->cfg->ops->init(mmc); 1671272cc70bSAndy Fleming 1672272cc70bSAndy Fleming if (err) 1673272cc70bSAndy Fleming return err; 1674272cc70bSAndy Fleming 1675786e8f81SAndrew Gabbasov mmc->ddr_mode = 0; 1676b86b85e2SIlya Yanok mmc_set_bus_width(mmc, 1); 1677b86b85e2SIlya Yanok mmc_set_clock(mmc, 1); 1678b86b85e2SIlya Yanok 1679272cc70bSAndy Fleming /* Reset the Card */ 1680272cc70bSAndy Fleming err = mmc_go_idle(mmc); 1681272cc70bSAndy Fleming 1682272cc70bSAndy Fleming if (err) 1683272cc70bSAndy Fleming return err; 1684272cc70bSAndy Fleming 1685bc897b1dSLei Wen /* The internal partition reset to user partition(0) at every CMD0*/ 1686c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->hwpart = 0; 1687bc897b1dSLei Wen 1688272cc70bSAndy Fleming /* Test for SD version 2 */ 1689272cc70bSAndy Fleming err = mmc_send_if_cond(mmc); 1690272cc70bSAndy Fleming 1691272cc70bSAndy Fleming /* Now try to get the SD card's operating condition */ 1692272cc70bSAndy Fleming err = sd_send_op_cond(mmc); 1693272cc70bSAndy Fleming 1694272cc70bSAndy Fleming /* If the command timed out, we check for an MMC card */ 1695272cc70bSAndy Fleming if (err == TIMEOUT) { 1696272cc70bSAndy Fleming err = mmc_send_op_cond(mmc); 1697272cc70bSAndy Fleming 1698bd47c135SAndrew Gabbasov if (err) { 169956196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 1700272cc70bSAndy Fleming printf("Card did not respond to voltage select!\n"); 170156196826SPaul Burton #endif 1702272cc70bSAndy Fleming return UNUSABLE_ERR; 1703272cc70bSAndy Fleming } 1704272cc70bSAndy Fleming } 1705272cc70bSAndy Fleming 1706bd47c135SAndrew Gabbasov if (!err) 1707e9550449SChe-Liang Chiou mmc->init_in_progress = 1; 1708e9550449SChe-Liang Chiou 1709e9550449SChe-Liang Chiou return err; 1710e9550449SChe-Liang Chiou } 1711e9550449SChe-Liang Chiou 1712e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc) 1713e9550449SChe-Liang Chiou { 1714e9550449SChe-Liang Chiou int err = 0; 1715e9550449SChe-Liang Chiou 1716bd47c135SAndrew Gabbasov mmc->init_in_progress = 0; 1717e9550449SChe-Liang Chiou if (mmc->op_cond_pending) 1718e9550449SChe-Liang Chiou err = mmc_complete_op_cond(mmc); 1719e9550449SChe-Liang Chiou 1720e9550449SChe-Liang Chiou if (!err) 1721bc897b1dSLei Wen err = mmc_startup(mmc); 1722bc897b1dSLei Wen if (err) 1723bc897b1dSLei Wen mmc->has_init = 0; 1724bc897b1dSLei Wen else 1725bc897b1dSLei Wen mmc->has_init = 1; 1726e9550449SChe-Liang Chiou return err; 1727e9550449SChe-Liang Chiou } 1728e9550449SChe-Liang Chiou 1729e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc) 1730e9550449SChe-Liang Chiou { 1731bd47c135SAndrew Gabbasov int err = 0; 1732d803fea5SMateusz Zalega unsigned start; 173333fb211dSSimon Glass #ifdef CONFIG_DM_MMC 173433fb211dSSimon Glass struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev); 1735e9550449SChe-Liang Chiou 173633fb211dSSimon Glass upriv->mmc = mmc; 173733fb211dSSimon Glass #endif 1738e9550449SChe-Liang Chiou if (mmc->has_init) 1739e9550449SChe-Liang Chiou return 0; 1740d803fea5SMateusz Zalega 1741d803fea5SMateusz Zalega start = get_timer(0); 1742d803fea5SMateusz Zalega 1743e9550449SChe-Liang Chiou if (!mmc->init_in_progress) 1744e9550449SChe-Liang Chiou err = mmc_start_init(mmc); 1745e9550449SChe-Liang Chiou 1746bd47c135SAndrew Gabbasov if (!err) 1747e9550449SChe-Liang Chiou err = mmc_complete_init(mmc); 1748e9550449SChe-Liang Chiou debug("%s: %d, time %lu\n", __func__, err, get_timer(start)); 1749bc897b1dSLei Wen return err; 1750272cc70bSAndy Fleming } 1751272cc70bSAndy Fleming 1752ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val) 1753ab71188cSMarkus Niebel { 1754ab71188cSMarkus Niebel mmc->dsr = val; 1755ab71188cSMarkus Niebel return 0; 1756ab71188cSMarkus Niebel } 1757ab71188cSMarkus Niebel 1758cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */ 1759cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis) 1760272cc70bSAndy Fleming { 1761272cc70bSAndy Fleming return -1; 1762272cc70bSAndy Fleming } 1763272cc70bSAndy Fleming 1764cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */ 1765cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis) 1766cee9ab7cSJeroen Hofstee { 1767cee9ab7cSJeroen Hofstee return -1; 1768cee9ab7cSJeroen Hofstee } 1769272cc70bSAndy Fleming 1770e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit) 1771e9550449SChe-Liang Chiou { 1772e9550449SChe-Liang Chiou mmc->preinit = preinit; 1773e9550449SChe-Liang Chiou } 1774e9550449SChe-Liang Chiou 17758e3332e2SSjoerd Simons #if defined(CONFIG_DM_MMC) && defined(CONFIG_SPL_BUILD) 17768e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 17778e3332e2SSjoerd Simons { 17788e3332e2SSjoerd Simons return 0; 17798e3332e2SSjoerd Simons } 17808e3332e2SSjoerd Simons #elif defined(CONFIG_DM_MMC) 17818e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 17828e3332e2SSjoerd Simons { 17834a1db6d8SSimon Glass int ret, i; 17848e3332e2SSjoerd Simons struct uclass *uc; 17854a1db6d8SSimon Glass struct udevice *dev; 17868e3332e2SSjoerd Simons 17878e3332e2SSjoerd Simons ret = uclass_get(UCLASS_MMC, &uc); 17888e3332e2SSjoerd Simons if (ret) 17898e3332e2SSjoerd Simons return ret; 17908e3332e2SSjoerd Simons 17914a1db6d8SSimon Glass /* 17924a1db6d8SSimon Glass * Try to add them in sequence order. Really with driver model we 17934a1db6d8SSimon Glass * should allow holes, but the current MMC list does not allow that. 17944a1db6d8SSimon Glass * So if we request 0, 1, 3 we will get 0, 1, 2. 17954a1db6d8SSimon Glass */ 17964a1db6d8SSimon Glass for (i = 0; ; i++) { 17974a1db6d8SSimon Glass ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev); 17984a1db6d8SSimon Glass if (ret == -ENODEV) 17994a1db6d8SSimon Glass break; 18004a1db6d8SSimon Glass } 18014a1db6d8SSimon Glass uclass_foreach_dev(dev, uc) { 18024a1db6d8SSimon Glass ret = device_probe(dev); 18038e3332e2SSjoerd Simons if (ret) 18044a1db6d8SSimon Glass printf("%s - probe failed: %d\n", dev->name, ret); 18058e3332e2SSjoerd Simons } 18068e3332e2SSjoerd Simons 18078e3332e2SSjoerd Simons return 0; 18088e3332e2SSjoerd Simons } 18098e3332e2SSjoerd Simons #else 18108e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 18118e3332e2SSjoerd Simons { 18128e3332e2SSjoerd Simons if (board_mmc_init(bis) < 0) 18138e3332e2SSjoerd Simons cpu_mmc_init(bis); 18148e3332e2SSjoerd Simons 18158e3332e2SSjoerd Simons return 0; 18168e3332e2SSjoerd Simons } 18178e3332e2SSjoerd Simons #endif 1818e9550449SChe-Liang Chiou 1819272cc70bSAndy Fleming int mmc_initialize(bd_t *bis) 1820272cc70bSAndy Fleming { 18211b26bab1SDaniel Kochmański static int initialized = 0; 18228e3332e2SSjoerd Simons int ret; 18231b26bab1SDaniel Kochmański if (initialized) /* Avoid initializing mmc multiple times */ 18241b26bab1SDaniel Kochmański return 0; 18251b26bab1SDaniel Kochmański initialized = 1; 18261b26bab1SDaniel Kochmański 1827c40fdca6SSimon Glass #ifndef CONFIG_BLK 1828c40fdca6SSimon Glass mmc_list_init(); 1829c40fdca6SSimon Glass #endif 18308e3332e2SSjoerd Simons ret = mmc_probe(bis); 18318e3332e2SSjoerd Simons if (ret) 18328e3332e2SSjoerd Simons return ret; 1833272cc70bSAndy Fleming 1834bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD 1835272cc70bSAndy Fleming print_mmc_devices(','); 1836bb0dc108SYing Zhang #endif 1837272cc70bSAndy Fleming 1838c40fdca6SSimon Glass mmc_do_preinit(); 1839272cc70bSAndy Fleming return 0; 1840272cc70bSAndy Fleming } 18413690d6d6SAmar 18423690d6d6SAmar #ifdef CONFIG_SUPPORT_EMMC_BOOT 18433690d6d6SAmar /* 18443690d6d6SAmar * This function changes the size of boot partition and the size of rpmb 18453690d6d6SAmar * partition present on EMMC devices. 18463690d6d6SAmar * 18473690d6d6SAmar * Input Parameters: 18483690d6d6SAmar * struct *mmc: pointer for the mmc device strcuture 18493690d6d6SAmar * bootsize: size of boot partition 18503690d6d6SAmar * rpmbsize: size of rpmb partition 18513690d6d6SAmar * 18523690d6d6SAmar * Returns 0 on success. 18533690d6d6SAmar */ 18543690d6d6SAmar 18553690d6d6SAmar int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize, 18563690d6d6SAmar unsigned long rpmbsize) 18573690d6d6SAmar { 18583690d6d6SAmar int err; 18593690d6d6SAmar struct mmc_cmd cmd; 18603690d6d6SAmar 18613690d6d6SAmar /* Only use this command for raw EMMC moviNAND. Enter backdoor mode */ 18623690d6d6SAmar cmd.cmdidx = MMC_CMD_RES_MAN; 18633690d6d6SAmar cmd.resp_type = MMC_RSP_R1b; 18643690d6d6SAmar cmd.cmdarg = MMC_CMD62_ARG1; 18653690d6d6SAmar 18663690d6d6SAmar err = mmc_send_cmd(mmc, &cmd, NULL); 18673690d6d6SAmar if (err) { 18683690d6d6SAmar debug("mmc_boot_partition_size_change: Error1 = %d\n", err); 18693690d6d6SAmar return err; 18703690d6d6SAmar } 18713690d6d6SAmar 18723690d6d6SAmar /* Boot partition changing mode */ 18733690d6d6SAmar cmd.cmdidx = MMC_CMD_RES_MAN; 18743690d6d6SAmar cmd.resp_type = MMC_RSP_R1b; 18753690d6d6SAmar cmd.cmdarg = MMC_CMD62_ARG2; 18763690d6d6SAmar 18773690d6d6SAmar err = mmc_send_cmd(mmc, &cmd, NULL); 18783690d6d6SAmar if (err) { 18793690d6d6SAmar debug("mmc_boot_partition_size_change: Error2 = %d\n", err); 18803690d6d6SAmar return err; 18813690d6d6SAmar } 18823690d6d6SAmar /* boot partition size is multiple of 128KB */ 18833690d6d6SAmar bootsize = (bootsize * 1024) / 128; 18843690d6d6SAmar 18853690d6d6SAmar /* Arg: boot partition size */ 18863690d6d6SAmar cmd.cmdidx = MMC_CMD_RES_MAN; 18873690d6d6SAmar cmd.resp_type = MMC_RSP_R1b; 18883690d6d6SAmar cmd.cmdarg = bootsize; 18893690d6d6SAmar 18903690d6d6SAmar err = mmc_send_cmd(mmc, &cmd, NULL); 18913690d6d6SAmar if (err) { 18923690d6d6SAmar debug("mmc_boot_partition_size_change: Error3 = %d\n", err); 18933690d6d6SAmar return err; 18943690d6d6SAmar } 18953690d6d6SAmar /* RPMB partition size is multiple of 128KB */ 18963690d6d6SAmar rpmbsize = (rpmbsize * 1024) / 128; 18973690d6d6SAmar /* Arg: RPMB partition size */ 18983690d6d6SAmar cmd.cmdidx = MMC_CMD_RES_MAN; 18993690d6d6SAmar cmd.resp_type = MMC_RSP_R1b; 19003690d6d6SAmar cmd.cmdarg = rpmbsize; 19013690d6d6SAmar 19023690d6d6SAmar err = mmc_send_cmd(mmc, &cmd, NULL); 19033690d6d6SAmar if (err) { 19043690d6d6SAmar debug("mmc_boot_partition_size_change: Error4 = %d\n", err); 19053690d6d6SAmar return err; 19063690d6d6SAmar } 19073690d6d6SAmar return 0; 19083690d6d6SAmar } 19093690d6d6SAmar 19103690d6d6SAmar /* 19115a99b9deSTom Rini * Modify EXT_CSD[177] which is BOOT_BUS_WIDTH 19125a99b9deSTom Rini * based on the passed in values for BOOT_BUS_WIDTH, RESET_BOOT_BUS_WIDTH 19135a99b9deSTom Rini * and BOOT_MODE. 19145a99b9deSTom Rini * 19155a99b9deSTom Rini * Returns 0 on success. 19165a99b9deSTom Rini */ 19175a99b9deSTom Rini int mmc_set_boot_bus_width(struct mmc *mmc, u8 width, u8 reset, u8 mode) 19185a99b9deSTom Rini { 19195a99b9deSTom Rini int err; 19205a99b9deSTom Rini 19215a99b9deSTom Rini err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_BUS_WIDTH, 19225a99b9deSTom Rini EXT_CSD_BOOT_BUS_WIDTH_MODE(mode) | 19235a99b9deSTom Rini EXT_CSD_BOOT_BUS_WIDTH_RESET(reset) | 19245a99b9deSTom Rini EXT_CSD_BOOT_BUS_WIDTH_WIDTH(width)); 19255a99b9deSTom Rini 19265a99b9deSTom Rini if (err) 19275a99b9deSTom Rini return err; 19285a99b9deSTom Rini return 0; 19295a99b9deSTom Rini } 19305a99b9deSTom Rini 19315a99b9deSTom Rini /* 1932792970b0STom Rini * Modify EXT_CSD[179] which is PARTITION_CONFIG (formerly BOOT_CONFIG) 1933792970b0STom Rini * based on the passed in values for BOOT_ACK, BOOT_PARTITION_ENABLE and 1934792970b0STom Rini * PARTITION_ACCESS. 1935792970b0STom Rini * 1936792970b0STom Rini * Returns 0 on success. 1937792970b0STom Rini */ 1938792970b0STom Rini int mmc_set_part_conf(struct mmc *mmc, u8 ack, u8 part_num, u8 access) 1939792970b0STom Rini { 1940792970b0STom Rini int err; 1941792970b0STom Rini 1942792970b0STom Rini err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, 1943792970b0STom Rini EXT_CSD_BOOT_ACK(ack) | 1944792970b0STom Rini EXT_CSD_BOOT_PART_NUM(part_num) | 1945792970b0STom Rini EXT_CSD_PARTITION_ACCESS(access)); 1946792970b0STom Rini 1947792970b0STom Rini if (err) 1948792970b0STom Rini return err; 1949792970b0STom Rini return 0; 1950792970b0STom Rini } 195133ace362STom Rini 195233ace362STom Rini /* 195333ace362STom Rini * Modify EXT_CSD[162] which is RST_n_FUNCTION based on the given value 195433ace362STom Rini * for enable. Note that this is a write-once field for non-zero values. 195533ace362STom Rini * 195633ace362STom Rini * Returns 0 on success. 195733ace362STom Rini */ 195833ace362STom Rini int mmc_set_rst_n_function(struct mmc *mmc, u8 enable) 195933ace362STom Rini { 196033ace362STom Rini return mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_RST_N_FUNCTION, 196133ace362STom Rini enable); 196233ace362STom Rini } 19633690d6d6SAmar #endif 1964663acabdSSimon Glass 196533fb211dSSimon Glass #ifdef CONFIG_BLK 196633fb211dSSimon Glass static const struct blk_ops mmc_blk_ops = { 196733fb211dSSimon Glass .read = mmc_bread, 196833fb211dSSimon Glass .write = mmc_bwrite, 196933fb211dSSimon Glass .select_hwpart = mmc_select_hwpart, 197033fb211dSSimon Glass }; 197133fb211dSSimon Glass 197233fb211dSSimon Glass U_BOOT_DRIVER(mmc_blk) = { 197333fb211dSSimon Glass .name = "mmc_blk", 197433fb211dSSimon Glass .id = UCLASS_BLK, 197533fb211dSSimon Glass .ops = &mmc_blk_ops, 197633fb211dSSimon Glass }; 197733fb211dSSimon Glass #else 1978663acabdSSimon Glass U_BOOT_LEGACY_BLK(mmc) = { 1979663acabdSSimon Glass .if_typename = "mmc", 1980663acabdSSimon Glass .if_type = IF_TYPE_MMC, 1981663acabdSSimon Glass .max_devs = -1, 19823c457f4dSSimon Glass .get_dev = mmc_get_dev, 1983e17d1143SSimon Glass .select_hwpart = mmc_select_hwpartp, 1984663acabdSSimon Glass }; 198533fb211dSSimon Glass #endif 1986