/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ /* * drivers/mmc/aml_sd_emmc.c * * Copyright (C) 2020 Amlogic, Inc. All rights reserved. * */ #include #include #include //#include #include #include #include #include #ifdef CONFIG_STORE_COMPATIBLE #include #endif #include #include //#define SD_DEBUG_ENABLE #ifdef SD_DEBUG_ENABLE #define sd_debug(a...) printf(a); #else #define sd_debug(a...) #endif //#define EMMC_DEBUG_ENABLE #ifdef EMMC_DEBUG_ENABLE #define emmc_debug(a...) printf(a); #else #define emmc_debug(a...) #endif extern bool aml_is_emmc_tsd (struct mmc *mmc); /* * ********************************************************************************************** * board relative * ********************************************************************************************** */ unsigned long sd_emmc_base_addr[3] = {SD_EMMC_BASE_A, SD_EMMC_BASE_B, SD_EMMC_BASE_C}; static struct aml_card_sd_info aml_sd_emmc_ports[]={ { .sd_emmc_port=SDIO_PORT_A,.name="SDIO Port A"}, { .sd_emmc_port=SDIO_PORT_B,.name="SDIO Port B"}, { .sd_emmc_port=SDIO_PORT_C,.name="SDIO Port C"}, }; /*The default source clock is 1GMHZ, tx_phase is 0*/ #define MMC_CLOCK_MAX 2 static struct fixed_adj_table calc_fixed_adj[]={ {40000000, 20}, {50000000, 18}, }; struct aml_card_sd_info * cpu_sd_emmc_get(unsigned port) { if (portclk_lay.core == mmc->clk_lay.old_core) return 1; mmc->clk_lay.old_core = mmc->clk_lay.core; printf(">>>calc: source clk %d, core clk %d\n", mmc->clk_lay.source, mmc->clk_lay.core); full_div = mmc->clk_lay.source / mmc->clk_lay.core; sdclk_idx = full_div / 2; sdclk_idx -= full_div % 2 ? 0 : 1; printf("full_div %d, sdclk_idx %d\n", full_div, sdclk_idx); /* ns */ source_cycle = 1000000000 / mmc->clk_lay.source; printf("cycle of source clock is %d \n", source_cycle); if (source_cycle < TODLY_MAX_NS) { todly_idx_max = (TODLY_MAX_NS + source_cycle - 1) / source_cycle; todly_idx_min = TODLY_MIN_NS / source_cycle; printf("todly_idx_min %d, todly_idx_max %d\n", todly_idx_min, todly_idx_max); inv_idx_min = todly_idx_min + sdclk_idx; inv_idx_max = todly_idx_max + sdclk_idx; printf("inv_idx_min %d, inv_idx_max %d\n", inv_idx_min, inv_idx_max); inv_idx_min = inv_idx_min % full_div; inv_idx_max = inv_idx_max % full_div; printf("ROUND: inv_idx_min %d, inv_idx_max %d\n", inv_idx_min, inv_idx_max); if (inv_idx_min > inv_idx_max) { val_idx_min = inv_idx_max + 1; val_idx_max = inv_idx_min - 1; val_idx_sta = val_idx_min; val_idx_win = val_idx_max - val_idx_min; } else if (inv_idx_min <= inv_idx_max) { val_idx_max = inv_idx_max + 1; val_idx_min = inv_idx_min - 1; val_idx_sta = val_idx_max; val_idx_win = (full_div + val_idx_min) - val_idx_max; } } else { val_idx_max = sdclk_idx + 1; val_idx_min = sdclk_idx - 1; val_idx_sta = val_idx_max; val_idx_win = full_div / 2; //val_idx_win = (full_div + val_idx_min) - val_idx_max; } printf("val_idx_sta %d, val_idx_win %d\n", val_idx_sta, val_idx_win); mmc->fixdiv = val_idx_sta + (val_idx_win >> 1); printf("fixdiv = %d\n", mmc->fixdiv); return ret; } void aml_sd_cfg_swth(struct mmc *mmc) { unsigned sd_emmc_clkc = 0,clk,clk_src,clk_div = 0; unsigned int vconf = 0; unsigned bus_width=(mmc->bus_width == 1)?0:mmc->bus_width/4; struct aml_card_sd_info *aml_priv = mmc->priv; struct sd_emmc_global_regs *sd_emmc_reg = aml_priv->sd_emmc_reg; //struct sd_emmc_config* sd_emmc_cfg = (struct sd_emmc_config*)&vconf; emmc_debug("mmc->clock=%d; clk_div=%d\n",mmc->clock ,clk_div); unsigned int adj = 0; /* reset gdelay , gadjust register */ sd_emmc_reg->gdelay = 0; sd_emmc_reg->gadjust = 0; if (mmc->clock > 12000000) { clk = SD_EMMC_CLKSRC_DIV2; clk_src = 1; }else{ clk = SD_EMMC_CLKSRC_24M; clk_src = 0; } if (mmc->clockcfg->f_min) mmc->clock=mmc->cfg->f_min; if (mmc->clock>mmc->cfg->f_max) mmc->clock=mmc->cfg->f_max; clk_div= clk / mmc->clock; #if CONFIG_EMMC_DDR52_EN if (mmc->ddr_mode) { clk_div /= 2; sd_debug("DDR: \n"); } #endif sd_emmc_clkc =((0 << Cfg_irq_sdio_sleep_ds) | (0 << Cfg_irq_sdio_sleep) | (1 << Cfg_always_on) | (0 << Cfg_rx_delay) | (0 << Cfg_tx_delay) | (0 << Cfg_sram_pd) | (0 << Cfg_rx_phase) | (0 << Cfg_tx_phase) | (2 << Cfg_co_phase) | (clk_src << Cfg_src) | (clk_div << Cfg_div)); sd_emmc_reg->gclock = sd_emmc_clkc; //vconf = sd_emmc_reg->gcfg; vconf = bus_width & 0x3; //1bit mode vconf |= (9 & 0xf) << 4; //512byte block length vconf |= (7 & 0xf) << 8 ; //64 CLK cycle, here 2^8 = 256 clk cycles vconf |= (4 & 0xf) << 12; //1024 CLK cycle, Max. 100mS. #if CONFIG_EMMC_DDR52_EN vconf |= (mmc->ddr_mode & 0x1) << 2; #endif sd_emmc_reg->gcfg = vconf; sd_emmc_para_config(sd_emmc_reg, mmc->clock, aml_priv->sd_emmc_port); if (mmc->cfg->ops->calc && (!strcmp(mmc->cfg->name, "SDIO Port C"))) { mmc->clk_lay.source = mmc->clock * clk_div; mmc->clk_lay.core = mmc->clock; if (!mmc->cfg->ops->calc(mmc)) { sd_emmc_clkc = sd_emmc_reg->gclock; sd_emmc_clkc &= ~(3 << Cfg_tx_phase); sd_emmc_clkc &= ~(3 << Cfg_co_phase); sd_emmc_clkc |= (2 << Cfg_tx_phase); sd_emmc_reg->gclock = sd_emmc_clkc; adj |= (mmc->fixdiv << 16); adj |= (1 << 13); sd_emmc_reg->gadjust = adj; printf("fixdiv calc done: clk = 0x%x, adj = 0x%x\n", sd_emmc_clkc, adj); } } printf("co-phase 0x%x, tx-dly %d, clock %d\n", (sd_emmc_reg->gclock >> Cfg_co_phase) & 3, (sd_emmc_reg->gclock >> Cfg_tx_delay) & 0x3f, mmc->clock); emmc_debug("bus_width=%d; tclk_div=%d; tclk=%d;sd_clk=%d\n", bus_width,clk_div,clk,mmc->clock); emmc_debug("port=%d act_clk=%d\n",aml_priv->sd_emmc_port,clk/clk_div); return; } static int sd_inand_check_insert(struct mmc *mmc) { int level; struct aml_card_sd_info *sd_inand_info = mmc->priv; level = sd_inand_info->sd_emmc_detect(sd_inand_info->sd_emmc_port); if (level) { if (sd_inand_info->init_retry) { sd_inand_info->sd_emmc_pwr_off(sd_inand_info->sd_emmc_port); sd_inand_info->init_retry = 0; } if (sd_inand_info->inited_flag) { sd_inand_info->sd_emmc_pwr_off(sd_inand_info->sd_emmc_port); sd_inand_info->removed_flag = 1; sd_inand_info->inited_flag = 0; } return 0; //No card is inserted } else { return 1; //A card is inserted } } //Clear response data buffer static void sd_inand_clear_response(unsigned * res_buf) { int i; if (res_buf == NULL) return; for (i = 0; i < MAX_RESPONSE_BYTES; i++) res_buf[i]=0; } /* static int sd_inand_check_response(struct mmc_cmd *cmd) { int ret = SD_NO_ERROR; SD_Response_R1_t *r1 = (SD_Response_R1_t *)cmd->response; switch (cmd->resp_type) { case MMC_RSP_R1: case MMC_RSP_R1b: if (r1->card_status.OUT_OF_RANGE) return SD_ERROR_OUT_OF_RANGE; else if (r1->card_status.ADDRESS_ERROR) return SD_ERROR_ADDRESS; else if (r1->card_status.BLOCK_LEN_ERROR) return SD_ERROR_BLOCK_LEN; else if (r1->card_status.ERASE_SEQ_ERROR) return SD_ERROR_ERASE_SEQ; else if (r1->card_status.ERASE_PARAM) return SD_ERROR_ERASE_PARAM; else if (r1->card_status.WP_VIOLATION) return SD_ERROR_WP_VIOLATION; else if (r1->card_status.CARD_IS_LOCKED) return SD_ERROR_CARD_IS_LOCKED; else if (r1->card_status.LOCK_UNLOCK_FAILED) return SD_ERROR_LOCK_UNLOCK_FAILED; else if (r1->card_status.COM_CRC_ERROR) return SD_ERROR_COM_CRC; else if (r1->card_status.ILLEGAL_COMMAND) return SD_ERROR_ILLEGAL_COMMAND; else if (r1->card_status.CARD_ECC_FAILED) return SD_ERROR_CARD_ECC_FAILED; else if (r1->card_status.CC_ERROR) return SD_ERROR_CC; else if (r1->card_status.ERROR) return SD_ERROR_GENERAL; else if (r1->card_status.CID_CSD_OVERWRITE) return SD_ERROR_CID_CSD_OVERWRITE; else if (r1->card_status.AKE_SEQ_ERROR) return SD_ERROR_AKE_SEQ; break; default: break; } return ret; }*/ extern unsigned sd_debug_board_1bit_flag; static int sd_inand_staff_init(struct mmc *mmc) { struct aml_card_sd_info * sdio=mmc->priv; //unsigned base; sd_debug(""); sdio->sd_emmc_pwr_prepare(sdio->sd_emmc_port); sd_debug("power off"); sdio->sd_emmc_pwr_off(sdio->sd_emmc_port); //try to init mmc controller clock firstly mmc->clock = 400000; aml_sd_cfg_swth(mmc); //only power ctrl for external tf card if (sdio->sd_emmc_port == SDIO_PORT_B) { //base=get_timer(0); #if defined(CONFIG_VLSI_EMULATOR) //while (get_timer(base)<1) ; #else //while (get_timer(base)<200) ; #endif } sdio->sd_emmc_pwr_on(sdio->sd_emmc_port); sdio->sd_emmc_init(sdio->sd_emmc_port); if (sd_debug_board_1bit_flag == 1) { struct mmc_config *cfg; cfg = &((struct aml_card_sd_info *)mmc->priv)->cfg; cfg->host_caps = MMC_MODE_HS; mmc->cfg = cfg; } //only power ctrl for external tf card if (sdio->sd_emmc_port == SDIO_PORT_B) { //base=get_timer(0); #if defined(CONFIG_VLSI_EMULATOR) //while (get_timer(base)<1) ; #else //while (get_timer(base)<200) ; #endif } if (!sdio->inited_flag) sdio->inited_flag = 1; return SD_NO_ERROR; } /* * ********************************************************************************************** * u-boot interface function * ********************************************************************************************** */ int aml_sd_send_cmd_ffu(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) { int ret = SD_NO_ERROR; u32 resp_buffer; u32 vstart = 0; u32 status_irq = 0; u32 *write_buffer = NULL; struct sd_emmc_status *status_irq_reg = (void *)&status_irq; struct sd_emmc_start *desc_start = (struct sd_emmc_start*)&vstart; struct aml_card_sd_info *aml_priv = mmc->priv; struct sd_emmc_global_regs *sd_emmc_reg = aml_priv->sd_emmc_reg; struct cmd_cfg *des_cmd_cur = NULL; struct sd_emmc_desc_info *desc_cur = (struct sd_emmc_desc_info*)aml_priv->desc_buf; u32 blks = 0, desc_cnt = 0; dma_addr_t dma_addr_data = 0, dma_addr_info = 0; memset(desc_cur, 0, (NEWSD_MAX_DESC_MUN>>2)*sizeof(struct sd_emmc_desc_info)); des_cmd_cur = (struct cmd_cfg *)&(desc_cur->cmd_info); des_cmd_cur->cmd_index = 0x80 | cmd->cmdidx; //bit:31 owner = 1 bit:24-29 cmdidx desc_cur->cmd_arg = cmd->cmdarg; sd_inand_clear_response(cmd->response); //check response type if (cmd->resp_type & MMC_RSP_PRESENT) { resp_buffer = (unsigned long)cmd->response; des_cmd_cur->no_resp = 0; //save Resp into Resp addr, and check response from register for RSP_136 if (cmd->resp_type & MMC_RSP_136) des_cmd_cur->resp_128 = 1; if (cmd->resp_type & MMC_RSP_BUSY) des_cmd_cur->r1b = 1; //check data0 busy after R1 response if (!(cmd->resp_type & MMC_RSP_CRC)) des_cmd_cur->resp_nocrc = 1; des_cmd_cur->resp_num = 0; desc_cur->resp_addr = resp_buffer; } else des_cmd_cur->no_resp = 1; if (data) { des_cmd_cur->data_io = 1; // cmd has data read or write if (data->flags == MMC_DATA_WRITE) { write_buffer = (u32 *)malloc(data->blocks * data->blocksize); if (!write_buffer) { printf("%s: No memory for write_buffer\n", __func__); return -ENOMEM; } memset(write_buffer, 0, data->blocks * data->blocksize); memcpy(write_buffer, (u32 *)data->src, data->blocks*data->blocksize); dma_addr_data = dma_map_single((void *)write_buffer, data->blocks * data->blocksize, DMA_TO_DEVICE); if (data->blocks > 1) { blks = data->blocks; desc_cnt = 0; while (blks) { des_cmd_cur = (struct cmd_cfg *)&(desc_cur->cmd_info); des_cmd_cur->block_mode = 1; if (blks > 511) { des_cmd_cur->length = 511; blks -= 511; } else { des_cmd_cur->length = blks; blks = 0; } if (desc_cnt != 0) { des_cmd_cur->no_resp = 1; des_cmd_cur->no_cmd = 1; } des_cmd_cur->data_num = 0; des_cmd_cur->data_io = 1; // cmd has data read or write des_cmd_cur->owner = 1; des_cmd_cur->data_wr = 1; desc_cur->data_addr = ((unsigned long)(dma_addr_data) + (desc_cnt * 511 * 512)); desc_cur->data_addr &= ~(1<<0); //DDR if (blks) { desc_cur++; desc_cnt++; memset(desc_cur, 0, sizeof(struct sd_emmc_desc_info)); } } } else { printf("data blks < 1\n"); free(write_buffer); return 1; } } else { printf("ffu (flags == read) error\n"); return 1; } } /*Prepare desc for config register*/ des_cmd_cur->end_of_chain = 1; //the end flag of descriptor chain sd_emmc_reg->gstatus = NEWSD_IRQ_ALL; dma_addr_info = dma_map_single((void *)aml_priv->desc_buf, NEWSD_MAX_DESC_MUN * (sizeof(struct sd_emmc_desc_info)), DMA_TO_DEVICE); //start transfer cmd desc_start->init = 0; desc_start->busy = 1; desc_start->addr = (unsigned long)dma_addr_info >> 2; sd_emmc_reg->gstart = vstart; while (1) { status_irq = sd_emmc_reg->gstatus; if (status_irq_reg->end_of_chain) break; } if (status_irq_reg->rxd_err) { ret |= SD_EMMC_RXD_ERROR; if (!mmc->refix) printf("emmc/sd read error, cmd%d, status=0x%x\n", cmd->cmdidx, status_irq); } if (status_irq_reg->txd_err) { ret |= SD_EMMC_TXD_ERROR; if (!mmc->refix) printf("emmc/sd write error, cmd%d, status=0x%x\n", cmd->cmdidx, status_irq); } if (status_irq_reg->desc_err) { ret |= SD_EMMC_DESC_ERROR; if (!mmc->refix) printf("emmc/sd descriptor error, cmd%d, status=0x%x\n", cmd->cmdidx, status_irq); } if (status_irq_reg->resp_err) { ret |= SD_EMMC_RESP_CRC_ERROR; if (!mmc->refix) printf("emmc/sd response crc error, cmd%d, status=0x%x\n", cmd->cmdidx, status_irq); } if (status_irq_reg->resp_timeout) { ret |= SD_EMMC_RESP_TIMEOUT_ERROR; if (!mmc->refix) printf("emmc/sd response timeout, cmd%d, status=0x%x\n", cmd->cmdidx, status_irq); } if (status_irq_reg->desc_timeout) { ret |= SD_EMMC_DESC_TIMEOUT_ERROR; if (!mmc->refix) printf("emmc/sd descriptor timeout, cmd%d, status=0x%x\n", cmd->cmdidx, status_irq); } if (cmd->resp_type & MMC_RSP_136) { cmd->response[0] = sd_emmc_reg->gcmd_rsp3; cmd->response[1] = sd_emmc_reg->gcmd_rsp2; cmd->response[2] = sd_emmc_reg->gcmd_rsp1; cmd->response[3] = sd_emmc_reg->gcmd_rsp0; } else { cmd->response[0] = sd_emmc_reg->gcmd_rsp0; } sd_debug("cmd->cmdidx = %d, cmd->cmdarg=0x%x, ret=0x%x\n",cmd->cmdidx,cmd->cmdarg,ret); sd_debug("cmd->response[0]=0x%x;\n",cmd->response[0]); sd_debug("cmd->response[1]=0x%x;\n",cmd->response[1]); sd_debug("cmd->response[2]=0x%x;\n",cmd->response[2]); sd_debug("cmd->response[3]=0x%x;\n",cmd->response[3]); dma_unmap_single(dma_addr_info, NEWSD_MAX_DESC_MUN * (sizeof(struct sd_emmc_desc_info)), DMA_TO_DEVICE); if (des_cmd_cur->data_wr == 1) { dma_unmap_single(dma_addr_data, data->blocks * data->blocksize, DMA_TO_DEVICE); free(write_buffer); write_buffer = NULL; } if (ret) { if (status_irq_reg->resp_timeout) return TIMEOUT; else return ret; } return SD_NO_ERROR; } /* * Sends a command out on the bus. Takes the mmc pointer, * a command pointer, and an optional data pointer. */ int aml_sd_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) { int ret = SD_NO_ERROR; u32 resp_buffer; u32 vstart = 0; u32 status_irq = 0; //u32 inalign = 0; u32 *write_buffer = NULL; struct sd_emmc_status *status_irq_reg = (void *)&status_irq; struct sd_emmc_start *desc_start = (struct sd_emmc_start*)&vstart; //struct sd_emmc_config* sd_emmc_cfg = (struct sd_emmc_config*)&vconf; struct aml_card_sd_info *aml_priv = mmc->priv; struct sd_emmc_global_regs *sd_emmc_reg = aml_priv->sd_emmc_reg; struct cmd_cfg *des_cmd_cur = NULL; struct sd_emmc_desc_info *desc_cur = (struct sd_emmc_desc_info*)aml_priv->desc_buf; dma_addr_t dma_addr_data = 0, dma_addr_info = 0; //vconf = sd_emmc_reg->gcfg; memset(desc_cur, 0, (NEWSD_MAX_DESC_MUN>>2)*sizeof(struct sd_emmc_desc_info)); des_cmd_cur = (struct cmd_cfg *)&(desc_cur->cmd_info); des_cmd_cur->cmd_index = 0x80 | cmd->cmdidx; //bit:31 owner = 1 bit:24-29 cmdidx desc_cur->cmd_arg = cmd->cmdarg; sd_inand_clear_response(cmd->response); //check response type if (cmd->resp_type & MMC_RSP_PRESENT) { resp_buffer = (unsigned long)cmd->response;//dma_map_single((void*)cmd->response,sizeof(uint)*4,DMA_FROM_DEVICE); des_cmd_cur->no_resp = 0; //save Resp into Resp addr, and check response from register for RSP_136 if (cmd->resp_type & MMC_RSP_136) des_cmd_cur->resp_128 = 1; if (cmd->resp_type & MMC_RSP_BUSY) des_cmd_cur->r1b = 1; //check data0 busy after R1 response if (!(cmd->resp_type & MMC_RSP_CRC)) des_cmd_cur->resp_nocrc = 1; des_cmd_cur->resp_num = 0; desc_cur->resp_addr = resp_buffer; } else des_cmd_cur->no_resp = 1; if (data) { des_cmd_cur->data_io = 1; // cmd has data read or write if (data->flags == MMC_DATA_READ) { des_cmd_cur->data_wr = 0; //read data from sd/emmc dma_addr_data = dma_map_single((void *)data->dest, data->blocks * data->blocksize, DMA_FROM_DEVICE); } else { des_cmd_cur->data_wr = 1; write_buffer = (u32 *)malloc(data->blocks * data->blocksize); if (!write_buffer) { printf("%s: No memory for write_buffer\n", __func__); return -ENOMEM; } memset(write_buffer, 0 ,data->blocks * data->blocksize); memcpy(write_buffer, (u32 *)data->src, data->blocks*data->blocksize); dma_addr_data = dma_map_single((void *)write_buffer, data->blocks * data->blocksize, DMA_TO_DEVICE); } if (data->blocks > 1) { des_cmd_cur->block_mode = 1; des_cmd_cur->length = data->blocks; } else { des_cmd_cur->block_mode = 0; des_cmd_cur->length = data->blocksize; } des_cmd_cur->data_num = 0; if (des_cmd_cur->data_wr == 1) desc_cur->data_addr = (unsigned long)dma_addr_data; else desc_cur->data_addr = dma_addr_data; desc_cur->data_addr &= ~(1<<0); //DDR } if (data) { if ((data->blocks*data->blocksize <0x200) && (data->flags == MMC_DATA_READ)) { desc_cur->data_addr = (unsigned long)sd_emmc_reg->gping; desc_cur->data_addr |= 1<<0; } //des_cmd_cur->timeout = 7; } /*Prepare desc for config register*/ des_cmd_cur->owner = 1; des_cmd_cur->end_of_chain = 0; //sd_emmc_reg->gcfg = vconf; des_cmd_cur->end_of_chain = 1; //the end flag of descriptor chain sd_emmc_reg->gstatus = NEWSD_IRQ_ALL; dma_addr_info = dma_map_single((void *)aml_priv->desc_buf, NEWSD_MAX_DESC_MUN * (sizeof(struct sd_emmc_desc_info)), DMA_TO_DEVICE); //start transfer cmd desc_start->init = 0; desc_start->busy = 1; desc_start->addr = (unsigned long)dma_addr_info >> 2; #if 0 sd_emmc_reg->gstart = vstart; #else sd_emmc_reg->gcmd_cfg = desc_cur->cmd_info; sd_emmc_reg->gcmd_dat = desc_cur->data_addr; sd_emmc_reg->gcmd_arg = desc_cur->cmd_arg; #endif //waiting end of chain // mmc->refix = 0; while (1) { status_irq = sd_emmc_reg->gstatus; if (status_irq_reg->end_of_chain) break; } if (status_irq_reg->rxd_err) { ret |= SD_EMMC_RXD_ERROR; if (!mmc->refix) printf("emmc/sd read error, cmd%d, cmd->cmdarg=0x%x, status=0x%x\n", cmd->cmdidx, cmd->cmdarg, status_irq); } if (status_irq_reg->txd_err) { ret |= SD_EMMC_TXD_ERROR; if (!mmc->refix) printf("emmc/sd write error, cmd%d, cmd->cmdarg=0x%x, status=0x%x\n", cmd->cmdidx, cmd->cmdarg, status_irq); } if (status_irq_reg->desc_err) { ret |= SD_EMMC_DESC_ERROR; if (!mmc->refix) printf("emmc/sd descriptor error, cmd%d, cmd->cmdarg=0x%x, status=0x%x\n", cmd->cmdidx, cmd->cmdarg, status_irq); } if (status_irq_reg->resp_err) { ret |= SD_EMMC_RESP_CRC_ERROR; if (!mmc->refix) printf("emmc/sd response crc error, cmd%d, cmd->cmdarg=0x%x, status=0x%x\n", cmd->cmdidx, cmd->cmdarg, status_irq); } if (status_irq_reg->resp_timeout) { ret |= SD_EMMC_RESP_TIMEOUT_ERROR; if (!mmc->refix) printf("emmc/sd response timeout, cmd%d, cmd->cmdarg=0x%x, status=0x%x\n", cmd->cmdidx, cmd->cmdarg, status_irq); } if (status_irq_reg->desc_timeout) { ret |= SD_EMMC_DESC_TIMEOUT_ERROR; if (!mmc->refix) printf("emmc/sd descriptor timeout, cmd%d, cmd->cmdarg=0x%x, status=0x%x\n", cmd->cmdidx, cmd->cmdarg, status_irq); } dma_unmap_single(dma_addr_info, NEWSD_MAX_DESC_MUN * (sizeof(struct sd_emmc_desc_info)), DMA_TO_DEVICE); if (data && data->dest && data->flags == MMC_DATA_READ) { dma_unmap_single(dma_addr_data, data->blocks * data->blocksize, DMA_FROM_DEVICE); if (data->blocks * data->blocksize < 0x200) memcpy(data->dest, (const void *)sd_emmc_reg->gping,data->blocks*data->blocksize); } /*we get response [0]:bit0~31 * response [1]:bit32~63 * response [2]:bit64~95 * response [3]:bit96~127 * actually mmc driver definition is: * response [0]:bit96~127 * response [1]:bit64~95 * response [2]:bit32~63 * response [3]:bit0~31 */ if (cmd->resp_type & MMC_RSP_136) { cmd->response[0] = sd_emmc_reg->gcmd_rsp3; cmd->response[1] = sd_emmc_reg->gcmd_rsp2; cmd->response[2] = sd_emmc_reg->gcmd_rsp1; cmd->response[3] = sd_emmc_reg->gcmd_rsp0; } else { cmd->response[0] = sd_emmc_reg->gcmd_rsp0; } sd_debug("cmd->cmdidx = %d, cmd->cmdarg=0x%x, ret=0x%x\n",cmd->cmdidx,cmd->cmdarg,ret); sd_debug("cmd->response[0]=0x%x;\n",cmd->response[0]); sd_debug("cmd->response[1]=0x%x;\n",cmd->response[1]); sd_debug("cmd->response[2]=0x%x;\n",cmd->response[2]); sd_debug("cmd->response[3]=0x%x;\n",cmd->response[3]); if (des_cmd_cur->data_wr == 1) { dma_unmap_single(dma_addr_data, data->blocks * data->blocksize, DMA_TO_DEVICE); free(write_buffer); write_buffer = NULL; } if (ret) { if (status_irq_reg->resp_timeout) return TIMEOUT; else return ret; } return SD_NO_ERROR; } int aml_sd_init(struct mmc *mmc) { struct aml_card_sd_info *sdio=mmc->priv; if (sdio->inited_flag) { sdio->sd_emmc_init(sdio->sd_emmc_port); mmc->cfg->ops->set_ios(mmc); return 0; } if (sd_inand_check_insert(mmc)) { sd_inand_staff_init(mmc); return 0; } else return 1; } u8 line_x, cal_time; u8 dly_tmp; u8 max_index; int aml_send_calibration_blocks(struct mmc *mmc, char *buffer, u32 start_blk, u32 cnt) { int err = 0, ret = 0; struct mmc_cmd cmd = {0}; struct mmc_cmd stop = {0}; struct mmc_data data = {{0}, 0}; stop.cmdidx = MMC_CMD_STOP_TRANSMISSION; stop.cmdarg = 0; stop.resp_type = MMC_RSP_R1b; if (cnt > 1) cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; else cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK; cmd.cmdarg = start_blk; //start address = 0 cmd.resp_type = MMC_RSP_R1; data.dest = buffer; data.blocks = cnt; data.blocksize = mmc->read_bl_len; data.flags = MMC_DATA_READ; err = aml_sd_send_cmd(mmc, &cmd, &data); if (err) emmc_debug("%s [%d] send calibration read blocks error %d cnt = %d\n", __func__, __LINE__, err, cnt); if (cnt > 1 || err) { ret = aml_sd_send_cmd(mmc, &stop, NULL); if (ret) emmc_debug("%s [%d] send calibration stop blocks error %d\n", __func__, __LINE__, ret); } if (ret || err) return -1; return 0; } int __attribute__((unused)) sd_emmc_test_adj(struct mmc *mmc) { int err = 0, ret = 0; struct mmc_cmd cmd = {0}; struct mmc_cmd stop = {0}; struct mmc_data data = {{0}, 0}; char *blk_test = NULL; struct aml_card_sd_info *aml_priv = mmc->priv; struct sd_emmc_global_regs *sd_emmc_reg = aml_priv->sd_emmc_reg; u32 adjust = sd_emmc_reg->gadjust; struct sd_emmc_adjust *gadjust = (struct sd_emmc_adjust *)&adjust; u32 vclk, clk_div, retry; struct sd_emmc_clock *clkc = (struct sd_emmc_clock *)&(vclk); vclk = sd_emmc_reg->gclock; clk_div = clkc->div; retry = clk_div; blk_test = malloc(0x400 * mmc->read_bl_len); if (!blk_test) return -1; stop.cmdidx = MMC_CMD_STOP_TRANSMISSION; stop.cmdarg = 0; stop.resp_type = MMC_RSP_R1b; cmd.cmdarg = 0x14000; cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; cmd.resp_type = MMC_RSP_R1; data.dest = blk_test; data.blocks = 0x400; data.blocksize = mmc->read_bl_len; data.flags = MMC_DATA_READ; __Retry: err = aml_sd_send_cmd(mmc, &cmd, &data); if (err) emmc_debug("%s [%d] send test read blocks error %d\n", __func__, __LINE__, err); ret = aml_sd_send_cmd(mmc, &stop, NULL); if (ret) emmc_debug("%s [%d] send test stop blocks error %d\n", __func__, __LINE__, ret); if (ret || err) { if (retry == 0) { free(blk_test); return 1; } retry--; gadjust->adj_delay--; sd_emmc_reg->gadjust = adjust; printf("adj retry sampling point:(%d)->(%d)", gadjust->adj_delay+1, gadjust->adj_delay); emmc_debug("%s [%d]: delay = 0x%x gadjust =0x%x\n", __func__, __LINE__, sd_emmc_reg->gdelay, sd_emmc_reg->gadjust); goto __Retry; } free(blk_test); return 0; } int set_emmc_calc_fixed_adj(struct mmc *mmc) { struct aml_card_sd_info *aml_priv = mmc->priv; struct sd_emmc_global_regs *sd_emmc_reg = aml_priv->sd_emmc_reg; u32 adjust = sd_emmc_reg->gadjust; struct sd_emmc_adjust *gadjust = (struct sd_emmc_adjust *)&adjust; u32 clk_num; gadjust->adj_enable = 1; for (clk_num = 0; clk_num < MMC_CLOCK_MAX; clk_num++) { if (mmc->clock == calc_fixed_adj[clk_num].clk) { gadjust->adj_delay = calc_fixed_adj[clk_num].fixed_adj; sd_emmc_reg->gadjust = adjust; printf("[%s][%d]find fixed adj_delay=%d\n", __func__, __LINE__, gadjust->adj_delay); break; } } if (clk_num == MMC_CLOCK_MAX) { printf("[%s][%d] no find fixed adj value\n", __func__, __LINE__); return -1; } return 0; } int aml_sd_retry_refix(struct mmc *mmc) { struct aml_card_sd_info *aml_priv = mmc->priv; struct sd_emmc_global_regs *sd_emmc_reg = aml_priv->sd_emmc_reg; u32 start_blk = 0; u32 vclk, clk_div; struct sd_emmc_clock *clkc = (struct sd_emmc_clock *)&(vclk); u32 adjust = sd_emmc_reg->gadjust; struct sd_emmc_adjust *gadjust = (struct sd_emmc_adjust *)&adjust; int err = 0, ret = 0, adj_delay = 0; char *blk_test = NULL; #ifdef MMC_HS400_MODE int pre_status = 0; int start = 0; #endif emmc_debug("tuning..................\n"); //const u8 *blk_pattern = tuning_data->blk_pattern; //u8 *blk_test; //unsigned int blksz = tuning_data->blksz; //int ret = 0; int n, nmatch, ntries = 10; int wrap_win_start = -1, wrap_win_size = 0; int best_win_start = -1, best_win_size = -1; int curr_win_start = -1, curr_win_size = 0; u8 rx_tuning_result[25/SAMPLE_STEP_COUNT] = { 0 }; blk_test = malloc(REFIX_BLK_CNT * mmc->read_bl_len); if (!blk_test) return -1; vclk = sd_emmc_reg->gclock; clk_div = clkc->div; for (adj_delay = 0; adj_delay < clk_div; adj_delay+=SAMPLE_STEP_COUNT) { // Perform tuning ntries times per clk_div increment gadjust->adj_delay = adj_delay; gadjust->adj_enable = 1; gadjust->cali_enable = 0; gadjust->cali_rise = 0; sd_emmc_reg->gadjust = adjust; start_blk = CALI_PATTERN_ADDR; emmc_debug("%s [%d]: gadjust =0x%x\n", __func__, __LINE__, sd_emmc_reg->gadjust); for (n = 0, nmatch = 0; n < ntries; n++) { memset(blk_test, 0, REFIX_BLK_CNT); err = aml_send_calibration_blocks(mmc, blk_test, start_blk, REFIX_BLK_CNT); if (!err && !ret) nmatch++; else { emmc_debug("refix error: adj_delay=%d nmatch=%d err=%d ret=%d\n",adj_delay, nmatch, err, ret); break; } } if (adj_delay < sizeof(rx_tuning_result) / sizeof (rx_tuning_result[0])) rx_tuning_result[adj_delay] = nmatch; if (nmatch == ntries) { if (adj_delay == 0) wrap_win_start = adj_delay; if (wrap_win_start >= 0) wrap_win_size += SAMPLE_STEP_COUNT; if (curr_win_start < 0) curr_win_start = adj_delay; curr_win_size += SAMPLE_STEP_COUNT; } else { if (curr_win_start >= 0) { if (best_win_start < 0) { best_win_start = curr_win_start; best_win_size = curr_win_size; } else { if (best_win_size < curr_win_size) { best_win_start = curr_win_start; best_win_size = curr_win_size; } } wrap_win_start = -1; curr_win_start = -1; curr_win_size = 0; } } emmc_debug("adj_delay:[%d]\n", adj_delay); emmc_debug("curr_win_start=%d, curr_win_size=%d\n",curr_win_start, curr_win_size); emmc_debug("wrap_win_start=%d, wrap_win_size=%d\n",wrap_win_start, wrap_win_size); emmc_debug("best_win_start=%d, best_win_size=%d\n\n",best_win_start, best_win_size); } #if 0 for (n = 0; n <= clkc->div; n++) { if (n < sizeof(rx_tuning_result) / sizeof (rx_tuning_result[0])) printf("RX[%d]=%d\n", n, rx_tuning_result[n]); } #endif if (curr_win_start >= 0) { if (best_win_start < 0) { best_win_start = curr_win_start; best_win_size = curr_win_size; } else if (wrap_win_size > 0) { // Wrap around case if (curr_win_size + wrap_win_size > best_win_size) { best_win_start = curr_win_start; best_win_size = curr_win_size + wrap_win_size; } } else if (best_win_size < curr_win_size) { best_win_start = curr_win_start; best_win_size = curr_win_size; } curr_win_start = -1; curr_win_size = 0; } if (best_win_start < 0) { printf("Tuning failed to find a valid window, using default rx phase\n"); ret = -1; //writel(vclk2_bak, host->base + SDHC_CLK2); } else { adj_delay = best_win_start + (best_win_size / 2); if (adj_delay >= clkc->div) adj_delay -= clkc->div; gadjust->adj_enable = 1; gadjust->cali_enable = 0; gadjust->cali_rise = 0; gadjust->adj_delay = adj_delay; sd_emmc_reg->gadjust = adjust; } printf("%s[%d]:delay = 0x%x,gadjust =0x%x\n", __func__, __LINE__, sd_emmc_reg->gdelay, sd_emmc_reg->gadjust); emmc_debug("%s [%d]: adj_delay = %d\n", __func__, __LINE__, adj_delay); free(blk_test); #ifdef MMC_HS400_MODE for (n = 0; n < clkc->div; n++) { if (n == clkc->div - 1) { if (rx_tuning_result[n] == ntries && pre_status == 1) printf("meson-mmc: emmc: [ %d -- %d ] is ok\n", start, n); else if (rx_tuning_result[n] != ntries && pre_status == -1) printf("meson-mmc: emmc: [ %d -- %d ] is nok\n", start, n); else if (rx_tuning_result[n] == ntries && pre_status != 1) printf("meson-mmc: emmc: [ %d ] is ok\n", n); else if (rx_tuning_result[n] != ntries && pre_status == 1) printf("meson-mmc: emmc: [ %d ] is nok\n", n); } if (rx_tuning_result[n] == ntries) { if (pre_status == -1) { if (start == n - 1) printf("meson-mmc: emmc: [ %d ] is nok\n", start); else printf("meson-mmc: emmc: [ %d -- %d] is nok\n", start, n-1); } else if (pre_status == 1) continue; start = n; pre_status = 1; } else if (rx_tuning_result[n] != ntries) { if (pre_status == 1) { if (start == n - 1) printf("meson-mmc: emmc: [ %d ] is ok\n", start); else printf("meson-mmc: emmc: [ %d -- %d ] is ok\n", start, n-1); } else if (pre_status == -1) continue; start = n; pre_status = -1; } } printf("meson-mmc: emmc: %s[%d]:delay1 = 0x%x, gadjust =0x%x\n", __func__, __LINE__, sd_emmc_reg->gdelay, sd_emmc_reg->gadjust); printf("meson-mmc: emmc: %s [%d]: adj_delay = %d\n", __func__, __LINE__, adj_delay); #endif /* test adj sampling point*/ /*ret = sd_emmc_test_adj(mmc);*/ return ret; } int aml_sd_calibration(struct mmc *mmc) { struct aml_card_sd_info *aml_priv = mmc->priv; struct sd_emmc_global_regs *sd_emmc_reg = aml_priv->sd_emmc_reg; cpu_id_t cpu_id = get_cpu_id(); if (cpu_id.family_id == MESON_CPU_MAJOR_ID_GXBB) sd_emmc_reg->gdelay = 0x85854055; else if (cpu_id.family_id == MESON_CPU_MAJOR_ID_GXTVBB) sd_emmc_reg->gdelay = 0x10101331; return 0; } static const struct mmc_ops aml_sd_emmc_ops = { .send_cmd = aml_sd_send_cmd, .set_ios = aml_sd_cfg_swth, .init = aml_sd_init, // .getcd = , // .getwp = , #ifdef MMC_ADJ_FIXED .calibration = aml_sd_calibration, .refix = aml_sd_retry_refix, .calc_fixed_adj = set_emmc_calc_fixed_adj, #endif #ifdef MMC_ADJ_FIX_CALC .calc = aml_fixdiv_calc, #endif }; void sd_emmc_register(struct aml_card_sd_info * aml_priv) { struct mmc_config *cfg; aml_priv->removed_flag = 1; aml_priv->inited_flag = 0; aml_priv->sd_emmc_reg = (struct sd_emmc_global_regs *)sd_emmc_base_addr[aml_priv->sd_emmc_port]; cfg = &aml_priv->cfg; cfg->name = aml_priv->name; cfg->ops = &aml_sd_emmc_ops; cfg->voltages = MMC_VDD_33_34|MMC_VDD_32_33|MMC_VDD_31_32|MMC_VDD_165_195; cfg->host_caps = MMC_MODE_8BIT|MMC_MODE_4BIT | MMC_MODE_HS_52MHz | MMC_MODE_HS | #if CONFIG_EMMC_DDR52_EN MMC_MODE_HC | MMC_MODE_DDR_52MHz; #else MMC_MODE_HC; #endif cfg->f_min = 400000; cfg->f_max = 40000000; /** * For blank emmc, part-type should be unknown. * But fastboot will not happy about this when * gpt or mbr are being flashed. * a predefined parttype had to be added here * to satisfy the fastboot. */ #ifdef CONFIG_AML_GPT cfg->part_type = PART_TYPE_EFI; #else cfg->part_type = PART_TYPE_AML; #endif cfg->b_max = 256; mmc_create(cfg,aml_priv); } bool aml_is_emmc_tsd (struct mmc *mmc) // is eMMC OR TSD { struct aml_card_sd_info * sdio=mmc->priv; return ((sdio->sd_emmc_port == SDIO_PORT_C)); }