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> 13*d4622df3SStephen Warren #include <errno.h> 14272cc70bSAndy Fleming #include <mmc.h> 15272cc70bSAndy Fleming #include <part.h> 16272cc70bSAndy Fleming #include <malloc.h> 17272cc70bSAndy Fleming #include <linux/list.h> 189b1f942cSRabin Vincent #include <div64.h> 19da61fa5fSPaul Burton #include "mmc_private.h" 20272cc70bSAndy Fleming 21272cc70bSAndy Fleming static struct list_head mmc_devices; 22272cc70bSAndy Fleming static int cur_dev_num = -1; 23272cc70bSAndy Fleming 24d23d8d7eSNikita Kiryanov int __weak 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 45314284b1SThierry Reding int __board_mmc_getcd(struct mmc *mmc) { 4611fdade2SStefano Babic return -1; 4711fdade2SStefano Babic } 4811fdade2SStefano Babic 49314284b1SThierry Reding int board_mmc_getcd(struct mmc *mmc)__attribute__((weak, 5011fdade2SStefano Babic alias("__board_mmc_getcd"))); 5111fdade2SStefano Babic 52da61fa5fSPaul Burton int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) 53272cc70bSAndy Fleming { 545db2fe3aSRaffaele Recalcati int ret; 558635ff9eSMarek Vasut 568635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE 575db2fe3aSRaffaele Recalcati int i; 585db2fe3aSRaffaele Recalcati u8 *ptr; 595db2fe3aSRaffaele Recalcati 605db2fe3aSRaffaele Recalcati printf("CMD_SEND:%d\n", cmd->cmdidx); 615db2fe3aSRaffaele Recalcati printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg); 6293bfd616SPantelis Antoniou ret = mmc->cfg->ops->send_cmd(mmc, cmd, data); 635db2fe3aSRaffaele Recalcati switch (cmd->resp_type) { 645db2fe3aSRaffaele Recalcati case MMC_RSP_NONE: 655db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_NONE\n"); 665db2fe3aSRaffaele Recalcati break; 675db2fe3aSRaffaele Recalcati case MMC_RSP_R1: 685db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n", 695db2fe3aSRaffaele Recalcati cmd->response[0]); 705db2fe3aSRaffaele Recalcati break; 715db2fe3aSRaffaele Recalcati case MMC_RSP_R1b: 725db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n", 735db2fe3aSRaffaele Recalcati cmd->response[0]); 745db2fe3aSRaffaele Recalcati break; 755db2fe3aSRaffaele Recalcati case MMC_RSP_R2: 765db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R2\t\t 0x%08X \n", 775db2fe3aSRaffaele Recalcati cmd->response[0]); 785db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 795db2fe3aSRaffaele Recalcati cmd->response[1]); 805db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 815db2fe3aSRaffaele Recalcati cmd->response[2]); 825db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 835db2fe3aSRaffaele Recalcati cmd->response[3]); 845db2fe3aSRaffaele Recalcati printf("\n"); 855db2fe3aSRaffaele Recalcati printf("\t\t\t\t\tDUMPING DATA\n"); 865db2fe3aSRaffaele Recalcati for (i = 0; i < 4; i++) { 875db2fe3aSRaffaele Recalcati int j; 885db2fe3aSRaffaele Recalcati printf("\t\t\t\t\t%03d - ", i*4); 89146bec79SDirk Behme ptr = (u8 *)&cmd->response[i]; 905db2fe3aSRaffaele Recalcati ptr += 3; 915db2fe3aSRaffaele Recalcati for (j = 0; j < 4; j++) 925db2fe3aSRaffaele Recalcati printf("%02X ", *ptr--); 935db2fe3aSRaffaele Recalcati printf("\n"); 945db2fe3aSRaffaele Recalcati } 955db2fe3aSRaffaele Recalcati break; 965db2fe3aSRaffaele Recalcati case MMC_RSP_R3: 975db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n", 985db2fe3aSRaffaele Recalcati cmd->response[0]); 995db2fe3aSRaffaele Recalcati break; 1005db2fe3aSRaffaele Recalcati default: 1015db2fe3aSRaffaele Recalcati printf("\t\tERROR MMC rsp not supported\n"); 1025db2fe3aSRaffaele Recalcati break; 1035db2fe3aSRaffaele Recalcati } 1045db2fe3aSRaffaele Recalcati #else 10593bfd616SPantelis Antoniou ret = mmc->cfg->ops->send_cmd(mmc, cmd, data); 1065db2fe3aSRaffaele Recalcati #endif 1078635ff9eSMarek Vasut return ret; 108272cc70bSAndy Fleming } 109272cc70bSAndy Fleming 110da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout) 1115d4fc8d9SRaffaele Recalcati { 1125d4fc8d9SRaffaele Recalcati struct mmc_cmd cmd; 113d617c426SJan Kloetzke int err, retries = 5; 1145d4fc8d9SRaffaele Recalcati #ifdef CONFIG_MMC_TRACE 1155d4fc8d9SRaffaele Recalcati int status; 1165d4fc8d9SRaffaele Recalcati #endif 1175d4fc8d9SRaffaele Recalcati 1185d4fc8d9SRaffaele Recalcati cmd.cmdidx = MMC_CMD_SEND_STATUS; 1195d4fc8d9SRaffaele Recalcati cmd.resp_type = MMC_RSP_R1; 120aaf3d41aSMarek Vasut if (!mmc_host_is_spi(mmc)) 121aaf3d41aSMarek Vasut cmd.cmdarg = mmc->rca << 16; 1225d4fc8d9SRaffaele Recalcati 1235d4fc8d9SRaffaele Recalcati do { 1245d4fc8d9SRaffaele Recalcati err = mmc_send_cmd(mmc, &cmd, NULL); 125d617c426SJan Kloetzke if (!err) { 126d617c426SJan Kloetzke if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) && 127d617c426SJan Kloetzke (cmd.response[0] & MMC_STATUS_CURR_STATE) != 128d617c426SJan Kloetzke MMC_STATE_PRG) 1295d4fc8d9SRaffaele Recalcati break; 130d617c426SJan Kloetzke else if (cmd.response[0] & MMC_STATUS_MASK) { 13156196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 132d617c426SJan Kloetzke printf("Status Error: 0x%08X\n", 133d617c426SJan Kloetzke cmd.response[0]); 13456196826SPaul Burton #endif 135d617c426SJan Kloetzke return COMM_ERR; 136d617c426SJan Kloetzke } 137d617c426SJan Kloetzke } else if (--retries < 0) 138d617c426SJan Kloetzke return err; 1395d4fc8d9SRaffaele Recalcati 1405d4fc8d9SRaffaele Recalcati udelay(1000); 1415d4fc8d9SRaffaele Recalcati 1425d4fc8d9SRaffaele Recalcati } while (timeout--); 1435d4fc8d9SRaffaele Recalcati 1445db2fe3aSRaffaele Recalcati #ifdef CONFIG_MMC_TRACE 1455db2fe3aSRaffaele Recalcati status = (cmd.response[0] & MMC_STATUS_CURR_STATE) >> 9; 1465db2fe3aSRaffaele Recalcati printf("CURR STATE:%d\n", status); 1475db2fe3aSRaffaele Recalcati #endif 1485b0c942fSJongman Heo if (timeout <= 0) { 14956196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 1505d4fc8d9SRaffaele Recalcati printf("Timeout waiting card ready\n"); 15156196826SPaul Burton #endif 1525d4fc8d9SRaffaele Recalcati return TIMEOUT; 1535d4fc8d9SRaffaele Recalcati } 1546b2221b0SAndrew Gabbasov if (cmd.response[0] & MMC_STATUS_SWITCH_ERROR) 1556b2221b0SAndrew Gabbasov return SWITCH_ERR; 1565d4fc8d9SRaffaele Recalcati 1575d4fc8d9SRaffaele Recalcati return 0; 1585d4fc8d9SRaffaele Recalcati } 1595d4fc8d9SRaffaele Recalcati 160da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len) 161272cc70bSAndy Fleming { 162272cc70bSAndy Fleming struct mmc_cmd cmd; 163272cc70bSAndy Fleming 164d22e3d46SJaehoon Chung if (mmc->card_caps & MMC_MODE_DDR_52MHz) 165d22e3d46SJaehoon Chung return 0; 166d22e3d46SJaehoon Chung 167272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SET_BLOCKLEN; 168272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 169272cc70bSAndy Fleming cmd.cmdarg = len; 170272cc70bSAndy Fleming 171272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, NULL); 172272cc70bSAndy Fleming } 173272cc70bSAndy Fleming 174272cc70bSAndy Fleming struct mmc *find_mmc_device(int dev_num) 175272cc70bSAndy Fleming { 176272cc70bSAndy Fleming struct mmc *m; 177272cc70bSAndy Fleming struct list_head *entry; 178272cc70bSAndy Fleming 179272cc70bSAndy Fleming list_for_each(entry, &mmc_devices) { 180272cc70bSAndy Fleming m = list_entry(entry, struct mmc, link); 181272cc70bSAndy Fleming 182272cc70bSAndy Fleming if (m->block_dev.dev == dev_num) 183272cc70bSAndy Fleming return m; 184272cc70bSAndy Fleming } 185272cc70bSAndy Fleming 18656196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 187272cc70bSAndy Fleming printf("MMC Device %d not found\n", dev_num); 18856196826SPaul Burton #endif 189272cc70bSAndy Fleming 190272cc70bSAndy Fleming return NULL; 191272cc70bSAndy Fleming } 192272cc70bSAndy Fleming 193ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start, 194fdbb873eSKim Phillips lbaint_t blkcnt) 195272cc70bSAndy Fleming { 196272cc70bSAndy Fleming struct mmc_cmd cmd; 197272cc70bSAndy Fleming struct mmc_data data; 198272cc70bSAndy Fleming 1994a1a06bcSAlagu Sankar if (blkcnt > 1) 2004a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; 2014a1a06bcSAlagu Sankar else 202272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK; 203272cc70bSAndy Fleming 204272cc70bSAndy Fleming if (mmc->high_capacity) 2054a1a06bcSAlagu Sankar cmd.cmdarg = start; 206272cc70bSAndy Fleming else 2074a1a06bcSAlagu Sankar cmd.cmdarg = start * mmc->read_bl_len; 208272cc70bSAndy Fleming 209272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 210272cc70bSAndy Fleming 211272cc70bSAndy Fleming data.dest = dst; 2124a1a06bcSAlagu Sankar data.blocks = blkcnt; 213272cc70bSAndy Fleming data.blocksize = mmc->read_bl_len; 214272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 215272cc70bSAndy Fleming 2164a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, &data)) 2174a1a06bcSAlagu Sankar return 0; 2184a1a06bcSAlagu Sankar 2194a1a06bcSAlagu Sankar if (blkcnt > 1) { 2204a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; 2214a1a06bcSAlagu Sankar cmd.cmdarg = 0; 2224a1a06bcSAlagu Sankar cmd.resp_type = MMC_RSP_R1b; 2234a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, NULL)) { 22456196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2254a1a06bcSAlagu Sankar printf("mmc fail to send stop cmd\n"); 22656196826SPaul Burton #endif 2274a1a06bcSAlagu Sankar return 0; 2284a1a06bcSAlagu Sankar } 229272cc70bSAndy Fleming } 230272cc70bSAndy Fleming 2314a1a06bcSAlagu Sankar return blkcnt; 232272cc70bSAndy Fleming } 233272cc70bSAndy Fleming 234ff8fef56SSascha Silbe static ulong mmc_bread(int dev_num, lbaint_t start, lbaint_t blkcnt, void *dst) 235272cc70bSAndy Fleming { 2364a1a06bcSAlagu Sankar lbaint_t cur, blocks_todo = blkcnt; 237272cc70bSAndy Fleming 2384a1a06bcSAlagu Sankar if (blkcnt == 0) 2394a1a06bcSAlagu Sankar return 0; 2404a1a06bcSAlagu Sankar 2414a1a06bcSAlagu Sankar struct mmc *mmc = find_mmc_device(dev_num); 242272cc70bSAndy Fleming if (!mmc) 243272cc70bSAndy Fleming return 0; 244272cc70bSAndy Fleming 245d2bf29e3SLei Wen if ((start + blkcnt) > mmc->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", 248d2bf29e3SLei Wen start + blkcnt, mmc->block_dev.lba); 24956196826SPaul Burton #endif 250d2bf29e3SLei Wen return 0; 251d2bf29e3SLei Wen } 252272cc70bSAndy Fleming 2534a1a06bcSAlagu Sankar if (mmc_set_blocklen(mmc, mmc->read_bl_len)) 254272cc70bSAndy Fleming return 0; 255272cc70bSAndy Fleming 2564a1a06bcSAlagu Sankar do { 25793bfd616SPantelis Antoniou cur = (blocks_todo > mmc->cfg->b_max) ? 25893bfd616SPantelis Antoniou mmc->cfg->b_max : blocks_todo; 2594a1a06bcSAlagu Sankar if(mmc_read_blocks(mmc, dst, start, cur) != cur) 2604a1a06bcSAlagu Sankar return 0; 2614a1a06bcSAlagu Sankar blocks_todo -= cur; 2624a1a06bcSAlagu Sankar start += cur; 2634a1a06bcSAlagu Sankar dst += cur * mmc->read_bl_len; 2644a1a06bcSAlagu Sankar } while (blocks_todo > 0); 265272cc70bSAndy Fleming 266272cc70bSAndy Fleming return blkcnt; 267272cc70bSAndy Fleming } 268272cc70bSAndy Fleming 269fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc) 270272cc70bSAndy Fleming { 271272cc70bSAndy Fleming struct mmc_cmd cmd; 272272cc70bSAndy Fleming int err; 273272cc70bSAndy Fleming 274272cc70bSAndy Fleming udelay(1000); 275272cc70bSAndy Fleming 276272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_GO_IDLE_STATE; 277272cc70bSAndy Fleming cmd.cmdarg = 0; 278272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_NONE; 279272cc70bSAndy Fleming 280272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 281272cc70bSAndy Fleming 282272cc70bSAndy Fleming if (err) 283272cc70bSAndy Fleming return err; 284272cc70bSAndy Fleming 285272cc70bSAndy Fleming udelay(2000); 286272cc70bSAndy Fleming 287272cc70bSAndy Fleming return 0; 288272cc70bSAndy Fleming } 289272cc70bSAndy Fleming 290fdbb873eSKim Phillips static int sd_send_op_cond(struct mmc *mmc) 291272cc70bSAndy Fleming { 292272cc70bSAndy Fleming int timeout = 1000; 293272cc70bSAndy Fleming int err; 294272cc70bSAndy Fleming struct mmc_cmd cmd; 295272cc70bSAndy Fleming 296272cc70bSAndy Fleming do { 297272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 298272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 299272cc70bSAndy Fleming cmd.cmdarg = 0; 300272cc70bSAndy Fleming 301272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 302272cc70bSAndy Fleming 303272cc70bSAndy Fleming if (err) 304272cc70bSAndy Fleming return err; 305272cc70bSAndy Fleming 306272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_OP_COND; 307272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R3; 308250de12bSStefano Babic 309250de12bSStefano Babic /* 310250de12bSStefano Babic * Most cards do not answer if some reserved bits 311250de12bSStefano Babic * in the ocr are set. However, Some controller 312250de12bSStefano Babic * can set bit 7 (reserved for low voltages), but 313250de12bSStefano Babic * how to manage low voltages SD card is not yet 314250de12bSStefano Babic * specified. 315250de12bSStefano Babic */ 316d52ebf10SThomas Chou cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 : 31793bfd616SPantelis Antoniou (mmc->cfg->voltages & 0xff8000); 318272cc70bSAndy Fleming 319272cc70bSAndy Fleming if (mmc->version == SD_VERSION_2) 320272cc70bSAndy Fleming cmd.cmdarg |= OCR_HCS; 321272cc70bSAndy Fleming 322272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 323272cc70bSAndy Fleming 324272cc70bSAndy Fleming if (err) 325272cc70bSAndy Fleming return err; 326272cc70bSAndy Fleming 327272cc70bSAndy Fleming udelay(1000); 328272cc70bSAndy Fleming } while ((!(cmd.response[0] & OCR_BUSY)) && timeout--); 329272cc70bSAndy Fleming 330272cc70bSAndy Fleming if (timeout <= 0) 331272cc70bSAndy Fleming return UNUSABLE_ERR; 332272cc70bSAndy Fleming 333272cc70bSAndy Fleming if (mmc->version != SD_VERSION_2) 334272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 335272cc70bSAndy Fleming 336d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 337d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 338d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 339d52ebf10SThomas Chou cmd.cmdarg = 0; 340d52ebf10SThomas Chou 341d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 342d52ebf10SThomas Chou 343d52ebf10SThomas Chou if (err) 344d52ebf10SThomas Chou return err; 345d52ebf10SThomas Chou } 346d52ebf10SThomas Chou 347998be3ddSRabin Vincent mmc->ocr = cmd.response[0]; 348272cc70bSAndy Fleming 349272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 350272cc70bSAndy Fleming mmc->rca = 0; 351272cc70bSAndy Fleming 352272cc70bSAndy Fleming return 0; 353272cc70bSAndy Fleming } 354272cc70bSAndy Fleming 355e9550449SChe-Liang Chiou /* We pass in the cmd since otherwise the init seems to fail */ 356e9550449SChe-Liang Chiou static int mmc_send_op_cond_iter(struct mmc *mmc, struct mmc_cmd *cmd, 357e9550449SChe-Liang Chiou int use_arg) 358272cc70bSAndy Fleming { 359272cc70bSAndy Fleming int err; 360272cc70bSAndy Fleming 361e9550449SChe-Liang Chiou cmd->cmdidx = MMC_CMD_SEND_OP_COND; 362e9550449SChe-Liang Chiou cmd->resp_type = MMC_RSP_R3; 363e9550449SChe-Liang Chiou cmd->cmdarg = 0; 364e9550449SChe-Liang Chiou if (use_arg && !mmc_host_is_spi(mmc)) { 365e9550449SChe-Liang Chiou cmd->cmdarg = 36693bfd616SPantelis Antoniou (mmc->cfg->voltages & 367e9550449SChe-Liang Chiou (mmc->op_cond_response & OCR_VOLTAGE_MASK)) | 368e9550449SChe-Liang Chiou (mmc->op_cond_response & OCR_ACCESS_MODE); 369e9550449SChe-Liang Chiou 37093bfd616SPantelis Antoniou if (mmc->cfg->host_caps & MMC_MODE_HC) 371e9550449SChe-Liang Chiou cmd->cmdarg |= OCR_HCS; 372e9550449SChe-Liang Chiou } 373e9550449SChe-Liang Chiou err = mmc_send_cmd(mmc, cmd, NULL); 374e9550449SChe-Liang Chiou if (err) 375e9550449SChe-Liang Chiou return err; 376e9550449SChe-Liang Chiou mmc->op_cond_response = cmd->response[0]; 377e9550449SChe-Liang Chiou return 0; 378e9550449SChe-Liang Chiou } 379e9550449SChe-Liang Chiou 380e9550449SChe-Liang Chiou int mmc_send_op_cond(struct mmc *mmc) 381e9550449SChe-Liang Chiou { 382e9550449SChe-Liang Chiou struct mmc_cmd cmd; 383e9550449SChe-Liang Chiou int err, i; 384e9550449SChe-Liang Chiou 385272cc70bSAndy Fleming /* Some cards seem to need this */ 386272cc70bSAndy Fleming mmc_go_idle(mmc); 387272cc70bSAndy Fleming 38831cacbabSRaffaele Recalcati /* Asking to the card its capabilities */ 389e9550449SChe-Liang Chiou mmc->op_cond_pending = 1; 390e9550449SChe-Liang Chiou for (i = 0; i < 2; i++) { 391e9550449SChe-Liang Chiou err = mmc_send_op_cond_iter(mmc, &cmd, i != 0); 39231cacbabSRaffaele Recalcati if (err) 39331cacbabSRaffaele Recalcati return err; 39431cacbabSRaffaele Recalcati 395e9550449SChe-Liang Chiou /* exit if not busy (flag seems to be inverted) */ 396e9550449SChe-Liang Chiou if (mmc->op_cond_response & OCR_BUSY) 397e9550449SChe-Liang Chiou return 0; 398e9550449SChe-Liang Chiou } 399e9550449SChe-Liang Chiou return IN_PROGRESS; 400e9550449SChe-Liang Chiou } 40131cacbabSRaffaele Recalcati 402e9550449SChe-Liang Chiou int mmc_complete_op_cond(struct mmc *mmc) 403e9550449SChe-Liang Chiou { 404e9550449SChe-Liang Chiou struct mmc_cmd cmd; 405e9550449SChe-Liang Chiou int timeout = 1000; 406e9550449SChe-Liang Chiou uint start; 407e9550449SChe-Liang Chiou int err; 408e9550449SChe-Liang Chiou 409e9550449SChe-Liang Chiou mmc->op_cond_pending = 0; 410e9550449SChe-Liang Chiou start = get_timer(0); 411272cc70bSAndy Fleming do { 412e9550449SChe-Liang Chiou err = mmc_send_op_cond_iter(mmc, &cmd, 1); 413272cc70bSAndy Fleming if (err) 414272cc70bSAndy Fleming return err; 415e9550449SChe-Liang Chiou if (get_timer(start) > timeout) 416272cc70bSAndy Fleming return UNUSABLE_ERR; 417e9550449SChe-Liang Chiou udelay(100); 418e9550449SChe-Liang Chiou } while (!(mmc->op_cond_response & OCR_BUSY)); 419272cc70bSAndy Fleming 420d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 421d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 422d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 423d52ebf10SThomas Chou cmd.cmdarg = 0; 424d52ebf10SThomas Chou 425d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 426d52ebf10SThomas Chou 427d52ebf10SThomas Chou if (err) 428d52ebf10SThomas Chou return err; 429d52ebf10SThomas Chou } 430d52ebf10SThomas Chou 431272cc70bSAndy Fleming mmc->version = MMC_VERSION_UNKNOWN; 432998be3ddSRabin Vincent mmc->ocr = cmd.response[0]; 433272cc70bSAndy Fleming 434272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 435def816a2SStephen Warren mmc->rca = 1; 436272cc70bSAndy Fleming 437272cc70bSAndy Fleming return 0; 438272cc70bSAndy Fleming } 439272cc70bSAndy Fleming 440272cc70bSAndy Fleming 441fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd) 442272cc70bSAndy Fleming { 443272cc70bSAndy Fleming struct mmc_cmd cmd; 444272cc70bSAndy Fleming struct mmc_data data; 445272cc70bSAndy Fleming int err; 446272cc70bSAndy Fleming 447272cc70bSAndy Fleming /* Get the Card Status Register */ 448272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_EXT_CSD; 449272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 450272cc70bSAndy Fleming cmd.cmdarg = 0; 451272cc70bSAndy Fleming 452cdfd1ac6SYoshihiro Shimoda data.dest = (char *)ext_csd; 453272cc70bSAndy Fleming data.blocks = 1; 4548bfa195eSSimon Glass data.blocksize = MMC_MAX_BLOCK_LEN; 455272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 456272cc70bSAndy Fleming 457272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 458272cc70bSAndy Fleming 459272cc70bSAndy Fleming return err; 460272cc70bSAndy Fleming } 461272cc70bSAndy Fleming 462272cc70bSAndy Fleming 463fdbb873eSKim Phillips static int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) 464272cc70bSAndy Fleming { 465272cc70bSAndy Fleming struct mmc_cmd cmd; 4665d4fc8d9SRaffaele Recalcati int timeout = 1000; 4675d4fc8d9SRaffaele Recalcati int ret; 468272cc70bSAndy Fleming 469272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SWITCH; 470272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1b; 471272cc70bSAndy Fleming cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | 472272cc70bSAndy Fleming (index << 16) | 473272cc70bSAndy Fleming (value << 8); 474272cc70bSAndy Fleming 4755d4fc8d9SRaffaele Recalcati ret = mmc_send_cmd(mmc, &cmd, NULL); 4765d4fc8d9SRaffaele Recalcati 4775d4fc8d9SRaffaele Recalcati /* Waiting for the ready status */ 47893ad0d18SJan Kloetzke if (!ret) 47993ad0d18SJan Kloetzke ret = mmc_send_status(mmc, timeout); 4805d4fc8d9SRaffaele Recalcati 4815d4fc8d9SRaffaele Recalcati return ret; 4825d4fc8d9SRaffaele Recalcati 483272cc70bSAndy Fleming } 484272cc70bSAndy Fleming 485fdbb873eSKim Phillips static int mmc_change_freq(struct mmc *mmc) 486272cc70bSAndy Fleming { 4878bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 488272cc70bSAndy Fleming char cardtype; 489272cc70bSAndy Fleming int err; 490272cc70bSAndy Fleming 491272cc70bSAndy Fleming mmc->card_caps = 0; 492272cc70bSAndy Fleming 493d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 494d52ebf10SThomas Chou return 0; 495d52ebf10SThomas Chou 496272cc70bSAndy Fleming /* Only version 4 supports high-speed */ 497272cc70bSAndy Fleming if (mmc->version < MMC_VERSION_4) 498272cc70bSAndy Fleming return 0; 499272cc70bSAndy Fleming 500272cc70bSAndy Fleming err = mmc_send_ext_csd(mmc, ext_csd); 501272cc70bSAndy Fleming 502272cc70bSAndy Fleming if (err) 503272cc70bSAndy Fleming return err; 504272cc70bSAndy Fleming 5050560db18SLei Wen cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf; 506272cc70bSAndy Fleming 507272cc70bSAndy Fleming err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1); 508272cc70bSAndy Fleming 509272cc70bSAndy Fleming if (err) 5106b2221b0SAndrew Gabbasov return err == SWITCH_ERR ? 0 : err; 511272cc70bSAndy Fleming 512272cc70bSAndy Fleming /* Now check to see that it worked */ 513272cc70bSAndy Fleming err = mmc_send_ext_csd(mmc, ext_csd); 514272cc70bSAndy Fleming 515272cc70bSAndy Fleming if (err) 516272cc70bSAndy Fleming return err; 517272cc70bSAndy Fleming 518272cc70bSAndy Fleming /* No high-speed support */ 5190560db18SLei Wen if (!ext_csd[EXT_CSD_HS_TIMING]) 520272cc70bSAndy Fleming return 0; 521272cc70bSAndy Fleming 522272cc70bSAndy Fleming /* High Speed is set, there are two types: 52MHz and 26MHz */ 523d22e3d46SJaehoon Chung if (cardtype & EXT_CSD_CARD_TYPE_52) { 524d22e3d46SJaehoon Chung if (cardtype & EXT_CSD_CARD_TYPE_DDR_52) 525d22e3d46SJaehoon Chung mmc->card_caps |= MMC_MODE_DDR_52MHz; 526272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; 527d22e3d46SJaehoon Chung } else { 528272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS; 529d22e3d46SJaehoon Chung } 530272cc70bSAndy Fleming 531272cc70bSAndy Fleming return 0; 532272cc70bSAndy Fleming } 533272cc70bSAndy Fleming 534f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num) 535f866a46dSStephen Warren { 536f866a46dSStephen Warren switch (part_num) { 537f866a46dSStephen Warren case 0: 538f866a46dSStephen Warren mmc->capacity = mmc->capacity_user; 539f866a46dSStephen Warren break; 540f866a46dSStephen Warren case 1: 541f866a46dSStephen Warren case 2: 542f866a46dSStephen Warren mmc->capacity = mmc->capacity_boot; 543f866a46dSStephen Warren break; 544f866a46dSStephen Warren case 3: 545f866a46dSStephen Warren mmc->capacity = mmc->capacity_rpmb; 546f866a46dSStephen Warren break; 547f866a46dSStephen Warren case 4: 548f866a46dSStephen Warren case 5: 549f866a46dSStephen Warren case 6: 550f866a46dSStephen Warren case 7: 551f866a46dSStephen Warren mmc->capacity = mmc->capacity_gp[part_num - 4]; 552f866a46dSStephen Warren break; 553f866a46dSStephen Warren default: 554f866a46dSStephen Warren return -1; 555f866a46dSStephen Warren } 556f866a46dSStephen Warren 557f866a46dSStephen Warren mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len); 558f866a46dSStephen Warren 559f866a46dSStephen Warren return 0; 560f866a46dSStephen Warren } 561f866a46dSStephen Warren 562d2356284SStephen Warren int mmc_select_hwpart(int dev_num, int hwpart) 563d2356284SStephen Warren { 564d2356284SStephen Warren struct mmc *mmc = find_mmc_device(dev_num); 565d2356284SStephen Warren int ret; 566d2356284SStephen Warren 567d2356284SStephen Warren if (!mmc) 568*d4622df3SStephen Warren return -ENODEV; 569d2356284SStephen Warren 570d2356284SStephen Warren if (mmc->part_num == hwpart) 571d2356284SStephen Warren return 0; 572d2356284SStephen Warren 573d2356284SStephen Warren if (mmc->part_config == MMCPART_NOAVAILABLE) { 574d2356284SStephen Warren printf("Card doesn't support part_switch\n"); 575*d4622df3SStephen Warren return -EMEDIUMTYPE; 576d2356284SStephen Warren } 577d2356284SStephen Warren 578d2356284SStephen Warren ret = mmc_switch_part(dev_num, hwpart); 579d2356284SStephen Warren if (ret) 580*d4622df3SStephen Warren return ret; 581d2356284SStephen Warren 582d2356284SStephen Warren mmc->part_num = hwpart; 583d2356284SStephen Warren 584d2356284SStephen Warren return 0; 585d2356284SStephen Warren } 586d2356284SStephen Warren 587d2356284SStephen Warren 588bc897b1dSLei Wen int mmc_switch_part(int dev_num, unsigned int part_num) 589bc897b1dSLei Wen { 590bc897b1dSLei Wen struct mmc *mmc = find_mmc_device(dev_num); 591f866a46dSStephen Warren int ret; 592bc897b1dSLei Wen 593bc897b1dSLei Wen if (!mmc) 594bc897b1dSLei Wen return -1; 595bc897b1dSLei Wen 596f866a46dSStephen Warren ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, 597bc897b1dSLei Wen (mmc->part_config & ~PART_ACCESS_MASK) 598bc897b1dSLei Wen | (part_num & PART_ACCESS_MASK)); 599f866a46dSStephen Warren if (ret) 600f866a46dSStephen Warren return ret; 601f866a46dSStephen Warren 602f866a46dSStephen Warren return mmc_set_capacity(mmc, part_num); 603bc897b1dSLei Wen } 604bc897b1dSLei Wen 60548972d90SThierry Reding int mmc_getcd(struct mmc *mmc) 60648972d90SThierry Reding { 60748972d90SThierry Reding int cd; 60848972d90SThierry Reding 60948972d90SThierry Reding cd = board_mmc_getcd(mmc); 61048972d90SThierry Reding 611d4e1da4eSPeter Korsgaard if (cd < 0) { 61293bfd616SPantelis Antoniou if (mmc->cfg->ops->getcd) 61393bfd616SPantelis Antoniou cd = mmc->cfg->ops->getcd(mmc); 614d4e1da4eSPeter Korsgaard else 615d4e1da4eSPeter Korsgaard cd = 1; 616d4e1da4eSPeter Korsgaard } 61748972d90SThierry Reding 61848972d90SThierry Reding return cd; 61948972d90SThierry Reding } 62048972d90SThierry Reding 621fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) 622272cc70bSAndy Fleming { 623272cc70bSAndy Fleming struct mmc_cmd cmd; 624272cc70bSAndy Fleming struct mmc_data data; 625272cc70bSAndy Fleming 626272cc70bSAndy Fleming /* Switch the frequency */ 627272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SWITCH_FUNC; 628272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 629272cc70bSAndy Fleming cmd.cmdarg = (mode << 31) | 0xffffff; 630272cc70bSAndy Fleming cmd.cmdarg &= ~(0xf << (group * 4)); 631272cc70bSAndy Fleming cmd.cmdarg |= value << (group * 4); 632272cc70bSAndy Fleming 633272cc70bSAndy Fleming data.dest = (char *)resp; 634272cc70bSAndy Fleming data.blocksize = 64; 635272cc70bSAndy Fleming data.blocks = 1; 636272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 637272cc70bSAndy Fleming 638272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, &data); 639272cc70bSAndy Fleming } 640272cc70bSAndy Fleming 641272cc70bSAndy Fleming 642fdbb873eSKim Phillips static int sd_change_freq(struct mmc *mmc) 643272cc70bSAndy Fleming { 644272cc70bSAndy Fleming int err; 645272cc70bSAndy Fleming struct mmc_cmd cmd; 646f781dd38SAnton staaf ALLOC_CACHE_ALIGN_BUFFER(uint, scr, 2); 647f781dd38SAnton staaf ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16); 648272cc70bSAndy Fleming struct mmc_data data; 649272cc70bSAndy Fleming int timeout; 650272cc70bSAndy Fleming 651272cc70bSAndy Fleming mmc->card_caps = 0; 652272cc70bSAndy Fleming 653d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 654d52ebf10SThomas Chou return 0; 655d52ebf10SThomas Chou 656272cc70bSAndy Fleming /* Read the SCR to find out if this card supports higher speeds */ 657272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 658272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 659272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 660272cc70bSAndy Fleming 661272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 662272cc70bSAndy Fleming 663272cc70bSAndy Fleming if (err) 664272cc70bSAndy Fleming return err; 665272cc70bSAndy Fleming 666272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_SCR; 667272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 668272cc70bSAndy Fleming cmd.cmdarg = 0; 669272cc70bSAndy Fleming 670272cc70bSAndy Fleming timeout = 3; 671272cc70bSAndy Fleming 672272cc70bSAndy Fleming retry_scr: 673f781dd38SAnton staaf data.dest = (char *)scr; 674272cc70bSAndy Fleming data.blocksize = 8; 675272cc70bSAndy Fleming data.blocks = 1; 676272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 677272cc70bSAndy Fleming 678272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 679272cc70bSAndy Fleming 680272cc70bSAndy Fleming if (err) { 681272cc70bSAndy Fleming if (timeout--) 682272cc70bSAndy Fleming goto retry_scr; 683272cc70bSAndy Fleming 684272cc70bSAndy Fleming return err; 685272cc70bSAndy Fleming } 686272cc70bSAndy Fleming 6874e3d89baSYauhen Kharuzhy mmc->scr[0] = __be32_to_cpu(scr[0]); 6884e3d89baSYauhen Kharuzhy mmc->scr[1] = __be32_to_cpu(scr[1]); 689272cc70bSAndy Fleming 690272cc70bSAndy Fleming switch ((mmc->scr[0] >> 24) & 0xf) { 691272cc70bSAndy Fleming case 0: 692272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 693272cc70bSAndy Fleming break; 694272cc70bSAndy Fleming case 1: 695272cc70bSAndy Fleming mmc->version = SD_VERSION_1_10; 696272cc70bSAndy Fleming break; 697272cc70bSAndy Fleming case 2: 698272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 6991741c64dSJaehoon Chung if ((mmc->scr[0] >> 15) & 0x1) 7001741c64dSJaehoon Chung mmc->version = SD_VERSION_3; 701272cc70bSAndy Fleming break; 702272cc70bSAndy Fleming default: 703272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 704272cc70bSAndy Fleming break; 705272cc70bSAndy Fleming } 706272cc70bSAndy Fleming 707b44c7083SAlagu Sankar if (mmc->scr[0] & SD_DATA_4BIT) 708b44c7083SAlagu Sankar mmc->card_caps |= MMC_MODE_4BIT; 709b44c7083SAlagu Sankar 710272cc70bSAndy Fleming /* Version 1.0 doesn't support switching */ 711272cc70bSAndy Fleming if (mmc->version == SD_VERSION_1_0) 712272cc70bSAndy Fleming return 0; 713272cc70bSAndy Fleming 714272cc70bSAndy Fleming timeout = 4; 715272cc70bSAndy Fleming while (timeout--) { 716272cc70bSAndy Fleming err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1, 717f781dd38SAnton staaf (u8 *)switch_status); 718272cc70bSAndy Fleming 719272cc70bSAndy Fleming if (err) 720272cc70bSAndy Fleming return err; 721272cc70bSAndy Fleming 722272cc70bSAndy Fleming /* The high-speed function is busy. Try again */ 7234e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY)) 724272cc70bSAndy Fleming break; 725272cc70bSAndy Fleming } 726272cc70bSAndy Fleming 727272cc70bSAndy Fleming /* If high-speed isn't supported, we return */ 7284e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)) 729272cc70bSAndy Fleming return 0; 730272cc70bSAndy Fleming 7312c3fbf4cSMacpaul Lin /* 7322c3fbf4cSMacpaul Lin * If the host doesn't support SD_HIGHSPEED, do not switch card to 7332c3fbf4cSMacpaul Lin * HIGHSPEED mode even if the card support SD_HIGHSPPED. 7342c3fbf4cSMacpaul Lin * This can avoid furthur problem when the card runs in different 7352c3fbf4cSMacpaul Lin * mode between the host. 7362c3fbf4cSMacpaul Lin */ 73793bfd616SPantelis Antoniou if (!((mmc->cfg->host_caps & MMC_MODE_HS_52MHz) && 73893bfd616SPantelis Antoniou (mmc->cfg->host_caps & MMC_MODE_HS))) 7392c3fbf4cSMacpaul Lin return 0; 7402c3fbf4cSMacpaul Lin 741f781dd38SAnton staaf err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status); 742272cc70bSAndy Fleming 743272cc70bSAndy Fleming if (err) 744272cc70bSAndy Fleming return err; 745272cc70bSAndy Fleming 7464e3d89baSYauhen Kharuzhy if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000) 747272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS; 748272cc70bSAndy Fleming 749272cc70bSAndy Fleming return 0; 750272cc70bSAndy Fleming } 751272cc70bSAndy Fleming 752272cc70bSAndy Fleming /* frequency bases */ 753272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */ 7545f837c2cSMike Frysinger static const int fbase[] = { 755272cc70bSAndy Fleming 10000, 756272cc70bSAndy Fleming 100000, 757272cc70bSAndy Fleming 1000000, 758272cc70bSAndy Fleming 10000000, 759272cc70bSAndy Fleming }; 760272cc70bSAndy Fleming 761272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice 762272cc70bSAndy Fleming * to platforms without floating point. 763272cc70bSAndy Fleming */ 7645f837c2cSMike Frysinger static const int multipliers[] = { 765272cc70bSAndy Fleming 0, /* reserved */ 766272cc70bSAndy Fleming 10, 767272cc70bSAndy Fleming 12, 768272cc70bSAndy Fleming 13, 769272cc70bSAndy Fleming 15, 770272cc70bSAndy Fleming 20, 771272cc70bSAndy Fleming 25, 772272cc70bSAndy Fleming 30, 773272cc70bSAndy Fleming 35, 774272cc70bSAndy Fleming 40, 775272cc70bSAndy Fleming 45, 776272cc70bSAndy Fleming 50, 777272cc70bSAndy Fleming 55, 778272cc70bSAndy Fleming 60, 779272cc70bSAndy Fleming 70, 780272cc70bSAndy Fleming 80, 781272cc70bSAndy Fleming }; 782272cc70bSAndy Fleming 783fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc) 784272cc70bSAndy Fleming { 78593bfd616SPantelis Antoniou if (mmc->cfg->ops->set_ios) 78693bfd616SPantelis Antoniou mmc->cfg->ops->set_ios(mmc); 787272cc70bSAndy Fleming } 788272cc70bSAndy Fleming 789272cc70bSAndy Fleming void mmc_set_clock(struct mmc *mmc, uint clock) 790272cc70bSAndy Fleming { 79193bfd616SPantelis Antoniou if (clock > mmc->cfg->f_max) 79293bfd616SPantelis Antoniou clock = mmc->cfg->f_max; 793272cc70bSAndy Fleming 79493bfd616SPantelis Antoniou if (clock < mmc->cfg->f_min) 79593bfd616SPantelis Antoniou clock = mmc->cfg->f_min; 796272cc70bSAndy Fleming 797272cc70bSAndy Fleming mmc->clock = clock; 798272cc70bSAndy Fleming 799272cc70bSAndy Fleming mmc_set_ios(mmc); 800272cc70bSAndy Fleming } 801272cc70bSAndy Fleming 802fdbb873eSKim Phillips static void mmc_set_bus_width(struct mmc *mmc, uint width) 803272cc70bSAndy Fleming { 804272cc70bSAndy Fleming mmc->bus_width = width; 805272cc70bSAndy Fleming 806272cc70bSAndy Fleming mmc_set_ios(mmc); 807272cc70bSAndy Fleming } 808272cc70bSAndy Fleming 809fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc) 810272cc70bSAndy Fleming { 811f866a46dSStephen Warren int err, i; 812272cc70bSAndy Fleming uint mult, freq; 813639b7827SYoshihiro Shimoda u64 cmult, csize, capacity; 814272cc70bSAndy Fleming struct mmc_cmd cmd; 8158bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 8168bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 8175d4fc8d9SRaffaele Recalcati int timeout = 1000; 818272cc70bSAndy Fleming 819d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON 820d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */ 821d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF; 822d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R1; 823d52ebf10SThomas Chou cmd.cmdarg = 1; 824d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 825d52ebf10SThomas Chou 826d52ebf10SThomas Chou if (err) 827d52ebf10SThomas Chou return err; 828d52ebf10SThomas Chou } 829d52ebf10SThomas Chou #endif 830d52ebf10SThomas Chou 831272cc70bSAndy Fleming /* Put the Card in Identify Mode */ 832d52ebf10SThomas Chou cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID : 833d52ebf10SThomas Chou MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */ 834272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 835272cc70bSAndy Fleming cmd.cmdarg = 0; 836272cc70bSAndy Fleming 837272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 838272cc70bSAndy Fleming 839272cc70bSAndy Fleming if (err) 840272cc70bSAndy Fleming return err; 841272cc70bSAndy Fleming 842272cc70bSAndy Fleming memcpy(mmc->cid, cmd.response, 16); 843272cc70bSAndy Fleming 844272cc70bSAndy Fleming /* 845272cc70bSAndy Fleming * For MMC cards, set the Relative Address. 846272cc70bSAndy Fleming * For SD cards, get the Relatvie Address. 847272cc70bSAndy Fleming * This also puts the cards into Standby State 848272cc70bSAndy Fleming */ 849d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 850272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR; 851272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 852272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R6; 853272cc70bSAndy Fleming 854272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 855272cc70bSAndy Fleming 856272cc70bSAndy Fleming if (err) 857272cc70bSAndy Fleming return err; 858272cc70bSAndy Fleming 859272cc70bSAndy Fleming if (IS_SD(mmc)) 860998be3ddSRabin Vincent mmc->rca = (cmd.response[0] >> 16) & 0xffff; 861d52ebf10SThomas Chou } 862272cc70bSAndy Fleming 863272cc70bSAndy Fleming /* Get the Card-Specific Data */ 864272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_CSD; 865272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 866272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 867272cc70bSAndy Fleming 868272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 869272cc70bSAndy Fleming 8705d4fc8d9SRaffaele Recalcati /* Waiting for the ready status */ 8715d4fc8d9SRaffaele Recalcati mmc_send_status(mmc, timeout); 8725d4fc8d9SRaffaele Recalcati 873272cc70bSAndy Fleming if (err) 874272cc70bSAndy Fleming return err; 875272cc70bSAndy Fleming 876998be3ddSRabin Vincent mmc->csd[0] = cmd.response[0]; 877998be3ddSRabin Vincent mmc->csd[1] = cmd.response[1]; 878998be3ddSRabin Vincent mmc->csd[2] = cmd.response[2]; 879998be3ddSRabin Vincent mmc->csd[3] = cmd.response[3]; 880272cc70bSAndy Fleming 881272cc70bSAndy Fleming if (mmc->version == MMC_VERSION_UNKNOWN) { 8820b453ffeSRabin Vincent int version = (cmd.response[0] >> 26) & 0xf; 883272cc70bSAndy Fleming 884272cc70bSAndy Fleming switch (version) { 885272cc70bSAndy Fleming case 0: 886272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 887272cc70bSAndy Fleming break; 888272cc70bSAndy Fleming case 1: 889272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_4; 890272cc70bSAndy Fleming break; 891272cc70bSAndy Fleming case 2: 892272cc70bSAndy Fleming mmc->version = MMC_VERSION_2_2; 893272cc70bSAndy Fleming break; 894272cc70bSAndy Fleming case 3: 895272cc70bSAndy Fleming mmc->version = MMC_VERSION_3; 896272cc70bSAndy Fleming break; 897272cc70bSAndy Fleming case 4: 898272cc70bSAndy Fleming mmc->version = MMC_VERSION_4; 899272cc70bSAndy Fleming break; 900272cc70bSAndy Fleming default: 901272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 902272cc70bSAndy Fleming break; 903272cc70bSAndy Fleming } 904272cc70bSAndy Fleming } 905272cc70bSAndy Fleming 906272cc70bSAndy Fleming /* divide frequency by 10, since the mults are 10x bigger */ 9070b453ffeSRabin Vincent freq = fbase[(cmd.response[0] & 0x7)]; 9080b453ffeSRabin Vincent mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; 909272cc70bSAndy Fleming 910272cc70bSAndy Fleming mmc->tran_speed = freq * mult; 911272cc70bSAndy Fleming 912ab71188cSMarkus Niebel mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1); 913998be3ddSRabin Vincent mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf); 914272cc70bSAndy Fleming 915272cc70bSAndy Fleming if (IS_SD(mmc)) 916272cc70bSAndy Fleming mmc->write_bl_len = mmc->read_bl_len; 917272cc70bSAndy Fleming else 918998be3ddSRabin Vincent mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf); 919272cc70bSAndy Fleming 920272cc70bSAndy Fleming if (mmc->high_capacity) { 921272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3f) << 16 922272cc70bSAndy Fleming | (mmc->csd[2] & 0xffff0000) >> 16; 923272cc70bSAndy Fleming cmult = 8; 924272cc70bSAndy Fleming } else { 925272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3ff) << 2 926272cc70bSAndy Fleming | (mmc->csd[2] & 0xc0000000) >> 30; 927272cc70bSAndy Fleming cmult = (mmc->csd[2] & 0x00038000) >> 15; 928272cc70bSAndy Fleming } 929272cc70bSAndy Fleming 930f866a46dSStephen Warren mmc->capacity_user = (csize + 1) << (cmult + 2); 931f866a46dSStephen Warren mmc->capacity_user *= mmc->read_bl_len; 932f866a46dSStephen Warren mmc->capacity_boot = 0; 933f866a46dSStephen Warren mmc->capacity_rpmb = 0; 934f866a46dSStephen Warren for (i = 0; i < 4; i++) 935f866a46dSStephen Warren mmc->capacity_gp[i] = 0; 936272cc70bSAndy Fleming 9378bfa195eSSimon Glass if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN) 9388bfa195eSSimon Glass mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 939272cc70bSAndy Fleming 9408bfa195eSSimon Glass if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN) 9418bfa195eSSimon Glass mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 942272cc70bSAndy Fleming 943ab71188cSMarkus Niebel if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) { 944ab71188cSMarkus Niebel cmd.cmdidx = MMC_CMD_SET_DSR; 945ab71188cSMarkus Niebel cmd.cmdarg = (mmc->dsr & 0xffff) << 16; 946ab71188cSMarkus Niebel cmd.resp_type = MMC_RSP_NONE; 947ab71188cSMarkus Niebel if (mmc_send_cmd(mmc, &cmd, NULL)) 948ab71188cSMarkus Niebel printf("MMC: SET_DSR failed\n"); 949ab71188cSMarkus Niebel } 950ab71188cSMarkus Niebel 951272cc70bSAndy Fleming /* Select the card, and put it into Transfer Mode */ 952d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 953272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SELECT_CARD; 954fe8f7066SAjay Bhargav cmd.resp_type = MMC_RSP_R1; 955272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 956272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 957272cc70bSAndy Fleming 958272cc70bSAndy Fleming if (err) 959272cc70bSAndy Fleming return err; 960d52ebf10SThomas Chou } 961272cc70bSAndy Fleming 962e6f99a56SLei Wen /* 963e6f99a56SLei Wen * For SD, its erase group is always one sector 964e6f99a56SLei Wen */ 965e6f99a56SLei Wen mmc->erase_grp_size = 1; 966bc897b1dSLei Wen mmc->part_config = MMCPART_NOAVAILABLE; 967d23e2c09SSukumar Ghorai if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) { 968d23e2c09SSukumar Ghorai /* check ext_csd version and capacity */ 969d23e2c09SSukumar Ghorai err = mmc_send_ext_csd(mmc, ext_csd); 970fdbb873eSKim Phillips if (!err && (ext_csd[EXT_CSD_REV] >= 2)) { 971639b7827SYoshihiro Shimoda /* 972639b7827SYoshihiro Shimoda * According to the JEDEC Standard, the value of 973639b7827SYoshihiro Shimoda * ext_csd's capacity is valid if the value is more 974639b7827SYoshihiro Shimoda * than 2GB 975639b7827SYoshihiro Shimoda */ 9760560db18SLei Wen capacity = ext_csd[EXT_CSD_SEC_CNT] << 0 9770560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 9780560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 9790560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; 9808bfa195eSSimon Glass capacity *= MMC_MAX_BLOCK_LEN; 981b1f1e821SŁukasz Majewski if ((capacity >> 20) > 2 * 1024) 982f866a46dSStephen Warren mmc->capacity_user = capacity; 983d23e2c09SSukumar Ghorai } 984bc897b1dSLei Wen 98564f4a619SJaehoon Chung switch (ext_csd[EXT_CSD_REV]) { 98664f4a619SJaehoon Chung case 1: 98764f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_1; 98864f4a619SJaehoon Chung break; 98964f4a619SJaehoon Chung case 2: 99064f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_2; 99164f4a619SJaehoon Chung break; 99264f4a619SJaehoon Chung case 3: 99364f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_3; 99464f4a619SJaehoon Chung break; 99564f4a619SJaehoon Chung case 5: 99664f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_41; 99764f4a619SJaehoon Chung break; 99864f4a619SJaehoon Chung case 6: 99964f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_5; 100064f4a619SJaehoon Chung break; 100164f4a619SJaehoon Chung } 100264f4a619SJaehoon Chung 1003e6f99a56SLei Wen /* 10041937e5aaSOliver Metz * Host needs to enable ERASE_GRP_DEF bit if device is 10051937e5aaSOliver Metz * partitioned. This bit will be lost every time after a reset 10061937e5aaSOliver Metz * or power off. This will affect erase size. 1007e6f99a56SLei Wen */ 10081937e5aaSOliver Metz if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) && 10091937e5aaSOliver Metz (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) { 10101937e5aaSOliver Metz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 10111937e5aaSOliver Metz EXT_CSD_ERASE_GROUP_DEF, 1); 10121937e5aaSOliver Metz 10131937e5aaSOliver Metz if (err) 10141937e5aaSOliver Metz return err; 10151937e5aaSOliver Metz 10161937e5aaSOliver Metz /* Read out group size from ext_csd */ 10170560db18SLei Wen mmc->erase_grp_size = 10188bfa195eSSimon Glass ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 10198bfa195eSSimon Glass MMC_MAX_BLOCK_LEN * 1024; 10208bfa195eSSimon Glass } else { 10211937e5aaSOliver Metz /* Calculate the group size from the csd value. */ 1022e6f99a56SLei Wen int erase_gsz, erase_gmul; 1023e6f99a56SLei Wen erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10; 1024e6f99a56SLei Wen erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5; 1025e6f99a56SLei Wen mmc->erase_grp_size = (erase_gsz + 1) 1026e6f99a56SLei Wen * (erase_gmul + 1); 1027e6f99a56SLei Wen } 1028e6f99a56SLei Wen 1029bc897b1dSLei Wen /* store the partition info of emmc */ 10308948ea83SStephen Warren if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || 10318948ea83SStephen Warren ext_csd[EXT_CSD_BOOT_MULT]) 10320560db18SLei Wen mmc->part_config = ext_csd[EXT_CSD_PART_CONF]; 1033f866a46dSStephen Warren 1034f866a46dSStephen Warren mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17; 1035f866a46dSStephen Warren 1036f866a46dSStephen Warren mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17; 1037f866a46dSStephen Warren 1038f866a46dSStephen Warren for (i = 0; i < 4; i++) { 1039f866a46dSStephen Warren int idx = EXT_CSD_GP_SIZE_MULT + i * 3; 1040f866a46dSStephen Warren mmc->capacity_gp[i] = (ext_csd[idx + 2] << 16) + 1041f866a46dSStephen Warren (ext_csd[idx + 1] << 8) + ext_csd[idx]; 1042f866a46dSStephen Warren mmc->capacity_gp[i] *= 1043f866a46dSStephen Warren ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 1044f866a46dSStephen Warren mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1045d23e2c09SSukumar Ghorai } 1046f866a46dSStephen Warren } 1047f866a46dSStephen Warren 1048f866a46dSStephen Warren err = mmc_set_capacity(mmc, mmc->part_num); 1049f866a46dSStephen Warren if (err) 1050f866a46dSStephen Warren return err; 1051d23e2c09SSukumar Ghorai 1052272cc70bSAndy Fleming if (IS_SD(mmc)) 1053272cc70bSAndy Fleming err = sd_change_freq(mmc); 1054272cc70bSAndy Fleming else 1055272cc70bSAndy Fleming err = mmc_change_freq(mmc); 1056272cc70bSAndy Fleming 1057272cc70bSAndy Fleming if (err) 1058272cc70bSAndy Fleming return err; 1059272cc70bSAndy Fleming 1060272cc70bSAndy Fleming /* Restrict card's capabilities by what the host can do */ 106193bfd616SPantelis Antoniou mmc->card_caps &= mmc->cfg->host_caps; 1062272cc70bSAndy Fleming 1063272cc70bSAndy Fleming if (IS_SD(mmc)) { 1064272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_4BIT) { 1065272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 1066272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1067272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1068272cc70bSAndy Fleming 1069272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1070272cc70bSAndy Fleming if (err) 1071272cc70bSAndy Fleming return err; 1072272cc70bSAndy Fleming 1073272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH; 1074272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1075272cc70bSAndy Fleming cmd.cmdarg = 2; 1076272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1077272cc70bSAndy Fleming if (err) 1078272cc70bSAndy Fleming return err; 1079272cc70bSAndy Fleming 1080272cc70bSAndy Fleming mmc_set_bus_width(mmc, 4); 1081272cc70bSAndy Fleming } 1082272cc70bSAndy Fleming 1083272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_HS) 1084ad5fd922SJaehoon Chung mmc->tran_speed = 50000000; 1085272cc70bSAndy Fleming else 1086ad5fd922SJaehoon Chung mmc->tran_speed = 25000000; 1087272cc70bSAndy Fleming } else { 10887798f6dbSAndy Fleming int idx; 10897798f6dbSAndy Fleming 10907798f6dbSAndy Fleming /* An array of possible bus widths in order of preference */ 10917798f6dbSAndy Fleming static unsigned ext_csd_bits[] = { 1092d22e3d46SJaehoon Chung EXT_CSD_DDR_BUS_WIDTH_8, 1093d22e3d46SJaehoon Chung EXT_CSD_DDR_BUS_WIDTH_4, 10947798f6dbSAndy Fleming EXT_CSD_BUS_WIDTH_8, 10957798f6dbSAndy Fleming EXT_CSD_BUS_WIDTH_4, 10967798f6dbSAndy Fleming EXT_CSD_BUS_WIDTH_1, 10977798f6dbSAndy Fleming }; 10987798f6dbSAndy Fleming 10997798f6dbSAndy Fleming /* An array to map CSD bus widths to host cap bits */ 11007798f6dbSAndy Fleming static unsigned ext_to_hostcaps[] = { 1101d22e3d46SJaehoon Chung [EXT_CSD_DDR_BUS_WIDTH_4] = MMC_MODE_DDR_52MHz, 1102d22e3d46SJaehoon Chung [EXT_CSD_DDR_BUS_WIDTH_8] = MMC_MODE_DDR_52MHz, 11037798f6dbSAndy Fleming [EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT, 11047798f6dbSAndy Fleming [EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT, 11057798f6dbSAndy Fleming }; 11067798f6dbSAndy Fleming 11077798f6dbSAndy Fleming /* An array to map chosen bus width to an integer */ 11087798f6dbSAndy Fleming static unsigned widths[] = { 1109d22e3d46SJaehoon Chung 8, 4, 8, 4, 1, 11107798f6dbSAndy Fleming }; 11117798f6dbSAndy Fleming 11127798f6dbSAndy Fleming for (idx=0; idx < ARRAY_SIZE(ext_csd_bits); idx++) { 11137798f6dbSAndy Fleming unsigned int extw = ext_csd_bits[idx]; 11147798f6dbSAndy Fleming 11157798f6dbSAndy Fleming /* 11167798f6dbSAndy Fleming * Check to make sure the controller supports 11177798f6dbSAndy Fleming * this bus width, if it's more than 1 11187798f6dbSAndy Fleming */ 11197798f6dbSAndy Fleming if (extw != EXT_CSD_BUS_WIDTH_1 && 112093bfd616SPantelis Antoniou !(mmc->cfg->host_caps & ext_to_hostcaps[extw])) 11217798f6dbSAndy Fleming continue; 11227798f6dbSAndy Fleming 1123272cc70bSAndy Fleming err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 11247798f6dbSAndy Fleming EXT_CSD_BUS_WIDTH, extw); 1125272cc70bSAndy Fleming 1126272cc70bSAndy Fleming if (err) 11274137894eSLei Wen continue; 1128272cc70bSAndy Fleming 11297798f6dbSAndy Fleming mmc_set_bus_width(mmc, widths[idx]); 1130272cc70bSAndy Fleming 11314137894eSLei Wen err = mmc_send_ext_csd(mmc, test_csd); 11324137894eSLei Wen if (!err && ext_csd[EXT_CSD_PARTITIONING_SUPPORT] \ 11334137894eSLei Wen == test_csd[EXT_CSD_PARTITIONING_SUPPORT] 11344137894eSLei Wen && ext_csd[EXT_CSD_ERASE_GROUP_DEF] \ 11354137894eSLei Wen == test_csd[EXT_CSD_ERASE_GROUP_DEF] \ 11364137894eSLei Wen && ext_csd[EXT_CSD_REV] \ 11374137894eSLei Wen == test_csd[EXT_CSD_REV] 11384137894eSLei Wen && ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] \ 11394137894eSLei Wen == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 11404137894eSLei Wen && memcmp(&ext_csd[EXT_CSD_SEC_CNT], \ 11414137894eSLei Wen &test_csd[EXT_CSD_SEC_CNT], 4) == 0) { 1142272cc70bSAndy Fleming 11437798f6dbSAndy Fleming mmc->card_caps |= ext_to_hostcaps[extw]; 11444137894eSLei Wen break; 11454137894eSLei Wen } 1146272cc70bSAndy Fleming } 1147272cc70bSAndy Fleming 1148272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_HS) { 1149272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_HS_52MHz) 1150ad5fd922SJaehoon Chung mmc->tran_speed = 52000000; 1151272cc70bSAndy Fleming else 1152ad5fd922SJaehoon Chung mmc->tran_speed = 26000000; 1153272cc70bSAndy Fleming } 1154ad5fd922SJaehoon Chung } 1155ad5fd922SJaehoon Chung 1156ad5fd922SJaehoon Chung mmc_set_clock(mmc, mmc->tran_speed); 1157272cc70bSAndy Fleming 1158272cc70bSAndy Fleming /* fill in device description */ 1159272cc70bSAndy Fleming mmc->block_dev.lun = 0; 1160272cc70bSAndy Fleming mmc->block_dev.type = 0; 1161272cc70bSAndy Fleming mmc->block_dev.blksz = mmc->read_bl_len; 11620472fbfdSEgbert Eich mmc->block_dev.log2blksz = LOG2(mmc->block_dev.blksz); 11639b1f942cSRabin Vincent mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len); 116456196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 1165babce5f6STaylor Hutt sprintf(mmc->block_dev.vendor, "Man %06x Snr %04x%04x", 1166babce5f6STaylor Hutt mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff), 1167babce5f6STaylor Hutt (mmc->cid[3] >> 16) & 0xffff); 1168babce5f6STaylor Hutt sprintf(mmc->block_dev.product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff, 11690b453ffeSRabin Vincent (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, 1170babce5f6STaylor Hutt (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff, 1171babce5f6STaylor Hutt (mmc->cid[2] >> 24) & 0xff); 1172babce5f6STaylor Hutt sprintf(mmc->block_dev.revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf, 1173babce5f6STaylor Hutt (mmc->cid[2] >> 16) & 0xf); 117456196826SPaul Burton #else 117556196826SPaul Burton mmc->block_dev.vendor[0] = 0; 117656196826SPaul Burton mmc->block_dev.product[0] = 0; 117756196826SPaul Burton mmc->block_dev.revision[0] = 0; 117856196826SPaul Burton #endif 1179122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT) 1180272cc70bSAndy Fleming init_part(&mmc->block_dev); 1181122efd43SMikhail Kshevetskiy #endif 1182272cc70bSAndy Fleming 1183272cc70bSAndy Fleming return 0; 1184272cc70bSAndy Fleming } 1185272cc70bSAndy Fleming 1186fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc) 1187272cc70bSAndy Fleming { 1188272cc70bSAndy Fleming struct mmc_cmd cmd; 1189272cc70bSAndy Fleming int err; 1190272cc70bSAndy Fleming 1191272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_IF_COND; 1192272cc70bSAndy Fleming /* We set the bit if the host supports voltages between 2.7 and 3.6 V */ 119393bfd616SPantelis Antoniou cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa; 1194272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R7; 1195272cc70bSAndy Fleming 1196272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1197272cc70bSAndy Fleming 1198272cc70bSAndy Fleming if (err) 1199272cc70bSAndy Fleming return err; 1200272cc70bSAndy Fleming 1201998be3ddSRabin Vincent if ((cmd.response[0] & 0xff) != 0xaa) 1202272cc70bSAndy Fleming return UNUSABLE_ERR; 1203272cc70bSAndy Fleming else 1204272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 1205272cc70bSAndy Fleming 1206272cc70bSAndy Fleming return 0; 1207272cc70bSAndy Fleming } 1208272cc70bSAndy Fleming 120993bfd616SPantelis Antoniou /* not used any more */ 121093bfd616SPantelis Antoniou int __deprecated mmc_register(struct mmc *mmc) 1211272cc70bSAndy Fleming { 121293bfd616SPantelis Antoniou #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 121393bfd616SPantelis Antoniou printf("%s is deprecated! use mmc_create() instead.\n", __func__); 121493bfd616SPantelis Antoniou #endif 121593bfd616SPantelis Antoniou return -1; 121693bfd616SPantelis Antoniou } 121793bfd616SPantelis Antoniou 121893bfd616SPantelis Antoniou struct mmc *mmc_create(const struct mmc_config *cfg, void *priv) 121993bfd616SPantelis Antoniou { 122093bfd616SPantelis Antoniou struct mmc *mmc; 122193bfd616SPantelis Antoniou 122293bfd616SPantelis Antoniou /* quick validation */ 122393bfd616SPantelis Antoniou if (cfg == NULL || cfg->ops == NULL || cfg->ops->send_cmd == NULL || 122493bfd616SPantelis Antoniou cfg->f_min == 0 || cfg->f_max == 0 || cfg->b_max == 0) 122593bfd616SPantelis Antoniou return NULL; 122693bfd616SPantelis Antoniou 122793bfd616SPantelis Antoniou mmc = calloc(1, sizeof(*mmc)); 122893bfd616SPantelis Antoniou if (mmc == NULL) 122993bfd616SPantelis Antoniou return NULL; 123093bfd616SPantelis Antoniou 123193bfd616SPantelis Antoniou mmc->cfg = cfg; 123293bfd616SPantelis Antoniou mmc->priv = priv; 123393bfd616SPantelis Antoniou 123493bfd616SPantelis Antoniou /* the following chunk was mmc_register() */ 123593bfd616SPantelis Antoniou 1236ab71188cSMarkus Niebel /* Setup dsr related values */ 1237ab71188cSMarkus Niebel mmc->dsr_imp = 0; 1238ab71188cSMarkus Niebel mmc->dsr = 0xffffffff; 1239272cc70bSAndy Fleming /* Setup the universal parts of the block interface just once */ 1240272cc70bSAndy Fleming mmc->block_dev.if_type = IF_TYPE_MMC; 1241272cc70bSAndy Fleming mmc->block_dev.dev = cur_dev_num++; 1242272cc70bSAndy Fleming mmc->block_dev.removable = 1; 1243272cc70bSAndy Fleming mmc->block_dev.block_read = mmc_bread; 1244272cc70bSAndy Fleming mmc->block_dev.block_write = mmc_bwrite; 1245e6f99a56SLei Wen mmc->block_dev.block_erase = mmc_berase; 124693bfd616SPantelis Antoniou 124793bfd616SPantelis Antoniou /* setup initial part type */ 124893bfd616SPantelis Antoniou mmc->block_dev.part_type = mmc->cfg->part_type; 1249272cc70bSAndy Fleming 1250272cc70bSAndy Fleming INIT_LIST_HEAD(&mmc->link); 1251272cc70bSAndy Fleming 1252272cc70bSAndy Fleming list_add_tail(&mmc->link, &mmc_devices); 1253272cc70bSAndy Fleming 125493bfd616SPantelis Antoniou return mmc; 125593bfd616SPantelis Antoniou } 125693bfd616SPantelis Antoniou 125793bfd616SPantelis Antoniou void mmc_destroy(struct mmc *mmc) 125893bfd616SPantelis Antoniou { 125993bfd616SPantelis Antoniou /* only freeing memory for now */ 126093bfd616SPantelis Antoniou free(mmc); 1261272cc70bSAndy Fleming } 1262272cc70bSAndy Fleming 1263df3fc526SMatthew McClintock #ifdef CONFIG_PARTITIONS 1264272cc70bSAndy Fleming block_dev_desc_t *mmc_get_dev(int dev) 1265272cc70bSAndy Fleming { 1266272cc70bSAndy Fleming struct mmc *mmc = find_mmc_device(dev); 12676bb4b4bcSBenoît Thébaudeau if (!mmc || mmc_init(mmc)) 126840242bc3SŁukasz Majewski return NULL; 1269272cc70bSAndy Fleming 127040242bc3SŁukasz Majewski return &mmc->block_dev; 1271272cc70bSAndy Fleming } 1272df3fc526SMatthew McClintock #endif 1273272cc70bSAndy Fleming 1274e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc) 1275272cc70bSAndy Fleming { 1276afd5932bSMacpaul Lin int err; 1277272cc70bSAndy Fleming 1278ab769f22SPantelis Antoniou /* we pretend there's no card when init is NULL */ 127993bfd616SPantelis Antoniou if (mmc_getcd(mmc) == 0 || mmc->cfg->ops->init == NULL) { 128048972d90SThierry Reding mmc->has_init = 0; 128156196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 128248972d90SThierry Reding printf("MMC: no card present\n"); 128356196826SPaul Burton #endif 128448972d90SThierry Reding return NO_CARD_ERR; 128548972d90SThierry Reding } 128648972d90SThierry Reding 1287bc897b1dSLei Wen if (mmc->has_init) 1288bc897b1dSLei Wen return 0; 1289bc897b1dSLei Wen 1290ab769f22SPantelis Antoniou /* made sure it's not NULL earlier */ 129193bfd616SPantelis Antoniou err = mmc->cfg->ops->init(mmc); 1292272cc70bSAndy Fleming 1293272cc70bSAndy Fleming if (err) 1294272cc70bSAndy Fleming return err; 1295272cc70bSAndy Fleming 1296b86b85e2SIlya Yanok mmc_set_bus_width(mmc, 1); 1297b86b85e2SIlya Yanok mmc_set_clock(mmc, 1); 1298b86b85e2SIlya Yanok 1299272cc70bSAndy Fleming /* Reset the Card */ 1300272cc70bSAndy Fleming err = mmc_go_idle(mmc); 1301272cc70bSAndy Fleming 1302272cc70bSAndy Fleming if (err) 1303272cc70bSAndy Fleming return err; 1304272cc70bSAndy Fleming 1305bc897b1dSLei Wen /* The internal partition reset to user partition(0) at every CMD0*/ 1306bc897b1dSLei Wen mmc->part_num = 0; 1307bc897b1dSLei Wen 1308272cc70bSAndy Fleming /* Test for SD version 2 */ 1309272cc70bSAndy Fleming err = mmc_send_if_cond(mmc); 1310272cc70bSAndy Fleming 1311272cc70bSAndy Fleming /* Now try to get the SD card's operating condition */ 1312272cc70bSAndy Fleming err = sd_send_op_cond(mmc); 1313272cc70bSAndy Fleming 1314272cc70bSAndy Fleming /* If the command timed out, we check for an MMC card */ 1315272cc70bSAndy Fleming if (err == TIMEOUT) { 1316272cc70bSAndy Fleming err = mmc_send_op_cond(mmc); 1317272cc70bSAndy Fleming 1318e9550449SChe-Liang Chiou if (err && err != IN_PROGRESS) { 131956196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 1320272cc70bSAndy Fleming printf("Card did not respond to voltage select!\n"); 132156196826SPaul Burton #endif 1322272cc70bSAndy Fleming return UNUSABLE_ERR; 1323272cc70bSAndy Fleming } 1324272cc70bSAndy Fleming } 1325272cc70bSAndy Fleming 1326e9550449SChe-Liang Chiou if (err == IN_PROGRESS) 1327e9550449SChe-Liang Chiou mmc->init_in_progress = 1; 1328e9550449SChe-Liang Chiou 1329e9550449SChe-Liang Chiou return err; 1330e9550449SChe-Liang Chiou } 1331e9550449SChe-Liang Chiou 1332e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc) 1333e9550449SChe-Liang Chiou { 1334e9550449SChe-Liang Chiou int err = 0; 1335e9550449SChe-Liang Chiou 1336e9550449SChe-Liang Chiou if (mmc->op_cond_pending) 1337e9550449SChe-Liang Chiou err = mmc_complete_op_cond(mmc); 1338e9550449SChe-Liang Chiou 1339e9550449SChe-Liang Chiou if (!err) 1340bc897b1dSLei Wen err = mmc_startup(mmc); 1341bc897b1dSLei Wen if (err) 1342bc897b1dSLei Wen mmc->has_init = 0; 1343bc897b1dSLei Wen else 1344bc897b1dSLei Wen mmc->has_init = 1; 1345e9550449SChe-Liang Chiou mmc->init_in_progress = 0; 1346e9550449SChe-Liang Chiou return err; 1347e9550449SChe-Liang Chiou } 1348e9550449SChe-Liang Chiou 1349e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc) 1350e9550449SChe-Liang Chiou { 1351e9550449SChe-Liang Chiou int err = IN_PROGRESS; 1352d803fea5SMateusz Zalega unsigned start; 1353e9550449SChe-Liang Chiou 1354e9550449SChe-Liang Chiou if (mmc->has_init) 1355e9550449SChe-Liang Chiou return 0; 1356d803fea5SMateusz Zalega 1357d803fea5SMateusz Zalega start = get_timer(0); 1358d803fea5SMateusz Zalega 1359e9550449SChe-Liang Chiou if (!mmc->init_in_progress) 1360e9550449SChe-Liang Chiou err = mmc_start_init(mmc); 1361e9550449SChe-Liang Chiou 1362e9550449SChe-Liang Chiou if (!err || err == IN_PROGRESS) 1363e9550449SChe-Liang Chiou err = mmc_complete_init(mmc); 1364e9550449SChe-Liang Chiou debug("%s: %d, time %lu\n", __func__, err, get_timer(start)); 1365bc897b1dSLei Wen return err; 1366272cc70bSAndy Fleming } 1367272cc70bSAndy Fleming 1368ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val) 1369ab71188cSMarkus Niebel { 1370ab71188cSMarkus Niebel mmc->dsr = val; 1371ab71188cSMarkus Niebel return 0; 1372ab71188cSMarkus Niebel } 1373ab71188cSMarkus Niebel 1374272cc70bSAndy Fleming /* 1375272cc70bSAndy Fleming * CPU and board-specific MMC initializations. Aliased function 1376272cc70bSAndy Fleming * signals caller to move on 1377272cc70bSAndy Fleming */ 1378272cc70bSAndy Fleming static int __def_mmc_init(bd_t *bis) 1379272cc70bSAndy Fleming { 1380272cc70bSAndy Fleming return -1; 1381272cc70bSAndy Fleming } 1382272cc70bSAndy Fleming 1383f9a109b3SPeter Tyser int cpu_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init"))); 1384f9a109b3SPeter Tyser int board_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init"))); 1385272cc70bSAndy Fleming 138656196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 138756196826SPaul Burton 1388272cc70bSAndy Fleming void print_mmc_devices(char separator) 1389272cc70bSAndy Fleming { 1390272cc70bSAndy Fleming struct mmc *m; 1391272cc70bSAndy Fleming struct list_head *entry; 1392272cc70bSAndy Fleming 1393272cc70bSAndy Fleming list_for_each(entry, &mmc_devices) { 1394272cc70bSAndy Fleming m = list_entry(entry, struct mmc, link); 1395272cc70bSAndy Fleming 139693bfd616SPantelis Antoniou printf("%s: %d", m->cfg->name, m->block_dev.dev); 1397272cc70bSAndy Fleming 1398272cc70bSAndy Fleming if (entry->next != &mmc_devices) 1399272cc70bSAndy Fleming printf("%c ", separator); 1400272cc70bSAndy Fleming } 1401272cc70bSAndy Fleming 1402272cc70bSAndy Fleming printf("\n"); 1403272cc70bSAndy Fleming } 1404272cc70bSAndy Fleming 140556196826SPaul Burton #else 140656196826SPaul Burton void print_mmc_devices(char separator) { } 140756196826SPaul Burton #endif 140856196826SPaul Burton 1409ea6ebe21SLei Wen int get_mmc_num(void) 1410ea6ebe21SLei Wen { 1411ea6ebe21SLei Wen return cur_dev_num; 1412ea6ebe21SLei Wen } 1413ea6ebe21SLei Wen 1414e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit) 1415e9550449SChe-Liang Chiou { 1416e9550449SChe-Liang Chiou mmc->preinit = preinit; 1417e9550449SChe-Liang Chiou } 1418e9550449SChe-Liang Chiou 1419e9550449SChe-Liang Chiou static void do_preinit(void) 1420e9550449SChe-Liang Chiou { 1421e9550449SChe-Liang Chiou struct mmc *m; 1422e9550449SChe-Liang Chiou struct list_head *entry; 1423e9550449SChe-Liang Chiou 1424e9550449SChe-Liang Chiou list_for_each(entry, &mmc_devices) { 1425e9550449SChe-Liang Chiou m = list_entry(entry, struct mmc, link); 1426e9550449SChe-Liang Chiou 1427e9550449SChe-Liang Chiou if (m->preinit) 1428e9550449SChe-Liang Chiou mmc_start_init(m); 1429e9550449SChe-Liang Chiou } 1430e9550449SChe-Liang Chiou } 1431e9550449SChe-Liang Chiou 1432e9550449SChe-Liang Chiou 1433272cc70bSAndy Fleming int mmc_initialize(bd_t *bis) 1434272cc70bSAndy Fleming { 1435272cc70bSAndy Fleming INIT_LIST_HEAD (&mmc_devices); 1436272cc70bSAndy Fleming cur_dev_num = 0; 1437272cc70bSAndy Fleming 1438272cc70bSAndy Fleming if (board_mmc_init(bis) < 0) 1439272cc70bSAndy Fleming cpu_mmc_init(bis); 1440272cc70bSAndy Fleming 1441bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD 1442272cc70bSAndy Fleming print_mmc_devices(','); 1443bb0dc108SYing Zhang #endif 1444272cc70bSAndy Fleming 1445e9550449SChe-Liang Chiou do_preinit(); 1446272cc70bSAndy Fleming return 0; 1447272cc70bSAndy Fleming } 14483690d6d6SAmar 14493690d6d6SAmar #ifdef CONFIG_SUPPORT_EMMC_BOOT 14503690d6d6SAmar /* 14513690d6d6SAmar * This function changes the size of boot partition and the size of rpmb 14523690d6d6SAmar * partition present on EMMC devices. 14533690d6d6SAmar * 14543690d6d6SAmar * Input Parameters: 14553690d6d6SAmar * struct *mmc: pointer for the mmc device strcuture 14563690d6d6SAmar * bootsize: size of boot partition 14573690d6d6SAmar * rpmbsize: size of rpmb partition 14583690d6d6SAmar * 14593690d6d6SAmar * Returns 0 on success. 14603690d6d6SAmar */ 14613690d6d6SAmar 14623690d6d6SAmar int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize, 14633690d6d6SAmar unsigned long rpmbsize) 14643690d6d6SAmar { 14653690d6d6SAmar int err; 14663690d6d6SAmar struct mmc_cmd cmd; 14673690d6d6SAmar 14683690d6d6SAmar /* Only use this command for raw EMMC moviNAND. Enter backdoor mode */ 14693690d6d6SAmar cmd.cmdidx = MMC_CMD_RES_MAN; 14703690d6d6SAmar cmd.resp_type = MMC_RSP_R1b; 14713690d6d6SAmar cmd.cmdarg = MMC_CMD62_ARG1; 14723690d6d6SAmar 14733690d6d6SAmar err = mmc_send_cmd(mmc, &cmd, NULL); 14743690d6d6SAmar if (err) { 14753690d6d6SAmar debug("mmc_boot_partition_size_change: Error1 = %d\n", err); 14763690d6d6SAmar return err; 14773690d6d6SAmar } 14783690d6d6SAmar 14793690d6d6SAmar /* Boot partition changing mode */ 14803690d6d6SAmar cmd.cmdidx = MMC_CMD_RES_MAN; 14813690d6d6SAmar cmd.resp_type = MMC_RSP_R1b; 14823690d6d6SAmar cmd.cmdarg = MMC_CMD62_ARG2; 14833690d6d6SAmar 14843690d6d6SAmar err = mmc_send_cmd(mmc, &cmd, NULL); 14853690d6d6SAmar if (err) { 14863690d6d6SAmar debug("mmc_boot_partition_size_change: Error2 = %d\n", err); 14873690d6d6SAmar return err; 14883690d6d6SAmar } 14893690d6d6SAmar /* boot partition size is multiple of 128KB */ 14903690d6d6SAmar bootsize = (bootsize * 1024) / 128; 14913690d6d6SAmar 14923690d6d6SAmar /* Arg: boot partition size */ 14933690d6d6SAmar cmd.cmdidx = MMC_CMD_RES_MAN; 14943690d6d6SAmar cmd.resp_type = MMC_RSP_R1b; 14953690d6d6SAmar cmd.cmdarg = bootsize; 14963690d6d6SAmar 14973690d6d6SAmar err = mmc_send_cmd(mmc, &cmd, NULL); 14983690d6d6SAmar if (err) { 14993690d6d6SAmar debug("mmc_boot_partition_size_change: Error3 = %d\n", err); 15003690d6d6SAmar return err; 15013690d6d6SAmar } 15023690d6d6SAmar /* RPMB partition size is multiple of 128KB */ 15033690d6d6SAmar rpmbsize = (rpmbsize * 1024) / 128; 15043690d6d6SAmar /* Arg: RPMB partition size */ 15053690d6d6SAmar cmd.cmdidx = MMC_CMD_RES_MAN; 15063690d6d6SAmar cmd.resp_type = MMC_RSP_R1b; 15073690d6d6SAmar cmd.cmdarg = rpmbsize; 15083690d6d6SAmar 15093690d6d6SAmar err = mmc_send_cmd(mmc, &cmd, NULL); 15103690d6d6SAmar if (err) { 15113690d6d6SAmar debug("mmc_boot_partition_size_change: Error4 = %d\n", err); 15123690d6d6SAmar return err; 15133690d6d6SAmar } 15143690d6d6SAmar return 0; 15153690d6d6SAmar } 15163690d6d6SAmar 15173690d6d6SAmar /* 15185a99b9deSTom Rini * Modify EXT_CSD[177] which is BOOT_BUS_WIDTH 15195a99b9deSTom Rini * based on the passed in values for BOOT_BUS_WIDTH, RESET_BOOT_BUS_WIDTH 15205a99b9deSTom Rini * and BOOT_MODE. 15215a99b9deSTom Rini * 15225a99b9deSTom Rini * Returns 0 on success. 15235a99b9deSTom Rini */ 15245a99b9deSTom Rini int mmc_set_boot_bus_width(struct mmc *mmc, u8 width, u8 reset, u8 mode) 15255a99b9deSTom Rini { 15265a99b9deSTom Rini int err; 15275a99b9deSTom Rini 15285a99b9deSTom Rini err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_BUS_WIDTH, 15295a99b9deSTom Rini EXT_CSD_BOOT_BUS_WIDTH_MODE(mode) | 15305a99b9deSTom Rini EXT_CSD_BOOT_BUS_WIDTH_RESET(reset) | 15315a99b9deSTom Rini EXT_CSD_BOOT_BUS_WIDTH_WIDTH(width)); 15325a99b9deSTom Rini 15335a99b9deSTom Rini if (err) 15345a99b9deSTom Rini return err; 15355a99b9deSTom Rini return 0; 15365a99b9deSTom Rini } 15375a99b9deSTom Rini 15385a99b9deSTom Rini /* 1539792970b0STom Rini * Modify EXT_CSD[179] which is PARTITION_CONFIG (formerly BOOT_CONFIG) 1540792970b0STom Rini * based on the passed in values for BOOT_ACK, BOOT_PARTITION_ENABLE and 1541792970b0STom Rini * PARTITION_ACCESS. 1542792970b0STom Rini * 1543792970b0STom Rini * Returns 0 on success. 1544792970b0STom Rini */ 1545792970b0STom Rini int mmc_set_part_conf(struct mmc *mmc, u8 ack, u8 part_num, u8 access) 1546792970b0STom Rini { 1547792970b0STom Rini int err; 1548792970b0STom Rini 1549792970b0STom Rini err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, 1550792970b0STom Rini EXT_CSD_BOOT_ACK(ack) | 1551792970b0STom Rini EXT_CSD_BOOT_PART_NUM(part_num) | 1552792970b0STom Rini EXT_CSD_PARTITION_ACCESS(access)); 1553792970b0STom Rini 1554792970b0STom Rini if (err) 1555792970b0STom Rini return err; 1556792970b0STom Rini return 0; 1557792970b0STom Rini } 155833ace362STom Rini 155933ace362STom Rini /* 156033ace362STom Rini * Modify EXT_CSD[162] which is RST_n_FUNCTION based on the given value 156133ace362STom Rini * for enable. Note that this is a write-once field for non-zero values. 156233ace362STom Rini * 156333ace362STom Rini * Returns 0 on success. 156433ace362STom Rini */ 156533ace362STom Rini int mmc_set_rst_n_function(struct mmc *mmc, u8 enable) 156633ace362STom Rini { 156733ace362STom Rini return mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_RST_N_FUNCTION, 156833ace362STom Rini enable); 156933ace362STom Rini } 15703690d6d6SAmar #endif 1571