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> 13d4622df3SStephen 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 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); 615db2fe3aSRaffaele Recalcati switch (cmd->resp_type) { 625db2fe3aSRaffaele Recalcati case MMC_RSP_NONE: 635db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_NONE\n"); 645db2fe3aSRaffaele Recalcati break; 655db2fe3aSRaffaele Recalcati case MMC_RSP_R1: 665db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n", 675db2fe3aSRaffaele Recalcati cmd->response[0]); 685db2fe3aSRaffaele Recalcati break; 695db2fe3aSRaffaele Recalcati case MMC_RSP_R1b: 705db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n", 715db2fe3aSRaffaele Recalcati cmd->response[0]); 725db2fe3aSRaffaele Recalcati break; 735db2fe3aSRaffaele Recalcati case MMC_RSP_R2: 745db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R2\t\t 0x%08X \n", 755db2fe3aSRaffaele Recalcati cmd->response[0]); 765db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 775db2fe3aSRaffaele Recalcati cmd->response[1]); 785db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 795db2fe3aSRaffaele Recalcati cmd->response[2]); 805db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 815db2fe3aSRaffaele Recalcati cmd->response[3]); 825db2fe3aSRaffaele Recalcati printf("\n"); 835db2fe3aSRaffaele Recalcati printf("\t\t\t\t\tDUMPING DATA\n"); 845db2fe3aSRaffaele Recalcati for (i = 0; i < 4; i++) { 855db2fe3aSRaffaele Recalcati int j; 865db2fe3aSRaffaele Recalcati printf("\t\t\t\t\t%03d - ", i*4); 87146bec79SDirk Behme ptr = (u8 *)&cmd->response[i]; 885db2fe3aSRaffaele Recalcati ptr += 3; 895db2fe3aSRaffaele Recalcati for (j = 0; j < 4; j++) 905db2fe3aSRaffaele Recalcati printf("%02X ", *ptr--); 915db2fe3aSRaffaele Recalcati printf("\n"); 925db2fe3aSRaffaele Recalcati } 935db2fe3aSRaffaele Recalcati break; 945db2fe3aSRaffaele Recalcati case MMC_RSP_R3: 955db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n", 965db2fe3aSRaffaele Recalcati cmd->response[0]); 975db2fe3aSRaffaele Recalcati break; 985db2fe3aSRaffaele Recalcati default: 995db2fe3aSRaffaele Recalcati printf("\t\tERROR MMC rsp not supported\n"); 1005db2fe3aSRaffaele Recalcati break; 1015db2fe3aSRaffaele Recalcati } 1025db2fe3aSRaffaele Recalcati #else 10393bfd616SPantelis Antoniou ret = mmc->cfg->ops->send_cmd(mmc, cmd, data); 1045db2fe3aSRaffaele Recalcati #endif 1058635ff9eSMarek Vasut return ret; 106272cc70bSAndy Fleming } 107272cc70bSAndy Fleming 108da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout) 1095d4fc8d9SRaffaele Recalcati { 1105d4fc8d9SRaffaele Recalcati struct mmc_cmd cmd; 111d617c426SJan Kloetzke int err, retries = 5; 1125d4fc8d9SRaffaele Recalcati #ifdef CONFIG_MMC_TRACE 1135d4fc8d9SRaffaele Recalcati int status; 1145d4fc8d9SRaffaele Recalcati #endif 1155d4fc8d9SRaffaele Recalcati 1165d4fc8d9SRaffaele Recalcati cmd.cmdidx = MMC_CMD_SEND_STATUS; 1175d4fc8d9SRaffaele Recalcati cmd.resp_type = MMC_RSP_R1; 118aaf3d41aSMarek Vasut if (!mmc_host_is_spi(mmc)) 119aaf3d41aSMarek Vasut cmd.cmdarg = mmc->rca << 16; 1205d4fc8d9SRaffaele Recalcati 1211677eef4SAndrew Gabbasov while (1) { 1225d4fc8d9SRaffaele Recalcati err = mmc_send_cmd(mmc, &cmd, NULL); 123d617c426SJan Kloetzke if (!err) { 124d617c426SJan Kloetzke if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) && 125d617c426SJan Kloetzke (cmd.response[0] & MMC_STATUS_CURR_STATE) != 126d617c426SJan Kloetzke MMC_STATE_PRG) 1275d4fc8d9SRaffaele Recalcati break; 128d617c426SJan Kloetzke else if (cmd.response[0] & MMC_STATUS_MASK) { 12956196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 130d617c426SJan Kloetzke printf("Status Error: 0x%08X\n", 131d617c426SJan Kloetzke cmd.response[0]); 13256196826SPaul Burton #endif 133d617c426SJan Kloetzke return COMM_ERR; 134d617c426SJan Kloetzke } 135d617c426SJan Kloetzke } else if (--retries < 0) 136d617c426SJan Kloetzke return err; 1375d4fc8d9SRaffaele Recalcati 1381677eef4SAndrew Gabbasov if (timeout-- <= 0) 1391677eef4SAndrew Gabbasov break; 1405d4fc8d9SRaffaele Recalcati 1411677eef4SAndrew Gabbasov udelay(1000); 1421677eef4SAndrew Gabbasov } 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 164786e8f81SAndrew Gabbasov if (mmc->ddr_mode) 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 2961677eef4SAndrew Gabbasov while (1) { 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 3271677eef4SAndrew Gabbasov if (cmd.response[0] & OCR_BUSY) 3281677eef4SAndrew Gabbasov break; 329272cc70bSAndy Fleming 3301677eef4SAndrew Gabbasov if (timeout-- <= 0) 331272cc70bSAndy Fleming return UNUSABLE_ERR; 332272cc70bSAndy Fleming 3331677eef4SAndrew Gabbasov udelay(1000); 3341677eef4SAndrew Gabbasov } 3351677eef4SAndrew Gabbasov 336272cc70bSAndy Fleming if (mmc->version != SD_VERSION_2) 337272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 338272cc70bSAndy Fleming 339d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 340d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 341d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 342d52ebf10SThomas Chou cmd.cmdarg = 0; 343d52ebf10SThomas Chou 344d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 345d52ebf10SThomas Chou 346d52ebf10SThomas Chou if (err) 347d52ebf10SThomas Chou return err; 348d52ebf10SThomas Chou } 349d52ebf10SThomas Chou 350998be3ddSRabin Vincent mmc->ocr = cmd.response[0]; 351272cc70bSAndy Fleming 352272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 353272cc70bSAndy Fleming mmc->rca = 0; 354272cc70bSAndy Fleming 355272cc70bSAndy Fleming return 0; 356272cc70bSAndy Fleming } 357272cc70bSAndy Fleming 3585289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg) 359272cc70bSAndy Fleming { 3605289b535SAndrew Gabbasov struct mmc_cmd cmd; 361272cc70bSAndy Fleming int err; 362272cc70bSAndy Fleming 3635289b535SAndrew Gabbasov cmd.cmdidx = MMC_CMD_SEND_OP_COND; 3645289b535SAndrew Gabbasov cmd.resp_type = MMC_RSP_R3; 3655289b535SAndrew Gabbasov cmd.cmdarg = 0; 366e9550449SChe-Liang Chiou if (use_arg && !mmc_host_is_spi(mmc)) { 3675289b535SAndrew Gabbasov cmd.cmdarg = 36893bfd616SPantelis Antoniou (mmc->cfg->voltages & 369a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_VOLTAGE_MASK)) | 370a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_ACCESS_MODE); 371e9550449SChe-Liang Chiou 37293bfd616SPantelis Antoniou if (mmc->cfg->host_caps & MMC_MODE_HC) 3735289b535SAndrew Gabbasov cmd.cmdarg |= OCR_HCS; 374e9550449SChe-Liang Chiou } 3755289b535SAndrew Gabbasov err = mmc_send_cmd(mmc, &cmd, NULL); 376e9550449SChe-Liang Chiou if (err) 377e9550449SChe-Liang Chiou return err; 3785289b535SAndrew Gabbasov mmc->ocr = cmd.response[0]; 379e9550449SChe-Liang Chiou return 0; 380e9550449SChe-Liang Chiou } 381e9550449SChe-Liang Chiou 382750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc) 383e9550449SChe-Liang Chiou { 384e9550449SChe-Liang Chiou int err, i; 385e9550449SChe-Liang Chiou 386272cc70bSAndy Fleming /* Some cards seem to need this */ 387272cc70bSAndy Fleming mmc_go_idle(mmc); 388272cc70bSAndy Fleming 38931cacbabSRaffaele Recalcati /* Asking to the card its capabilities */ 390e9550449SChe-Liang Chiou for (i = 0; i < 2; i++) { 3915289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, i != 0); 39231cacbabSRaffaele Recalcati if (err) 39331cacbabSRaffaele Recalcati return err; 39431cacbabSRaffaele Recalcati 395e9550449SChe-Liang Chiou /* exit if not busy (flag seems to be inverted) */ 396a626c8d4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 397*bd47c135SAndrew Gabbasov break; 398e9550449SChe-Liang Chiou } 399*bd47c135SAndrew Gabbasov mmc->op_cond_pending = 1; 400*bd47c135SAndrew Gabbasov return 0; 401e9550449SChe-Liang Chiou } 40231cacbabSRaffaele Recalcati 403750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc) 404e9550449SChe-Liang Chiou { 405e9550449SChe-Liang Chiou struct mmc_cmd cmd; 406e9550449SChe-Liang Chiou int timeout = 1000; 407e9550449SChe-Liang Chiou uint start; 408e9550449SChe-Liang Chiou int err; 409e9550449SChe-Liang Chiou 410e9550449SChe-Liang Chiou mmc->op_cond_pending = 0; 411cc17c01fSAndrew Gabbasov if (!(mmc->ocr & OCR_BUSY)) { 412e9550449SChe-Liang Chiou start = get_timer(0); 4131677eef4SAndrew Gabbasov while (1) { 4145289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, 1); 415272cc70bSAndy Fleming if (err) 416272cc70bSAndy Fleming return err; 4171677eef4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 4181677eef4SAndrew Gabbasov break; 419e9550449SChe-Liang Chiou if (get_timer(start) > timeout) 420272cc70bSAndy Fleming return UNUSABLE_ERR; 421e9550449SChe-Liang Chiou udelay(100); 4221677eef4SAndrew Gabbasov } 423cc17c01fSAndrew Gabbasov } 424272cc70bSAndy Fleming 425d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 426d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 427d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 428d52ebf10SThomas Chou cmd.cmdarg = 0; 429d52ebf10SThomas Chou 430d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 431d52ebf10SThomas Chou 432d52ebf10SThomas Chou if (err) 433d52ebf10SThomas Chou return err; 434a626c8d4SAndrew Gabbasov 435a626c8d4SAndrew Gabbasov mmc->ocr = cmd.response[0]; 436d52ebf10SThomas Chou } 437d52ebf10SThomas Chou 438272cc70bSAndy Fleming mmc->version = MMC_VERSION_UNKNOWN; 439272cc70bSAndy Fleming 440272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 441def816a2SStephen Warren mmc->rca = 1; 442272cc70bSAndy Fleming 443272cc70bSAndy Fleming return 0; 444272cc70bSAndy Fleming } 445272cc70bSAndy Fleming 446272cc70bSAndy Fleming 447fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd) 448272cc70bSAndy Fleming { 449272cc70bSAndy Fleming struct mmc_cmd cmd; 450272cc70bSAndy Fleming struct mmc_data data; 451272cc70bSAndy Fleming int err; 452272cc70bSAndy Fleming 453272cc70bSAndy Fleming /* Get the Card Status Register */ 454272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_EXT_CSD; 455272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 456272cc70bSAndy Fleming cmd.cmdarg = 0; 457272cc70bSAndy Fleming 458cdfd1ac6SYoshihiro Shimoda data.dest = (char *)ext_csd; 459272cc70bSAndy Fleming data.blocks = 1; 4608bfa195eSSimon Glass data.blocksize = MMC_MAX_BLOCK_LEN; 461272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 462272cc70bSAndy Fleming 463272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 464272cc70bSAndy Fleming 465272cc70bSAndy Fleming return err; 466272cc70bSAndy Fleming } 467272cc70bSAndy Fleming 468272cc70bSAndy Fleming 469fdbb873eSKim Phillips static int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) 470272cc70bSAndy Fleming { 471272cc70bSAndy Fleming struct mmc_cmd cmd; 4725d4fc8d9SRaffaele Recalcati int timeout = 1000; 4735d4fc8d9SRaffaele Recalcati int ret; 474272cc70bSAndy Fleming 475272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SWITCH; 476272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1b; 477272cc70bSAndy Fleming cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | 478272cc70bSAndy Fleming (index << 16) | 479272cc70bSAndy Fleming (value << 8); 480272cc70bSAndy Fleming 4815d4fc8d9SRaffaele Recalcati ret = mmc_send_cmd(mmc, &cmd, NULL); 4825d4fc8d9SRaffaele Recalcati 4835d4fc8d9SRaffaele Recalcati /* Waiting for the ready status */ 48493ad0d18SJan Kloetzke if (!ret) 48593ad0d18SJan Kloetzke ret = mmc_send_status(mmc, timeout); 4865d4fc8d9SRaffaele Recalcati 4875d4fc8d9SRaffaele Recalcati return ret; 4885d4fc8d9SRaffaele Recalcati 489272cc70bSAndy Fleming } 490272cc70bSAndy Fleming 491fdbb873eSKim Phillips static int mmc_change_freq(struct mmc *mmc) 492272cc70bSAndy Fleming { 4938bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 494272cc70bSAndy Fleming char cardtype; 495272cc70bSAndy Fleming int err; 496272cc70bSAndy Fleming 497fc5b32fbSAndrew Gabbasov mmc->card_caps = 0; 498272cc70bSAndy Fleming 499d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 500d52ebf10SThomas Chou return 0; 501d52ebf10SThomas Chou 502272cc70bSAndy Fleming /* Only version 4 supports high-speed */ 503272cc70bSAndy Fleming if (mmc->version < MMC_VERSION_4) 504272cc70bSAndy Fleming return 0; 505272cc70bSAndy Fleming 506fc5b32fbSAndrew Gabbasov mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT; 507fc5b32fbSAndrew Gabbasov 508272cc70bSAndy Fleming err = mmc_send_ext_csd(mmc, ext_csd); 509272cc70bSAndy Fleming 510272cc70bSAndy Fleming if (err) 511272cc70bSAndy Fleming return err; 512272cc70bSAndy Fleming 5130560db18SLei Wen cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf; 514272cc70bSAndy Fleming 515272cc70bSAndy Fleming err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1); 516272cc70bSAndy Fleming 517272cc70bSAndy Fleming if (err) 5186b2221b0SAndrew Gabbasov return err == SWITCH_ERR ? 0 : err; 519272cc70bSAndy Fleming 520272cc70bSAndy Fleming /* Now check to see that it worked */ 521272cc70bSAndy Fleming err = mmc_send_ext_csd(mmc, ext_csd); 522272cc70bSAndy Fleming 523272cc70bSAndy Fleming if (err) 524272cc70bSAndy Fleming return err; 525272cc70bSAndy Fleming 526272cc70bSAndy Fleming /* No high-speed support */ 5270560db18SLei Wen if (!ext_csd[EXT_CSD_HS_TIMING]) 528272cc70bSAndy Fleming return 0; 529272cc70bSAndy Fleming 530272cc70bSAndy Fleming /* High Speed is set, there are two types: 52MHz and 26MHz */ 531d22e3d46SJaehoon Chung if (cardtype & EXT_CSD_CARD_TYPE_52) { 532201d5ac4SAndrew Gabbasov if (cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V) 533d22e3d46SJaehoon Chung mmc->card_caps |= MMC_MODE_DDR_52MHz; 534272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; 535d22e3d46SJaehoon Chung } else { 536272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS; 537d22e3d46SJaehoon Chung } 538272cc70bSAndy Fleming 539272cc70bSAndy Fleming return 0; 540272cc70bSAndy Fleming } 541272cc70bSAndy Fleming 542f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num) 543f866a46dSStephen Warren { 544f866a46dSStephen Warren switch (part_num) { 545f866a46dSStephen Warren case 0: 546f866a46dSStephen Warren mmc->capacity = mmc->capacity_user; 547f866a46dSStephen Warren break; 548f866a46dSStephen Warren case 1: 549f866a46dSStephen Warren case 2: 550f866a46dSStephen Warren mmc->capacity = mmc->capacity_boot; 551f866a46dSStephen Warren break; 552f866a46dSStephen Warren case 3: 553f866a46dSStephen Warren mmc->capacity = mmc->capacity_rpmb; 554f866a46dSStephen Warren break; 555f866a46dSStephen Warren case 4: 556f866a46dSStephen Warren case 5: 557f866a46dSStephen Warren case 6: 558f866a46dSStephen Warren case 7: 559f866a46dSStephen Warren mmc->capacity = mmc->capacity_gp[part_num - 4]; 560f866a46dSStephen Warren break; 561f866a46dSStephen Warren default: 562f866a46dSStephen Warren return -1; 563f866a46dSStephen Warren } 564f866a46dSStephen Warren 565f866a46dSStephen Warren mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len); 566f866a46dSStephen Warren 567f866a46dSStephen Warren return 0; 568f866a46dSStephen Warren } 569f866a46dSStephen Warren 570d2356284SStephen Warren int mmc_select_hwpart(int dev_num, int hwpart) 571d2356284SStephen Warren { 572d2356284SStephen Warren struct mmc *mmc = find_mmc_device(dev_num); 573d2356284SStephen Warren int ret; 574d2356284SStephen Warren 575d2356284SStephen Warren if (!mmc) 576d4622df3SStephen Warren return -ENODEV; 577d2356284SStephen Warren 578d2356284SStephen Warren if (mmc->part_num == hwpart) 579d2356284SStephen Warren return 0; 580d2356284SStephen Warren 581d2356284SStephen Warren if (mmc->part_config == MMCPART_NOAVAILABLE) { 582d2356284SStephen Warren printf("Card doesn't support part_switch\n"); 583d4622df3SStephen Warren return -EMEDIUMTYPE; 584d2356284SStephen Warren } 585d2356284SStephen Warren 586d2356284SStephen Warren ret = mmc_switch_part(dev_num, hwpart); 587d2356284SStephen Warren if (ret) 588d4622df3SStephen Warren return ret; 589d2356284SStephen Warren 590d2356284SStephen Warren mmc->part_num = hwpart; 591d2356284SStephen Warren 592d2356284SStephen Warren return 0; 593d2356284SStephen Warren } 594d2356284SStephen Warren 595d2356284SStephen Warren 596bc897b1dSLei Wen int mmc_switch_part(int dev_num, unsigned int part_num) 597bc897b1dSLei Wen { 598bc897b1dSLei Wen struct mmc *mmc = find_mmc_device(dev_num); 599f866a46dSStephen Warren int ret; 600bc897b1dSLei Wen 601bc897b1dSLei Wen if (!mmc) 602bc897b1dSLei Wen return -1; 603bc897b1dSLei Wen 604f866a46dSStephen Warren ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, 605bc897b1dSLei Wen (mmc->part_config & ~PART_ACCESS_MASK) 606bc897b1dSLei Wen | (part_num & PART_ACCESS_MASK)); 607f866a46dSStephen Warren 6086dc93e70SPeter Bigot /* 6096dc93e70SPeter Bigot * Set the capacity if the switch succeeded or was intended 6106dc93e70SPeter Bigot * to return to representing the raw device. 6116dc93e70SPeter Bigot */ 6126dc93e70SPeter Bigot if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) 6136dc93e70SPeter Bigot ret = mmc_set_capacity(mmc, part_num); 6146dc93e70SPeter Bigot 6156dc93e70SPeter Bigot return ret; 616bc897b1dSLei Wen } 617bc897b1dSLei Wen 618ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc, 619ac9da0e0SDiego Santa Cruz const struct mmc_hwpart_conf *conf, 620ac9da0e0SDiego Santa Cruz enum mmc_hwpart_conf_mode mode) 621ac9da0e0SDiego Santa Cruz { 622ac9da0e0SDiego Santa Cruz u8 part_attrs = 0; 623ac9da0e0SDiego Santa Cruz u32 enh_size_mult; 624ac9da0e0SDiego Santa Cruz u32 enh_start_addr; 625ac9da0e0SDiego Santa Cruz u32 gp_size_mult[4]; 626ac9da0e0SDiego Santa Cruz u32 max_enh_size_mult; 627ac9da0e0SDiego Santa Cruz u32 tot_enh_size_mult = 0; 6288dda5b0eSDiego Santa Cruz u8 wr_rel_set; 629ac9da0e0SDiego Santa Cruz int i, pidx, err; 630ac9da0e0SDiego Santa Cruz ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 631ac9da0e0SDiego Santa Cruz 632ac9da0e0SDiego Santa Cruz if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE) 633ac9da0e0SDiego Santa Cruz return -EINVAL; 634ac9da0e0SDiego Santa Cruz 635ac9da0e0SDiego Santa Cruz if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) { 636ac9da0e0SDiego Santa Cruz printf("eMMC >= 4.4 required for enhanced user data area\n"); 637ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 638ac9da0e0SDiego Santa Cruz } 639ac9da0e0SDiego Santa Cruz 640ac9da0e0SDiego Santa Cruz if (!(mmc->part_support & PART_SUPPORT)) { 641ac9da0e0SDiego Santa Cruz printf("Card does not support partitioning\n"); 642ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 643ac9da0e0SDiego Santa Cruz } 644ac9da0e0SDiego Santa Cruz 645ac9da0e0SDiego Santa Cruz if (!mmc->hc_wp_grp_size) { 646ac9da0e0SDiego Santa Cruz printf("Card does not define HC WP group size\n"); 647ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 648ac9da0e0SDiego Santa Cruz } 649ac9da0e0SDiego Santa Cruz 650ac9da0e0SDiego Santa Cruz /* check partition alignment and total enhanced size */ 651ac9da0e0SDiego Santa Cruz if (conf->user.enh_size) { 652ac9da0e0SDiego Santa Cruz if (conf->user.enh_size % mmc->hc_wp_grp_size || 653ac9da0e0SDiego Santa Cruz conf->user.enh_start % mmc->hc_wp_grp_size) { 654ac9da0e0SDiego Santa Cruz printf("User data enhanced area not HC WP group " 655ac9da0e0SDiego Santa Cruz "size aligned\n"); 656ac9da0e0SDiego Santa Cruz return -EINVAL; 657ac9da0e0SDiego Santa Cruz } 658ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_USR; 659ac9da0e0SDiego Santa Cruz enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size; 660ac9da0e0SDiego Santa Cruz if (mmc->high_capacity) { 661ac9da0e0SDiego Santa Cruz enh_start_addr = conf->user.enh_start; 662ac9da0e0SDiego Santa Cruz } else { 663ac9da0e0SDiego Santa Cruz enh_start_addr = (conf->user.enh_start << 9); 664ac9da0e0SDiego Santa Cruz } 665ac9da0e0SDiego Santa Cruz } else { 666ac9da0e0SDiego Santa Cruz enh_size_mult = 0; 667ac9da0e0SDiego Santa Cruz enh_start_addr = 0; 668ac9da0e0SDiego Santa Cruz } 669ac9da0e0SDiego Santa Cruz tot_enh_size_mult += enh_size_mult; 670ac9da0e0SDiego Santa Cruz 671ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 672ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) { 673ac9da0e0SDiego Santa Cruz printf("GP%i partition not HC WP group size " 674ac9da0e0SDiego Santa Cruz "aligned\n", pidx+1); 675ac9da0e0SDiego Santa Cruz return -EINVAL; 676ac9da0e0SDiego Santa Cruz } 677ac9da0e0SDiego Santa Cruz gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size; 678ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) { 679ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_GP(pidx); 680ac9da0e0SDiego Santa Cruz tot_enh_size_mult += gp_size_mult[pidx]; 681ac9da0e0SDiego Santa Cruz } 682ac9da0e0SDiego Santa Cruz } 683ac9da0e0SDiego Santa Cruz 684ac9da0e0SDiego Santa Cruz if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) { 685ac9da0e0SDiego Santa Cruz printf("Card does not support enhanced attribute\n"); 686ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 687ac9da0e0SDiego Santa Cruz } 688ac9da0e0SDiego Santa Cruz 689ac9da0e0SDiego Santa Cruz err = mmc_send_ext_csd(mmc, ext_csd); 690ac9da0e0SDiego Santa Cruz if (err) 691ac9da0e0SDiego Santa Cruz return err; 692ac9da0e0SDiego Santa Cruz 693ac9da0e0SDiego Santa Cruz max_enh_size_mult = 694ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) + 695ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) + 696ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT]; 697ac9da0e0SDiego Santa Cruz if (tot_enh_size_mult > max_enh_size_mult) { 698ac9da0e0SDiego Santa Cruz printf("Total enhanced size exceeds maximum (%u > %u)\n", 699ac9da0e0SDiego Santa Cruz tot_enh_size_mult, max_enh_size_mult); 700ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 701ac9da0e0SDiego Santa Cruz } 702ac9da0e0SDiego Santa Cruz 7038dda5b0eSDiego Santa Cruz /* The default value of EXT_CSD_WR_REL_SET is device 7048dda5b0eSDiego Santa Cruz * dependent, the values can only be changed if the 7058dda5b0eSDiego Santa Cruz * EXT_CSD_HS_CTRL_REL bit is set. The values can be 7068dda5b0eSDiego Santa Cruz * changed only once and before partitioning is completed. */ 7078dda5b0eSDiego Santa Cruz wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 7088dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_change) { 7098dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_set) 7108dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_USR; 7118dda5b0eSDiego Santa Cruz else 7128dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR; 7138dda5b0eSDiego Santa Cruz } 7148dda5b0eSDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 7158dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_change) { 7168dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_set) 7178dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx); 7188dda5b0eSDiego Santa Cruz else 7198dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx); 7208dda5b0eSDiego Santa Cruz } 7218dda5b0eSDiego Santa Cruz } 7228dda5b0eSDiego Santa Cruz 7238dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] && 7248dda5b0eSDiego Santa Cruz !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) { 7258dda5b0eSDiego Santa Cruz puts("Card does not support host controlled partition write " 7268dda5b0eSDiego Santa Cruz "reliability settings\n"); 7278dda5b0eSDiego Santa Cruz return -EMEDIUMTYPE; 7288dda5b0eSDiego Santa Cruz } 7298dda5b0eSDiego Santa Cruz 730ac9da0e0SDiego Santa Cruz if (ext_csd[EXT_CSD_PARTITION_SETTING] & 731ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED) { 732ac9da0e0SDiego Santa Cruz printf("Card already partitioned\n"); 733ac9da0e0SDiego Santa Cruz return -EPERM; 734ac9da0e0SDiego Santa Cruz } 735ac9da0e0SDiego Santa Cruz 736ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_CHECK) 737ac9da0e0SDiego Santa Cruz return 0; 738ac9da0e0SDiego Santa Cruz 739ac9da0e0SDiego Santa Cruz /* Partitioning requires high-capacity size definitions */ 740ac9da0e0SDiego Santa Cruz if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) { 741ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 742ac9da0e0SDiego Santa Cruz EXT_CSD_ERASE_GROUP_DEF, 1); 743ac9da0e0SDiego Santa Cruz 744ac9da0e0SDiego Santa Cruz if (err) 745ac9da0e0SDiego Santa Cruz return err; 746ac9da0e0SDiego Santa Cruz 747ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 748ac9da0e0SDiego Santa Cruz 749ac9da0e0SDiego Santa Cruz /* update erase group size to be high-capacity */ 750ac9da0e0SDiego Santa Cruz mmc->erase_grp_size = 751ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 752ac9da0e0SDiego Santa Cruz 753ac9da0e0SDiego Santa Cruz } 754ac9da0e0SDiego Santa Cruz 755ac9da0e0SDiego Santa Cruz /* all OK, write the configuration */ 756ac9da0e0SDiego Santa Cruz for (i = 0; i < 4; i++) { 757ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 758ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_START_ADDR+i, 759ac9da0e0SDiego Santa Cruz (enh_start_addr >> (i*8)) & 0xFF); 760ac9da0e0SDiego Santa Cruz if (err) 761ac9da0e0SDiego Santa Cruz return err; 762ac9da0e0SDiego Santa Cruz } 763ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 764ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 765ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_SIZE_MULT+i, 766ac9da0e0SDiego Santa Cruz (enh_size_mult >> (i*8)) & 0xFF); 767ac9da0e0SDiego Santa Cruz if (err) 768ac9da0e0SDiego Santa Cruz return err; 769ac9da0e0SDiego Santa Cruz } 770ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 771ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 772ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 773ac9da0e0SDiego Santa Cruz EXT_CSD_GP_SIZE_MULT+pidx*3+i, 774ac9da0e0SDiego Santa Cruz (gp_size_mult[pidx] >> (i*8)) & 0xFF); 775ac9da0e0SDiego Santa Cruz if (err) 776ac9da0e0SDiego Santa Cruz return err; 777ac9da0e0SDiego Santa Cruz } 778ac9da0e0SDiego Santa Cruz } 779ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 780ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs); 781ac9da0e0SDiego Santa Cruz if (err) 782ac9da0e0SDiego Santa Cruz return err; 783ac9da0e0SDiego Santa Cruz 784ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_SET) 785ac9da0e0SDiego Santa Cruz return 0; 786ac9da0e0SDiego Santa Cruz 7878dda5b0eSDiego Santa Cruz /* The WR_REL_SET is a write-once register but shall be 7888dda5b0eSDiego Santa Cruz * written before setting PART_SETTING_COMPLETED. As it is 7898dda5b0eSDiego Santa Cruz * write-once we can only write it when completing the 7908dda5b0eSDiego Santa Cruz * partitioning. */ 7918dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) { 7928dda5b0eSDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 7938dda5b0eSDiego Santa Cruz EXT_CSD_WR_REL_SET, wr_rel_set); 7948dda5b0eSDiego Santa Cruz if (err) 7958dda5b0eSDiego Santa Cruz return err; 7968dda5b0eSDiego Santa Cruz } 7978dda5b0eSDiego Santa Cruz 798ac9da0e0SDiego Santa Cruz /* Setting PART_SETTING_COMPLETED confirms the partition 799ac9da0e0SDiego Santa Cruz * configuration but it only becomes effective after power 800ac9da0e0SDiego Santa Cruz * cycle, so we do not adjust the partition related settings 801ac9da0e0SDiego Santa Cruz * in the mmc struct. */ 802ac9da0e0SDiego Santa Cruz 803ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 804ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING, 805ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED); 806ac9da0e0SDiego Santa Cruz if (err) 807ac9da0e0SDiego Santa Cruz return err; 808ac9da0e0SDiego Santa Cruz 809ac9da0e0SDiego Santa Cruz return 0; 810ac9da0e0SDiego Santa Cruz } 811ac9da0e0SDiego Santa Cruz 81248972d90SThierry Reding int mmc_getcd(struct mmc *mmc) 81348972d90SThierry Reding { 81448972d90SThierry Reding int cd; 81548972d90SThierry Reding 81648972d90SThierry Reding cd = board_mmc_getcd(mmc); 81748972d90SThierry Reding 818d4e1da4eSPeter Korsgaard if (cd < 0) { 81993bfd616SPantelis Antoniou if (mmc->cfg->ops->getcd) 82093bfd616SPantelis Antoniou cd = mmc->cfg->ops->getcd(mmc); 821d4e1da4eSPeter Korsgaard else 822d4e1da4eSPeter Korsgaard cd = 1; 823d4e1da4eSPeter Korsgaard } 82448972d90SThierry Reding 82548972d90SThierry Reding return cd; 82648972d90SThierry Reding } 82748972d90SThierry Reding 828fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) 829272cc70bSAndy Fleming { 830272cc70bSAndy Fleming struct mmc_cmd cmd; 831272cc70bSAndy Fleming struct mmc_data data; 832272cc70bSAndy Fleming 833272cc70bSAndy Fleming /* Switch the frequency */ 834272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SWITCH_FUNC; 835272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 836272cc70bSAndy Fleming cmd.cmdarg = (mode << 31) | 0xffffff; 837272cc70bSAndy Fleming cmd.cmdarg &= ~(0xf << (group * 4)); 838272cc70bSAndy Fleming cmd.cmdarg |= value << (group * 4); 839272cc70bSAndy Fleming 840272cc70bSAndy Fleming data.dest = (char *)resp; 841272cc70bSAndy Fleming data.blocksize = 64; 842272cc70bSAndy Fleming data.blocks = 1; 843272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 844272cc70bSAndy Fleming 845272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, &data); 846272cc70bSAndy Fleming } 847272cc70bSAndy Fleming 848272cc70bSAndy Fleming 849fdbb873eSKim Phillips static int sd_change_freq(struct mmc *mmc) 850272cc70bSAndy Fleming { 851272cc70bSAndy Fleming int err; 852272cc70bSAndy Fleming struct mmc_cmd cmd; 853f781dd38SAnton staaf ALLOC_CACHE_ALIGN_BUFFER(uint, scr, 2); 854f781dd38SAnton staaf ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16); 855272cc70bSAndy Fleming struct mmc_data data; 856272cc70bSAndy Fleming int timeout; 857272cc70bSAndy Fleming 858272cc70bSAndy Fleming mmc->card_caps = 0; 859272cc70bSAndy Fleming 860d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 861d52ebf10SThomas Chou return 0; 862d52ebf10SThomas Chou 863272cc70bSAndy Fleming /* Read the SCR to find out if this card supports higher speeds */ 864272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 865272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 866272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 867272cc70bSAndy Fleming 868272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 869272cc70bSAndy Fleming 870272cc70bSAndy Fleming if (err) 871272cc70bSAndy Fleming return err; 872272cc70bSAndy Fleming 873272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_SCR; 874272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 875272cc70bSAndy Fleming cmd.cmdarg = 0; 876272cc70bSAndy Fleming 877272cc70bSAndy Fleming timeout = 3; 878272cc70bSAndy Fleming 879272cc70bSAndy Fleming retry_scr: 880f781dd38SAnton staaf data.dest = (char *)scr; 881272cc70bSAndy Fleming data.blocksize = 8; 882272cc70bSAndy Fleming data.blocks = 1; 883272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 884272cc70bSAndy Fleming 885272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 886272cc70bSAndy Fleming 887272cc70bSAndy Fleming if (err) { 888272cc70bSAndy Fleming if (timeout--) 889272cc70bSAndy Fleming goto retry_scr; 890272cc70bSAndy Fleming 891272cc70bSAndy Fleming return err; 892272cc70bSAndy Fleming } 893272cc70bSAndy Fleming 8944e3d89baSYauhen Kharuzhy mmc->scr[0] = __be32_to_cpu(scr[0]); 8954e3d89baSYauhen Kharuzhy mmc->scr[1] = __be32_to_cpu(scr[1]); 896272cc70bSAndy Fleming 897272cc70bSAndy Fleming switch ((mmc->scr[0] >> 24) & 0xf) { 898272cc70bSAndy Fleming case 0: 899272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 900272cc70bSAndy Fleming break; 901272cc70bSAndy Fleming case 1: 902272cc70bSAndy Fleming mmc->version = SD_VERSION_1_10; 903272cc70bSAndy Fleming break; 904272cc70bSAndy Fleming case 2: 905272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 9061741c64dSJaehoon Chung if ((mmc->scr[0] >> 15) & 0x1) 9071741c64dSJaehoon Chung mmc->version = SD_VERSION_3; 908272cc70bSAndy Fleming break; 909272cc70bSAndy Fleming default: 910272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 911272cc70bSAndy Fleming break; 912272cc70bSAndy Fleming } 913272cc70bSAndy Fleming 914b44c7083SAlagu Sankar if (mmc->scr[0] & SD_DATA_4BIT) 915b44c7083SAlagu Sankar mmc->card_caps |= MMC_MODE_4BIT; 916b44c7083SAlagu Sankar 917272cc70bSAndy Fleming /* Version 1.0 doesn't support switching */ 918272cc70bSAndy Fleming if (mmc->version == SD_VERSION_1_0) 919272cc70bSAndy Fleming return 0; 920272cc70bSAndy Fleming 921272cc70bSAndy Fleming timeout = 4; 922272cc70bSAndy Fleming while (timeout--) { 923272cc70bSAndy Fleming err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1, 924f781dd38SAnton staaf (u8 *)switch_status); 925272cc70bSAndy Fleming 926272cc70bSAndy Fleming if (err) 927272cc70bSAndy Fleming return err; 928272cc70bSAndy Fleming 929272cc70bSAndy Fleming /* The high-speed function is busy. Try again */ 9304e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY)) 931272cc70bSAndy Fleming break; 932272cc70bSAndy Fleming } 933272cc70bSAndy Fleming 934272cc70bSAndy Fleming /* If high-speed isn't supported, we return */ 9354e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)) 936272cc70bSAndy Fleming return 0; 937272cc70bSAndy Fleming 9382c3fbf4cSMacpaul Lin /* 9392c3fbf4cSMacpaul Lin * If the host doesn't support SD_HIGHSPEED, do not switch card to 9402c3fbf4cSMacpaul Lin * HIGHSPEED mode even if the card support SD_HIGHSPPED. 9412c3fbf4cSMacpaul Lin * This can avoid furthur problem when the card runs in different 9422c3fbf4cSMacpaul Lin * mode between the host. 9432c3fbf4cSMacpaul Lin */ 94493bfd616SPantelis Antoniou if (!((mmc->cfg->host_caps & MMC_MODE_HS_52MHz) && 94593bfd616SPantelis Antoniou (mmc->cfg->host_caps & MMC_MODE_HS))) 9462c3fbf4cSMacpaul Lin return 0; 9472c3fbf4cSMacpaul Lin 948f781dd38SAnton staaf err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status); 949272cc70bSAndy Fleming 950272cc70bSAndy Fleming if (err) 951272cc70bSAndy Fleming return err; 952272cc70bSAndy Fleming 9534e3d89baSYauhen Kharuzhy if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000) 954272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS; 955272cc70bSAndy Fleming 956272cc70bSAndy Fleming return 0; 957272cc70bSAndy Fleming } 958272cc70bSAndy Fleming 959272cc70bSAndy Fleming /* frequency bases */ 960272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */ 9615f837c2cSMike Frysinger static const int fbase[] = { 962272cc70bSAndy Fleming 10000, 963272cc70bSAndy Fleming 100000, 964272cc70bSAndy Fleming 1000000, 965272cc70bSAndy Fleming 10000000, 966272cc70bSAndy Fleming }; 967272cc70bSAndy Fleming 968272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice 969272cc70bSAndy Fleming * to platforms without floating point. 970272cc70bSAndy Fleming */ 9715f837c2cSMike Frysinger static const int multipliers[] = { 972272cc70bSAndy Fleming 0, /* reserved */ 973272cc70bSAndy Fleming 10, 974272cc70bSAndy Fleming 12, 975272cc70bSAndy Fleming 13, 976272cc70bSAndy Fleming 15, 977272cc70bSAndy Fleming 20, 978272cc70bSAndy Fleming 25, 979272cc70bSAndy Fleming 30, 980272cc70bSAndy Fleming 35, 981272cc70bSAndy Fleming 40, 982272cc70bSAndy Fleming 45, 983272cc70bSAndy Fleming 50, 984272cc70bSAndy Fleming 55, 985272cc70bSAndy Fleming 60, 986272cc70bSAndy Fleming 70, 987272cc70bSAndy Fleming 80, 988272cc70bSAndy Fleming }; 989272cc70bSAndy Fleming 990fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc) 991272cc70bSAndy Fleming { 99293bfd616SPantelis Antoniou if (mmc->cfg->ops->set_ios) 99393bfd616SPantelis Antoniou mmc->cfg->ops->set_ios(mmc); 994272cc70bSAndy Fleming } 995272cc70bSAndy Fleming 996272cc70bSAndy Fleming void mmc_set_clock(struct mmc *mmc, uint clock) 997272cc70bSAndy Fleming { 99893bfd616SPantelis Antoniou if (clock > mmc->cfg->f_max) 99993bfd616SPantelis Antoniou clock = mmc->cfg->f_max; 1000272cc70bSAndy Fleming 100193bfd616SPantelis Antoniou if (clock < mmc->cfg->f_min) 100293bfd616SPantelis Antoniou clock = mmc->cfg->f_min; 1003272cc70bSAndy Fleming 1004272cc70bSAndy Fleming mmc->clock = clock; 1005272cc70bSAndy Fleming 1006272cc70bSAndy Fleming mmc_set_ios(mmc); 1007272cc70bSAndy Fleming } 1008272cc70bSAndy Fleming 1009fdbb873eSKim Phillips static void mmc_set_bus_width(struct mmc *mmc, uint width) 1010272cc70bSAndy Fleming { 1011272cc70bSAndy Fleming mmc->bus_width = width; 1012272cc70bSAndy Fleming 1013272cc70bSAndy Fleming mmc_set_ios(mmc); 1014272cc70bSAndy Fleming } 1015272cc70bSAndy Fleming 1016fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc) 1017272cc70bSAndy Fleming { 1018f866a46dSStephen Warren int err, i; 1019272cc70bSAndy Fleming uint mult, freq; 1020639b7827SYoshihiro Shimoda u64 cmult, csize, capacity; 1021272cc70bSAndy Fleming struct mmc_cmd cmd; 10228bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 10238bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 10245d4fc8d9SRaffaele Recalcati int timeout = 1000; 10250c453bb7SDiego Santa Cruz bool has_parts = false; 10268a0cf490SDiego Santa Cruz bool part_completed; 1027272cc70bSAndy Fleming 1028d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON 1029d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */ 1030d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF; 1031d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R1; 1032d52ebf10SThomas Chou cmd.cmdarg = 1; 1033d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 1034d52ebf10SThomas Chou 1035d52ebf10SThomas Chou if (err) 1036d52ebf10SThomas Chou return err; 1037d52ebf10SThomas Chou } 1038d52ebf10SThomas Chou #endif 1039d52ebf10SThomas Chou 1040272cc70bSAndy Fleming /* Put the Card in Identify Mode */ 1041d52ebf10SThomas Chou cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID : 1042d52ebf10SThomas Chou MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */ 1043272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1044272cc70bSAndy Fleming cmd.cmdarg = 0; 1045272cc70bSAndy Fleming 1046272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1047272cc70bSAndy Fleming 1048272cc70bSAndy Fleming if (err) 1049272cc70bSAndy Fleming return err; 1050272cc70bSAndy Fleming 1051272cc70bSAndy Fleming memcpy(mmc->cid, cmd.response, 16); 1052272cc70bSAndy Fleming 1053272cc70bSAndy Fleming /* 1054272cc70bSAndy Fleming * For MMC cards, set the Relative Address. 1055272cc70bSAndy Fleming * For SD cards, get the Relatvie Address. 1056272cc70bSAndy Fleming * This also puts the cards into Standby State 1057272cc70bSAndy Fleming */ 1058d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1059272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR; 1060272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1061272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R6; 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 if (IS_SD(mmc)) 1069998be3ddSRabin Vincent mmc->rca = (cmd.response[0] >> 16) & 0xffff; 1070d52ebf10SThomas Chou } 1071272cc70bSAndy Fleming 1072272cc70bSAndy Fleming /* Get the Card-Specific Data */ 1073272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_CSD; 1074272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1075272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1076272cc70bSAndy Fleming 1077272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1078272cc70bSAndy Fleming 10795d4fc8d9SRaffaele Recalcati /* Waiting for the ready status */ 10805d4fc8d9SRaffaele Recalcati mmc_send_status(mmc, timeout); 10815d4fc8d9SRaffaele Recalcati 1082272cc70bSAndy Fleming if (err) 1083272cc70bSAndy Fleming return err; 1084272cc70bSAndy Fleming 1085998be3ddSRabin Vincent mmc->csd[0] = cmd.response[0]; 1086998be3ddSRabin Vincent mmc->csd[1] = cmd.response[1]; 1087998be3ddSRabin Vincent mmc->csd[2] = cmd.response[2]; 1088998be3ddSRabin Vincent mmc->csd[3] = cmd.response[3]; 1089272cc70bSAndy Fleming 1090272cc70bSAndy Fleming if (mmc->version == MMC_VERSION_UNKNOWN) { 10910b453ffeSRabin Vincent int version = (cmd.response[0] >> 26) & 0xf; 1092272cc70bSAndy Fleming 1093272cc70bSAndy Fleming switch (version) { 1094272cc70bSAndy Fleming case 0: 1095272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1096272cc70bSAndy Fleming break; 1097272cc70bSAndy Fleming case 1: 1098272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_4; 1099272cc70bSAndy Fleming break; 1100272cc70bSAndy Fleming case 2: 1101272cc70bSAndy Fleming mmc->version = MMC_VERSION_2_2; 1102272cc70bSAndy Fleming break; 1103272cc70bSAndy Fleming case 3: 1104272cc70bSAndy Fleming mmc->version = MMC_VERSION_3; 1105272cc70bSAndy Fleming break; 1106272cc70bSAndy Fleming case 4: 1107272cc70bSAndy Fleming mmc->version = MMC_VERSION_4; 1108272cc70bSAndy Fleming break; 1109272cc70bSAndy Fleming default: 1110272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1111272cc70bSAndy Fleming break; 1112272cc70bSAndy Fleming } 1113272cc70bSAndy Fleming } 1114272cc70bSAndy Fleming 1115272cc70bSAndy Fleming /* divide frequency by 10, since the mults are 10x bigger */ 11160b453ffeSRabin Vincent freq = fbase[(cmd.response[0] & 0x7)]; 11170b453ffeSRabin Vincent mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; 1118272cc70bSAndy Fleming 1119272cc70bSAndy Fleming mmc->tran_speed = freq * mult; 1120272cc70bSAndy Fleming 1121ab71188cSMarkus Niebel mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1); 1122998be3ddSRabin Vincent mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf); 1123272cc70bSAndy Fleming 1124272cc70bSAndy Fleming if (IS_SD(mmc)) 1125272cc70bSAndy Fleming mmc->write_bl_len = mmc->read_bl_len; 1126272cc70bSAndy Fleming else 1127998be3ddSRabin Vincent mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf); 1128272cc70bSAndy Fleming 1129272cc70bSAndy Fleming if (mmc->high_capacity) { 1130272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3f) << 16 1131272cc70bSAndy Fleming | (mmc->csd[2] & 0xffff0000) >> 16; 1132272cc70bSAndy Fleming cmult = 8; 1133272cc70bSAndy Fleming } else { 1134272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3ff) << 2 1135272cc70bSAndy Fleming | (mmc->csd[2] & 0xc0000000) >> 30; 1136272cc70bSAndy Fleming cmult = (mmc->csd[2] & 0x00038000) >> 15; 1137272cc70bSAndy Fleming } 1138272cc70bSAndy Fleming 1139f866a46dSStephen Warren mmc->capacity_user = (csize + 1) << (cmult + 2); 1140f866a46dSStephen Warren mmc->capacity_user *= mmc->read_bl_len; 1141f866a46dSStephen Warren mmc->capacity_boot = 0; 1142f866a46dSStephen Warren mmc->capacity_rpmb = 0; 1143f866a46dSStephen Warren for (i = 0; i < 4; i++) 1144f866a46dSStephen Warren mmc->capacity_gp[i] = 0; 1145272cc70bSAndy Fleming 11468bfa195eSSimon Glass if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN) 11478bfa195eSSimon Glass mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 1148272cc70bSAndy Fleming 11498bfa195eSSimon Glass if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN) 11508bfa195eSSimon Glass mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 1151272cc70bSAndy Fleming 1152ab71188cSMarkus Niebel if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) { 1153ab71188cSMarkus Niebel cmd.cmdidx = MMC_CMD_SET_DSR; 1154ab71188cSMarkus Niebel cmd.cmdarg = (mmc->dsr & 0xffff) << 16; 1155ab71188cSMarkus Niebel cmd.resp_type = MMC_RSP_NONE; 1156ab71188cSMarkus Niebel if (mmc_send_cmd(mmc, &cmd, NULL)) 1157ab71188cSMarkus Niebel printf("MMC: SET_DSR failed\n"); 1158ab71188cSMarkus Niebel } 1159ab71188cSMarkus Niebel 1160272cc70bSAndy Fleming /* Select the card, and put it into Transfer Mode */ 1161d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1162272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SELECT_CARD; 1163fe8f7066SAjay Bhargav cmd.resp_type = MMC_RSP_R1; 1164272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1165272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1166272cc70bSAndy Fleming 1167272cc70bSAndy Fleming if (err) 1168272cc70bSAndy Fleming return err; 1169d52ebf10SThomas Chou } 1170272cc70bSAndy Fleming 1171e6f99a56SLei Wen /* 1172e6f99a56SLei Wen * For SD, its erase group is always one sector 1173e6f99a56SLei Wen */ 1174e6f99a56SLei Wen mmc->erase_grp_size = 1; 1175bc897b1dSLei Wen mmc->part_config = MMCPART_NOAVAILABLE; 1176d23e2c09SSukumar Ghorai if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) { 1177d23e2c09SSukumar Ghorai /* check ext_csd version and capacity */ 1178d23e2c09SSukumar Ghorai err = mmc_send_ext_csd(mmc, ext_csd); 11799cf199ebSDiego Santa Cruz if (err) 11809cf199ebSDiego Santa Cruz return err; 11819cf199ebSDiego Santa Cruz if (ext_csd[EXT_CSD_REV] >= 2) { 1182639b7827SYoshihiro Shimoda /* 1183639b7827SYoshihiro Shimoda * According to the JEDEC Standard, the value of 1184639b7827SYoshihiro Shimoda * ext_csd's capacity is valid if the value is more 1185639b7827SYoshihiro Shimoda * than 2GB 1186639b7827SYoshihiro Shimoda */ 11870560db18SLei Wen capacity = ext_csd[EXT_CSD_SEC_CNT] << 0 11880560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 11890560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 11900560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; 11918bfa195eSSimon Glass capacity *= MMC_MAX_BLOCK_LEN; 1192b1f1e821SŁukasz Majewski if ((capacity >> 20) > 2 * 1024) 1193f866a46dSStephen Warren mmc->capacity_user = capacity; 1194d23e2c09SSukumar Ghorai } 1195bc897b1dSLei Wen 119664f4a619SJaehoon Chung switch (ext_csd[EXT_CSD_REV]) { 119764f4a619SJaehoon Chung case 1: 119864f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_1; 119964f4a619SJaehoon Chung break; 120064f4a619SJaehoon Chung case 2: 120164f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_2; 120264f4a619SJaehoon Chung break; 120364f4a619SJaehoon Chung case 3: 120464f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_3; 120564f4a619SJaehoon Chung break; 120664f4a619SJaehoon Chung case 5: 120764f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_41; 120864f4a619SJaehoon Chung break; 120964f4a619SJaehoon Chung case 6: 121064f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_5; 121164f4a619SJaehoon Chung break; 1212edab723bSMarkus Niebel case 7: 1213edab723bSMarkus Niebel mmc->version = MMC_VERSION_5_0; 1214edab723bSMarkus Niebel break; 121564f4a619SJaehoon Chung } 121664f4a619SJaehoon Chung 12178a0cf490SDiego Santa Cruz /* The partition data may be non-zero but it is only 12188a0cf490SDiego Santa Cruz * effective if PARTITION_SETTING_COMPLETED is set in 12198a0cf490SDiego Santa Cruz * EXT_CSD, so ignore any data if this bit is not set, 12208a0cf490SDiego Santa Cruz * except for enabling the high-capacity group size 12218a0cf490SDiego Santa Cruz * definition (see below). */ 12228a0cf490SDiego Santa Cruz part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] & 12238a0cf490SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED); 12248a0cf490SDiego Santa Cruz 12250c453bb7SDiego Santa Cruz /* store the partition info of emmc */ 12260c453bb7SDiego Santa Cruz mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT]; 12270c453bb7SDiego Santa Cruz if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || 12280c453bb7SDiego Santa Cruz ext_csd[EXT_CSD_BOOT_MULT]) 12290c453bb7SDiego Santa Cruz mmc->part_config = ext_csd[EXT_CSD_PART_CONF]; 12308a0cf490SDiego Santa Cruz if (part_completed && 12318a0cf490SDiego Santa Cruz (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT)) 12320c453bb7SDiego Santa Cruz mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]; 12330c453bb7SDiego Santa Cruz 12340c453bb7SDiego Santa Cruz mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17; 12350c453bb7SDiego Santa Cruz 12360c453bb7SDiego Santa Cruz mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17; 12370c453bb7SDiego Santa Cruz 12380c453bb7SDiego Santa Cruz for (i = 0; i < 4; i++) { 12390c453bb7SDiego Santa Cruz int idx = EXT_CSD_GP_SIZE_MULT + i * 3; 12408a0cf490SDiego Santa Cruz uint mult = (ext_csd[idx + 2] << 16) + 12410c453bb7SDiego Santa Cruz (ext_csd[idx + 1] << 8) + ext_csd[idx]; 12428a0cf490SDiego Santa Cruz if (mult) 12438a0cf490SDiego Santa Cruz has_parts = true; 12448a0cf490SDiego Santa Cruz if (!part_completed) 12458a0cf490SDiego Santa Cruz continue; 12468a0cf490SDiego Santa Cruz mmc->capacity_gp[i] = mult; 12470c453bb7SDiego Santa Cruz mmc->capacity_gp[i] *= 12480c453bb7SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 12490c453bb7SDiego Santa Cruz mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1250f8e89d67SDiego Santa Cruz mmc->capacity_gp[i] <<= 19; 12510c453bb7SDiego Santa Cruz } 12520c453bb7SDiego Santa Cruz 12538a0cf490SDiego Santa Cruz if (part_completed) { 1254a7f852b6SDiego Santa Cruz mmc->enh_user_size = 1255a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_SIZE_MULT+2] << 16) + 1256a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_SIZE_MULT+1] << 8) + 1257a7f852b6SDiego Santa Cruz ext_csd[EXT_CSD_ENH_SIZE_MULT]; 1258a7f852b6SDiego Santa Cruz mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 1259a7f852b6SDiego Santa Cruz mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1260a7f852b6SDiego Santa Cruz mmc->enh_user_size <<= 19; 1261a7f852b6SDiego Santa Cruz mmc->enh_user_start = 1262a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_START_ADDR+3] << 24) + 1263a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_START_ADDR+2] << 16) + 1264a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_START_ADDR+1] << 8) + 1265a7f852b6SDiego Santa Cruz ext_csd[EXT_CSD_ENH_START_ADDR]; 1266a7f852b6SDiego Santa Cruz if (mmc->high_capacity) 1267a7f852b6SDiego Santa Cruz mmc->enh_user_start <<= 9; 12688a0cf490SDiego Santa Cruz } 1269a7f852b6SDiego Santa Cruz 1270e6f99a56SLei Wen /* 12711937e5aaSOliver Metz * Host needs to enable ERASE_GRP_DEF bit if device is 12721937e5aaSOliver Metz * partitioned. This bit will be lost every time after a reset 12731937e5aaSOliver Metz * or power off. This will affect erase size. 1274e6f99a56SLei Wen */ 12758a0cf490SDiego Santa Cruz if (part_completed) 12760c453bb7SDiego Santa Cruz has_parts = true; 12771937e5aaSOliver Metz if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) && 12780c453bb7SDiego Santa Cruz (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) 12790c453bb7SDiego Santa Cruz has_parts = true; 12800c453bb7SDiego Santa Cruz if (has_parts) { 12811937e5aaSOliver Metz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 12821937e5aaSOliver Metz EXT_CSD_ERASE_GROUP_DEF, 1); 12831937e5aaSOliver Metz 12841937e5aaSOliver Metz if (err) 12851937e5aaSOliver Metz return err; 1286021a8055SHannes Petermaier else 1287021a8055SHannes Petermaier ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 1288037dc0abSDiego Santa Cruz } 12891937e5aaSOliver Metz 1290037dc0abSDiego Santa Cruz if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) { 12911937e5aaSOliver Metz /* Read out group size from ext_csd */ 12920560db18SLei Wen mmc->erase_grp_size = 1293a4ff9f83SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 1294d7b29129SMarkus Niebel /* 1295d7b29129SMarkus Niebel * if high capacity and partition setting completed 1296d7b29129SMarkus Niebel * SEC_COUNT is valid even if it is smaller than 2 GiB 1297d7b29129SMarkus Niebel * JEDEC Standard JESD84-B45, 6.2.4 1298d7b29129SMarkus Niebel */ 12998a0cf490SDiego Santa Cruz if (mmc->high_capacity && part_completed) { 1300d7b29129SMarkus Niebel capacity = (ext_csd[EXT_CSD_SEC_CNT]) | 1301d7b29129SMarkus Niebel (ext_csd[EXT_CSD_SEC_CNT + 1] << 8) | 1302d7b29129SMarkus Niebel (ext_csd[EXT_CSD_SEC_CNT + 2] << 16) | 1303d7b29129SMarkus Niebel (ext_csd[EXT_CSD_SEC_CNT + 3] << 24); 1304d7b29129SMarkus Niebel capacity *= MMC_MAX_BLOCK_LEN; 1305d7b29129SMarkus Niebel mmc->capacity_user = capacity; 1306d7b29129SMarkus Niebel } 13078bfa195eSSimon Glass } else { 13081937e5aaSOliver Metz /* Calculate the group size from the csd value. */ 1309e6f99a56SLei Wen int erase_gsz, erase_gmul; 1310e6f99a56SLei Wen erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10; 1311e6f99a56SLei Wen erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5; 1312e6f99a56SLei Wen mmc->erase_grp_size = (erase_gsz + 1) 1313e6f99a56SLei Wen * (erase_gmul + 1); 1314e6f99a56SLei Wen } 1315037dc0abSDiego Santa Cruz 1316037dc0abSDiego Santa Cruz mmc->hc_wp_grp_size = 1024 1317037dc0abSDiego Santa Cruz * ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 1318037dc0abSDiego Santa Cruz * ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 13199e41a00bSDiego Santa Cruz 13209e41a00bSDiego Santa Cruz mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 1321f866a46dSStephen Warren } 1322f866a46dSStephen Warren 1323f866a46dSStephen Warren err = mmc_set_capacity(mmc, mmc->part_num); 1324f866a46dSStephen Warren if (err) 1325f866a46dSStephen Warren return err; 1326d23e2c09SSukumar Ghorai 1327272cc70bSAndy Fleming if (IS_SD(mmc)) 1328272cc70bSAndy Fleming err = sd_change_freq(mmc); 1329272cc70bSAndy Fleming else 1330272cc70bSAndy Fleming err = mmc_change_freq(mmc); 1331272cc70bSAndy Fleming 1332272cc70bSAndy Fleming if (err) 1333272cc70bSAndy Fleming return err; 1334272cc70bSAndy Fleming 1335272cc70bSAndy Fleming /* Restrict card's capabilities by what the host can do */ 133693bfd616SPantelis Antoniou mmc->card_caps &= mmc->cfg->host_caps; 1337272cc70bSAndy Fleming 1338272cc70bSAndy Fleming if (IS_SD(mmc)) { 1339272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_4BIT) { 1340272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 1341272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1342272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1343272cc70bSAndy Fleming 1344272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1345272cc70bSAndy Fleming if (err) 1346272cc70bSAndy Fleming return err; 1347272cc70bSAndy Fleming 1348272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH; 1349272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1350272cc70bSAndy Fleming cmd.cmdarg = 2; 1351272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1352272cc70bSAndy Fleming if (err) 1353272cc70bSAndy Fleming return err; 1354272cc70bSAndy Fleming 1355272cc70bSAndy Fleming mmc_set_bus_width(mmc, 4); 1356272cc70bSAndy Fleming } 1357272cc70bSAndy Fleming 1358272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_HS) 1359ad5fd922SJaehoon Chung mmc->tran_speed = 50000000; 1360272cc70bSAndy Fleming else 1361ad5fd922SJaehoon Chung mmc->tran_speed = 25000000; 1362fc5b32fbSAndrew Gabbasov } else if (mmc->version >= MMC_VERSION_4) { 1363fc5b32fbSAndrew Gabbasov /* Only version 4 of MMC supports wider bus widths */ 13647798f6dbSAndy Fleming int idx; 13657798f6dbSAndy Fleming 13667798f6dbSAndy Fleming /* An array of possible bus widths in order of preference */ 13677798f6dbSAndy Fleming static unsigned ext_csd_bits[] = { 1368d22e3d46SJaehoon Chung EXT_CSD_DDR_BUS_WIDTH_8, 1369d22e3d46SJaehoon Chung EXT_CSD_DDR_BUS_WIDTH_4, 13707798f6dbSAndy Fleming EXT_CSD_BUS_WIDTH_8, 13717798f6dbSAndy Fleming EXT_CSD_BUS_WIDTH_4, 13727798f6dbSAndy Fleming EXT_CSD_BUS_WIDTH_1, 13737798f6dbSAndy Fleming }; 13747798f6dbSAndy Fleming 13757798f6dbSAndy Fleming /* An array to map CSD bus widths to host cap bits */ 13767798f6dbSAndy Fleming static unsigned ext_to_hostcaps[] = { 1377786e8f81SAndrew Gabbasov [EXT_CSD_DDR_BUS_WIDTH_4] = 1378786e8f81SAndrew Gabbasov MMC_MODE_DDR_52MHz | MMC_MODE_4BIT, 1379786e8f81SAndrew Gabbasov [EXT_CSD_DDR_BUS_WIDTH_8] = 1380786e8f81SAndrew Gabbasov MMC_MODE_DDR_52MHz | MMC_MODE_8BIT, 13817798f6dbSAndy Fleming [EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT, 13827798f6dbSAndy Fleming [EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT, 13837798f6dbSAndy Fleming }; 13847798f6dbSAndy Fleming 13857798f6dbSAndy Fleming /* An array to map chosen bus width to an integer */ 13867798f6dbSAndy Fleming static unsigned widths[] = { 1387d22e3d46SJaehoon Chung 8, 4, 8, 4, 1, 13887798f6dbSAndy Fleming }; 13897798f6dbSAndy Fleming 13907798f6dbSAndy Fleming for (idx=0; idx < ARRAY_SIZE(ext_csd_bits); idx++) { 13917798f6dbSAndy Fleming unsigned int extw = ext_csd_bits[idx]; 1392786e8f81SAndrew Gabbasov unsigned int caps = ext_to_hostcaps[extw]; 13937798f6dbSAndy Fleming 13947798f6dbSAndy Fleming /* 1395bf477073SAndrew Gabbasov * If the bus width is still not changed, 1396bf477073SAndrew Gabbasov * don't try to set the default again. 1397bf477073SAndrew Gabbasov * Otherwise, recover from switch attempts 1398bf477073SAndrew Gabbasov * by switching to 1-bit bus width. 1399bf477073SAndrew Gabbasov */ 1400bf477073SAndrew Gabbasov if (extw == EXT_CSD_BUS_WIDTH_1 && 1401bf477073SAndrew Gabbasov mmc->bus_width == 1) { 1402bf477073SAndrew Gabbasov err = 0; 1403bf477073SAndrew Gabbasov break; 1404bf477073SAndrew Gabbasov } 1405bf477073SAndrew Gabbasov 1406bf477073SAndrew Gabbasov /* 1407786e8f81SAndrew Gabbasov * Check to make sure the card and controller support 1408786e8f81SAndrew Gabbasov * these capabilities 14097798f6dbSAndy Fleming */ 1410786e8f81SAndrew Gabbasov if ((mmc->card_caps & caps) != caps) 14117798f6dbSAndy Fleming continue; 14127798f6dbSAndy Fleming 1413272cc70bSAndy Fleming err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 14147798f6dbSAndy Fleming EXT_CSD_BUS_WIDTH, extw); 1415272cc70bSAndy Fleming 1416272cc70bSAndy Fleming if (err) 14174137894eSLei Wen continue; 1418272cc70bSAndy Fleming 1419786e8f81SAndrew Gabbasov mmc->ddr_mode = (caps & MMC_MODE_DDR_52MHz) ? 1 : 0; 14207798f6dbSAndy Fleming mmc_set_bus_width(mmc, widths[idx]); 1421272cc70bSAndy Fleming 14224137894eSLei Wen err = mmc_send_ext_csd(mmc, test_csd); 1423272cc70bSAndy Fleming 1424786e8f81SAndrew Gabbasov if (err) 1425786e8f81SAndrew Gabbasov continue; 1426786e8f81SAndrew Gabbasov 1427786e8f81SAndrew Gabbasov /* Only compare read only fields */ 1428786e8f81SAndrew Gabbasov if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] 1429786e8f81SAndrew Gabbasov == test_csd[EXT_CSD_PARTITIONING_SUPPORT] && 1430786e8f81SAndrew Gabbasov ext_csd[EXT_CSD_HC_WP_GRP_SIZE] 1431786e8f81SAndrew Gabbasov == test_csd[EXT_CSD_HC_WP_GRP_SIZE] && 1432786e8f81SAndrew Gabbasov ext_csd[EXT_CSD_REV] 1433786e8f81SAndrew Gabbasov == test_csd[EXT_CSD_REV] && 1434786e8f81SAndrew Gabbasov ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 1435786e8f81SAndrew Gabbasov == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] && 1436786e8f81SAndrew Gabbasov memcmp(&ext_csd[EXT_CSD_SEC_CNT], 1437786e8f81SAndrew Gabbasov &test_csd[EXT_CSD_SEC_CNT], 4) == 0) 14384137894eSLei Wen break; 1439786e8f81SAndrew Gabbasov else 1440786e8f81SAndrew Gabbasov err = SWITCH_ERR; 14414137894eSLei Wen } 1442786e8f81SAndrew Gabbasov 1443786e8f81SAndrew Gabbasov if (err) 1444786e8f81SAndrew Gabbasov return err; 1445272cc70bSAndy Fleming 1446272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_HS) { 1447272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_HS_52MHz) 1448ad5fd922SJaehoon Chung mmc->tran_speed = 52000000; 1449272cc70bSAndy Fleming else 1450ad5fd922SJaehoon Chung mmc->tran_speed = 26000000; 1451272cc70bSAndy Fleming } 1452ad5fd922SJaehoon Chung } 1453ad5fd922SJaehoon Chung 1454ad5fd922SJaehoon Chung mmc_set_clock(mmc, mmc->tran_speed); 1455272cc70bSAndy Fleming 14565af8f45cSAndrew Gabbasov /* Fix the block length for DDR mode */ 14575af8f45cSAndrew Gabbasov if (mmc->ddr_mode) { 14585af8f45cSAndrew Gabbasov mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 14595af8f45cSAndrew Gabbasov mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 14605af8f45cSAndrew Gabbasov } 14615af8f45cSAndrew Gabbasov 1462272cc70bSAndy Fleming /* fill in device description */ 1463272cc70bSAndy Fleming mmc->block_dev.lun = 0; 1464272cc70bSAndy Fleming mmc->block_dev.type = 0; 1465272cc70bSAndy Fleming mmc->block_dev.blksz = mmc->read_bl_len; 14660472fbfdSEgbert Eich mmc->block_dev.log2blksz = LOG2(mmc->block_dev.blksz); 14679b1f942cSRabin Vincent mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len); 146856196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 1469babce5f6STaylor Hutt sprintf(mmc->block_dev.vendor, "Man %06x Snr %04x%04x", 1470babce5f6STaylor Hutt mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff), 1471babce5f6STaylor Hutt (mmc->cid[3] >> 16) & 0xffff); 1472babce5f6STaylor Hutt sprintf(mmc->block_dev.product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff, 14730b453ffeSRabin Vincent (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, 1474babce5f6STaylor Hutt (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff, 1475babce5f6STaylor Hutt (mmc->cid[2] >> 24) & 0xff); 1476babce5f6STaylor Hutt sprintf(mmc->block_dev.revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf, 1477babce5f6STaylor Hutt (mmc->cid[2] >> 16) & 0xf); 147856196826SPaul Burton #else 147956196826SPaul Burton mmc->block_dev.vendor[0] = 0; 148056196826SPaul Burton mmc->block_dev.product[0] = 0; 148156196826SPaul Burton mmc->block_dev.revision[0] = 0; 148256196826SPaul Burton #endif 1483122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT) 1484272cc70bSAndy Fleming init_part(&mmc->block_dev); 1485122efd43SMikhail Kshevetskiy #endif 1486272cc70bSAndy Fleming 1487272cc70bSAndy Fleming return 0; 1488272cc70bSAndy Fleming } 1489272cc70bSAndy Fleming 1490fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc) 1491272cc70bSAndy Fleming { 1492272cc70bSAndy Fleming struct mmc_cmd cmd; 1493272cc70bSAndy Fleming int err; 1494272cc70bSAndy Fleming 1495272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_IF_COND; 1496272cc70bSAndy Fleming /* We set the bit if the host supports voltages between 2.7 and 3.6 V */ 149793bfd616SPantelis Antoniou cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa; 1498272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R7; 1499272cc70bSAndy Fleming 1500272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1501272cc70bSAndy Fleming 1502272cc70bSAndy Fleming if (err) 1503272cc70bSAndy Fleming return err; 1504272cc70bSAndy Fleming 1505998be3ddSRabin Vincent if ((cmd.response[0] & 0xff) != 0xaa) 1506272cc70bSAndy Fleming return UNUSABLE_ERR; 1507272cc70bSAndy Fleming else 1508272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 1509272cc70bSAndy Fleming 1510272cc70bSAndy Fleming return 0; 1511272cc70bSAndy Fleming } 1512272cc70bSAndy Fleming 151393bfd616SPantelis Antoniou /* not used any more */ 151493bfd616SPantelis Antoniou int __deprecated mmc_register(struct mmc *mmc) 1515272cc70bSAndy Fleming { 151693bfd616SPantelis Antoniou #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 151793bfd616SPantelis Antoniou printf("%s is deprecated! use mmc_create() instead.\n", __func__); 151893bfd616SPantelis Antoniou #endif 151993bfd616SPantelis Antoniou return -1; 152093bfd616SPantelis Antoniou } 152193bfd616SPantelis Antoniou 152293bfd616SPantelis Antoniou struct mmc *mmc_create(const struct mmc_config *cfg, void *priv) 152393bfd616SPantelis Antoniou { 152493bfd616SPantelis Antoniou struct mmc *mmc; 152593bfd616SPantelis Antoniou 152693bfd616SPantelis Antoniou /* quick validation */ 152793bfd616SPantelis Antoniou if (cfg == NULL || cfg->ops == NULL || cfg->ops->send_cmd == NULL || 152893bfd616SPantelis Antoniou cfg->f_min == 0 || cfg->f_max == 0 || cfg->b_max == 0) 152993bfd616SPantelis Antoniou return NULL; 153093bfd616SPantelis Antoniou 153193bfd616SPantelis Antoniou mmc = calloc(1, sizeof(*mmc)); 153293bfd616SPantelis Antoniou if (mmc == NULL) 153393bfd616SPantelis Antoniou return NULL; 153493bfd616SPantelis Antoniou 153593bfd616SPantelis Antoniou mmc->cfg = cfg; 153693bfd616SPantelis Antoniou mmc->priv = priv; 153793bfd616SPantelis Antoniou 153893bfd616SPantelis Antoniou /* the following chunk was mmc_register() */ 153993bfd616SPantelis Antoniou 1540ab71188cSMarkus Niebel /* Setup dsr related values */ 1541ab71188cSMarkus Niebel mmc->dsr_imp = 0; 1542ab71188cSMarkus Niebel mmc->dsr = 0xffffffff; 1543272cc70bSAndy Fleming /* Setup the universal parts of the block interface just once */ 1544272cc70bSAndy Fleming mmc->block_dev.if_type = IF_TYPE_MMC; 1545272cc70bSAndy Fleming mmc->block_dev.dev = cur_dev_num++; 1546272cc70bSAndy Fleming mmc->block_dev.removable = 1; 1547272cc70bSAndy Fleming mmc->block_dev.block_read = mmc_bread; 1548272cc70bSAndy Fleming mmc->block_dev.block_write = mmc_bwrite; 1549e6f99a56SLei Wen mmc->block_dev.block_erase = mmc_berase; 155093bfd616SPantelis Antoniou 155193bfd616SPantelis Antoniou /* setup initial part type */ 155293bfd616SPantelis Antoniou mmc->block_dev.part_type = mmc->cfg->part_type; 1553272cc70bSAndy Fleming 1554272cc70bSAndy Fleming INIT_LIST_HEAD(&mmc->link); 1555272cc70bSAndy Fleming 1556272cc70bSAndy Fleming list_add_tail(&mmc->link, &mmc_devices); 1557272cc70bSAndy Fleming 155893bfd616SPantelis Antoniou return mmc; 155993bfd616SPantelis Antoniou } 156093bfd616SPantelis Antoniou 156193bfd616SPantelis Antoniou void mmc_destroy(struct mmc *mmc) 156293bfd616SPantelis Antoniou { 156393bfd616SPantelis Antoniou /* only freeing memory for now */ 156493bfd616SPantelis Antoniou free(mmc); 1565272cc70bSAndy Fleming } 1566272cc70bSAndy Fleming 1567df3fc526SMatthew McClintock #ifdef CONFIG_PARTITIONS 1568272cc70bSAndy Fleming block_dev_desc_t *mmc_get_dev(int dev) 1569272cc70bSAndy Fleming { 1570272cc70bSAndy Fleming struct mmc *mmc = find_mmc_device(dev); 15716bb4b4bcSBenoît Thébaudeau if (!mmc || mmc_init(mmc)) 157240242bc3SŁukasz Majewski return NULL; 1573272cc70bSAndy Fleming 157440242bc3SŁukasz Majewski return &mmc->block_dev; 1575272cc70bSAndy Fleming } 1576df3fc526SMatthew McClintock #endif 1577272cc70bSAndy Fleming 157895de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */ 157995de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void) 158095de9ab2SPaul Kocialkowski { 158195de9ab2SPaul Kocialkowski } 158295de9ab2SPaul Kocialkowski 1583e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc) 1584272cc70bSAndy Fleming { 1585afd5932bSMacpaul Lin int err; 1586272cc70bSAndy Fleming 1587ab769f22SPantelis Antoniou /* we pretend there's no card when init is NULL */ 158893bfd616SPantelis Antoniou if (mmc_getcd(mmc) == 0 || mmc->cfg->ops->init == NULL) { 158948972d90SThierry Reding mmc->has_init = 0; 159056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 159148972d90SThierry Reding printf("MMC: no card present\n"); 159256196826SPaul Burton #endif 159348972d90SThierry Reding return NO_CARD_ERR; 159448972d90SThierry Reding } 159548972d90SThierry Reding 1596bc897b1dSLei Wen if (mmc->has_init) 1597bc897b1dSLei Wen return 0; 1598bc897b1dSLei Wen 159995de9ab2SPaul Kocialkowski board_mmc_power_init(); 160095de9ab2SPaul Kocialkowski 1601ab769f22SPantelis Antoniou /* made sure it's not NULL earlier */ 160293bfd616SPantelis Antoniou err = mmc->cfg->ops->init(mmc); 1603272cc70bSAndy Fleming 1604272cc70bSAndy Fleming if (err) 1605272cc70bSAndy Fleming return err; 1606272cc70bSAndy Fleming 1607786e8f81SAndrew Gabbasov mmc->ddr_mode = 0; 1608b86b85e2SIlya Yanok mmc_set_bus_width(mmc, 1); 1609b86b85e2SIlya Yanok mmc_set_clock(mmc, 1); 1610b86b85e2SIlya Yanok 1611272cc70bSAndy Fleming /* Reset the Card */ 1612272cc70bSAndy Fleming err = mmc_go_idle(mmc); 1613272cc70bSAndy Fleming 1614272cc70bSAndy Fleming if (err) 1615272cc70bSAndy Fleming return err; 1616272cc70bSAndy Fleming 1617bc897b1dSLei Wen /* The internal partition reset to user partition(0) at every CMD0*/ 1618bc897b1dSLei Wen mmc->part_num = 0; 1619bc897b1dSLei Wen 1620272cc70bSAndy Fleming /* Test for SD version 2 */ 1621272cc70bSAndy Fleming err = mmc_send_if_cond(mmc); 1622272cc70bSAndy Fleming 1623272cc70bSAndy Fleming /* Now try to get the SD card's operating condition */ 1624272cc70bSAndy Fleming err = sd_send_op_cond(mmc); 1625272cc70bSAndy Fleming 1626272cc70bSAndy Fleming /* If the command timed out, we check for an MMC card */ 1627272cc70bSAndy Fleming if (err == TIMEOUT) { 1628272cc70bSAndy Fleming err = mmc_send_op_cond(mmc); 1629272cc70bSAndy Fleming 1630*bd47c135SAndrew Gabbasov if (err) { 163156196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 1632272cc70bSAndy Fleming printf("Card did not respond to voltage select!\n"); 163356196826SPaul Burton #endif 1634272cc70bSAndy Fleming return UNUSABLE_ERR; 1635272cc70bSAndy Fleming } 1636272cc70bSAndy Fleming } 1637272cc70bSAndy Fleming 1638*bd47c135SAndrew Gabbasov if (!err) 1639e9550449SChe-Liang Chiou mmc->init_in_progress = 1; 1640e9550449SChe-Liang Chiou 1641e9550449SChe-Liang Chiou return err; 1642e9550449SChe-Liang Chiou } 1643e9550449SChe-Liang Chiou 1644e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc) 1645e9550449SChe-Liang Chiou { 1646e9550449SChe-Liang Chiou int err = 0; 1647e9550449SChe-Liang Chiou 1648*bd47c135SAndrew Gabbasov mmc->init_in_progress = 0; 1649e9550449SChe-Liang Chiou if (mmc->op_cond_pending) 1650e9550449SChe-Liang Chiou err = mmc_complete_op_cond(mmc); 1651e9550449SChe-Liang Chiou 1652e9550449SChe-Liang Chiou if (!err) 1653bc897b1dSLei Wen err = mmc_startup(mmc); 1654bc897b1dSLei Wen if (err) 1655bc897b1dSLei Wen mmc->has_init = 0; 1656bc897b1dSLei Wen else 1657bc897b1dSLei Wen mmc->has_init = 1; 1658e9550449SChe-Liang Chiou return err; 1659e9550449SChe-Liang Chiou } 1660e9550449SChe-Liang Chiou 1661e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc) 1662e9550449SChe-Liang Chiou { 1663*bd47c135SAndrew Gabbasov int err = 0; 1664d803fea5SMateusz Zalega unsigned start; 1665e9550449SChe-Liang Chiou 1666e9550449SChe-Liang Chiou if (mmc->has_init) 1667e9550449SChe-Liang Chiou return 0; 1668d803fea5SMateusz Zalega 1669d803fea5SMateusz Zalega start = get_timer(0); 1670d803fea5SMateusz Zalega 1671e9550449SChe-Liang Chiou if (!mmc->init_in_progress) 1672e9550449SChe-Liang Chiou err = mmc_start_init(mmc); 1673e9550449SChe-Liang Chiou 1674*bd47c135SAndrew Gabbasov if (!err) 1675e9550449SChe-Liang Chiou err = mmc_complete_init(mmc); 1676e9550449SChe-Liang Chiou debug("%s: %d, time %lu\n", __func__, err, get_timer(start)); 1677bc897b1dSLei Wen return err; 1678272cc70bSAndy Fleming } 1679272cc70bSAndy Fleming 1680ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val) 1681ab71188cSMarkus Niebel { 1682ab71188cSMarkus Niebel mmc->dsr = val; 1683ab71188cSMarkus Niebel return 0; 1684ab71188cSMarkus Niebel } 1685ab71188cSMarkus Niebel 1686cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */ 1687cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis) 1688272cc70bSAndy Fleming { 1689272cc70bSAndy Fleming return -1; 1690272cc70bSAndy Fleming } 1691272cc70bSAndy Fleming 1692cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */ 1693cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis) 1694cee9ab7cSJeroen Hofstee { 1695cee9ab7cSJeroen Hofstee return -1; 1696cee9ab7cSJeroen Hofstee } 1697272cc70bSAndy Fleming 169856196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 169956196826SPaul Burton 1700272cc70bSAndy Fleming void print_mmc_devices(char separator) 1701272cc70bSAndy Fleming { 1702272cc70bSAndy Fleming struct mmc *m; 1703272cc70bSAndy Fleming struct list_head *entry; 170434dd9284SPrzemyslaw Marczak char *mmc_type; 1705272cc70bSAndy Fleming 1706272cc70bSAndy Fleming list_for_each(entry, &mmc_devices) { 1707272cc70bSAndy Fleming m = list_entry(entry, struct mmc, link); 1708272cc70bSAndy Fleming 170934dd9284SPrzemyslaw Marczak if (m->has_init) 171034dd9284SPrzemyslaw Marczak mmc_type = IS_SD(m) ? "SD" : "eMMC"; 171134dd9284SPrzemyslaw Marczak else 171234dd9284SPrzemyslaw Marczak mmc_type = NULL; 171334dd9284SPrzemyslaw Marczak 171493bfd616SPantelis Antoniou printf("%s: %d", m->cfg->name, m->block_dev.dev); 171534dd9284SPrzemyslaw Marczak if (mmc_type) 171634dd9284SPrzemyslaw Marczak printf(" (%s)", mmc_type); 1717272cc70bSAndy Fleming 1718e75eaf10SLubomir Popov if (entry->next != &mmc_devices) { 1719272cc70bSAndy Fleming printf("%c", separator); 1720e75eaf10SLubomir Popov if (separator != '\n') 1721e75eaf10SLubomir Popov puts (" "); 1722e75eaf10SLubomir Popov } 1723272cc70bSAndy Fleming } 1724272cc70bSAndy Fleming 1725272cc70bSAndy Fleming printf("\n"); 1726272cc70bSAndy Fleming } 1727272cc70bSAndy Fleming 172856196826SPaul Burton #else 172956196826SPaul Burton void print_mmc_devices(char separator) { } 173056196826SPaul Burton #endif 173156196826SPaul Burton 1732ea6ebe21SLei Wen int get_mmc_num(void) 1733ea6ebe21SLei Wen { 1734ea6ebe21SLei Wen return cur_dev_num; 1735ea6ebe21SLei Wen } 1736ea6ebe21SLei Wen 1737e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit) 1738e9550449SChe-Liang Chiou { 1739e9550449SChe-Liang Chiou mmc->preinit = preinit; 1740e9550449SChe-Liang Chiou } 1741e9550449SChe-Liang Chiou 1742e9550449SChe-Liang Chiou static void do_preinit(void) 1743e9550449SChe-Liang Chiou { 1744e9550449SChe-Liang Chiou struct mmc *m; 1745e9550449SChe-Liang Chiou struct list_head *entry; 1746e9550449SChe-Liang Chiou 1747e9550449SChe-Liang Chiou list_for_each(entry, &mmc_devices) { 1748e9550449SChe-Liang Chiou m = list_entry(entry, struct mmc, link); 1749e9550449SChe-Liang Chiou 1750e9550449SChe-Liang Chiou if (m->preinit) 1751e9550449SChe-Liang Chiou mmc_start_init(m); 1752e9550449SChe-Liang Chiou } 1753e9550449SChe-Liang Chiou } 1754e9550449SChe-Liang Chiou 1755e9550449SChe-Liang Chiou 1756272cc70bSAndy Fleming int mmc_initialize(bd_t *bis) 1757272cc70bSAndy Fleming { 1758272cc70bSAndy Fleming INIT_LIST_HEAD (&mmc_devices); 1759272cc70bSAndy Fleming cur_dev_num = 0; 1760272cc70bSAndy Fleming 1761272cc70bSAndy Fleming if (board_mmc_init(bis) < 0) 1762272cc70bSAndy Fleming cpu_mmc_init(bis); 1763272cc70bSAndy Fleming 1764bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD 1765272cc70bSAndy Fleming print_mmc_devices(','); 1766bb0dc108SYing Zhang #endif 1767272cc70bSAndy Fleming 1768e9550449SChe-Liang Chiou do_preinit(); 1769272cc70bSAndy Fleming return 0; 1770272cc70bSAndy Fleming } 17713690d6d6SAmar 17723690d6d6SAmar #ifdef CONFIG_SUPPORT_EMMC_BOOT 17733690d6d6SAmar /* 17743690d6d6SAmar * This function changes the size of boot partition and the size of rpmb 17753690d6d6SAmar * partition present on EMMC devices. 17763690d6d6SAmar * 17773690d6d6SAmar * Input Parameters: 17783690d6d6SAmar * struct *mmc: pointer for the mmc device strcuture 17793690d6d6SAmar * bootsize: size of boot partition 17803690d6d6SAmar * rpmbsize: size of rpmb partition 17813690d6d6SAmar * 17823690d6d6SAmar * Returns 0 on success. 17833690d6d6SAmar */ 17843690d6d6SAmar 17853690d6d6SAmar int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize, 17863690d6d6SAmar unsigned long rpmbsize) 17873690d6d6SAmar { 17883690d6d6SAmar int err; 17893690d6d6SAmar struct mmc_cmd cmd; 17903690d6d6SAmar 17913690d6d6SAmar /* Only use this command for raw EMMC moviNAND. Enter backdoor mode */ 17923690d6d6SAmar cmd.cmdidx = MMC_CMD_RES_MAN; 17933690d6d6SAmar cmd.resp_type = MMC_RSP_R1b; 17943690d6d6SAmar cmd.cmdarg = MMC_CMD62_ARG1; 17953690d6d6SAmar 17963690d6d6SAmar err = mmc_send_cmd(mmc, &cmd, NULL); 17973690d6d6SAmar if (err) { 17983690d6d6SAmar debug("mmc_boot_partition_size_change: Error1 = %d\n", err); 17993690d6d6SAmar return err; 18003690d6d6SAmar } 18013690d6d6SAmar 18023690d6d6SAmar /* Boot partition changing mode */ 18033690d6d6SAmar cmd.cmdidx = MMC_CMD_RES_MAN; 18043690d6d6SAmar cmd.resp_type = MMC_RSP_R1b; 18053690d6d6SAmar cmd.cmdarg = MMC_CMD62_ARG2; 18063690d6d6SAmar 18073690d6d6SAmar err = mmc_send_cmd(mmc, &cmd, NULL); 18083690d6d6SAmar if (err) { 18093690d6d6SAmar debug("mmc_boot_partition_size_change: Error2 = %d\n", err); 18103690d6d6SAmar return err; 18113690d6d6SAmar } 18123690d6d6SAmar /* boot partition size is multiple of 128KB */ 18133690d6d6SAmar bootsize = (bootsize * 1024) / 128; 18143690d6d6SAmar 18153690d6d6SAmar /* Arg: boot partition size */ 18163690d6d6SAmar cmd.cmdidx = MMC_CMD_RES_MAN; 18173690d6d6SAmar cmd.resp_type = MMC_RSP_R1b; 18183690d6d6SAmar cmd.cmdarg = bootsize; 18193690d6d6SAmar 18203690d6d6SAmar err = mmc_send_cmd(mmc, &cmd, NULL); 18213690d6d6SAmar if (err) { 18223690d6d6SAmar debug("mmc_boot_partition_size_change: Error3 = %d\n", err); 18233690d6d6SAmar return err; 18243690d6d6SAmar } 18253690d6d6SAmar /* RPMB partition size is multiple of 128KB */ 18263690d6d6SAmar rpmbsize = (rpmbsize * 1024) / 128; 18273690d6d6SAmar /* Arg: RPMB partition size */ 18283690d6d6SAmar cmd.cmdidx = MMC_CMD_RES_MAN; 18293690d6d6SAmar cmd.resp_type = MMC_RSP_R1b; 18303690d6d6SAmar cmd.cmdarg = rpmbsize; 18313690d6d6SAmar 18323690d6d6SAmar err = mmc_send_cmd(mmc, &cmd, NULL); 18333690d6d6SAmar if (err) { 18343690d6d6SAmar debug("mmc_boot_partition_size_change: Error4 = %d\n", err); 18353690d6d6SAmar return err; 18363690d6d6SAmar } 18373690d6d6SAmar return 0; 18383690d6d6SAmar } 18393690d6d6SAmar 18403690d6d6SAmar /* 18415a99b9deSTom Rini * Modify EXT_CSD[177] which is BOOT_BUS_WIDTH 18425a99b9deSTom Rini * based on the passed in values for BOOT_BUS_WIDTH, RESET_BOOT_BUS_WIDTH 18435a99b9deSTom Rini * and BOOT_MODE. 18445a99b9deSTom Rini * 18455a99b9deSTom Rini * Returns 0 on success. 18465a99b9deSTom Rini */ 18475a99b9deSTom Rini int mmc_set_boot_bus_width(struct mmc *mmc, u8 width, u8 reset, u8 mode) 18485a99b9deSTom Rini { 18495a99b9deSTom Rini int err; 18505a99b9deSTom Rini 18515a99b9deSTom Rini err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_BUS_WIDTH, 18525a99b9deSTom Rini EXT_CSD_BOOT_BUS_WIDTH_MODE(mode) | 18535a99b9deSTom Rini EXT_CSD_BOOT_BUS_WIDTH_RESET(reset) | 18545a99b9deSTom Rini EXT_CSD_BOOT_BUS_WIDTH_WIDTH(width)); 18555a99b9deSTom Rini 18565a99b9deSTom Rini if (err) 18575a99b9deSTom Rini return err; 18585a99b9deSTom Rini return 0; 18595a99b9deSTom Rini } 18605a99b9deSTom Rini 18615a99b9deSTom Rini /* 1862792970b0STom Rini * Modify EXT_CSD[179] which is PARTITION_CONFIG (formerly BOOT_CONFIG) 1863792970b0STom Rini * based on the passed in values for BOOT_ACK, BOOT_PARTITION_ENABLE and 1864792970b0STom Rini * PARTITION_ACCESS. 1865792970b0STom Rini * 1866792970b0STom Rini * Returns 0 on success. 1867792970b0STom Rini */ 1868792970b0STom Rini int mmc_set_part_conf(struct mmc *mmc, u8 ack, u8 part_num, u8 access) 1869792970b0STom Rini { 1870792970b0STom Rini int err; 1871792970b0STom Rini 1872792970b0STom Rini err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, 1873792970b0STom Rini EXT_CSD_BOOT_ACK(ack) | 1874792970b0STom Rini EXT_CSD_BOOT_PART_NUM(part_num) | 1875792970b0STom Rini EXT_CSD_PARTITION_ACCESS(access)); 1876792970b0STom Rini 1877792970b0STom Rini if (err) 1878792970b0STom Rini return err; 1879792970b0STom Rini return 0; 1880792970b0STom Rini } 188133ace362STom Rini 188233ace362STom Rini /* 188333ace362STom Rini * Modify EXT_CSD[162] which is RST_n_FUNCTION based on the given value 188433ace362STom Rini * for enable. Note that this is a write-once field for non-zero values. 188533ace362STom Rini * 188633ace362STom Rini * Returns 0 on success. 188733ace362STom Rini */ 188833ace362STom Rini int mmc_set_rst_n_function(struct mmc *mmc, u8 enable) 188933ace362STom Rini { 189033ace362STom Rini return mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_RST_N_FUNCTION, 189133ace362STom Rini enable); 189233ace362STom Rini } 18933690d6d6SAmar #endif 1894