1272cc70bSAndy Fleming /* 2272cc70bSAndy Fleming * Copyright 2008, Freescale Semiconductor, Inc 3272cc70bSAndy Fleming * Andy Fleming 4272cc70bSAndy Fleming * 5272cc70bSAndy Fleming * Based vaguely on the Linux code 6272cc70bSAndy Fleming * 71a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 8272cc70bSAndy Fleming */ 9272cc70bSAndy Fleming 10272cc70bSAndy Fleming #include <config.h> 11272cc70bSAndy Fleming #include <common.h> 12272cc70bSAndy Fleming #include <command.h> 138e3332e2SSjoerd Simons #include <dm.h> 148e3332e2SSjoerd Simons #include <dm/device-internal.h> 15d4622df3SStephen Warren #include <errno.h> 16272cc70bSAndy Fleming #include <mmc.h> 17272cc70bSAndy Fleming #include <part.h> 18272cc70bSAndy Fleming #include <malloc.h> 19cf92e05cSSimon Glass #include <memalign.h> 20272cc70bSAndy Fleming #include <linux/list.h> 219b1f942cSRabin Vincent #include <div64.h> 22da61fa5fSPaul Burton #include "mmc_private.h" 23272cc70bSAndy Fleming 24272cc70bSAndy Fleming static struct list_head mmc_devices; 25272cc70bSAndy Fleming static int cur_dev_num = -1; 26272cc70bSAndy Fleming 27750121c3SJeroen Hofstee __weak int board_mmc_getwp(struct mmc *mmc) 28d23d8d7eSNikita Kiryanov { 29d23d8d7eSNikita Kiryanov return -1; 30d23d8d7eSNikita Kiryanov } 31d23d8d7eSNikita Kiryanov 32d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc) 33d23d8d7eSNikita Kiryanov { 34d23d8d7eSNikita Kiryanov int wp; 35d23d8d7eSNikita Kiryanov 36d23d8d7eSNikita Kiryanov wp = board_mmc_getwp(mmc); 37d23d8d7eSNikita Kiryanov 38d4e1da4eSPeter Korsgaard if (wp < 0) { 3993bfd616SPantelis Antoniou if (mmc->cfg->ops->getwp) 4093bfd616SPantelis Antoniou wp = mmc->cfg->ops->getwp(mmc); 41d4e1da4eSPeter Korsgaard else 42d4e1da4eSPeter Korsgaard wp = 0; 43d4e1da4eSPeter Korsgaard } 44d23d8d7eSNikita Kiryanov 45d23d8d7eSNikita Kiryanov return wp; 46d23d8d7eSNikita Kiryanov } 47d23d8d7eSNikita Kiryanov 48cee9ab7cSJeroen Hofstee __weak int board_mmc_getcd(struct mmc *mmc) 49cee9ab7cSJeroen Hofstee { 5011fdade2SStefano Babic return -1; 5111fdade2SStefano Babic } 5211fdade2SStefano Babic 53da61fa5fSPaul Burton int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) 54272cc70bSAndy Fleming { 555db2fe3aSRaffaele Recalcati int ret; 568635ff9eSMarek Vasut 578635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE 585db2fe3aSRaffaele Recalcati int i; 595db2fe3aSRaffaele Recalcati u8 *ptr; 605db2fe3aSRaffaele Recalcati 615db2fe3aSRaffaele Recalcati printf("CMD_SEND:%d\n", cmd->cmdidx); 625db2fe3aSRaffaele Recalcati printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg); 6393bfd616SPantelis Antoniou ret = mmc->cfg->ops->send_cmd(mmc, cmd, data); 645db2fe3aSRaffaele Recalcati switch (cmd->resp_type) { 655db2fe3aSRaffaele Recalcati case MMC_RSP_NONE: 665db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_NONE\n"); 675db2fe3aSRaffaele Recalcati break; 685db2fe3aSRaffaele Recalcati case MMC_RSP_R1: 695db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n", 705db2fe3aSRaffaele Recalcati cmd->response[0]); 715db2fe3aSRaffaele Recalcati break; 725db2fe3aSRaffaele Recalcati case MMC_RSP_R1b: 735db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n", 745db2fe3aSRaffaele Recalcati cmd->response[0]); 755db2fe3aSRaffaele Recalcati break; 765db2fe3aSRaffaele Recalcati case MMC_RSP_R2: 775db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R2\t\t 0x%08X \n", 785db2fe3aSRaffaele Recalcati cmd->response[0]); 795db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 805db2fe3aSRaffaele Recalcati cmd->response[1]); 815db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 825db2fe3aSRaffaele Recalcati cmd->response[2]); 835db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 845db2fe3aSRaffaele Recalcati cmd->response[3]); 855db2fe3aSRaffaele Recalcati printf("\n"); 865db2fe3aSRaffaele Recalcati printf("\t\t\t\t\tDUMPING DATA\n"); 875db2fe3aSRaffaele Recalcati for (i = 0; i < 4; i++) { 885db2fe3aSRaffaele Recalcati int j; 895db2fe3aSRaffaele Recalcati printf("\t\t\t\t\t%03d - ", i*4); 90146bec79SDirk Behme ptr = (u8 *)&cmd->response[i]; 915db2fe3aSRaffaele Recalcati ptr += 3; 925db2fe3aSRaffaele Recalcati for (j = 0; j < 4; j++) 935db2fe3aSRaffaele Recalcati printf("%02X ", *ptr--); 945db2fe3aSRaffaele Recalcati printf("\n"); 955db2fe3aSRaffaele Recalcati } 965db2fe3aSRaffaele Recalcati break; 975db2fe3aSRaffaele Recalcati case MMC_RSP_R3: 985db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n", 995db2fe3aSRaffaele Recalcati cmd->response[0]); 1005db2fe3aSRaffaele Recalcati break; 1015db2fe3aSRaffaele Recalcati default: 1025db2fe3aSRaffaele Recalcati printf("\t\tERROR MMC rsp not supported\n"); 1035db2fe3aSRaffaele Recalcati break; 1045db2fe3aSRaffaele Recalcati } 1055db2fe3aSRaffaele Recalcati #else 10693bfd616SPantelis Antoniou ret = mmc->cfg->ops->send_cmd(mmc, cmd, data); 1075db2fe3aSRaffaele Recalcati #endif 1088635ff9eSMarek Vasut return ret; 109272cc70bSAndy Fleming } 110272cc70bSAndy Fleming 111da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout) 1125d4fc8d9SRaffaele Recalcati { 1135d4fc8d9SRaffaele Recalcati struct mmc_cmd cmd; 114d617c426SJan Kloetzke int err, retries = 5; 1155d4fc8d9SRaffaele Recalcati #ifdef CONFIG_MMC_TRACE 1165d4fc8d9SRaffaele Recalcati int status; 1175d4fc8d9SRaffaele Recalcati #endif 1185d4fc8d9SRaffaele Recalcati 1195d4fc8d9SRaffaele Recalcati cmd.cmdidx = MMC_CMD_SEND_STATUS; 1205d4fc8d9SRaffaele Recalcati cmd.resp_type = MMC_RSP_R1; 121aaf3d41aSMarek Vasut if (!mmc_host_is_spi(mmc)) 122aaf3d41aSMarek Vasut cmd.cmdarg = mmc->rca << 16; 1235d4fc8d9SRaffaele Recalcati 1241677eef4SAndrew Gabbasov while (1) { 1255d4fc8d9SRaffaele Recalcati err = mmc_send_cmd(mmc, &cmd, NULL); 126d617c426SJan Kloetzke if (!err) { 127d617c426SJan Kloetzke if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) && 128d617c426SJan Kloetzke (cmd.response[0] & MMC_STATUS_CURR_STATE) != 129d617c426SJan Kloetzke MMC_STATE_PRG) 1305d4fc8d9SRaffaele Recalcati break; 131d617c426SJan Kloetzke else if (cmd.response[0] & MMC_STATUS_MASK) { 13256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 133d617c426SJan Kloetzke printf("Status Error: 0x%08X\n", 134d617c426SJan Kloetzke cmd.response[0]); 13556196826SPaul Burton #endif 136d617c426SJan Kloetzke return COMM_ERR; 137d617c426SJan Kloetzke } 138d617c426SJan Kloetzke } else if (--retries < 0) 139d617c426SJan Kloetzke return err; 1405d4fc8d9SRaffaele Recalcati 1411677eef4SAndrew Gabbasov if (timeout-- <= 0) 1421677eef4SAndrew Gabbasov break; 1435d4fc8d9SRaffaele Recalcati 1441677eef4SAndrew Gabbasov udelay(1000); 1451677eef4SAndrew Gabbasov } 1465d4fc8d9SRaffaele Recalcati 1475db2fe3aSRaffaele Recalcati #ifdef CONFIG_MMC_TRACE 1485db2fe3aSRaffaele Recalcati status = (cmd.response[0] & MMC_STATUS_CURR_STATE) >> 9; 1495db2fe3aSRaffaele Recalcati printf("CURR STATE:%d\n", status); 1505db2fe3aSRaffaele Recalcati #endif 1515b0c942fSJongman Heo if (timeout <= 0) { 15256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 1535d4fc8d9SRaffaele Recalcati printf("Timeout waiting card ready\n"); 15456196826SPaul Burton #endif 1555d4fc8d9SRaffaele Recalcati return TIMEOUT; 1565d4fc8d9SRaffaele Recalcati } 1576b2221b0SAndrew Gabbasov if (cmd.response[0] & MMC_STATUS_SWITCH_ERROR) 1586b2221b0SAndrew Gabbasov return SWITCH_ERR; 1595d4fc8d9SRaffaele Recalcati 1605d4fc8d9SRaffaele Recalcati return 0; 1615d4fc8d9SRaffaele Recalcati } 1625d4fc8d9SRaffaele Recalcati 163da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len) 164272cc70bSAndy Fleming { 165272cc70bSAndy Fleming struct mmc_cmd cmd; 166272cc70bSAndy Fleming 167786e8f81SAndrew Gabbasov if (mmc->ddr_mode) 168d22e3d46SJaehoon Chung return 0; 169d22e3d46SJaehoon Chung 170272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SET_BLOCKLEN; 171272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 172272cc70bSAndy Fleming cmd.cmdarg = len; 173272cc70bSAndy Fleming 174272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, NULL); 175272cc70bSAndy Fleming } 176272cc70bSAndy Fleming 177272cc70bSAndy Fleming struct mmc *find_mmc_device(int dev_num) 178272cc70bSAndy Fleming { 179272cc70bSAndy Fleming struct mmc *m; 180272cc70bSAndy Fleming struct list_head *entry; 181272cc70bSAndy Fleming 182272cc70bSAndy Fleming list_for_each(entry, &mmc_devices) { 183272cc70bSAndy Fleming m = list_entry(entry, struct mmc, link); 184272cc70bSAndy Fleming 185272cc70bSAndy Fleming if (m->block_dev.dev == dev_num) 186272cc70bSAndy Fleming return m; 187272cc70bSAndy Fleming } 188272cc70bSAndy Fleming 18956196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 190272cc70bSAndy Fleming printf("MMC Device %d not found\n", dev_num); 19156196826SPaul Burton #endif 192272cc70bSAndy Fleming 193272cc70bSAndy Fleming return NULL; 194272cc70bSAndy Fleming } 195272cc70bSAndy Fleming 196ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start, 197fdbb873eSKim Phillips lbaint_t blkcnt) 198272cc70bSAndy Fleming { 199272cc70bSAndy Fleming struct mmc_cmd cmd; 200272cc70bSAndy Fleming struct mmc_data data; 201272cc70bSAndy Fleming 2024a1a06bcSAlagu Sankar if (blkcnt > 1) 2034a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; 2044a1a06bcSAlagu Sankar else 205272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK; 206272cc70bSAndy Fleming 207272cc70bSAndy Fleming if (mmc->high_capacity) 2084a1a06bcSAlagu Sankar cmd.cmdarg = start; 209272cc70bSAndy Fleming else 2104a1a06bcSAlagu Sankar cmd.cmdarg = start * mmc->read_bl_len; 211272cc70bSAndy Fleming 212272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 213272cc70bSAndy Fleming 214272cc70bSAndy Fleming data.dest = dst; 2154a1a06bcSAlagu Sankar data.blocks = blkcnt; 216272cc70bSAndy Fleming data.blocksize = mmc->read_bl_len; 217272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 218272cc70bSAndy Fleming 2194a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, &data)) 2204a1a06bcSAlagu Sankar return 0; 2214a1a06bcSAlagu Sankar 2224a1a06bcSAlagu Sankar if (blkcnt > 1) { 2234a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; 2244a1a06bcSAlagu Sankar cmd.cmdarg = 0; 2254a1a06bcSAlagu Sankar cmd.resp_type = MMC_RSP_R1b; 2264a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, NULL)) { 22756196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2284a1a06bcSAlagu Sankar printf("mmc fail to send stop cmd\n"); 22956196826SPaul Burton #endif 2304a1a06bcSAlagu Sankar return 0; 2314a1a06bcSAlagu Sankar } 232272cc70bSAndy Fleming } 233272cc70bSAndy Fleming 2344a1a06bcSAlagu Sankar return blkcnt; 235272cc70bSAndy Fleming } 236272cc70bSAndy Fleming 2377c4213f6SStephen Warren static ulong mmc_bread(block_dev_desc_t *block_dev, lbaint_t start, 2387c4213f6SStephen Warren lbaint_t blkcnt, void *dst) 239272cc70bSAndy Fleming { 2407c4213f6SStephen Warren int dev_num = block_dev->dev; 241873cc1d7SStephen Warren int err; 2424a1a06bcSAlagu Sankar lbaint_t cur, blocks_todo = blkcnt; 243272cc70bSAndy Fleming 2444a1a06bcSAlagu Sankar if (blkcnt == 0) 2454a1a06bcSAlagu Sankar return 0; 2464a1a06bcSAlagu Sankar 2474a1a06bcSAlagu Sankar struct mmc *mmc = find_mmc_device(dev_num); 248272cc70bSAndy Fleming if (!mmc) 249272cc70bSAndy Fleming return 0; 250272cc70bSAndy Fleming 251873cc1d7SStephen Warren err = mmc_select_hwpart(dev_num, block_dev->hwpart); 252873cc1d7SStephen Warren if (err < 0) 253873cc1d7SStephen Warren return 0; 254873cc1d7SStephen Warren 255d2bf29e3SLei Wen if ((start + blkcnt) > mmc->block_dev.lba) { 25656196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 257ff8fef56SSascha Silbe printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n", 258d2bf29e3SLei Wen start + blkcnt, mmc->block_dev.lba); 25956196826SPaul Burton #endif 260d2bf29e3SLei Wen return 0; 261d2bf29e3SLei Wen } 262272cc70bSAndy Fleming 26311692991SSimon Glass if (mmc_set_blocklen(mmc, mmc->read_bl_len)) { 26411692991SSimon Glass debug("%s: Failed to set blocklen\n", __func__); 265272cc70bSAndy Fleming return 0; 26611692991SSimon Glass } 267272cc70bSAndy Fleming 2684a1a06bcSAlagu Sankar do { 26993bfd616SPantelis Antoniou cur = (blocks_todo > mmc->cfg->b_max) ? 27093bfd616SPantelis Antoniou mmc->cfg->b_max : blocks_todo; 27111692991SSimon Glass if (mmc_read_blocks(mmc, dst, start, cur) != cur) { 27211692991SSimon Glass debug("%s: Failed to read blocks\n", __func__); 2734a1a06bcSAlagu Sankar return 0; 27411692991SSimon Glass } 2754a1a06bcSAlagu Sankar blocks_todo -= cur; 2764a1a06bcSAlagu Sankar start += cur; 2774a1a06bcSAlagu Sankar dst += cur * mmc->read_bl_len; 2784a1a06bcSAlagu Sankar } while (blocks_todo > 0); 279272cc70bSAndy Fleming 280272cc70bSAndy Fleming return blkcnt; 281272cc70bSAndy Fleming } 282272cc70bSAndy Fleming 283fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc) 284272cc70bSAndy Fleming { 285272cc70bSAndy Fleming struct mmc_cmd cmd; 286272cc70bSAndy Fleming int err; 287272cc70bSAndy Fleming 288272cc70bSAndy Fleming udelay(1000); 289272cc70bSAndy Fleming 290272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_GO_IDLE_STATE; 291272cc70bSAndy Fleming cmd.cmdarg = 0; 292272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_NONE; 293272cc70bSAndy Fleming 294272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 295272cc70bSAndy Fleming 296272cc70bSAndy Fleming if (err) 297272cc70bSAndy Fleming return err; 298272cc70bSAndy Fleming 299272cc70bSAndy Fleming udelay(2000); 300272cc70bSAndy Fleming 301272cc70bSAndy Fleming return 0; 302272cc70bSAndy Fleming } 303272cc70bSAndy Fleming 304fdbb873eSKim Phillips static int sd_send_op_cond(struct mmc *mmc) 305272cc70bSAndy Fleming { 306272cc70bSAndy Fleming int timeout = 1000; 307272cc70bSAndy Fleming int err; 308272cc70bSAndy Fleming struct mmc_cmd cmd; 309272cc70bSAndy Fleming 3101677eef4SAndrew Gabbasov while (1) { 311272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 312272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 313272cc70bSAndy Fleming cmd.cmdarg = 0; 314272cc70bSAndy Fleming 315272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 316272cc70bSAndy Fleming 317272cc70bSAndy Fleming if (err) 318272cc70bSAndy Fleming return err; 319272cc70bSAndy Fleming 320272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_OP_COND; 321272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R3; 322250de12bSStefano Babic 323250de12bSStefano Babic /* 324250de12bSStefano Babic * Most cards do not answer if some reserved bits 325250de12bSStefano Babic * in the ocr are set. However, Some controller 326250de12bSStefano Babic * can set bit 7 (reserved for low voltages), but 327250de12bSStefano Babic * how to manage low voltages SD card is not yet 328250de12bSStefano Babic * specified. 329250de12bSStefano Babic */ 330d52ebf10SThomas Chou cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 : 33193bfd616SPantelis Antoniou (mmc->cfg->voltages & 0xff8000); 332272cc70bSAndy Fleming 333272cc70bSAndy Fleming if (mmc->version == SD_VERSION_2) 334272cc70bSAndy Fleming cmd.cmdarg |= OCR_HCS; 335272cc70bSAndy Fleming 336272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 337272cc70bSAndy Fleming 338272cc70bSAndy Fleming if (err) 339272cc70bSAndy Fleming return err; 340272cc70bSAndy Fleming 3411677eef4SAndrew Gabbasov if (cmd.response[0] & OCR_BUSY) 3421677eef4SAndrew Gabbasov break; 343272cc70bSAndy Fleming 3441677eef4SAndrew Gabbasov if (timeout-- <= 0) 345272cc70bSAndy Fleming return UNUSABLE_ERR; 346272cc70bSAndy Fleming 3471677eef4SAndrew Gabbasov udelay(1000); 3481677eef4SAndrew Gabbasov } 3491677eef4SAndrew Gabbasov 350272cc70bSAndy Fleming if (mmc->version != SD_VERSION_2) 351272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 352272cc70bSAndy Fleming 353d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 354d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 355d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 356d52ebf10SThomas Chou cmd.cmdarg = 0; 357d52ebf10SThomas Chou 358d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 359d52ebf10SThomas Chou 360d52ebf10SThomas Chou if (err) 361d52ebf10SThomas Chou return err; 362d52ebf10SThomas Chou } 363d52ebf10SThomas Chou 364998be3ddSRabin Vincent mmc->ocr = cmd.response[0]; 365272cc70bSAndy Fleming 366272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 367272cc70bSAndy Fleming mmc->rca = 0; 368272cc70bSAndy Fleming 369272cc70bSAndy Fleming return 0; 370272cc70bSAndy Fleming } 371272cc70bSAndy Fleming 3725289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg) 373272cc70bSAndy Fleming { 3745289b535SAndrew Gabbasov struct mmc_cmd cmd; 375272cc70bSAndy Fleming int err; 376272cc70bSAndy Fleming 3775289b535SAndrew Gabbasov cmd.cmdidx = MMC_CMD_SEND_OP_COND; 3785289b535SAndrew Gabbasov cmd.resp_type = MMC_RSP_R3; 3795289b535SAndrew Gabbasov cmd.cmdarg = 0; 3805a20397bSRob Herring if (use_arg && !mmc_host_is_spi(mmc)) 3815a20397bSRob Herring cmd.cmdarg = OCR_HCS | 38293bfd616SPantelis Antoniou (mmc->cfg->voltages & 383a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_VOLTAGE_MASK)) | 384a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_ACCESS_MODE); 385e9550449SChe-Liang Chiou 3865289b535SAndrew Gabbasov err = mmc_send_cmd(mmc, &cmd, NULL); 387e9550449SChe-Liang Chiou if (err) 388e9550449SChe-Liang Chiou return err; 3895289b535SAndrew Gabbasov mmc->ocr = cmd.response[0]; 390e9550449SChe-Liang Chiou return 0; 391e9550449SChe-Liang Chiou } 392e9550449SChe-Liang Chiou 393750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc) 394e9550449SChe-Liang Chiou { 395e9550449SChe-Liang Chiou int err, i; 396e9550449SChe-Liang Chiou 397272cc70bSAndy Fleming /* Some cards seem to need this */ 398272cc70bSAndy Fleming mmc_go_idle(mmc); 399272cc70bSAndy Fleming 40031cacbabSRaffaele Recalcati /* Asking to the card its capabilities */ 401e9550449SChe-Liang Chiou for (i = 0; i < 2; i++) { 4025289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, i != 0); 40331cacbabSRaffaele Recalcati if (err) 40431cacbabSRaffaele Recalcati return err; 40531cacbabSRaffaele Recalcati 406e9550449SChe-Liang Chiou /* exit if not busy (flag seems to be inverted) */ 407a626c8d4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 408bd47c135SAndrew Gabbasov break; 409e9550449SChe-Liang Chiou } 410bd47c135SAndrew Gabbasov mmc->op_cond_pending = 1; 411bd47c135SAndrew Gabbasov return 0; 412e9550449SChe-Liang Chiou } 41331cacbabSRaffaele Recalcati 414750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc) 415e9550449SChe-Liang Chiou { 416e9550449SChe-Liang Chiou struct mmc_cmd cmd; 417e9550449SChe-Liang Chiou int timeout = 1000; 418e9550449SChe-Liang Chiou uint start; 419e9550449SChe-Liang Chiou int err; 420e9550449SChe-Liang Chiou 421e9550449SChe-Liang Chiou mmc->op_cond_pending = 0; 422cc17c01fSAndrew Gabbasov if (!(mmc->ocr & OCR_BUSY)) { 423e9550449SChe-Liang Chiou start = get_timer(0); 4241677eef4SAndrew Gabbasov while (1) { 4255289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, 1); 426272cc70bSAndy Fleming if (err) 427272cc70bSAndy Fleming return err; 4281677eef4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 4291677eef4SAndrew Gabbasov break; 430e9550449SChe-Liang Chiou if (get_timer(start) > timeout) 431272cc70bSAndy Fleming return UNUSABLE_ERR; 432e9550449SChe-Liang Chiou udelay(100); 4331677eef4SAndrew Gabbasov } 434cc17c01fSAndrew Gabbasov } 435272cc70bSAndy Fleming 436d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 437d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 438d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 439d52ebf10SThomas Chou cmd.cmdarg = 0; 440d52ebf10SThomas Chou 441d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 442d52ebf10SThomas Chou 443d52ebf10SThomas Chou if (err) 444d52ebf10SThomas Chou return err; 445a626c8d4SAndrew Gabbasov 446a626c8d4SAndrew Gabbasov mmc->ocr = cmd.response[0]; 447d52ebf10SThomas Chou } 448d52ebf10SThomas Chou 449272cc70bSAndy Fleming mmc->version = MMC_VERSION_UNKNOWN; 450272cc70bSAndy Fleming 451272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 452def816a2SStephen Warren mmc->rca = 1; 453272cc70bSAndy Fleming 454272cc70bSAndy Fleming return 0; 455272cc70bSAndy Fleming } 456272cc70bSAndy Fleming 457272cc70bSAndy Fleming 458fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd) 459272cc70bSAndy Fleming { 460272cc70bSAndy Fleming struct mmc_cmd cmd; 461272cc70bSAndy Fleming struct mmc_data data; 462272cc70bSAndy Fleming int err; 463272cc70bSAndy Fleming 464272cc70bSAndy Fleming /* Get the Card Status Register */ 465272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_EXT_CSD; 466272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 467272cc70bSAndy Fleming cmd.cmdarg = 0; 468272cc70bSAndy Fleming 469cdfd1ac6SYoshihiro Shimoda data.dest = (char *)ext_csd; 470272cc70bSAndy Fleming data.blocks = 1; 4718bfa195eSSimon Glass data.blocksize = MMC_MAX_BLOCK_LEN; 472272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 473272cc70bSAndy Fleming 474272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 475272cc70bSAndy Fleming 476272cc70bSAndy Fleming return err; 477272cc70bSAndy Fleming } 478272cc70bSAndy Fleming 479272cc70bSAndy Fleming 480fdbb873eSKim Phillips static int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) 481272cc70bSAndy Fleming { 482272cc70bSAndy Fleming struct mmc_cmd cmd; 4835d4fc8d9SRaffaele Recalcati int timeout = 1000; 4845d4fc8d9SRaffaele Recalcati int ret; 485272cc70bSAndy Fleming 486272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SWITCH; 487272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1b; 488272cc70bSAndy Fleming cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | 489272cc70bSAndy Fleming (index << 16) | 490272cc70bSAndy Fleming (value << 8); 491272cc70bSAndy Fleming 4925d4fc8d9SRaffaele Recalcati ret = mmc_send_cmd(mmc, &cmd, NULL); 4935d4fc8d9SRaffaele Recalcati 4945d4fc8d9SRaffaele Recalcati /* Waiting for the ready status */ 49593ad0d18SJan Kloetzke if (!ret) 49693ad0d18SJan Kloetzke ret = mmc_send_status(mmc, timeout); 4975d4fc8d9SRaffaele Recalcati 4985d4fc8d9SRaffaele Recalcati return ret; 4995d4fc8d9SRaffaele Recalcati 500272cc70bSAndy Fleming } 501272cc70bSAndy Fleming 502fdbb873eSKim Phillips static int mmc_change_freq(struct mmc *mmc) 503272cc70bSAndy Fleming { 5048bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 505272cc70bSAndy Fleming char cardtype; 506272cc70bSAndy Fleming int err; 507272cc70bSAndy Fleming 508fc5b32fbSAndrew Gabbasov mmc->card_caps = 0; 509272cc70bSAndy Fleming 510d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 511d52ebf10SThomas Chou return 0; 512d52ebf10SThomas Chou 513272cc70bSAndy Fleming /* Only version 4 supports high-speed */ 514272cc70bSAndy Fleming if (mmc->version < MMC_VERSION_4) 515272cc70bSAndy Fleming return 0; 516272cc70bSAndy Fleming 517fc5b32fbSAndrew Gabbasov mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT; 518fc5b32fbSAndrew Gabbasov 519272cc70bSAndy Fleming err = mmc_send_ext_csd(mmc, ext_csd); 520272cc70bSAndy Fleming 521272cc70bSAndy Fleming if (err) 522272cc70bSAndy Fleming return err; 523272cc70bSAndy Fleming 5240560db18SLei Wen cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf; 525272cc70bSAndy Fleming 526272cc70bSAndy Fleming err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1); 527272cc70bSAndy Fleming 528272cc70bSAndy Fleming if (err) 5296b2221b0SAndrew Gabbasov return err == SWITCH_ERR ? 0 : err; 530272cc70bSAndy Fleming 531272cc70bSAndy Fleming /* Now check to see that it worked */ 532272cc70bSAndy Fleming err = mmc_send_ext_csd(mmc, ext_csd); 533272cc70bSAndy Fleming 534272cc70bSAndy Fleming if (err) 535272cc70bSAndy Fleming return err; 536272cc70bSAndy Fleming 537272cc70bSAndy Fleming /* No high-speed support */ 5380560db18SLei Wen if (!ext_csd[EXT_CSD_HS_TIMING]) 539272cc70bSAndy Fleming return 0; 540272cc70bSAndy Fleming 541272cc70bSAndy Fleming /* High Speed is set, there are two types: 52MHz and 26MHz */ 542d22e3d46SJaehoon Chung if (cardtype & EXT_CSD_CARD_TYPE_52) { 543201d5ac4SAndrew Gabbasov if (cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V) 544d22e3d46SJaehoon Chung mmc->card_caps |= MMC_MODE_DDR_52MHz; 545272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; 546d22e3d46SJaehoon Chung } else { 547272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS; 548d22e3d46SJaehoon Chung } 549272cc70bSAndy Fleming 550272cc70bSAndy Fleming return 0; 551272cc70bSAndy Fleming } 552272cc70bSAndy Fleming 553f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num) 554f866a46dSStephen Warren { 555f866a46dSStephen Warren switch (part_num) { 556f866a46dSStephen Warren case 0: 557f866a46dSStephen Warren mmc->capacity = mmc->capacity_user; 558f866a46dSStephen Warren break; 559f866a46dSStephen Warren case 1: 560f866a46dSStephen Warren case 2: 561f866a46dSStephen Warren mmc->capacity = mmc->capacity_boot; 562f866a46dSStephen Warren break; 563f866a46dSStephen Warren case 3: 564f866a46dSStephen Warren mmc->capacity = mmc->capacity_rpmb; 565f866a46dSStephen Warren break; 566f866a46dSStephen Warren case 4: 567f866a46dSStephen Warren case 5: 568f866a46dSStephen Warren case 6: 569f866a46dSStephen Warren case 7: 570f866a46dSStephen Warren mmc->capacity = mmc->capacity_gp[part_num - 4]; 571f866a46dSStephen Warren break; 572f866a46dSStephen Warren default: 573f866a46dSStephen Warren return -1; 574f866a46dSStephen Warren } 575f866a46dSStephen Warren 576f866a46dSStephen Warren mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len); 577f866a46dSStephen Warren 578f866a46dSStephen Warren return 0; 579f866a46dSStephen Warren } 580f866a46dSStephen Warren 581d2356284SStephen Warren int mmc_select_hwpart(int dev_num, int hwpart) 582d2356284SStephen Warren { 583d2356284SStephen Warren struct mmc *mmc = find_mmc_device(dev_num); 584d2356284SStephen Warren int ret; 585d2356284SStephen Warren 586d2356284SStephen Warren if (!mmc) 587d4622df3SStephen Warren return -ENODEV; 588d2356284SStephen Warren 589873cc1d7SStephen Warren if (mmc->block_dev.hwpart == hwpart) 590d2356284SStephen Warren return 0; 591d2356284SStephen Warren 592d2356284SStephen Warren if (mmc->part_config == MMCPART_NOAVAILABLE) { 593d2356284SStephen Warren printf("Card doesn't support part_switch\n"); 594d4622df3SStephen Warren return -EMEDIUMTYPE; 595d2356284SStephen Warren } 596d2356284SStephen Warren 597d2356284SStephen Warren ret = mmc_switch_part(dev_num, hwpart); 598d2356284SStephen Warren if (ret) 599d4622df3SStephen Warren return ret; 600d2356284SStephen Warren 601d2356284SStephen Warren return 0; 602d2356284SStephen Warren } 603d2356284SStephen Warren 604d2356284SStephen Warren 605bc897b1dSLei Wen int mmc_switch_part(int dev_num, unsigned int part_num) 606bc897b1dSLei Wen { 607bc897b1dSLei Wen struct mmc *mmc = find_mmc_device(dev_num); 608f866a46dSStephen Warren int ret; 609bc897b1dSLei Wen 610bc897b1dSLei Wen if (!mmc) 611bc897b1dSLei Wen return -1; 612bc897b1dSLei Wen 613f866a46dSStephen Warren ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, 614bc897b1dSLei Wen (mmc->part_config & ~PART_ACCESS_MASK) 615bc897b1dSLei Wen | (part_num & PART_ACCESS_MASK)); 616f866a46dSStephen Warren 6176dc93e70SPeter Bigot /* 6186dc93e70SPeter Bigot * Set the capacity if the switch succeeded or was intended 6196dc93e70SPeter Bigot * to return to representing the raw device. 6206dc93e70SPeter Bigot */ 621873cc1d7SStephen Warren if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) { 6226dc93e70SPeter Bigot ret = mmc_set_capacity(mmc, part_num); 623873cc1d7SStephen Warren mmc->block_dev.hwpart = part_num; 624873cc1d7SStephen Warren } 6256dc93e70SPeter Bigot 6266dc93e70SPeter Bigot return ret; 627bc897b1dSLei Wen } 628bc897b1dSLei Wen 629ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc, 630ac9da0e0SDiego Santa Cruz const struct mmc_hwpart_conf *conf, 631ac9da0e0SDiego Santa Cruz enum mmc_hwpart_conf_mode mode) 632ac9da0e0SDiego Santa Cruz { 633ac9da0e0SDiego Santa Cruz u8 part_attrs = 0; 634ac9da0e0SDiego Santa Cruz u32 enh_size_mult; 635ac9da0e0SDiego Santa Cruz u32 enh_start_addr; 636ac9da0e0SDiego Santa Cruz u32 gp_size_mult[4]; 637ac9da0e0SDiego Santa Cruz u32 max_enh_size_mult; 638ac9da0e0SDiego Santa Cruz u32 tot_enh_size_mult = 0; 6398dda5b0eSDiego Santa Cruz u8 wr_rel_set; 640ac9da0e0SDiego Santa Cruz int i, pidx, err; 641ac9da0e0SDiego Santa Cruz ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 642ac9da0e0SDiego Santa Cruz 643ac9da0e0SDiego Santa Cruz if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE) 644ac9da0e0SDiego Santa Cruz return -EINVAL; 645ac9da0e0SDiego Santa Cruz 646ac9da0e0SDiego Santa Cruz if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) { 647ac9da0e0SDiego Santa Cruz printf("eMMC >= 4.4 required for enhanced user data area\n"); 648ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 649ac9da0e0SDiego Santa Cruz } 650ac9da0e0SDiego Santa Cruz 651ac9da0e0SDiego Santa Cruz if (!(mmc->part_support & PART_SUPPORT)) { 652ac9da0e0SDiego Santa Cruz printf("Card does not support partitioning\n"); 653ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 654ac9da0e0SDiego Santa Cruz } 655ac9da0e0SDiego Santa Cruz 656ac9da0e0SDiego Santa Cruz if (!mmc->hc_wp_grp_size) { 657ac9da0e0SDiego Santa Cruz printf("Card does not define HC WP group size\n"); 658ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 659ac9da0e0SDiego Santa Cruz } 660ac9da0e0SDiego Santa Cruz 661ac9da0e0SDiego Santa Cruz /* check partition alignment and total enhanced size */ 662ac9da0e0SDiego Santa Cruz if (conf->user.enh_size) { 663ac9da0e0SDiego Santa Cruz if (conf->user.enh_size % mmc->hc_wp_grp_size || 664ac9da0e0SDiego Santa Cruz conf->user.enh_start % mmc->hc_wp_grp_size) { 665ac9da0e0SDiego Santa Cruz printf("User data enhanced area not HC WP group " 666ac9da0e0SDiego Santa Cruz "size aligned\n"); 667ac9da0e0SDiego Santa Cruz return -EINVAL; 668ac9da0e0SDiego Santa Cruz } 669ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_USR; 670ac9da0e0SDiego Santa Cruz enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size; 671ac9da0e0SDiego Santa Cruz if (mmc->high_capacity) { 672ac9da0e0SDiego Santa Cruz enh_start_addr = conf->user.enh_start; 673ac9da0e0SDiego Santa Cruz } else { 674ac9da0e0SDiego Santa Cruz enh_start_addr = (conf->user.enh_start << 9); 675ac9da0e0SDiego Santa Cruz } 676ac9da0e0SDiego Santa Cruz } else { 677ac9da0e0SDiego Santa Cruz enh_size_mult = 0; 678ac9da0e0SDiego Santa Cruz enh_start_addr = 0; 679ac9da0e0SDiego Santa Cruz } 680ac9da0e0SDiego Santa Cruz tot_enh_size_mult += enh_size_mult; 681ac9da0e0SDiego Santa Cruz 682ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 683ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) { 684ac9da0e0SDiego Santa Cruz printf("GP%i partition not HC WP group size " 685ac9da0e0SDiego Santa Cruz "aligned\n", pidx+1); 686ac9da0e0SDiego Santa Cruz return -EINVAL; 687ac9da0e0SDiego Santa Cruz } 688ac9da0e0SDiego Santa Cruz gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size; 689ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) { 690ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_GP(pidx); 691ac9da0e0SDiego Santa Cruz tot_enh_size_mult += gp_size_mult[pidx]; 692ac9da0e0SDiego Santa Cruz } 693ac9da0e0SDiego Santa Cruz } 694ac9da0e0SDiego Santa Cruz 695ac9da0e0SDiego Santa Cruz if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) { 696ac9da0e0SDiego Santa Cruz printf("Card does not support enhanced attribute\n"); 697ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 698ac9da0e0SDiego Santa Cruz } 699ac9da0e0SDiego Santa Cruz 700ac9da0e0SDiego Santa Cruz err = mmc_send_ext_csd(mmc, ext_csd); 701ac9da0e0SDiego Santa Cruz if (err) 702ac9da0e0SDiego Santa Cruz return err; 703ac9da0e0SDiego Santa Cruz 704ac9da0e0SDiego Santa Cruz max_enh_size_mult = 705ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) + 706ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) + 707ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT]; 708ac9da0e0SDiego Santa Cruz if (tot_enh_size_mult > max_enh_size_mult) { 709ac9da0e0SDiego Santa Cruz printf("Total enhanced size exceeds maximum (%u > %u)\n", 710ac9da0e0SDiego Santa Cruz tot_enh_size_mult, max_enh_size_mult); 711ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 712ac9da0e0SDiego Santa Cruz } 713ac9da0e0SDiego Santa Cruz 7148dda5b0eSDiego Santa Cruz /* The default value of EXT_CSD_WR_REL_SET is device 7158dda5b0eSDiego Santa Cruz * dependent, the values can only be changed if the 7168dda5b0eSDiego Santa Cruz * EXT_CSD_HS_CTRL_REL bit is set. The values can be 7178dda5b0eSDiego Santa Cruz * changed only once and before partitioning is completed. */ 7188dda5b0eSDiego Santa Cruz wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 7198dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_change) { 7208dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_set) 7218dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_USR; 7228dda5b0eSDiego Santa Cruz else 7238dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR; 7248dda5b0eSDiego Santa Cruz } 7258dda5b0eSDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 7268dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_change) { 7278dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_set) 7288dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx); 7298dda5b0eSDiego Santa Cruz else 7308dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx); 7318dda5b0eSDiego Santa Cruz } 7328dda5b0eSDiego Santa Cruz } 7338dda5b0eSDiego Santa Cruz 7348dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] && 7358dda5b0eSDiego Santa Cruz !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) { 7368dda5b0eSDiego Santa Cruz puts("Card does not support host controlled partition write " 7378dda5b0eSDiego Santa Cruz "reliability settings\n"); 7388dda5b0eSDiego Santa Cruz return -EMEDIUMTYPE; 7398dda5b0eSDiego Santa Cruz } 7408dda5b0eSDiego Santa Cruz 741ac9da0e0SDiego Santa Cruz if (ext_csd[EXT_CSD_PARTITION_SETTING] & 742ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED) { 743ac9da0e0SDiego Santa Cruz printf("Card already partitioned\n"); 744ac9da0e0SDiego Santa Cruz return -EPERM; 745ac9da0e0SDiego Santa Cruz } 746ac9da0e0SDiego Santa Cruz 747ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_CHECK) 748ac9da0e0SDiego Santa Cruz return 0; 749ac9da0e0SDiego Santa Cruz 750ac9da0e0SDiego Santa Cruz /* Partitioning requires high-capacity size definitions */ 751ac9da0e0SDiego Santa Cruz if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) { 752ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 753ac9da0e0SDiego Santa Cruz EXT_CSD_ERASE_GROUP_DEF, 1); 754ac9da0e0SDiego Santa Cruz 755ac9da0e0SDiego Santa Cruz if (err) 756ac9da0e0SDiego Santa Cruz return err; 757ac9da0e0SDiego Santa Cruz 758ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 759ac9da0e0SDiego Santa Cruz 760ac9da0e0SDiego Santa Cruz /* update erase group size to be high-capacity */ 761ac9da0e0SDiego Santa Cruz mmc->erase_grp_size = 762ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 763ac9da0e0SDiego Santa Cruz 764ac9da0e0SDiego Santa Cruz } 765ac9da0e0SDiego Santa Cruz 766ac9da0e0SDiego Santa Cruz /* all OK, write the configuration */ 767ac9da0e0SDiego Santa Cruz for (i = 0; i < 4; i++) { 768ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 769ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_START_ADDR+i, 770ac9da0e0SDiego Santa Cruz (enh_start_addr >> (i*8)) & 0xFF); 771ac9da0e0SDiego Santa Cruz if (err) 772ac9da0e0SDiego Santa Cruz return err; 773ac9da0e0SDiego Santa Cruz } 774ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 775ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 776ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_SIZE_MULT+i, 777ac9da0e0SDiego Santa Cruz (enh_size_mult >> (i*8)) & 0xFF); 778ac9da0e0SDiego Santa Cruz if (err) 779ac9da0e0SDiego Santa Cruz return err; 780ac9da0e0SDiego Santa Cruz } 781ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 782ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 783ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 784ac9da0e0SDiego Santa Cruz EXT_CSD_GP_SIZE_MULT+pidx*3+i, 785ac9da0e0SDiego Santa Cruz (gp_size_mult[pidx] >> (i*8)) & 0xFF); 786ac9da0e0SDiego Santa Cruz if (err) 787ac9da0e0SDiego Santa Cruz return err; 788ac9da0e0SDiego Santa Cruz } 789ac9da0e0SDiego Santa Cruz } 790ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 791ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs); 792ac9da0e0SDiego Santa Cruz if (err) 793ac9da0e0SDiego Santa Cruz return err; 794ac9da0e0SDiego Santa Cruz 795ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_SET) 796ac9da0e0SDiego Santa Cruz return 0; 797ac9da0e0SDiego Santa Cruz 7988dda5b0eSDiego Santa Cruz /* The WR_REL_SET is a write-once register but shall be 7998dda5b0eSDiego Santa Cruz * written before setting PART_SETTING_COMPLETED. As it is 8008dda5b0eSDiego Santa Cruz * write-once we can only write it when completing the 8018dda5b0eSDiego Santa Cruz * partitioning. */ 8028dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) { 8038dda5b0eSDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 8048dda5b0eSDiego Santa Cruz EXT_CSD_WR_REL_SET, wr_rel_set); 8058dda5b0eSDiego Santa Cruz if (err) 8068dda5b0eSDiego Santa Cruz return err; 8078dda5b0eSDiego Santa Cruz } 8088dda5b0eSDiego Santa Cruz 809ac9da0e0SDiego Santa Cruz /* Setting PART_SETTING_COMPLETED confirms the partition 810ac9da0e0SDiego Santa Cruz * configuration but it only becomes effective after power 811ac9da0e0SDiego Santa Cruz * cycle, so we do not adjust the partition related settings 812ac9da0e0SDiego Santa Cruz * in the mmc struct. */ 813ac9da0e0SDiego Santa Cruz 814ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 815ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING, 816ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED); 817ac9da0e0SDiego Santa Cruz if (err) 818ac9da0e0SDiego Santa Cruz return err; 819ac9da0e0SDiego Santa Cruz 820ac9da0e0SDiego Santa Cruz return 0; 821ac9da0e0SDiego Santa Cruz } 822ac9da0e0SDiego Santa Cruz 82348972d90SThierry Reding int mmc_getcd(struct mmc *mmc) 82448972d90SThierry Reding { 82548972d90SThierry Reding int cd; 82648972d90SThierry Reding 82748972d90SThierry Reding cd = board_mmc_getcd(mmc); 82848972d90SThierry Reding 829d4e1da4eSPeter Korsgaard if (cd < 0) { 83093bfd616SPantelis Antoniou if (mmc->cfg->ops->getcd) 83193bfd616SPantelis Antoniou cd = mmc->cfg->ops->getcd(mmc); 832d4e1da4eSPeter Korsgaard else 833d4e1da4eSPeter Korsgaard cd = 1; 834d4e1da4eSPeter Korsgaard } 83548972d90SThierry Reding 83648972d90SThierry Reding return cd; 83748972d90SThierry Reding } 83848972d90SThierry Reding 839fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) 840272cc70bSAndy Fleming { 841272cc70bSAndy Fleming struct mmc_cmd cmd; 842272cc70bSAndy Fleming struct mmc_data data; 843272cc70bSAndy Fleming 844272cc70bSAndy Fleming /* Switch the frequency */ 845272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SWITCH_FUNC; 846272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 847272cc70bSAndy Fleming cmd.cmdarg = (mode << 31) | 0xffffff; 848272cc70bSAndy Fleming cmd.cmdarg &= ~(0xf << (group * 4)); 849272cc70bSAndy Fleming cmd.cmdarg |= value << (group * 4); 850272cc70bSAndy Fleming 851272cc70bSAndy Fleming data.dest = (char *)resp; 852272cc70bSAndy Fleming data.blocksize = 64; 853272cc70bSAndy Fleming data.blocks = 1; 854272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 855272cc70bSAndy Fleming 856272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, &data); 857272cc70bSAndy Fleming } 858272cc70bSAndy Fleming 859272cc70bSAndy Fleming 860fdbb873eSKim Phillips static int sd_change_freq(struct mmc *mmc) 861272cc70bSAndy Fleming { 862272cc70bSAndy Fleming int err; 863272cc70bSAndy Fleming struct mmc_cmd cmd; 864f781dd38SAnton staaf ALLOC_CACHE_ALIGN_BUFFER(uint, scr, 2); 865f781dd38SAnton staaf ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16); 866272cc70bSAndy Fleming struct mmc_data data; 867272cc70bSAndy Fleming int timeout; 868272cc70bSAndy Fleming 869272cc70bSAndy Fleming mmc->card_caps = 0; 870272cc70bSAndy Fleming 871d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 872d52ebf10SThomas Chou return 0; 873d52ebf10SThomas Chou 874272cc70bSAndy Fleming /* Read the SCR to find out if this card supports higher speeds */ 875272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 876272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 877272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 878272cc70bSAndy Fleming 879272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 880272cc70bSAndy Fleming 881272cc70bSAndy Fleming if (err) 882272cc70bSAndy Fleming return err; 883272cc70bSAndy Fleming 884272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_SCR; 885272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 886272cc70bSAndy Fleming cmd.cmdarg = 0; 887272cc70bSAndy Fleming 888272cc70bSAndy Fleming timeout = 3; 889272cc70bSAndy Fleming 890272cc70bSAndy Fleming retry_scr: 891f781dd38SAnton staaf data.dest = (char *)scr; 892272cc70bSAndy Fleming data.blocksize = 8; 893272cc70bSAndy Fleming data.blocks = 1; 894272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 895272cc70bSAndy Fleming 896272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 897272cc70bSAndy Fleming 898272cc70bSAndy Fleming if (err) { 899272cc70bSAndy Fleming if (timeout--) 900272cc70bSAndy Fleming goto retry_scr; 901272cc70bSAndy Fleming 902272cc70bSAndy Fleming return err; 903272cc70bSAndy Fleming } 904272cc70bSAndy Fleming 9054e3d89baSYauhen Kharuzhy mmc->scr[0] = __be32_to_cpu(scr[0]); 9064e3d89baSYauhen Kharuzhy mmc->scr[1] = __be32_to_cpu(scr[1]); 907272cc70bSAndy Fleming 908272cc70bSAndy Fleming switch ((mmc->scr[0] >> 24) & 0xf) { 909272cc70bSAndy Fleming case 0: 910272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 911272cc70bSAndy Fleming break; 912272cc70bSAndy Fleming case 1: 913272cc70bSAndy Fleming mmc->version = SD_VERSION_1_10; 914272cc70bSAndy Fleming break; 915272cc70bSAndy Fleming case 2: 916272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 9171741c64dSJaehoon Chung if ((mmc->scr[0] >> 15) & 0x1) 9181741c64dSJaehoon Chung mmc->version = SD_VERSION_3; 919272cc70bSAndy Fleming break; 920272cc70bSAndy Fleming default: 921272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 922272cc70bSAndy Fleming break; 923272cc70bSAndy Fleming } 924272cc70bSAndy Fleming 925b44c7083SAlagu Sankar if (mmc->scr[0] & SD_DATA_4BIT) 926b44c7083SAlagu Sankar mmc->card_caps |= MMC_MODE_4BIT; 927b44c7083SAlagu Sankar 928272cc70bSAndy Fleming /* Version 1.0 doesn't support switching */ 929272cc70bSAndy Fleming if (mmc->version == SD_VERSION_1_0) 930272cc70bSAndy Fleming return 0; 931272cc70bSAndy Fleming 932272cc70bSAndy Fleming timeout = 4; 933272cc70bSAndy Fleming while (timeout--) { 934272cc70bSAndy Fleming err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1, 935f781dd38SAnton staaf (u8 *)switch_status); 936272cc70bSAndy Fleming 937272cc70bSAndy Fleming if (err) 938272cc70bSAndy Fleming return err; 939272cc70bSAndy Fleming 940272cc70bSAndy Fleming /* The high-speed function is busy. Try again */ 9414e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY)) 942272cc70bSAndy Fleming break; 943272cc70bSAndy Fleming } 944272cc70bSAndy Fleming 945272cc70bSAndy Fleming /* If high-speed isn't supported, we return */ 9464e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)) 947272cc70bSAndy Fleming return 0; 948272cc70bSAndy Fleming 9492c3fbf4cSMacpaul Lin /* 9502c3fbf4cSMacpaul Lin * If the host doesn't support SD_HIGHSPEED, do not switch card to 9512c3fbf4cSMacpaul Lin * HIGHSPEED mode even if the card support SD_HIGHSPPED. 9522c3fbf4cSMacpaul Lin * This can avoid furthur problem when the card runs in different 9532c3fbf4cSMacpaul Lin * mode between the host. 9542c3fbf4cSMacpaul Lin */ 95593bfd616SPantelis Antoniou if (!((mmc->cfg->host_caps & MMC_MODE_HS_52MHz) && 95693bfd616SPantelis Antoniou (mmc->cfg->host_caps & MMC_MODE_HS))) 9572c3fbf4cSMacpaul Lin return 0; 9582c3fbf4cSMacpaul Lin 959f781dd38SAnton staaf err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status); 960272cc70bSAndy Fleming 961272cc70bSAndy Fleming if (err) 962272cc70bSAndy Fleming return err; 963272cc70bSAndy Fleming 9644e3d89baSYauhen Kharuzhy if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000) 965272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS; 966272cc70bSAndy Fleming 967272cc70bSAndy Fleming return 0; 968272cc70bSAndy Fleming } 969272cc70bSAndy Fleming 970272cc70bSAndy Fleming /* frequency bases */ 971272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */ 9725f837c2cSMike Frysinger static const int fbase[] = { 973272cc70bSAndy Fleming 10000, 974272cc70bSAndy Fleming 100000, 975272cc70bSAndy Fleming 1000000, 976272cc70bSAndy Fleming 10000000, 977272cc70bSAndy Fleming }; 978272cc70bSAndy Fleming 979272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice 980272cc70bSAndy Fleming * to platforms without floating point. 981272cc70bSAndy Fleming */ 9825f837c2cSMike Frysinger static const int multipliers[] = { 983272cc70bSAndy Fleming 0, /* reserved */ 984272cc70bSAndy Fleming 10, 985272cc70bSAndy Fleming 12, 986272cc70bSAndy Fleming 13, 987272cc70bSAndy Fleming 15, 988272cc70bSAndy Fleming 20, 989272cc70bSAndy Fleming 25, 990272cc70bSAndy Fleming 30, 991272cc70bSAndy Fleming 35, 992272cc70bSAndy Fleming 40, 993272cc70bSAndy Fleming 45, 994272cc70bSAndy Fleming 50, 995272cc70bSAndy Fleming 55, 996272cc70bSAndy Fleming 60, 997272cc70bSAndy Fleming 70, 998272cc70bSAndy Fleming 80, 999272cc70bSAndy Fleming }; 1000272cc70bSAndy Fleming 1001fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc) 1002272cc70bSAndy Fleming { 100393bfd616SPantelis Antoniou if (mmc->cfg->ops->set_ios) 100493bfd616SPantelis Antoniou mmc->cfg->ops->set_ios(mmc); 1005272cc70bSAndy Fleming } 1006272cc70bSAndy Fleming 1007272cc70bSAndy Fleming void mmc_set_clock(struct mmc *mmc, uint clock) 1008272cc70bSAndy Fleming { 100993bfd616SPantelis Antoniou if (clock > mmc->cfg->f_max) 101093bfd616SPantelis Antoniou clock = mmc->cfg->f_max; 1011272cc70bSAndy Fleming 101293bfd616SPantelis Antoniou if (clock < mmc->cfg->f_min) 101393bfd616SPantelis Antoniou clock = mmc->cfg->f_min; 1014272cc70bSAndy Fleming 1015272cc70bSAndy Fleming mmc->clock = clock; 1016272cc70bSAndy Fleming 1017272cc70bSAndy Fleming mmc_set_ios(mmc); 1018272cc70bSAndy Fleming } 1019272cc70bSAndy Fleming 1020fdbb873eSKim Phillips static void mmc_set_bus_width(struct mmc *mmc, uint width) 1021272cc70bSAndy Fleming { 1022272cc70bSAndy Fleming mmc->bus_width = width; 1023272cc70bSAndy Fleming 1024272cc70bSAndy Fleming mmc_set_ios(mmc); 1025272cc70bSAndy Fleming } 1026272cc70bSAndy Fleming 1027fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc) 1028272cc70bSAndy Fleming { 1029f866a46dSStephen Warren int err, i; 1030272cc70bSAndy Fleming uint mult, freq; 1031639b7827SYoshihiro Shimoda u64 cmult, csize, capacity; 1032272cc70bSAndy Fleming struct mmc_cmd cmd; 10338bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 10348bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 10355d4fc8d9SRaffaele Recalcati int timeout = 1000; 10360c453bb7SDiego Santa Cruz bool has_parts = false; 10378a0cf490SDiego Santa Cruz bool part_completed; 1038272cc70bSAndy Fleming 1039d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON 1040d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */ 1041d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF; 1042d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R1; 1043d52ebf10SThomas Chou cmd.cmdarg = 1; 1044d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 1045d52ebf10SThomas Chou 1046d52ebf10SThomas Chou if (err) 1047d52ebf10SThomas Chou return err; 1048d52ebf10SThomas Chou } 1049d52ebf10SThomas Chou #endif 1050d52ebf10SThomas Chou 1051272cc70bSAndy Fleming /* Put the Card in Identify Mode */ 1052d52ebf10SThomas Chou cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID : 1053d52ebf10SThomas Chou MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */ 1054272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1055272cc70bSAndy Fleming cmd.cmdarg = 0; 1056272cc70bSAndy Fleming 1057272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1058272cc70bSAndy Fleming 1059272cc70bSAndy Fleming if (err) 1060272cc70bSAndy Fleming return err; 1061272cc70bSAndy Fleming 1062272cc70bSAndy Fleming memcpy(mmc->cid, cmd.response, 16); 1063272cc70bSAndy Fleming 1064272cc70bSAndy Fleming /* 1065272cc70bSAndy Fleming * For MMC cards, set the Relative Address. 1066272cc70bSAndy Fleming * For SD cards, get the Relatvie Address. 1067272cc70bSAndy Fleming * This also puts the cards into Standby State 1068272cc70bSAndy Fleming */ 1069d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1070272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR; 1071272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1072272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R6; 1073272cc70bSAndy Fleming 1074272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1075272cc70bSAndy Fleming 1076272cc70bSAndy Fleming if (err) 1077272cc70bSAndy Fleming return err; 1078272cc70bSAndy Fleming 1079272cc70bSAndy Fleming if (IS_SD(mmc)) 1080998be3ddSRabin Vincent mmc->rca = (cmd.response[0] >> 16) & 0xffff; 1081d52ebf10SThomas Chou } 1082272cc70bSAndy Fleming 1083272cc70bSAndy Fleming /* Get the Card-Specific Data */ 1084272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_CSD; 1085272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1086272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1087272cc70bSAndy Fleming 1088272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1089272cc70bSAndy Fleming 10905d4fc8d9SRaffaele Recalcati /* Waiting for the ready status */ 10915d4fc8d9SRaffaele Recalcati mmc_send_status(mmc, timeout); 10925d4fc8d9SRaffaele Recalcati 1093272cc70bSAndy Fleming if (err) 1094272cc70bSAndy Fleming return err; 1095272cc70bSAndy Fleming 1096998be3ddSRabin Vincent mmc->csd[0] = cmd.response[0]; 1097998be3ddSRabin Vincent mmc->csd[1] = cmd.response[1]; 1098998be3ddSRabin Vincent mmc->csd[2] = cmd.response[2]; 1099998be3ddSRabin Vincent mmc->csd[3] = cmd.response[3]; 1100272cc70bSAndy Fleming 1101272cc70bSAndy Fleming if (mmc->version == MMC_VERSION_UNKNOWN) { 11020b453ffeSRabin Vincent int version = (cmd.response[0] >> 26) & 0xf; 1103272cc70bSAndy Fleming 1104272cc70bSAndy Fleming switch (version) { 1105272cc70bSAndy Fleming case 0: 1106272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1107272cc70bSAndy Fleming break; 1108272cc70bSAndy Fleming case 1: 1109272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_4; 1110272cc70bSAndy Fleming break; 1111272cc70bSAndy Fleming case 2: 1112272cc70bSAndy Fleming mmc->version = MMC_VERSION_2_2; 1113272cc70bSAndy Fleming break; 1114272cc70bSAndy Fleming case 3: 1115272cc70bSAndy Fleming mmc->version = MMC_VERSION_3; 1116272cc70bSAndy Fleming break; 1117272cc70bSAndy Fleming case 4: 1118272cc70bSAndy Fleming mmc->version = MMC_VERSION_4; 1119272cc70bSAndy Fleming break; 1120272cc70bSAndy Fleming default: 1121272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1122272cc70bSAndy Fleming break; 1123272cc70bSAndy Fleming } 1124272cc70bSAndy Fleming } 1125272cc70bSAndy Fleming 1126272cc70bSAndy Fleming /* divide frequency by 10, since the mults are 10x bigger */ 11270b453ffeSRabin Vincent freq = fbase[(cmd.response[0] & 0x7)]; 11280b453ffeSRabin Vincent mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; 1129272cc70bSAndy Fleming 1130272cc70bSAndy Fleming mmc->tran_speed = freq * mult; 1131272cc70bSAndy Fleming 1132ab71188cSMarkus Niebel mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1); 1133998be3ddSRabin Vincent mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf); 1134272cc70bSAndy Fleming 1135272cc70bSAndy Fleming if (IS_SD(mmc)) 1136272cc70bSAndy Fleming mmc->write_bl_len = mmc->read_bl_len; 1137272cc70bSAndy Fleming else 1138998be3ddSRabin Vincent mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf); 1139272cc70bSAndy Fleming 1140272cc70bSAndy Fleming if (mmc->high_capacity) { 1141272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3f) << 16 1142272cc70bSAndy Fleming | (mmc->csd[2] & 0xffff0000) >> 16; 1143272cc70bSAndy Fleming cmult = 8; 1144272cc70bSAndy Fleming } else { 1145272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3ff) << 2 1146272cc70bSAndy Fleming | (mmc->csd[2] & 0xc0000000) >> 30; 1147272cc70bSAndy Fleming cmult = (mmc->csd[2] & 0x00038000) >> 15; 1148272cc70bSAndy Fleming } 1149272cc70bSAndy Fleming 1150f866a46dSStephen Warren mmc->capacity_user = (csize + 1) << (cmult + 2); 1151f866a46dSStephen Warren mmc->capacity_user *= mmc->read_bl_len; 1152f866a46dSStephen Warren mmc->capacity_boot = 0; 1153f866a46dSStephen Warren mmc->capacity_rpmb = 0; 1154f866a46dSStephen Warren for (i = 0; i < 4; i++) 1155f866a46dSStephen Warren mmc->capacity_gp[i] = 0; 1156272cc70bSAndy Fleming 11578bfa195eSSimon Glass if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN) 11588bfa195eSSimon Glass mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 1159272cc70bSAndy Fleming 11608bfa195eSSimon Glass if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN) 11618bfa195eSSimon Glass mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 1162272cc70bSAndy Fleming 1163ab71188cSMarkus Niebel if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) { 1164ab71188cSMarkus Niebel cmd.cmdidx = MMC_CMD_SET_DSR; 1165ab71188cSMarkus Niebel cmd.cmdarg = (mmc->dsr & 0xffff) << 16; 1166ab71188cSMarkus Niebel cmd.resp_type = MMC_RSP_NONE; 1167ab71188cSMarkus Niebel if (mmc_send_cmd(mmc, &cmd, NULL)) 1168ab71188cSMarkus Niebel printf("MMC: SET_DSR failed\n"); 1169ab71188cSMarkus Niebel } 1170ab71188cSMarkus Niebel 1171272cc70bSAndy Fleming /* Select the card, and put it into Transfer Mode */ 1172d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1173272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SELECT_CARD; 1174fe8f7066SAjay Bhargav cmd.resp_type = MMC_RSP_R1; 1175272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1176272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1177272cc70bSAndy Fleming 1178272cc70bSAndy Fleming if (err) 1179272cc70bSAndy Fleming return err; 1180d52ebf10SThomas Chou } 1181272cc70bSAndy Fleming 1182e6f99a56SLei Wen /* 1183e6f99a56SLei Wen * For SD, its erase group is always one sector 1184e6f99a56SLei Wen */ 1185e6f99a56SLei Wen mmc->erase_grp_size = 1; 1186bc897b1dSLei Wen mmc->part_config = MMCPART_NOAVAILABLE; 1187d23e2c09SSukumar Ghorai if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) { 1188d23e2c09SSukumar Ghorai /* check ext_csd version and capacity */ 1189d23e2c09SSukumar Ghorai err = mmc_send_ext_csd(mmc, ext_csd); 11909cf199ebSDiego Santa Cruz if (err) 11919cf199ebSDiego Santa Cruz return err; 11929cf199ebSDiego Santa Cruz if (ext_csd[EXT_CSD_REV] >= 2) { 1193639b7827SYoshihiro Shimoda /* 1194639b7827SYoshihiro Shimoda * According to the JEDEC Standard, the value of 1195639b7827SYoshihiro Shimoda * ext_csd's capacity is valid if the value is more 1196639b7827SYoshihiro Shimoda * than 2GB 1197639b7827SYoshihiro Shimoda */ 11980560db18SLei Wen capacity = ext_csd[EXT_CSD_SEC_CNT] << 0 11990560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 12000560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 12010560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; 12028bfa195eSSimon Glass capacity *= MMC_MAX_BLOCK_LEN; 1203b1f1e821SŁukasz Majewski if ((capacity >> 20) > 2 * 1024) 1204f866a46dSStephen Warren mmc->capacity_user = capacity; 1205d23e2c09SSukumar Ghorai } 1206bc897b1dSLei Wen 120764f4a619SJaehoon Chung switch (ext_csd[EXT_CSD_REV]) { 120864f4a619SJaehoon Chung case 1: 120964f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_1; 121064f4a619SJaehoon Chung break; 121164f4a619SJaehoon Chung case 2: 121264f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_2; 121364f4a619SJaehoon Chung break; 121464f4a619SJaehoon Chung case 3: 121564f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_3; 121664f4a619SJaehoon Chung break; 121764f4a619SJaehoon Chung case 5: 121864f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_41; 121964f4a619SJaehoon Chung break; 122064f4a619SJaehoon Chung case 6: 122164f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_5; 122264f4a619SJaehoon Chung break; 1223edab723bSMarkus Niebel case 7: 1224edab723bSMarkus Niebel mmc->version = MMC_VERSION_5_0; 1225edab723bSMarkus Niebel break; 122664f4a619SJaehoon Chung } 122764f4a619SJaehoon Chung 12288a0cf490SDiego Santa Cruz /* The partition data may be non-zero but it is only 12298a0cf490SDiego Santa Cruz * effective if PARTITION_SETTING_COMPLETED is set in 12308a0cf490SDiego Santa Cruz * EXT_CSD, so ignore any data if this bit is not set, 12318a0cf490SDiego Santa Cruz * except for enabling the high-capacity group size 12328a0cf490SDiego Santa Cruz * definition (see below). */ 12338a0cf490SDiego Santa Cruz part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] & 12348a0cf490SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED); 12358a0cf490SDiego Santa Cruz 12360c453bb7SDiego Santa Cruz /* store the partition info of emmc */ 12370c453bb7SDiego Santa Cruz mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT]; 12380c453bb7SDiego Santa Cruz if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || 12390c453bb7SDiego Santa Cruz ext_csd[EXT_CSD_BOOT_MULT]) 12400c453bb7SDiego Santa Cruz mmc->part_config = ext_csd[EXT_CSD_PART_CONF]; 12418a0cf490SDiego Santa Cruz if (part_completed && 12428a0cf490SDiego Santa Cruz (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT)) 12430c453bb7SDiego Santa Cruz mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]; 12440c453bb7SDiego Santa Cruz 12450c453bb7SDiego Santa Cruz mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17; 12460c453bb7SDiego Santa Cruz 12470c453bb7SDiego Santa Cruz mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17; 12480c453bb7SDiego Santa Cruz 12490c453bb7SDiego Santa Cruz for (i = 0; i < 4; i++) { 12500c453bb7SDiego Santa Cruz int idx = EXT_CSD_GP_SIZE_MULT + i * 3; 12518a0cf490SDiego Santa Cruz uint mult = (ext_csd[idx + 2] << 16) + 12520c453bb7SDiego Santa Cruz (ext_csd[idx + 1] << 8) + ext_csd[idx]; 12538a0cf490SDiego Santa Cruz if (mult) 12548a0cf490SDiego Santa Cruz has_parts = true; 12558a0cf490SDiego Santa Cruz if (!part_completed) 12568a0cf490SDiego Santa Cruz continue; 12578a0cf490SDiego Santa Cruz mmc->capacity_gp[i] = mult; 12580c453bb7SDiego Santa Cruz mmc->capacity_gp[i] *= 12590c453bb7SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 12600c453bb7SDiego Santa Cruz mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1261f8e89d67SDiego Santa Cruz mmc->capacity_gp[i] <<= 19; 12620c453bb7SDiego Santa Cruz } 12630c453bb7SDiego Santa Cruz 12648a0cf490SDiego Santa Cruz if (part_completed) { 1265a7f852b6SDiego Santa Cruz mmc->enh_user_size = 1266a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_SIZE_MULT+2] << 16) + 1267a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_SIZE_MULT+1] << 8) + 1268a7f852b6SDiego Santa Cruz ext_csd[EXT_CSD_ENH_SIZE_MULT]; 1269a7f852b6SDiego Santa Cruz mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 1270a7f852b6SDiego Santa Cruz mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1271a7f852b6SDiego Santa Cruz mmc->enh_user_size <<= 19; 1272a7f852b6SDiego Santa Cruz mmc->enh_user_start = 1273a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_START_ADDR+3] << 24) + 1274a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_START_ADDR+2] << 16) + 1275a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_START_ADDR+1] << 8) + 1276a7f852b6SDiego Santa Cruz ext_csd[EXT_CSD_ENH_START_ADDR]; 1277a7f852b6SDiego Santa Cruz if (mmc->high_capacity) 1278a7f852b6SDiego Santa Cruz mmc->enh_user_start <<= 9; 12798a0cf490SDiego Santa Cruz } 1280a7f852b6SDiego Santa Cruz 1281e6f99a56SLei Wen /* 12821937e5aaSOliver Metz * Host needs to enable ERASE_GRP_DEF bit if device is 12831937e5aaSOliver Metz * partitioned. This bit will be lost every time after a reset 12841937e5aaSOliver Metz * or power off. This will affect erase size. 1285e6f99a56SLei Wen */ 12868a0cf490SDiego Santa Cruz if (part_completed) 12870c453bb7SDiego Santa Cruz has_parts = true; 12881937e5aaSOliver Metz if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) && 12890c453bb7SDiego Santa Cruz (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) 12900c453bb7SDiego Santa Cruz has_parts = true; 12910c453bb7SDiego Santa Cruz if (has_parts) { 12921937e5aaSOliver Metz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 12931937e5aaSOliver Metz EXT_CSD_ERASE_GROUP_DEF, 1); 12941937e5aaSOliver Metz 12951937e5aaSOliver Metz if (err) 12961937e5aaSOliver Metz return err; 1297021a8055SHannes Petermaier else 1298021a8055SHannes Petermaier ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 1299037dc0abSDiego Santa Cruz } 13001937e5aaSOliver Metz 1301037dc0abSDiego Santa Cruz if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) { 13021937e5aaSOliver Metz /* Read out group size from ext_csd */ 13030560db18SLei Wen mmc->erase_grp_size = 1304a4ff9f83SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 1305d7b29129SMarkus Niebel /* 1306d7b29129SMarkus Niebel * if high capacity and partition setting completed 1307d7b29129SMarkus Niebel * SEC_COUNT is valid even if it is smaller than 2 GiB 1308d7b29129SMarkus Niebel * JEDEC Standard JESD84-B45, 6.2.4 1309d7b29129SMarkus Niebel */ 13108a0cf490SDiego Santa Cruz if (mmc->high_capacity && part_completed) { 1311d7b29129SMarkus Niebel capacity = (ext_csd[EXT_CSD_SEC_CNT]) | 1312d7b29129SMarkus Niebel (ext_csd[EXT_CSD_SEC_CNT + 1] << 8) | 1313d7b29129SMarkus Niebel (ext_csd[EXT_CSD_SEC_CNT + 2] << 16) | 1314d7b29129SMarkus Niebel (ext_csd[EXT_CSD_SEC_CNT + 3] << 24); 1315d7b29129SMarkus Niebel capacity *= MMC_MAX_BLOCK_LEN; 1316d7b29129SMarkus Niebel mmc->capacity_user = capacity; 1317d7b29129SMarkus Niebel } 13188bfa195eSSimon Glass } else { 13191937e5aaSOliver Metz /* Calculate the group size from the csd value. */ 1320e6f99a56SLei Wen int erase_gsz, erase_gmul; 1321e6f99a56SLei Wen erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10; 1322e6f99a56SLei Wen erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5; 1323e6f99a56SLei Wen mmc->erase_grp_size = (erase_gsz + 1) 1324e6f99a56SLei Wen * (erase_gmul + 1); 1325e6f99a56SLei Wen } 1326037dc0abSDiego Santa Cruz 1327037dc0abSDiego Santa Cruz mmc->hc_wp_grp_size = 1024 1328037dc0abSDiego Santa Cruz * ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 1329037dc0abSDiego Santa Cruz * ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 13309e41a00bSDiego Santa Cruz 13319e41a00bSDiego Santa Cruz mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 1332f866a46dSStephen Warren } 1333f866a46dSStephen Warren 1334873cc1d7SStephen Warren err = mmc_set_capacity(mmc, mmc->block_dev.hwpart); 1335f866a46dSStephen Warren if (err) 1336f866a46dSStephen Warren return err; 1337d23e2c09SSukumar Ghorai 1338272cc70bSAndy Fleming if (IS_SD(mmc)) 1339272cc70bSAndy Fleming err = sd_change_freq(mmc); 1340272cc70bSAndy Fleming else 1341272cc70bSAndy Fleming err = mmc_change_freq(mmc); 1342272cc70bSAndy Fleming 1343272cc70bSAndy Fleming if (err) 1344272cc70bSAndy Fleming return err; 1345272cc70bSAndy Fleming 1346272cc70bSAndy Fleming /* Restrict card's capabilities by what the host can do */ 134793bfd616SPantelis Antoniou mmc->card_caps &= mmc->cfg->host_caps; 1348272cc70bSAndy Fleming 1349272cc70bSAndy Fleming if (IS_SD(mmc)) { 1350272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_4BIT) { 1351272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 1352272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1353272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1354272cc70bSAndy Fleming 1355272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1356272cc70bSAndy Fleming if (err) 1357272cc70bSAndy Fleming return err; 1358272cc70bSAndy Fleming 1359272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH; 1360272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1361272cc70bSAndy Fleming cmd.cmdarg = 2; 1362272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1363272cc70bSAndy Fleming if (err) 1364272cc70bSAndy Fleming return err; 1365272cc70bSAndy Fleming 1366272cc70bSAndy Fleming mmc_set_bus_width(mmc, 4); 1367272cc70bSAndy Fleming } 1368272cc70bSAndy Fleming 1369272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_HS) 1370ad5fd922SJaehoon Chung mmc->tran_speed = 50000000; 1371272cc70bSAndy Fleming else 1372ad5fd922SJaehoon Chung mmc->tran_speed = 25000000; 1373fc5b32fbSAndrew Gabbasov } else if (mmc->version >= MMC_VERSION_4) { 1374fc5b32fbSAndrew Gabbasov /* Only version 4 of MMC supports wider bus widths */ 13757798f6dbSAndy Fleming int idx; 13767798f6dbSAndy Fleming 13777798f6dbSAndy Fleming /* An array of possible bus widths in order of preference */ 13787798f6dbSAndy Fleming static unsigned ext_csd_bits[] = { 1379d22e3d46SJaehoon Chung EXT_CSD_DDR_BUS_WIDTH_8, 1380d22e3d46SJaehoon Chung EXT_CSD_DDR_BUS_WIDTH_4, 13817798f6dbSAndy Fleming EXT_CSD_BUS_WIDTH_8, 13827798f6dbSAndy Fleming EXT_CSD_BUS_WIDTH_4, 13837798f6dbSAndy Fleming EXT_CSD_BUS_WIDTH_1, 13847798f6dbSAndy Fleming }; 13857798f6dbSAndy Fleming 13867798f6dbSAndy Fleming /* An array to map CSD bus widths to host cap bits */ 13877798f6dbSAndy Fleming static unsigned ext_to_hostcaps[] = { 1388786e8f81SAndrew Gabbasov [EXT_CSD_DDR_BUS_WIDTH_4] = 1389786e8f81SAndrew Gabbasov MMC_MODE_DDR_52MHz | MMC_MODE_4BIT, 1390786e8f81SAndrew Gabbasov [EXT_CSD_DDR_BUS_WIDTH_8] = 1391786e8f81SAndrew Gabbasov MMC_MODE_DDR_52MHz | MMC_MODE_8BIT, 13927798f6dbSAndy Fleming [EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT, 13937798f6dbSAndy Fleming [EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT, 13947798f6dbSAndy Fleming }; 13957798f6dbSAndy Fleming 13967798f6dbSAndy Fleming /* An array to map chosen bus width to an integer */ 13977798f6dbSAndy Fleming static unsigned widths[] = { 1398d22e3d46SJaehoon Chung 8, 4, 8, 4, 1, 13997798f6dbSAndy Fleming }; 14007798f6dbSAndy Fleming 14017798f6dbSAndy Fleming for (idx=0; idx < ARRAY_SIZE(ext_csd_bits); idx++) { 14027798f6dbSAndy Fleming unsigned int extw = ext_csd_bits[idx]; 1403786e8f81SAndrew Gabbasov unsigned int caps = ext_to_hostcaps[extw]; 14047798f6dbSAndy Fleming 14057798f6dbSAndy Fleming /* 1406bf477073SAndrew Gabbasov * If the bus width is still not changed, 1407bf477073SAndrew Gabbasov * don't try to set the default again. 1408bf477073SAndrew Gabbasov * Otherwise, recover from switch attempts 1409bf477073SAndrew Gabbasov * by switching to 1-bit bus width. 1410bf477073SAndrew Gabbasov */ 1411bf477073SAndrew Gabbasov if (extw == EXT_CSD_BUS_WIDTH_1 && 1412bf477073SAndrew Gabbasov mmc->bus_width == 1) { 1413bf477073SAndrew Gabbasov err = 0; 1414bf477073SAndrew Gabbasov break; 1415bf477073SAndrew Gabbasov } 1416bf477073SAndrew Gabbasov 1417bf477073SAndrew Gabbasov /* 1418786e8f81SAndrew Gabbasov * Check to make sure the card and controller support 1419786e8f81SAndrew Gabbasov * these capabilities 14207798f6dbSAndy Fleming */ 1421786e8f81SAndrew Gabbasov if ((mmc->card_caps & caps) != caps) 14227798f6dbSAndy Fleming continue; 14237798f6dbSAndy Fleming 1424272cc70bSAndy Fleming err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 14257798f6dbSAndy Fleming EXT_CSD_BUS_WIDTH, extw); 1426272cc70bSAndy Fleming 1427272cc70bSAndy Fleming if (err) 14284137894eSLei Wen continue; 1429272cc70bSAndy Fleming 1430786e8f81SAndrew Gabbasov mmc->ddr_mode = (caps & MMC_MODE_DDR_52MHz) ? 1 : 0; 14317798f6dbSAndy Fleming mmc_set_bus_width(mmc, widths[idx]); 1432272cc70bSAndy Fleming 14334137894eSLei Wen err = mmc_send_ext_csd(mmc, test_csd); 1434272cc70bSAndy Fleming 1435786e8f81SAndrew Gabbasov if (err) 1436786e8f81SAndrew Gabbasov continue; 1437786e8f81SAndrew Gabbasov 1438786e8f81SAndrew Gabbasov /* Only compare read only fields */ 1439786e8f81SAndrew Gabbasov if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] 1440786e8f81SAndrew Gabbasov == test_csd[EXT_CSD_PARTITIONING_SUPPORT] && 1441786e8f81SAndrew Gabbasov ext_csd[EXT_CSD_HC_WP_GRP_SIZE] 1442786e8f81SAndrew Gabbasov == test_csd[EXT_CSD_HC_WP_GRP_SIZE] && 1443786e8f81SAndrew Gabbasov ext_csd[EXT_CSD_REV] 1444786e8f81SAndrew Gabbasov == test_csd[EXT_CSD_REV] && 1445786e8f81SAndrew Gabbasov ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 1446786e8f81SAndrew Gabbasov == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] && 1447786e8f81SAndrew Gabbasov memcmp(&ext_csd[EXT_CSD_SEC_CNT], 1448786e8f81SAndrew Gabbasov &test_csd[EXT_CSD_SEC_CNT], 4) == 0) 14494137894eSLei Wen break; 1450786e8f81SAndrew Gabbasov else 1451786e8f81SAndrew Gabbasov err = SWITCH_ERR; 14524137894eSLei Wen } 1453786e8f81SAndrew Gabbasov 1454786e8f81SAndrew Gabbasov if (err) 1455786e8f81SAndrew Gabbasov return err; 1456272cc70bSAndy Fleming 1457272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_HS) { 1458272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_HS_52MHz) 1459ad5fd922SJaehoon Chung mmc->tran_speed = 52000000; 1460272cc70bSAndy Fleming else 1461ad5fd922SJaehoon Chung mmc->tran_speed = 26000000; 1462272cc70bSAndy Fleming } 1463ad5fd922SJaehoon Chung } 1464ad5fd922SJaehoon Chung 1465ad5fd922SJaehoon Chung mmc_set_clock(mmc, mmc->tran_speed); 1466272cc70bSAndy Fleming 14675af8f45cSAndrew Gabbasov /* Fix the block length for DDR mode */ 14685af8f45cSAndrew Gabbasov if (mmc->ddr_mode) { 14695af8f45cSAndrew Gabbasov mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 14705af8f45cSAndrew Gabbasov mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 14715af8f45cSAndrew Gabbasov } 14725af8f45cSAndrew Gabbasov 1473272cc70bSAndy Fleming /* fill in device description */ 1474272cc70bSAndy Fleming mmc->block_dev.lun = 0; 1475873cc1d7SStephen Warren mmc->block_dev.hwpart = 0; 1476272cc70bSAndy Fleming mmc->block_dev.type = 0; 1477272cc70bSAndy Fleming mmc->block_dev.blksz = mmc->read_bl_len; 14780472fbfdSEgbert Eich mmc->block_dev.log2blksz = LOG2(mmc->block_dev.blksz); 14799b1f942cSRabin Vincent mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len); 1480fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \ 1481fc011f64SSjoerd Simons (defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \ 1482fc011f64SSjoerd Simons !defined(CONFIG_USE_TINY_PRINTF)) 1483babce5f6STaylor Hutt sprintf(mmc->block_dev.vendor, "Man %06x Snr %04x%04x", 1484babce5f6STaylor Hutt mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff), 1485babce5f6STaylor Hutt (mmc->cid[3] >> 16) & 0xffff); 1486babce5f6STaylor Hutt sprintf(mmc->block_dev.product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff, 14870b453ffeSRabin Vincent (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, 1488babce5f6STaylor Hutt (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff, 1489babce5f6STaylor Hutt (mmc->cid[2] >> 24) & 0xff); 1490babce5f6STaylor Hutt sprintf(mmc->block_dev.revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf, 1491babce5f6STaylor Hutt (mmc->cid[2] >> 16) & 0xf); 149256196826SPaul Burton #else 149356196826SPaul Burton mmc->block_dev.vendor[0] = 0; 149456196826SPaul Burton mmc->block_dev.product[0] = 0; 149556196826SPaul Burton mmc->block_dev.revision[0] = 0; 149656196826SPaul Burton #endif 1497122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT) 1498272cc70bSAndy Fleming init_part(&mmc->block_dev); 1499122efd43SMikhail Kshevetskiy #endif 1500272cc70bSAndy Fleming 1501272cc70bSAndy Fleming return 0; 1502272cc70bSAndy Fleming } 1503272cc70bSAndy Fleming 1504fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc) 1505272cc70bSAndy Fleming { 1506272cc70bSAndy Fleming struct mmc_cmd cmd; 1507272cc70bSAndy Fleming int err; 1508272cc70bSAndy Fleming 1509272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_IF_COND; 1510272cc70bSAndy Fleming /* We set the bit if the host supports voltages between 2.7 and 3.6 V */ 151193bfd616SPantelis Antoniou cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa; 1512272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R7; 1513272cc70bSAndy Fleming 1514272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1515272cc70bSAndy Fleming 1516272cc70bSAndy Fleming if (err) 1517272cc70bSAndy Fleming return err; 1518272cc70bSAndy Fleming 1519998be3ddSRabin Vincent if ((cmd.response[0] & 0xff) != 0xaa) 1520272cc70bSAndy Fleming return UNUSABLE_ERR; 1521272cc70bSAndy Fleming else 1522272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 1523272cc70bSAndy Fleming 1524272cc70bSAndy Fleming return 0; 1525272cc70bSAndy Fleming } 1526272cc70bSAndy Fleming 152793bfd616SPantelis Antoniou /* not used any more */ 152893bfd616SPantelis Antoniou int __deprecated mmc_register(struct mmc *mmc) 1529272cc70bSAndy Fleming { 153093bfd616SPantelis Antoniou #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 153193bfd616SPantelis Antoniou printf("%s is deprecated! use mmc_create() instead.\n", __func__); 153293bfd616SPantelis Antoniou #endif 153393bfd616SPantelis Antoniou return -1; 153493bfd616SPantelis Antoniou } 153593bfd616SPantelis Antoniou 153693bfd616SPantelis Antoniou struct mmc *mmc_create(const struct mmc_config *cfg, void *priv) 153793bfd616SPantelis Antoniou { 153893bfd616SPantelis Antoniou struct mmc *mmc; 153993bfd616SPantelis Antoniou 154093bfd616SPantelis Antoniou /* quick validation */ 154193bfd616SPantelis Antoniou if (cfg == NULL || cfg->ops == NULL || cfg->ops->send_cmd == NULL || 154293bfd616SPantelis Antoniou cfg->f_min == 0 || cfg->f_max == 0 || cfg->b_max == 0) 154393bfd616SPantelis Antoniou return NULL; 154493bfd616SPantelis Antoniou 154593bfd616SPantelis Antoniou mmc = calloc(1, sizeof(*mmc)); 154693bfd616SPantelis Antoniou if (mmc == NULL) 154793bfd616SPantelis Antoniou return NULL; 154893bfd616SPantelis Antoniou 154993bfd616SPantelis Antoniou mmc->cfg = cfg; 155093bfd616SPantelis Antoniou mmc->priv = priv; 155193bfd616SPantelis Antoniou 155293bfd616SPantelis Antoniou /* the following chunk was mmc_register() */ 155393bfd616SPantelis Antoniou 1554ab71188cSMarkus Niebel /* Setup dsr related values */ 1555ab71188cSMarkus Niebel mmc->dsr_imp = 0; 1556ab71188cSMarkus Niebel mmc->dsr = 0xffffffff; 1557272cc70bSAndy Fleming /* Setup the universal parts of the block interface just once */ 1558272cc70bSAndy Fleming mmc->block_dev.if_type = IF_TYPE_MMC; 1559272cc70bSAndy Fleming mmc->block_dev.dev = cur_dev_num++; 1560272cc70bSAndy Fleming mmc->block_dev.removable = 1; 1561272cc70bSAndy Fleming mmc->block_dev.block_read = mmc_bread; 1562272cc70bSAndy Fleming mmc->block_dev.block_write = mmc_bwrite; 1563e6f99a56SLei Wen mmc->block_dev.block_erase = mmc_berase; 156493bfd616SPantelis Antoniou 156593bfd616SPantelis Antoniou /* setup initial part type */ 156693bfd616SPantelis Antoniou mmc->block_dev.part_type = mmc->cfg->part_type; 1567272cc70bSAndy Fleming 1568272cc70bSAndy Fleming INIT_LIST_HEAD(&mmc->link); 1569272cc70bSAndy Fleming 1570272cc70bSAndy Fleming list_add_tail(&mmc->link, &mmc_devices); 1571272cc70bSAndy Fleming 157293bfd616SPantelis Antoniou return mmc; 157393bfd616SPantelis Antoniou } 157493bfd616SPantelis Antoniou 157593bfd616SPantelis Antoniou void mmc_destroy(struct mmc *mmc) 157693bfd616SPantelis Antoniou { 157793bfd616SPantelis Antoniou /* only freeing memory for now */ 157893bfd616SPantelis Antoniou free(mmc); 1579272cc70bSAndy Fleming } 1580272cc70bSAndy Fleming 1581df3fc526SMatthew McClintock #ifdef CONFIG_PARTITIONS 1582272cc70bSAndy Fleming block_dev_desc_t *mmc_get_dev(int dev) 1583272cc70bSAndy Fleming { 1584272cc70bSAndy Fleming struct mmc *mmc = find_mmc_device(dev); 15856bb4b4bcSBenoît Thébaudeau if (!mmc || mmc_init(mmc)) 158640242bc3SŁukasz Majewski return NULL; 1587272cc70bSAndy Fleming 158840242bc3SŁukasz Majewski return &mmc->block_dev; 1589272cc70bSAndy Fleming } 1590df3fc526SMatthew McClintock #endif 1591272cc70bSAndy Fleming 159295de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */ 159395de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void) 159495de9ab2SPaul Kocialkowski { 159595de9ab2SPaul Kocialkowski } 159695de9ab2SPaul Kocialkowski 1597e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc) 1598272cc70bSAndy Fleming { 1599afd5932bSMacpaul Lin int err; 1600272cc70bSAndy Fleming 1601ab769f22SPantelis Antoniou /* we pretend there's no card when init is NULL */ 160293bfd616SPantelis Antoniou if (mmc_getcd(mmc) == 0 || mmc->cfg->ops->init == NULL) { 160348972d90SThierry Reding mmc->has_init = 0; 160456196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 160548972d90SThierry Reding printf("MMC: no card present\n"); 160656196826SPaul Burton #endif 160748972d90SThierry Reding return NO_CARD_ERR; 160848972d90SThierry Reding } 160948972d90SThierry Reding 1610bc897b1dSLei Wen if (mmc->has_init) 1611bc897b1dSLei Wen return 0; 1612bc897b1dSLei Wen 16135a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 16145a8dbdc6SYangbo Lu mmc_adapter_card_type_ident(); 16155a8dbdc6SYangbo Lu #endif 161695de9ab2SPaul Kocialkowski board_mmc_power_init(); 161795de9ab2SPaul Kocialkowski 1618ab769f22SPantelis Antoniou /* made sure it's not NULL earlier */ 161993bfd616SPantelis Antoniou err = mmc->cfg->ops->init(mmc); 1620272cc70bSAndy Fleming 1621272cc70bSAndy Fleming if (err) 1622272cc70bSAndy Fleming return err; 1623272cc70bSAndy Fleming 1624786e8f81SAndrew Gabbasov mmc->ddr_mode = 0; 1625b86b85e2SIlya Yanok mmc_set_bus_width(mmc, 1); 1626b86b85e2SIlya Yanok mmc_set_clock(mmc, 1); 1627b86b85e2SIlya Yanok 1628272cc70bSAndy Fleming /* Reset the Card */ 1629272cc70bSAndy Fleming err = mmc_go_idle(mmc); 1630272cc70bSAndy Fleming 1631272cc70bSAndy Fleming if (err) 1632272cc70bSAndy Fleming return err; 1633272cc70bSAndy Fleming 1634bc897b1dSLei Wen /* The internal partition reset to user partition(0) at every CMD0*/ 1635873cc1d7SStephen Warren mmc->block_dev.hwpart = 0; 1636bc897b1dSLei Wen 1637272cc70bSAndy Fleming /* Test for SD version 2 */ 1638272cc70bSAndy Fleming err = mmc_send_if_cond(mmc); 1639272cc70bSAndy Fleming 1640272cc70bSAndy Fleming /* Now try to get the SD card's operating condition */ 1641272cc70bSAndy Fleming err = sd_send_op_cond(mmc); 1642272cc70bSAndy Fleming 1643272cc70bSAndy Fleming /* If the command timed out, we check for an MMC card */ 1644272cc70bSAndy Fleming if (err == TIMEOUT) { 1645272cc70bSAndy Fleming err = mmc_send_op_cond(mmc); 1646272cc70bSAndy Fleming 1647bd47c135SAndrew Gabbasov if (err) { 164856196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 1649272cc70bSAndy Fleming printf("Card did not respond to voltage select!\n"); 165056196826SPaul Burton #endif 1651272cc70bSAndy Fleming return UNUSABLE_ERR; 1652272cc70bSAndy Fleming } 1653272cc70bSAndy Fleming } 1654272cc70bSAndy Fleming 1655bd47c135SAndrew Gabbasov if (!err) 1656e9550449SChe-Liang Chiou mmc->init_in_progress = 1; 1657e9550449SChe-Liang Chiou 1658e9550449SChe-Liang Chiou return err; 1659e9550449SChe-Liang Chiou } 1660e9550449SChe-Liang Chiou 1661e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc) 1662e9550449SChe-Liang Chiou { 1663e9550449SChe-Liang Chiou int err = 0; 1664e9550449SChe-Liang Chiou 1665bd47c135SAndrew Gabbasov mmc->init_in_progress = 0; 1666e9550449SChe-Liang Chiou if (mmc->op_cond_pending) 1667e9550449SChe-Liang Chiou err = mmc_complete_op_cond(mmc); 1668e9550449SChe-Liang Chiou 1669e9550449SChe-Liang Chiou if (!err) 1670bc897b1dSLei Wen err = mmc_startup(mmc); 1671bc897b1dSLei Wen if (err) 1672bc897b1dSLei Wen mmc->has_init = 0; 1673bc897b1dSLei Wen else 1674bc897b1dSLei Wen mmc->has_init = 1; 1675e9550449SChe-Liang Chiou return err; 1676e9550449SChe-Liang Chiou } 1677e9550449SChe-Liang Chiou 1678e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc) 1679e9550449SChe-Liang Chiou { 1680bd47c135SAndrew Gabbasov int err = 0; 1681d803fea5SMateusz Zalega unsigned start; 1682e9550449SChe-Liang Chiou 1683e9550449SChe-Liang Chiou if (mmc->has_init) 1684e9550449SChe-Liang Chiou return 0; 1685d803fea5SMateusz Zalega 1686d803fea5SMateusz Zalega start = get_timer(0); 1687d803fea5SMateusz Zalega 1688e9550449SChe-Liang Chiou if (!mmc->init_in_progress) 1689e9550449SChe-Liang Chiou err = mmc_start_init(mmc); 1690e9550449SChe-Liang Chiou 1691bd47c135SAndrew Gabbasov if (!err) 1692e9550449SChe-Liang Chiou err = mmc_complete_init(mmc); 1693e9550449SChe-Liang Chiou debug("%s: %d, time %lu\n", __func__, err, get_timer(start)); 1694bc897b1dSLei Wen return err; 1695272cc70bSAndy Fleming } 1696272cc70bSAndy Fleming 1697ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val) 1698ab71188cSMarkus Niebel { 1699ab71188cSMarkus Niebel mmc->dsr = val; 1700ab71188cSMarkus Niebel return 0; 1701ab71188cSMarkus Niebel } 1702ab71188cSMarkus Niebel 1703cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */ 1704cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis) 1705272cc70bSAndy Fleming { 1706272cc70bSAndy Fleming return -1; 1707272cc70bSAndy Fleming } 1708272cc70bSAndy Fleming 1709cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */ 1710cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis) 1711cee9ab7cSJeroen Hofstee { 1712cee9ab7cSJeroen Hofstee return -1; 1713cee9ab7cSJeroen Hofstee } 1714272cc70bSAndy Fleming 171556196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 171656196826SPaul Burton 1717272cc70bSAndy Fleming void print_mmc_devices(char separator) 1718272cc70bSAndy Fleming { 1719272cc70bSAndy Fleming struct mmc *m; 1720272cc70bSAndy Fleming struct list_head *entry; 172134dd9284SPrzemyslaw Marczak char *mmc_type; 1722272cc70bSAndy Fleming 1723272cc70bSAndy Fleming list_for_each(entry, &mmc_devices) { 1724272cc70bSAndy Fleming m = list_entry(entry, struct mmc, link); 1725272cc70bSAndy Fleming 172634dd9284SPrzemyslaw Marczak if (m->has_init) 172734dd9284SPrzemyslaw Marczak mmc_type = IS_SD(m) ? "SD" : "eMMC"; 172834dd9284SPrzemyslaw Marczak else 172934dd9284SPrzemyslaw Marczak mmc_type = NULL; 173034dd9284SPrzemyslaw Marczak 173193bfd616SPantelis Antoniou printf("%s: %d", m->cfg->name, m->block_dev.dev); 173234dd9284SPrzemyslaw Marczak if (mmc_type) 173334dd9284SPrzemyslaw Marczak printf(" (%s)", mmc_type); 1734272cc70bSAndy Fleming 1735e75eaf10SLubomir Popov if (entry->next != &mmc_devices) { 1736272cc70bSAndy Fleming printf("%c", separator); 1737e75eaf10SLubomir Popov if (separator != '\n') 1738e75eaf10SLubomir Popov puts (" "); 1739e75eaf10SLubomir Popov } 1740272cc70bSAndy Fleming } 1741272cc70bSAndy Fleming 1742272cc70bSAndy Fleming printf("\n"); 1743272cc70bSAndy Fleming } 1744272cc70bSAndy Fleming 174556196826SPaul Burton #else 174656196826SPaul Burton void print_mmc_devices(char separator) { } 174756196826SPaul Burton #endif 174856196826SPaul Burton 1749ea6ebe21SLei Wen int get_mmc_num(void) 1750ea6ebe21SLei Wen { 1751ea6ebe21SLei Wen return cur_dev_num; 1752ea6ebe21SLei Wen } 1753ea6ebe21SLei Wen 1754e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit) 1755e9550449SChe-Liang Chiou { 1756e9550449SChe-Liang Chiou mmc->preinit = preinit; 1757e9550449SChe-Liang Chiou } 1758e9550449SChe-Liang Chiou 1759e9550449SChe-Liang Chiou static void do_preinit(void) 1760e9550449SChe-Liang Chiou { 1761e9550449SChe-Liang Chiou struct mmc *m; 1762e9550449SChe-Liang Chiou struct list_head *entry; 1763e9550449SChe-Liang Chiou 1764e9550449SChe-Liang Chiou list_for_each(entry, &mmc_devices) { 1765e9550449SChe-Liang Chiou m = list_entry(entry, struct mmc, link); 1766e9550449SChe-Liang Chiou 17675a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 17685a8dbdc6SYangbo Lu mmc_set_preinit(m, 1); 17695a8dbdc6SYangbo Lu #endif 1770e9550449SChe-Liang Chiou if (m->preinit) 1771e9550449SChe-Liang Chiou mmc_start_init(m); 1772e9550449SChe-Liang Chiou } 1773e9550449SChe-Liang Chiou } 1774e9550449SChe-Liang Chiou 17758e3332e2SSjoerd Simons #if defined(CONFIG_DM_MMC) && defined(CONFIG_SPL_BUILD) 17768e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 17778e3332e2SSjoerd Simons { 17788e3332e2SSjoerd Simons return 0; 17798e3332e2SSjoerd Simons } 17808e3332e2SSjoerd Simons #elif defined(CONFIG_DM_MMC) 17818e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 17828e3332e2SSjoerd Simons { 1783*4a1db6d8SSimon Glass int ret, i; 17848e3332e2SSjoerd Simons struct uclass *uc; 1785*4a1db6d8SSimon Glass struct udevice *dev; 17868e3332e2SSjoerd Simons 17878e3332e2SSjoerd Simons ret = uclass_get(UCLASS_MMC, &uc); 17888e3332e2SSjoerd Simons if (ret) 17898e3332e2SSjoerd Simons return ret; 17908e3332e2SSjoerd Simons 1791*4a1db6d8SSimon Glass /* 1792*4a1db6d8SSimon Glass * Try to add them in sequence order. Really with driver model we 1793*4a1db6d8SSimon Glass * should allow holes, but the current MMC list does not allow that. 1794*4a1db6d8SSimon Glass * So if we request 0, 1, 3 we will get 0, 1, 2. 1795*4a1db6d8SSimon Glass */ 1796*4a1db6d8SSimon Glass for (i = 0; ; i++) { 1797*4a1db6d8SSimon Glass ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev); 1798*4a1db6d8SSimon Glass if (ret == -ENODEV) 1799*4a1db6d8SSimon Glass break; 1800*4a1db6d8SSimon Glass } 1801*4a1db6d8SSimon Glass uclass_foreach_dev(dev, uc) { 1802*4a1db6d8SSimon Glass ret = device_probe(dev); 18038e3332e2SSjoerd Simons if (ret) 1804*4a1db6d8SSimon Glass printf("%s - probe failed: %d\n", dev->name, ret); 18058e3332e2SSjoerd Simons } 18068e3332e2SSjoerd Simons 18078e3332e2SSjoerd Simons return 0; 18088e3332e2SSjoerd Simons } 18098e3332e2SSjoerd Simons #else 18108e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 18118e3332e2SSjoerd Simons { 18128e3332e2SSjoerd Simons if (board_mmc_init(bis) < 0) 18138e3332e2SSjoerd Simons cpu_mmc_init(bis); 18148e3332e2SSjoerd Simons 18158e3332e2SSjoerd Simons return 0; 18168e3332e2SSjoerd Simons } 18178e3332e2SSjoerd Simons #endif 1818e9550449SChe-Liang Chiou 1819272cc70bSAndy Fleming int mmc_initialize(bd_t *bis) 1820272cc70bSAndy Fleming { 18211b26bab1SDaniel Kochmański static int initialized = 0; 18228e3332e2SSjoerd Simons int ret; 18231b26bab1SDaniel Kochmański if (initialized) /* Avoid initializing mmc multiple times */ 18241b26bab1SDaniel Kochmański return 0; 18251b26bab1SDaniel Kochmański initialized = 1; 18261b26bab1SDaniel Kochmański 1827272cc70bSAndy Fleming INIT_LIST_HEAD (&mmc_devices); 1828272cc70bSAndy Fleming cur_dev_num = 0; 1829272cc70bSAndy Fleming 18308e3332e2SSjoerd Simons ret = mmc_probe(bis); 18318e3332e2SSjoerd Simons if (ret) 18328e3332e2SSjoerd Simons return ret; 1833272cc70bSAndy Fleming 1834bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD 1835272cc70bSAndy Fleming print_mmc_devices(','); 1836bb0dc108SYing Zhang #endif 1837272cc70bSAndy Fleming 1838e9550449SChe-Liang Chiou do_preinit(); 1839272cc70bSAndy Fleming return 0; 1840272cc70bSAndy Fleming } 18413690d6d6SAmar 18423690d6d6SAmar #ifdef CONFIG_SUPPORT_EMMC_BOOT 18433690d6d6SAmar /* 18443690d6d6SAmar * This function changes the size of boot partition and the size of rpmb 18453690d6d6SAmar * partition present on EMMC devices. 18463690d6d6SAmar * 18473690d6d6SAmar * Input Parameters: 18483690d6d6SAmar * struct *mmc: pointer for the mmc device strcuture 18493690d6d6SAmar * bootsize: size of boot partition 18503690d6d6SAmar * rpmbsize: size of rpmb partition 18513690d6d6SAmar * 18523690d6d6SAmar * Returns 0 on success. 18533690d6d6SAmar */ 18543690d6d6SAmar 18553690d6d6SAmar int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize, 18563690d6d6SAmar unsigned long rpmbsize) 18573690d6d6SAmar { 18583690d6d6SAmar int err; 18593690d6d6SAmar struct mmc_cmd cmd; 18603690d6d6SAmar 18613690d6d6SAmar /* Only use this command for raw EMMC moviNAND. Enter backdoor mode */ 18623690d6d6SAmar cmd.cmdidx = MMC_CMD_RES_MAN; 18633690d6d6SAmar cmd.resp_type = MMC_RSP_R1b; 18643690d6d6SAmar cmd.cmdarg = MMC_CMD62_ARG1; 18653690d6d6SAmar 18663690d6d6SAmar err = mmc_send_cmd(mmc, &cmd, NULL); 18673690d6d6SAmar if (err) { 18683690d6d6SAmar debug("mmc_boot_partition_size_change: Error1 = %d\n", err); 18693690d6d6SAmar return err; 18703690d6d6SAmar } 18713690d6d6SAmar 18723690d6d6SAmar /* Boot partition changing mode */ 18733690d6d6SAmar cmd.cmdidx = MMC_CMD_RES_MAN; 18743690d6d6SAmar cmd.resp_type = MMC_RSP_R1b; 18753690d6d6SAmar cmd.cmdarg = MMC_CMD62_ARG2; 18763690d6d6SAmar 18773690d6d6SAmar err = mmc_send_cmd(mmc, &cmd, NULL); 18783690d6d6SAmar if (err) { 18793690d6d6SAmar debug("mmc_boot_partition_size_change: Error2 = %d\n", err); 18803690d6d6SAmar return err; 18813690d6d6SAmar } 18823690d6d6SAmar /* boot partition size is multiple of 128KB */ 18833690d6d6SAmar bootsize = (bootsize * 1024) / 128; 18843690d6d6SAmar 18853690d6d6SAmar /* Arg: boot partition size */ 18863690d6d6SAmar cmd.cmdidx = MMC_CMD_RES_MAN; 18873690d6d6SAmar cmd.resp_type = MMC_RSP_R1b; 18883690d6d6SAmar cmd.cmdarg = bootsize; 18893690d6d6SAmar 18903690d6d6SAmar err = mmc_send_cmd(mmc, &cmd, NULL); 18913690d6d6SAmar if (err) { 18923690d6d6SAmar debug("mmc_boot_partition_size_change: Error3 = %d\n", err); 18933690d6d6SAmar return err; 18943690d6d6SAmar } 18953690d6d6SAmar /* RPMB partition size is multiple of 128KB */ 18963690d6d6SAmar rpmbsize = (rpmbsize * 1024) / 128; 18973690d6d6SAmar /* Arg: RPMB partition size */ 18983690d6d6SAmar cmd.cmdidx = MMC_CMD_RES_MAN; 18993690d6d6SAmar cmd.resp_type = MMC_RSP_R1b; 19003690d6d6SAmar cmd.cmdarg = rpmbsize; 19013690d6d6SAmar 19023690d6d6SAmar err = mmc_send_cmd(mmc, &cmd, NULL); 19033690d6d6SAmar if (err) { 19043690d6d6SAmar debug("mmc_boot_partition_size_change: Error4 = %d\n", err); 19053690d6d6SAmar return err; 19063690d6d6SAmar } 19073690d6d6SAmar return 0; 19083690d6d6SAmar } 19093690d6d6SAmar 19103690d6d6SAmar /* 19115a99b9deSTom Rini * Modify EXT_CSD[177] which is BOOT_BUS_WIDTH 19125a99b9deSTom Rini * based on the passed in values for BOOT_BUS_WIDTH, RESET_BOOT_BUS_WIDTH 19135a99b9deSTom Rini * and BOOT_MODE. 19145a99b9deSTom Rini * 19155a99b9deSTom Rini * Returns 0 on success. 19165a99b9deSTom Rini */ 19175a99b9deSTom Rini int mmc_set_boot_bus_width(struct mmc *mmc, u8 width, u8 reset, u8 mode) 19185a99b9deSTom Rini { 19195a99b9deSTom Rini int err; 19205a99b9deSTom Rini 19215a99b9deSTom Rini err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_BUS_WIDTH, 19225a99b9deSTom Rini EXT_CSD_BOOT_BUS_WIDTH_MODE(mode) | 19235a99b9deSTom Rini EXT_CSD_BOOT_BUS_WIDTH_RESET(reset) | 19245a99b9deSTom Rini EXT_CSD_BOOT_BUS_WIDTH_WIDTH(width)); 19255a99b9deSTom Rini 19265a99b9deSTom Rini if (err) 19275a99b9deSTom Rini return err; 19285a99b9deSTom Rini return 0; 19295a99b9deSTom Rini } 19305a99b9deSTom Rini 19315a99b9deSTom Rini /* 1932792970b0STom Rini * Modify EXT_CSD[179] which is PARTITION_CONFIG (formerly BOOT_CONFIG) 1933792970b0STom Rini * based on the passed in values for BOOT_ACK, BOOT_PARTITION_ENABLE and 1934792970b0STom Rini * PARTITION_ACCESS. 1935792970b0STom Rini * 1936792970b0STom Rini * Returns 0 on success. 1937792970b0STom Rini */ 1938792970b0STom Rini int mmc_set_part_conf(struct mmc *mmc, u8 ack, u8 part_num, u8 access) 1939792970b0STom Rini { 1940792970b0STom Rini int err; 1941792970b0STom Rini 1942792970b0STom Rini err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, 1943792970b0STom Rini EXT_CSD_BOOT_ACK(ack) | 1944792970b0STom Rini EXT_CSD_BOOT_PART_NUM(part_num) | 1945792970b0STom Rini EXT_CSD_PARTITION_ACCESS(access)); 1946792970b0STom Rini 1947792970b0STom Rini if (err) 1948792970b0STom Rini return err; 1949792970b0STom Rini return 0; 1950792970b0STom Rini } 195133ace362STom Rini 195233ace362STom Rini /* 195333ace362STom Rini * Modify EXT_CSD[162] which is RST_n_FUNCTION based on the given value 195433ace362STom Rini * for enable. Note that this is a write-once field for non-zero values. 195533ace362STom Rini * 195633ace362STom Rini * Returns 0 on success. 195733ace362STom Rini */ 195833ace362STom Rini int mmc_set_rst_n_function(struct mmc *mmc, u8 enable) 195933ace362STom Rini { 196033ace362STom Rini return mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_RST_N_FUNCTION, 196133ace362STom Rini enable); 196233ace362STom Rini } 19633690d6d6SAmar #endif 1964