/* * Copyright (C) 2017 ALLWINNERTECH TECHNOLOGY CO., LTD. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * 3. Neither the name of ALLWINNERTECH TECHNOLOGY CO., LTD. nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "hal_def.h" #include "sdio.h" #include "sdmmc.h" #include "hal_sdhost.h" #include "_sdhost.h" #include "_mmc.h" #include "_sd.h" #ifdef CONFIG_USE_MMC /* int32_t mmc_sd_get_csd(struct mmc_card *card) //static { struct mmc_command cmd = {0}; uint32_t csd[4] = {0}; cmd.opcode = MMC_SEND_CSD; cmd.arg = card->rca<<16; cmd.flags = MMC_RSP_R2 | MMC_CMD_AC; if (mmc_wait_for_cmd(card->host, &cmd)) { return -1; } HAL_Memcpy((void *)csd, (void *)cmd.resp, 16); //decode CSD reg card->csd.csd_ver = (csd[3]>>30)&0x3; card->csd.trans_speed = csd[3]&0xff; card->csd.read_blk_len = (csd[2]>>16)&0xf; if (card->type == CT_MMC || card->csd.csd_ver == 0) { card->csd.c_size_mult = (csd[1]>>15)&0x7; card->csd.c_size = ((csd[1]>>30)&0x3)|((csd[2]&0x3ff)<<2); } else { card->csd.c_size_mult = 0; card->csd.c_size = ((csd[1]>>16)&0xffff)|((csd[2]&0x3f)<<16); } card->csd.cmd_class = (csd[2]>>20)&0xfff; card->csd.mmc_spec_ver = (csd[3]>>26)&0xf; return 0; } */ int32_t mmc_send_op_cond(struct mmc_card *card, uint32_t ocr, uint32_t *rocr) { struct mmc_command cmd = {0}; uint32_t i = 0; cmd.opcode = MMC_SEND_OP_COND; cmd.arg = 0; cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR; SD_LOGD("%s,%d arg use ocr?\n", __func__, __LINE__); do { if (mmc_wait_for_cmd(card->host, &cmd)) { return -1; } cmd.arg = 0x40000000|(cmd.resp[0]&0xFF8080); #ifndef SYSTEM_SIMULATION HAL_MSleep(10); if (++i == 100) break; #else smc_model_powerup_rdy(card->smc_no); #endif } while(!(cmd.resp[0] & 0x80000000)); if (!(cmd.resp[0] & 0x80000000)) { SD_LOGD("Wait card power up ready timeout, i = %d !\n", i); return -1; } cmd.resp[0] &= 0x7fffffff; HAL_Memcpy((void *)&card->ocr, (void *)&cmd.resp[0], 4); SD_LOGD("ocr = %08x !!\n", (unsigned int)cmd.resp[0]); if (card->ocr.high_capacity) /* bit30 */ mmc_card_set_blockaddr(card); return 0; } static int32_t mmc_public_new_rca(struct mmc_card *card) { struct mmc_command cmd = {0}; cmd.opcode = MMC_SET_RELATIVE_ADDR; cmd.arg = 0x1234 << 16; // why 1234 ?? cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; //different from SD card; if (mmc_wait_for_cmd(card->host, &cmd)) { return -1; } card->rca = 0x1234; SD_LOGD("rca = %04x !!\n", (unsigned int)card->rca); return 0; } int32_t mmc_send_extcsd(struct mmc_card *card) { struct mmc_command cmd = {0}; struct mmc_data data = {0}; struct mmc_request mrq; uint8_t extcsd[512] = {0}; struct scatterlist sg = {0}; sg.len = 512; sg.buffer = extcsd; cmd.opcode = MMC_SEND_EXT_CSD; cmd.arg = 0; cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; cmd.data = &data; data.blksz = 512; data.sg_len = 1; data.sg = &sg; data.flags = MMC_DATA_READ; mrq.cmd = &cmd; mrq.data = &data; if (mmc_wait_for_req(card->host, &mrq)) { return -1; } SD_LOGD("%s,%d %s\n", __func__, __LINE__, "extcsd"); sd_hex_dump_bytes((void *)extcsd, 512); //decode EXTCSD card->extcsd.version = extcsd[192]; card->extcsd.card_type = extcsd[196]; card->extcsd.csd_struc = extcsd[194]; card->extcsd.hs_timing = extcsd[185]; card->extcsd.bus_width = extcsd[183]; if (extcsd[160] & MMC_SWITCH_PART_SUPPORT) card->extcsd.part_config = extcsd[179]; if (card->extcsd.version >= 3) //>=4.3 card->extcsd.boot_bus_cond = extcsd[177]; return 0; } static int32_t mmc_switch_buswidth(struct mmc_card *card, uint32_t width) { uint8_t set_val; int32_t ret = -1; switch (width) { case MMC_BUS_WIDTH_1: set_val = MMC_EXT_CSD_BUS_WIDTH_1; break; case MMC_BUS_WIDTH_4: set_val = MMC_EXT_CSD_BUS_WIDTH_4; break; case MMC_BUS_WIDTH_8: set_val = MMC_EXT_CSD_BUS_WIDTH_8; break; default: set_val = MMC_EXT_CSD_BUS_WIDTH_1; } ret = mmc_switch(card, MMC_EXT_CSD_CMD_SET_NORMAL, MMC_EXT_CSD_BUS_WIDTH, set_val); if (-1 == ret) { SD_LOGW("Old-MMC Card with 1 bit data only!!\n"); return -1; } SD_LOGD("RS-MMC Card!!\n"); card->bus_width = width; return 0; } int32_t mmc_set_buswidth(struct mmc_card *card, uint32_t width) { if (card->type == CT_MMC) { if (card->csd.mmc_spec_ver < MMC_CSD_SPEC_VER_4) { card->bus_width = width = MMC_BUS_WIDTH_1; } else if (mmc_switch_buswidth(card, width)) { SD_LOGD("Set bus width error, use default 1 bit !!\n"); return -1; } } else if (card->type == CT_SDSC1x || card->type == CT_SDSC20 || \ card->type == CT_SDHC20 || card->type == CT_SDXC30) { if (mmc_app_set_bus_width(card, width)) { SD_LOGD("Set bus width error, use default 1 bit !!\n"); return -1; } } else return -1; HAL_SDC_Set_BusWidth(card->host, width); SD_LOGD("Set bus width type: %d !!\n", (unsigned int)width); return 0; } int32_t mmc_switch_part(struct mmc_card *card, uint32_t part_num) { return mmc_switch(card, MMC_EXT_CSD_CMD_SET_NORMAL, MMC_EXT_CSD_PART_CONF, (card->extcsd.part_config & ~MMC_SWITCH_PART_ACCESS_MASK) | (part_num & MMC_SWITCH_PART_ACCESS_MASK)); } int32_t mmc_switch_boot_part(struct mmc_card *card, uint32_t boot_ack, uint32_t boot_part) { return mmc_switch(card, MMC_EXT_CSD_CMD_SET_NORMAL, MMC_EXT_CSD_PART_CONF, (card->extcsd.part_config & (~MMC_SWITCH_PART_BOOT_PART_MASK) & (~MMC_SWITCH_PART_BOOT_ACK_MASK)) | ((boot_part << 3) & MMC_SWITCH_PART_BOOT_PART_MASK) | (boot_ack << 6)); } int32_t mmc_switch_boot_bus_cond(struct mmc_card *card, uint32_t boot_mode, uint32_t rst_bus_cond, uint32_t bus_width) { return mmc_switch(card, MMC_EXT_CSD_CMD_SET_NORMAL, MMC_EXT_CSD_BOOT_BUS_COND, (card->extcsd.boot_bus_cond & (~MMC_SWITCH_BOOT_MODE_MASK) & (~MMC_SWITCH_BOOT_RST_BUS_COND_MASK) & (~MMC_SWITCH_BOOT_BUS_WIDTH_MASK)) | ((boot_mode << 3) & MMC_SWITCH_BOOT_MODE_MASK) | ((rst_bus_cond << 2) & MMC_SWITCH_BOOT_RST_BUS_COND_MASK) | ((bus_width) & MMC_SWITCH_BOOT_BUS_WIDTH_MASK) ); } int32_t smc_model_set_blkcnt(struct mmc_host *host, uint32_t blkcnt) { struct mmc_command cmd = {0}; cmd.opcode = MMC_SET_BLOCK_COUNT; cmd.arg = blkcnt & 0xffff; cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; if (mmc_wait_for_cmd(host, &cmd)) { return -1; } host->blkcnt = blkcnt; return 0; } int32_t sdmmc_stream_write(struct mmc_card *card, uint32_t blk_num, uint32_t blk_size, uint32_t sg_len, struct scatterlist *sg) { struct mmc_command cmd = {0}; struct mmc_data data = {0}; struct mmc_request mrq; uint32_t status = 0; if (!card || !card->host) { SD_LOGE_RAW(ROM_ERR_MASK, "%s,%d err", __func__, __LINE__); return -1; } cmd.opcode = MMC_WRITE_SINGLE_BLOCK; cmd.arg = blk_num; if (!mmc_card_blockaddr(card)) cmd.arg <<= 9; cmd.stop = 0; cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 |MMC_CMD_ADTC; cmd.data = &data; data.flags |= MMC_DATA_WRITE | MMC_DATA_STREAM; data.blksz = blk_size; data.sg_len = sg_len; data.sg = sg; mrq.cmd = &cmd; mrq.data = &data; if (mmc_wait_for_req(card->host, &mrq)) { return -1; } /* check busy */ do { if (HAL_SDC_Is_Busy(card->host)) continue; mmc_send_status(card, &status); } while (!(status & 0x100)); return 0; } /* * Starting point for MMC card init. */ int mmc_attach_mmc(struct mmc_card *card, struct mmc_host *host) { int err; uint32_t ocr; uint32_t clk = 400000; if (!host) { SD_LOGE_RAW(ROM_ERR_MASK, "%s,%d no host exist!\n", __func__, __LINE__); return -1; } //SD_WARN_ON(!host->claimed); /* send cmd1 to check MMC */ err = mmc_send_op_cond(card, 0, &ocr); if (err) return err; card->type = CT_MMC; /* cmd2, send cid */ if (mmc_all_send_cid(host, card->cidno)) { SD_LOGD("All cards send CID number failed !!\n"); return -1; } else SD_LOGD("CID number:%x\n", (unsigned int)card->cidno[0]); SD_LOGD("%s,%d !!!!!!!@@@@@@@@ called mmc_attach_sd\n", __func__, __LINE__); /* cmd3, For native busses: get card RCA and quit open drain mode. */ err = mmc_public_new_rca(card); /* cmd10, get CID register */ if (sdmmc_send_cid(card)) { SD_LOGW("Card send CID reg failed !!\n"); return -1; } /* cmd9, get CSD register */ if (mmc_sd_get_csd(card)) { SD_LOGW("Card send CSD reg failed !!\n"); return -1; } /* cmd7, Select card to standby state, as all following commands rely on that. */ if (mmc_select_card(card, 1)) { SD_LOGW("mmc_select_card failed !!\n"); return -1; } if (card->csd.mmc_spec_ver < MMC_CSD_SPEC_VER_4) err = 0; else err = mmc_send_extcsd(card); if (err == -1) return -1; //sd-acmd6, set buswidth, mmc-cmd6, switch buswidth if (-1 == sdmmc_set_buswidth(card, 4)) return -1; mmc_switch_to_high_speed(card); card->sd_bus_speed = SD_SWITCH_ACCESS_HS_SDR25; if (card->sd_bus_speed == SD_SWITCH_ACCESS_SDR104) clk = 208000000; else if (card->sd_bus_speed == SD_SWITCH_ACCESS_SDR50) clk = 104000000; else if (card->sd_bus_speed == SD_SWITCH_ACCESS_HS_SDR25) clk = 50000000; else clk = 25000000; clk = 50000000; HAL_SDC_Update_Clk(card->host, clk); sdmmc_enumerate_card_info(card); //send tunning pattern if (card->sd_bus_speed == SD_SWITCH_ACCESS_SDR104 || card->sd_bus_speed == SD_SWITCH_ACCESS_SDR50) sd_send_tuning_pattern(card); card->host->card = card; return err; } #endif /* CONFIG_USE_MMC */