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> 33272cc70bSAndy Fleming #include <mmc.h> 349b1f942cSRabin Vincent #include <div64.h> 35272cc70bSAndy Fleming 36ce0fbcd2SMatt Waddel /* Set block count limit because of 16 bit register limit on some hardware*/ 37ce0fbcd2SMatt Waddel #ifndef CONFIG_SYS_MMC_MAX_BLK_COUNT 38ce0fbcd2SMatt Waddel #define CONFIG_SYS_MMC_MAX_BLK_COUNT 65535 39ce0fbcd2SMatt Waddel #endif 40ce0fbcd2SMatt Waddel 41272cc70bSAndy Fleming static struct list_head mmc_devices; 42272cc70bSAndy Fleming static int cur_dev_num = -1; 43272cc70bSAndy Fleming 4411fdade2SStefano Babic int __board_mmc_getcd(u8 *cd, struct mmc *mmc) { 4511fdade2SStefano Babic return -1; 4611fdade2SStefano Babic } 4711fdade2SStefano Babic 4811fdade2SStefano Babic int board_mmc_getcd(u8 *cd, struct mmc *mmc)__attribute__((weak, 4911fdade2SStefano Babic alias("__board_mmc_getcd"))); 5011fdade2SStefano Babic 51272cc70bSAndy Fleming int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) 52272cc70bSAndy Fleming { 53272cc70bSAndy Fleming return mmc->send_cmd(mmc, cmd, data); 54272cc70bSAndy Fleming } 55272cc70bSAndy Fleming 56272cc70bSAndy Fleming int mmc_set_blocklen(struct mmc *mmc, int len) 57272cc70bSAndy Fleming { 58272cc70bSAndy Fleming struct mmc_cmd cmd; 59272cc70bSAndy Fleming 60272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SET_BLOCKLEN; 61272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 62272cc70bSAndy Fleming cmd.cmdarg = len; 63272cc70bSAndy Fleming cmd.flags = 0; 64272cc70bSAndy Fleming 65272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, NULL); 66272cc70bSAndy Fleming } 67272cc70bSAndy Fleming 68272cc70bSAndy Fleming struct mmc *find_mmc_device(int dev_num) 69272cc70bSAndy Fleming { 70272cc70bSAndy Fleming struct mmc *m; 71272cc70bSAndy Fleming struct list_head *entry; 72272cc70bSAndy Fleming 73272cc70bSAndy Fleming list_for_each(entry, &mmc_devices) { 74272cc70bSAndy Fleming m = list_entry(entry, struct mmc, link); 75272cc70bSAndy Fleming 76272cc70bSAndy Fleming if (m->block_dev.dev == dev_num) 77272cc70bSAndy Fleming return m; 78272cc70bSAndy Fleming } 79272cc70bSAndy Fleming 80272cc70bSAndy Fleming printf("MMC Device %d not found\n", dev_num); 81272cc70bSAndy Fleming 82272cc70bSAndy Fleming return NULL; 83272cc70bSAndy Fleming } 84272cc70bSAndy Fleming 85272cc70bSAndy Fleming static ulong 860158126eSLei Wen mmc_write_blocks(struct mmc *mmc, ulong start, lbaint_t blkcnt, const void*src) 87272cc70bSAndy Fleming { 88272cc70bSAndy Fleming struct mmc_cmd cmd; 89272cc70bSAndy Fleming struct mmc_data data; 90272cc70bSAndy Fleming 91d2bf29e3SLei Wen if ((start + blkcnt) > mmc->block_dev.lba) { 92def412b6SSteve Sakoman printf("MMC: block number 0x%lx exceeds max(0x%lx)\n", 93d2bf29e3SLei Wen start + blkcnt, mmc->block_dev.lba); 94d2bf29e3SLei Wen return 0; 95d2bf29e3SLei Wen } 96272cc70bSAndy Fleming 97272cc70bSAndy Fleming if (blkcnt > 1) 98272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK; 99272cc70bSAndy Fleming else 100272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_WRITE_SINGLE_BLOCK; 101272cc70bSAndy Fleming 102272cc70bSAndy Fleming if (mmc->high_capacity) 103272cc70bSAndy Fleming cmd.cmdarg = start; 104272cc70bSAndy Fleming else 105def412b6SSteve Sakoman cmd.cmdarg = start * mmc->write_bl_len; 106272cc70bSAndy Fleming 107272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 108272cc70bSAndy Fleming cmd.flags = 0; 109272cc70bSAndy Fleming 110272cc70bSAndy Fleming data.src = src; 111272cc70bSAndy Fleming data.blocks = blkcnt; 112def412b6SSteve Sakoman data.blocksize = mmc->write_bl_len; 113272cc70bSAndy Fleming data.flags = MMC_DATA_WRITE; 114272cc70bSAndy Fleming 115def412b6SSteve Sakoman if (mmc_send_cmd(mmc, &cmd, &data)) { 116def412b6SSteve Sakoman printf("mmc write failed\n"); 117def412b6SSteve Sakoman return 0; 118272cc70bSAndy Fleming } 119272cc70bSAndy Fleming 120*d52ebf10SThomas Chou /* SPI multiblock writes terminate using a special 121*d52ebf10SThomas Chou * token, not a STOP_TRANSMISSION request. 122*d52ebf10SThomas Chou */ 123*d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc) && blkcnt > 1) { 124272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; 125272cc70bSAndy Fleming cmd.cmdarg = 0; 126272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1b; 127272cc70bSAndy Fleming cmd.flags = 0; 128def412b6SSteve Sakoman if (mmc_send_cmd(mmc, &cmd, NULL)) { 129def412b6SSteve Sakoman printf("mmc fail to send stop cmd\n"); 130def412b6SSteve Sakoman return 0; 131272cc70bSAndy Fleming } 1320158126eSLei Wen } 1330158126eSLei Wen 1340158126eSLei Wen return blkcnt; 1350158126eSLei Wen } 1360158126eSLei Wen 1370158126eSLei Wen static ulong 1380158126eSLei Wen mmc_bwrite(int dev_num, ulong start, lbaint_t blkcnt, const void*src) 1390158126eSLei Wen { 1400158126eSLei Wen lbaint_t cur, blocks_todo = blkcnt; 1410158126eSLei Wen 142def412b6SSteve Sakoman struct mmc *mmc = find_mmc_device(dev_num); 1430158126eSLei Wen if (!mmc) 144def412b6SSteve Sakoman return 0; 1450158126eSLei Wen 146def412b6SSteve Sakoman if (mmc_set_blocklen(mmc, mmc->write_bl_len)) 147def412b6SSteve Sakoman return 0; 1480158126eSLei Wen 1490158126eSLei Wen do { 150ce0fbcd2SMatt Waddel cur = (blocks_todo > CONFIG_SYS_MMC_MAX_BLK_COUNT) ? 151ce0fbcd2SMatt Waddel CONFIG_SYS_MMC_MAX_BLK_COUNT : blocks_todo; 1520158126eSLei Wen if(mmc_write_blocks(mmc, start, cur, src) != cur) 153def412b6SSteve Sakoman return 0; 1540158126eSLei Wen blocks_todo -= cur; 1550158126eSLei Wen start += cur; 1560158126eSLei Wen src += cur * mmc->write_bl_len; 1570158126eSLei Wen } while (blocks_todo > 0); 158272cc70bSAndy Fleming 159272cc70bSAndy Fleming return blkcnt; 160272cc70bSAndy Fleming } 161272cc70bSAndy Fleming 1624a1a06bcSAlagu Sankar int mmc_read_blocks(struct mmc *mmc, void *dst, ulong start, lbaint_t blkcnt) 163272cc70bSAndy Fleming { 164272cc70bSAndy Fleming struct mmc_cmd cmd; 165272cc70bSAndy Fleming struct mmc_data data; 166272cc70bSAndy Fleming 1674a1a06bcSAlagu Sankar if (blkcnt > 1) 1684a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; 1694a1a06bcSAlagu Sankar else 170272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK; 171272cc70bSAndy Fleming 172272cc70bSAndy Fleming if (mmc->high_capacity) 1734a1a06bcSAlagu Sankar cmd.cmdarg = start; 174272cc70bSAndy Fleming else 1754a1a06bcSAlagu Sankar cmd.cmdarg = start * mmc->read_bl_len; 176272cc70bSAndy Fleming 177272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 178272cc70bSAndy Fleming cmd.flags = 0; 179272cc70bSAndy Fleming 180272cc70bSAndy Fleming data.dest = dst; 1814a1a06bcSAlagu Sankar data.blocks = blkcnt; 182272cc70bSAndy Fleming data.blocksize = mmc->read_bl_len; 183272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 184272cc70bSAndy Fleming 1854a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, &data)) 1864a1a06bcSAlagu Sankar return 0; 1874a1a06bcSAlagu Sankar 1884a1a06bcSAlagu Sankar if (blkcnt > 1) { 1894a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; 1904a1a06bcSAlagu Sankar cmd.cmdarg = 0; 1914a1a06bcSAlagu Sankar cmd.resp_type = MMC_RSP_R1b; 1924a1a06bcSAlagu Sankar cmd.flags = 0; 1934a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, NULL)) { 1944a1a06bcSAlagu Sankar printf("mmc fail to send stop cmd\n"); 1954a1a06bcSAlagu Sankar return 0; 1964a1a06bcSAlagu Sankar } 197272cc70bSAndy Fleming } 198272cc70bSAndy Fleming 1994a1a06bcSAlagu Sankar return blkcnt; 200272cc70bSAndy Fleming } 201272cc70bSAndy Fleming 202272cc70bSAndy Fleming static ulong mmc_bread(int dev_num, ulong start, lbaint_t blkcnt, void *dst) 203272cc70bSAndy Fleming { 2044a1a06bcSAlagu Sankar lbaint_t cur, blocks_todo = blkcnt; 205272cc70bSAndy Fleming 2064a1a06bcSAlagu Sankar if (blkcnt == 0) 2074a1a06bcSAlagu Sankar return 0; 2084a1a06bcSAlagu Sankar 2094a1a06bcSAlagu Sankar struct mmc *mmc = find_mmc_device(dev_num); 210272cc70bSAndy Fleming if (!mmc) 211272cc70bSAndy Fleming return 0; 212272cc70bSAndy Fleming 213d2bf29e3SLei Wen if ((start + blkcnt) > mmc->block_dev.lba) { 2144a1a06bcSAlagu Sankar printf("MMC: block number 0x%lx exceeds max(0x%lx)\n", 215d2bf29e3SLei Wen start + blkcnt, mmc->block_dev.lba); 216d2bf29e3SLei Wen return 0; 217d2bf29e3SLei Wen } 218272cc70bSAndy Fleming 2194a1a06bcSAlagu Sankar if (mmc_set_blocklen(mmc, mmc->read_bl_len)) 220272cc70bSAndy Fleming return 0; 221272cc70bSAndy Fleming 2224a1a06bcSAlagu Sankar do { 223ce0fbcd2SMatt Waddel cur = (blocks_todo > CONFIG_SYS_MMC_MAX_BLK_COUNT) ? 224ce0fbcd2SMatt Waddel CONFIG_SYS_MMC_MAX_BLK_COUNT : blocks_todo; 2254a1a06bcSAlagu Sankar if(mmc_read_blocks(mmc, dst, start, cur) != cur) 2264a1a06bcSAlagu Sankar return 0; 2274a1a06bcSAlagu Sankar blocks_todo -= cur; 2284a1a06bcSAlagu Sankar start += cur; 2294a1a06bcSAlagu Sankar dst += cur * mmc->read_bl_len; 2304a1a06bcSAlagu Sankar } while (blocks_todo > 0); 231272cc70bSAndy Fleming 232272cc70bSAndy Fleming return blkcnt; 233272cc70bSAndy Fleming } 234272cc70bSAndy Fleming 235272cc70bSAndy Fleming int mmc_go_idle(struct mmc* mmc) 236272cc70bSAndy Fleming { 237272cc70bSAndy Fleming struct mmc_cmd cmd; 238272cc70bSAndy Fleming int err; 239272cc70bSAndy Fleming 240272cc70bSAndy Fleming udelay(1000); 241272cc70bSAndy Fleming 242272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_GO_IDLE_STATE; 243272cc70bSAndy Fleming cmd.cmdarg = 0; 244272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_NONE; 245272cc70bSAndy Fleming cmd.flags = 0; 246272cc70bSAndy Fleming 247272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 248272cc70bSAndy Fleming 249272cc70bSAndy Fleming if (err) 250272cc70bSAndy Fleming return err; 251272cc70bSAndy Fleming 252272cc70bSAndy Fleming udelay(2000); 253272cc70bSAndy Fleming 254272cc70bSAndy Fleming return 0; 255272cc70bSAndy Fleming } 256272cc70bSAndy Fleming 257272cc70bSAndy Fleming int 258272cc70bSAndy Fleming sd_send_op_cond(struct mmc *mmc) 259272cc70bSAndy Fleming { 260272cc70bSAndy Fleming int timeout = 1000; 261272cc70bSAndy Fleming int err; 262272cc70bSAndy Fleming struct mmc_cmd cmd; 263272cc70bSAndy Fleming 264272cc70bSAndy Fleming do { 265272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 266272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 267272cc70bSAndy Fleming cmd.cmdarg = 0; 268272cc70bSAndy Fleming cmd.flags = 0; 269272cc70bSAndy Fleming 270272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 271272cc70bSAndy Fleming 272272cc70bSAndy Fleming if (err) 273272cc70bSAndy Fleming return err; 274272cc70bSAndy Fleming 275272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_OP_COND; 276272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R3; 277250de12bSStefano Babic 278250de12bSStefano Babic /* 279250de12bSStefano Babic * Most cards do not answer if some reserved bits 280250de12bSStefano Babic * in the ocr are set. However, Some controller 281250de12bSStefano Babic * can set bit 7 (reserved for low voltages), but 282250de12bSStefano Babic * how to manage low voltages SD card is not yet 283250de12bSStefano Babic * specified. 284250de12bSStefano Babic */ 285*d52ebf10SThomas Chou cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 : 286*d52ebf10SThomas Chou (mmc->voltages & 0xff8000); 287272cc70bSAndy Fleming 288272cc70bSAndy Fleming if (mmc->version == SD_VERSION_2) 289272cc70bSAndy Fleming cmd.cmdarg |= OCR_HCS; 290272cc70bSAndy Fleming 291272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 292272cc70bSAndy Fleming 293272cc70bSAndy Fleming if (err) 294272cc70bSAndy Fleming return err; 295272cc70bSAndy Fleming 296272cc70bSAndy Fleming udelay(1000); 297272cc70bSAndy Fleming } while ((!(cmd.response[0] & OCR_BUSY)) && timeout--); 298272cc70bSAndy Fleming 299272cc70bSAndy Fleming if (timeout <= 0) 300272cc70bSAndy Fleming return UNUSABLE_ERR; 301272cc70bSAndy Fleming 302272cc70bSAndy Fleming if (mmc->version != SD_VERSION_2) 303272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 304272cc70bSAndy Fleming 305*d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 306*d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 307*d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 308*d52ebf10SThomas Chou cmd.cmdarg = 0; 309*d52ebf10SThomas Chou cmd.flags = 0; 310*d52ebf10SThomas Chou 311*d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 312*d52ebf10SThomas Chou 313*d52ebf10SThomas Chou if (err) 314*d52ebf10SThomas Chou return err; 315*d52ebf10SThomas Chou } 316*d52ebf10SThomas Chou 317998be3ddSRabin Vincent mmc->ocr = cmd.response[0]; 318272cc70bSAndy Fleming 319272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 320272cc70bSAndy Fleming mmc->rca = 0; 321272cc70bSAndy Fleming 322272cc70bSAndy Fleming return 0; 323272cc70bSAndy Fleming } 324272cc70bSAndy Fleming 325272cc70bSAndy Fleming int mmc_send_op_cond(struct mmc *mmc) 326272cc70bSAndy Fleming { 327272cc70bSAndy Fleming int timeout = 1000; 328272cc70bSAndy Fleming struct mmc_cmd cmd; 329272cc70bSAndy Fleming int err; 330272cc70bSAndy Fleming 331272cc70bSAndy Fleming /* Some cards seem to need this */ 332272cc70bSAndy Fleming mmc_go_idle(mmc); 333272cc70bSAndy Fleming 334272cc70bSAndy Fleming do { 335272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_OP_COND; 336272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R3; 337*d52ebf10SThomas Chou cmd.cmdarg = OCR_HCS | (mmc_host_is_spi(mmc) ? 0 : 338*d52ebf10SThomas Chou mmc->voltages); 339272cc70bSAndy Fleming cmd.flags = 0; 340272cc70bSAndy Fleming 341272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 342272cc70bSAndy Fleming 343272cc70bSAndy Fleming if (err) 344272cc70bSAndy Fleming return err; 345272cc70bSAndy Fleming 346272cc70bSAndy Fleming udelay(1000); 347272cc70bSAndy Fleming } while (!(cmd.response[0] & OCR_BUSY) && timeout--); 348272cc70bSAndy Fleming 349272cc70bSAndy Fleming if (timeout <= 0) 350272cc70bSAndy Fleming return UNUSABLE_ERR; 351272cc70bSAndy Fleming 352*d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 353*d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 354*d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 355*d52ebf10SThomas Chou cmd.cmdarg = 0; 356*d52ebf10SThomas Chou cmd.flags = 0; 357*d52ebf10SThomas Chou 358*d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 359*d52ebf10SThomas Chou 360*d52ebf10SThomas Chou if (err) 361*d52ebf10SThomas Chou return err; 362*d52ebf10SThomas Chou } 363*d52ebf10SThomas Chou 364272cc70bSAndy Fleming mmc->version = MMC_VERSION_UNKNOWN; 365998be3ddSRabin Vincent mmc->ocr = cmd.response[0]; 366272cc70bSAndy Fleming 367272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 368272cc70bSAndy Fleming mmc->rca = 0; 369272cc70bSAndy Fleming 370272cc70bSAndy Fleming return 0; 371272cc70bSAndy Fleming } 372272cc70bSAndy Fleming 373272cc70bSAndy Fleming 374272cc70bSAndy Fleming int mmc_send_ext_csd(struct mmc *mmc, char *ext_csd) 375272cc70bSAndy Fleming { 376272cc70bSAndy Fleming struct mmc_cmd cmd; 377272cc70bSAndy Fleming struct mmc_data data; 378272cc70bSAndy Fleming int err; 379272cc70bSAndy Fleming 380272cc70bSAndy Fleming /* Get the Card Status Register */ 381272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_EXT_CSD; 382272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 383272cc70bSAndy Fleming cmd.cmdarg = 0; 384272cc70bSAndy Fleming cmd.flags = 0; 385272cc70bSAndy Fleming 386272cc70bSAndy Fleming data.dest = ext_csd; 387272cc70bSAndy Fleming data.blocks = 1; 388272cc70bSAndy Fleming data.blocksize = 512; 389272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 390272cc70bSAndy Fleming 391272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 392272cc70bSAndy Fleming 393272cc70bSAndy Fleming return err; 394272cc70bSAndy Fleming } 395272cc70bSAndy Fleming 396272cc70bSAndy Fleming 397272cc70bSAndy Fleming int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) 398272cc70bSAndy Fleming { 399272cc70bSAndy Fleming struct mmc_cmd cmd; 400272cc70bSAndy Fleming 401272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SWITCH; 402272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1b; 403272cc70bSAndy Fleming cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | 404272cc70bSAndy Fleming (index << 16) | 405272cc70bSAndy Fleming (value << 8); 406272cc70bSAndy Fleming cmd.flags = 0; 407272cc70bSAndy Fleming 408272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, NULL); 409272cc70bSAndy Fleming } 410272cc70bSAndy Fleming 411272cc70bSAndy Fleming int mmc_change_freq(struct mmc *mmc) 412272cc70bSAndy Fleming { 413272cc70bSAndy Fleming char ext_csd[512]; 414272cc70bSAndy Fleming char cardtype; 415272cc70bSAndy Fleming int err; 416272cc70bSAndy Fleming 417272cc70bSAndy Fleming mmc->card_caps = 0; 418272cc70bSAndy Fleming 419*d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 420*d52ebf10SThomas Chou return 0; 421*d52ebf10SThomas Chou 422272cc70bSAndy Fleming /* Only version 4 supports high-speed */ 423272cc70bSAndy Fleming if (mmc->version < MMC_VERSION_4) 424272cc70bSAndy Fleming return 0; 425272cc70bSAndy Fleming 426272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_4BIT; 427272cc70bSAndy Fleming 428272cc70bSAndy Fleming err = mmc_send_ext_csd(mmc, ext_csd); 429272cc70bSAndy Fleming 430272cc70bSAndy Fleming if (err) 431272cc70bSAndy Fleming return err; 432272cc70bSAndy Fleming 433272cc70bSAndy Fleming if (ext_csd[212] || ext_csd[213] || ext_csd[214] || ext_csd[215]) 434272cc70bSAndy Fleming mmc->high_capacity = 1; 435272cc70bSAndy Fleming 436272cc70bSAndy Fleming cardtype = ext_csd[196] & 0xf; 437272cc70bSAndy Fleming 438272cc70bSAndy Fleming err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1); 439272cc70bSAndy Fleming 440272cc70bSAndy Fleming if (err) 441272cc70bSAndy Fleming return err; 442272cc70bSAndy Fleming 443272cc70bSAndy Fleming /* Now check to see that it worked */ 444272cc70bSAndy Fleming err = mmc_send_ext_csd(mmc, ext_csd); 445272cc70bSAndy Fleming 446272cc70bSAndy Fleming if (err) 447272cc70bSAndy Fleming return err; 448272cc70bSAndy Fleming 449272cc70bSAndy Fleming /* No high-speed support */ 450272cc70bSAndy Fleming if (!ext_csd[185]) 451272cc70bSAndy Fleming return 0; 452272cc70bSAndy Fleming 453272cc70bSAndy Fleming /* High Speed is set, there are two types: 52MHz and 26MHz */ 454272cc70bSAndy Fleming if (cardtype & MMC_HS_52MHZ) 455272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; 456272cc70bSAndy Fleming else 457272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS; 458272cc70bSAndy Fleming 459272cc70bSAndy Fleming return 0; 460272cc70bSAndy Fleming } 461272cc70bSAndy Fleming 462272cc70bSAndy Fleming int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) 463272cc70bSAndy Fleming { 464272cc70bSAndy Fleming struct mmc_cmd cmd; 465272cc70bSAndy Fleming struct mmc_data data; 466272cc70bSAndy Fleming 467272cc70bSAndy Fleming /* Switch the frequency */ 468272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SWITCH_FUNC; 469272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 470272cc70bSAndy Fleming cmd.cmdarg = (mode << 31) | 0xffffff; 471272cc70bSAndy Fleming cmd.cmdarg &= ~(0xf << (group * 4)); 472272cc70bSAndy Fleming cmd.cmdarg |= value << (group * 4); 473272cc70bSAndy Fleming cmd.flags = 0; 474272cc70bSAndy Fleming 475272cc70bSAndy Fleming data.dest = (char *)resp; 476272cc70bSAndy Fleming data.blocksize = 64; 477272cc70bSAndy Fleming data.blocks = 1; 478272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 479272cc70bSAndy Fleming 480272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, &data); 481272cc70bSAndy Fleming } 482272cc70bSAndy Fleming 483272cc70bSAndy Fleming 484272cc70bSAndy Fleming int sd_change_freq(struct mmc *mmc) 485272cc70bSAndy Fleming { 486272cc70bSAndy Fleming int err; 487272cc70bSAndy Fleming struct mmc_cmd cmd; 488272cc70bSAndy Fleming uint scr[2]; 489272cc70bSAndy Fleming uint switch_status[16]; 490272cc70bSAndy Fleming struct mmc_data data; 491272cc70bSAndy Fleming int timeout; 492272cc70bSAndy Fleming 493272cc70bSAndy Fleming mmc->card_caps = 0; 494272cc70bSAndy Fleming 495*d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 496*d52ebf10SThomas Chou return 0; 497*d52ebf10SThomas Chou 498272cc70bSAndy Fleming /* Read the SCR to find out if this card supports higher speeds */ 499272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 500272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 501272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 502272cc70bSAndy Fleming cmd.flags = 0; 503272cc70bSAndy Fleming 504272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 505272cc70bSAndy Fleming 506272cc70bSAndy Fleming if (err) 507272cc70bSAndy Fleming return err; 508272cc70bSAndy Fleming 509272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_SCR; 510272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 511272cc70bSAndy Fleming cmd.cmdarg = 0; 512272cc70bSAndy Fleming cmd.flags = 0; 513272cc70bSAndy Fleming 514272cc70bSAndy Fleming timeout = 3; 515272cc70bSAndy Fleming 516272cc70bSAndy Fleming retry_scr: 517272cc70bSAndy Fleming data.dest = (char *)&scr; 518272cc70bSAndy Fleming data.blocksize = 8; 519272cc70bSAndy Fleming data.blocks = 1; 520272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 521272cc70bSAndy Fleming 522272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 523272cc70bSAndy Fleming 524272cc70bSAndy Fleming if (err) { 525272cc70bSAndy Fleming if (timeout--) 526272cc70bSAndy Fleming goto retry_scr; 527272cc70bSAndy Fleming 528272cc70bSAndy Fleming return err; 529272cc70bSAndy Fleming } 530272cc70bSAndy Fleming 5314e3d89baSYauhen Kharuzhy mmc->scr[0] = __be32_to_cpu(scr[0]); 5324e3d89baSYauhen Kharuzhy mmc->scr[1] = __be32_to_cpu(scr[1]); 533272cc70bSAndy Fleming 534272cc70bSAndy Fleming switch ((mmc->scr[0] >> 24) & 0xf) { 535272cc70bSAndy Fleming case 0: 536272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 537272cc70bSAndy Fleming break; 538272cc70bSAndy Fleming case 1: 539272cc70bSAndy Fleming mmc->version = SD_VERSION_1_10; 540272cc70bSAndy Fleming break; 541272cc70bSAndy Fleming case 2: 542272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 543272cc70bSAndy Fleming break; 544272cc70bSAndy Fleming default: 545272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 546272cc70bSAndy Fleming break; 547272cc70bSAndy Fleming } 548272cc70bSAndy Fleming 549b44c7083SAlagu Sankar if (mmc->scr[0] & SD_DATA_4BIT) 550b44c7083SAlagu Sankar mmc->card_caps |= MMC_MODE_4BIT; 551b44c7083SAlagu Sankar 552272cc70bSAndy Fleming /* Version 1.0 doesn't support switching */ 553272cc70bSAndy Fleming if (mmc->version == SD_VERSION_1_0) 554272cc70bSAndy Fleming return 0; 555272cc70bSAndy Fleming 556272cc70bSAndy Fleming timeout = 4; 557272cc70bSAndy Fleming while (timeout--) { 558272cc70bSAndy Fleming err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1, 559272cc70bSAndy Fleming (u8 *)&switch_status); 560272cc70bSAndy Fleming 561272cc70bSAndy Fleming if (err) 562272cc70bSAndy Fleming return err; 563272cc70bSAndy Fleming 564272cc70bSAndy Fleming /* The high-speed function is busy. Try again */ 5654e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY)) 566272cc70bSAndy Fleming break; 567272cc70bSAndy Fleming } 568272cc70bSAndy Fleming 569272cc70bSAndy Fleming /* If high-speed isn't supported, we return */ 5704e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)) 571272cc70bSAndy Fleming return 0; 572272cc70bSAndy Fleming 573272cc70bSAndy Fleming err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)&switch_status); 574272cc70bSAndy Fleming 575272cc70bSAndy Fleming if (err) 576272cc70bSAndy Fleming return err; 577272cc70bSAndy Fleming 5784e3d89baSYauhen Kharuzhy if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000) 579272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS; 580272cc70bSAndy Fleming 581272cc70bSAndy Fleming return 0; 582272cc70bSAndy Fleming } 583272cc70bSAndy Fleming 584272cc70bSAndy Fleming /* frequency bases */ 585272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */ 5865f837c2cSMike Frysinger static const int fbase[] = { 587272cc70bSAndy Fleming 10000, 588272cc70bSAndy Fleming 100000, 589272cc70bSAndy Fleming 1000000, 590272cc70bSAndy Fleming 10000000, 591272cc70bSAndy Fleming }; 592272cc70bSAndy Fleming 593272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice 594272cc70bSAndy Fleming * to platforms without floating point. 595272cc70bSAndy Fleming */ 5965f837c2cSMike Frysinger static const int multipliers[] = { 597272cc70bSAndy Fleming 0, /* reserved */ 598272cc70bSAndy Fleming 10, 599272cc70bSAndy Fleming 12, 600272cc70bSAndy Fleming 13, 601272cc70bSAndy Fleming 15, 602272cc70bSAndy Fleming 20, 603272cc70bSAndy Fleming 25, 604272cc70bSAndy Fleming 30, 605272cc70bSAndy Fleming 35, 606272cc70bSAndy Fleming 40, 607272cc70bSAndy Fleming 45, 608272cc70bSAndy Fleming 50, 609272cc70bSAndy Fleming 55, 610272cc70bSAndy Fleming 60, 611272cc70bSAndy Fleming 70, 612272cc70bSAndy Fleming 80, 613272cc70bSAndy Fleming }; 614272cc70bSAndy Fleming 615272cc70bSAndy Fleming void mmc_set_ios(struct mmc *mmc) 616272cc70bSAndy Fleming { 617272cc70bSAndy Fleming mmc->set_ios(mmc); 618272cc70bSAndy Fleming } 619272cc70bSAndy Fleming 620272cc70bSAndy Fleming void mmc_set_clock(struct mmc *mmc, uint clock) 621272cc70bSAndy Fleming { 622272cc70bSAndy Fleming if (clock > mmc->f_max) 623272cc70bSAndy Fleming clock = mmc->f_max; 624272cc70bSAndy Fleming 625272cc70bSAndy Fleming if (clock < mmc->f_min) 626272cc70bSAndy Fleming clock = mmc->f_min; 627272cc70bSAndy Fleming 628272cc70bSAndy Fleming mmc->clock = clock; 629272cc70bSAndy Fleming 630272cc70bSAndy Fleming mmc_set_ios(mmc); 631272cc70bSAndy Fleming } 632272cc70bSAndy Fleming 633272cc70bSAndy Fleming void mmc_set_bus_width(struct mmc *mmc, uint width) 634272cc70bSAndy Fleming { 635272cc70bSAndy Fleming mmc->bus_width = width; 636272cc70bSAndy Fleming 637272cc70bSAndy Fleming mmc_set_ios(mmc); 638272cc70bSAndy Fleming } 639272cc70bSAndy Fleming 640272cc70bSAndy Fleming int mmc_startup(struct mmc *mmc) 641272cc70bSAndy Fleming { 642272cc70bSAndy Fleming int err; 643272cc70bSAndy Fleming uint mult, freq; 644272cc70bSAndy Fleming u64 cmult, csize; 645272cc70bSAndy Fleming struct mmc_cmd cmd; 646d23e2c09SSukumar Ghorai char ext_csd[512]; 647272cc70bSAndy Fleming 648*d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON 649*d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */ 650*d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF; 651*d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R1; 652*d52ebf10SThomas Chou cmd.cmdarg = 1; 653*d52ebf10SThomas Chou cmd.flags = 0; 654*d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 655*d52ebf10SThomas Chou 656*d52ebf10SThomas Chou if (err) 657*d52ebf10SThomas Chou return err; 658*d52ebf10SThomas Chou } 659*d52ebf10SThomas Chou #endif 660*d52ebf10SThomas Chou 661272cc70bSAndy Fleming /* Put the Card in Identify Mode */ 662*d52ebf10SThomas Chou cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID : 663*d52ebf10SThomas Chou MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */ 664272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 665272cc70bSAndy Fleming cmd.cmdarg = 0; 666272cc70bSAndy Fleming cmd.flags = 0; 667272cc70bSAndy Fleming 668272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 669272cc70bSAndy Fleming 670272cc70bSAndy Fleming if (err) 671272cc70bSAndy Fleming return err; 672272cc70bSAndy Fleming 673272cc70bSAndy Fleming memcpy(mmc->cid, cmd.response, 16); 674272cc70bSAndy Fleming 675272cc70bSAndy Fleming /* 676272cc70bSAndy Fleming * For MMC cards, set the Relative Address. 677272cc70bSAndy Fleming * For SD cards, get the Relatvie Address. 678272cc70bSAndy Fleming * This also puts the cards into Standby State 679272cc70bSAndy Fleming */ 680*d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 681272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR; 682272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 683272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R6; 684272cc70bSAndy Fleming cmd.flags = 0; 685272cc70bSAndy Fleming 686272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 687272cc70bSAndy Fleming 688272cc70bSAndy Fleming if (err) 689272cc70bSAndy Fleming return err; 690272cc70bSAndy Fleming 691272cc70bSAndy Fleming if (IS_SD(mmc)) 692998be3ddSRabin Vincent mmc->rca = (cmd.response[0] >> 16) & 0xffff; 693*d52ebf10SThomas Chou } 694272cc70bSAndy Fleming 695272cc70bSAndy Fleming /* Get the Card-Specific Data */ 696272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_CSD; 697272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 698272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 699272cc70bSAndy Fleming cmd.flags = 0; 700272cc70bSAndy Fleming 701272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 702272cc70bSAndy Fleming 703272cc70bSAndy Fleming if (err) 704272cc70bSAndy Fleming return err; 705272cc70bSAndy Fleming 706998be3ddSRabin Vincent mmc->csd[0] = cmd.response[0]; 707998be3ddSRabin Vincent mmc->csd[1] = cmd.response[1]; 708998be3ddSRabin Vincent mmc->csd[2] = cmd.response[2]; 709998be3ddSRabin Vincent mmc->csd[3] = cmd.response[3]; 710272cc70bSAndy Fleming 711272cc70bSAndy Fleming if (mmc->version == MMC_VERSION_UNKNOWN) { 7120b453ffeSRabin Vincent int version = (cmd.response[0] >> 26) & 0xf; 713272cc70bSAndy Fleming 714272cc70bSAndy Fleming switch (version) { 715272cc70bSAndy Fleming case 0: 716272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 717272cc70bSAndy Fleming break; 718272cc70bSAndy Fleming case 1: 719272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_4; 720272cc70bSAndy Fleming break; 721272cc70bSAndy Fleming case 2: 722272cc70bSAndy Fleming mmc->version = MMC_VERSION_2_2; 723272cc70bSAndy Fleming break; 724272cc70bSAndy Fleming case 3: 725272cc70bSAndy Fleming mmc->version = MMC_VERSION_3; 726272cc70bSAndy Fleming break; 727272cc70bSAndy Fleming case 4: 728272cc70bSAndy Fleming mmc->version = MMC_VERSION_4; 729272cc70bSAndy Fleming break; 730272cc70bSAndy Fleming default: 731272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 732272cc70bSAndy Fleming break; 733272cc70bSAndy Fleming } 734272cc70bSAndy Fleming } 735272cc70bSAndy Fleming 736272cc70bSAndy Fleming /* divide frequency by 10, since the mults are 10x bigger */ 7370b453ffeSRabin Vincent freq = fbase[(cmd.response[0] & 0x7)]; 7380b453ffeSRabin Vincent mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; 739272cc70bSAndy Fleming 740272cc70bSAndy Fleming mmc->tran_speed = freq * mult; 741272cc70bSAndy Fleming 742998be3ddSRabin Vincent mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf); 743272cc70bSAndy Fleming 744272cc70bSAndy Fleming if (IS_SD(mmc)) 745272cc70bSAndy Fleming mmc->write_bl_len = mmc->read_bl_len; 746272cc70bSAndy Fleming else 747998be3ddSRabin Vincent mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf); 748272cc70bSAndy Fleming 749272cc70bSAndy Fleming if (mmc->high_capacity) { 750272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3f) << 16 751272cc70bSAndy Fleming | (mmc->csd[2] & 0xffff0000) >> 16; 752272cc70bSAndy Fleming cmult = 8; 753272cc70bSAndy Fleming } else { 754272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3ff) << 2 755272cc70bSAndy Fleming | (mmc->csd[2] & 0xc0000000) >> 30; 756272cc70bSAndy Fleming cmult = (mmc->csd[2] & 0x00038000) >> 15; 757272cc70bSAndy Fleming } 758272cc70bSAndy Fleming 759272cc70bSAndy Fleming mmc->capacity = (csize + 1) << (cmult + 2); 760272cc70bSAndy Fleming mmc->capacity *= mmc->read_bl_len; 761272cc70bSAndy Fleming 762272cc70bSAndy Fleming if (mmc->read_bl_len > 512) 763272cc70bSAndy Fleming mmc->read_bl_len = 512; 764272cc70bSAndy Fleming 765272cc70bSAndy Fleming if (mmc->write_bl_len > 512) 766272cc70bSAndy Fleming mmc->write_bl_len = 512; 767272cc70bSAndy Fleming 768272cc70bSAndy Fleming /* Select the card, and put it into Transfer Mode */ 769*d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 770272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SELECT_CARD; 771272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1b; 772272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 773272cc70bSAndy Fleming cmd.flags = 0; 774272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 775272cc70bSAndy Fleming 776272cc70bSAndy Fleming if (err) 777272cc70bSAndy Fleming return err; 778*d52ebf10SThomas Chou } 779272cc70bSAndy Fleming 780d23e2c09SSukumar Ghorai if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) { 781d23e2c09SSukumar Ghorai /* check ext_csd version and capacity */ 782d23e2c09SSukumar Ghorai err = mmc_send_ext_csd(mmc, ext_csd); 783d23e2c09SSukumar Ghorai if (!err & (ext_csd[192] >= 2)) { 784d23e2c09SSukumar Ghorai mmc->capacity = ext_csd[212] << 0 | ext_csd[213] << 8 | 785d23e2c09SSukumar Ghorai ext_csd[214] << 16 | ext_csd[215] << 24; 786d23e2c09SSukumar Ghorai mmc->capacity *= 512; 787d23e2c09SSukumar Ghorai } 788d23e2c09SSukumar Ghorai } 789d23e2c09SSukumar Ghorai 790272cc70bSAndy Fleming if (IS_SD(mmc)) 791272cc70bSAndy Fleming err = sd_change_freq(mmc); 792272cc70bSAndy Fleming else 793272cc70bSAndy Fleming err = mmc_change_freq(mmc); 794272cc70bSAndy Fleming 795272cc70bSAndy Fleming if (err) 796272cc70bSAndy Fleming return err; 797272cc70bSAndy Fleming 798272cc70bSAndy Fleming /* Restrict card's capabilities by what the host can do */ 799272cc70bSAndy Fleming mmc->card_caps &= mmc->host_caps; 800272cc70bSAndy Fleming 801272cc70bSAndy Fleming if (IS_SD(mmc)) { 802272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_4BIT) { 803272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 804272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 805272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 806272cc70bSAndy Fleming cmd.flags = 0; 807272cc70bSAndy Fleming 808272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 809272cc70bSAndy Fleming if (err) 810272cc70bSAndy Fleming return err; 811272cc70bSAndy Fleming 812272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH; 813272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 814272cc70bSAndy Fleming cmd.cmdarg = 2; 815272cc70bSAndy Fleming cmd.flags = 0; 816272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 817272cc70bSAndy Fleming if (err) 818272cc70bSAndy Fleming return err; 819272cc70bSAndy Fleming 820272cc70bSAndy Fleming mmc_set_bus_width(mmc, 4); 821272cc70bSAndy Fleming } 822272cc70bSAndy Fleming 823272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_HS) 824272cc70bSAndy Fleming mmc_set_clock(mmc, 50000000); 825272cc70bSAndy Fleming else 826272cc70bSAndy Fleming mmc_set_clock(mmc, 25000000); 827272cc70bSAndy Fleming } else { 828272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_4BIT) { 829272cc70bSAndy Fleming /* Set the card to use 4 bit*/ 830272cc70bSAndy Fleming err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 831272cc70bSAndy Fleming EXT_CSD_BUS_WIDTH, 832272cc70bSAndy Fleming EXT_CSD_BUS_WIDTH_4); 833272cc70bSAndy Fleming 834272cc70bSAndy Fleming if (err) 835272cc70bSAndy Fleming return err; 836272cc70bSAndy Fleming 837272cc70bSAndy Fleming mmc_set_bus_width(mmc, 4); 838272cc70bSAndy Fleming } else if (mmc->card_caps & MMC_MODE_8BIT) { 839272cc70bSAndy Fleming /* Set the card to use 8 bit*/ 840272cc70bSAndy Fleming err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 841272cc70bSAndy Fleming EXT_CSD_BUS_WIDTH, 842272cc70bSAndy Fleming EXT_CSD_BUS_WIDTH_8); 843272cc70bSAndy Fleming 844272cc70bSAndy Fleming if (err) 845272cc70bSAndy Fleming return err; 846272cc70bSAndy Fleming 847272cc70bSAndy Fleming mmc_set_bus_width(mmc, 8); 848272cc70bSAndy Fleming } 849272cc70bSAndy Fleming 850272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_HS) { 851272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_HS_52MHz) 852272cc70bSAndy Fleming mmc_set_clock(mmc, 52000000); 853272cc70bSAndy Fleming else 854272cc70bSAndy Fleming mmc_set_clock(mmc, 26000000); 855272cc70bSAndy Fleming } else 856272cc70bSAndy Fleming mmc_set_clock(mmc, 20000000); 857272cc70bSAndy Fleming } 858272cc70bSAndy Fleming 859272cc70bSAndy Fleming /* fill in device description */ 860272cc70bSAndy Fleming mmc->block_dev.lun = 0; 861272cc70bSAndy Fleming mmc->block_dev.type = 0; 862272cc70bSAndy Fleming mmc->block_dev.blksz = mmc->read_bl_len; 8639b1f942cSRabin Vincent mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len); 8640b453ffeSRabin Vincent sprintf(mmc->block_dev.vendor, "Man %06x Snr %08x", mmc->cid[0] >> 8, 8650b453ffeSRabin Vincent (mmc->cid[2] << 8) | (mmc->cid[3] >> 24)); 8660b453ffeSRabin Vincent sprintf(mmc->block_dev.product, "%c%c%c%c%c", mmc->cid[0] & 0xff, 8670b453ffeSRabin Vincent (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, 8680b453ffeSRabin Vincent (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff); 8690b453ffeSRabin Vincent sprintf(mmc->block_dev.revision, "%d.%d", mmc->cid[2] >> 28, 8700b453ffeSRabin Vincent (mmc->cid[2] >> 24) & 0xf); 871272cc70bSAndy Fleming init_part(&mmc->block_dev); 872272cc70bSAndy Fleming 873272cc70bSAndy Fleming return 0; 874272cc70bSAndy Fleming } 875272cc70bSAndy Fleming 876272cc70bSAndy Fleming int mmc_send_if_cond(struct mmc *mmc) 877272cc70bSAndy Fleming { 878272cc70bSAndy Fleming struct mmc_cmd cmd; 879272cc70bSAndy Fleming int err; 880272cc70bSAndy Fleming 881272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_IF_COND; 882272cc70bSAndy Fleming /* We set the bit if the host supports voltages between 2.7 and 3.6 V */ 883272cc70bSAndy Fleming cmd.cmdarg = ((mmc->voltages & 0xff8000) != 0) << 8 | 0xaa; 884272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R7; 885272cc70bSAndy Fleming cmd.flags = 0; 886272cc70bSAndy Fleming 887272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 888272cc70bSAndy Fleming 889272cc70bSAndy Fleming if (err) 890272cc70bSAndy Fleming return err; 891272cc70bSAndy Fleming 892998be3ddSRabin Vincent if ((cmd.response[0] & 0xff) != 0xaa) 893272cc70bSAndy Fleming return UNUSABLE_ERR; 894272cc70bSAndy Fleming else 895272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 896272cc70bSAndy Fleming 897272cc70bSAndy Fleming return 0; 898272cc70bSAndy Fleming } 899272cc70bSAndy Fleming 900272cc70bSAndy Fleming int mmc_register(struct mmc *mmc) 901272cc70bSAndy Fleming { 902272cc70bSAndy Fleming /* Setup the universal parts of the block interface just once */ 903272cc70bSAndy Fleming mmc->block_dev.if_type = IF_TYPE_MMC; 904272cc70bSAndy Fleming mmc->block_dev.dev = cur_dev_num++; 905272cc70bSAndy Fleming mmc->block_dev.removable = 1; 906272cc70bSAndy Fleming mmc->block_dev.block_read = mmc_bread; 907272cc70bSAndy Fleming mmc->block_dev.block_write = mmc_bwrite; 908272cc70bSAndy Fleming 909272cc70bSAndy Fleming INIT_LIST_HEAD (&mmc->link); 910272cc70bSAndy Fleming 911272cc70bSAndy Fleming list_add_tail (&mmc->link, &mmc_devices); 912272cc70bSAndy Fleming 913272cc70bSAndy Fleming return 0; 914272cc70bSAndy Fleming } 915272cc70bSAndy Fleming 916272cc70bSAndy Fleming block_dev_desc_t *mmc_get_dev(int dev) 917272cc70bSAndy Fleming { 918272cc70bSAndy Fleming struct mmc *mmc = find_mmc_device(dev); 919272cc70bSAndy Fleming 920e85649c7SRabin Vincent return mmc ? &mmc->block_dev : NULL; 921272cc70bSAndy Fleming } 922272cc70bSAndy Fleming 923272cc70bSAndy Fleming int mmc_init(struct mmc *mmc) 924272cc70bSAndy Fleming { 925272cc70bSAndy Fleming int err; 926272cc70bSAndy Fleming 927272cc70bSAndy Fleming err = mmc->init(mmc); 928272cc70bSAndy Fleming 929272cc70bSAndy Fleming if (err) 930272cc70bSAndy Fleming return err; 931272cc70bSAndy Fleming 932b86b85e2SIlya Yanok mmc_set_bus_width(mmc, 1); 933b86b85e2SIlya Yanok mmc_set_clock(mmc, 1); 934b86b85e2SIlya Yanok 935272cc70bSAndy Fleming /* Reset the Card */ 936272cc70bSAndy Fleming err = mmc_go_idle(mmc); 937272cc70bSAndy Fleming 938272cc70bSAndy Fleming if (err) 939272cc70bSAndy Fleming return err; 940272cc70bSAndy Fleming 941272cc70bSAndy Fleming /* Test for SD version 2 */ 942272cc70bSAndy Fleming err = mmc_send_if_cond(mmc); 943272cc70bSAndy Fleming 944272cc70bSAndy Fleming /* Now try to get the SD card's operating condition */ 945272cc70bSAndy Fleming err = sd_send_op_cond(mmc); 946272cc70bSAndy Fleming 947272cc70bSAndy Fleming /* If the command timed out, we check for an MMC card */ 948272cc70bSAndy Fleming if (err == TIMEOUT) { 949272cc70bSAndy Fleming err = mmc_send_op_cond(mmc); 950272cc70bSAndy Fleming 951272cc70bSAndy Fleming if (err) { 952272cc70bSAndy Fleming printf("Card did not respond to voltage select!\n"); 953272cc70bSAndy Fleming return UNUSABLE_ERR; 954272cc70bSAndy Fleming } 955272cc70bSAndy Fleming } 956272cc70bSAndy Fleming 957272cc70bSAndy Fleming return mmc_startup(mmc); 958272cc70bSAndy Fleming } 959272cc70bSAndy Fleming 960272cc70bSAndy Fleming /* 961272cc70bSAndy Fleming * CPU and board-specific MMC initializations. Aliased function 962272cc70bSAndy Fleming * signals caller to move on 963272cc70bSAndy Fleming */ 964272cc70bSAndy Fleming static int __def_mmc_init(bd_t *bis) 965272cc70bSAndy Fleming { 966272cc70bSAndy Fleming return -1; 967272cc70bSAndy Fleming } 968272cc70bSAndy Fleming 969f9a109b3SPeter Tyser int cpu_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init"))); 970f9a109b3SPeter Tyser int board_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init"))); 971272cc70bSAndy Fleming 972272cc70bSAndy Fleming void print_mmc_devices(char separator) 973272cc70bSAndy Fleming { 974272cc70bSAndy Fleming struct mmc *m; 975272cc70bSAndy Fleming struct list_head *entry; 976272cc70bSAndy Fleming 977272cc70bSAndy Fleming list_for_each(entry, &mmc_devices) { 978272cc70bSAndy Fleming m = list_entry(entry, struct mmc, link); 979272cc70bSAndy Fleming 980272cc70bSAndy Fleming printf("%s: %d", m->name, m->block_dev.dev); 981272cc70bSAndy Fleming 982272cc70bSAndy Fleming if (entry->next != &mmc_devices) 983272cc70bSAndy Fleming printf("%c ", separator); 984272cc70bSAndy Fleming } 985272cc70bSAndy Fleming 986272cc70bSAndy Fleming printf("\n"); 987272cc70bSAndy Fleming } 988272cc70bSAndy Fleming 989272cc70bSAndy Fleming int mmc_initialize(bd_t *bis) 990272cc70bSAndy Fleming { 991272cc70bSAndy Fleming INIT_LIST_HEAD (&mmc_devices); 992272cc70bSAndy Fleming cur_dev_num = 0; 993272cc70bSAndy Fleming 994272cc70bSAndy Fleming if (board_mmc_init(bis) < 0) 995272cc70bSAndy Fleming cpu_mmc_init(bis); 996272cc70bSAndy Fleming 997272cc70bSAndy Fleming print_mmc_devices(','); 998272cc70bSAndy Fleming 999272cc70bSAndy Fleming return 0; 1000272cc70bSAndy Fleming } 1001