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> 182051aefeSPeng Fan #include <power/regulator.h> 19272cc70bSAndy Fleming #include <malloc.h> 20cf92e05cSSimon Glass #include <memalign.h> 21272cc70bSAndy Fleming #include <linux/list.h> 229b1f942cSRabin Vincent #include <div64.h> 23da61fa5fSPaul Burton #include "mmc_private.h" 24272cc70bSAndy Fleming 253697e599SPeng Fan static const unsigned int sd_au_size[] = { 263697e599SPeng Fan 0, SZ_16K / 512, SZ_32K / 512, 273697e599SPeng Fan SZ_64K / 512, SZ_128K / 512, SZ_256K / 512, 283697e599SPeng Fan SZ_512K / 512, SZ_1M / 512, SZ_2M / 512, 293697e599SPeng Fan SZ_4M / 512, SZ_8M / 512, (SZ_8M + SZ_4M) / 512, 303697e599SPeng Fan SZ_16M / 512, (SZ_16M + SZ_8M) / 512, SZ_32M / 512, SZ_64M / 512, 313697e599SPeng Fan }; 323697e599SPeng Fan 33aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage); 34fb7c3bebSKishon Vijay Abraham I static int mmc_power_cycle(struct mmc *mmc); 3501298da3SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps); 36aff5d3c8SKishon Vijay Abraham I 37b5b838f1SMarek Vasut #if CONFIG_IS_ENABLED(MMC_TINY) 38b5b838f1SMarek Vasut static struct mmc mmc_static; 39b5b838f1SMarek Vasut struct mmc *find_mmc_device(int dev_num) 40b5b838f1SMarek Vasut { 41b5b838f1SMarek Vasut return &mmc_static; 42b5b838f1SMarek Vasut } 43b5b838f1SMarek Vasut 44b5b838f1SMarek Vasut void mmc_do_preinit(void) 45b5b838f1SMarek Vasut { 46b5b838f1SMarek Vasut struct mmc *m = &mmc_static; 47b5b838f1SMarek Vasut #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 48b5b838f1SMarek Vasut mmc_set_preinit(m, 1); 49b5b838f1SMarek Vasut #endif 50b5b838f1SMarek Vasut if (m->preinit) 51b5b838f1SMarek Vasut mmc_start_init(m); 52b5b838f1SMarek Vasut } 53b5b838f1SMarek Vasut 54b5b838f1SMarek Vasut struct blk_desc *mmc_get_blk_desc(struct mmc *mmc) 55b5b838f1SMarek Vasut { 56b5b838f1SMarek Vasut return &mmc->block_dev; 57b5b838f1SMarek Vasut } 58b5b838f1SMarek Vasut #endif 59b5b838f1SMarek Vasut 60e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 61c10b85d6SJean-Jacques Hiblot 62c10b85d6SJean-Jacques Hiblot static int mmc_wait_dat0(struct mmc *mmc, int state, int timeout) 63c10b85d6SJean-Jacques Hiblot { 64c10b85d6SJean-Jacques Hiblot return -ENOSYS; 65c10b85d6SJean-Jacques Hiblot } 66c10b85d6SJean-Jacques Hiblot 67750121c3SJeroen Hofstee __weak int board_mmc_getwp(struct mmc *mmc) 68d23d8d7eSNikita Kiryanov { 69d23d8d7eSNikita Kiryanov return -1; 70d23d8d7eSNikita Kiryanov } 71d23d8d7eSNikita Kiryanov 72d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc) 73d23d8d7eSNikita Kiryanov { 74d23d8d7eSNikita Kiryanov int wp; 75d23d8d7eSNikita Kiryanov 76d23d8d7eSNikita Kiryanov wp = board_mmc_getwp(mmc); 77d23d8d7eSNikita Kiryanov 78d4e1da4eSPeter Korsgaard if (wp < 0) { 7993bfd616SPantelis Antoniou if (mmc->cfg->ops->getwp) 8093bfd616SPantelis Antoniou wp = mmc->cfg->ops->getwp(mmc); 81d4e1da4eSPeter Korsgaard else 82d4e1da4eSPeter Korsgaard wp = 0; 83d4e1da4eSPeter Korsgaard } 84d23d8d7eSNikita Kiryanov 85d23d8d7eSNikita Kiryanov return wp; 86d23d8d7eSNikita Kiryanov } 87d23d8d7eSNikita Kiryanov 88cee9ab7cSJeroen Hofstee __weak int board_mmc_getcd(struct mmc *mmc) 89cee9ab7cSJeroen Hofstee { 9011fdade2SStefano Babic return -1; 9111fdade2SStefano Babic } 928ca51e51SSimon Glass #endif 9311fdade2SStefano Babic 948635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE 95c0c76ebaSSimon Glass void mmmc_trace_before_send(struct mmc *mmc, struct mmc_cmd *cmd) 96c0c76ebaSSimon Glass { 97c0c76ebaSSimon Glass printf("CMD_SEND:%d\n", cmd->cmdidx); 98c0c76ebaSSimon Glass printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg); 99c0c76ebaSSimon Glass } 100c0c76ebaSSimon Glass 101c0c76ebaSSimon Glass void mmmc_trace_after_send(struct mmc *mmc, struct mmc_cmd *cmd, int ret) 102c0c76ebaSSimon Glass { 1035db2fe3aSRaffaele Recalcati int i; 1045db2fe3aSRaffaele Recalcati u8 *ptr; 1055db2fe3aSRaffaele Recalcati 1067863ce58SBin Meng if (ret) { 1077863ce58SBin Meng printf("\t\tRET\t\t\t %d\n", ret); 1087863ce58SBin Meng } else { 1095db2fe3aSRaffaele Recalcati switch (cmd->resp_type) { 1105db2fe3aSRaffaele Recalcati case MMC_RSP_NONE: 1115db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_NONE\n"); 1125db2fe3aSRaffaele Recalcati break; 1135db2fe3aSRaffaele Recalcati case MMC_RSP_R1: 1145db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n", 1155db2fe3aSRaffaele Recalcati cmd->response[0]); 1165db2fe3aSRaffaele Recalcati break; 1175db2fe3aSRaffaele Recalcati case MMC_RSP_R1b: 1185db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n", 1195db2fe3aSRaffaele Recalcati cmd->response[0]); 1205db2fe3aSRaffaele Recalcati break; 1215db2fe3aSRaffaele Recalcati case MMC_RSP_R2: 1225db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R2\t\t 0x%08X \n", 1235db2fe3aSRaffaele Recalcati cmd->response[0]); 1245db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1255db2fe3aSRaffaele Recalcati cmd->response[1]); 1265db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1275db2fe3aSRaffaele Recalcati cmd->response[2]); 1285db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1295db2fe3aSRaffaele Recalcati cmd->response[3]); 1305db2fe3aSRaffaele Recalcati printf("\n"); 1315db2fe3aSRaffaele Recalcati printf("\t\t\t\t\tDUMPING DATA\n"); 1325db2fe3aSRaffaele Recalcati for (i = 0; i < 4; i++) { 1335db2fe3aSRaffaele Recalcati int j; 1345db2fe3aSRaffaele Recalcati printf("\t\t\t\t\t%03d - ", i*4); 135146bec79SDirk Behme ptr = (u8 *)&cmd->response[i]; 1365db2fe3aSRaffaele Recalcati ptr += 3; 1375db2fe3aSRaffaele Recalcati for (j = 0; j < 4; j++) 1385db2fe3aSRaffaele Recalcati printf("%02X ", *ptr--); 1395db2fe3aSRaffaele Recalcati printf("\n"); 1405db2fe3aSRaffaele Recalcati } 1415db2fe3aSRaffaele Recalcati break; 1425db2fe3aSRaffaele Recalcati case MMC_RSP_R3: 1435db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n", 1445db2fe3aSRaffaele Recalcati cmd->response[0]); 1455db2fe3aSRaffaele Recalcati break; 1465db2fe3aSRaffaele Recalcati default: 1475db2fe3aSRaffaele Recalcati printf("\t\tERROR MMC rsp not supported\n"); 1485db2fe3aSRaffaele Recalcati break; 1495db2fe3aSRaffaele Recalcati } 1507863ce58SBin Meng } 151c0c76ebaSSimon Glass } 152c0c76ebaSSimon Glass 153c0c76ebaSSimon Glass void mmc_trace_state(struct mmc *mmc, struct mmc_cmd *cmd) 154c0c76ebaSSimon Glass { 155c0c76ebaSSimon Glass int status; 156c0c76ebaSSimon Glass 157c0c76ebaSSimon Glass status = (cmd->response[0] & MMC_STATUS_CURR_STATE) >> 9; 158c0c76ebaSSimon Glass printf("CURR STATE:%d\n", status); 159c0c76ebaSSimon Glass } 1605db2fe3aSRaffaele Recalcati #endif 161c0c76ebaSSimon Glass 16235f9e196SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG) 16335f9e196SJean-Jacques Hiblot const char *mmc_mode_name(enum bus_mode mode) 16435f9e196SJean-Jacques Hiblot { 16535f9e196SJean-Jacques Hiblot static const char *const names[] = { 16635f9e196SJean-Jacques Hiblot [MMC_LEGACY] = "MMC legacy", 16735f9e196SJean-Jacques Hiblot [SD_LEGACY] = "SD Legacy", 16835f9e196SJean-Jacques Hiblot [MMC_HS] = "MMC High Speed (26MHz)", 16935f9e196SJean-Jacques Hiblot [SD_HS] = "SD High Speed (50MHz)", 17035f9e196SJean-Jacques Hiblot [UHS_SDR12] = "UHS SDR12 (25MHz)", 17135f9e196SJean-Jacques Hiblot [UHS_SDR25] = "UHS SDR25 (50MHz)", 17235f9e196SJean-Jacques Hiblot [UHS_SDR50] = "UHS SDR50 (100MHz)", 17335f9e196SJean-Jacques Hiblot [UHS_SDR104] = "UHS SDR104 (208MHz)", 17435f9e196SJean-Jacques Hiblot [UHS_DDR50] = "UHS DDR50 (50MHz)", 17535f9e196SJean-Jacques Hiblot [MMC_HS_52] = "MMC High Speed (52MHz)", 17635f9e196SJean-Jacques Hiblot [MMC_DDR_52] = "MMC DDR52 (52MHz)", 17735f9e196SJean-Jacques Hiblot [MMC_HS_200] = "HS200 (200MHz)", 17835f9e196SJean-Jacques Hiblot }; 17935f9e196SJean-Jacques Hiblot 18035f9e196SJean-Jacques Hiblot if (mode >= MMC_MODES_END) 18135f9e196SJean-Jacques Hiblot return "Unknown mode"; 18235f9e196SJean-Jacques Hiblot else 18335f9e196SJean-Jacques Hiblot return names[mode]; 18435f9e196SJean-Jacques Hiblot } 18535f9e196SJean-Jacques Hiblot #endif 18635f9e196SJean-Jacques Hiblot 18705038576SJean-Jacques Hiblot static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode) 18805038576SJean-Jacques Hiblot { 18905038576SJean-Jacques Hiblot static const int freqs[] = { 19005038576SJean-Jacques Hiblot [SD_LEGACY] = 25000000, 19105038576SJean-Jacques Hiblot [MMC_HS] = 26000000, 19205038576SJean-Jacques Hiblot [SD_HS] = 50000000, 19305038576SJean-Jacques Hiblot [UHS_SDR12] = 25000000, 19405038576SJean-Jacques Hiblot [UHS_SDR25] = 50000000, 19505038576SJean-Jacques Hiblot [UHS_SDR50] = 100000000, 19605038576SJean-Jacques Hiblot [UHS_SDR104] = 208000000, 19705038576SJean-Jacques Hiblot [UHS_DDR50] = 50000000, 19805038576SJean-Jacques Hiblot [MMC_HS_52] = 52000000, 19905038576SJean-Jacques Hiblot [MMC_DDR_52] = 52000000, 20005038576SJean-Jacques Hiblot [MMC_HS_200] = 200000000, 20105038576SJean-Jacques Hiblot }; 20205038576SJean-Jacques Hiblot 20305038576SJean-Jacques Hiblot if (mode == MMC_LEGACY) 20405038576SJean-Jacques Hiblot return mmc->legacy_speed; 20505038576SJean-Jacques Hiblot else if (mode >= MMC_MODES_END) 20605038576SJean-Jacques Hiblot return 0; 20705038576SJean-Jacques Hiblot else 20805038576SJean-Jacques Hiblot return freqs[mode]; 20905038576SJean-Jacques Hiblot } 21005038576SJean-Jacques Hiblot 21135f9e196SJean-Jacques Hiblot static int mmc_select_mode(struct mmc *mmc, enum bus_mode mode) 21235f9e196SJean-Jacques Hiblot { 21335f9e196SJean-Jacques Hiblot mmc->selected_mode = mode; 21405038576SJean-Jacques Hiblot mmc->tran_speed = mmc_mode2freq(mmc, mode); 2153862b854SJean-Jacques Hiblot mmc->ddr_mode = mmc_is_mode_ddr(mode); 21635f9e196SJean-Jacques Hiblot debug("selecting mode %s (freq : %d MHz)\n", mmc_mode_name(mode), 21735f9e196SJean-Jacques Hiblot mmc->tran_speed / 1000000); 21835f9e196SJean-Jacques Hiblot return 0; 21935f9e196SJean-Jacques Hiblot } 22035f9e196SJean-Jacques Hiblot 221e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 222c0c76ebaSSimon Glass int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) 223c0c76ebaSSimon Glass { 224c0c76ebaSSimon Glass int ret; 225c0c76ebaSSimon Glass 226c0c76ebaSSimon Glass mmmc_trace_before_send(mmc, cmd); 227c0c76ebaSSimon Glass ret = mmc->cfg->ops->send_cmd(mmc, cmd, data); 228c0c76ebaSSimon Glass mmmc_trace_after_send(mmc, cmd, ret); 229c0c76ebaSSimon Glass 2308635ff9eSMarek Vasut return ret; 231272cc70bSAndy Fleming } 2328ca51e51SSimon Glass #endif 233272cc70bSAndy Fleming 234da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout) 2355d4fc8d9SRaffaele Recalcati { 2365d4fc8d9SRaffaele Recalcati struct mmc_cmd cmd; 237d617c426SJan Kloetzke int err, retries = 5; 2385d4fc8d9SRaffaele Recalcati 2395d4fc8d9SRaffaele Recalcati cmd.cmdidx = MMC_CMD_SEND_STATUS; 2405d4fc8d9SRaffaele Recalcati cmd.resp_type = MMC_RSP_R1; 241aaf3d41aSMarek Vasut if (!mmc_host_is_spi(mmc)) 242aaf3d41aSMarek Vasut cmd.cmdarg = mmc->rca << 16; 2435d4fc8d9SRaffaele Recalcati 2441677eef4SAndrew Gabbasov while (1) { 2455d4fc8d9SRaffaele Recalcati err = mmc_send_cmd(mmc, &cmd, NULL); 246d617c426SJan Kloetzke if (!err) { 247d617c426SJan Kloetzke if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) && 248d617c426SJan Kloetzke (cmd.response[0] & MMC_STATUS_CURR_STATE) != 249d617c426SJan Kloetzke MMC_STATE_PRG) 2505d4fc8d9SRaffaele Recalcati break; 251d0c221feSJean-Jacques Hiblot 252d0c221feSJean-Jacques Hiblot if (cmd.response[0] & MMC_STATUS_MASK) { 25356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 254d617c426SJan Kloetzke printf("Status Error: 0x%08X\n", 255d617c426SJan Kloetzke cmd.response[0]); 25656196826SPaul Burton #endif 257915ffa52SJaehoon Chung return -ECOMM; 258d617c426SJan Kloetzke } 259d617c426SJan Kloetzke } else if (--retries < 0) 260d617c426SJan Kloetzke return err; 2615d4fc8d9SRaffaele Recalcati 2621677eef4SAndrew Gabbasov if (timeout-- <= 0) 2631677eef4SAndrew Gabbasov break; 2645d4fc8d9SRaffaele Recalcati 2651677eef4SAndrew Gabbasov udelay(1000); 2661677eef4SAndrew Gabbasov } 2675d4fc8d9SRaffaele Recalcati 268c0c76ebaSSimon Glass mmc_trace_state(mmc, &cmd); 2695b0c942fSJongman Heo if (timeout <= 0) { 27056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2715d4fc8d9SRaffaele Recalcati printf("Timeout waiting card ready\n"); 27256196826SPaul Burton #endif 273915ffa52SJaehoon Chung return -ETIMEDOUT; 2745d4fc8d9SRaffaele Recalcati } 2755d4fc8d9SRaffaele Recalcati 2765d4fc8d9SRaffaele Recalcati return 0; 2775d4fc8d9SRaffaele Recalcati } 2785d4fc8d9SRaffaele Recalcati 279da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len) 280272cc70bSAndy Fleming { 281272cc70bSAndy Fleming struct mmc_cmd cmd; 28283dc4227SKishon Vijay Abraham I int err; 283272cc70bSAndy Fleming 284786e8f81SAndrew Gabbasov if (mmc->ddr_mode) 285d22e3d46SJaehoon Chung return 0; 286d22e3d46SJaehoon Chung 287272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SET_BLOCKLEN; 288272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 289272cc70bSAndy Fleming cmd.cmdarg = len; 290272cc70bSAndy Fleming 29183dc4227SKishon Vijay Abraham I err = mmc_send_cmd(mmc, &cmd, NULL); 29283dc4227SKishon Vijay Abraham I 29383dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS 29483dc4227SKishon Vijay Abraham I if (err && (mmc->quirks & MMC_QUIRK_RETRY_SET_BLOCKLEN)) { 29583dc4227SKishon Vijay Abraham I int retries = 4; 29683dc4227SKishon Vijay Abraham I /* 29783dc4227SKishon Vijay Abraham I * It has been seen that SET_BLOCKLEN may fail on the first 29883dc4227SKishon Vijay Abraham I * attempt, let's try a few more time 29983dc4227SKishon Vijay Abraham I */ 30083dc4227SKishon Vijay Abraham I do { 30183dc4227SKishon Vijay Abraham I err = mmc_send_cmd(mmc, &cmd, NULL); 30283dc4227SKishon Vijay Abraham I if (!err) 30383dc4227SKishon Vijay Abraham I break; 30483dc4227SKishon Vijay Abraham I } while (retries--); 30583dc4227SKishon Vijay Abraham I } 30683dc4227SKishon Vijay Abraham I #endif 30783dc4227SKishon Vijay Abraham I 30883dc4227SKishon Vijay Abraham I return err; 309272cc70bSAndy Fleming } 310272cc70bSAndy Fleming 3119815e3baSJean-Jacques Hiblot static const u8 tuning_blk_pattern_4bit[] = { 3129815e3baSJean-Jacques Hiblot 0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc, 3139815e3baSJean-Jacques Hiblot 0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef, 3149815e3baSJean-Jacques Hiblot 0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb, 3159815e3baSJean-Jacques Hiblot 0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef, 3169815e3baSJean-Jacques Hiblot 0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c, 3179815e3baSJean-Jacques Hiblot 0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee, 3189815e3baSJean-Jacques Hiblot 0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff, 3199815e3baSJean-Jacques Hiblot 0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde, 3209815e3baSJean-Jacques Hiblot }; 3219815e3baSJean-Jacques Hiblot 3229815e3baSJean-Jacques Hiblot static const u8 tuning_blk_pattern_8bit[] = { 3239815e3baSJean-Jacques Hiblot 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 3249815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc, 3259815e3baSJean-Jacques Hiblot 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff, 3269815e3baSJean-Jacques Hiblot 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff, 3279815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd, 3289815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, 3299815e3baSJean-Jacques Hiblot 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff, 3309815e3baSJean-Jacques Hiblot 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff, 3319815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 3329815e3baSJean-Jacques Hiblot 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 3339815e3baSJean-Jacques Hiblot 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 3349815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 3359815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 3369815e3baSJean-Jacques Hiblot 0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 3379815e3baSJean-Jacques Hiblot 0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 3389815e3baSJean-Jacques Hiblot 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 3399815e3baSJean-Jacques Hiblot }; 3409815e3baSJean-Jacques Hiblot 3419815e3baSJean-Jacques Hiblot int mmc_send_tuning(struct mmc *mmc, u32 opcode, int *cmd_error) 3429815e3baSJean-Jacques Hiblot { 3439815e3baSJean-Jacques Hiblot struct mmc_cmd cmd; 3449815e3baSJean-Jacques Hiblot struct mmc_data data; 3459815e3baSJean-Jacques Hiblot const u8 *tuning_block_pattern; 3469815e3baSJean-Jacques Hiblot int size, err; 3479815e3baSJean-Jacques Hiblot 3489815e3baSJean-Jacques Hiblot if (mmc->bus_width == 8) { 3499815e3baSJean-Jacques Hiblot tuning_block_pattern = tuning_blk_pattern_8bit; 3509815e3baSJean-Jacques Hiblot size = sizeof(tuning_blk_pattern_8bit); 3519815e3baSJean-Jacques Hiblot } else if (mmc->bus_width == 4) { 3529815e3baSJean-Jacques Hiblot tuning_block_pattern = tuning_blk_pattern_4bit; 3539815e3baSJean-Jacques Hiblot size = sizeof(tuning_blk_pattern_4bit); 3549815e3baSJean-Jacques Hiblot } else { 3559815e3baSJean-Jacques Hiblot return -EINVAL; 3569815e3baSJean-Jacques Hiblot } 3579815e3baSJean-Jacques Hiblot 3589815e3baSJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, data_buf, size); 3599815e3baSJean-Jacques Hiblot 3609815e3baSJean-Jacques Hiblot cmd.cmdidx = opcode; 3619815e3baSJean-Jacques Hiblot cmd.cmdarg = 0; 3629815e3baSJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 3639815e3baSJean-Jacques Hiblot 3649815e3baSJean-Jacques Hiblot data.dest = (void *)data_buf; 3659815e3baSJean-Jacques Hiblot data.blocks = 1; 3669815e3baSJean-Jacques Hiblot data.blocksize = size; 3679815e3baSJean-Jacques Hiblot data.flags = MMC_DATA_READ; 3689815e3baSJean-Jacques Hiblot 3699815e3baSJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, &data); 3709815e3baSJean-Jacques Hiblot if (err) 3719815e3baSJean-Jacques Hiblot return err; 3729815e3baSJean-Jacques Hiblot 3739815e3baSJean-Jacques Hiblot if (memcmp(data_buf, tuning_block_pattern, size)) 3749815e3baSJean-Jacques Hiblot return -EIO; 3759815e3baSJean-Jacques Hiblot 3769815e3baSJean-Jacques Hiblot return 0; 3779815e3baSJean-Jacques Hiblot } 3789815e3baSJean-Jacques Hiblot 379ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start, 380fdbb873eSKim Phillips lbaint_t blkcnt) 381272cc70bSAndy Fleming { 382272cc70bSAndy Fleming struct mmc_cmd cmd; 383272cc70bSAndy Fleming struct mmc_data data; 384272cc70bSAndy Fleming 3854a1a06bcSAlagu Sankar if (blkcnt > 1) 3864a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; 3874a1a06bcSAlagu Sankar else 388272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK; 389272cc70bSAndy Fleming 390272cc70bSAndy Fleming if (mmc->high_capacity) 3914a1a06bcSAlagu Sankar cmd.cmdarg = start; 392272cc70bSAndy Fleming else 3934a1a06bcSAlagu Sankar cmd.cmdarg = start * mmc->read_bl_len; 394272cc70bSAndy Fleming 395272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 396272cc70bSAndy Fleming 397272cc70bSAndy Fleming data.dest = dst; 3984a1a06bcSAlagu Sankar data.blocks = blkcnt; 399272cc70bSAndy Fleming data.blocksize = mmc->read_bl_len; 400272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 401272cc70bSAndy Fleming 4024a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, &data)) 4034a1a06bcSAlagu Sankar return 0; 4044a1a06bcSAlagu Sankar 4054a1a06bcSAlagu Sankar if (blkcnt > 1) { 4064a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; 4074a1a06bcSAlagu Sankar cmd.cmdarg = 0; 4084a1a06bcSAlagu Sankar cmd.resp_type = MMC_RSP_R1b; 4094a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, NULL)) { 41056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 4114a1a06bcSAlagu Sankar printf("mmc fail to send stop cmd\n"); 41256196826SPaul Burton #endif 4134a1a06bcSAlagu Sankar return 0; 4144a1a06bcSAlagu Sankar } 415272cc70bSAndy Fleming } 416272cc70bSAndy Fleming 4174a1a06bcSAlagu Sankar return blkcnt; 418272cc70bSAndy Fleming } 419272cc70bSAndy Fleming 420c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK) 4217dba0b93SSimon Glass ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst) 42233fb211dSSimon Glass #else 4237dba0b93SSimon Glass ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt, 4247dba0b93SSimon Glass void *dst) 42533fb211dSSimon Glass #endif 426272cc70bSAndy Fleming { 427c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK) 42833fb211dSSimon Glass struct blk_desc *block_dev = dev_get_uclass_platdata(dev); 42933fb211dSSimon Glass #endif 430bcce53d0SSimon Glass int dev_num = block_dev->devnum; 431873cc1d7SStephen Warren int err; 4324a1a06bcSAlagu Sankar lbaint_t cur, blocks_todo = blkcnt; 433272cc70bSAndy Fleming 4344a1a06bcSAlagu Sankar if (blkcnt == 0) 4354a1a06bcSAlagu Sankar return 0; 4364a1a06bcSAlagu Sankar 4374a1a06bcSAlagu Sankar struct mmc *mmc = find_mmc_device(dev_num); 438272cc70bSAndy Fleming if (!mmc) 439272cc70bSAndy Fleming return 0; 440272cc70bSAndy Fleming 441b5b838f1SMarek Vasut if (CONFIG_IS_ENABLED(MMC_TINY)) 442b5b838f1SMarek Vasut err = mmc_switch_part(mmc, block_dev->hwpart); 443b5b838f1SMarek Vasut else 44469f45cd5SSimon Glass err = blk_dselect_hwpart(block_dev, block_dev->hwpart); 445b5b838f1SMarek Vasut 446873cc1d7SStephen Warren if (err < 0) 447873cc1d7SStephen Warren return 0; 448873cc1d7SStephen Warren 449c40fdca6SSimon Glass if ((start + blkcnt) > block_dev->lba) { 45056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 451ff8fef56SSascha Silbe printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n", 452c40fdca6SSimon Glass start + blkcnt, block_dev->lba); 45356196826SPaul Burton #endif 454d2bf29e3SLei Wen return 0; 455d2bf29e3SLei Wen } 456272cc70bSAndy Fleming 45711692991SSimon Glass if (mmc_set_blocklen(mmc, mmc->read_bl_len)) { 45811692991SSimon Glass debug("%s: Failed to set blocklen\n", __func__); 459272cc70bSAndy Fleming return 0; 46011692991SSimon Glass } 461272cc70bSAndy Fleming 4624a1a06bcSAlagu Sankar do { 46393bfd616SPantelis Antoniou cur = (blocks_todo > mmc->cfg->b_max) ? 46493bfd616SPantelis Antoniou mmc->cfg->b_max : blocks_todo; 46511692991SSimon Glass if (mmc_read_blocks(mmc, dst, start, cur) != cur) { 46611692991SSimon Glass debug("%s: Failed to read blocks\n", __func__); 4674a1a06bcSAlagu Sankar return 0; 46811692991SSimon Glass } 4694a1a06bcSAlagu Sankar blocks_todo -= cur; 4704a1a06bcSAlagu Sankar start += cur; 4714a1a06bcSAlagu Sankar dst += cur * mmc->read_bl_len; 4724a1a06bcSAlagu Sankar } while (blocks_todo > 0); 473272cc70bSAndy Fleming 474272cc70bSAndy Fleming return blkcnt; 475272cc70bSAndy Fleming } 476272cc70bSAndy Fleming 477fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc) 478272cc70bSAndy Fleming { 479272cc70bSAndy Fleming struct mmc_cmd cmd; 480272cc70bSAndy Fleming int err; 481272cc70bSAndy Fleming 482272cc70bSAndy Fleming udelay(1000); 483272cc70bSAndy Fleming 484272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_GO_IDLE_STATE; 485272cc70bSAndy Fleming cmd.cmdarg = 0; 486272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_NONE; 487272cc70bSAndy Fleming 488272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 489272cc70bSAndy Fleming 490272cc70bSAndy Fleming if (err) 491272cc70bSAndy Fleming return err; 492272cc70bSAndy Fleming 493272cc70bSAndy Fleming udelay(2000); 494272cc70bSAndy Fleming 495272cc70bSAndy Fleming return 0; 496272cc70bSAndy Fleming } 497272cc70bSAndy Fleming 498c10b85d6SJean-Jacques Hiblot static int mmc_switch_voltage(struct mmc *mmc, int signal_voltage) 499c10b85d6SJean-Jacques Hiblot { 500c10b85d6SJean-Jacques Hiblot struct mmc_cmd cmd; 501c10b85d6SJean-Jacques Hiblot int err = 0; 502c10b85d6SJean-Jacques Hiblot 503c10b85d6SJean-Jacques Hiblot /* 504c10b85d6SJean-Jacques Hiblot * Send CMD11 only if the request is to switch the card to 505c10b85d6SJean-Jacques Hiblot * 1.8V signalling. 506c10b85d6SJean-Jacques Hiblot */ 507c10b85d6SJean-Jacques Hiblot if (signal_voltage == MMC_SIGNAL_VOLTAGE_330) 508c10b85d6SJean-Jacques Hiblot return mmc_set_signal_voltage(mmc, signal_voltage); 509c10b85d6SJean-Jacques Hiblot 510c10b85d6SJean-Jacques Hiblot cmd.cmdidx = SD_CMD_SWITCH_UHS18V; 511c10b85d6SJean-Jacques Hiblot cmd.cmdarg = 0; 512c10b85d6SJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 513c10b85d6SJean-Jacques Hiblot 514c10b85d6SJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 515c10b85d6SJean-Jacques Hiblot if (err) 516c10b85d6SJean-Jacques Hiblot return err; 517c10b85d6SJean-Jacques Hiblot 518c10b85d6SJean-Jacques Hiblot if (!mmc_host_is_spi(mmc) && (cmd.response[0] & MMC_STATUS_ERROR)) 519c10b85d6SJean-Jacques Hiblot return -EIO; 520c10b85d6SJean-Jacques Hiblot 521c10b85d6SJean-Jacques Hiblot /* 522c10b85d6SJean-Jacques Hiblot * The card should drive cmd and dat[0:3] low immediately 523c10b85d6SJean-Jacques Hiblot * after the response of cmd11, but wait 100 us to be sure 524c10b85d6SJean-Jacques Hiblot */ 525c10b85d6SJean-Jacques Hiblot err = mmc_wait_dat0(mmc, 0, 100); 526c10b85d6SJean-Jacques Hiblot if (err == -ENOSYS) 527c10b85d6SJean-Jacques Hiblot udelay(100); 528c10b85d6SJean-Jacques Hiblot else if (err) 529c10b85d6SJean-Jacques Hiblot return -ETIMEDOUT; 530c10b85d6SJean-Jacques Hiblot 531c10b85d6SJean-Jacques Hiblot /* 532c10b85d6SJean-Jacques Hiblot * During a signal voltage level switch, the clock must be gated 533c10b85d6SJean-Jacques Hiblot * for 5 ms according to the SD spec 534c10b85d6SJean-Jacques Hiblot */ 535c10b85d6SJean-Jacques Hiblot mmc_set_clock(mmc, mmc->clock, true); 536c10b85d6SJean-Jacques Hiblot 537c10b85d6SJean-Jacques Hiblot err = mmc_set_signal_voltage(mmc, signal_voltage); 538c10b85d6SJean-Jacques Hiblot if (err) 539c10b85d6SJean-Jacques Hiblot return err; 540c10b85d6SJean-Jacques Hiblot 541c10b85d6SJean-Jacques Hiblot /* Keep clock gated for at least 10 ms, though spec only says 5 ms */ 542c10b85d6SJean-Jacques Hiblot mdelay(10); 543c10b85d6SJean-Jacques Hiblot mmc_set_clock(mmc, mmc->clock, false); 544c10b85d6SJean-Jacques Hiblot 545c10b85d6SJean-Jacques Hiblot /* 546c10b85d6SJean-Jacques Hiblot * Failure to switch is indicated by the card holding 547c10b85d6SJean-Jacques Hiblot * dat[0:3] low. Wait for at least 1 ms according to spec 548c10b85d6SJean-Jacques Hiblot */ 549c10b85d6SJean-Jacques Hiblot err = mmc_wait_dat0(mmc, 1, 1000); 550c10b85d6SJean-Jacques Hiblot if (err == -ENOSYS) 551c10b85d6SJean-Jacques Hiblot udelay(1000); 552c10b85d6SJean-Jacques Hiblot else if (err) 553c10b85d6SJean-Jacques Hiblot return -ETIMEDOUT; 554c10b85d6SJean-Jacques Hiblot 555c10b85d6SJean-Jacques Hiblot return 0; 556c10b85d6SJean-Jacques Hiblot } 557c10b85d6SJean-Jacques Hiblot 558c10b85d6SJean-Jacques Hiblot static int sd_send_op_cond(struct mmc *mmc, bool uhs_en) 559272cc70bSAndy Fleming { 560272cc70bSAndy Fleming int timeout = 1000; 561272cc70bSAndy Fleming int err; 562272cc70bSAndy Fleming struct mmc_cmd cmd; 563272cc70bSAndy Fleming 5641677eef4SAndrew Gabbasov while (1) { 565272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 566272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 567272cc70bSAndy Fleming cmd.cmdarg = 0; 568272cc70bSAndy Fleming 569272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 570272cc70bSAndy Fleming 571272cc70bSAndy Fleming if (err) 572272cc70bSAndy Fleming return err; 573272cc70bSAndy Fleming 574272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_OP_COND; 575272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R3; 576250de12bSStefano Babic 577250de12bSStefano Babic /* 578250de12bSStefano Babic * Most cards do not answer if some reserved bits 579250de12bSStefano Babic * in the ocr are set. However, Some controller 580250de12bSStefano Babic * can set bit 7 (reserved for low voltages), but 581250de12bSStefano Babic * how to manage low voltages SD card is not yet 582250de12bSStefano Babic * specified. 583250de12bSStefano Babic */ 584d52ebf10SThomas Chou cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 : 58593bfd616SPantelis Antoniou (mmc->cfg->voltages & 0xff8000); 586272cc70bSAndy Fleming 587272cc70bSAndy Fleming if (mmc->version == SD_VERSION_2) 588272cc70bSAndy Fleming cmd.cmdarg |= OCR_HCS; 589272cc70bSAndy Fleming 590c10b85d6SJean-Jacques Hiblot if (uhs_en) 591c10b85d6SJean-Jacques Hiblot cmd.cmdarg |= OCR_S18R; 592c10b85d6SJean-Jacques Hiblot 593272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 594272cc70bSAndy Fleming 595272cc70bSAndy Fleming if (err) 596272cc70bSAndy Fleming return err; 597272cc70bSAndy Fleming 5981677eef4SAndrew Gabbasov if (cmd.response[0] & OCR_BUSY) 5991677eef4SAndrew Gabbasov break; 600272cc70bSAndy Fleming 6011677eef4SAndrew Gabbasov if (timeout-- <= 0) 602915ffa52SJaehoon Chung return -EOPNOTSUPP; 603272cc70bSAndy Fleming 6041677eef4SAndrew Gabbasov udelay(1000); 6051677eef4SAndrew Gabbasov } 6061677eef4SAndrew Gabbasov 607272cc70bSAndy Fleming if (mmc->version != SD_VERSION_2) 608272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 609272cc70bSAndy Fleming 610d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 611d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 612d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 613d52ebf10SThomas Chou cmd.cmdarg = 0; 614d52ebf10SThomas Chou 615d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 616d52ebf10SThomas Chou 617d52ebf10SThomas Chou if (err) 618d52ebf10SThomas Chou return err; 619d52ebf10SThomas Chou } 620d52ebf10SThomas Chou 621998be3ddSRabin Vincent mmc->ocr = cmd.response[0]; 622272cc70bSAndy Fleming 623c10b85d6SJean-Jacques Hiblot if (uhs_en && !(mmc_host_is_spi(mmc)) && (cmd.response[0] & 0x41000000) 624c10b85d6SJean-Jacques Hiblot == 0x41000000) { 625c10b85d6SJean-Jacques Hiblot err = mmc_switch_voltage(mmc, MMC_SIGNAL_VOLTAGE_180); 626c10b85d6SJean-Jacques Hiblot if (err) 627c10b85d6SJean-Jacques Hiblot return err; 628c10b85d6SJean-Jacques Hiblot } 629c10b85d6SJean-Jacques Hiblot 630272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 631272cc70bSAndy Fleming mmc->rca = 0; 632272cc70bSAndy Fleming 633272cc70bSAndy Fleming return 0; 634272cc70bSAndy Fleming } 635272cc70bSAndy Fleming 6365289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg) 637272cc70bSAndy Fleming { 6385289b535SAndrew Gabbasov struct mmc_cmd cmd; 639272cc70bSAndy Fleming int err; 640272cc70bSAndy Fleming 6415289b535SAndrew Gabbasov cmd.cmdidx = MMC_CMD_SEND_OP_COND; 6425289b535SAndrew Gabbasov cmd.resp_type = MMC_RSP_R3; 6435289b535SAndrew Gabbasov cmd.cmdarg = 0; 6445a20397bSRob Herring if (use_arg && !mmc_host_is_spi(mmc)) 6455a20397bSRob Herring cmd.cmdarg = OCR_HCS | 64693bfd616SPantelis Antoniou (mmc->cfg->voltages & 647a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_VOLTAGE_MASK)) | 648a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_ACCESS_MODE); 649e9550449SChe-Liang Chiou 6505289b535SAndrew Gabbasov err = mmc_send_cmd(mmc, &cmd, NULL); 651e9550449SChe-Liang Chiou if (err) 652e9550449SChe-Liang Chiou return err; 6535289b535SAndrew Gabbasov mmc->ocr = cmd.response[0]; 654e9550449SChe-Liang Chiou return 0; 655e9550449SChe-Liang Chiou } 656e9550449SChe-Liang Chiou 657750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc) 658e9550449SChe-Liang Chiou { 659e9550449SChe-Liang Chiou int err, i; 660e9550449SChe-Liang Chiou 661272cc70bSAndy Fleming /* Some cards seem to need this */ 662272cc70bSAndy Fleming mmc_go_idle(mmc); 663272cc70bSAndy Fleming 66431cacbabSRaffaele Recalcati /* Asking to the card its capabilities */ 665e9550449SChe-Liang Chiou for (i = 0; i < 2; i++) { 6665289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, i != 0); 66731cacbabSRaffaele Recalcati if (err) 66831cacbabSRaffaele Recalcati return err; 66931cacbabSRaffaele Recalcati 670e9550449SChe-Liang Chiou /* exit if not busy (flag seems to be inverted) */ 671a626c8d4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 672bd47c135SAndrew Gabbasov break; 673e9550449SChe-Liang Chiou } 674bd47c135SAndrew Gabbasov mmc->op_cond_pending = 1; 675bd47c135SAndrew Gabbasov return 0; 676e9550449SChe-Liang Chiou } 67731cacbabSRaffaele Recalcati 678750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc) 679e9550449SChe-Liang Chiou { 680e9550449SChe-Liang Chiou struct mmc_cmd cmd; 681e9550449SChe-Liang Chiou int timeout = 1000; 682e9550449SChe-Liang Chiou uint start; 683e9550449SChe-Liang Chiou int err; 684e9550449SChe-Liang Chiou 685e9550449SChe-Liang Chiou mmc->op_cond_pending = 0; 686cc17c01fSAndrew Gabbasov if (!(mmc->ocr & OCR_BUSY)) { 687d188b113SYangbo Lu /* Some cards seem to need this */ 688d188b113SYangbo Lu mmc_go_idle(mmc); 689d188b113SYangbo Lu 690e9550449SChe-Liang Chiou start = get_timer(0); 6911677eef4SAndrew Gabbasov while (1) { 6925289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, 1); 693272cc70bSAndy Fleming if (err) 694272cc70bSAndy Fleming return err; 6951677eef4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 6961677eef4SAndrew Gabbasov break; 697e9550449SChe-Liang Chiou if (get_timer(start) > timeout) 698915ffa52SJaehoon Chung return -EOPNOTSUPP; 699e9550449SChe-Liang Chiou udelay(100); 7001677eef4SAndrew Gabbasov } 701cc17c01fSAndrew Gabbasov } 702272cc70bSAndy Fleming 703d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 704d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 705d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 706d52ebf10SThomas Chou cmd.cmdarg = 0; 707d52ebf10SThomas Chou 708d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 709d52ebf10SThomas Chou 710d52ebf10SThomas Chou if (err) 711d52ebf10SThomas Chou return err; 712a626c8d4SAndrew Gabbasov 713a626c8d4SAndrew Gabbasov mmc->ocr = cmd.response[0]; 714d52ebf10SThomas Chou } 715d52ebf10SThomas Chou 716272cc70bSAndy Fleming mmc->version = MMC_VERSION_UNKNOWN; 717272cc70bSAndy Fleming 718272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 719def816a2SStephen Warren mmc->rca = 1; 720272cc70bSAndy Fleming 721272cc70bSAndy Fleming return 0; 722272cc70bSAndy Fleming } 723272cc70bSAndy Fleming 724272cc70bSAndy Fleming 725fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd) 726272cc70bSAndy Fleming { 727272cc70bSAndy Fleming struct mmc_cmd cmd; 728272cc70bSAndy Fleming struct mmc_data data; 729272cc70bSAndy Fleming int err; 730272cc70bSAndy Fleming 731272cc70bSAndy Fleming /* Get the Card Status Register */ 732272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_EXT_CSD; 733272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 734272cc70bSAndy Fleming cmd.cmdarg = 0; 735272cc70bSAndy Fleming 736cdfd1ac6SYoshihiro Shimoda data.dest = (char *)ext_csd; 737272cc70bSAndy Fleming data.blocks = 1; 7388bfa195eSSimon Glass data.blocksize = MMC_MAX_BLOCK_LEN; 739272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 740272cc70bSAndy Fleming 741272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 742272cc70bSAndy Fleming 743272cc70bSAndy Fleming return err; 744272cc70bSAndy Fleming } 745272cc70bSAndy Fleming 746c40704f4SSimon Glass int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) 747272cc70bSAndy Fleming { 748272cc70bSAndy Fleming struct mmc_cmd cmd; 7495d4fc8d9SRaffaele Recalcati int timeout = 1000; 750a9003dc6SMaxime Ripard int retries = 3; 7515d4fc8d9SRaffaele Recalcati int ret; 752272cc70bSAndy Fleming 753272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SWITCH; 754272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1b; 755272cc70bSAndy Fleming cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | 756272cc70bSAndy Fleming (index << 16) | 757272cc70bSAndy Fleming (value << 8); 758272cc70bSAndy Fleming 759a9003dc6SMaxime Ripard while (retries > 0) { 7605d4fc8d9SRaffaele Recalcati ret = mmc_send_cmd(mmc, &cmd, NULL); 7615d4fc8d9SRaffaele Recalcati 7625d4fc8d9SRaffaele Recalcati /* Waiting for the ready status */ 763a9003dc6SMaxime Ripard if (!ret) { 76493ad0d18SJan Kloetzke ret = mmc_send_status(mmc, timeout); 765a9003dc6SMaxime Ripard return ret; 766a9003dc6SMaxime Ripard } 767a9003dc6SMaxime Ripard 768a9003dc6SMaxime Ripard retries--; 769a9003dc6SMaxime Ripard } 7705d4fc8d9SRaffaele Recalcati 7715d4fc8d9SRaffaele Recalcati return ret; 7725d4fc8d9SRaffaele Recalcati 773272cc70bSAndy Fleming } 774272cc70bSAndy Fleming 7753862b854SJean-Jacques Hiblot static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode) 776272cc70bSAndy Fleming { 777272cc70bSAndy Fleming int err; 7783862b854SJean-Jacques Hiblot int speed_bits; 7793862b854SJean-Jacques Hiblot 7803862b854SJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 7813862b854SJean-Jacques Hiblot 7823862b854SJean-Jacques Hiblot switch (mode) { 7833862b854SJean-Jacques Hiblot case MMC_HS: 7843862b854SJean-Jacques Hiblot case MMC_HS_52: 7853862b854SJean-Jacques Hiblot case MMC_DDR_52: 7863862b854SJean-Jacques Hiblot speed_bits = EXT_CSD_TIMING_HS; 787634d4849SKishon Vijay Abraham I break; 788634d4849SKishon Vijay Abraham I case MMC_HS_200: 789634d4849SKishon Vijay Abraham I speed_bits = EXT_CSD_TIMING_HS200; 790634d4849SKishon Vijay Abraham I break; 7913862b854SJean-Jacques Hiblot case MMC_LEGACY: 7923862b854SJean-Jacques Hiblot speed_bits = EXT_CSD_TIMING_LEGACY; 7933862b854SJean-Jacques Hiblot break; 7943862b854SJean-Jacques Hiblot default: 7953862b854SJean-Jacques Hiblot return -EINVAL; 7963862b854SJean-Jacques Hiblot } 7973862b854SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 7983862b854SJean-Jacques Hiblot speed_bits); 7993862b854SJean-Jacques Hiblot if (err) 8003862b854SJean-Jacques Hiblot return err; 8013862b854SJean-Jacques Hiblot 8023862b854SJean-Jacques Hiblot if ((mode == MMC_HS) || (mode == MMC_HS_52)) { 8033862b854SJean-Jacques Hiblot /* Now check to see that it worked */ 8043862b854SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, test_csd); 8053862b854SJean-Jacques Hiblot if (err) 8063862b854SJean-Jacques Hiblot return err; 8073862b854SJean-Jacques Hiblot 8083862b854SJean-Jacques Hiblot /* No high-speed support */ 8093862b854SJean-Jacques Hiblot if (!test_csd[EXT_CSD_HS_TIMING]) 8103862b854SJean-Jacques Hiblot return -ENOTSUPP; 8113862b854SJean-Jacques Hiblot } 8123862b854SJean-Jacques Hiblot 8133862b854SJean-Jacques Hiblot return 0; 8143862b854SJean-Jacques Hiblot } 8153862b854SJean-Jacques Hiblot 8163862b854SJean-Jacques Hiblot static int mmc_get_capabilities(struct mmc *mmc) 8173862b854SJean-Jacques Hiblot { 8183862b854SJean-Jacques Hiblot u8 *ext_csd = mmc->ext_csd; 8193862b854SJean-Jacques Hiblot char cardtype; 820272cc70bSAndy Fleming 82100e446faSJean-Jacques Hiblot mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(MMC_LEGACY); 822272cc70bSAndy Fleming 823d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 824d52ebf10SThomas Chou return 0; 825d52ebf10SThomas Chou 826272cc70bSAndy Fleming /* Only version 4 supports high-speed */ 827272cc70bSAndy Fleming if (mmc->version < MMC_VERSION_4) 828272cc70bSAndy Fleming return 0; 829272cc70bSAndy Fleming 8303862b854SJean-Jacques Hiblot if (!ext_csd) { 8313862b854SJean-Jacques Hiblot printf("No ext_csd found!\n"); /* this should enver happen */ 8323862b854SJean-Jacques Hiblot return -ENOTSUPP; 8333862b854SJean-Jacques Hiblot } 8343862b854SJean-Jacques Hiblot 835fc5b32fbSAndrew Gabbasov mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT; 836fc5b32fbSAndrew Gabbasov 837634d4849SKishon Vijay Abraham I cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0x3f; 838bc1e3272SJean-Jacques Hiblot mmc->cardtype = cardtype; 839272cc70bSAndy Fleming 840634d4849SKishon Vijay Abraham I if (cardtype & (EXT_CSD_CARD_TYPE_HS200_1_2V | 841634d4849SKishon Vijay Abraham I EXT_CSD_CARD_TYPE_HS200_1_8V)) { 842634d4849SKishon Vijay Abraham I mmc->card_caps |= MMC_MODE_HS200; 843634d4849SKishon Vijay Abraham I } 844d22e3d46SJaehoon Chung if (cardtype & EXT_CSD_CARD_TYPE_52) { 8453862b854SJean-Jacques Hiblot if (cardtype & EXT_CSD_CARD_TYPE_DDR_52) 846d22e3d46SJaehoon Chung mmc->card_caps |= MMC_MODE_DDR_52MHz; 8473862b854SJean-Jacques Hiblot mmc->card_caps |= MMC_MODE_HS_52MHz; 848d22e3d46SJaehoon Chung } 8493862b854SJean-Jacques Hiblot if (cardtype & EXT_CSD_CARD_TYPE_26) 8503862b854SJean-Jacques Hiblot mmc->card_caps |= MMC_MODE_HS; 851272cc70bSAndy Fleming 852272cc70bSAndy Fleming return 0; 853272cc70bSAndy Fleming } 854272cc70bSAndy Fleming 855f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num) 856f866a46dSStephen Warren { 857f866a46dSStephen Warren switch (part_num) { 858f866a46dSStephen Warren case 0: 859f866a46dSStephen Warren mmc->capacity = mmc->capacity_user; 860f866a46dSStephen Warren break; 861f866a46dSStephen Warren case 1: 862f866a46dSStephen Warren case 2: 863f866a46dSStephen Warren mmc->capacity = mmc->capacity_boot; 864f866a46dSStephen Warren break; 865f866a46dSStephen Warren case 3: 866f866a46dSStephen Warren mmc->capacity = mmc->capacity_rpmb; 867f866a46dSStephen Warren break; 868f866a46dSStephen Warren case 4: 869f866a46dSStephen Warren case 5: 870f866a46dSStephen Warren case 6: 871f866a46dSStephen Warren case 7: 872f866a46dSStephen Warren mmc->capacity = mmc->capacity_gp[part_num - 4]; 873f866a46dSStephen Warren break; 874f866a46dSStephen Warren default: 875f866a46dSStephen Warren return -1; 876f866a46dSStephen Warren } 877f866a46dSStephen Warren 878c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len); 879f866a46dSStephen Warren 880f866a46dSStephen Warren return 0; 881f866a46dSStephen Warren } 882f866a46dSStephen Warren 88301298da3SJean-Jacques Hiblot static int mmc_boot_part_access_chk(struct mmc *mmc, unsigned int part_num) 88401298da3SJean-Jacques Hiblot { 88501298da3SJean-Jacques Hiblot int forbidden = 0; 88601298da3SJean-Jacques Hiblot bool change = false; 88701298da3SJean-Jacques Hiblot 88801298da3SJean-Jacques Hiblot if (part_num & PART_ACCESS_MASK) 88901298da3SJean-Jacques Hiblot forbidden = MMC_CAP(MMC_HS_200); 89001298da3SJean-Jacques Hiblot 89101298da3SJean-Jacques Hiblot if (MMC_CAP(mmc->selected_mode) & forbidden) { 89201298da3SJean-Jacques Hiblot debug("selected mode (%s) is forbidden for part %d\n", 89301298da3SJean-Jacques Hiblot mmc_mode_name(mmc->selected_mode), part_num); 89401298da3SJean-Jacques Hiblot change = true; 89501298da3SJean-Jacques Hiblot } else if (mmc->selected_mode != mmc->best_mode) { 89601298da3SJean-Jacques Hiblot debug("selected mode is not optimal\n"); 89701298da3SJean-Jacques Hiblot change = true; 89801298da3SJean-Jacques Hiblot } 89901298da3SJean-Jacques Hiblot 90001298da3SJean-Jacques Hiblot if (change) 90101298da3SJean-Jacques Hiblot return mmc_select_mode_and_width(mmc, 90201298da3SJean-Jacques Hiblot mmc->card_caps & ~forbidden); 90301298da3SJean-Jacques Hiblot 90401298da3SJean-Jacques Hiblot return 0; 90501298da3SJean-Jacques Hiblot } 90601298da3SJean-Jacques Hiblot 9077dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num) 908bc897b1dSLei Wen { 909f866a46dSStephen Warren int ret; 910bc897b1dSLei Wen 91101298da3SJean-Jacques Hiblot ret = mmc_boot_part_access_chk(mmc, part_num); 91201298da3SJean-Jacques Hiblot if (ret) 91301298da3SJean-Jacques Hiblot return ret; 91401298da3SJean-Jacques Hiblot 915f866a46dSStephen Warren ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, 916bc897b1dSLei Wen (mmc->part_config & ~PART_ACCESS_MASK) 917bc897b1dSLei Wen | (part_num & PART_ACCESS_MASK)); 918f866a46dSStephen Warren 9196dc93e70SPeter Bigot /* 9206dc93e70SPeter Bigot * Set the capacity if the switch succeeded or was intended 9216dc93e70SPeter Bigot * to return to representing the raw device. 9226dc93e70SPeter Bigot */ 923873cc1d7SStephen Warren if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) { 9246dc93e70SPeter Bigot ret = mmc_set_capacity(mmc, part_num); 925fdbb139fSSimon Glass mmc_get_blk_desc(mmc)->hwpart = part_num; 926873cc1d7SStephen Warren } 9276dc93e70SPeter Bigot 9286dc93e70SPeter Bigot return ret; 929bc897b1dSLei Wen } 930bc897b1dSLei Wen 931ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc, 932ac9da0e0SDiego Santa Cruz const struct mmc_hwpart_conf *conf, 933ac9da0e0SDiego Santa Cruz enum mmc_hwpart_conf_mode mode) 934ac9da0e0SDiego Santa Cruz { 935ac9da0e0SDiego Santa Cruz u8 part_attrs = 0; 936ac9da0e0SDiego Santa Cruz u32 enh_size_mult; 937ac9da0e0SDiego Santa Cruz u32 enh_start_addr; 938ac9da0e0SDiego Santa Cruz u32 gp_size_mult[4]; 939ac9da0e0SDiego Santa Cruz u32 max_enh_size_mult; 940ac9da0e0SDiego Santa Cruz u32 tot_enh_size_mult = 0; 9418dda5b0eSDiego Santa Cruz u8 wr_rel_set; 942ac9da0e0SDiego Santa Cruz int i, pidx, err; 943ac9da0e0SDiego Santa Cruz ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 944ac9da0e0SDiego Santa Cruz 945ac9da0e0SDiego Santa Cruz if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE) 946ac9da0e0SDiego Santa Cruz return -EINVAL; 947ac9da0e0SDiego Santa Cruz 948ac9da0e0SDiego Santa Cruz if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) { 949ac9da0e0SDiego Santa Cruz printf("eMMC >= 4.4 required for enhanced user data area\n"); 950ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 951ac9da0e0SDiego Santa Cruz } 952ac9da0e0SDiego Santa Cruz 953ac9da0e0SDiego Santa Cruz if (!(mmc->part_support & PART_SUPPORT)) { 954ac9da0e0SDiego Santa Cruz printf("Card does not support partitioning\n"); 955ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 956ac9da0e0SDiego Santa Cruz } 957ac9da0e0SDiego Santa Cruz 958ac9da0e0SDiego Santa Cruz if (!mmc->hc_wp_grp_size) { 959ac9da0e0SDiego Santa Cruz printf("Card does not define HC WP group size\n"); 960ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 961ac9da0e0SDiego Santa Cruz } 962ac9da0e0SDiego Santa Cruz 963ac9da0e0SDiego Santa Cruz /* check partition alignment and total enhanced size */ 964ac9da0e0SDiego Santa Cruz if (conf->user.enh_size) { 965ac9da0e0SDiego Santa Cruz if (conf->user.enh_size % mmc->hc_wp_grp_size || 966ac9da0e0SDiego Santa Cruz conf->user.enh_start % mmc->hc_wp_grp_size) { 967ac9da0e0SDiego Santa Cruz printf("User data enhanced area not HC WP group " 968ac9da0e0SDiego Santa Cruz "size aligned\n"); 969ac9da0e0SDiego Santa Cruz return -EINVAL; 970ac9da0e0SDiego Santa Cruz } 971ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_USR; 972ac9da0e0SDiego Santa Cruz enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size; 973ac9da0e0SDiego Santa Cruz if (mmc->high_capacity) { 974ac9da0e0SDiego Santa Cruz enh_start_addr = conf->user.enh_start; 975ac9da0e0SDiego Santa Cruz } else { 976ac9da0e0SDiego Santa Cruz enh_start_addr = (conf->user.enh_start << 9); 977ac9da0e0SDiego Santa Cruz } 978ac9da0e0SDiego Santa Cruz } else { 979ac9da0e0SDiego Santa Cruz enh_size_mult = 0; 980ac9da0e0SDiego Santa Cruz enh_start_addr = 0; 981ac9da0e0SDiego Santa Cruz } 982ac9da0e0SDiego Santa Cruz tot_enh_size_mult += enh_size_mult; 983ac9da0e0SDiego Santa Cruz 984ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 985ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) { 986ac9da0e0SDiego Santa Cruz printf("GP%i partition not HC WP group size " 987ac9da0e0SDiego Santa Cruz "aligned\n", pidx+1); 988ac9da0e0SDiego Santa Cruz return -EINVAL; 989ac9da0e0SDiego Santa Cruz } 990ac9da0e0SDiego Santa Cruz gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size; 991ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) { 992ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_GP(pidx); 993ac9da0e0SDiego Santa Cruz tot_enh_size_mult += gp_size_mult[pidx]; 994ac9da0e0SDiego Santa Cruz } 995ac9da0e0SDiego Santa Cruz } 996ac9da0e0SDiego Santa Cruz 997ac9da0e0SDiego Santa Cruz if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) { 998ac9da0e0SDiego Santa Cruz printf("Card does not support enhanced attribute\n"); 999ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1000ac9da0e0SDiego Santa Cruz } 1001ac9da0e0SDiego Santa Cruz 1002ac9da0e0SDiego Santa Cruz err = mmc_send_ext_csd(mmc, ext_csd); 1003ac9da0e0SDiego Santa Cruz if (err) 1004ac9da0e0SDiego Santa Cruz return err; 1005ac9da0e0SDiego Santa Cruz 1006ac9da0e0SDiego Santa Cruz max_enh_size_mult = 1007ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) + 1008ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) + 1009ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT]; 1010ac9da0e0SDiego Santa Cruz if (tot_enh_size_mult > max_enh_size_mult) { 1011ac9da0e0SDiego Santa Cruz printf("Total enhanced size exceeds maximum (%u > %u)\n", 1012ac9da0e0SDiego Santa Cruz tot_enh_size_mult, max_enh_size_mult); 1013ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1014ac9da0e0SDiego Santa Cruz } 1015ac9da0e0SDiego Santa Cruz 10168dda5b0eSDiego Santa Cruz /* The default value of EXT_CSD_WR_REL_SET is device 10178dda5b0eSDiego Santa Cruz * dependent, the values can only be changed if the 10188dda5b0eSDiego Santa Cruz * EXT_CSD_HS_CTRL_REL bit is set. The values can be 10198dda5b0eSDiego Santa Cruz * changed only once and before partitioning is completed. */ 10208dda5b0eSDiego Santa Cruz wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 10218dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_change) { 10228dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_set) 10238dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_USR; 10248dda5b0eSDiego Santa Cruz else 10258dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR; 10268dda5b0eSDiego Santa Cruz } 10278dda5b0eSDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 10288dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_change) { 10298dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_set) 10308dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx); 10318dda5b0eSDiego Santa Cruz else 10328dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx); 10338dda5b0eSDiego Santa Cruz } 10348dda5b0eSDiego Santa Cruz } 10358dda5b0eSDiego Santa Cruz 10368dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] && 10378dda5b0eSDiego Santa Cruz !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) { 10388dda5b0eSDiego Santa Cruz puts("Card does not support host controlled partition write " 10398dda5b0eSDiego Santa Cruz "reliability settings\n"); 10408dda5b0eSDiego Santa Cruz return -EMEDIUMTYPE; 10418dda5b0eSDiego Santa Cruz } 10428dda5b0eSDiego Santa Cruz 1043ac9da0e0SDiego Santa Cruz if (ext_csd[EXT_CSD_PARTITION_SETTING] & 1044ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED) { 1045ac9da0e0SDiego Santa Cruz printf("Card already partitioned\n"); 1046ac9da0e0SDiego Santa Cruz return -EPERM; 1047ac9da0e0SDiego Santa Cruz } 1048ac9da0e0SDiego Santa Cruz 1049ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_CHECK) 1050ac9da0e0SDiego Santa Cruz return 0; 1051ac9da0e0SDiego Santa Cruz 1052ac9da0e0SDiego Santa Cruz /* Partitioning requires high-capacity size definitions */ 1053ac9da0e0SDiego Santa Cruz if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) { 1054ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1055ac9da0e0SDiego Santa Cruz EXT_CSD_ERASE_GROUP_DEF, 1); 1056ac9da0e0SDiego Santa Cruz 1057ac9da0e0SDiego Santa Cruz if (err) 1058ac9da0e0SDiego Santa Cruz return err; 1059ac9da0e0SDiego Santa Cruz 1060ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 1061ac9da0e0SDiego Santa Cruz 1062ac9da0e0SDiego Santa Cruz /* update erase group size to be high-capacity */ 1063ac9da0e0SDiego Santa Cruz mmc->erase_grp_size = 1064ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 1065ac9da0e0SDiego Santa Cruz 1066ac9da0e0SDiego Santa Cruz } 1067ac9da0e0SDiego Santa Cruz 1068ac9da0e0SDiego Santa Cruz /* all OK, write the configuration */ 1069ac9da0e0SDiego Santa Cruz for (i = 0; i < 4; i++) { 1070ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1071ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_START_ADDR+i, 1072ac9da0e0SDiego Santa Cruz (enh_start_addr >> (i*8)) & 0xFF); 1073ac9da0e0SDiego Santa Cruz if (err) 1074ac9da0e0SDiego Santa Cruz return err; 1075ac9da0e0SDiego Santa Cruz } 1076ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 1077ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1078ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_SIZE_MULT+i, 1079ac9da0e0SDiego Santa Cruz (enh_size_mult >> (i*8)) & 0xFF); 1080ac9da0e0SDiego Santa Cruz if (err) 1081ac9da0e0SDiego Santa Cruz return err; 1082ac9da0e0SDiego Santa Cruz } 1083ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 1084ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 1085ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1086ac9da0e0SDiego Santa Cruz EXT_CSD_GP_SIZE_MULT+pidx*3+i, 1087ac9da0e0SDiego Santa Cruz (gp_size_mult[pidx] >> (i*8)) & 0xFF); 1088ac9da0e0SDiego Santa Cruz if (err) 1089ac9da0e0SDiego Santa Cruz return err; 1090ac9da0e0SDiego Santa Cruz } 1091ac9da0e0SDiego Santa Cruz } 1092ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1093ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs); 1094ac9da0e0SDiego Santa Cruz if (err) 1095ac9da0e0SDiego Santa Cruz return err; 1096ac9da0e0SDiego Santa Cruz 1097ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_SET) 1098ac9da0e0SDiego Santa Cruz return 0; 1099ac9da0e0SDiego Santa Cruz 11008dda5b0eSDiego Santa Cruz /* The WR_REL_SET is a write-once register but shall be 11018dda5b0eSDiego Santa Cruz * written before setting PART_SETTING_COMPLETED. As it is 11028dda5b0eSDiego Santa Cruz * write-once we can only write it when completing the 11038dda5b0eSDiego Santa Cruz * partitioning. */ 11048dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) { 11058dda5b0eSDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 11068dda5b0eSDiego Santa Cruz EXT_CSD_WR_REL_SET, wr_rel_set); 11078dda5b0eSDiego Santa Cruz if (err) 11088dda5b0eSDiego Santa Cruz return err; 11098dda5b0eSDiego Santa Cruz } 11108dda5b0eSDiego Santa Cruz 1111ac9da0e0SDiego Santa Cruz /* Setting PART_SETTING_COMPLETED confirms the partition 1112ac9da0e0SDiego Santa Cruz * configuration but it only becomes effective after power 1113ac9da0e0SDiego Santa Cruz * cycle, so we do not adjust the partition related settings 1114ac9da0e0SDiego Santa Cruz * in the mmc struct. */ 1115ac9da0e0SDiego Santa Cruz 1116ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1117ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING, 1118ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED); 1119ac9da0e0SDiego Santa Cruz if (err) 1120ac9da0e0SDiego Santa Cruz return err; 1121ac9da0e0SDiego Santa Cruz 1122ac9da0e0SDiego Santa Cruz return 0; 1123ac9da0e0SDiego Santa Cruz } 1124ac9da0e0SDiego Santa Cruz 1125e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 112648972d90SThierry Reding int mmc_getcd(struct mmc *mmc) 112748972d90SThierry Reding { 112848972d90SThierry Reding int cd; 112948972d90SThierry Reding 113048972d90SThierry Reding cd = board_mmc_getcd(mmc); 113148972d90SThierry Reding 1132d4e1da4eSPeter Korsgaard if (cd < 0) { 113393bfd616SPantelis Antoniou if (mmc->cfg->ops->getcd) 113493bfd616SPantelis Antoniou cd = mmc->cfg->ops->getcd(mmc); 1135d4e1da4eSPeter Korsgaard else 1136d4e1da4eSPeter Korsgaard cd = 1; 1137d4e1da4eSPeter Korsgaard } 113848972d90SThierry Reding 113948972d90SThierry Reding return cd; 114048972d90SThierry Reding } 11418ca51e51SSimon Glass #endif 114248972d90SThierry Reding 1143fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) 1144272cc70bSAndy Fleming { 1145272cc70bSAndy Fleming struct mmc_cmd cmd; 1146272cc70bSAndy Fleming struct mmc_data data; 1147272cc70bSAndy Fleming 1148272cc70bSAndy Fleming /* Switch the frequency */ 1149272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SWITCH_FUNC; 1150272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1151272cc70bSAndy Fleming cmd.cmdarg = (mode << 31) | 0xffffff; 1152272cc70bSAndy Fleming cmd.cmdarg &= ~(0xf << (group * 4)); 1153272cc70bSAndy Fleming cmd.cmdarg |= value << (group * 4); 1154272cc70bSAndy Fleming 1155272cc70bSAndy Fleming data.dest = (char *)resp; 1156272cc70bSAndy Fleming data.blocksize = 64; 1157272cc70bSAndy Fleming data.blocks = 1; 1158272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 1159272cc70bSAndy Fleming 1160272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, &data); 1161272cc70bSAndy Fleming } 1162272cc70bSAndy Fleming 1163272cc70bSAndy Fleming 1164d0c221feSJean-Jacques Hiblot static int sd_get_capabilities(struct mmc *mmc) 1165272cc70bSAndy Fleming { 1166272cc70bSAndy Fleming int err; 1167272cc70bSAndy Fleming struct mmc_cmd cmd; 116818e7c8f6SSuniel Mahesh ALLOC_CACHE_ALIGN_BUFFER(__be32, scr, 2); 116918e7c8f6SSuniel Mahesh ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16); 1170272cc70bSAndy Fleming struct mmc_data data; 1171272cc70bSAndy Fleming int timeout; 1172c10b85d6SJean-Jacques Hiblot u32 sd3_bus_mode; 1173272cc70bSAndy Fleming 117400e446faSJean-Jacques Hiblot mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(SD_LEGACY); 1175272cc70bSAndy Fleming 1176d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 1177d52ebf10SThomas Chou return 0; 1178d52ebf10SThomas Chou 1179272cc70bSAndy Fleming /* Read the SCR to find out if this card supports higher speeds */ 1180272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 1181272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1182272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1183272cc70bSAndy Fleming 1184272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1185272cc70bSAndy Fleming 1186272cc70bSAndy Fleming if (err) 1187272cc70bSAndy Fleming return err; 1188272cc70bSAndy Fleming 1189272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_SCR; 1190272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1191272cc70bSAndy Fleming cmd.cmdarg = 0; 1192272cc70bSAndy Fleming 1193272cc70bSAndy Fleming timeout = 3; 1194272cc70bSAndy Fleming 1195272cc70bSAndy Fleming retry_scr: 1196f781dd38SAnton staaf data.dest = (char *)scr; 1197272cc70bSAndy Fleming data.blocksize = 8; 1198272cc70bSAndy Fleming data.blocks = 1; 1199272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 1200272cc70bSAndy Fleming 1201272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 1202272cc70bSAndy Fleming 1203272cc70bSAndy Fleming if (err) { 1204272cc70bSAndy Fleming if (timeout--) 1205272cc70bSAndy Fleming goto retry_scr; 1206272cc70bSAndy Fleming 1207272cc70bSAndy Fleming return err; 1208272cc70bSAndy Fleming } 1209272cc70bSAndy Fleming 12104e3d89baSYauhen Kharuzhy mmc->scr[0] = __be32_to_cpu(scr[0]); 12114e3d89baSYauhen Kharuzhy mmc->scr[1] = __be32_to_cpu(scr[1]); 1212272cc70bSAndy Fleming 1213272cc70bSAndy Fleming switch ((mmc->scr[0] >> 24) & 0xf) { 1214272cc70bSAndy Fleming case 0: 1215272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1216272cc70bSAndy Fleming break; 1217272cc70bSAndy Fleming case 1: 1218272cc70bSAndy Fleming mmc->version = SD_VERSION_1_10; 1219272cc70bSAndy Fleming break; 1220272cc70bSAndy Fleming case 2: 1221272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 12221741c64dSJaehoon Chung if ((mmc->scr[0] >> 15) & 0x1) 12231741c64dSJaehoon Chung mmc->version = SD_VERSION_3; 1224272cc70bSAndy Fleming break; 1225272cc70bSAndy Fleming default: 1226272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1227272cc70bSAndy Fleming break; 1228272cc70bSAndy Fleming } 1229272cc70bSAndy Fleming 1230b44c7083SAlagu Sankar if (mmc->scr[0] & SD_DATA_4BIT) 1231b44c7083SAlagu Sankar mmc->card_caps |= MMC_MODE_4BIT; 1232b44c7083SAlagu Sankar 1233272cc70bSAndy Fleming /* Version 1.0 doesn't support switching */ 1234272cc70bSAndy Fleming if (mmc->version == SD_VERSION_1_0) 1235272cc70bSAndy Fleming return 0; 1236272cc70bSAndy Fleming 1237272cc70bSAndy Fleming timeout = 4; 1238272cc70bSAndy Fleming while (timeout--) { 1239272cc70bSAndy Fleming err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1, 1240f781dd38SAnton staaf (u8 *)switch_status); 1241272cc70bSAndy Fleming 1242272cc70bSAndy Fleming if (err) 1243272cc70bSAndy Fleming return err; 1244272cc70bSAndy Fleming 1245272cc70bSAndy Fleming /* The high-speed function is busy. Try again */ 12464e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY)) 1247272cc70bSAndy Fleming break; 1248272cc70bSAndy Fleming } 1249272cc70bSAndy Fleming 1250272cc70bSAndy Fleming /* If high-speed isn't supported, we return */ 1251d0c221feSJean-Jacques Hiblot if (__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED) 1252d0c221feSJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(SD_HS); 1253272cc70bSAndy Fleming 1254c10b85d6SJean-Jacques Hiblot /* Version before 3.0 don't support UHS modes */ 1255c10b85d6SJean-Jacques Hiblot if (mmc->version < SD_VERSION_3) 1256c10b85d6SJean-Jacques Hiblot return 0; 1257c10b85d6SJean-Jacques Hiblot 1258c10b85d6SJean-Jacques Hiblot sd3_bus_mode = __be32_to_cpu(switch_status[3]) >> 16 & 0x1f; 1259c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR104) 1260c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR104); 1261c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR50) 1262c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR50); 1263c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR25) 1264c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR25); 1265c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR12) 1266c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR12); 1267c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_DDR50) 1268c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_DDR50); 1269c10b85d6SJean-Jacques Hiblot 12702c3fbf4cSMacpaul Lin return 0; 1271d0c221feSJean-Jacques Hiblot } 1272d0c221feSJean-Jacques Hiblot 1273d0c221feSJean-Jacques Hiblot static int sd_set_card_speed(struct mmc *mmc, enum bus_mode mode) 1274d0c221feSJean-Jacques Hiblot { 1275d0c221feSJean-Jacques Hiblot int err; 1276d0c221feSJean-Jacques Hiblot 1277d0c221feSJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16); 1278c10b85d6SJean-Jacques Hiblot int speed; 12792c3fbf4cSMacpaul Lin 1280c10b85d6SJean-Jacques Hiblot switch (mode) { 1281c10b85d6SJean-Jacques Hiblot case SD_LEGACY: 1282c10b85d6SJean-Jacques Hiblot case UHS_SDR12: 1283c10b85d6SJean-Jacques Hiblot speed = UHS_SDR12_BUS_SPEED; 1284c10b85d6SJean-Jacques Hiblot break; 1285c10b85d6SJean-Jacques Hiblot case SD_HS: 1286c10b85d6SJean-Jacques Hiblot case UHS_SDR25: 1287c10b85d6SJean-Jacques Hiblot speed = UHS_SDR25_BUS_SPEED; 1288c10b85d6SJean-Jacques Hiblot break; 1289c10b85d6SJean-Jacques Hiblot case UHS_SDR50: 1290c10b85d6SJean-Jacques Hiblot speed = UHS_SDR50_BUS_SPEED; 1291c10b85d6SJean-Jacques Hiblot break; 1292c10b85d6SJean-Jacques Hiblot case UHS_DDR50: 1293c10b85d6SJean-Jacques Hiblot speed = UHS_DDR50_BUS_SPEED; 1294c10b85d6SJean-Jacques Hiblot break; 1295c10b85d6SJean-Jacques Hiblot case UHS_SDR104: 1296c10b85d6SJean-Jacques Hiblot speed = UHS_SDR104_BUS_SPEED; 1297c10b85d6SJean-Jacques Hiblot break; 1298c10b85d6SJean-Jacques Hiblot default: 1299c10b85d6SJean-Jacques Hiblot return -EINVAL; 1300c10b85d6SJean-Jacques Hiblot } 1301c10b85d6SJean-Jacques Hiblot 1302c10b85d6SJean-Jacques Hiblot err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, speed, (u8 *)switch_status); 1303272cc70bSAndy Fleming if (err) 1304272cc70bSAndy Fleming return err; 1305272cc70bSAndy Fleming 1306c10b85d6SJean-Jacques Hiblot if ((__be32_to_cpu(switch_status[4]) >> 24) != speed) 1307d0c221feSJean-Jacques Hiblot return -ENOTSUPP; 1308d0c221feSJean-Jacques Hiblot 1309d0c221feSJean-Jacques Hiblot return 0; 1310d0c221feSJean-Jacques Hiblot } 1311d0c221feSJean-Jacques Hiblot 1312d0c221feSJean-Jacques Hiblot int sd_select_bus_width(struct mmc *mmc, int w) 1313d0c221feSJean-Jacques Hiblot { 1314d0c221feSJean-Jacques Hiblot int err; 1315d0c221feSJean-Jacques Hiblot struct mmc_cmd cmd; 1316d0c221feSJean-Jacques Hiblot 1317d0c221feSJean-Jacques Hiblot if ((w != 4) && (w != 1)) 1318d0c221feSJean-Jacques Hiblot return -EINVAL; 1319d0c221feSJean-Jacques Hiblot 1320d0c221feSJean-Jacques Hiblot cmd.cmdidx = MMC_CMD_APP_CMD; 1321d0c221feSJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 1322d0c221feSJean-Jacques Hiblot cmd.cmdarg = mmc->rca << 16; 1323d0c221feSJean-Jacques Hiblot 1324d0c221feSJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 1325d0c221feSJean-Jacques Hiblot if (err) 1326d0c221feSJean-Jacques Hiblot return err; 1327d0c221feSJean-Jacques Hiblot 1328d0c221feSJean-Jacques Hiblot cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH; 1329d0c221feSJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 1330d0c221feSJean-Jacques Hiblot if (w == 4) 1331d0c221feSJean-Jacques Hiblot cmd.cmdarg = 2; 1332d0c221feSJean-Jacques Hiblot else if (w == 1) 1333d0c221feSJean-Jacques Hiblot cmd.cmdarg = 0; 1334d0c221feSJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 1335d0c221feSJean-Jacques Hiblot if (err) 1336d0c221feSJean-Jacques Hiblot return err; 1337272cc70bSAndy Fleming 1338272cc70bSAndy Fleming return 0; 1339272cc70bSAndy Fleming } 1340272cc70bSAndy Fleming 13413697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc) 13423697e599SPeng Fan { 13433697e599SPeng Fan int err, i; 13443697e599SPeng Fan struct mmc_cmd cmd; 13453697e599SPeng Fan ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16); 13463697e599SPeng Fan struct mmc_data data; 13473697e599SPeng Fan int timeout = 3; 13483697e599SPeng Fan unsigned int au, eo, et, es; 13493697e599SPeng Fan 13503697e599SPeng Fan cmd.cmdidx = MMC_CMD_APP_CMD; 13513697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 13523697e599SPeng Fan cmd.cmdarg = mmc->rca << 16; 13533697e599SPeng Fan 13543697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, NULL); 13553697e599SPeng Fan if (err) 13563697e599SPeng Fan return err; 13573697e599SPeng Fan 13583697e599SPeng Fan cmd.cmdidx = SD_CMD_APP_SD_STATUS; 13593697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 13603697e599SPeng Fan cmd.cmdarg = 0; 13613697e599SPeng Fan 13623697e599SPeng Fan retry_ssr: 13633697e599SPeng Fan data.dest = (char *)ssr; 13643697e599SPeng Fan data.blocksize = 64; 13653697e599SPeng Fan data.blocks = 1; 13663697e599SPeng Fan data.flags = MMC_DATA_READ; 13673697e599SPeng Fan 13683697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, &data); 13693697e599SPeng Fan if (err) { 13703697e599SPeng Fan if (timeout--) 13713697e599SPeng Fan goto retry_ssr; 13723697e599SPeng Fan 13733697e599SPeng Fan return err; 13743697e599SPeng Fan } 13753697e599SPeng Fan 13763697e599SPeng Fan for (i = 0; i < 16; i++) 13773697e599SPeng Fan ssr[i] = be32_to_cpu(ssr[i]); 13783697e599SPeng Fan 13793697e599SPeng Fan au = (ssr[2] >> 12) & 0xF; 13803697e599SPeng Fan if ((au <= 9) || (mmc->version == SD_VERSION_3)) { 13813697e599SPeng Fan mmc->ssr.au = sd_au_size[au]; 13823697e599SPeng Fan es = (ssr[3] >> 24) & 0xFF; 13833697e599SPeng Fan es |= (ssr[2] & 0xFF) << 8; 13843697e599SPeng Fan et = (ssr[3] >> 18) & 0x3F; 13853697e599SPeng Fan if (es && et) { 13863697e599SPeng Fan eo = (ssr[3] >> 16) & 0x3; 13873697e599SPeng Fan mmc->ssr.erase_timeout = (et * 1000) / es; 13883697e599SPeng Fan mmc->ssr.erase_offset = eo * 1000; 13893697e599SPeng Fan } 13903697e599SPeng Fan } else { 13913697e599SPeng Fan debug("Invalid Allocation Unit Size.\n"); 13923697e599SPeng Fan } 13933697e599SPeng Fan 13943697e599SPeng Fan return 0; 13953697e599SPeng Fan } 13963697e599SPeng Fan 1397272cc70bSAndy Fleming /* frequency bases */ 1398272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */ 13995f837c2cSMike Frysinger static const int fbase[] = { 1400272cc70bSAndy Fleming 10000, 1401272cc70bSAndy Fleming 100000, 1402272cc70bSAndy Fleming 1000000, 1403272cc70bSAndy Fleming 10000000, 1404272cc70bSAndy Fleming }; 1405272cc70bSAndy Fleming 1406272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice 1407272cc70bSAndy Fleming * to platforms without floating point. 1408272cc70bSAndy Fleming */ 140961fe076fSSimon Glass static const u8 multipliers[] = { 1410272cc70bSAndy Fleming 0, /* reserved */ 1411272cc70bSAndy Fleming 10, 1412272cc70bSAndy Fleming 12, 1413272cc70bSAndy Fleming 13, 1414272cc70bSAndy Fleming 15, 1415272cc70bSAndy Fleming 20, 1416272cc70bSAndy Fleming 25, 1417272cc70bSAndy Fleming 30, 1418272cc70bSAndy Fleming 35, 1419272cc70bSAndy Fleming 40, 1420272cc70bSAndy Fleming 45, 1421272cc70bSAndy Fleming 50, 1422272cc70bSAndy Fleming 55, 1423272cc70bSAndy Fleming 60, 1424272cc70bSAndy Fleming 70, 1425272cc70bSAndy Fleming 80, 1426272cc70bSAndy Fleming }; 1427272cc70bSAndy Fleming 1428d0c221feSJean-Jacques Hiblot static inline int bus_width(uint cap) 1429d0c221feSJean-Jacques Hiblot { 1430d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_8BIT) 1431d0c221feSJean-Jacques Hiblot return 8; 1432d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_4BIT) 1433d0c221feSJean-Jacques Hiblot return 4; 1434d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_1BIT) 1435d0c221feSJean-Jacques Hiblot return 1; 1436d0c221feSJean-Jacques Hiblot printf("invalid bus witdh capability 0x%x\n", cap); 1437d0c221feSJean-Jacques Hiblot return 0; 1438d0c221feSJean-Jacques Hiblot } 1439d0c221feSJean-Jacques Hiblot 1440e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 1441ec841209SKishon Vijay Abraham I static int mmc_execute_tuning(struct mmc *mmc, uint opcode) 1442ec841209SKishon Vijay Abraham I { 1443ec841209SKishon Vijay Abraham I return -ENOTSUPP; 1444ec841209SKishon Vijay Abraham I } 1445ec841209SKishon Vijay Abraham I 1446318a7a57SJean-Jacques Hiblot static void mmc_send_init_stream(struct mmc *mmc) 1447318a7a57SJean-Jacques Hiblot { 1448318a7a57SJean-Jacques Hiblot } 1449318a7a57SJean-Jacques Hiblot 14502a4d212fSKishon Vijay Abraham I static int mmc_set_ios(struct mmc *mmc) 1451272cc70bSAndy Fleming { 14522a4d212fSKishon Vijay Abraham I int ret = 0; 14532a4d212fSKishon Vijay Abraham I 145493bfd616SPantelis Antoniou if (mmc->cfg->ops->set_ios) 14552a4d212fSKishon Vijay Abraham I ret = mmc->cfg->ops->set_ios(mmc); 14562a4d212fSKishon Vijay Abraham I 14572a4d212fSKishon Vijay Abraham I return ret; 1458272cc70bSAndy Fleming } 14598ca51e51SSimon Glass #endif 1460272cc70bSAndy Fleming 146135f67820SKishon Vijay Abraham I int mmc_set_clock(struct mmc *mmc, uint clock, bool disable) 1462272cc70bSAndy Fleming { 146393bfd616SPantelis Antoniou if (clock > mmc->cfg->f_max) 146493bfd616SPantelis Antoniou clock = mmc->cfg->f_max; 1465272cc70bSAndy Fleming 146693bfd616SPantelis Antoniou if (clock < mmc->cfg->f_min) 146793bfd616SPantelis Antoniou clock = mmc->cfg->f_min; 1468272cc70bSAndy Fleming 1469272cc70bSAndy Fleming mmc->clock = clock; 147035f67820SKishon Vijay Abraham I mmc->clk_disable = disable; 1471272cc70bSAndy Fleming 14722a4d212fSKishon Vijay Abraham I return mmc_set_ios(mmc); 1473272cc70bSAndy Fleming } 1474272cc70bSAndy Fleming 14752a4d212fSKishon Vijay Abraham I static int mmc_set_bus_width(struct mmc *mmc, uint width) 1476272cc70bSAndy Fleming { 1477272cc70bSAndy Fleming mmc->bus_width = width; 1478272cc70bSAndy Fleming 14792a4d212fSKishon Vijay Abraham I return mmc_set_ios(mmc); 1480272cc70bSAndy Fleming } 1481272cc70bSAndy Fleming 14824c9d2aaaSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG) 14834c9d2aaaSJean-Jacques Hiblot /* 14844c9d2aaaSJean-Jacques Hiblot * helper function to display the capabilities in a human 14854c9d2aaaSJean-Jacques Hiblot * friendly manner. The capabilities include bus width and 14864c9d2aaaSJean-Jacques Hiblot * supported modes. 14874c9d2aaaSJean-Jacques Hiblot */ 14884c9d2aaaSJean-Jacques Hiblot void mmc_dump_capabilities(const char *text, uint caps) 14894c9d2aaaSJean-Jacques Hiblot { 14904c9d2aaaSJean-Jacques Hiblot enum bus_mode mode; 14914c9d2aaaSJean-Jacques Hiblot 14924c9d2aaaSJean-Jacques Hiblot printf("%s: widths [", text); 14934c9d2aaaSJean-Jacques Hiblot if (caps & MMC_MODE_8BIT) 14944c9d2aaaSJean-Jacques Hiblot printf("8, "); 14954c9d2aaaSJean-Jacques Hiblot if (caps & MMC_MODE_4BIT) 14964c9d2aaaSJean-Jacques Hiblot printf("4, "); 1497d0c221feSJean-Jacques Hiblot if (caps & MMC_MODE_1BIT) 1498d0c221feSJean-Jacques Hiblot printf("1, "); 1499d0c221feSJean-Jacques Hiblot printf("\b\b] modes ["); 15004c9d2aaaSJean-Jacques Hiblot for (mode = MMC_LEGACY; mode < MMC_MODES_END; mode++) 15014c9d2aaaSJean-Jacques Hiblot if (MMC_CAP(mode) & caps) 15024c9d2aaaSJean-Jacques Hiblot printf("%s, ", mmc_mode_name(mode)); 15034c9d2aaaSJean-Jacques Hiblot printf("\b\b]\n"); 15044c9d2aaaSJean-Jacques Hiblot } 15054c9d2aaaSJean-Jacques Hiblot #endif 15064c9d2aaaSJean-Jacques Hiblot 1507d0c221feSJean-Jacques Hiblot struct mode_width_tuning { 1508d0c221feSJean-Jacques Hiblot enum bus_mode mode; 1509d0c221feSJean-Jacques Hiblot uint widths; 1510634d4849SKishon Vijay Abraham I uint tuning; 1511d0c221feSJean-Jacques Hiblot }; 1512d0c221feSJean-Jacques Hiblot 1513bc1e3272SJean-Jacques Hiblot int mmc_voltage_to_mv(enum mmc_voltage voltage) 1514bc1e3272SJean-Jacques Hiblot { 1515bc1e3272SJean-Jacques Hiblot switch (voltage) { 1516bc1e3272SJean-Jacques Hiblot case MMC_SIGNAL_VOLTAGE_000: return 0; 1517bc1e3272SJean-Jacques Hiblot case MMC_SIGNAL_VOLTAGE_330: return 3300; 1518bc1e3272SJean-Jacques Hiblot case MMC_SIGNAL_VOLTAGE_180: return 1800; 1519bc1e3272SJean-Jacques Hiblot case MMC_SIGNAL_VOLTAGE_120: return 1200; 1520bc1e3272SJean-Jacques Hiblot } 1521bc1e3272SJean-Jacques Hiblot return -EINVAL; 1522bc1e3272SJean-Jacques Hiblot } 1523bc1e3272SJean-Jacques Hiblot 1524aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage) 1525aff5d3c8SKishon Vijay Abraham I { 1526bc1e3272SJean-Jacques Hiblot int err; 1527bc1e3272SJean-Jacques Hiblot 1528bc1e3272SJean-Jacques Hiblot if (mmc->signal_voltage == signal_voltage) 1529bc1e3272SJean-Jacques Hiblot return 0; 1530bc1e3272SJean-Jacques Hiblot 1531aff5d3c8SKishon Vijay Abraham I mmc->signal_voltage = signal_voltage; 1532bc1e3272SJean-Jacques Hiblot err = mmc_set_ios(mmc); 1533bc1e3272SJean-Jacques Hiblot if (err) 1534bc1e3272SJean-Jacques Hiblot debug("unable to set voltage (err %d)\n", err); 1535bc1e3272SJean-Jacques Hiblot 1536bc1e3272SJean-Jacques Hiblot return err; 1537aff5d3c8SKishon Vijay Abraham I } 1538aff5d3c8SKishon Vijay Abraham I 1539d0c221feSJean-Jacques Hiblot static const struct mode_width_tuning sd_modes_by_pref[] = { 1540d0c221feSJean-Jacques Hiblot { 1541c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR104, 1542c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1543c10b85d6SJean-Jacques Hiblot .tuning = MMC_CMD_SEND_TUNING_BLOCK 1544c10b85d6SJean-Jacques Hiblot }, 1545c10b85d6SJean-Jacques Hiblot { 1546c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR50, 1547c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1548c10b85d6SJean-Jacques Hiblot }, 1549c10b85d6SJean-Jacques Hiblot { 1550c10b85d6SJean-Jacques Hiblot .mode = UHS_DDR50, 1551c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1552c10b85d6SJean-Jacques Hiblot }, 1553c10b85d6SJean-Jacques Hiblot { 1554c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR25, 1555c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1556c10b85d6SJean-Jacques Hiblot }, 1557c10b85d6SJean-Jacques Hiblot { 1558d0c221feSJean-Jacques Hiblot .mode = SD_HS, 1559d0c221feSJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1560d0c221feSJean-Jacques Hiblot }, 1561d0c221feSJean-Jacques Hiblot { 1562c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR12, 1563c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1564c10b85d6SJean-Jacques Hiblot }, 1565c10b85d6SJean-Jacques Hiblot { 1566d0c221feSJean-Jacques Hiblot .mode = SD_LEGACY, 1567d0c221feSJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1568d0c221feSJean-Jacques Hiblot } 1569d0c221feSJean-Jacques Hiblot }; 1570d0c221feSJean-Jacques Hiblot 1571d0c221feSJean-Jacques Hiblot #define for_each_sd_mode_by_pref(caps, mwt) \ 1572d0c221feSJean-Jacques Hiblot for (mwt = sd_modes_by_pref;\ 1573d0c221feSJean-Jacques Hiblot mwt < sd_modes_by_pref + ARRAY_SIZE(sd_modes_by_pref);\ 1574d0c221feSJean-Jacques Hiblot mwt++) \ 1575d0c221feSJean-Jacques Hiblot if (caps & MMC_CAP(mwt->mode)) 1576d0c221feSJean-Jacques Hiblot 157701298da3SJean-Jacques Hiblot static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps) 15788ac8a263SJean-Jacques Hiblot { 15798ac8a263SJean-Jacques Hiblot int err; 1580d0c221feSJean-Jacques Hiblot uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT}; 1581d0c221feSJean-Jacques Hiblot const struct mode_width_tuning *mwt; 1582c10b85d6SJean-Jacques Hiblot bool uhs_en = (mmc->ocr & OCR_S18R) ? true : false; 1583c10b85d6SJean-Jacques Hiblot uint caps; 1584c10b85d6SJean-Jacques Hiblot 158552d241dfSJean-Jacques Hiblot #ifdef DEBUG 158652d241dfSJean-Jacques Hiblot mmc_dump_capabilities("sd card", card_caps); 15871da8eb59SJean-Jacques Hiblot mmc_dump_capabilities("host", mmc->host_caps); 158852d241dfSJean-Jacques Hiblot #endif 15898ac8a263SJean-Jacques Hiblot 15908ac8a263SJean-Jacques Hiblot /* Restrict card's capabilities by what the host can do */ 15911da8eb59SJean-Jacques Hiblot caps = card_caps & mmc->host_caps; 15928ac8a263SJean-Jacques Hiblot 1593c10b85d6SJean-Jacques Hiblot if (!uhs_en) 1594c10b85d6SJean-Jacques Hiblot caps &= ~UHS_CAPS; 1595c10b85d6SJean-Jacques Hiblot 1596c10b85d6SJean-Jacques Hiblot for_each_sd_mode_by_pref(caps, mwt) { 1597d0c221feSJean-Jacques Hiblot uint *w; 15988ac8a263SJean-Jacques Hiblot 1599d0c221feSJean-Jacques Hiblot for (w = widths; w < widths + ARRAY_SIZE(widths); w++) { 1600c10b85d6SJean-Jacques Hiblot if (*w & caps & mwt->widths) { 1601d0c221feSJean-Jacques Hiblot debug("trying mode %s width %d (at %d MHz)\n", 1602d0c221feSJean-Jacques Hiblot mmc_mode_name(mwt->mode), 1603d0c221feSJean-Jacques Hiblot bus_width(*w), 1604d0c221feSJean-Jacques Hiblot mmc_mode2freq(mmc, mwt->mode) / 1000000); 1605d0c221feSJean-Jacques Hiblot 1606d0c221feSJean-Jacques Hiblot /* configure the bus width (card + host) */ 1607d0c221feSJean-Jacques Hiblot err = sd_select_bus_width(mmc, bus_width(*w)); 16088ac8a263SJean-Jacques Hiblot if (err) 1609d0c221feSJean-Jacques Hiblot goto error; 1610d0c221feSJean-Jacques Hiblot mmc_set_bus_width(mmc, bus_width(*w)); 16118ac8a263SJean-Jacques Hiblot 1612d0c221feSJean-Jacques Hiblot /* configure the bus mode (card) */ 1613d0c221feSJean-Jacques Hiblot err = sd_set_card_speed(mmc, mwt->mode); 16148ac8a263SJean-Jacques Hiblot if (err) 1615d0c221feSJean-Jacques Hiblot goto error; 16168ac8a263SJean-Jacques Hiblot 1617d0c221feSJean-Jacques Hiblot /* configure the bus mode (host) */ 1618d0c221feSJean-Jacques Hiblot mmc_select_mode(mmc, mwt->mode); 161935f67820SKishon Vijay Abraham I mmc_set_clock(mmc, mmc->tran_speed, false); 16208ac8a263SJean-Jacques Hiblot 1621c10b85d6SJean-Jacques Hiblot /* execute tuning if needed */ 1622c10b85d6SJean-Jacques Hiblot if (mwt->tuning && !mmc_host_is_spi(mmc)) { 1623c10b85d6SJean-Jacques Hiblot err = mmc_execute_tuning(mmc, 1624c10b85d6SJean-Jacques Hiblot mwt->tuning); 1625c10b85d6SJean-Jacques Hiblot if (err) { 1626c10b85d6SJean-Jacques Hiblot debug("tuning failed\n"); 1627c10b85d6SJean-Jacques Hiblot goto error; 1628c10b85d6SJean-Jacques Hiblot } 1629c10b85d6SJean-Jacques Hiblot } 1630c10b85d6SJean-Jacques Hiblot 16318ac8a263SJean-Jacques Hiblot err = sd_read_ssr(mmc); 1632d0c221feSJean-Jacques Hiblot if (!err) 16338ac8a263SJean-Jacques Hiblot return 0; 1634d0c221feSJean-Jacques Hiblot 1635d0c221feSJean-Jacques Hiblot printf("bad ssr\n"); 1636d0c221feSJean-Jacques Hiblot 1637d0c221feSJean-Jacques Hiblot error: 1638d0c221feSJean-Jacques Hiblot /* revert to a safer bus speed */ 1639d0c221feSJean-Jacques Hiblot mmc_select_mode(mmc, SD_LEGACY); 164035f67820SKishon Vijay Abraham I mmc_set_clock(mmc, mmc->tran_speed, false); 1641d0c221feSJean-Jacques Hiblot } 1642d0c221feSJean-Jacques Hiblot } 1643d0c221feSJean-Jacques Hiblot } 1644d0c221feSJean-Jacques Hiblot 1645d0c221feSJean-Jacques Hiblot printf("unable to select a mode\n"); 1646d0c221feSJean-Jacques Hiblot return -ENOTSUPP; 16478ac8a263SJean-Jacques Hiblot } 16488ac8a263SJean-Jacques Hiblot 16497382e691SJean-Jacques Hiblot /* 16507382e691SJean-Jacques Hiblot * read the compare the part of ext csd that is constant. 16517382e691SJean-Jacques Hiblot * This can be used to check that the transfer is working 16527382e691SJean-Jacques Hiblot * as expected. 16537382e691SJean-Jacques Hiblot */ 16547382e691SJean-Jacques Hiblot static int mmc_read_and_compare_ext_csd(struct mmc *mmc) 16557382e691SJean-Jacques Hiblot { 16567382e691SJean-Jacques Hiblot int err; 16577382e691SJean-Jacques Hiblot const u8 *ext_csd = mmc->ext_csd; 16587382e691SJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 16597382e691SJean-Jacques Hiblot 16601de06b9fSJean-Jacques Hiblot if (mmc->version < MMC_VERSION_4) 16611de06b9fSJean-Jacques Hiblot return 0; 16621de06b9fSJean-Jacques Hiblot 16637382e691SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, test_csd); 16647382e691SJean-Jacques Hiblot if (err) 16657382e691SJean-Jacques Hiblot return err; 16667382e691SJean-Jacques Hiblot 16677382e691SJean-Jacques Hiblot /* Only compare read only fields */ 16687382e691SJean-Jacques Hiblot if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] 16697382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_PARTITIONING_SUPPORT] && 16707382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_WP_GRP_SIZE] 16717382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_HC_WP_GRP_SIZE] && 16727382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_REV] 16737382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_REV] && 16747382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 16757382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] && 16767382e691SJean-Jacques Hiblot memcmp(&ext_csd[EXT_CSD_SEC_CNT], 16777382e691SJean-Jacques Hiblot &test_csd[EXT_CSD_SEC_CNT], 4) == 0) 16787382e691SJean-Jacques Hiblot return 0; 16797382e691SJean-Jacques Hiblot 16807382e691SJean-Jacques Hiblot return -EBADMSG; 16817382e691SJean-Jacques Hiblot } 16827382e691SJean-Jacques Hiblot 1683bc1e3272SJean-Jacques Hiblot static int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode, 1684bc1e3272SJean-Jacques Hiblot uint32_t allowed_mask) 1685bc1e3272SJean-Jacques Hiblot { 1686bc1e3272SJean-Jacques Hiblot u32 card_mask = 0; 1687bc1e3272SJean-Jacques Hiblot 1688bc1e3272SJean-Jacques Hiblot switch (mode) { 1689bc1e3272SJean-Jacques Hiblot case MMC_HS_200: 1690bc1e3272SJean-Jacques Hiblot if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_8V) 1691bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_180; 1692bc1e3272SJean-Jacques Hiblot if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_2V) 1693bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_120; 1694bc1e3272SJean-Jacques Hiblot break; 1695bc1e3272SJean-Jacques Hiblot case MMC_DDR_52: 1696bc1e3272SJean-Jacques Hiblot if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V) 1697bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_330 | 1698bc1e3272SJean-Jacques Hiblot MMC_SIGNAL_VOLTAGE_180; 1699bc1e3272SJean-Jacques Hiblot if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_2V) 1700bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_120; 1701bc1e3272SJean-Jacques Hiblot break; 1702bc1e3272SJean-Jacques Hiblot default: 1703bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_330; 1704bc1e3272SJean-Jacques Hiblot break; 1705bc1e3272SJean-Jacques Hiblot } 1706bc1e3272SJean-Jacques Hiblot 1707bc1e3272SJean-Jacques Hiblot while (card_mask & allowed_mask) { 1708bc1e3272SJean-Jacques Hiblot enum mmc_voltage best_match; 1709bc1e3272SJean-Jacques Hiblot 1710bc1e3272SJean-Jacques Hiblot best_match = 1 << (ffs(card_mask & allowed_mask) - 1); 1711bc1e3272SJean-Jacques Hiblot if (!mmc_set_signal_voltage(mmc, best_match)) 1712bc1e3272SJean-Jacques Hiblot return 0; 1713bc1e3272SJean-Jacques Hiblot 1714bc1e3272SJean-Jacques Hiblot allowed_mask &= ~best_match; 1715bc1e3272SJean-Jacques Hiblot } 1716bc1e3272SJean-Jacques Hiblot 1717bc1e3272SJean-Jacques Hiblot return -ENOTSUPP; 1718bc1e3272SJean-Jacques Hiblot } 1719bc1e3272SJean-Jacques Hiblot 17203862b854SJean-Jacques Hiblot static const struct mode_width_tuning mmc_modes_by_pref[] = { 17218ac8a263SJean-Jacques Hiblot { 17223862b854SJean-Jacques Hiblot .mode = MMC_HS_200, 17233862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT, 1724634d4849SKishon Vijay Abraham I .tuning = MMC_CMD_SEND_TUNING_BLOCK_HS200 17253862b854SJean-Jacques Hiblot }, 17263862b854SJean-Jacques Hiblot { 17273862b854SJean-Jacques Hiblot .mode = MMC_DDR_52, 17283862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT, 17293862b854SJean-Jacques Hiblot }, 17303862b854SJean-Jacques Hiblot { 17313862b854SJean-Jacques Hiblot .mode = MMC_HS_52, 17323862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 17333862b854SJean-Jacques Hiblot }, 17343862b854SJean-Jacques Hiblot { 17353862b854SJean-Jacques Hiblot .mode = MMC_HS, 17363862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 17373862b854SJean-Jacques Hiblot }, 17383862b854SJean-Jacques Hiblot { 17393862b854SJean-Jacques Hiblot .mode = MMC_LEGACY, 17403862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 17413862b854SJean-Jacques Hiblot } 17428ac8a263SJean-Jacques Hiblot }; 17438ac8a263SJean-Jacques Hiblot 17443862b854SJean-Jacques Hiblot #define for_each_mmc_mode_by_pref(caps, mwt) \ 17453862b854SJean-Jacques Hiblot for (mwt = mmc_modes_by_pref;\ 17463862b854SJean-Jacques Hiblot mwt < mmc_modes_by_pref + ARRAY_SIZE(mmc_modes_by_pref);\ 17473862b854SJean-Jacques Hiblot mwt++) \ 17483862b854SJean-Jacques Hiblot if (caps & MMC_CAP(mwt->mode)) 17493862b854SJean-Jacques Hiblot 17503862b854SJean-Jacques Hiblot static const struct ext_csd_bus_width { 17513862b854SJean-Jacques Hiblot uint cap; 17523862b854SJean-Jacques Hiblot bool is_ddr; 17533862b854SJean-Jacques Hiblot uint ext_csd_bits; 17543862b854SJean-Jacques Hiblot } ext_csd_bus_width[] = { 17553862b854SJean-Jacques Hiblot {MMC_MODE_8BIT, true, EXT_CSD_DDR_BUS_WIDTH_8}, 17563862b854SJean-Jacques Hiblot {MMC_MODE_4BIT, true, EXT_CSD_DDR_BUS_WIDTH_4}, 17573862b854SJean-Jacques Hiblot {MMC_MODE_8BIT, false, EXT_CSD_BUS_WIDTH_8}, 17583862b854SJean-Jacques Hiblot {MMC_MODE_4BIT, false, EXT_CSD_BUS_WIDTH_4}, 17593862b854SJean-Jacques Hiblot {MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1}, 17603862b854SJean-Jacques Hiblot }; 17613862b854SJean-Jacques Hiblot 17623862b854SJean-Jacques Hiblot #define for_each_supported_width(caps, ddr, ecbv) \ 17633862b854SJean-Jacques Hiblot for (ecbv = ext_csd_bus_width;\ 17643862b854SJean-Jacques Hiblot ecbv < ext_csd_bus_width + ARRAY_SIZE(ext_csd_bus_width);\ 17653862b854SJean-Jacques Hiblot ecbv++) \ 17663862b854SJean-Jacques Hiblot if ((ddr == ecbv->is_ddr) && (caps & ecbv->cap)) 17673862b854SJean-Jacques Hiblot 176801298da3SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps) 17693862b854SJean-Jacques Hiblot { 17703862b854SJean-Jacques Hiblot int err; 17713862b854SJean-Jacques Hiblot const struct mode_width_tuning *mwt; 17723862b854SJean-Jacques Hiblot const struct ext_csd_bus_width *ecbw; 17733862b854SJean-Jacques Hiblot 177452d241dfSJean-Jacques Hiblot #ifdef DEBUG 177552d241dfSJean-Jacques Hiblot mmc_dump_capabilities("mmc", card_caps); 17761da8eb59SJean-Jacques Hiblot mmc_dump_capabilities("host", mmc->host_caps); 177752d241dfSJean-Jacques Hiblot #endif 177852d241dfSJean-Jacques Hiblot 17798ac8a263SJean-Jacques Hiblot /* Restrict card's capabilities by what the host can do */ 17801da8eb59SJean-Jacques Hiblot card_caps &= mmc->host_caps; 17818ac8a263SJean-Jacques Hiblot 17828ac8a263SJean-Jacques Hiblot /* Only version 4 of MMC supports wider bus widths */ 17838ac8a263SJean-Jacques Hiblot if (mmc->version < MMC_VERSION_4) 17848ac8a263SJean-Jacques Hiblot return 0; 17858ac8a263SJean-Jacques Hiblot 1786dfda9d88SJean-Jacques Hiblot if (!mmc->ext_csd) { 1787dfda9d88SJean-Jacques Hiblot debug("No ext_csd found!\n"); /* this should enver happen */ 1788dfda9d88SJean-Jacques Hiblot return -ENOTSUPP; 1789dfda9d88SJean-Jacques Hiblot } 1790dfda9d88SJean-Jacques Hiblot 179101298da3SJean-Jacques Hiblot mmc_set_clock(mmc, mmc->legacy_speed, false); 179201298da3SJean-Jacques Hiblot 179301298da3SJean-Jacques Hiblot for_each_mmc_mode_by_pref(card_caps, mwt) { 179401298da3SJean-Jacques Hiblot for_each_supported_width(card_caps & mwt->widths, 17953862b854SJean-Jacques Hiblot mmc_is_mode_ddr(mwt->mode), ecbw) { 1796bc1e3272SJean-Jacques Hiblot enum mmc_voltage old_voltage; 17973862b854SJean-Jacques Hiblot debug("trying mode %s width %d (at %d MHz)\n", 17983862b854SJean-Jacques Hiblot mmc_mode_name(mwt->mode), 17993862b854SJean-Jacques Hiblot bus_width(ecbw->cap), 18003862b854SJean-Jacques Hiblot mmc_mode2freq(mmc, mwt->mode) / 1000000); 1801bc1e3272SJean-Jacques Hiblot old_voltage = mmc->signal_voltage; 1802bc1e3272SJean-Jacques Hiblot err = mmc_set_lowest_voltage(mmc, mwt->mode, 1803bc1e3272SJean-Jacques Hiblot MMC_ALL_SIGNAL_VOLTAGE); 1804bc1e3272SJean-Jacques Hiblot if (err) 1805bc1e3272SJean-Jacques Hiblot continue; 1806bc1e3272SJean-Jacques Hiblot 18073862b854SJean-Jacques Hiblot /* configure the bus width (card + host) */ 18083862b854SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 18093862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, 18103862b854SJean-Jacques Hiblot ecbw->ext_csd_bits & ~EXT_CSD_DDR_FLAG); 18113862b854SJean-Jacques Hiblot if (err) 18123862b854SJean-Jacques Hiblot goto error; 18133862b854SJean-Jacques Hiblot mmc_set_bus_width(mmc, bus_width(ecbw->cap)); 18143862b854SJean-Jacques Hiblot 18153862b854SJean-Jacques Hiblot /* configure the bus speed (card) */ 18163862b854SJean-Jacques Hiblot err = mmc_set_card_speed(mmc, mwt->mode); 18173862b854SJean-Jacques Hiblot if (err) 18183862b854SJean-Jacques Hiblot goto error; 18193862b854SJean-Jacques Hiblot 18208ac8a263SJean-Jacques Hiblot /* 18213862b854SJean-Jacques Hiblot * configure the bus width AND the ddr mode (card) 18223862b854SJean-Jacques Hiblot * The host side will be taken care of in the next step 18238ac8a263SJean-Jacques Hiblot */ 18243862b854SJean-Jacques Hiblot if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) { 18253862b854SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 18263862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, 18273862b854SJean-Jacques Hiblot ecbw->ext_csd_bits); 18283862b854SJean-Jacques Hiblot if (err) 18293862b854SJean-Jacques Hiblot goto error; 18308ac8a263SJean-Jacques Hiblot } 18318ac8a263SJean-Jacques Hiblot 18323862b854SJean-Jacques Hiblot /* configure the bus mode (host) */ 18333862b854SJean-Jacques Hiblot mmc_select_mode(mmc, mwt->mode); 183435f67820SKishon Vijay Abraham I mmc_set_clock(mmc, mmc->tran_speed, false); 18358ac8a263SJean-Jacques Hiblot 1836634d4849SKishon Vijay Abraham I /* execute tuning if needed */ 1837634d4849SKishon Vijay Abraham I if (mwt->tuning) { 1838634d4849SKishon Vijay Abraham I err = mmc_execute_tuning(mmc, mwt->tuning); 1839634d4849SKishon Vijay Abraham I if (err) { 1840634d4849SKishon Vijay Abraham I debug("tuning failed\n"); 1841634d4849SKishon Vijay Abraham I goto error; 1842634d4849SKishon Vijay Abraham I } 1843634d4849SKishon Vijay Abraham I } 1844634d4849SKishon Vijay Abraham I 18453862b854SJean-Jacques Hiblot /* do a transfer to check the configuration */ 18467382e691SJean-Jacques Hiblot err = mmc_read_and_compare_ext_csd(mmc); 18477382e691SJean-Jacques Hiblot if (!err) 18483862b854SJean-Jacques Hiblot return 0; 18493862b854SJean-Jacques Hiblot error: 1850bc1e3272SJean-Jacques Hiblot mmc_set_signal_voltage(mmc, old_voltage); 18513862b854SJean-Jacques Hiblot /* if an error occured, revert to a safer bus mode */ 18523862b854SJean-Jacques Hiblot mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 18533862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_1); 18543862b854SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_LEGACY); 18553862b854SJean-Jacques Hiblot mmc_set_bus_width(mmc, 1); 18563862b854SJean-Jacques Hiblot } 18578ac8a263SJean-Jacques Hiblot } 18588ac8a263SJean-Jacques Hiblot 18593862b854SJean-Jacques Hiblot printf("unable to select a mode\n"); 18608ac8a263SJean-Jacques Hiblot 18613862b854SJean-Jacques Hiblot return -ENOTSUPP; 18628ac8a263SJean-Jacques Hiblot } 18638ac8a263SJean-Jacques Hiblot 1864dfda9d88SJean-Jacques Hiblot static int mmc_startup_v4(struct mmc *mmc) 1865c744b6f6SJean-Jacques Hiblot { 1866c744b6f6SJean-Jacques Hiblot int err, i; 1867c744b6f6SJean-Jacques Hiblot u64 capacity; 1868c744b6f6SJean-Jacques Hiblot bool has_parts = false; 1869c744b6f6SJean-Jacques Hiblot bool part_completed; 1870*f7d5dffcSJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 1871c744b6f6SJean-Jacques Hiblot 1872c744b6f6SJean-Jacques Hiblot if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4)) 1873c744b6f6SJean-Jacques Hiblot return 0; 1874c744b6f6SJean-Jacques Hiblot 1875c744b6f6SJean-Jacques Hiblot /* check ext_csd version and capacity */ 1876c744b6f6SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, ext_csd); 1877c744b6f6SJean-Jacques Hiblot if (err) 1878*f7d5dffcSJean-Jacques Hiblot goto error; 1879*f7d5dffcSJean-Jacques Hiblot 1880*f7d5dffcSJean-Jacques Hiblot /* store the ext csd for future reference */ 1881*f7d5dffcSJean-Jacques Hiblot if (!mmc->ext_csd) 1882*f7d5dffcSJean-Jacques Hiblot mmc->ext_csd = malloc(MMC_MAX_BLOCK_LEN); 1883*f7d5dffcSJean-Jacques Hiblot if (!mmc->ext_csd) 1884*f7d5dffcSJean-Jacques Hiblot return -ENOMEM; 1885*f7d5dffcSJean-Jacques Hiblot memcpy(mmc->ext_csd, ext_csd, MMC_MAX_BLOCK_LEN); 1886*f7d5dffcSJean-Jacques Hiblot 1887c744b6f6SJean-Jacques Hiblot if (ext_csd[EXT_CSD_REV] >= 2) { 1888c744b6f6SJean-Jacques Hiblot /* 1889c744b6f6SJean-Jacques Hiblot * According to the JEDEC Standard, the value of 1890c744b6f6SJean-Jacques Hiblot * ext_csd's capacity is valid if the value is more 1891c744b6f6SJean-Jacques Hiblot * than 2GB 1892c744b6f6SJean-Jacques Hiblot */ 1893c744b6f6SJean-Jacques Hiblot capacity = ext_csd[EXT_CSD_SEC_CNT] << 0 1894c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 1895c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 1896c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; 1897c744b6f6SJean-Jacques Hiblot capacity *= MMC_MAX_BLOCK_LEN; 1898c744b6f6SJean-Jacques Hiblot if ((capacity >> 20) > 2 * 1024) 1899c744b6f6SJean-Jacques Hiblot mmc->capacity_user = capacity; 1900c744b6f6SJean-Jacques Hiblot } 1901c744b6f6SJean-Jacques Hiblot 1902c744b6f6SJean-Jacques Hiblot switch (ext_csd[EXT_CSD_REV]) { 1903c744b6f6SJean-Jacques Hiblot case 1: 1904c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_1; 1905c744b6f6SJean-Jacques Hiblot break; 1906c744b6f6SJean-Jacques Hiblot case 2: 1907c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_2; 1908c744b6f6SJean-Jacques Hiblot break; 1909c744b6f6SJean-Jacques Hiblot case 3: 1910c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_3; 1911c744b6f6SJean-Jacques Hiblot break; 1912c744b6f6SJean-Jacques Hiblot case 5: 1913c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_41; 1914c744b6f6SJean-Jacques Hiblot break; 1915c744b6f6SJean-Jacques Hiblot case 6: 1916c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_5; 1917c744b6f6SJean-Jacques Hiblot break; 1918c744b6f6SJean-Jacques Hiblot case 7: 1919c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_5_0; 1920c744b6f6SJean-Jacques Hiblot break; 1921c744b6f6SJean-Jacques Hiblot case 8: 1922c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_5_1; 1923c744b6f6SJean-Jacques Hiblot break; 1924c744b6f6SJean-Jacques Hiblot } 1925c744b6f6SJean-Jacques Hiblot 1926c744b6f6SJean-Jacques Hiblot /* The partition data may be non-zero but it is only 1927c744b6f6SJean-Jacques Hiblot * effective if PARTITION_SETTING_COMPLETED is set in 1928c744b6f6SJean-Jacques Hiblot * EXT_CSD, so ignore any data if this bit is not set, 1929c744b6f6SJean-Jacques Hiblot * except for enabling the high-capacity group size 1930c744b6f6SJean-Jacques Hiblot * definition (see below). 1931c744b6f6SJean-Jacques Hiblot */ 1932c744b6f6SJean-Jacques Hiblot part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] & 1933c744b6f6SJean-Jacques Hiblot EXT_CSD_PARTITION_SETTING_COMPLETED); 1934c744b6f6SJean-Jacques Hiblot 1935c744b6f6SJean-Jacques Hiblot /* store the partition info of emmc */ 1936c744b6f6SJean-Jacques Hiblot mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT]; 1937c744b6f6SJean-Jacques Hiblot if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || 1938c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_BOOT_MULT]) 1939c744b6f6SJean-Jacques Hiblot mmc->part_config = ext_csd[EXT_CSD_PART_CONF]; 1940c744b6f6SJean-Jacques Hiblot if (part_completed && 1941c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT)) 1942c744b6f6SJean-Jacques Hiblot mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]; 1943c744b6f6SJean-Jacques Hiblot 1944c744b6f6SJean-Jacques Hiblot mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17; 1945c744b6f6SJean-Jacques Hiblot 1946c744b6f6SJean-Jacques Hiblot mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17; 1947c744b6f6SJean-Jacques Hiblot 1948c744b6f6SJean-Jacques Hiblot for (i = 0; i < 4; i++) { 1949c744b6f6SJean-Jacques Hiblot int idx = EXT_CSD_GP_SIZE_MULT + i * 3; 1950c744b6f6SJean-Jacques Hiblot uint mult = (ext_csd[idx + 2] << 16) + 1951c744b6f6SJean-Jacques Hiblot (ext_csd[idx + 1] << 8) + ext_csd[idx]; 1952c744b6f6SJean-Jacques Hiblot if (mult) 1953c744b6f6SJean-Jacques Hiblot has_parts = true; 1954c744b6f6SJean-Jacques Hiblot if (!part_completed) 1955c744b6f6SJean-Jacques Hiblot continue; 1956c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] = mult; 1957c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] *= 1958c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 1959c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1960c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] <<= 19; 1961c744b6f6SJean-Jacques Hiblot } 1962c744b6f6SJean-Jacques Hiblot 1963c744b6f6SJean-Jacques Hiblot if (part_completed) { 1964c744b6f6SJean-Jacques Hiblot mmc->enh_user_size = 1965c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) + 1966c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) + 1967c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ENH_SIZE_MULT]; 1968c744b6f6SJean-Jacques Hiblot mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 1969c744b6f6SJean-Jacques Hiblot mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1970c744b6f6SJean-Jacques Hiblot mmc->enh_user_size <<= 19; 1971c744b6f6SJean-Jacques Hiblot mmc->enh_user_start = 1972c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24) + 1973c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) + 1974c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) + 1975c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ENH_START_ADDR]; 1976c744b6f6SJean-Jacques Hiblot if (mmc->high_capacity) 1977c744b6f6SJean-Jacques Hiblot mmc->enh_user_start <<= 9; 1978c744b6f6SJean-Jacques Hiblot } 1979c744b6f6SJean-Jacques Hiblot 1980c744b6f6SJean-Jacques Hiblot /* 1981c744b6f6SJean-Jacques Hiblot * Host needs to enable ERASE_GRP_DEF bit if device is 1982c744b6f6SJean-Jacques Hiblot * partitioned. This bit will be lost every time after a reset 1983c744b6f6SJean-Jacques Hiblot * or power off. This will affect erase size. 1984c744b6f6SJean-Jacques Hiblot */ 1985c744b6f6SJean-Jacques Hiblot if (part_completed) 1986c744b6f6SJean-Jacques Hiblot has_parts = true; 1987c744b6f6SJean-Jacques Hiblot if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) && 1988c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) 1989c744b6f6SJean-Jacques Hiblot has_parts = true; 1990c744b6f6SJean-Jacques Hiblot if (has_parts) { 1991c744b6f6SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1992c744b6f6SJean-Jacques Hiblot EXT_CSD_ERASE_GROUP_DEF, 1); 1993c744b6f6SJean-Jacques Hiblot 1994c744b6f6SJean-Jacques Hiblot if (err) 1995*f7d5dffcSJean-Jacques Hiblot goto error; 1996c744b6f6SJean-Jacques Hiblot 1997c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 1998c744b6f6SJean-Jacques Hiblot } 1999c744b6f6SJean-Jacques Hiblot 2000c744b6f6SJean-Jacques Hiblot if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) { 2001c744b6f6SJean-Jacques Hiblot /* Read out group size from ext_csd */ 2002c744b6f6SJean-Jacques Hiblot mmc->erase_grp_size = 2003c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 2004c744b6f6SJean-Jacques Hiblot /* 2005c744b6f6SJean-Jacques Hiblot * if high capacity and partition setting completed 2006c744b6f6SJean-Jacques Hiblot * SEC_COUNT is valid even if it is smaller than 2 GiB 2007c744b6f6SJean-Jacques Hiblot * JEDEC Standard JESD84-B45, 6.2.4 2008c744b6f6SJean-Jacques Hiblot */ 2009c744b6f6SJean-Jacques Hiblot if (mmc->high_capacity && part_completed) { 2010c744b6f6SJean-Jacques Hiblot capacity = (ext_csd[EXT_CSD_SEC_CNT]) | 2011c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 1] << 8) | 2012c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 2] << 16) | 2013c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 3] << 24); 2014c744b6f6SJean-Jacques Hiblot capacity *= MMC_MAX_BLOCK_LEN; 2015c744b6f6SJean-Jacques Hiblot mmc->capacity_user = capacity; 2016c744b6f6SJean-Jacques Hiblot } 2017c744b6f6SJean-Jacques Hiblot } else { 2018c744b6f6SJean-Jacques Hiblot /* Calculate the group size from the csd value. */ 2019c744b6f6SJean-Jacques Hiblot int erase_gsz, erase_gmul; 2020c744b6f6SJean-Jacques Hiblot 2021c744b6f6SJean-Jacques Hiblot erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10; 2022c744b6f6SJean-Jacques Hiblot erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5; 2023c744b6f6SJean-Jacques Hiblot mmc->erase_grp_size = (erase_gsz + 1) 2024c744b6f6SJean-Jacques Hiblot * (erase_gmul + 1); 2025c744b6f6SJean-Jacques Hiblot } 2026c744b6f6SJean-Jacques Hiblot 2027c744b6f6SJean-Jacques Hiblot mmc->hc_wp_grp_size = 1024 2028c744b6f6SJean-Jacques Hiblot * ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 2029c744b6f6SJean-Jacques Hiblot * ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 2030c744b6f6SJean-Jacques Hiblot 2031c744b6f6SJean-Jacques Hiblot mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 2032c744b6f6SJean-Jacques Hiblot 2033c744b6f6SJean-Jacques Hiblot return 0; 2034*f7d5dffcSJean-Jacques Hiblot error: 2035*f7d5dffcSJean-Jacques Hiblot if (mmc->ext_csd) { 2036*f7d5dffcSJean-Jacques Hiblot free(mmc->ext_csd); 2037*f7d5dffcSJean-Jacques Hiblot mmc->ext_csd = NULL; 2038*f7d5dffcSJean-Jacques Hiblot } 2039*f7d5dffcSJean-Jacques Hiblot return err; 2040c744b6f6SJean-Jacques Hiblot } 2041c744b6f6SJean-Jacques Hiblot 2042fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc) 2043272cc70bSAndy Fleming { 2044f866a46dSStephen Warren int err, i; 2045272cc70bSAndy Fleming uint mult, freq; 2046c744b6f6SJean-Jacques Hiblot u64 cmult, csize; 2047272cc70bSAndy Fleming struct mmc_cmd cmd; 2048c40fdca6SSimon Glass struct blk_desc *bdesc; 2049272cc70bSAndy Fleming 2050d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON 2051d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */ 2052d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF; 2053d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R1; 2054d52ebf10SThomas Chou cmd.cmdarg = 1; 2055d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 2056d52ebf10SThomas Chou if (err) 2057d52ebf10SThomas Chou return err; 2058d52ebf10SThomas Chou } 2059d52ebf10SThomas Chou #endif 2060d52ebf10SThomas Chou 2061272cc70bSAndy Fleming /* Put the Card in Identify Mode */ 2062d52ebf10SThomas Chou cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID : 2063d52ebf10SThomas Chou MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */ 2064272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 2065272cc70bSAndy Fleming cmd.cmdarg = 0; 2066272cc70bSAndy Fleming 2067272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2068272cc70bSAndy Fleming 206983dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS 207083dc4227SKishon Vijay Abraham I if (err && (mmc->quirks & MMC_QUIRK_RETRY_SEND_CID)) { 207183dc4227SKishon Vijay Abraham I int retries = 4; 207283dc4227SKishon Vijay Abraham I /* 207383dc4227SKishon Vijay Abraham I * It has been seen that SEND_CID may fail on the first 207483dc4227SKishon Vijay Abraham I * attempt, let's try a few more time 207583dc4227SKishon Vijay Abraham I */ 207683dc4227SKishon Vijay Abraham I do { 207783dc4227SKishon Vijay Abraham I err = mmc_send_cmd(mmc, &cmd, NULL); 207883dc4227SKishon Vijay Abraham I if (!err) 207983dc4227SKishon Vijay Abraham I break; 208083dc4227SKishon Vijay Abraham I } while (retries--); 208183dc4227SKishon Vijay Abraham I } 208283dc4227SKishon Vijay Abraham I #endif 208383dc4227SKishon Vijay Abraham I 2084272cc70bSAndy Fleming if (err) 2085272cc70bSAndy Fleming return err; 2086272cc70bSAndy Fleming 2087272cc70bSAndy Fleming memcpy(mmc->cid, cmd.response, 16); 2088272cc70bSAndy Fleming 2089272cc70bSAndy Fleming /* 2090272cc70bSAndy Fleming * For MMC cards, set the Relative Address. 2091272cc70bSAndy Fleming * For SD cards, get the Relatvie Address. 2092272cc70bSAndy Fleming * This also puts the cards into Standby State 2093272cc70bSAndy Fleming */ 2094d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 2095272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR; 2096272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 2097272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R6; 2098272cc70bSAndy Fleming 2099272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2100272cc70bSAndy Fleming 2101272cc70bSAndy Fleming if (err) 2102272cc70bSAndy Fleming return err; 2103272cc70bSAndy Fleming 2104272cc70bSAndy Fleming if (IS_SD(mmc)) 2105998be3ddSRabin Vincent mmc->rca = (cmd.response[0] >> 16) & 0xffff; 2106d52ebf10SThomas Chou } 2107272cc70bSAndy Fleming 2108272cc70bSAndy Fleming /* Get the Card-Specific Data */ 2109272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_CSD; 2110272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 2111272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 2112272cc70bSAndy Fleming 2113272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2114272cc70bSAndy Fleming 2115272cc70bSAndy Fleming if (err) 2116272cc70bSAndy Fleming return err; 2117272cc70bSAndy Fleming 2118998be3ddSRabin Vincent mmc->csd[0] = cmd.response[0]; 2119998be3ddSRabin Vincent mmc->csd[1] = cmd.response[1]; 2120998be3ddSRabin Vincent mmc->csd[2] = cmd.response[2]; 2121998be3ddSRabin Vincent mmc->csd[3] = cmd.response[3]; 2122272cc70bSAndy Fleming 2123272cc70bSAndy Fleming if (mmc->version == MMC_VERSION_UNKNOWN) { 21240b453ffeSRabin Vincent int version = (cmd.response[0] >> 26) & 0xf; 2125272cc70bSAndy Fleming 2126272cc70bSAndy Fleming switch (version) { 2127272cc70bSAndy Fleming case 0: 2128272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 2129272cc70bSAndy Fleming break; 2130272cc70bSAndy Fleming case 1: 2131272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_4; 2132272cc70bSAndy Fleming break; 2133272cc70bSAndy Fleming case 2: 2134272cc70bSAndy Fleming mmc->version = MMC_VERSION_2_2; 2135272cc70bSAndy Fleming break; 2136272cc70bSAndy Fleming case 3: 2137272cc70bSAndy Fleming mmc->version = MMC_VERSION_3; 2138272cc70bSAndy Fleming break; 2139272cc70bSAndy Fleming case 4: 2140272cc70bSAndy Fleming mmc->version = MMC_VERSION_4; 2141272cc70bSAndy Fleming break; 2142272cc70bSAndy Fleming default: 2143272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 2144272cc70bSAndy Fleming break; 2145272cc70bSAndy Fleming } 2146272cc70bSAndy Fleming } 2147272cc70bSAndy Fleming 2148272cc70bSAndy Fleming /* divide frequency by 10, since the mults are 10x bigger */ 21490b453ffeSRabin Vincent freq = fbase[(cmd.response[0] & 0x7)]; 21500b453ffeSRabin Vincent mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; 2151272cc70bSAndy Fleming 215235f9e196SJean-Jacques Hiblot mmc->legacy_speed = freq * mult; 215335f9e196SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_LEGACY); 2154272cc70bSAndy Fleming 2155ab71188cSMarkus Niebel mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1); 2156998be3ddSRabin Vincent mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf); 2157272cc70bSAndy Fleming 2158272cc70bSAndy Fleming if (IS_SD(mmc)) 2159272cc70bSAndy Fleming mmc->write_bl_len = mmc->read_bl_len; 2160272cc70bSAndy Fleming else 2161998be3ddSRabin Vincent mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf); 2162272cc70bSAndy Fleming 2163272cc70bSAndy Fleming if (mmc->high_capacity) { 2164272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3f) << 16 2165272cc70bSAndy Fleming | (mmc->csd[2] & 0xffff0000) >> 16; 2166272cc70bSAndy Fleming cmult = 8; 2167272cc70bSAndy Fleming } else { 2168272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3ff) << 2 2169272cc70bSAndy Fleming | (mmc->csd[2] & 0xc0000000) >> 30; 2170272cc70bSAndy Fleming cmult = (mmc->csd[2] & 0x00038000) >> 15; 2171272cc70bSAndy Fleming } 2172272cc70bSAndy Fleming 2173f866a46dSStephen Warren mmc->capacity_user = (csize + 1) << (cmult + 2); 2174f866a46dSStephen Warren mmc->capacity_user *= mmc->read_bl_len; 2175f866a46dSStephen Warren mmc->capacity_boot = 0; 2176f866a46dSStephen Warren mmc->capacity_rpmb = 0; 2177f866a46dSStephen Warren for (i = 0; i < 4; i++) 2178f866a46dSStephen Warren mmc->capacity_gp[i] = 0; 2179272cc70bSAndy Fleming 21808bfa195eSSimon Glass if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN) 21818bfa195eSSimon Glass mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 2182272cc70bSAndy Fleming 21838bfa195eSSimon Glass if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN) 21848bfa195eSSimon Glass mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 2185272cc70bSAndy Fleming 2186ab71188cSMarkus Niebel if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) { 2187ab71188cSMarkus Niebel cmd.cmdidx = MMC_CMD_SET_DSR; 2188ab71188cSMarkus Niebel cmd.cmdarg = (mmc->dsr & 0xffff) << 16; 2189ab71188cSMarkus Niebel cmd.resp_type = MMC_RSP_NONE; 2190ab71188cSMarkus Niebel if (mmc_send_cmd(mmc, &cmd, NULL)) 2191ab71188cSMarkus Niebel printf("MMC: SET_DSR failed\n"); 2192ab71188cSMarkus Niebel } 2193ab71188cSMarkus Niebel 2194272cc70bSAndy Fleming /* Select the card, and put it into Transfer Mode */ 2195d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 2196272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SELECT_CARD; 2197fe8f7066SAjay Bhargav cmd.resp_type = MMC_RSP_R1; 2198272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 2199272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2200272cc70bSAndy Fleming 2201272cc70bSAndy Fleming if (err) 2202272cc70bSAndy Fleming return err; 2203d52ebf10SThomas Chou } 2204272cc70bSAndy Fleming 2205e6f99a56SLei Wen /* 2206e6f99a56SLei Wen * For SD, its erase group is always one sector 2207e6f99a56SLei Wen */ 2208e6f99a56SLei Wen mmc->erase_grp_size = 1; 2209bc897b1dSLei Wen mmc->part_config = MMCPART_NOAVAILABLE; 2210c744b6f6SJean-Jacques Hiblot 2211dfda9d88SJean-Jacques Hiblot err = mmc_startup_v4(mmc); 22129cf199ebSDiego Santa Cruz if (err) 22139cf199ebSDiego Santa Cruz return err; 2214f866a46dSStephen Warren 2215c40fdca6SSimon Glass err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart); 2216f866a46dSStephen Warren if (err) 2217f866a46dSStephen Warren return err; 2218d23e2c09SSukumar Ghorai 221901298da3SJean-Jacques Hiblot if (IS_SD(mmc)) { 222001298da3SJean-Jacques Hiblot err = sd_get_capabilities(mmc); 222101298da3SJean-Jacques Hiblot if (err) 222201298da3SJean-Jacques Hiblot return err; 222301298da3SJean-Jacques Hiblot err = sd_select_mode_and_width(mmc, mmc->card_caps); 222401298da3SJean-Jacques Hiblot } else { 222501298da3SJean-Jacques Hiblot err = mmc_get_capabilities(mmc); 222601298da3SJean-Jacques Hiblot if (err) 222701298da3SJean-Jacques Hiblot return err; 222801298da3SJean-Jacques Hiblot mmc_select_mode_and_width(mmc, mmc->card_caps); 222901298da3SJean-Jacques Hiblot } 2230272cc70bSAndy Fleming 2231272cc70bSAndy Fleming if (err) 2232272cc70bSAndy Fleming return err; 2233272cc70bSAndy Fleming 223401298da3SJean-Jacques Hiblot mmc->best_mode = mmc->selected_mode; 2235272cc70bSAndy Fleming 22365af8f45cSAndrew Gabbasov /* Fix the block length for DDR mode */ 22375af8f45cSAndrew Gabbasov if (mmc->ddr_mode) { 22385af8f45cSAndrew Gabbasov mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 22395af8f45cSAndrew Gabbasov mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 22405af8f45cSAndrew Gabbasov } 22415af8f45cSAndrew Gabbasov 2242272cc70bSAndy Fleming /* fill in device description */ 2243c40fdca6SSimon Glass bdesc = mmc_get_blk_desc(mmc); 2244c40fdca6SSimon Glass bdesc->lun = 0; 2245c40fdca6SSimon Glass bdesc->hwpart = 0; 2246c40fdca6SSimon Glass bdesc->type = 0; 2247c40fdca6SSimon Glass bdesc->blksz = mmc->read_bl_len; 2248c40fdca6SSimon Glass bdesc->log2blksz = LOG2(bdesc->blksz); 2249c40fdca6SSimon Glass bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len); 2250fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \ 2251fc011f64SSjoerd Simons (defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \ 2252fc011f64SSjoerd Simons !defined(CONFIG_USE_TINY_PRINTF)) 2253c40fdca6SSimon Glass sprintf(bdesc->vendor, "Man %06x Snr %04x%04x", 2254babce5f6STaylor Hutt mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff), 2255babce5f6STaylor Hutt (mmc->cid[3] >> 16) & 0xffff); 2256c40fdca6SSimon Glass sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff, 22570b453ffeSRabin Vincent (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, 2258babce5f6STaylor Hutt (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff, 2259babce5f6STaylor Hutt (mmc->cid[2] >> 24) & 0xff); 2260c40fdca6SSimon Glass sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf, 2261babce5f6STaylor Hutt (mmc->cid[2] >> 16) & 0xf); 226256196826SPaul Burton #else 2263c40fdca6SSimon Glass bdesc->vendor[0] = 0; 2264c40fdca6SSimon Glass bdesc->product[0] = 0; 2265c40fdca6SSimon Glass bdesc->revision[0] = 0; 226656196826SPaul Burton #endif 2267122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT) 2268c40fdca6SSimon Glass part_init(bdesc); 2269122efd43SMikhail Kshevetskiy #endif 2270272cc70bSAndy Fleming 2271272cc70bSAndy Fleming return 0; 2272272cc70bSAndy Fleming } 2273272cc70bSAndy Fleming 2274fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc) 2275272cc70bSAndy Fleming { 2276272cc70bSAndy Fleming struct mmc_cmd cmd; 2277272cc70bSAndy Fleming int err; 2278272cc70bSAndy Fleming 2279272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_IF_COND; 2280272cc70bSAndy Fleming /* We set the bit if the host supports voltages between 2.7 and 3.6 V */ 228193bfd616SPantelis Antoniou cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa; 2282272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R7; 2283272cc70bSAndy Fleming 2284272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2285272cc70bSAndy Fleming 2286272cc70bSAndy Fleming if (err) 2287272cc70bSAndy Fleming return err; 2288272cc70bSAndy Fleming 2289998be3ddSRabin Vincent if ((cmd.response[0] & 0xff) != 0xaa) 2290915ffa52SJaehoon Chung return -EOPNOTSUPP; 2291272cc70bSAndy Fleming else 2292272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 2293272cc70bSAndy Fleming 2294272cc70bSAndy Fleming return 0; 2295272cc70bSAndy Fleming } 2296272cc70bSAndy Fleming 2297c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 229895de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */ 229995de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void) 230095de9ab2SPaul Kocialkowski { 230195de9ab2SPaul Kocialkowski } 230205cbeb7cSSimon Glass #endif 230395de9ab2SPaul Kocialkowski 23042051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc) 23052051aefeSPeng Fan { 2306c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 230706ec045fSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_REGULATOR) 23082051aefeSPeng Fan int ret; 23092051aefeSPeng Fan 23102051aefeSPeng Fan ret = device_get_supply_regulator(mmc->dev, "vmmc-supply", 231106ec045fSJean-Jacques Hiblot &mmc->vmmc_supply); 231206ec045fSJean-Jacques Hiblot if (ret) 2313288db7c7SJaehoon Chung debug("%s: No vmmc supply\n", mmc->dev->name); 23142051aefeSPeng Fan 231506ec045fSJean-Jacques Hiblot ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply", 231606ec045fSJean-Jacques Hiblot &mmc->vqmmc_supply); 231706ec045fSJean-Jacques Hiblot if (ret) 231806ec045fSJean-Jacques Hiblot debug("%s: No vqmmc supply\n", mmc->dev->name); 23192051aefeSPeng Fan #endif 232005cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */ 232105cbeb7cSSimon Glass /* 232205cbeb7cSSimon Glass * Driver model should use a regulator, as above, rather than calling 232305cbeb7cSSimon Glass * out to board code. 232405cbeb7cSSimon Glass */ 232505cbeb7cSSimon Glass board_mmc_power_init(); 232605cbeb7cSSimon Glass #endif 23272051aefeSPeng Fan return 0; 23282051aefeSPeng Fan } 23292051aefeSPeng Fan 2330fb7c3bebSKishon Vijay Abraham I /* 2331fb7c3bebSKishon Vijay Abraham I * put the host in the initial state: 2332fb7c3bebSKishon Vijay Abraham I * - turn on Vdd (card power supply) 2333fb7c3bebSKishon Vijay Abraham I * - configure the bus width and clock to minimal values 2334fb7c3bebSKishon Vijay Abraham I */ 2335fb7c3bebSKishon Vijay Abraham I static void mmc_set_initial_state(struct mmc *mmc) 2336fb7c3bebSKishon Vijay Abraham I { 2337fb7c3bebSKishon Vijay Abraham I int err; 2338fb7c3bebSKishon Vijay Abraham I 2339fb7c3bebSKishon Vijay Abraham I /* First try to set 3.3V. If it fails set to 1.8V */ 2340fb7c3bebSKishon Vijay Abraham I err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_330); 2341fb7c3bebSKishon Vijay Abraham I if (err != 0) 2342fb7c3bebSKishon Vijay Abraham I err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_180); 2343fb7c3bebSKishon Vijay Abraham I if (err != 0) 2344fb7c3bebSKishon Vijay Abraham I printf("mmc: failed to set signal voltage\n"); 2345fb7c3bebSKishon Vijay Abraham I 2346fb7c3bebSKishon Vijay Abraham I mmc_select_mode(mmc, MMC_LEGACY); 2347fb7c3bebSKishon Vijay Abraham I mmc_set_bus_width(mmc, 1); 234835f67820SKishon Vijay Abraham I mmc_set_clock(mmc, 0, false); 2349fb7c3bebSKishon Vijay Abraham I } 2350fb7c3bebSKishon Vijay Abraham I 2351fb7c3bebSKishon Vijay Abraham I static int mmc_power_on(struct mmc *mmc) 2352fb7c3bebSKishon Vijay Abraham I { 2353fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR) 2354fb7c3bebSKishon Vijay Abraham I if (mmc->vmmc_supply) { 2355fb7c3bebSKishon Vijay Abraham I int ret = regulator_set_enable(mmc->vmmc_supply, true); 2356fb7c3bebSKishon Vijay Abraham I 2357fb7c3bebSKishon Vijay Abraham I if (ret) { 2358fb7c3bebSKishon Vijay Abraham I puts("Error enabling VMMC supply\n"); 2359fb7c3bebSKishon Vijay Abraham I return ret; 2360fb7c3bebSKishon Vijay Abraham I } 2361fb7c3bebSKishon Vijay Abraham I } 2362fb7c3bebSKishon Vijay Abraham I #endif 2363fb7c3bebSKishon Vijay Abraham I return 0; 2364fb7c3bebSKishon Vijay Abraham I } 2365fb7c3bebSKishon Vijay Abraham I 2366fb7c3bebSKishon Vijay Abraham I static int mmc_power_off(struct mmc *mmc) 2367fb7c3bebSKishon Vijay Abraham I { 23682e7410d7SKishon Vijay Abraham I mmc_set_clock(mmc, 1, true); 2369fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR) 2370fb7c3bebSKishon Vijay Abraham I if (mmc->vmmc_supply) { 2371fb7c3bebSKishon Vijay Abraham I int ret = regulator_set_enable(mmc->vmmc_supply, false); 2372fb7c3bebSKishon Vijay Abraham I 2373fb7c3bebSKishon Vijay Abraham I if (ret) { 2374c10b85d6SJean-Jacques Hiblot debug("Error disabling VMMC supply\n"); 2375fb7c3bebSKishon Vijay Abraham I return ret; 2376fb7c3bebSKishon Vijay Abraham I } 2377fb7c3bebSKishon Vijay Abraham I } 2378fb7c3bebSKishon Vijay Abraham I #endif 2379fb7c3bebSKishon Vijay Abraham I return 0; 2380fb7c3bebSKishon Vijay Abraham I } 2381fb7c3bebSKishon Vijay Abraham I 2382fb7c3bebSKishon Vijay Abraham I static int mmc_power_cycle(struct mmc *mmc) 2383fb7c3bebSKishon Vijay Abraham I { 2384fb7c3bebSKishon Vijay Abraham I int ret; 2385fb7c3bebSKishon Vijay Abraham I 2386fb7c3bebSKishon Vijay Abraham I ret = mmc_power_off(mmc); 2387fb7c3bebSKishon Vijay Abraham I if (ret) 2388fb7c3bebSKishon Vijay Abraham I return ret; 2389fb7c3bebSKishon Vijay Abraham I /* 2390fb7c3bebSKishon Vijay Abraham I * SD spec recommends at least 1ms of delay. Let's wait for 2ms 2391fb7c3bebSKishon Vijay Abraham I * to be on the safer side. 2392fb7c3bebSKishon Vijay Abraham I */ 2393fb7c3bebSKishon Vijay Abraham I udelay(2000); 2394fb7c3bebSKishon Vijay Abraham I return mmc_power_on(mmc); 2395fb7c3bebSKishon Vijay Abraham I } 2396fb7c3bebSKishon Vijay Abraham I 2397e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc) 2398272cc70bSAndy Fleming { 23998ca51e51SSimon Glass bool no_card; 2400c10b85d6SJean-Jacques Hiblot bool uhs_en = supports_uhs(mmc->cfg->host_caps); 2401afd5932bSMacpaul Lin int err; 2402272cc70bSAndy Fleming 24031da8eb59SJean-Jacques Hiblot /* 24041da8eb59SJean-Jacques Hiblot * all hosts are capable of 1 bit bus-width and able to use the legacy 24051da8eb59SJean-Jacques Hiblot * timings. 24061da8eb59SJean-Jacques Hiblot */ 24071da8eb59SJean-Jacques Hiblot mmc->host_caps = mmc->cfg->host_caps | MMC_CAP(SD_LEGACY) | 24081da8eb59SJean-Jacques Hiblot MMC_CAP(MMC_LEGACY) | MMC_MODE_1BIT; 240904a2ea24SJean-Jacques Hiblot 2410ab769f22SPantelis Antoniou /* we pretend there's no card when init is NULL */ 24118ca51e51SSimon Glass no_card = mmc_getcd(mmc) == 0; 2412e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 24138ca51e51SSimon Glass no_card = no_card || (mmc->cfg->ops->init == NULL); 24148ca51e51SSimon Glass #endif 24158ca51e51SSimon Glass if (no_card) { 241648972d90SThierry Reding mmc->has_init = 0; 241756196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 241848972d90SThierry Reding printf("MMC: no card present\n"); 241956196826SPaul Burton #endif 2420915ffa52SJaehoon Chung return -ENOMEDIUM; 242148972d90SThierry Reding } 242248972d90SThierry Reding 2423bc897b1dSLei Wen if (mmc->has_init) 2424bc897b1dSLei Wen return 0; 2425bc897b1dSLei Wen 24265a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 24275a8dbdc6SYangbo Lu mmc_adapter_card_type_ident(); 24285a8dbdc6SYangbo Lu #endif 24292051aefeSPeng Fan err = mmc_power_init(mmc); 24302051aefeSPeng Fan if (err) 24312051aefeSPeng Fan return err; 243295de9ab2SPaul Kocialkowski 243383dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS 243483dc4227SKishon Vijay Abraham I mmc->quirks = MMC_QUIRK_RETRY_SET_BLOCKLEN | 243583dc4227SKishon Vijay Abraham I MMC_QUIRK_RETRY_SEND_CID; 243683dc4227SKishon Vijay Abraham I #endif 243783dc4227SKishon Vijay Abraham I 243804a2ea24SJean-Jacques Hiblot err = mmc_power_cycle(mmc); 243904a2ea24SJean-Jacques Hiblot if (err) { 244004a2ea24SJean-Jacques Hiblot /* 244104a2ea24SJean-Jacques Hiblot * if power cycling is not supported, we should not try 244204a2ea24SJean-Jacques Hiblot * to use the UHS modes, because we wouldn't be able to 244304a2ea24SJean-Jacques Hiblot * recover from an error during the UHS initialization. 244404a2ea24SJean-Jacques Hiblot */ 244504a2ea24SJean-Jacques Hiblot debug("Unable to do a full power cycle. Disabling the UHS modes for safety\n"); 244604a2ea24SJean-Jacques Hiblot uhs_en = false; 244704a2ea24SJean-Jacques Hiblot mmc->host_caps &= ~UHS_CAPS; 2448fb7c3bebSKishon Vijay Abraham I err = mmc_power_on(mmc); 244904a2ea24SJean-Jacques Hiblot } 2450fb7c3bebSKishon Vijay Abraham I if (err) 2451fb7c3bebSKishon Vijay Abraham I return err; 2452fb7c3bebSKishon Vijay Abraham I 2453e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 24548ca51e51SSimon Glass /* The device has already been probed ready for use */ 24558ca51e51SSimon Glass #else 2456ab769f22SPantelis Antoniou /* made sure it's not NULL earlier */ 245793bfd616SPantelis Antoniou err = mmc->cfg->ops->init(mmc); 2458272cc70bSAndy Fleming if (err) 2459272cc70bSAndy Fleming return err; 24608ca51e51SSimon Glass #endif 2461786e8f81SAndrew Gabbasov mmc->ddr_mode = 0; 2462aff5d3c8SKishon Vijay Abraham I 2463c10b85d6SJean-Jacques Hiblot retry: 2464fb7c3bebSKishon Vijay Abraham I mmc_set_initial_state(mmc); 2465318a7a57SJean-Jacques Hiblot mmc_send_init_stream(mmc); 2466318a7a57SJean-Jacques Hiblot 2467272cc70bSAndy Fleming /* Reset the Card */ 2468272cc70bSAndy Fleming err = mmc_go_idle(mmc); 2469272cc70bSAndy Fleming 2470272cc70bSAndy Fleming if (err) 2471272cc70bSAndy Fleming return err; 2472272cc70bSAndy Fleming 2473bc897b1dSLei Wen /* The internal partition reset to user partition(0) at every CMD0*/ 2474c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->hwpart = 0; 2475bc897b1dSLei Wen 2476272cc70bSAndy Fleming /* Test for SD version 2 */ 2477272cc70bSAndy Fleming err = mmc_send_if_cond(mmc); 2478272cc70bSAndy Fleming 2479272cc70bSAndy Fleming /* Now try to get the SD card's operating condition */ 2480c10b85d6SJean-Jacques Hiblot err = sd_send_op_cond(mmc, uhs_en); 2481c10b85d6SJean-Jacques Hiblot if (err && uhs_en) { 2482c10b85d6SJean-Jacques Hiblot uhs_en = false; 2483c10b85d6SJean-Jacques Hiblot mmc_power_cycle(mmc); 2484c10b85d6SJean-Jacques Hiblot goto retry; 2485c10b85d6SJean-Jacques Hiblot } 2486272cc70bSAndy Fleming 2487272cc70bSAndy Fleming /* If the command timed out, we check for an MMC card */ 2488915ffa52SJaehoon Chung if (err == -ETIMEDOUT) { 2489272cc70bSAndy Fleming err = mmc_send_op_cond(mmc); 2490272cc70bSAndy Fleming 2491bd47c135SAndrew Gabbasov if (err) { 249256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2493272cc70bSAndy Fleming printf("Card did not respond to voltage select!\n"); 249456196826SPaul Burton #endif 2495915ffa52SJaehoon Chung return -EOPNOTSUPP; 2496272cc70bSAndy Fleming } 2497272cc70bSAndy Fleming } 2498272cc70bSAndy Fleming 2499bd47c135SAndrew Gabbasov if (!err) 2500e9550449SChe-Liang Chiou mmc->init_in_progress = 1; 2501e9550449SChe-Liang Chiou 2502e9550449SChe-Liang Chiou return err; 2503e9550449SChe-Liang Chiou } 2504e9550449SChe-Liang Chiou 2505e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc) 2506e9550449SChe-Liang Chiou { 2507e9550449SChe-Liang Chiou int err = 0; 2508e9550449SChe-Liang Chiou 2509bd47c135SAndrew Gabbasov mmc->init_in_progress = 0; 2510e9550449SChe-Liang Chiou if (mmc->op_cond_pending) 2511e9550449SChe-Liang Chiou err = mmc_complete_op_cond(mmc); 2512e9550449SChe-Liang Chiou 2513e9550449SChe-Liang Chiou if (!err) 2514bc897b1dSLei Wen err = mmc_startup(mmc); 2515bc897b1dSLei Wen if (err) 2516bc897b1dSLei Wen mmc->has_init = 0; 2517bc897b1dSLei Wen else 2518bc897b1dSLei Wen mmc->has_init = 1; 2519e9550449SChe-Liang Chiou return err; 2520e9550449SChe-Liang Chiou } 2521e9550449SChe-Liang Chiou 2522e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc) 2523e9550449SChe-Liang Chiou { 2524bd47c135SAndrew Gabbasov int err = 0; 2525ce9eca94SMarek Vasut __maybe_unused unsigned start; 2526c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 252733fb211dSSimon Glass struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev); 2528e9550449SChe-Liang Chiou 252933fb211dSSimon Glass upriv->mmc = mmc; 253033fb211dSSimon Glass #endif 2531e9550449SChe-Liang Chiou if (mmc->has_init) 2532e9550449SChe-Liang Chiou return 0; 2533d803fea5SMateusz Zalega 2534d803fea5SMateusz Zalega start = get_timer(0); 2535d803fea5SMateusz Zalega 2536e9550449SChe-Liang Chiou if (!mmc->init_in_progress) 2537e9550449SChe-Liang Chiou err = mmc_start_init(mmc); 2538e9550449SChe-Liang Chiou 2539bd47c135SAndrew Gabbasov if (!err) 2540e9550449SChe-Liang Chiou err = mmc_complete_init(mmc); 2541919b4858SJagan Teki if (err) 2542919b4858SJagan Teki printf("%s: %d, time %lu\n", __func__, err, get_timer(start)); 2543919b4858SJagan Teki 2544bc897b1dSLei Wen return err; 2545272cc70bSAndy Fleming } 2546272cc70bSAndy Fleming 2547ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val) 2548ab71188cSMarkus Niebel { 2549ab71188cSMarkus Niebel mmc->dsr = val; 2550ab71188cSMarkus Niebel return 0; 2551ab71188cSMarkus Niebel } 2552ab71188cSMarkus Niebel 2553cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */ 2554cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis) 2555272cc70bSAndy Fleming { 2556272cc70bSAndy Fleming return -1; 2557272cc70bSAndy Fleming } 2558272cc70bSAndy Fleming 2559cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */ 2560cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis) 2561cee9ab7cSJeroen Hofstee { 2562cee9ab7cSJeroen Hofstee return -1; 2563cee9ab7cSJeroen Hofstee } 2564272cc70bSAndy Fleming 2565e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit) 2566e9550449SChe-Liang Chiou { 2567e9550449SChe-Liang Chiou mmc->preinit = preinit; 2568e9550449SChe-Liang Chiou } 2569e9550449SChe-Liang Chiou 2570c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD) 25718e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 25728e3332e2SSjoerd Simons { 25738e3332e2SSjoerd Simons return 0; 25748e3332e2SSjoerd Simons } 2575c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC) 25768e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 25778e3332e2SSjoerd Simons { 25784a1db6d8SSimon Glass int ret, i; 25798e3332e2SSjoerd Simons struct uclass *uc; 25804a1db6d8SSimon Glass struct udevice *dev; 25818e3332e2SSjoerd Simons 25828e3332e2SSjoerd Simons ret = uclass_get(UCLASS_MMC, &uc); 25838e3332e2SSjoerd Simons if (ret) 25848e3332e2SSjoerd Simons return ret; 25858e3332e2SSjoerd Simons 25864a1db6d8SSimon Glass /* 25874a1db6d8SSimon Glass * Try to add them in sequence order. Really with driver model we 25884a1db6d8SSimon Glass * should allow holes, but the current MMC list does not allow that. 25894a1db6d8SSimon Glass * So if we request 0, 1, 3 we will get 0, 1, 2. 25904a1db6d8SSimon Glass */ 25914a1db6d8SSimon Glass for (i = 0; ; i++) { 25924a1db6d8SSimon Glass ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev); 25934a1db6d8SSimon Glass if (ret == -ENODEV) 25944a1db6d8SSimon Glass break; 25954a1db6d8SSimon Glass } 25964a1db6d8SSimon Glass uclass_foreach_dev(dev, uc) { 25974a1db6d8SSimon Glass ret = device_probe(dev); 25988e3332e2SSjoerd Simons if (ret) 25994a1db6d8SSimon Glass printf("%s - probe failed: %d\n", dev->name, ret); 26008e3332e2SSjoerd Simons } 26018e3332e2SSjoerd Simons 26028e3332e2SSjoerd Simons return 0; 26038e3332e2SSjoerd Simons } 26048e3332e2SSjoerd Simons #else 26058e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 26068e3332e2SSjoerd Simons { 26078e3332e2SSjoerd Simons if (board_mmc_init(bis) < 0) 26088e3332e2SSjoerd Simons cpu_mmc_init(bis); 26098e3332e2SSjoerd Simons 26108e3332e2SSjoerd Simons return 0; 26118e3332e2SSjoerd Simons } 26128e3332e2SSjoerd Simons #endif 2613e9550449SChe-Liang Chiou 2614272cc70bSAndy Fleming int mmc_initialize(bd_t *bis) 2615272cc70bSAndy Fleming { 26161b26bab1SDaniel Kochmański static int initialized = 0; 26178e3332e2SSjoerd Simons int ret; 26181b26bab1SDaniel Kochmański if (initialized) /* Avoid initializing mmc multiple times */ 26191b26bab1SDaniel Kochmański return 0; 26201b26bab1SDaniel Kochmański initialized = 1; 26211b26bab1SDaniel Kochmański 2622c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK) 2623b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY) 2624c40fdca6SSimon Glass mmc_list_init(); 2625c40fdca6SSimon Glass #endif 2626b5b838f1SMarek Vasut #endif 26278e3332e2SSjoerd Simons ret = mmc_probe(bis); 26288e3332e2SSjoerd Simons if (ret) 26298e3332e2SSjoerd Simons return ret; 2630272cc70bSAndy Fleming 2631bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD 2632272cc70bSAndy Fleming print_mmc_devices(','); 2633bb0dc108SYing Zhang #endif 2634272cc70bSAndy Fleming 2635c40fdca6SSimon Glass mmc_do_preinit(); 2636272cc70bSAndy Fleming return 0; 2637272cc70bSAndy Fleming } 2638cd3d4880STomas Melin 2639cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE 2640cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc) 2641cd3d4880STomas Melin { 2642cd3d4880STomas Melin int err; 2643cd3d4880STomas Melin ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 2644cd3d4880STomas Melin 2645cd3d4880STomas Melin err = mmc_send_ext_csd(mmc, ext_csd); 2646cd3d4880STomas Melin if (err) { 2647cd3d4880STomas Melin puts("Could not get ext_csd register values\n"); 2648cd3d4880STomas Melin return err; 2649cd3d4880STomas Melin } 2650cd3d4880STomas Melin 2651cd3d4880STomas Melin if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) { 2652cd3d4880STomas Melin puts("Background operations not supported on device\n"); 2653cd3d4880STomas Melin return -EMEDIUMTYPE; 2654cd3d4880STomas Melin } 2655cd3d4880STomas Melin 2656cd3d4880STomas Melin if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) { 2657cd3d4880STomas Melin puts("Background operations already enabled\n"); 2658cd3d4880STomas Melin return 0; 2659cd3d4880STomas Melin } 2660cd3d4880STomas Melin 2661cd3d4880STomas Melin err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1); 2662cd3d4880STomas Melin if (err) { 2663cd3d4880STomas Melin puts("Failed to enable manual background operations\n"); 2664cd3d4880STomas Melin return err; 2665cd3d4880STomas Melin } 2666cd3d4880STomas Melin 2667cd3d4880STomas Melin puts("Enabled manual background operations\n"); 2668cd3d4880STomas Melin 2669cd3d4880STomas Melin return 0; 2670cd3d4880STomas Melin } 2671cd3d4880STomas Melin #endif 2672