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 * 7272cc70bSAndy Fleming * See file CREDITS for list of people who contributed to this 8272cc70bSAndy Fleming * project. 9272cc70bSAndy Fleming * 10272cc70bSAndy Fleming * This program is free software; you can redistribute it and/or 11272cc70bSAndy Fleming * modify it under the terms of the GNU General Public License as 12272cc70bSAndy Fleming * published by the Free Software Foundation; either version 2 of 13272cc70bSAndy Fleming * the License, or (at your option) any later version. 14272cc70bSAndy Fleming * 15272cc70bSAndy Fleming * This program is distributed in the hope that it will be useful, 16272cc70bSAndy Fleming * but WITHOUT ANY WARRANTY; without even the implied warranty of 17272cc70bSAndy Fleming * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18272cc70bSAndy Fleming * GNU General Public License for more details. 19272cc70bSAndy Fleming * 20272cc70bSAndy Fleming * You should have received a copy of the GNU General Public License 21272cc70bSAndy Fleming * along with this program; if not, write to the Free Software 22272cc70bSAndy Fleming * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 23272cc70bSAndy Fleming * MA 02111-1307 USA 24272cc70bSAndy Fleming */ 25272cc70bSAndy Fleming 26272cc70bSAndy Fleming #include <config.h> 27272cc70bSAndy Fleming #include <common.h> 28272cc70bSAndy Fleming #include <command.h> 29272cc70bSAndy Fleming #include <mmc.h> 30272cc70bSAndy Fleming #include <part.h> 31272cc70bSAndy Fleming #include <malloc.h> 32272cc70bSAndy Fleming #include <linux/list.h> 339b1f942cSRabin Vincent #include <div64.h> 34272cc70bSAndy Fleming 35ce0fbcd2SMatt Waddel /* Set block count limit because of 16 bit register limit on some hardware*/ 36ce0fbcd2SMatt Waddel #ifndef CONFIG_SYS_MMC_MAX_BLK_COUNT 37ce0fbcd2SMatt Waddel #define CONFIG_SYS_MMC_MAX_BLK_COUNT 65535 38ce0fbcd2SMatt Waddel #endif 39ce0fbcd2SMatt Waddel 40272cc70bSAndy Fleming static struct list_head mmc_devices; 41272cc70bSAndy Fleming static int cur_dev_num = -1; 42272cc70bSAndy Fleming 43314284b1SThierry Reding int __board_mmc_getcd(struct mmc *mmc) { 4411fdade2SStefano Babic return -1; 4511fdade2SStefano Babic } 4611fdade2SStefano Babic 47314284b1SThierry Reding int board_mmc_getcd(struct mmc *mmc)__attribute__((weak, 4811fdade2SStefano Babic alias("__board_mmc_getcd"))); 4911fdade2SStefano Babic 508635ff9eSMarek Vasut #ifdef CONFIG_MMC_BOUNCE_BUFFER 518635ff9eSMarek Vasut static int mmc_bounce_need_bounce(struct mmc_data *orig) 528635ff9eSMarek Vasut { 538635ff9eSMarek Vasut ulong addr, len; 548635ff9eSMarek Vasut 558635ff9eSMarek Vasut if (orig->flags & MMC_DATA_READ) 568635ff9eSMarek Vasut addr = (ulong)orig->dest; 578635ff9eSMarek Vasut else 588635ff9eSMarek Vasut addr = (ulong)orig->src; 598635ff9eSMarek Vasut 608635ff9eSMarek Vasut if (addr % ARCH_DMA_MINALIGN) { 618635ff9eSMarek Vasut debug("MMC: Unaligned data destination address %08lx!\n", addr); 628635ff9eSMarek Vasut return 1; 638635ff9eSMarek Vasut } 648635ff9eSMarek Vasut 658635ff9eSMarek Vasut len = (ulong)(orig->blocksize * orig->blocks); 668635ff9eSMarek Vasut if (len % ARCH_DMA_MINALIGN) { 678635ff9eSMarek Vasut debug("MMC: Unaligned data destination length %08lx!\n", len); 688635ff9eSMarek Vasut return 1; 698635ff9eSMarek Vasut } 708635ff9eSMarek Vasut 718635ff9eSMarek Vasut return 0; 728635ff9eSMarek Vasut } 738635ff9eSMarek Vasut 748635ff9eSMarek Vasut static int mmc_bounce_buffer_start(struct mmc_data *backup, 758635ff9eSMarek Vasut struct mmc_data *orig) 768635ff9eSMarek Vasut { 778635ff9eSMarek Vasut ulong origlen, len; 788635ff9eSMarek Vasut void *buffer; 798635ff9eSMarek Vasut 808635ff9eSMarek Vasut if (!orig) 818635ff9eSMarek Vasut return 0; 828635ff9eSMarek Vasut 838635ff9eSMarek Vasut if (!mmc_bounce_need_bounce(orig)) 848635ff9eSMarek Vasut return 0; 858635ff9eSMarek Vasut 868635ff9eSMarek Vasut memcpy(backup, orig, sizeof(struct mmc_data)); 878635ff9eSMarek Vasut 888635ff9eSMarek Vasut origlen = orig->blocksize * orig->blocks; 898635ff9eSMarek Vasut len = roundup(origlen, ARCH_DMA_MINALIGN); 908635ff9eSMarek Vasut buffer = memalign(ARCH_DMA_MINALIGN, len); 918635ff9eSMarek Vasut if (!buffer) { 928635ff9eSMarek Vasut puts("MMC: Error allocating MMC bounce buffer!\n"); 938635ff9eSMarek Vasut return 1; 948635ff9eSMarek Vasut } 958635ff9eSMarek Vasut 968635ff9eSMarek Vasut if (orig->flags & MMC_DATA_READ) { 978635ff9eSMarek Vasut orig->dest = buffer; 988635ff9eSMarek Vasut } else { 998635ff9eSMarek Vasut memcpy(buffer, orig->src, origlen); 1008635ff9eSMarek Vasut orig->src = buffer; 1018635ff9eSMarek Vasut } 1028635ff9eSMarek Vasut 1038635ff9eSMarek Vasut return 0; 1048635ff9eSMarek Vasut } 1058635ff9eSMarek Vasut 1068635ff9eSMarek Vasut static void mmc_bounce_buffer_stop(struct mmc_data *backup, 1078635ff9eSMarek Vasut struct mmc_data *orig) 1088635ff9eSMarek Vasut { 1098635ff9eSMarek Vasut ulong len; 1108635ff9eSMarek Vasut 1118635ff9eSMarek Vasut if (!orig) 1128635ff9eSMarek Vasut return; 1138635ff9eSMarek Vasut 1148635ff9eSMarek Vasut if (!mmc_bounce_need_bounce(backup)) 1158635ff9eSMarek Vasut return; 1168635ff9eSMarek Vasut 1178635ff9eSMarek Vasut if (backup->flags & MMC_DATA_READ) { 1188635ff9eSMarek Vasut len = backup->blocksize * backup->blocks; 1198635ff9eSMarek Vasut memcpy(backup->dest, orig->dest, len); 1208635ff9eSMarek Vasut free(orig->dest); 1218635ff9eSMarek Vasut orig->dest = backup->dest; 1228635ff9eSMarek Vasut } else { 1238635ff9eSMarek Vasut free((void *)orig->src); 1248635ff9eSMarek Vasut orig->src = backup->src; 1258635ff9eSMarek Vasut } 1268635ff9eSMarek Vasut 1278635ff9eSMarek Vasut return; 1288635ff9eSMarek Vasut 1298635ff9eSMarek Vasut } 1308635ff9eSMarek Vasut #else 1318635ff9eSMarek Vasut static inline int mmc_bounce_buffer_start(struct mmc_data *backup, 132dc3faf09SAnatolij Gustschin struct mmc_data *orig) { return 0; } 1338635ff9eSMarek Vasut static inline void mmc_bounce_buffer_stop(struct mmc_data *backup, 1348635ff9eSMarek Vasut struct mmc_data *orig) { } 1358635ff9eSMarek Vasut #endif 1368635ff9eSMarek Vasut 137272cc70bSAndy Fleming int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) 138272cc70bSAndy Fleming { 1398635ff9eSMarek Vasut struct mmc_data backup; 1405db2fe3aSRaffaele Recalcati int ret; 1418635ff9eSMarek Vasut 1428635ff9eSMarek Vasut memset(&backup, 0, sizeof(backup)); 1438635ff9eSMarek Vasut 1448635ff9eSMarek Vasut ret = mmc_bounce_buffer_start(&backup, data); 1458635ff9eSMarek Vasut if (ret) 1468635ff9eSMarek Vasut return ret; 1478635ff9eSMarek Vasut 1488635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE 1495db2fe3aSRaffaele Recalcati int i; 1505db2fe3aSRaffaele Recalcati u8 *ptr; 1515db2fe3aSRaffaele Recalcati 1525db2fe3aSRaffaele Recalcati printf("CMD_SEND:%d\n", cmd->cmdidx); 1535db2fe3aSRaffaele Recalcati printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg); 1545db2fe3aSRaffaele Recalcati printf("\t\tFLAG\t\t\t %d\n", cmd->flags); 1555db2fe3aSRaffaele Recalcati ret = mmc->send_cmd(mmc, cmd, data); 1565db2fe3aSRaffaele Recalcati switch (cmd->resp_type) { 1575db2fe3aSRaffaele Recalcati case MMC_RSP_NONE: 1585db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_NONE\n"); 1595db2fe3aSRaffaele Recalcati break; 1605db2fe3aSRaffaele Recalcati case MMC_RSP_R1: 1615db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n", 1625db2fe3aSRaffaele Recalcati cmd->response[0]); 1635db2fe3aSRaffaele Recalcati break; 1645db2fe3aSRaffaele Recalcati case MMC_RSP_R1b: 1655db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n", 1665db2fe3aSRaffaele Recalcati cmd->response[0]); 1675db2fe3aSRaffaele Recalcati break; 1685db2fe3aSRaffaele Recalcati case MMC_RSP_R2: 1695db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R2\t\t 0x%08X \n", 1705db2fe3aSRaffaele Recalcati cmd->response[0]); 1715db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1725db2fe3aSRaffaele Recalcati cmd->response[1]); 1735db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1745db2fe3aSRaffaele Recalcati cmd->response[2]); 1755db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1765db2fe3aSRaffaele Recalcati cmd->response[3]); 1775db2fe3aSRaffaele Recalcati printf("\n"); 1785db2fe3aSRaffaele Recalcati printf("\t\t\t\t\tDUMPING DATA\n"); 1795db2fe3aSRaffaele Recalcati for (i = 0; i < 4; i++) { 1805db2fe3aSRaffaele Recalcati int j; 1815db2fe3aSRaffaele Recalcati printf("\t\t\t\t\t%03d - ", i*4); 182146bec79SDirk Behme ptr = (u8 *)&cmd->response[i]; 1835db2fe3aSRaffaele Recalcati ptr += 3; 1845db2fe3aSRaffaele Recalcati for (j = 0; j < 4; j++) 1855db2fe3aSRaffaele Recalcati printf("%02X ", *ptr--); 1865db2fe3aSRaffaele Recalcati printf("\n"); 1875db2fe3aSRaffaele Recalcati } 1885db2fe3aSRaffaele Recalcati break; 1895db2fe3aSRaffaele Recalcati case MMC_RSP_R3: 1905db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n", 1915db2fe3aSRaffaele Recalcati cmd->response[0]); 1925db2fe3aSRaffaele Recalcati break; 1935db2fe3aSRaffaele Recalcati default: 1945db2fe3aSRaffaele Recalcati printf("\t\tERROR MMC rsp not supported\n"); 1955db2fe3aSRaffaele Recalcati break; 1965db2fe3aSRaffaele Recalcati } 1975db2fe3aSRaffaele Recalcati #else 1988635ff9eSMarek Vasut ret = mmc->send_cmd(mmc, cmd, data); 1995db2fe3aSRaffaele Recalcati #endif 2008635ff9eSMarek Vasut mmc_bounce_buffer_stop(&backup, data); 2018635ff9eSMarek Vasut return ret; 202272cc70bSAndy Fleming } 203272cc70bSAndy Fleming 2045d4fc8d9SRaffaele Recalcati int mmc_send_status(struct mmc *mmc, int timeout) 2055d4fc8d9SRaffaele Recalcati { 2065d4fc8d9SRaffaele Recalcati struct mmc_cmd cmd; 207d617c426SJan Kloetzke int err, retries = 5; 2085d4fc8d9SRaffaele Recalcati #ifdef CONFIG_MMC_TRACE 2095d4fc8d9SRaffaele Recalcati int status; 2105d4fc8d9SRaffaele Recalcati #endif 2115d4fc8d9SRaffaele Recalcati 2125d4fc8d9SRaffaele Recalcati cmd.cmdidx = MMC_CMD_SEND_STATUS; 2135d4fc8d9SRaffaele Recalcati cmd.resp_type = MMC_RSP_R1; 214aaf3d41aSMarek Vasut if (!mmc_host_is_spi(mmc)) 215aaf3d41aSMarek Vasut cmd.cmdarg = mmc->rca << 16; 2165d4fc8d9SRaffaele Recalcati cmd.flags = 0; 2175d4fc8d9SRaffaele Recalcati 2185d4fc8d9SRaffaele Recalcati do { 2195d4fc8d9SRaffaele Recalcati err = mmc_send_cmd(mmc, &cmd, NULL); 220d617c426SJan Kloetzke if (!err) { 221d617c426SJan Kloetzke if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) && 222d617c426SJan Kloetzke (cmd.response[0] & MMC_STATUS_CURR_STATE) != 223d617c426SJan Kloetzke MMC_STATE_PRG) 2245d4fc8d9SRaffaele Recalcati break; 225d617c426SJan Kloetzke else if (cmd.response[0] & MMC_STATUS_MASK) { 226d617c426SJan Kloetzke printf("Status Error: 0x%08X\n", 227d617c426SJan Kloetzke cmd.response[0]); 228d617c426SJan Kloetzke return COMM_ERR; 229d617c426SJan Kloetzke } 230d617c426SJan Kloetzke } else if (--retries < 0) 231d617c426SJan Kloetzke return err; 2325d4fc8d9SRaffaele Recalcati 2335d4fc8d9SRaffaele Recalcati udelay(1000); 2345d4fc8d9SRaffaele Recalcati 2355d4fc8d9SRaffaele Recalcati } while (timeout--); 2365d4fc8d9SRaffaele Recalcati 2375db2fe3aSRaffaele Recalcati #ifdef CONFIG_MMC_TRACE 2385db2fe3aSRaffaele Recalcati status = (cmd.response[0] & MMC_STATUS_CURR_STATE) >> 9; 2395db2fe3aSRaffaele Recalcati printf("CURR STATE:%d\n", status); 2405db2fe3aSRaffaele Recalcati #endif 2415d4fc8d9SRaffaele Recalcati if (!timeout) { 2425d4fc8d9SRaffaele Recalcati printf("Timeout waiting card ready\n"); 2435d4fc8d9SRaffaele Recalcati return TIMEOUT; 2445d4fc8d9SRaffaele Recalcati } 2455d4fc8d9SRaffaele Recalcati 2465d4fc8d9SRaffaele Recalcati return 0; 2475d4fc8d9SRaffaele Recalcati } 2485d4fc8d9SRaffaele Recalcati 249272cc70bSAndy Fleming int mmc_set_blocklen(struct mmc *mmc, int len) 250272cc70bSAndy Fleming { 251272cc70bSAndy Fleming struct mmc_cmd cmd; 252272cc70bSAndy Fleming 253272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SET_BLOCKLEN; 254272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 255272cc70bSAndy Fleming cmd.cmdarg = len; 256272cc70bSAndy Fleming cmd.flags = 0; 257272cc70bSAndy Fleming 258272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, NULL); 259272cc70bSAndy Fleming } 260272cc70bSAndy Fleming 261272cc70bSAndy Fleming struct mmc *find_mmc_device(int dev_num) 262272cc70bSAndy Fleming { 263272cc70bSAndy Fleming struct mmc *m; 264272cc70bSAndy Fleming struct list_head *entry; 265272cc70bSAndy Fleming 266272cc70bSAndy Fleming list_for_each(entry, &mmc_devices) { 267272cc70bSAndy Fleming m = list_entry(entry, struct mmc, link); 268272cc70bSAndy Fleming 269272cc70bSAndy Fleming if (m->block_dev.dev == dev_num) 270272cc70bSAndy Fleming return m; 271272cc70bSAndy Fleming } 272272cc70bSAndy Fleming 273272cc70bSAndy Fleming printf("MMC Device %d not found\n", dev_num); 274272cc70bSAndy Fleming 275272cc70bSAndy Fleming return NULL; 276272cc70bSAndy Fleming } 277272cc70bSAndy Fleming 278e6f99a56SLei Wen static ulong mmc_erase_t(struct mmc *mmc, ulong start, lbaint_t blkcnt) 279e6f99a56SLei Wen { 280e6f99a56SLei Wen struct mmc_cmd cmd; 281e6f99a56SLei Wen ulong end; 282e6f99a56SLei Wen int err, start_cmd, end_cmd; 283e6f99a56SLei Wen 284e6f99a56SLei Wen if (mmc->high_capacity) 285e6f99a56SLei Wen end = start + blkcnt - 1; 286e6f99a56SLei Wen else { 287e6f99a56SLei Wen end = (start + blkcnt - 1) * mmc->write_bl_len; 288e6f99a56SLei Wen start *= mmc->write_bl_len; 289e6f99a56SLei Wen } 290e6f99a56SLei Wen 291e6f99a56SLei Wen if (IS_SD(mmc)) { 292e6f99a56SLei Wen start_cmd = SD_CMD_ERASE_WR_BLK_START; 293e6f99a56SLei Wen end_cmd = SD_CMD_ERASE_WR_BLK_END; 294e6f99a56SLei Wen } else { 295e6f99a56SLei Wen start_cmd = MMC_CMD_ERASE_GROUP_START; 296e6f99a56SLei Wen end_cmd = MMC_CMD_ERASE_GROUP_END; 297e6f99a56SLei Wen } 298e6f99a56SLei Wen 299e6f99a56SLei Wen cmd.cmdidx = start_cmd; 300e6f99a56SLei Wen cmd.cmdarg = start; 301e6f99a56SLei Wen cmd.resp_type = MMC_RSP_R1; 302e6f99a56SLei Wen cmd.flags = 0; 303e6f99a56SLei Wen 304e6f99a56SLei Wen err = mmc_send_cmd(mmc, &cmd, NULL); 305e6f99a56SLei Wen if (err) 306e6f99a56SLei Wen goto err_out; 307e6f99a56SLei Wen 308e6f99a56SLei Wen cmd.cmdidx = end_cmd; 309e6f99a56SLei Wen cmd.cmdarg = end; 310e6f99a56SLei Wen 311e6f99a56SLei Wen err = mmc_send_cmd(mmc, &cmd, NULL); 312e6f99a56SLei Wen if (err) 313e6f99a56SLei Wen goto err_out; 314e6f99a56SLei Wen 315e6f99a56SLei Wen cmd.cmdidx = MMC_CMD_ERASE; 316e6f99a56SLei Wen cmd.cmdarg = SECURE_ERASE; 317e6f99a56SLei Wen cmd.resp_type = MMC_RSP_R1b; 318e6f99a56SLei Wen 319e6f99a56SLei Wen err = mmc_send_cmd(mmc, &cmd, NULL); 320e6f99a56SLei Wen if (err) 321e6f99a56SLei Wen goto err_out; 322e6f99a56SLei Wen 323e6f99a56SLei Wen return 0; 324e6f99a56SLei Wen 325e6f99a56SLei Wen err_out: 326e6f99a56SLei Wen puts("mmc erase failed\n"); 327e6f99a56SLei Wen return err; 328e6f99a56SLei Wen } 329e6f99a56SLei Wen 330e6f99a56SLei Wen static unsigned long 331e6f99a56SLei Wen mmc_berase(int dev_num, unsigned long start, lbaint_t blkcnt) 332e6f99a56SLei Wen { 333e6f99a56SLei Wen int err = 0; 334e6f99a56SLei Wen struct mmc *mmc = find_mmc_device(dev_num); 335e6f99a56SLei Wen lbaint_t blk = 0, blk_r = 0; 336*d2d8afaeSJerry Huang int timeout = 1000; 337e6f99a56SLei Wen 338e6f99a56SLei Wen if (!mmc) 339e6f99a56SLei Wen return -1; 340e6f99a56SLei Wen 341e6f99a56SLei Wen if ((start % mmc->erase_grp_size) || (blkcnt % mmc->erase_grp_size)) 342e6f99a56SLei Wen printf("\n\nCaution! Your devices Erase group is 0x%x\n" 343e6f99a56SLei Wen "The erase range would be change to 0x%lx~0x%lx\n\n", 344e6f99a56SLei Wen mmc->erase_grp_size, start & ~(mmc->erase_grp_size - 1), 345e6f99a56SLei Wen ((start + blkcnt + mmc->erase_grp_size) 346e6f99a56SLei Wen & ~(mmc->erase_grp_size - 1)) - 1); 347e6f99a56SLei Wen 348e6f99a56SLei Wen while (blk < blkcnt) { 349e6f99a56SLei Wen blk_r = ((blkcnt - blk) > mmc->erase_grp_size) ? 350e6f99a56SLei Wen mmc->erase_grp_size : (blkcnt - blk); 351e6f99a56SLei Wen err = mmc_erase_t(mmc, start + blk, blk_r); 352e6f99a56SLei Wen if (err) 353e6f99a56SLei Wen break; 354e6f99a56SLei Wen 355e6f99a56SLei Wen blk += blk_r; 356*d2d8afaeSJerry Huang 357*d2d8afaeSJerry Huang /* Waiting for the ready status */ 358*d2d8afaeSJerry Huang if (mmc_send_status(mmc, timeout)) 359*d2d8afaeSJerry Huang return 0; 360e6f99a56SLei Wen } 361e6f99a56SLei Wen 362e6f99a56SLei Wen return blk; 363e6f99a56SLei Wen } 364e6f99a56SLei Wen 365272cc70bSAndy Fleming static ulong 3660158126eSLei Wen mmc_write_blocks(struct mmc *mmc, ulong start, lbaint_t blkcnt, const void*src) 367272cc70bSAndy Fleming { 368272cc70bSAndy Fleming struct mmc_cmd cmd; 369272cc70bSAndy Fleming struct mmc_data data; 3705d4fc8d9SRaffaele Recalcati int timeout = 1000; 371272cc70bSAndy Fleming 372d2bf29e3SLei Wen if ((start + blkcnt) > mmc->block_dev.lba) { 373def412b6SSteve Sakoman printf("MMC: block number 0x%lx exceeds max(0x%lx)\n", 374d2bf29e3SLei Wen start + blkcnt, mmc->block_dev.lba); 375d2bf29e3SLei Wen return 0; 376d2bf29e3SLei Wen } 377272cc70bSAndy Fleming 378272cc70bSAndy Fleming if (blkcnt > 1) 379272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK; 380272cc70bSAndy Fleming else 381272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_WRITE_SINGLE_BLOCK; 382272cc70bSAndy Fleming 383272cc70bSAndy Fleming if (mmc->high_capacity) 384272cc70bSAndy Fleming cmd.cmdarg = start; 385272cc70bSAndy Fleming else 386def412b6SSteve Sakoman cmd.cmdarg = start * mmc->write_bl_len; 387272cc70bSAndy Fleming 388272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 389272cc70bSAndy Fleming cmd.flags = 0; 390272cc70bSAndy Fleming 391272cc70bSAndy Fleming data.src = src; 392272cc70bSAndy Fleming data.blocks = blkcnt; 393def412b6SSteve Sakoman data.blocksize = mmc->write_bl_len; 394272cc70bSAndy Fleming data.flags = MMC_DATA_WRITE; 395272cc70bSAndy Fleming 396def412b6SSteve Sakoman if (mmc_send_cmd(mmc, &cmd, &data)) { 397def412b6SSteve Sakoman printf("mmc write failed\n"); 398def412b6SSteve Sakoman return 0; 399272cc70bSAndy Fleming } 400272cc70bSAndy Fleming 401d52ebf10SThomas Chou /* SPI multiblock writes terminate using a special 402d52ebf10SThomas Chou * token, not a STOP_TRANSMISSION request. 403d52ebf10SThomas Chou */ 404d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc) && blkcnt > 1) { 405272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; 406272cc70bSAndy Fleming cmd.cmdarg = 0; 407272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1b; 408272cc70bSAndy Fleming cmd.flags = 0; 409def412b6SSteve Sakoman if (mmc_send_cmd(mmc, &cmd, NULL)) { 410def412b6SSteve Sakoman printf("mmc fail to send stop cmd\n"); 411def412b6SSteve Sakoman return 0; 412272cc70bSAndy Fleming } 41393ad0d18SJan Kloetzke } 4145d4fc8d9SRaffaele Recalcati 4155d4fc8d9SRaffaele Recalcati /* Waiting for the ready status */ 41693ad0d18SJan Kloetzke if (mmc_send_status(mmc, timeout)) 41793ad0d18SJan Kloetzke return 0; 4180158126eSLei Wen 4190158126eSLei Wen return blkcnt; 4200158126eSLei Wen } 4210158126eSLei Wen 4220158126eSLei Wen static ulong 4230158126eSLei Wen mmc_bwrite(int dev_num, ulong start, lbaint_t blkcnt, const void*src) 4240158126eSLei Wen { 4250158126eSLei Wen lbaint_t cur, blocks_todo = blkcnt; 4260158126eSLei Wen 427def412b6SSteve Sakoman struct mmc *mmc = find_mmc_device(dev_num); 4280158126eSLei Wen if (!mmc) 429def412b6SSteve Sakoman return 0; 4300158126eSLei Wen 431def412b6SSteve Sakoman if (mmc_set_blocklen(mmc, mmc->write_bl_len)) 432def412b6SSteve Sakoman return 0; 4330158126eSLei Wen 4340158126eSLei Wen do { 4358feafcc4SJohn Rigby cur = (blocks_todo > mmc->b_max) ? mmc->b_max : blocks_todo; 4360158126eSLei Wen if(mmc_write_blocks(mmc, start, cur, src) != cur) 437def412b6SSteve Sakoman return 0; 4380158126eSLei Wen blocks_todo -= cur; 4390158126eSLei Wen start += cur; 4400158126eSLei Wen src += cur * mmc->write_bl_len; 4410158126eSLei Wen } while (blocks_todo > 0); 442272cc70bSAndy Fleming 443272cc70bSAndy Fleming return blkcnt; 444272cc70bSAndy Fleming } 445272cc70bSAndy Fleming 4464a1a06bcSAlagu Sankar int mmc_read_blocks(struct mmc *mmc, void *dst, ulong start, lbaint_t blkcnt) 447272cc70bSAndy Fleming { 448272cc70bSAndy Fleming struct mmc_cmd cmd; 449272cc70bSAndy Fleming struct mmc_data data; 450272cc70bSAndy Fleming 4514a1a06bcSAlagu Sankar if (blkcnt > 1) 4524a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; 4534a1a06bcSAlagu Sankar else 454272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK; 455272cc70bSAndy Fleming 456272cc70bSAndy Fleming if (mmc->high_capacity) 4574a1a06bcSAlagu Sankar cmd.cmdarg = start; 458272cc70bSAndy Fleming else 4594a1a06bcSAlagu Sankar cmd.cmdarg = start * mmc->read_bl_len; 460272cc70bSAndy Fleming 461272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 462272cc70bSAndy Fleming cmd.flags = 0; 463272cc70bSAndy Fleming 464272cc70bSAndy Fleming data.dest = dst; 4654a1a06bcSAlagu Sankar data.blocks = blkcnt; 466272cc70bSAndy Fleming data.blocksize = mmc->read_bl_len; 467272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 468272cc70bSAndy Fleming 4694a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, &data)) 4704a1a06bcSAlagu Sankar return 0; 4714a1a06bcSAlagu Sankar 4724a1a06bcSAlagu Sankar if (blkcnt > 1) { 4734a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; 4744a1a06bcSAlagu Sankar cmd.cmdarg = 0; 4754a1a06bcSAlagu Sankar cmd.resp_type = MMC_RSP_R1b; 4764a1a06bcSAlagu Sankar cmd.flags = 0; 4774a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, NULL)) { 4784a1a06bcSAlagu Sankar printf("mmc fail to send stop cmd\n"); 4794a1a06bcSAlagu Sankar return 0; 4804a1a06bcSAlagu Sankar } 481272cc70bSAndy Fleming } 482272cc70bSAndy Fleming 4834a1a06bcSAlagu Sankar return blkcnt; 484272cc70bSAndy Fleming } 485272cc70bSAndy Fleming 486272cc70bSAndy Fleming static ulong mmc_bread(int dev_num, ulong start, lbaint_t blkcnt, void *dst) 487272cc70bSAndy Fleming { 4884a1a06bcSAlagu Sankar lbaint_t cur, blocks_todo = blkcnt; 489272cc70bSAndy Fleming 4904a1a06bcSAlagu Sankar if (blkcnt == 0) 4914a1a06bcSAlagu Sankar return 0; 4924a1a06bcSAlagu Sankar 4934a1a06bcSAlagu Sankar struct mmc *mmc = find_mmc_device(dev_num); 494272cc70bSAndy Fleming if (!mmc) 495272cc70bSAndy Fleming return 0; 496272cc70bSAndy Fleming 497d2bf29e3SLei Wen if ((start + blkcnt) > mmc->block_dev.lba) { 4984a1a06bcSAlagu Sankar printf("MMC: block number 0x%lx exceeds max(0x%lx)\n", 499d2bf29e3SLei Wen start + blkcnt, mmc->block_dev.lba); 500d2bf29e3SLei Wen return 0; 501d2bf29e3SLei Wen } 502272cc70bSAndy Fleming 5034a1a06bcSAlagu Sankar if (mmc_set_blocklen(mmc, mmc->read_bl_len)) 504272cc70bSAndy Fleming return 0; 505272cc70bSAndy Fleming 5064a1a06bcSAlagu Sankar do { 5078feafcc4SJohn Rigby cur = (blocks_todo > mmc->b_max) ? mmc->b_max : blocks_todo; 5084a1a06bcSAlagu Sankar if(mmc_read_blocks(mmc, dst, start, cur) != cur) 5094a1a06bcSAlagu Sankar return 0; 5104a1a06bcSAlagu Sankar blocks_todo -= cur; 5114a1a06bcSAlagu Sankar start += cur; 5124a1a06bcSAlagu Sankar dst += cur * mmc->read_bl_len; 5134a1a06bcSAlagu Sankar } while (blocks_todo > 0); 514272cc70bSAndy Fleming 515272cc70bSAndy Fleming return blkcnt; 516272cc70bSAndy Fleming } 517272cc70bSAndy Fleming 518272cc70bSAndy Fleming int mmc_go_idle(struct mmc* mmc) 519272cc70bSAndy Fleming { 520272cc70bSAndy Fleming struct mmc_cmd cmd; 521272cc70bSAndy Fleming int err; 522272cc70bSAndy Fleming 523272cc70bSAndy Fleming udelay(1000); 524272cc70bSAndy Fleming 525272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_GO_IDLE_STATE; 526272cc70bSAndy Fleming cmd.cmdarg = 0; 527272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_NONE; 528272cc70bSAndy Fleming cmd.flags = 0; 529272cc70bSAndy Fleming 530272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 531272cc70bSAndy Fleming 532272cc70bSAndy Fleming if (err) 533272cc70bSAndy Fleming return err; 534272cc70bSAndy Fleming 535272cc70bSAndy Fleming udelay(2000); 536272cc70bSAndy Fleming 537272cc70bSAndy Fleming return 0; 538272cc70bSAndy Fleming } 539272cc70bSAndy Fleming 540272cc70bSAndy Fleming int 541272cc70bSAndy Fleming sd_send_op_cond(struct mmc *mmc) 542272cc70bSAndy Fleming { 543272cc70bSAndy Fleming int timeout = 1000; 544272cc70bSAndy Fleming int err; 545272cc70bSAndy Fleming struct mmc_cmd cmd; 546272cc70bSAndy Fleming 547272cc70bSAndy Fleming do { 548272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 549272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 550272cc70bSAndy Fleming cmd.cmdarg = 0; 551272cc70bSAndy Fleming cmd.flags = 0; 552272cc70bSAndy Fleming 553272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 554272cc70bSAndy Fleming 555272cc70bSAndy Fleming if (err) 556272cc70bSAndy Fleming return err; 557272cc70bSAndy Fleming 558272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_OP_COND; 559272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R3; 560250de12bSStefano Babic 561250de12bSStefano Babic /* 562250de12bSStefano Babic * Most cards do not answer if some reserved bits 563250de12bSStefano Babic * in the ocr are set. However, Some controller 564250de12bSStefano Babic * can set bit 7 (reserved for low voltages), but 565250de12bSStefano Babic * how to manage low voltages SD card is not yet 566250de12bSStefano Babic * specified. 567250de12bSStefano Babic */ 568d52ebf10SThomas Chou cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 : 569d52ebf10SThomas Chou (mmc->voltages & 0xff8000); 570272cc70bSAndy Fleming 571272cc70bSAndy Fleming if (mmc->version == SD_VERSION_2) 572272cc70bSAndy Fleming cmd.cmdarg |= OCR_HCS; 573272cc70bSAndy Fleming 574272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 575272cc70bSAndy Fleming 576272cc70bSAndy Fleming if (err) 577272cc70bSAndy Fleming return err; 578272cc70bSAndy Fleming 579272cc70bSAndy Fleming udelay(1000); 580272cc70bSAndy Fleming } while ((!(cmd.response[0] & OCR_BUSY)) && timeout--); 581272cc70bSAndy Fleming 582272cc70bSAndy Fleming if (timeout <= 0) 583272cc70bSAndy Fleming return UNUSABLE_ERR; 584272cc70bSAndy Fleming 585272cc70bSAndy Fleming if (mmc->version != SD_VERSION_2) 586272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 587272cc70bSAndy Fleming 588d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 589d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 590d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 591d52ebf10SThomas Chou cmd.cmdarg = 0; 592d52ebf10SThomas Chou cmd.flags = 0; 593d52ebf10SThomas Chou 594d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 595d52ebf10SThomas Chou 596d52ebf10SThomas Chou if (err) 597d52ebf10SThomas Chou return err; 598d52ebf10SThomas Chou } 599d52ebf10SThomas Chou 600998be3ddSRabin Vincent mmc->ocr = cmd.response[0]; 601272cc70bSAndy Fleming 602272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 603272cc70bSAndy Fleming mmc->rca = 0; 604272cc70bSAndy Fleming 605272cc70bSAndy Fleming return 0; 606272cc70bSAndy Fleming } 607272cc70bSAndy Fleming 608272cc70bSAndy Fleming int mmc_send_op_cond(struct mmc *mmc) 609272cc70bSAndy Fleming { 61031cacbabSRaffaele Recalcati int timeout = 10000; 611272cc70bSAndy Fleming struct mmc_cmd cmd; 612272cc70bSAndy Fleming int err; 613272cc70bSAndy Fleming 614272cc70bSAndy Fleming /* Some cards seem to need this */ 615272cc70bSAndy Fleming mmc_go_idle(mmc); 616272cc70bSAndy Fleming 61731cacbabSRaffaele Recalcati /* Asking to the card its capabilities */ 61831cacbabSRaffaele Recalcati cmd.cmdidx = MMC_CMD_SEND_OP_COND; 61931cacbabSRaffaele Recalcati cmd.resp_type = MMC_RSP_R3; 62031cacbabSRaffaele Recalcati cmd.cmdarg = 0; 62131cacbabSRaffaele Recalcati cmd.flags = 0; 62231cacbabSRaffaele Recalcati 62331cacbabSRaffaele Recalcati err = mmc_send_cmd(mmc, &cmd, NULL); 62431cacbabSRaffaele Recalcati 62531cacbabSRaffaele Recalcati if (err) 62631cacbabSRaffaele Recalcati return err; 62731cacbabSRaffaele Recalcati 62831cacbabSRaffaele Recalcati udelay(1000); 62931cacbabSRaffaele Recalcati 630272cc70bSAndy Fleming do { 631272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_OP_COND; 632272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R3; 63331cacbabSRaffaele Recalcati cmd.cmdarg = (mmc_host_is_spi(mmc) ? 0 : 63431cacbabSRaffaele Recalcati (mmc->voltages & 63531cacbabSRaffaele Recalcati (cmd.response[0] & OCR_VOLTAGE_MASK)) | 63631cacbabSRaffaele Recalcati (cmd.response[0] & OCR_ACCESS_MODE)); 637b1f1e821SŁukasz Majewski 638b1f1e821SŁukasz Majewski if (mmc->host_caps & MMC_MODE_HC) 639b1f1e821SŁukasz Majewski cmd.cmdarg |= OCR_HCS; 640b1f1e821SŁukasz Majewski 641272cc70bSAndy Fleming cmd.flags = 0; 642272cc70bSAndy Fleming 643272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 644272cc70bSAndy Fleming 645272cc70bSAndy Fleming if (err) 646272cc70bSAndy Fleming return err; 647272cc70bSAndy Fleming 648272cc70bSAndy Fleming udelay(1000); 649272cc70bSAndy Fleming } while (!(cmd.response[0] & OCR_BUSY) && timeout--); 650272cc70bSAndy Fleming 651272cc70bSAndy Fleming if (timeout <= 0) 652272cc70bSAndy Fleming return UNUSABLE_ERR; 653272cc70bSAndy Fleming 654d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 655d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 656d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 657d52ebf10SThomas Chou cmd.cmdarg = 0; 658d52ebf10SThomas Chou cmd.flags = 0; 659d52ebf10SThomas Chou 660d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 661d52ebf10SThomas Chou 662d52ebf10SThomas Chou if (err) 663d52ebf10SThomas Chou return err; 664d52ebf10SThomas Chou } 665d52ebf10SThomas Chou 666272cc70bSAndy Fleming mmc->version = MMC_VERSION_UNKNOWN; 667998be3ddSRabin Vincent mmc->ocr = cmd.response[0]; 668272cc70bSAndy Fleming 669272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 670272cc70bSAndy Fleming mmc->rca = 0; 671272cc70bSAndy Fleming 672272cc70bSAndy Fleming return 0; 673272cc70bSAndy Fleming } 674272cc70bSAndy Fleming 675272cc70bSAndy Fleming 676272cc70bSAndy Fleming int mmc_send_ext_csd(struct mmc *mmc, char *ext_csd) 677272cc70bSAndy Fleming { 678272cc70bSAndy Fleming struct mmc_cmd cmd; 679272cc70bSAndy Fleming struct mmc_data data; 680272cc70bSAndy Fleming int err; 681272cc70bSAndy Fleming 682272cc70bSAndy Fleming /* Get the Card Status Register */ 683272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_EXT_CSD; 684272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 685272cc70bSAndy Fleming cmd.cmdarg = 0; 686272cc70bSAndy Fleming cmd.flags = 0; 687272cc70bSAndy Fleming 688272cc70bSAndy Fleming data.dest = ext_csd; 689272cc70bSAndy Fleming data.blocks = 1; 690272cc70bSAndy Fleming data.blocksize = 512; 691272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 692272cc70bSAndy Fleming 693272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 694272cc70bSAndy Fleming 695272cc70bSAndy Fleming return err; 696272cc70bSAndy Fleming } 697272cc70bSAndy Fleming 698272cc70bSAndy Fleming 699272cc70bSAndy Fleming int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) 700272cc70bSAndy Fleming { 701272cc70bSAndy Fleming struct mmc_cmd cmd; 7025d4fc8d9SRaffaele Recalcati int timeout = 1000; 7035d4fc8d9SRaffaele Recalcati int ret; 704272cc70bSAndy Fleming 705272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SWITCH; 706272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1b; 707272cc70bSAndy Fleming cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | 708272cc70bSAndy Fleming (index << 16) | 709272cc70bSAndy Fleming (value << 8); 710272cc70bSAndy Fleming cmd.flags = 0; 711272cc70bSAndy Fleming 7125d4fc8d9SRaffaele Recalcati ret = mmc_send_cmd(mmc, &cmd, NULL); 7135d4fc8d9SRaffaele Recalcati 7145d4fc8d9SRaffaele Recalcati /* Waiting for the ready status */ 71593ad0d18SJan Kloetzke if (!ret) 71693ad0d18SJan Kloetzke ret = mmc_send_status(mmc, timeout); 7175d4fc8d9SRaffaele Recalcati 7185d4fc8d9SRaffaele Recalcati return ret; 7195d4fc8d9SRaffaele Recalcati 720272cc70bSAndy Fleming } 721272cc70bSAndy Fleming 722272cc70bSAndy Fleming int mmc_change_freq(struct mmc *mmc) 723272cc70bSAndy Fleming { 724a1969923SAnton staaf ALLOC_CACHE_ALIGN_BUFFER(char, ext_csd, 512); 725272cc70bSAndy Fleming char cardtype; 726272cc70bSAndy Fleming int err; 727272cc70bSAndy Fleming 728272cc70bSAndy Fleming mmc->card_caps = 0; 729272cc70bSAndy Fleming 730d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 731d52ebf10SThomas Chou return 0; 732d52ebf10SThomas Chou 733272cc70bSAndy Fleming /* Only version 4 supports high-speed */ 734272cc70bSAndy Fleming if (mmc->version < MMC_VERSION_4) 735272cc70bSAndy Fleming return 0; 736272cc70bSAndy Fleming 737272cc70bSAndy Fleming err = mmc_send_ext_csd(mmc, ext_csd); 738272cc70bSAndy Fleming 739272cc70bSAndy Fleming if (err) 740272cc70bSAndy Fleming return err; 741272cc70bSAndy Fleming 7420560db18SLei Wen cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf; 743272cc70bSAndy Fleming 744272cc70bSAndy Fleming err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1); 745272cc70bSAndy Fleming 746272cc70bSAndy Fleming if (err) 747272cc70bSAndy Fleming return err; 748272cc70bSAndy Fleming 749272cc70bSAndy Fleming /* Now check to see that it worked */ 750272cc70bSAndy Fleming err = mmc_send_ext_csd(mmc, ext_csd); 751272cc70bSAndy Fleming 752272cc70bSAndy Fleming if (err) 753272cc70bSAndy Fleming return err; 754272cc70bSAndy Fleming 755272cc70bSAndy Fleming /* No high-speed support */ 7560560db18SLei Wen if (!ext_csd[EXT_CSD_HS_TIMING]) 757272cc70bSAndy Fleming return 0; 758272cc70bSAndy Fleming 759272cc70bSAndy Fleming /* High Speed is set, there are two types: 52MHz and 26MHz */ 760272cc70bSAndy Fleming if (cardtype & MMC_HS_52MHZ) 761272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; 762272cc70bSAndy Fleming else 763272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS; 764272cc70bSAndy Fleming 765272cc70bSAndy Fleming return 0; 766272cc70bSAndy Fleming } 767272cc70bSAndy Fleming 768bc897b1dSLei Wen int mmc_switch_part(int dev_num, unsigned int part_num) 769bc897b1dSLei Wen { 770bc897b1dSLei Wen struct mmc *mmc = find_mmc_device(dev_num); 771bc897b1dSLei Wen 772bc897b1dSLei Wen if (!mmc) 773bc897b1dSLei Wen return -1; 774bc897b1dSLei Wen 775bc897b1dSLei Wen return mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, 776bc897b1dSLei Wen (mmc->part_config & ~PART_ACCESS_MASK) 777bc897b1dSLei Wen | (part_num & PART_ACCESS_MASK)); 778bc897b1dSLei Wen } 779bc897b1dSLei Wen 78048972d90SThierry Reding int mmc_getcd(struct mmc *mmc) 78148972d90SThierry Reding { 78248972d90SThierry Reding int cd; 78348972d90SThierry Reding 78448972d90SThierry Reding cd = board_mmc_getcd(mmc); 78548972d90SThierry Reding 78648972d90SThierry Reding if ((cd < 0) && mmc->getcd) 78748972d90SThierry Reding cd = mmc->getcd(mmc); 78848972d90SThierry Reding 78948972d90SThierry Reding return cd; 79048972d90SThierry Reding } 79148972d90SThierry Reding 792272cc70bSAndy Fleming int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) 793272cc70bSAndy Fleming { 794272cc70bSAndy Fleming struct mmc_cmd cmd; 795272cc70bSAndy Fleming struct mmc_data data; 796272cc70bSAndy Fleming 797272cc70bSAndy Fleming /* Switch the frequency */ 798272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SWITCH_FUNC; 799272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 800272cc70bSAndy Fleming cmd.cmdarg = (mode << 31) | 0xffffff; 801272cc70bSAndy Fleming cmd.cmdarg &= ~(0xf << (group * 4)); 802272cc70bSAndy Fleming cmd.cmdarg |= value << (group * 4); 803272cc70bSAndy Fleming cmd.flags = 0; 804272cc70bSAndy Fleming 805272cc70bSAndy Fleming data.dest = (char *)resp; 806272cc70bSAndy Fleming data.blocksize = 64; 807272cc70bSAndy Fleming data.blocks = 1; 808272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 809272cc70bSAndy Fleming 810272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, &data); 811272cc70bSAndy Fleming } 812272cc70bSAndy Fleming 813272cc70bSAndy Fleming 814272cc70bSAndy Fleming int sd_change_freq(struct mmc *mmc) 815272cc70bSAndy Fleming { 816272cc70bSAndy Fleming int err; 817272cc70bSAndy Fleming struct mmc_cmd cmd; 818f781dd38SAnton staaf ALLOC_CACHE_ALIGN_BUFFER(uint, scr, 2); 819f781dd38SAnton staaf ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16); 820272cc70bSAndy Fleming struct mmc_data data; 821272cc70bSAndy Fleming int timeout; 822272cc70bSAndy Fleming 823272cc70bSAndy Fleming mmc->card_caps = 0; 824272cc70bSAndy Fleming 825d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 826d52ebf10SThomas Chou return 0; 827d52ebf10SThomas Chou 828272cc70bSAndy Fleming /* Read the SCR to find out if this card supports higher speeds */ 829272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 830272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 831272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 832272cc70bSAndy Fleming cmd.flags = 0; 833272cc70bSAndy Fleming 834272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 835272cc70bSAndy Fleming 836272cc70bSAndy Fleming if (err) 837272cc70bSAndy Fleming return err; 838272cc70bSAndy Fleming 839272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_SCR; 840272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 841272cc70bSAndy Fleming cmd.cmdarg = 0; 842272cc70bSAndy Fleming cmd.flags = 0; 843272cc70bSAndy Fleming 844272cc70bSAndy Fleming timeout = 3; 845272cc70bSAndy Fleming 846272cc70bSAndy Fleming retry_scr: 847f781dd38SAnton staaf data.dest = (char *)scr; 848272cc70bSAndy Fleming data.blocksize = 8; 849272cc70bSAndy Fleming data.blocks = 1; 850272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 851272cc70bSAndy Fleming 852272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 853272cc70bSAndy Fleming 854272cc70bSAndy Fleming if (err) { 855272cc70bSAndy Fleming if (timeout--) 856272cc70bSAndy Fleming goto retry_scr; 857272cc70bSAndy Fleming 858272cc70bSAndy Fleming return err; 859272cc70bSAndy Fleming } 860272cc70bSAndy Fleming 8614e3d89baSYauhen Kharuzhy mmc->scr[0] = __be32_to_cpu(scr[0]); 8624e3d89baSYauhen Kharuzhy mmc->scr[1] = __be32_to_cpu(scr[1]); 863272cc70bSAndy Fleming 864272cc70bSAndy Fleming switch ((mmc->scr[0] >> 24) & 0xf) { 865272cc70bSAndy Fleming case 0: 866272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 867272cc70bSAndy Fleming break; 868272cc70bSAndy Fleming case 1: 869272cc70bSAndy Fleming mmc->version = SD_VERSION_1_10; 870272cc70bSAndy Fleming break; 871272cc70bSAndy Fleming case 2: 872272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 873272cc70bSAndy Fleming break; 874272cc70bSAndy Fleming default: 875272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 876272cc70bSAndy Fleming break; 877272cc70bSAndy Fleming } 878272cc70bSAndy Fleming 879b44c7083SAlagu Sankar if (mmc->scr[0] & SD_DATA_4BIT) 880b44c7083SAlagu Sankar mmc->card_caps |= MMC_MODE_4BIT; 881b44c7083SAlagu Sankar 882272cc70bSAndy Fleming /* Version 1.0 doesn't support switching */ 883272cc70bSAndy Fleming if (mmc->version == SD_VERSION_1_0) 884272cc70bSAndy Fleming return 0; 885272cc70bSAndy Fleming 886272cc70bSAndy Fleming timeout = 4; 887272cc70bSAndy Fleming while (timeout--) { 888272cc70bSAndy Fleming err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1, 889f781dd38SAnton staaf (u8 *)switch_status); 890272cc70bSAndy Fleming 891272cc70bSAndy Fleming if (err) 892272cc70bSAndy Fleming return err; 893272cc70bSAndy Fleming 894272cc70bSAndy Fleming /* The high-speed function is busy. Try again */ 8954e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY)) 896272cc70bSAndy Fleming break; 897272cc70bSAndy Fleming } 898272cc70bSAndy Fleming 899272cc70bSAndy Fleming /* If high-speed isn't supported, we return */ 9004e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)) 901272cc70bSAndy Fleming return 0; 902272cc70bSAndy Fleming 9032c3fbf4cSMacpaul Lin /* 9042c3fbf4cSMacpaul Lin * If the host doesn't support SD_HIGHSPEED, do not switch card to 9052c3fbf4cSMacpaul Lin * HIGHSPEED mode even if the card support SD_HIGHSPPED. 9062c3fbf4cSMacpaul Lin * This can avoid furthur problem when the card runs in different 9072c3fbf4cSMacpaul Lin * mode between the host. 9082c3fbf4cSMacpaul Lin */ 9092c3fbf4cSMacpaul Lin if (!((mmc->host_caps & MMC_MODE_HS_52MHz) && 9102c3fbf4cSMacpaul Lin (mmc->host_caps & MMC_MODE_HS))) 9112c3fbf4cSMacpaul Lin return 0; 9122c3fbf4cSMacpaul Lin 913f781dd38SAnton staaf err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status); 914272cc70bSAndy Fleming 915272cc70bSAndy Fleming if (err) 916272cc70bSAndy Fleming return err; 917272cc70bSAndy Fleming 9184e3d89baSYauhen Kharuzhy if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000) 919272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS; 920272cc70bSAndy Fleming 921272cc70bSAndy Fleming return 0; 922272cc70bSAndy Fleming } 923272cc70bSAndy Fleming 924272cc70bSAndy Fleming /* frequency bases */ 925272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */ 9265f837c2cSMike Frysinger static const int fbase[] = { 927272cc70bSAndy Fleming 10000, 928272cc70bSAndy Fleming 100000, 929272cc70bSAndy Fleming 1000000, 930272cc70bSAndy Fleming 10000000, 931272cc70bSAndy Fleming }; 932272cc70bSAndy Fleming 933272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice 934272cc70bSAndy Fleming * to platforms without floating point. 935272cc70bSAndy Fleming */ 9365f837c2cSMike Frysinger static const int multipliers[] = { 937272cc70bSAndy Fleming 0, /* reserved */ 938272cc70bSAndy Fleming 10, 939272cc70bSAndy Fleming 12, 940272cc70bSAndy Fleming 13, 941272cc70bSAndy Fleming 15, 942272cc70bSAndy Fleming 20, 943272cc70bSAndy Fleming 25, 944272cc70bSAndy Fleming 30, 945272cc70bSAndy Fleming 35, 946272cc70bSAndy Fleming 40, 947272cc70bSAndy Fleming 45, 948272cc70bSAndy Fleming 50, 949272cc70bSAndy Fleming 55, 950272cc70bSAndy Fleming 60, 951272cc70bSAndy Fleming 70, 952272cc70bSAndy Fleming 80, 953272cc70bSAndy Fleming }; 954272cc70bSAndy Fleming 955272cc70bSAndy Fleming void mmc_set_ios(struct mmc *mmc) 956272cc70bSAndy Fleming { 957272cc70bSAndy Fleming mmc->set_ios(mmc); 958272cc70bSAndy Fleming } 959272cc70bSAndy Fleming 960272cc70bSAndy Fleming void mmc_set_clock(struct mmc *mmc, uint clock) 961272cc70bSAndy Fleming { 962272cc70bSAndy Fleming if (clock > mmc->f_max) 963272cc70bSAndy Fleming clock = mmc->f_max; 964272cc70bSAndy Fleming 965272cc70bSAndy Fleming if (clock < mmc->f_min) 966272cc70bSAndy Fleming clock = mmc->f_min; 967272cc70bSAndy Fleming 968272cc70bSAndy Fleming mmc->clock = clock; 969272cc70bSAndy Fleming 970272cc70bSAndy Fleming mmc_set_ios(mmc); 971272cc70bSAndy Fleming } 972272cc70bSAndy Fleming 973272cc70bSAndy Fleming void mmc_set_bus_width(struct mmc *mmc, uint width) 974272cc70bSAndy Fleming { 975272cc70bSAndy Fleming mmc->bus_width = width; 976272cc70bSAndy Fleming 977272cc70bSAndy Fleming mmc_set_ios(mmc); 978272cc70bSAndy Fleming } 979272cc70bSAndy Fleming 980272cc70bSAndy Fleming int mmc_startup(struct mmc *mmc) 981272cc70bSAndy Fleming { 9824137894eSLei Wen int err, width; 983272cc70bSAndy Fleming uint mult, freq; 984639b7827SYoshihiro Shimoda u64 cmult, csize, capacity; 985272cc70bSAndy Fleming struct mmc_cmd cmd; 986a1969923SAnton staaf ALLOC_CACHE_ALIGN_BUFFER(char, ext_csd, 512); 9874137894eSLei Wen ALLOC_CACHE_ALIGN_BUFFER(char, test_csd, 512); 9885d4fc8d9SRaffaele Recalcati int timeout = 1000; 989272cc70bSAndy Fleming 990d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON 991d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */ 992d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF; 993d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R1; 994d52ebf10SThomas Chou cmd.cmdarg = 1; 995d52ebf10SThomas Chou cmd.flags = 0; 996d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 997d52ebf10SThomas Chou 998d52ebf10SThomas Chou if (err) 999d52ebf10SThomas Chou return err; 1000d52ebf10SThomas Chou } 1001d52ebf10SThomas Chou #endif 1002d52ebf10SThomas Chou 1003272cc70bSAndy Fleming /* Put the Card in Identify Mode */ 1004d52ebf10SThomas Chou cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID : 1005d52ebf10SThomas Chou MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */ 1006272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1007272cc70bSAndy Fleming cmd.cmdarg = 0; 1008272cc70bSAndy Fleming cmd.flags = 0; 1009272cc70bSAndy Fleming 1010272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1011272cc70bSAndy Fleming 1012272cc70bSAndy Fleming if (err) 1013272cc70bSAndy Fleming return err; 1014272cc70bSAndy Fleming 1015272cc70bSAndy Fleming memcpy(mmc->cid, cmd.response, 16); 1016272cc70bSAndy Fleming 1017272cc70bSAndy Fleming /* 1018272cc70bSAndy Fleming * For MMC cards, set the Relative Address. 1019272cc70bSAndy Fleming * For SD cards, get the Relatvie Address. 1020272cc70bSAndy Fleming * This also puts the cards into Standby State 1021272cc70bSAndy Fleming */ 1022d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1023272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR; 1024272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1025272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R6; 1026272cc70bSAndy Fleming cmd.flags = 0; 1027272cc70bSAndy Fleming 1028272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1029272cc70bSAndy Fleming 1030272cc70bSAndy Fleming if (err) 1031272cc70bSAndy Fleming return err; 1032272cc70bSAndy Fleming 1033272cc70bSAndy Fleming if (IS_SD(mmc)) 1034998be3ddSRabin Vincent mmc->rca = (cmd.response[0] >> 16) & 0xffff; 1035d52ebf10SThomas Chou } 1036272cc70bSAndy Fleming 1037272cc70bSAndy Fleming /* Get the Card-Specific Data */ 1038272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_CSD; 1039272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1040272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1041272cc70bSAndy Fleming cmd.flags = 0; 1042272cc70bSAndy Fleming 1043272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1044272cc70bSAndy Fleming 10455d4fc8d9SRaffaele Recalcati /* Waiting for the ready status */ 10465d4fc8d9SRaffaele Recalcati mmc_send_status(mmc, timeout); 10475d4fc8d9SRaffaele Recalcati 1048272cc70bSAndy Fleming if (err) 1049272cc70bSAndy Fleming return err; 1050272cc70bSAndy Fleming 1051998be3ddSRabin Vincent mmc->csd[0] = cmd.response[0]; 1052998be3ddSRabin Vincent mmc->csd[1] = cmd.response[1]; 1053998be3ddSRabin Vincent mmc->csd[2] = cmd.response[2]; 1054998be3ddSRabin Vincent mmc->csd[3] = cmd.response[3]; 1055272cc70bSAndy Fleming 1056272cc70bSAndy Fleming if (mmc->version == MMC_VERSION_UNKNOWN) { 10570b453ffeSRabin Vincent int version = (cmd.response[0] >> 26) & 0xf; 1058272cc70bSAndy Fleming 1059272cc70bSAndy Fleming switch (version) { 1060272cc70bSAndy Fleming case 0: 1061272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1062272cc70bSAndy Fleming break; 1063272cc70bSAndy Fleming case 1: 1064272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_4; 1065272cc70bSAndy Fleming break; 1066272cc70bSAndy Fleming case 2: 1067272cc70bSAndy Fleming mmc->version = MMC_VERSION_2_2; 1068272cc70bSAndy Fleming break; 1069272cc70bSAndy Fleming case 3: 1070272cc70bSAndy Fleming mmc->version = MMC_VERSION_3; 1071272cc70bSAndy Fleming break; 1072272cc70bSAndy Fleming case 4: 1073272cc70bSAndy Fleming mmc->version = MMC_VERSION_4; 1074272cc70bSAndy Fleming break; 1075272cc70bSAndy Fleming default: 1076272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1077272cc70bSAndy Fleming break; 1078272cc70bSAndy Fleming } 1079272cc70bSAndy Fleming } 1080272cc70bSAndy Fleming 1081272cc70bSAndy Fleming /* divide frequency by 10, since the mults are 10x bigger */ 10820b453ffeSRabin Vincent freq = fbase[(cmd.response[0] & 0x7)]; 10830b453ffeSRabin Vincent mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; 1084272cc70bSAndy Fleming 1085272cc70bSAndy Fleming mmc->tran_speed = freq * mult; 1086272cc70bSAndy Fleming 1087998be3ddSRabin Vincent mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf); 1088272cc70bSAndy Fleming 1089272cc70bSAndy Fleming if (IS_SD(mmc)) 1090272cc70bSAndy Fleming mmc->write_bl_len = mmc->read_bl_len; 1091272cc70bSAndy Fleming else 1092998be3ddSRabin Vincent mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf); 1093272cc70bSAndy Fleming 1094272cc70bSAndy Fleming if (mmc->high_capacity) { 1095272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3f) << 16 1096272cc70bSAndy Fleming | (mmc->csd[2] & 0xffff0000) >> 16; 1097272cc70bSAndy Fleming cmult = 8; 1098272cc70bSAndy Fleming } else { 1099272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3ff) << 2 1100272cc70bSAndy Fleming | (mmc->csd[2] & 0xc0000000) >> 30; 1101272cc70bSAndy Fleming cmult = (mmc->csd[2] & 0x00038000) >> 15; 1102272cc70bSAndy Fleming } 1103272cc70bSAndy Fleming 1104272cc70bSAndy Fleming mmc->capacity = (csize + 1) << (cmult + 2); 1105272cc70bSAndy Fleming mmc->capacity *= mmc->read_bl_len; 1106272cc70bSAndy Fleming 1107272cc70bSAndy Fleming if (mmc->read_bl_len > 512) 1108272cc70bSAndy Fleming mmc->read_bl_len = 512; 1109272cc70bSAndy Fleming 1110272cc70bSAndy Fleming if (mmc->write_bl_len > 512) 1111272cc70bSAndy Fleming mmc->write_bl_len = 512; 1112272cc70bSAndy Fleming 1113272cc70bSAndy Fleming /* Select the card, and put it into Transfer Mode */ 1114d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1115272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SELECT_CARD; 1116fe8f7066SAjay Bhargav cmd.resp_type = MMC_RSP_R1; 1117272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1118272cc70bSAndy Fleming cmd.flags = 0; 1119272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1120272cc70bSAndy Fleming 1121272cc70bSAndy Fleming if (err) 1122272cc70bSAndy Fleming return err; 1123d52ebf10SThomas Chou } 1124272cc70bSAndy Fleming 1125e6f99a56SLei Wen /* 1126e6f99a56SLei Wen * For SD, its erase group is always one sector 1127e6f99a56SLei Wen */ 1128e6f99a56SLei Wen mmc->erase_grp_size = 1; 1129bc897b1dSLei Wen mmc->part_config = MMCPART_NOAVAILABLE; 1130d23e2c09SSukumar Ghorai if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) { 1131d23e2c09SSukumar Ghorai /* check ext_csd version and capacity */ 1132d23e2c09SSukumar Ghorai err = mmc_send_ext_csd(mmc, ext_csd); 11330560db18SLei Wen if (!err & (ext_csd[EXT_CSD_REV] >= 2)) { 1134639b7827SYoshihiro Shimoda /* 1135639b7827SYoshihiro Shimoda * According to the JEDEC Standard, the value of 1136639b7827SYoshihiro Shimoda * ext_csd's capacity is valid if the value is more 1137639b7827SYoshihiro Shimoda * than 2GB 1138639b7827SYoshihiro Shimoda */ 11390560db18SLei Wen capacity = ext_csd[EXT_CSD_SEC_CNT] << 0 11400560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 11410560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 11420560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; 1143639b7827SYoshihiro Shimoda capacity *= 512; 1144b1f1e821SŁukasz Majewski if ((capacity >> 20) > 2 * 1024) 1145639b7827SYoshihiro Shimoda mmc->capacity = capacity; 1146d23e2c09SSukumar Ghorai } 1147bc897b1dSLei Wen 1148e6f99a56SLei Wen /* 1149e6f99a56SLei Wen * Check whether GROUP_DEF is set, if yes, read out 1150e6f99a56SLei Wen * group size from ext_csd directly, or calculate 1151e6f99a56SLei Wen * the group size from the csd value. 1152e6f99a56SLei Wen */ 11530560db18SLei Wen if (ext_csd[EXT_CSD_ERASE_GROUP_DEF]) 11540560db18SLei Wen mmc->erase_grp_size = 11550560db18SLei Wen ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 512 * 1024; 1156e6f99a56SLei Wen else { 1157e6f99a56SLei Wen int erase_gsz, erase_gmul; 1158e6f99a56SLei Wen erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10; 1159e6f99a56SLei Wen erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5; 1160e6f99a56SLei Wen mmc->erase_grp_size = (erase_gsz + 1) 1161e6f99a56SLei Wen * (erase_gmul + 1); 1162e6f99a56SLei Wen } 1163e6f99a56SLei Wen 1164bc897b1dSLei Wen /* store the partition info of emmc */ 11650560db18SLei Wen if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) 11660560db18SLei Wen mmc->part_config = ext_csd[EXT_CSD_PART_CONF]; 1167d23e2c09SSukumar Ghorai } 1168d23e2c09SSukumar Ghorai 1169272cc70bSAndy Fleming if (IS_SD(mmc)) 1170272cc70bSAndy Fleming err = sd_change_freq(mmc); 1171272cc70bSAndy Fleming else 1172272cc70bSAndy Fleming err = mmc_change_freq(mmc); 1173272cc70bSAndy Fleming 1174272cc70bSAndy Fleming if (err) 1175272cc70bSAndy Fleming return err; 1176272cc70bSAndy Fleming 1177272cc70bSAndy Fleming /* Restrict card's capabilities by what the host can do */ 1178272cc70bSAndy Fleming mmc->card_caps &= mmc->host_caps; 1179272cc70bSAndy Fleming 1180272cc70bSAndy Fleming if (IS_SD(mmc)) { 1181272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_4BIT) { 1182272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 1183272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1184272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1185272cc70bSAndy Fleming cmd.flags = 0; 1186272cc70bSAndy Fleming 1187272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1188272cc70bSAndy Fleming if (err) 1189272cc70bSAndy Fleming return err; 1190272cc70bSAndy Fleming 1191272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH; 1192272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1193272cc70bSAndy Fleming cmd.cmdarg = 2; 1194272cc70bSAndy Fleming cmd.flags = 0; 1195272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1196272cc70bSAndy Fleming if (err) 1197272cc70bSAndy Fleming return err; 1198272cc70bSAndy Fleming 1199272cc70bSAndy Fleming mmc_set_bus_width(mmc, 4); 1200272cc70bSAndy Fleming } 1201272cc70bSAndy Fleming 1202272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_HS) 1203ad5fd922SJaehoon Chung mmc->tran_speed = 50000000; 1204272cc70bSAndy Fleming else 1205ad5fd922SJaehoon Chung mmc->tran_speed = 25000000; 1206272cc70bSAndy Fleming } else { 120762722036SŁukasz Majewski width = ((mmc->host_caps & MMC_MODE_MASK_WIDTH_BITS) >> 120862722036SŁukasz Majewski MMC_MODE_WIDTH_BITS_SHIFT); 120962722036SŁukasz Majewski for (; width >= 0; width--) { 1210272cc70bSAndy Fleming /* Set the card to use 4 bit*/ 1211272cc70bSAndy Fleming err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 12124137894eSLei Wen EXT_CSD_BUS_WIDTH, width); 1213272cc70bSAndy Fleming 1214272cc70bSAndy Fleming if (err) 12154137894eSLei Wen continue; 1216272cc70bSAndy Fleming 12174137894eSLei Wen if (!width) { 12184137894eSLei Wen mmc_set_bus_width(mmc, 1); 12194137894eSLei Wen break; 12204137894eSLei Wen } else 12214137894eSLei Wen mmc_set_bus_width(mmc, 4 * width); 1222272cc70bSAndy Fleming 12234137894eSLei Wen err = mmc_send_ext_csd(mmc, test_csd); 12244137894eSLei Wen if (!err && ext_csd[EXT_CSD_PARTITIONING_SUPPORT] \ 12254137894eSLei Wen == test_csd[EXT_CSD_PARTITIONING_SUPPORT] 12264137894eSLei Wen && ext_csd[EXT_CSD_ERASE_GROUP_DEF] \ 12274137894eSLei Wen == test_csd[EXT_CSD_ERASE_GROUP_DEF] \ 12284137894eSLei Wen && ext_csd[EXT_CSD_REV] \ 12294137894eSLei Wen == test_csd[EXT_CSD_REV] 12304137894eSLei Wen && ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] \ 12314137894eSLei Wen == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 12324137894eSLei Wen && memcmp(&ext_csd[EXT_CSD_SEC_CNT], \ 12334137894eSLei Wen &test_csd[EXT_CSD_SEC_CNT], 4) == 0) { 1234272cc70bSAndy Fleming 12354137894eSLei Wen mmc->card_caps |= width; 12364137894eSLei Wen break; 12374137894eSLei Wen } 1238272cc70bSAndy Fleming } 1239272cc70bSAndy Fleming 1240272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_HS) { 1241272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_HS_52MHz) 1242ad5fd922SJaehoon Chung mmc->tran_speed = 52000000; 1243272cc70bSAndy Fleming else 1244ad5fd922SJaehoon Chung mmc->tran_speed = 26000000; 1245272cc70bSAndy Fleming } 1246ad5fd922SJaehoon Chung } 1247ad5fd922SJaehoon Chung 1248ad5fd922SJaehoon Chung mmc_set_clock(mmc, mmc->tran_speed); 1249272cc70bSAndy Fleming 1250272cc70bSAndy Fleming /* fill in device description */ 1251272cc70bSAndy Fleming mmc->block_dev.lun = 0; 1252272cc70bSAndy Fleming mmc->block_dev.type = 0; 1253272cc70bSAndy Fleming mmc->block_dev.blksz = mmc->read_bl_len; 12549b1f942cSRabin Vincent mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len); 12550b453ffeSRabin Vincent sprintf(mmc->block_dev.vendor, "Man %06x Snr %08x", mmc->cid[0] >> 8, 12560b453ffeSRabin Vincent (mmc->cid[2] << 8) | (mmc->cid[3] >> 24)); 12570b453ffeSRabin Vincent sprintf(mmc->block_dev.product, "%c%c%c%c%c", mmc->cid[0] & 0xff, 12580b453ffeSRabin Vincent (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, 12590b453ffeSRabin Vincent (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff); 12600b453ffeSRabin Vincent sprintf(mmc->block_dev.revision, "%d.%d", mmc->cid[2] >> 28, 12610b453ffeSRabin Vincent (mmc->cid[2] >> 24) & 0xf); 1262272cc70bSAndy Fleming init_part(&mmc->block_dev); 1263272cc70bSAndy Fleming 1264272cc70bSAndy Fleming return 0; 1265272cc70bSAndy Fleming } 1266272cc70bSAndy Fleming 1267272cc70bSAndy Fleming int mmc_send_if_cond(struct mmc *mmc) 1268272cc70bSAndy Fleming { 1269272cc70bSAndy Fleming struct mmc_cmd cmd; 1270272cc70bSAndy Fleming int err; 1271272cc70bSAndy Fleming 1272272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_IF_COND; 1273272cc70bSAndy Fleming /* We set the bit if the host supports voltages between 2.7 and 3.6 V */ 1274272cc70bSAndy Fleming cmd.cmdarg = ((mmc->voltages & 0xff8000) != 0) << 8 | 0xaa; 1275272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R7; 1276272cc70bSAndy Fleming cmd.flags = 0; 1277272cc70bSAndy Fleming 1278272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1279272cc70bSAndy Fleming 1280272cc70bSAndy Fleming if (err) 1281272cc70bSAndy Fleming return err; 1282272cc70bSAndy Fleming 1283998be3ddSRabin Vincent if ((cmd.response[0] & 0xff) != 0xaa) 1284272cc70bSAndy Fleming return UNUSABLE_ERR; 1285272cc70bSAndy Fleming else 1286272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 1287272cc70bSAndy Fleming 1288272cc70bSAndy Fleming return 0; 1289272cc70bSAndy Fleming } 1290272cc70bSAndy Fleming 1291272cc70bSAndy Fleming int mmc_register(struct mmc *mmc) 1292272cc70bSAndy Fleming { 1293272cc70bSAndy Fleming /* Setup the universal parts of the block interface just once */ 1294272cc70bSAndy Fleming mmc->block_dev.if_type = IF_TYPE_MMC; 1295272cc70bSAndy Fleming mmc->block_dev.dev = cur_dev_num++; 1296272cc70bSAndy Fleming mmc->block_dev.removable = 1; 1297272cc70bSAndy Fleming mmc->block_dev.block_read = mmc_bread; 1298272cc70bSAndy Fleming mmc->block_dev.block_write = mmc_bwrite; 1299e6f99a56SLei Wen mmc->block_dev.block_erase = mmc_berase; 13008feafcc4SJohn Rigby if (!mmc->b_max) 13018feafcc4SJohn Rigby mmc->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; 1302272cc70bSAndy Fleming 1303272cc70bSAndy Fleming INIT_LIST_HEAD (&mmc->link); 1304272cc70bSAndy Fleming 1305272cc70bSAndy Fleming list_add_tail (&mmc->link, &mmc_devices); 1306272cc70bSAndy Fleming 1307272cc70bSAndy Fleming return 0; 1308272cc70bSAndy Fleming } 1309272cc70bSAndy Fleming 1310df3fc526SMatthew McClintock #ifdef CONFIG_PARTITIONS 1311272cc70bSAndy Fleming block_dev_desc_t *mmc_get_dev(int dev) 1312272cc70bSAndy Fleming { 1313272cc70bSAndy Fleming struct mmc *mmc = find_mmc_device(dev); 131440242bc3SŁukasz Majewski if (!mmc) 131540242bc3SŁukasz Majewski return NULL; 1316272cc70bSAndy Fleming 131740242bc3SŁukasz Majewski mmc_init(mmc); 131840242bc3SŁukasz Majewski return &mmc->block_dev; 1319272cc70bSAndy Fleming } 1320df3fc526SMatthew McClintock #endif 1321272cc70bSAndy Fleming 1322272cc70bSAndy Fleming int mmc_init(struct mmc *mmc) 1323272cc70bSAndy Fleming { 1324afd5932bSMacpaul Lin int err; 1325272cc70bSAndy Fleming 132648972d90SThierry Reding if (mmc_getcd(mmc) == 0) { 132748972d90SThierry Reding mmc->has_init = 0; 132848972d90SThierry Reding printf("MMC: no card present\n"); 132948972d90SThierry Reding return NO_CARD_ERR; 133048972d90SThierry Reding } 133148972d90SThierry Reding 1332bc897b1dSLei Wen if (mmc->has_init) 1333bc897b1dSLei Wen return 0; 1334bc897b1dSLei Wen 1335272cc70bSAndy Fleming err = mmc->init(mmc); 1336272cc70bSAndy Fleming 1337272cc70bSAndy Fleming if (err) 1338272cc70bSAndy Fleming return err; 1339272cc70bSAndy Fleming 1340b86b85e2SIlya Yanok mmc_set_bus_width(mmc, 1); 1341b86b85e2SIlya Yanok mmc_set_clock(mmc, 1); 1342b86b85e2SIlya Yanok 1343272cc70bSAndy Fleming /* Reset the Card */ 1344272cc70bSAndy Fleming err = mmc_go_idle(mmc); 1345272cc70bSAndy Fleming 1346272cc70bSAndy Fleming if (err) 1347272cc70bSAndy Fleming return err; 1348272cc70bSAndy Fleming 1349bc897b1dSLei Wen /* The internal partition reset to user partition(0) at every CMD0*/ 1350bc897b1dSLei Wen mmc->part_num = 0; 1351bc897b1dSLei Wen 1352272cc70bSAndy Fleming /* Test for SD version 2 */ 1353272cc70bSAndy Fleming err = mmc_send_if_cond(mmc); 1354272cc70bSAndy Fleming 1355272cc70bSAndy Fleming /* Now try to get the SD card's operating condition */ 1356272cc70bSAndy Fleming err = sd_send_op_cond(mmc); 1357272cc70bSAndy Fleming 1358272cc70bSAndy Fleming /* If the command timed out, we check for an MMC card */ 1359272cc70bSAndy Fleming if (err == TIMEOUT) { 1360272cc70bSAndy Fleming err = mmc_send_op_cond(mmc); 1361272cc70bSAndy Fleming 1362272cc70bSAndy Fleming if (err) { 1363272cc70bSAndy Fleming printf("Card did not respond to voltage select!\n"); 1364272cc70bSAndy Fleming return UNUSABLE_ERR; 1365272cc70bSAndy Fleming } 1366272cc70bSAndy Fleming } 1367272cc70bSAndy Fleming 1368bc897b1dSLei Wen err = mmc_startup(mmc); 1369bc897b1dSLei Wen if (err) 1370bc897b1dSLei Wen mmc->has_init = 0; 1371bc897b1dSLei Wen else 1372bc897b1dSLei Wen mmc->has_init = 1; 1373bc897b1dSLei Wen return err; 1374272cc70bSAndy Fleming } 1375272cc70bSAndy Fleming 1376272cc70bSAndy Fleming /* 1377272cc70bSAndy Fleming * CPU and board-specific MMC initializations. Aliased function 1378272cc70bSAndy Fleming * signals caller to move on 1379272cc70bSAndy Fleming */ 1380272cc70bSAndy Fleming static int __def_mmc_init(bd_t *bis) 1381272cc70bSAndy Fleming { 1382272cc70bSAndy Fleming return -1; 1383272cc70bSAndy Fleming } 1384272cc70bSAndy Fleming 1385f9a109b3SPeter Tyser int cpu_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init"))); 1386f9a109b3SPeter Tyser int board_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init"))); 1387272cc70bSAndy Fleming 1388272cc70bSAndy Fleming void print_mmc_devices(char separator) 1389272cc70bSAndy Fleming { 1390272cc70bSAndy Fleming struct mmc *m; 1391272cc70bSAndy Fleming struct list_head *entry; 1392272cc70bSAndy Fleming 1393272cc70bSAndy Fleming list_for_each(entry, &mmc_devices) { 1394272cc70bSAndy Fleming m = list_entry(entry, struct mmc, link); 1395272cc70bSAndy Fleming 1396272cc70bSAndy Fleming printf("%s: %d", m->name, m->block_dev.dev); 1397272cc70bSAndy Fleming 1398272cc70bSAndy Fleming if (entry->next != &mmc_devices) 1399272cc70bSAndy Fleming printf("%c ", separator); 1400272cc70bSAndy Fleming } 1401272cc70bSAndy Fleming 1402272cc70bSAndy Fleming printf("\n"); 1403272cc70bSAndy Fleming } 1404272cc70bSAndy Fleming 1405ea6ebe21SLei Wen int get_mmc_num(void) 1406ea6ebe21SLei Wen { 1407ea6ebe21SLei Wen return cur_dev_num; 1408ea6ebe21SLei Wen } 1409ea6ebe21SLei Wen 1410272cc70bSAndy Fleming int mmc_initialize(bd_t *bis) 1411272cc70bSAndy Fleming { 1412272cc70bSAndy Fleming INIT_LIST_HEAD (&mmc_devices); 1413272cc70bSAndy Fleming cur_dev_num = 0; 1414272cc70bSAndy Fleming 1415272cc70bSAndy Fleming if (board_mmc_init(bis) < 0) 1416272cc70bSAndy Fleming cpu_mmc_init(bis); 1417272cc70bSAndy Fleming 1418272cc70bSAndy Fleming print_mmc_devices(','); 1419272cc70bSAndy Fleming 1420272cc70bSAndy Fleming return 0; 1421272cc70bSAndy Fleming } 1422