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 36272cc70bSAndy Fleming static struct list_head mmc_devices; 37272cc70bSAndy Fleming static int cur_dev_num = -1; 38272cc70bSAndy Fleming 3911fdade2SStefano Babic int __board_mmc_getcd(u8 *cd, struct mmc *mmc) { 4011fdade2SStefano Babic return -1; 4111fdade2SStefano Babic } 4211fdade2SStefano Babic 4311fdade2SStefano Babic int board_mmc_getcd(u8 *cd, struct mmc *mmc)__attribute__((weak, 4411fdade2SStefano Babic alias("__board_mmc_getcd"))); 4511fdade2SStefano Babic 46272cc70bSAndy Fleming int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) 47272cc70bSAndy Fleming { 48272cc70bSAndy Fleming return mmc->send_cmd(mmc, cmd, data); 49272cc70bSAndy Fleming } 50272cc70bSAndy Fleming 51272cc70bSAndy Fleming int mmc_set_blocklen(struct mmc *mmc, int len) 52272cc70bSAndy Fleming { 53272cc70bSAndy Fleming struct mmc_cmd cmd; 54272cc70bSAndy Fleming 55272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SET_BLOCKLEN; 56272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 57272cc70bSAndy Fleming cmd.cmdarg = len; 58272cc70bSAndy Fleming cmd.flags = 0; 59272cc70bSAndy Fleming 60272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, NULL); 61272cc70bSAndy Fleming } 62272cc70bSAndy Fleming 63272cc70bSAndy Fleming struct mmc *find_mmc_device(int dev_num) 64272cc70bSAndy Fleming { 65272cc70bSAndy Fleming struct mmc *m; 66272cc70bSAndy Fleming struct list_head *entry; 67272cc70bSAndy Fleming 68272cc70bSAndy Fleming list_for_each(entry, &mmc_devices) { 69272cc70bSAndy Fleming m = list_entry(entry, struct mmc, link); 70272cc70bSAndy Fleming 71272cc70bSAndy Fleming if (m->block_dev.dev == dev_num) 72272cc70bSAndy Fleming return m; 73272cc70bSAndy Fleming } 74272cc70bSAndy Fleming 75272cc70bSAndy Fleming printf("MMC Device %d not found\n", dev_num); 76272cc70bSAndy Fleming 77272cc70bSAndy Fleming return NULL; 78272cc70bSAndy Fleming } 79272cc70bSAndy Fleming 80272cc70bSAndy Fleming static ulong 81272cc70bSAndy Fleming mmc_bwrite(int dev_num, ulong start, lbaint_t blkcnt, const void*src) 82272cc70bSAndy Fleming { 83272cc70bSAndy Fleming struct mmc_cmd cmd; 84272cc70bSAndy Fleming struct mmc_data data; 85272cc70bSAndy Fleming int err; 86272cc70bSAndy Fleming int stoperr = 0; 87272cc70bSAndy Fleming struct mmc *mmc = find_mmc_device(dev_num); 88272cc70bSAndy Fleming int blklen; 89272cc70bSAndy Fleming 90272cc70bSAndy Fleming if (!mmc) 91272cc70bSAndy Fleming return -1; 92272cc70bSAndy Fleming 93272cc70bSAndy Fleming blklen = mmc->write_bl_len; 94272cc70bSAndy Fleming 95*d2bf29e3SLei Wen if ((start + blkcnt) > mmc->block_dev.lba) { 96*d2bf29e3SLei Wen printf("MMC: block number 0x%x exceeds max(0x%x)", 97*d2bf29e3SLei Wen start + blkcnt, mmc->block_dev.lba); 98*d2bf29e3SLei Wen return 0; 99*d2bf29e3SLei Wen } 100272cc70bSAndy Fleming err = mmc_set_blocklen(mmc, mmc->write_bl_len); 101272cc70bSAndy Fleming 102272cc70bSAndy Fleming if (err) { 103272cc70bSAndy Fleming printf("set write bl len failed\n\r"); 104272cc70bSAndy Fleming return err; 105272cc70bSAndy Fleming } 106272cc70bSAndy Fleming 107272cc70bSAndy Fleming if (blkcnt > 1) 108272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK; 109272cc70bSAndy Fleming else 110272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_WRITE_SINGLE_BLOCK; 111272cc70bSAndy Fleming 112272cc70bSAndy Fleming if (mmc->high_capacity) 113272cc70bSAndy Fleming cmd.cmdarg = start; 114272cc70bSAndy Fleming else 115272cc70bSAndy Fleming cmd.cmdarg = start * blklen; 116272cc70bSAndy Fleming 117272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 118272cc70bSAndy Fleming cmd.flags = 0; 119272cc70bSAndy Fleming 120272cc70bSAndy Fleming data.src = src; 121272cc70bSAndy Fleming data.blocks = blkcnt; 122272cc70bSAndy Fleming data.blocksize = blklen; 123272cc70bSAndy Fleming data.flags = MMC_DATA_WRITE; 124272cc70bSAndy Fleming 125272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 126272cc70bSAndy Fleming 127272cc70bSAndy Fleming if (err) { 128272cc70bSAndy Fleming printf("mmc write failed\n\r"); 129272cc70bSAndy Fleming return err; 130272cc70bSAndy Fleming } 131272cc70bSAndy Fleming 132272cc70bSAndy Fleming if (blkcnt > 1) { 133272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; 134272cc70bSAndy Fleming cmd.cmdarg = 0; 135272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1b; 136272cc70bSAndy Fleming cmd.flags = 0; 137272cc70bSAndy Fleming stoperr = mmc_send_cmd(mmc, &cmd, NULL); 138272cc70bSAndy Fleming } 139272cc70bSAndy Fleming 140272cc70bSAndy Fleming return blkcnt; 141272cc70bSAndy Fleming } 142272cc70bSAndy Fleming 143272cc70bSAndy Fleming int mmc_read_block(struct mmc *mmc, void *dst, uint blocknum) 144272cc70bSAndy Fleming { 145272cc70bSAndy Fleming struct mmc_cmd cmd; 146272cc70bSAndy Fleming struct mmc_data data; 147272cc70bSAndy Fleming 148272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK; 149272cc70bSAndy Fleming 150272cc70bSAndy Fleming if (mmc->high_capacity) 151272cc70bSAndy Fleming cmd.cmdarg = blocknum; 152272cc70bSAndy Fleming else 153272cc70bSAndy Fleming cmd.cmdarg = blocknum * mmc->read_bl_len; 154272cc70bSAndy Fleming 155272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 156272cc70bSAndy Fleming cmd.flags = 0; 157272cc70bSAndy Fleming 158272cc70bSAndy Fleming data.dest = dst; 159272cc70bSAndy Fleming data.blocks = 1; 160272cc70bSAndy Fleming data.blocksize = mmc->read_bl_len; 161272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 162272cc70bSAndy Fleming 163272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, &data); 164272cc70bSAndy Fleming } 165272cc70bSAndy Fleming 166272cc70bSAndy Fleming int mmc_read(struct mmc *mmc, u64 src, uchar *dst, int size) 167272cc70bSAndy Fleming { 168272cc70bSAndy Fleming char *buffer; 169272cc70bSAndy Fleming int i; 170272cc70bSAndy Fleming int blklen = mmc->read_bl_len; 1719b1f942cSRabin Vincent int startblock = lldiv(src, mmc->read_bl_len); 1729b1f942cSRabin Vincent int endblock = lldiv(src + size - 1, mmc->read_bl_len); 173272cc70bSAndy Fleming int err = 0; 174272cc70bSAndy Fleming 175272cc70bSAndy Fleming /* Make a buffer big enough to hold all the blocks we might read */ 176272cc70bSAndy Fleming buffer = malloc(blklen); 177272cc70bSAndy Fleming 178272cc70bSAndy Fleming if (!buffer) { 179272cc70bSAndy Fleming printf("Could not allocate buffer for MMC read!\n"); 180272cc70bSAndy Fleming return -1; 181272cc70bSAndy Fleming } 182272cc70bSAndy Fleming 183272cc70bSAndy Fleming /* We always do full block reads from the card */ 184272cc70bSAndy Fleming err = mmc_set_blocklen(mmc, mmc->read_bl_len); 185272cc70bSAndy Fleming 186272cc70bSAndy Fleming if (err) 1878c4444ffSWolfgang Denk goto free_buffer; 188272cc70bSAndy Fleming 189272cc70bSAndy Fleming for (i = startblock; i <= endblock; i++) { 190272cc70bSAndy Fleming int segment_size; 191272cc70bSAndy Fleming int offset; 192272cc70bSAndy Fleming 193272cc70bSAndy Fleming err = mmc_read_block(mmc, buffer, i); 194272cc70bSAndy Fleming 195272cc70bSAndy Fleming if (err) 196272cc70bSAndy Fleming goto free_buffer; 197272cc70bSAndy Fleming 198272cc70bSAndy Fleming /* 199272cc70bSAndy Fleming * The first block may not be aligned, so we 200272cc70bSAndy Fleming * copy from the desired point in the block 201272cc70bSAndy Fleming */ 202272cc70bSAndy Fleming offset = (src & (blklen - 1)); 203272cc70bSAndy Fleming segment_size = MIN(blklen - offset, size); 204272cc70bSAndy Fleming 205272cc70bSAndy Fleming memcpy(dst, buffer + offset, segment_size); 206272cc70bSAndy Fleming 207272cc70bSAndy Fleming dst += segment_size; 208272cc70bSAndy Fleming src += segment_size; 209272cc70bSAndy Fleming size -= segment_size; 210272cc70bSAndy Fleming } 211272cc70bSAndy Fleming 212272cc70bSAndy Fleming free_buffer: 213272cc70bSAndy Fleming free(buffer); 214272cc70bSAndy Fleming 215272cc70bSAndy Fleming return err; 216272cc70bSAndy Fleming } 217272cc70bSAndy Fleming 218272cc70bSAndy Fleming static ulong mmc_bread(int dev_num, ulong start, lbaint_t blkcnt, void *dst) 219272cc70bSAndy Fleming { 220272cc70bSAndy Fleming int err; 221272cc70bSAndy Fleming int i; 222272cc70bSAndy Fleming struct mmc *mmc = find_mmc_device(dev_num); 223272cc70bSAndy Fleming 224272cc70bSAndy Fleming if (!mmc) 225272cc70bSAndy Fleming return 0; 226272cc70bSAndy Fleming 227*d2bf29e3SLei Wen if ((start + blkcnt) > mmc->block_dev.lba) { 228*d2bf29e3SLei Wen printf("MMC: block number 0x%x exceeds max(0x%x)", 229*d2bf29e3SLei Wen start + blkcnt, mmc->block_dev.lba); 230*d2bf29e3SLei Wen return 0; 231*d2bf29e3SLei Wen } 232272cc70bSAndy Fleming /* We always do full block reads from the card */ 233272cc70bSAndy Fleming err = mmc_set_blocklen(mmc, mmc->read_bl_len); 234272cc70bSAndy Fleming 235272cc70bSAndy Fleming if (err) { 236272cc70bSAndy Fleming return 0; 237272cc70bSAndy Fleming } 238272cc70bSAndy Fleming 239272cc70bSAndy Fleming for (i = start; i < start + blkcnt; i++, dst += mmc->read_bl_len) { 240272cc70bSAndy Fleming err = mmc_read_block(mmc, dst, i); 241272cc70bSAndy Fleming 242272cc70bSAndy Fleming if (err) { 243272cc70bSAndy Fleming printf("block read failed: %d\n", err); 244272cc70bSAndy Fleming return i - start; 245272cc70bSAndy Fleming } 246272cc70bSAndy Fleming } 247272cc70bSAndy Fleming 248272cc70bSAndy Fleming return blkcnt; 249272cc70bSAndy Fleming } 250272cc70bSAndy Fleming 251272cc70bSAndy Fleming int mmc_go_idle(struct mmc* mmc) 252272cc70bSAndy Fleming { 253272cc70bSAndy Fleming struct mmc_cmd cmd; 254272cc70bSAndy Fleming int err; 255272cc70bSAndy Fleming 256272cc70bSAndy Fleming udelay(1000); 257272cc70bSAndy Fleming 258272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_GO_IDLE_STATE; 259272cc70bSAndy Fleming cmd.cmdarg = 0; 260272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_NONE; 261272cc70bSAndy Fleming cmd.flags = 0; 262272cc70bSAndy Fleming 263272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 264272cc70bSAndy Fleming 265272cc70bSAndy Fleming if (err) 266272cc70bSAndy Fleming return err; 267272cc70bSAndy Fleming 268272cc70bSAndy Fleming udelay(2000); 269272cc70bSAndy Fleming 270272cc70bSAndy Fleming return 0; 271272cc70bSAndy Fleming } 272272cc70bSAndy Fleming 273272cc70bSAndy Fleming int 274272cc70bSAndy Fleming sd_send_op_cond(struct mmc *mmc) 275272cc70bSAndy Fleming { 276272cc70bSAndy Fleming int timeout = 1000; 277272cc70bSAndy Fleming int err; 278272cc70bSAndy Fleming struct mmc_cmd cmd; 279272cc70bSAndy Fleming 280272cc70bSAndy Fleming do { 281272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 282272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 283272cc70bSAndy Fleming cmd.cmdarg = 0; 284272cc70bSAndy Fleming cmd.flags = 0; 285272cc70bSAndy Fleming 286272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 287272cc70bSAndy Fleming 288272cc70bSAndy Fleming if (err) 289272cc70bSAndy Fleming return err; 290272cc70bSAndy Fleming 291272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_OP_COND; 292272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R3; 293250de12bSStefano Babic 294250de12bSStefano Babic /* 295250de12bSStefano Babic * Most cards do not answer if some reserved bits 296250de12bSStefano Babic * in the ocr are set. However, Some controller 297250de12bSStefano Babic * can set bit 7 (reserved for low voltages), but 298250de12bSStefano Babic * how to manage low voltages SD card is not yet 299250de12bSStefano Babic * specified. 300250de12bSStefano Babic */ 301250de12bSStefano Babic cmd.cmdarg = mmc->voltages & 0xff8000; 302272cc70bSAndy Fleming 303272cc70bSAndy Fleming if (mmc->version == SD_VERSION_2) 304272cc70bSAndy Fleming cmd.cmdarg |= OCR_HCS; 305272cc70bSAndy Fleming 306272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 307272cc70bSAndy Fleming 308272cc70bSAndy Fleming if (err) 309272cc70bSAndy Fleming return err; 310272cc70bSAndy Fleming 311272cc70bSAndy Fleming udelay(1000); 312272cc70bSAndy Fleming } while ((!(cmd.response[0] & OCR_BUSY)) && timeout--); 313272cc70bSAndy Fleming 314272cc70bSAndy Fleming if (timeout <= 0) 315272cc70bSAndy Fleming return UNUSABLE_ERR; 316272cc70bSAndy Fleming 317272cc70bSAndy Fleming if (mmc->version != SD_VERSION_2) 318272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 319272cc70bSAndy Fleming 320998be3ddSRabin Vincent mmc->ocr = cmd.response[0]; 321272cc70bSAndy Fleming 322272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 323272cc70bSAndy Fleming mmc->rca = 0; 324272cc70bSAndy Fleming 325272cc70bSAndy Fleming return 0; 326272cc70bSAndy Fleming } 327272cc70bSAndy Fleming 328272cc70bSAndy Fleming int mmc_send_op_cond(struct mmc *mmc) 329272cc70bSAndy Fleming { 330272cc70bSAndy Fleming int timeout = 1000; 331272cc70bSAndy Fleming struct mmc_cmd cmd; 332272cc70bSAndy Fleming int err; 333272cc70bSAndy Fleming 334272cc70bSAndy Fleming /* Some cards seem to need this */ 335272cc70bSAndy Fleming mmc_go_idle(mmc); 336272cc70bSAndy Fleming 337272cc70bSAndy Fleming do { 338272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_OP_COND; 339272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R3; 340272cc70bSAndy Fleming cmd.cmdarg = OCR_HCS | mmc->voltages; 341272cc70bSAndy Fleming cmd.flags = 0; 342272cc70bSAndy Fleming 343272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 344272cc70bSAndy Fleming 345272cc70bSAndy Fleming if (err) 346272cc70bSAndy Fleming return err; 347272cc70bSAndy Fleming 348272cc70bSAndy Fleming udelay(1000); 349272cc70bSAndy Fleming } while (!(cmd.response[0] & OCR_BUSY) && timeout--); 350272cc70bSAndy Fleming 351272cc70bSAndy Fleming if (timeout <= 0) 352272cc70bSAndy Fleming return UNUSABLE_ERR; 353272cc70bSAndy Fleming 354272cc70bSAndy Fleming mmc->version = MMC_VERSION_UNKNOWN; 355998be3ddSRabin Vincent mmc->ocr = cmd.response[0]; 356272cc70bSAndy Fleming 357272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 358272cc70bSAndy Fleming mmc->rca = 0; 359272cc70bSAndy Fleming 360272cc70bSAndy Fleming return 0; 361272cc70bSAndy Fleming } 362272cc70bSAndy Fleming 363272cc70bSAndy Fleming 364272cc70bSAndy Fleming int mmc_send_ext_csd(struct mmc *mmc, char *ext_csd) 365272cc70bSAndy Fleming { 366272cc70bSAndy Fleming struct mmc_cmd cmd; 367272cc70bSAndy Fleming struct mmc_data data; 368272cc70bSAndy Fleming int err; 369272cc70bSAndy Fleming 370272cc70bSAndy Fleming /* Get the Card Status Register */ 371272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_EXT_CSD; 372272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 373272cc70bSAndy Fleming cmd.cmdarg = 0; 374272cc70bSAndy Fleming cmd.flags = 0; 375272cc70bSAndy Fleming 376272cc70bSAndy Fleming data.dest = ext_csd; 377272cc70bSAndy Fleming data.blocks = 1; 378272cc70bSAndy Fleming data.blocksize = 512; 379272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 380272cc70bSAndy Fleming 381272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 382272cc70bSAndy Fleming 383272cc70bSAndy Fleming return err; 384272cc70bSAndy Fleming } 385272cc70bSAndy Fleming 386272cc70bSAndy Fleming 387272cc70bSAndy Fleming int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) 388272cc70bSAndy Fleming { 389272cc70bSAndy Fleming struct mmc_cmd cmd; 390272cc70bSAndy Fleming 391272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SWITCH; 392272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1b; 393272cc70bSAndy Fleming cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | 394272cc70bSAndy Fleming (index << 16) | 395272cc70bSAndy Fleming (value << 8); 396272cc70bSAndy Fleming cmd.flags = 0; 397272cc70bSAndy Fleming 398272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, NULL); 399272cc70bSAndy Fleming } 400272cc70bSAndy Fleming 401272cc70bSAndy Fleming int mmc_change_freq(struct mmc *mmc) 402272cc70bSAndy Fleming { 403272cc70bSAndy Fleming char ext_csd[512]; 404272cc70bSAndy Fleming char cardtype; 405272cc70bSAndy Fleming int err; 406272cc70bSAndy Fleming 407272cc70bSAndy Fleming mmc->card_caps = 0; 408272cc70bSAndy Fleming 409272cc70bSAndy Fleming /* Only version 4 supports high-speed */ 410272cc70bSAndy Fleming if (mmc->version < MMC_VERSION_4) 411272cc70bSAndy Fleming return 0; 412272cc70bSAndy Fleming 413272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_4BIT; 414272cc70bSAndy Fleming 415272cc70bSAndy Fleming err = mmc_send_ext_csd(mmc, ext_csd); 416272cc70bSAndy Fleming 417272cc70bSAndy Fleming if (err) 418272cc70bSAndy Fleming return err; 419272cc70bSAndy Fleming 420272cc70bSAndy Fleming if (ext_csd[212] || ext_csd[213] || ext_csd[214] || ext_csd[215]) 421272cc70bSAndy Fleming mmc->high_capacity = 1; 422272cc70bSAndy Fleming 423272cc70bSAndy Fleming cardtype = ext_csd[196] & 0xf; 424272cc70bSAndy Fleming 425272cc70bSAndy Fleming err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1); 426272cc70bSAndy Fleming 427272cc70bSAndy Fleming if (err) 428272cc70bSAndy Fleming return err; 429272cc70bSAndy Fleming 430272cc70bSAndy Fleming /* Now check to see that it worked */ 431272cc70bSAndy Fleming err = mmc_send_ext_csd(mmc, ext_csd); 432272cc70bSAndy Fleming 433272cc70bSAndy Fleming if (err) 434272cc70bSAndy Fleming return err; 435272cc70bSAndy Fleming 436272cc70bSAndy Fleming /* No high-speed support */ 437272cc70bSAndy Fleming if (!ext_csd[185]) 438272cc70bSAndy Fleming return 0; 439272cc70bSAndy Fleming 440272cc70bSAndy Fleming /* High Speed is set, there are two types: 52MHz and 26MHz */ 441272cc70bSAndy Fleming if (cardtype & MMC_HS_52MHZ) 442272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; 443272cc70bSAndy Fleming else 444272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS; 445272cc70bSAndy Fleming 446272cc70bSAndy Fleming return 0; 447272cc70bSAndy Fleming } 448272cc70bSAndy Fleming 449272cc70bSAndy Fleming int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) 450272cc70bSAndy Fleming { 451272cc70bSAndy Fleming struct mmc_cmd cmd; 452272cc70bSAndy Fleming struct mmc_data data; 453272cc70bSAndy Fleming 454272cc70bSAndy Fleming /* Switch the frequency */ 455272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SWITCH_FUNC; 456272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 457272cc70bSAndy Fleming cmd.cmdarg = (mode << 31) | 0xffffff; 458272cc70bSAndy Fleming cmd.cmdarg &= ~(0xf << (group * 4)); 459272cc70bSAndy Fleming cmd.cmdarg |= value << (group * 4); 460272cc70bSAndy Fleming cmd.flags = 0; 461272cc70bSAndy Fleming 462272cc70bSAndy Fleming data.dest = (char *)resp; 463272cc70bSAndy Fleming data.blocksize = 64; 464272cc70bSAndy Fleming data.blocks = 1; 465272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 466272cc70bSAndy Fleming 467272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, &data); 468272cc70bSAndy Fleming } 469272cc70bSAndy Fleming 470272cc70bSAndy Fleming 471272cc70bSAndy Fleming int sd_change_freq(struct mmc *mmc) 472272cc70bSAndy Fleming { 473272cc70bSAndy Fleming int err; 474272cc70bSAndy Fleming struct mmc_cmd cmd; 475272cc70bSAndy Fleming uint scr[2]; 476272cc70bSAndy Fleming uint switch_status[16]; 477272cc70bSAndy Fleming struct mmc_data data; 478272cc70bSAndy Fleming int timeout; 479272cc70bSAndy Fleming 480272cc70bSAndy Fleming mmc->card_caps = 0; 481272cc70bSAndy Fleming 482272cc70bSAndy Fleming /* Read the SCR to find out if this card supports higher speeds */ 483272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 484272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 485272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 486272cc70bSAndy Fleming cmd.flags = 0; 487272cc70bSAndy Fleming 488272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 489272cc70bSAndy Fleming 490272cc70bSAndy Fleming if (err) 491272cc70bSAndy Fleming return err; 492272cc70bSAndy Fleming 493272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_SCR; 494272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 495272cc70bSAndy Fleming cmd.cmdarg = 0; 496272cc70bSAndy Fleming cmd.flags = 0; 497272cc70bSAndy Fleming 498272cc70bSAndy Fleming timeout = 3; 499272cc70bSAndy Fleming 500272cc70bSAndy Fleming retry_scr: 501272cc70bSAndy Fleming data.dest = (char *)&scr; 502272cc70bSAndy Fleming data.blocksize = 8; 503272cc70bSAndy Fleming data.blocks = 1; 504272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 505272cc70bSAndy Fleming 506272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 507272cc70bSAndy Fleming 508272cc70bSAndy Fleming if (err) { 509272cc70bSAndy Fleming if (timeout--) 510272cc70bSAndy Fleming goto retry_scr; 511272cc70bSAndy Fleming 512272cc70bSAndy Fleming return err; 513272cc70bSAndy Fleming } 514272cc70bSAndy Fleming 5154e3d89baSYauhen Kharuzhy mmc->scr[0] = __be32_to_cpu(scr[0]); 5164e3d89baSYauhen Kharuzhy mmc->scr[1] = __be32_to_cpu(scr[1]); 517272cc70bSAndy Fleming 518272cc70bSAndy Fleming switch ((mmc->scr[0] >> 24) & 0xf) { 519272cc70bSAndy Fleming case 0: 520272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 521272cc70bSAndy Fleming break; 522272cc70bSAndy Fleming case 1: 523272cc70bSAndy Fleming mmc->version = SD_VERSION_1_10; 524272cc70bSAndy Fleming break; 525272cc70bSAndy Fleming case 2: 526272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 527272cc70bSAndy Fleming break; 528272cc70bSAndy Fleming default: 529272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 530272cc70bSAndy Fleming break; 531272cc70bSAndy Fleming } 532272cc70bSAndy Fleming 533272cc70bSAndy Fleming /* Version 1.0 doesn't support switching */ 534272cc70bSAndy Fleming if (mmc->version == SD_VERSION_1_0) 535272cc70bSAndy Fleming return 0; 536272cc70bSAndy Fleming 537272cc70bSAndy Fleming timeout = 4; 538272cc70bSAndy Fleming while (timeout--) { 539272cc70bSAndy Fleming err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1, 540272cc70bSAndy Fleming (u8 *)&switch_status); 541272cc70bSAndy Fleming 542272cc70bSAndy Fleming if (err) 543272cc70bSAndy Fleming return err; 544272cc70bSAndy Fleming 545272cc70bSAndy Fleming /* The high-speed function is busy. Try again */ 5464e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY)) 547272cc70bSAndy Fleming break; 548272cc70bSAndy Fleming } 549272cc70bSAndy Fleming 550272cc70bSAndy Fleming if (mmc->scr[0] & SD_DATA_4BIT) 551272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_4BIT; 552272cc70bSAndy Fleming 553272cc70bSAndy Fleming /* If high-speed isn't supported, we return */ 5544e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)) 555272cc70bSAndy Fleming return 0; 556272cc70bSAndy Fleming 557272cc70bSAndy Fleming err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)&switch_status); 558272cc70bSAndy Fleming 559272cc70bSAndy Fleming if (err) 560272cc70bSAndy Fleming return err; 561272cc70bSAndy Fleming 5624e3d89baSYauhen Kharuzhy if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000) 563272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS; 564272cc70bSAndy Fleming 565272cc70bSAndy Fleming return 0; 566272cc70bSAndy Fleming } 567272cc70bSAndy Fleming 568272cc70bSAndy Fleming /* frequency bases */ 569272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */ 570272cc70bSAndy Fleming int fbase[] = { 571272cc70bSAndy Fleming 10000, 572272cc70bSAndy Fleming 100000, 573272cc70bSAndy Fleming 1000000, 574272cc70bSAndy Fleming 10000000, 575272cc70bSAndy Fleming }; 576272cc70bSAndy Fleming 577272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice 578272cc70bSAndy Fleming * to platforms without floating point. 579272cc70bSAndy Fleming */ 580272cc70bSAndy Fleming int multipliers[] = { 581272cc70bSAndy Fleming 0, /* reserved */ 582272cc70bSAndy Fleming 10, 583272cc70bSAndy Fleming 12, 584272cc70bSAndy Fleming 13, 585272cc70bSAndy Fleming 15, 586272cc70bSAndy Fleming 20, 587272cc70bSAndy Fleming 25, 588272cc70bSAndy Fleming 30, 589272cc70bSAndy Fleming 35, 590272cc70bSAndy Fleming 40, 591272cc70bSAndy Fleming 45, 592272cc70bSAndy Fleming 50, 593272cc70bSAndy Fleming 55, 594272cc70bSAndy Fleming 60, 595272cc70bSAndy Fleming 70, 596272cc70bSAndy Fleming 80, 597272cc70bSAndy Fleming }; 598272cc70bSAndy Fleming 599272cc70bSAndy Fleming void mmc_set_ios(struct mmc *mmc) 600272cc70bSAndy Fleming { 601272cc70bSAndy Fleming mmc->set_ios(mmc); 602272cc70bSAndy Fleming } 603272cc70bSAndy Fleming 604272cc70bSAndy Fleming void mmc_set_clock(struct mmc *mmc, uint clock) 605272cc70bSAndy Fleming { 606272cc70bSAndy Fleming if (clock > mmc->f_max) 607272cc70bSAndy Fleming clock = mmc->f_max; 608272cc70bSAndy Fleming 609272cc70bSAndy Fleming if (clock < mmc->f_min) 610272cc70bSAndy Fleming clock = mmc->f_min; 611272cc70bSAndy Fleming 612272cc70bSAndy Fleming mmc->clock = clock; 613272cc70bSAndy Fleming 614272cc70bSAndy Fleming mmc_set_ios(mmc); 615272cc70bSAndy Fleming } 616272cc70bSAndy Fleming 617272cc70bSAndy Fleming void mmc_set_bus_width(struct mmc *mmc, uint width) 618272cc70bSAndy Fleming { 619272cc70bSAndy Fleming mmc->bus_width = width; 620272cc70bSAndy Fleming 621272cc70bSAndy Fleming mmc_set_ios(mmc); 622272cc70bSAndy Fleming } 623272cc70bSAndy Fleming 624272cc70bSAndy Fleming int mmc_startup(struct mmc *mmc) 625272cc70bSAndy Fleming { 626272cc70bSAndy Fleming int err; 627272cc70bSAndy Fleming uint mult, freq; 628272cc70bSAndy Fleming u64 cmult, csize; 629272cc70bSAndy Fleming struct mmc_cmd cmd; 630272cc70bSAndy Fleming 631272cc70bSAndy Fleming /* Put the Card in Identify Mode */ 632272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_ALL_SEND_CID; 633272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 634272cc70bSAndy Fleming cmd.cmdarg = 0; 635272cc70bSAndy Fleming cmd.flags = 0; 636272cc70bSAndy Fleming 637272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 638272cc70bSAndy Fleming 639272cc70bSAndy Fleming if (err) 640272cc70bSAndy Fleming return err; 641272cc70bSAndy Fleming 642272cc70bSAndy Fleming memcpy(mmc->cid, cmd.response, 16); 643272cc70bSAndy Fleming 644272cc70bSAndy Fleming /* 645272cc70bSAndy Fleming * For MMC cards, set the Relative Address. 646272cc70bSAndy Fleming * For SD cards, get the Relatvie Address. 647272cc70bSAndy Fleming * This also puts the cards into Standby State 648272cc70bSAndy Fleming */ 649272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR; 650272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 651272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R6; 652272cc70bSAndy Fleming cmd.flags = 0; 653272cc70bSAndy Fleming 654272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 655272cc70bSAndy Fleming 656272cc70bSAndy Fleming if (err) 657272cc70bSAndy Fleming return err; 658272cc70bSAndy Fleming 659272cc70bSAndy Fleming if (IS_SD(mmc)) 660998be3ddSRabin Vincent mmc->rca = (cmd.response[0] >> 16) & 0xffff; 661272cc70bSAndy Fleming 662272cc70bSAndy Fleming /* Get the Card-Specific Data */ 663272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_CSD; 664272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 665272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 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 673998be3ddSRabin Vincent mmc->csd[0] = cmd.response[0]; 674998be3ddSRabin Vincent mmc->csd[1] = cmd.response[1]; 675998be3ddSRabin Vincent mmc->csd[2] = cmd.response[2]; 676998be3ddSRabin Vincent mmc->csd[3] = cmd.response[3]; 677272cc70bSAndy Fleming 678272cc70bSAndy Fleming if (mmc->version == MMC_VERSION_UNKNOWN) { 6790b453ffeSRabin Vincent int version = (cmd.response[0] >> 26) & 0xf; 680272cc70bSAndy Fleming 681272cc70bSAndy Fleming switch (version) { 682272cc70bSAndy Fleming case 0: 683272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 684272cc70bSAndy Fleming break; 685272cc70bSAndy Fleming case 1: 686272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_4; 687272cc70bSAndy Fleming break; 688272cc70bSAndy Fleming case 2: 689272cc70bSAndy Fleming mmc->version = MMC_VERSION_2_2; 690272cc70bSAndy Fleming break; 691272cc70bSAndy Fleming case 3: 692272cc70bSAndy Fleming mmc->version = MMC_VERSION_3; 693272cc70bSAndy Fleming break; 694272cc70bSAndy Fleming case 4: 695272cc70bSAndy Fleming mmc->version = MMC_VERSION_4; 696272cc70bSAndy Fleming break; 697272cc70bSAndy Fleming default: 698272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 699272cc70bSAndy Fleming break; 700272cc70bSAndy Fleming } 701272cc70bSAndy Fleming } 702272cc70bSAndy Fleming 703272cc70bSAndy Fleming /* divide frequency by 10, since the mults are 10x bigger */ 7040b453ffeSRabin Vincent freq = fbase[(cmd.response[0] & 0x7)]; 7050b453ffeSRabin Vincent mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; 706272cc70bSAndy Fleming 707272cc70bSAndy Fleming mmc->tran_speed = freq * mult; 708272cc70bSAndy Fleming 709998be3ddSRabin Vincent mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf); 710272cc70bSAndy Fleming 711272cc70bSAndy Fleming if (IS_SD(mmc)) 712272cc70bSAndy Fleming mmc->write_bl_len = mmc->read_bl_len; 713272cc70bSAndy Fleming else 714998be3ddSRabin Vincent mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf); 715272cc70bSAndy Fleming 716272cc70bSAndy Fleming if (mmc->high_capacity) { 717272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3f) << 16 718272cc70bSAndy Fleming | (mmc->csd[2] & 0xffff0000) >> 16; 719272cc70bSAndy Fleming cmult = 8; 720272cc70bSAndy Fleming } else { 721272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3ff) << 2 722272cc70bSAndy Fleming | (mmc->csd[2] & 0xc0000000) >> 30; 723272cc70bSAndy Fleming cmult = (mmc->csd[2] & 0x00038000) >> 15; 724272cc70bSAndy Fleming } 725272cc70bSAndy Fleming 726272cc70bSAndy Fleming mmc->capacity = (csize + 1) << (cmult + 2); 727272cc70bSAndy Fleming mmc->capacity *= mmc->read_bl_len; 728272cc70bSAndy Fleming 729272cc70bSAndy Fleming if (mmc->read_bl_len > 512) 730272cc70bSAndy Fleming mmc->read_bl_len = 512; 731272cc70bSAndy Fleming 732272cc70bSAndy Fleming if (mmc->write_bl_len > 512) 733272cc70bSAndy Fleming mmc->write_bl_len = 512; 734272cc70bSAndy Fleming 735272cc70bSAndy Fleming /* Select the card, and put it into Transfer Mode */ 736272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SELECT_CARD; 737272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1b; 738272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 739272cc70bSAndy Fleming cmd.flags = 0; 740272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 741272cc70bSAndy Fleming 742272cc70bSAndy Fleming if (err) 743272cc70bSAndy Fleming return err; 744272cc70bSAndy Fleming 745272cc70bSAndy Fleming if (IS_SD(mmc)) 746272cc70bSAndy Fleming err = sd_change_freq(mmc); 747272cc70bSAndy Fleming else 748272cc70bSAndy Fleming err = mmc_change_freq(mmc); 749272cc70bSAndy Fleming 750272cc70bSAndy Fleming if (err) 751272cc70bSAndy Fleming return err; 752272cc70bSAndy Fleming 753272cc70bSAndy Fleming /* Restrict card's capabilities by what the host can do */ 754272cc70bSAndy Fleming mmc->card_caps &= mmc->host_caps; 755272cc70bSAndy Fleming 756272cc70bSAndy Fleming if (IS_SD(mmc)) { 757272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_4BIT) { 758272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 759272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 760272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 761272cc70bSAndy Fleming cmd.flags = 0; 762272cc70bSAndy Fleming 763272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 764272cc70bSAndy Fleming if (err) 765272cc70bSAndy Fleming return err; 766272cc70bSAndy Fleming 767272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH; 768272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 769272cc70bSAndy Fleming cmd.cmdarg = 2; 770272cc70bSAndy Fleming cmd.flags = 0; 771272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 772272cc70bSAndy Fleming if (err) 773272cc70bSAndy Fleming return err; 774272cc70bSAndy Fleming 775272cc70bSAndy Fleming mmc_set_bus_width(mmc, 4); 776272cc70bSAndy Fleming } 777272cc70bSAndy Fleming 778272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_HS) 779272cc70bSAndy Fleming mmc_set_clock(mmc, 50000000); 780272cc70bSAndy Fleming else 781272cc70bSAndy Fleming mmc_set_clock(mmc, 25000000); 782272cc70bSAndy Fleming } else { 783272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_4BIT) { 784272cc70bSAndy Fleming /* Set the card to use 4 bit*/ 785272cc70bSAndy Fleming err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 786272cc70bSAndy Fleming EXT_CSD_BUS_WIDTH, 787272cc70bSAndy Fleming EXT_CSD_BUS_WIDTH_4); 788272cc70bSAndy Fleming 789272cc70bSAndy Fleming if (err) 790272cc70bSAndy Fleming return err; 791272cc70bSAndy Fleming 792272cc70bSAndy Fleming mmc_set_bus_width(mmc, 4); 793272cc70bSAndy Fleming } else if (mmc->card_caps & MMC_MODE_8BIT) { 794272cc70bSAndy Fleming /* Set the card to use 8 bit*/ 795272cc70bSAndy Fleming err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 796272cc70bSAndy Fleming EXT_CSD_BUS_WIDTH, 797272cc70bSAndy Fleming EXT_CSD_BUS_WIDTH_8); 798272cc70bSAndy Fleming 799272cc70bSAndy Fleming if (err) 800272cc70bSAndy Fleming return err; 801272cc70bSAndy Fleming 802272cc70bSAndy Fleming mmc_set_bus_width(mmc, 8); 803272cc70bSAndy Fleming } 804272cc70bSAndy Fleming 805272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_HS) { 806272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_HS_52MHz) 807272cc70bSAndy Fleming mmc_set_clock(mmc, 52000000); 808272cc70bSAndy Fleming else 809272cc70bSAndy Fleming mmc_set_clock(mmc, 26000000); 810272cc70bSAndy Fleming } else 811272cc70bSAndy Fleming mmc_set_clock(mmc, 20000000); 812272cc70bSAndy Fleming } 813272cc70bSAndy Fleming 814272cc70bSAndy Fleming /* fill in device description */ 815272cc70bSAndy Fleming mmc->block_dev.lun = 0; 816272cc70bSAndy Fleming mmc->block_dev.type = 0; 817272cc70bSAndy Fleming mmc->block_dev.blksz = mmc->read_bl_len; 8189b1f942cSRabin Vincent mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len); 8190b453ffeSRabin Vincent sprintf(mmc->block_dev.vendor, "Man %06x Snr %08x", mmc->cid[0] >> 8, 8200b453ffeSRabin Vincent (mmc->cid[2] << 8) | (mmc->cid[3] >> 24)); 8210b453ffeSRabin Vincent sprintf(mmc->block_dev.product, "%c%c%c%c%c", mmc->cid[0] & 0xff, 8220b453ffeSRabin Vincent (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, 8230b453ffeSRabin Vincent (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff); 8240b453ffeSRabin Vincent sprintf(mmc->block_dev.revision, "%d.%d", mmc->cid[2] >> 28, 8250b453ffeSRabin Vincent (mmc->cid[2] >> 24) & 0xf); 826272cc70bSAndy Fleming init_part(&mmc->block_dev); 827272cc70bSAndy Fleming 828272cc70bSAndy Fleming return 0; 829272cc70bSAndy Fleming } 830272cc70bSAndy Fleming 831272cc70bSAndy Fleming int mmc_send_if_cond(struct mmc *mmc) 832272cc70bSAndy Fleming { 833272cc70bSAndy Fleming struct mmc_cmd cmd; 834272cc70bSAndy Fleming int err; 835272cc70bSAndy Fleming 836272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_IF_COND; 837272cc70bSAndy Fleming /* We set the bit if the host supports voltages between 2.7 and 3.6 V */ 838272cc70bSAndy Fleming cmd.cmdarg = ((mmc->voltages & 0xff8000) != 0) << 8 | 0xaa; 839272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R7; 840272cc70bSAndy Fleming cmd.flags = 0; 841272cc70bSAndy Fleming 842272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 843272cc70bSAndy Fleming 844272cc70bSAndy Fleming if (err) 845272cc70bSAndy Fleming return err; 846272cc70bSAndy Fleming 847998be3ddSRabin Vincent if ((cmd.response[0] & 0xff) != 0xaa) 848272cc70bSAndy Fleming return UNUSABLE_ERR; 849272cc70bSAndy Fleming else 850272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 851272cc70bSAndy Fleming 852272cc70bSAndy Fleming return 0; 853272cc70bSAndy Fleming } 854272cc70bSAndy Fleming 855272cc70bSAndy Fleming int mmc_register(struct mmc *mmc) 856272cc70bSAndy Fleming { 857272cc70bSAndy Fleming /* Setup the universal parts of the block interface just once */ 858272cc70bSAndy Fleming mmc->block_dev.if_type = IF_TYPE_MMC; 859272cc70bSAndy Fleming mmc->block_dev.dev = cur_dev_num++; 860272cc70bSAndy Fleming mmc->block_dev.removable = 1; 861272cc70bSAndy Fleming mmc->block_dev.block_read = mmc_bread; 862272cc70bSAndy Fleming mmc->block_dev.block_write = mmc_bwrite; 863272cc70bSAndy Fleming 864272cc70bSAndy Fleming INIT_LIST_HEAD (&mmc->link); 865272cc70bSAndy Fleming 866272cc70bSAndy Fleming list_add_tail (&mmc->link, &mmc_devices); 867272cc70bSAndy Fleming 868272cc70bSAndy Fleming return 0; 869272cc70bSAndy Fleming } 870272cc70bSAndy Fleming 871272cc70bSAndy Fleming block_dev_desc_t *mmc_get_dev(int dev) 872272cc70bSAndy Fleming { 873272cc70bSAndy Fleming struct mmc *mmc = find_mmc_device(dev); 874272cc70bSAndy Fleming 875e85649c7SRabin Vincent return mmc ? &mmc->block_dev : NULL; 876272cc70bSAndy Fleming } 877272cc70bSAndy Fleming 878272cc70bSAndy Fleming int mmc_init(struct mmc *mmc) 879272cc70bSAndy Fleming { 880272cc70bSAndy Fleming int err; 881272cc70bSAndy Fleming 882272cc70bSAndy Fleming err = mmc->init(mmc); 883272cc70bSAndy Fleming 884272cc70bSAndy Fleming if (err) 885272cc70bSAndy Fleming return err; 886272cc70bSAndy Fleming 887b86b85e2SIlya Yanok mmc_set_bus_width(mmc, 1); 888b86b85e2SIlya Yanok mmc_set_clock(mmc, 1); 889b86b85e2SIlya Yanok 890272cc70bSAndy Fleming /* Reset the Card */ 891272cc70bSAndy Fleming err = mmc_go_idle(mmc); 892272cc70bSAndy Fleming 893272cc70bSAndy Fleming if (err) 894272cc70bSAndy Fleming return err; 895272cc70bSAndy Fleming 896272cc70bSAndy Fleming /* Test for SD version 2 */ 897272cc70bSAndy Fleming err = mmc_send_if_cond(mmc); 898272cc70bSAndy Fleming 899272cc70bSAndy Fleming /* Now try to get the SD card's operating condition */ 900272cc70bSAndy Fleming err = sd_send_op_cond(mmc); 901272cc70bSAndy Fleming 902272cc70bSAndy Fleming /* If the command timed out, we check for an MMC card */ 903272cc70bSAndy Fleming if (err == TIMEOUT) { 904272cc70bSAndy Fleming err = mmc_send_op_cond(mmc); 905272cc70bSAndy Fleming 906272cc70bSAndy Fleming if (err) { 907272cc70bSAndy Fleming printf("Card did not respond to voltage select!\n"); 908272cc70bSAndy Fleming return UNUSABLE_ERR; 909272cc70bSAndy Fleming } 910272cc70bSAndy Fleming } 911272cc70bSAndy Fleming 912272cc70bSAndy Fleming return mmc_startup(mmc); 913272cc70bSAndy Fleming } 914272cc70bSAndy Fleming 915272cc70bSAndy Fleming /* 916272cc70bSAndy Fleming * CPU and board-specific MMC initializations. Aliased function 917272cc70bSAndy Fleming * signals caller to move on 918272cc70bSAndy Fleming */ 919272cc70bSAndy Fleming static int __def_mmc_init(bd_t *bis) 920272cc70bSAndy Fleming { 921272cc70bSAndy Fleming return -1; 922272cc70bSAndy Fleming } 923272cc70bSAndy Fleming 924f9a109b3SPeter Tyser int cpu_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init"))); 925f9a109b3SPeter Tyser int board_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init"))); 926272cc70bSAndy Fleming 927272cc70bSAndy Fleming void print_mmc_devices(char separator) 928272cc70bSAndy Fleming { 929272cc70bSAndy Fleming struct mmc *m; 930272cc70bSAndy Fleming struct list_head *entry; 931272cc70bSAndy Fleming 932272cc70bSAndy Fleming list_for_each(entry, &mmc_devices) { 933272cc70bSAndy Fleming m = list_entry(entry, struct mmc, link); 934272cc70bSAndy Fleming 935272cc70bSAndy Fleming printf("%s: %d", m->name, m->block_dev.dev); 936272cc70bSAndy Fleming 937272cc70bSAndy Fleming if (entry->next != &mmc_devices) 938272cc70bSAndy Fleming printf("%c ", separator); 939272cc70bSAndy Fleming } 940272cc70bSAndy Fleming 941272cc70bSAndy Fleming printf("\n"); 942272cc70bSAndy Fleming } 943272cc70bSAndy Fleming 944272cc70bSAndy Fleming int mmc_initialize(bd_t *bis) 945272cc70bSAndy Fleming { 946272cc70bSAndy Fleming INIT_LIST_HEAD (&mmc_devices); 947272cc70bSAndy Fleming cur_dev_num = 0; 948272cc70bSAndy Fleming 949272cc70bSAndy Fleming if (board_mmc_init(bis) < 0) 950272cc70bSAndy Fleming cpu_mmc_init(bis); 951272cc70bSAndy Fleming 952272cc70bSAndy Fleming print_mmc_devices(','); 953272cc70bSAndy Fleming 954272cc70bSAndy Fleming return 0; 955272cc70bSAndy Fleming } 956