11bd4fe43Sopenharmony_ci/* 21bd4fe43Sopenharmony_ci * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED. 31bd4fe43Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 41bd4fe43Sopenharmony_ci * you may not use this file except in compliance with the License. 51bd4fe43Sopenharmony_ci * You may obtain a copy of the License at 61bd4fe43Sopenharmony_ci * 71bd4fe43Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 81bd4fe43Sopenharmony_ci * 91bd4fe43Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 101bd4fe43Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 111bd4fe43Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 121bd4fe43Sopenharmony_ci * See the License for the specific language governing permissions and 131bd4fe43Sopenharmony_ci * limitations under the License. 141bd4fe43Sopenharmony_ci */ 151bd4fe43Sopenharmony_ci 161bd4fe43Sopenharmony_ci#include "sdhci.h" 171bd4fe43Sopenharmony_ci#include "sdhci_proc.h" 181bd4fe43Sopenharmony_ci 191bd4fe43Sopenharmony_ci#define HDF_LOG_TAG sdhci_adapter 201bd4fe43Sopenharmony_ci 211bd4fe43Sopenharmony_ci#define SDHCI_DMA_MAX_BUFF_SIZE 0x1000 221bd4fe43Sopenharmony_ci#define SDHCI_MAX_BLK_NUM 65535 231bd4fe43Sopenharmony_ci#define SDHCI_DETECET_RETRY 5 241bd4fe43Sopenharmony_ci#define SDHCI_RESET_RETRY_TIMES 100 251bd4fe43Sopenharmony_ci#define SDHCI_OFF_CLK2CARD_ON_DELAY 25 261bd4fe43Sopenharmony_ci#define SDHCI_MAX_HOST_NUM 2 271bd4fe43Sopenharmony_ci#define SDHCI_CLK_CTRL_RETRY_TIMES 20 281bd4fe43Sopenharmony_ci#define SDHCI_PHASE_SCALE_GAP 16 291bd4fe43Sopenharmony_ci#define SDHCI_DIV_MIDDLE 2 301bd4fe43Sopenharmony_ci#define SDHCI_CART_PLUG_STATE (SDHCI_INTERRUPT_CARD_INSERT | SDHCI_INTERRUPT_CARD_REMOVE) 311bd4fe43Sopenharmony_ci#define SDHCI_PLUG_STATE(h) (SdhciReadl(h, PSTATE_R) & SDHCI_CARD_PRESENT) 321bd4fe43Sopenharmony_ci 331bd4fe43Sopenharmony_cistatic void SdhciDumpregs(struct SdhciHost *host) 341bd4fe43Sopenharmony_ci{ 351bd4fe43Sopenharmony_ci HDF_LOGE(": =========== DUMP (host%u) REGISTER===========", host->hostId); 361bd4fe43Sopenharmony_ci HDF_LOGE(": Sys addr: 0x%08x | Version: 0x%04x", 371bd4fe43Sopenharmony_ci SdhciReadl(host, SDMASA_R), SdhciReadw(host, HOST_VERSION_R)); 381bd4fe43Sopenharmony_ci HDF_LOGE(": Blk size: 0x%04x | Blk cnt: 0x%04x", 391bd4fe43Sopenharmony_ci SdhciReadw(host, BLOCKSIZE_R), SdhciReadw(host, BLOCKCOUNT_R)); 401bd4fe43Sopenharmony_ci HDF_LOGE(": Argument: 0x%08x | Trn mode: 0x%04x", 411bd4fe43Sopenharmony_ci SdhciReadl(host, ARGUMENT_R), SdhciReadw(host, XFER_MODE_R)); 421bd4fe43Sopenharmony_ci HDF_LOGE(": Present: 0x%08x | Host ctl: 0x%08x", 431bd4fe43Sopenharmony_ci SdhciReadl(host, PSTATE_R), SdhciReadb(host, HOST_CTRL1_R)); 441bd4fe43Sopenharmony_ci HDF_LOGE(": Power: 0x%08x | Blk gap: 0x%08x", 451bd4fe43Sopenharmony_ci SdhciReadb(host, PWR_CTRL_R), SdhciReadb(host, BLOCK_GAP_CTRL_R)); 461bd4fe43Sopenharmony_ci HDF_LOGE(": Wake-up: 0x%08x | Clock: 0x%04x", 471bd4fe43Sopenharmony_ci SdhciReadb(host, WUP_CTRL_R), SdhciReadw(host, CLK_CTRL_R)); 481bd4fe43Sopenharmony_ci HDF_LOGE(": Timeout: 0x%08x | Int stat: 0x%08x", 491bd4fe43Sopenharmony_ci SdhciReadb(host, TOUT_CTRL_R), SdhciReadl(host, NORMAL_INT_STAT_R)); 501bd4fe43Sopenharmony_ci HDF_LOGE(": Int enab: 0x%08x | Sig enab: 0x%08x", 511bd4fe43Sopenharmony_ci SdhciReadl(host, NORMAL_INT_STAT_EN_R), SdhciReadl(host, NORMAL_INT_SIGNAL_EN_R)); 521bd4fe43Sopenharmony_ci HDF_LOGE(": ACMD err: 0x%04x | Slot int: 0x%04x", 531bd4fe43Sopenharmony_ci SdhciReadw(host, AUTO_CMD_STAT_R), SdhciReadw(host, SLOT_INT_STATUS_R)); 541bd4fe43Sopenharmony_ci HDF_LOGE(": Caps_1: 0x%08x | Caps_2: 0x%08x", 551bd4fe43Sopenharmony_ci SdhciReadl(host, CAPABILITIES1_R), SdhciReadl(host, CAPABILITIES2_R)); 561bd4fe43Sopenharmony_ci HDF_LOGE(": Cmd: 0x%04x | Max curr: 0x%08x | opcode = %d", 571bd4fe43Sopenharmony_ci SdhciReadw(host, CMD_R), SdhciReadl(host, CURR_CAPBILITIES1_R), (SdhciReadw(host, CMD_R) >> 8) & 0x1f); 581bd4fe43Sopenharmony_ci HDF_LOGE(": Resp 1: 0x%08x | Resp 0: 0x%08x", 591bd4fe43Sopenharmony_ci SdhciReadl(host, RESP01_R + 0x4), SdhciReadl(host, RESP01_R)); 601bd4fe43Sopenharmony_ci HDF_LOGE(": Resp 3: 0x%08x | Resp 2: 0x%08x", 611bd4fe43Sopenharmony_ci SdhciReadl(host, RESP01_R + 0xC), SdhciReadl(host, RESP01_R + 0x8)); 621bd4fe43Sopenharmony_ci HDF_LOGE(": Host ctl2: 0x%04x", SdhciReadw(host, HOST_CTRL2_R)); 631bd4fe43Sopenharmony_ci HDF_LOGE(": Emmc ctrl: 0x%04x | Multi cycle 0x%08x", 641bd4fe43Sopenharmony_ci SdhciReadw(host, EMMC_CTRL_R), SdhciReadl(host, MULTI_CYCLE_R)); 651bd4fe43Sopenharmony_ci if (host->flags & SDHCI_USE_64BIT_ADMA) { 661bd4fe43Sopenharmony_ci HDF_LOGE(": ADMA Err: 0x%08x\n", SdhciReadl(host, ADMA_ERR_STAT_R)); 671bd4fe43Sopenharmony_ci HDF_LOGE(": ADMA Addr(0:31): 0x%08x | ADMA Addr(32:63): 0x%08x", 681bd4fe43Sopenharmony_ci SdhciReadl(host, ADMA_SA_LOW_R), SdhciReadl(host, ADMA_SA_HIGH_R)); 691bd4fe43Sopenharmony_ci } else if (host->flags & SDHCI_USE_ADMA) { 701bd4fe43Sopenharmony_ci HDF_LOGE(": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x", 711bd4fe43Sopenharmony_ci SdhciReadl(host, ADMA_ERR_STAT_R), SdhciReadl(host, ADMA_SA_LOW_R)); 721bd4fe43Sopenharmony_ci } 731bd4fe43Sopenharmony_ci HDF_LOGE(": ==========================================="); 741bd4fe43Sopenharmony_ci} 751bd4fe43Sopenharmony_ci 761bd4fe43Sopenharmony_cistatic void SdhciDmaCacheClean(void *addr, uint32_t size) 771bd4fe43Sopenharmony_ci{ 781bd4fe43Sopenharmony_ci addr = (void *)(uintptr_t)DMA_TO_VMM_ADDR((paddr_t)(uintptr_t)addr); 791bd4fe43Sopenharmony_ci uint32_t start = (uintptr_t)addr & ~(CACHE_ALIGNED_SIZE - 1); 801bd4fe43Sopenharmony_ci uint32_t end = (uintptr_t)addr + size; 811bd4fe43Sopenharmony_ci 821bd4fe43Sopenharmony_ci end = ALIGN(end, CACHE_ALIGNED_SIZE); 831bd4fe43Sopenharmony_ci DCacheFlushRange(start, end); 841bd4fe43Sopenharmony_ci} 851bd4fe43Sopenharmony_ci 861bd4fe43Sopenharmony_cistatic void SdhciDmaCacheInv(void *addr, uint32_t size) 871bd4fe43Sopenharmony_ci{ 881bd4fe43Sopenharmony_ci addr = (void *)(uintptr_t)DMA_TO_VMM_ADDR((paddr_t)(uintptr_t)addr); 891bd4fe43Sopenharmony_ci uint32_t start = (uintptr_t)addr & ~(CACHE_ALIGNED_SIZE - 1); 901bd4fe43Sopenharmony_ci uint32_t end = (uintptr_t)addr + size; 911bd4fe43Sopenharmony_ci 921bd4fe43Sopenharmony_ci end = ALIGN(end, CACHE_ALIGNED_SIZE); 931bd4fe43Sopenharmony_ci DCacheInvRange(start, end); 941bd4fe43Sopenharmony_ci} 951bd4fe43Sopenharmony_ci 961bd4fe43Sopenharmony_cistatic void SdhciEnablePlugIrq(struct SdhciHost *host, uint32_t irq) 971bd4fe43Sopenharmony_ci{ 981bd4fe43Sopenharmony_ci SdhciWritel(host, irq, NORMAL_INT_STAT_EN_R); 991bd4fe43Sopenharmony_ci SdhciWritel(host, irq, NORMAL_INT_SIGNAL_EN_R); 1001bd4fe43Sopenharmony_ci} 1011bd4fe43Sopenharmony_ci 1021bd4fe43Sopenharmony_cistatic void SdhciSetCardDetection(struct SdhciHost *host, bool enable) 1031bd4fe43Sopenharmony_ci{ 1041bd4fe43Sopenharmony_ci uint32_t present; 1051bd4fe43Sopenharmony_ci 1061bd4fe43Sopenharmony_ci if (host->mmc->caps.bits.nonremovable > 0 || 1071bd4fe43Sopenharmony_ci host->quirks.bits.forceSWDetect > 0 || 1081bd4fe43Sopenharmony_ci host->quirks.bits.brokenCardDetection > 0) { 1091bd4fe43Sopenharmony_ci return; 1101bd4fe43Sopenharmony_ci } 1111bd4fe43Sopenharmony_ci 1121bd4fe43Sopenharmony_ci if (enable == true) { 1131bd4fe43Sopenharmony_ci present = SdhciReadl(host, PSTATE_R) & SDHCI_CARD_PRESENT; 1141bd4fe43Sopenharmony_ci host->irqEnable |= (present ? SDHCI_INTERRUPT_CARD_REMOVE : SDHCI_INTERRUPT_CARD_INSERT); 1151bd4fe43Sopenharmony_ci } else { 1161bd4fe43Sopenharmony_ci host->irqEnable &= (~(SDHCI_INTERRUPT_CARD_REMOVE | SDHCI_INTERRUPT_CARD_INSERT)); 1171bd4fe43Sopenharmony_ci } 1181bd4fe43Sopenharmony_ci} 1191bd4fe43Sopenharmony_ci 1201bd4fe43Sopenharmony_cistatic void SdhciEnableCardDetection(struct SdhciHost *host) 1211bd4fe43Sopenharmony_ci{ 1221bd4fe43Sopenharmony_ci SdhciSetCardDetection(host, true); 1231bd4fe43Sopenharmony_ci SdhciWritel(host, host->irqEnable, NORMAL_INT_STAT_EN_R); 1241bd4fe43Sopenharmony_ci SdhciWritel(host, host->irqEnable, NORMAL_INT_SIGNAL_EN_R); 1251bd4fe43Sopenharmony_ci} 1261bd4fe43Sopenharmony_ci 1271bd4fe43Sopenharmony_cistatic void SdhciReset(struct SdhciHost *host, uint32_t mask) 1281bd4fe43Sopenharmony_ci{ 1291bd4fe43Sopenharmony_ci uint32_t i; 1301bd4fe43Sopenharmony_ci uint8_t reg; 1311bd4fe43Sopenharmony_ci 1321bd4fe43Sopenharmony_ci SdhciWriteb(host, mask, SW_RST_R); 1331bd4fe43Sopenharmony_ci /* hw clears the bit when it's done */ 1341bd4fe43Sopenharmony_ci for (i = 0; i < SDHCI_RESET_RETRY_TIMES; i++) { 1351bd4fe43Sopenharmony_ci reg = SdhciReadb(host, SW_RST_R); 1361bd4fe43Sopenharmony_ci if ((reg & mask) == 0) { 1371bd4fe43Sopenharmony_ci return; 1381bd4fe43Sopenharmony_ci } 1391bd4fe43Sopenharmony_ci OsalMDelay(1); 1401bd4fe43Sopenharmony_ci } 1411bd4fe43Sopenharmony_ci 1421bd4fe43Sopenharmony_ci HDF_LOGE("host%u: Reset 0x%x never completed.", host->hostId, mask); 1431bd4fe43Sopenharmony_ci SdhciDumpregs(host); 1441bd4fe43Sopenharmony_ci} 1451bd4fe43Sopenharmony_ci 1461bd4fe43Sopenharmony_cistatic void SdhciDoReset(struct SdhciHost *host, uint32_t mask) 1471bd4fe43Sopenharmony_ci{ 1481bd4fe43Sopenharmony_ci SdhciReset(host, mask); 1491bd4fe43Sopenharmony_ci 1501bd4fe43Sopenharmony_ci if ((mask & SDHCI_RESET_ALL) > 0) { 1511bd4fe43Sopenharmony_ci host->presetEnabled = false; 1521bd4fe43Sopenharmony_ci host->clock = 0; 1531bd4fe43Sopenharmony_ci } 1541bd4fe43Sopenharmony_ci} 1551bd4fe43Sopenharmony_ci 1561bd4fe43Sopenharmony_cistatic void SdhciSetTransferMode(struct SdhciHost *host, struct MmcCmd *cmd) 1571bd4fe43Sopenharmony_ci{ 1581bd4fe43Sopenharmony_ci uint16_t mode; 1591bd4fe43Sopenharmony_ci 1601bd4fe43Sopenharmony_ci if (cmd->data == NULL) { 1611bd4fe43Sopenharmony_ci mode = SdhciReadw(host, XFER_MODE_R); 1621bd4fe43Sopenharmony_ci SdhciWritew(host, (mode & (~(SDHCI_TRNS_AUTO_CMD12 | SDHCI_TRNS_AUTO_CMD23))), XFER_MODE_R); 1631bd4fe43Sopenharmony_ci return; 1641bd4fe43Sopenharmony_ci } 1651bd4fe43Sopenharmony_ci 1661bd4fe43Sopenharmony_ci mode = SDHCI_TRNS_BLK_CNT_EN; 1671bd4fe43Sopenharmony_ci if (cmd->cmdCode == WRITE_MULTIPLE_BLOCK || cmd->cmdCode == READ_MULTIPLE_BLOCK || cmd->data->blockNum > 1) { 1681bd4fe43Sopenharmony_ci mode |= SDHCI_TRNS_MULTI; 1691bd4fe43Sopenharmony_ci if ((host->mmc->devType == MMC_DEV_SD && (MmcCntlrSdSupportCmd23(host->mmc) == false)) || 1701bd4fe43Sopenharmony_ci (host->mmc->devType == MMC_DEV_EMMC && (MmcCntlrEmmcSupportCmd23(host->mmc) == false))) { 1711bd4fe43Sopenharmony_ci mode |= SDHCI_TRNS_AUTO_CMD12; 1721bd4fe43Sopenharmony_ci } else { 1731bd4fe43Sopenharmony_ci if ((host->flags & SDHCI_AUTO_CMD23)) { 1741bd4fe43Sopenharmony_ci mode |= SDHCI_TRNS_AUTO_CMD23; 1751bd4fe43Sopenharmony_ci SdhciWritel(host, cmd->data->blockNum, SDHCI_ARGUMENT2); 1761bd4fe43Sopenharmony_ci } else if ((host->flags & SDHCI_AUTO_CMD12) > 0) { 1771bd4fe43Sopenharmony_ci mode |= SDHCI_TRNS_AUTO_CMD12; 1781bd4fe43Sopenharmony_ci } 1791bd4fe43Sopenharmony_ci } 1801bd4fe43Sopenharmony_ci } 1811bd4fe43Sopenharmony_ci 1821bd4fe43Sopenharmony_ci if ((cmd->data->dataFlags & DATA_READ) > 0) { 1831bd4fe43Sopenharmony_ci mode |= SDHCI_TRNS_READ; 1841bd4fe43Sopenharmony_ci } 1851bd4fe43Sopenharmony_ci if ((host->flags & SDHCI_REQ_USE_DMA) > 0) { 1861bd4fe43Sopenharmony_ci mode |= SDHCI_TRNS_DMA; 1871bd4fe43Sopenharmony_ci } 1881bd4fe43Sopenharmony_ci SdhciWritew(host, mode, XFER_MODE_R); 1891bd4fe43Sopenharmony_ci} 1901bd4fe43Sopenharmony_ci 1911bd4fe43Sopenharmony_cistatic void SdhciTaskletFinish(struct SdhciHost *host) 1921bd4fe43Sopenharmony_ci{ 1931bd4fe43Sopenharmony_ci struct MmcCmd *cmd = host->cmd; 1941bd4fe43Sopenharmony_ci 1951bd4fe43Sopenharmony_ci if (!(host->flags & SDHCI_DEVICE_DEAD) && 1961bd4fe43Sopenharmony_ci ((cmd->returnError != 0) || (cmd->data != NULL && cmd->data->returnError != 0))) { 1971bd4fe43Sopenharmony_ci SdhciDoReset(host, SDHCI_RESET_CMD); 1981bd4fe43Sopenharmony_ci SdhciDoReset(host, SDHCI_RESET_DATA); 1991bd4fe43Sopenharmony_ci } 2001bd4fe43Sopenharmony_ci 2011bd4fe43Sopenharmony_ci host->cmd = NULL; 2021bd4fe43Sopenharmony_ci (void)SDHCI_EVENT_SIGNAL(&host->sdhciEvent, SDHCI_PEND_REQUEST_DONE); 2031bd4fe43Sopenharmony_ci} 2041bd4fe43Sopenharmony_ci 2051bd4fe43Sopenharmony_cistatic uint32_t SdhciGenerateCmdFlag(struct MmcCmd *cmd) 2061bd4fe43Sopenharmony_ci{ 2071bd4fe43Sopenharmony_ci uint32_t flags; 2081bd4fe43Sopenharmony_ci 2091bd4fe43Sopenharmony_ci if ((cmd->respType & RESP_PRESENT) == 0) { 2101bd4fe43Sopenharmony_ci flags = SDHCI_CMD_NONE_RESP; 2111bd4fe43Sopenharmony_ci } else if ((cmd->respType & RESP_136) > 0) { 2121bd4fe43Sopenharmony_ci flags = SDHCI_CMD_LONG_RESP; 2131bd4fe43Sopenharmony_ci } else if ((cmd->respType & RESP_BUSY) > 0) { 2141bd4fe43Sopenharmony_ci flags = SDHCI_CMD_SHORT_RESP_BUSY; 2151bd4fe43Sopenharmony_ci } else { 2161bd4fe43Sopenharmony_ci flags = SDHCI_CMD_SHORT_RESP; 2171bd4fe43Sopenharmony_ci } 2181bd4fe43Sopenharmony_ci 2191bd4fe43Sopenharmony_ci if ((cmd->respType & RESP_CRC) > 0) { 2201bd4fe43Sopenharmony_ci flags |= SDHCI_CMD_CRC_CHECK_ENABLE; 2211bd4fe43Sopenharmony_ci } 2221bd4fe43Sopenharmony_ci if ((cmd->respType & RESP_CMDCODE) > 0) { 2231bd4fe43Sopenharmony_ci flags |= SDHCI_CMD_INDEX_CHECK_ENABLE; 2241bd4fe43Sopenharmony_ci } 2251bd4fe43Sopenharmony_ci 2261bd4fe43Sopenharmony_ci /* CMD19 is special in that the Data Present Select should be set */ 2271bd4fe43Sopenharmony_ci if (cmd->data != NULL || cmd->cmdCode == SD_CMD_SEND_TUNING_BLOCK || cmd->cmdCode == SEND_TUNING_BLOCK_HS200) { 2281bd4fe43Sopenharmony_ci flags |= SDHCI_CMD_DATA_TX; 2291bd4fe43Sopenharmony_ci } 2301bd4fe43Sopenharmony_ci 2311bd4fe43Sopenharmony_ci return flags; 2321bd4fe43Sopenharmony_ci} 2331bd4fe43Sopenharmony_ci 2341bd4fe43Sopenharmony_cistatic void SdhciSetDmaConfig(struct SdhciHost *host) 2351bd4fe43Sopenharmony_ci{ 2361bd4fe43Sopenharmony_ci uint8_t ctrl; 2371bd4fe43Sopenharmony_ci 2381bd4fe43Sopenharmony_ci if (host->version < SDHCI_HOST_SPEC_200) { 2391bd4fe43Sopenharmony_ci return; 2401bd4fe43Sopenharmony_ci } 2411bd4fe43Sopenharmony_ci 2421bd4fe43Sopenharmony_ci ctrl = SdhciReadb(host, HOST_CTRL1_R); 2431bd4fe43Sopenharmony_ci ctrl &= ~SDHCI_CTRL_DMA_ENABLE_MASK; 2441bd4fe43Sopenharmony_ci if ((host->flags & SDHCI_REQ_USE_DMA) && (host->flags & SDHCI_USE_ADMA)) { 2451bd4fe43Sopenharmony_ci if (host->flags & SDHCI_USE_64BIT_ADMA) { 2461bd4fe43Sopenharmony_ci ctrl |= SDHCI_CTRL_ADMA64_ENABLE; 2471bd4fe43Sopenharmony_ci } else { 2481bd4fe43Sopenharmony_ci ctrl |= SDHCI_CTRL_ADMA32_ENABLE; 2491bd4fe43Sopenharmony_ci } 2501bd4fe43Sopenharmony_ci } else { 2511bd4fe43Sopenharmony_ci ctrl |= SDHCI_CTRL_SDMA_ENABLE; 2521bd4fe43Sopenharmony_ci } 2531bd4fe43Sopenharmony_ci SdhciWriteb(host, ctrl, HOST_CTRL1_R); 2541bd4fe43Sopenharmony_ci} 2551bd4fe43Sopenharmony_ci 2561bd4fe43Sopenharmony_cistatic void SdhciSetTransferIrqs(struct SdhciHost *host) 2571bd4fe43Sopenharmony_ci{ 2581bd4fe43Sopenharmony_ci uint32_t pioIrqs = SDHCI_INTERRUPT_DATA_AVAIL | SDHCI_INTERRUPT_SPACE_AVAIL; 2591bd4fe43Sopenharmony_ci uint32_t dmaIrqs = SDHCI_INTERRUPT_DMA_END | SDHCI_INTERRUPT_ADMA_ERROR; 2601bd4fe43Sopenharmony_ci 2611bd4fe43Sopenharmony_ci if (host->flags & SDHCI_REQ_USE_DMA) { 2621bd4fe43Sopenharmony_ci host->irqEnable = (host->irqEnable & ~pioIrqs) | dmaIrqs; 2631bd4fe43Sopenharmony_ci } else { 2641bd4fe43Sopenharmony_ci host->irqEnable = (host->irqEnable & ~dmaIrqs) | pioIrqs; 2651bd4fe43Sopenharmony_ci } 2661bd4fe43Sopenharmony_ci SdhciEnablePlugIrq(host, host->irqEnable); 2671bd4fe43Sopenharmony_ci} 2681bd4fe43Sopenharmony_ci 2691bd4fe43Sopenharmony_cistatic void SdhciSetBlkSizeReg(struct SdhciHost *host, uint32_t blksz, uint32_t sdmaBoundary) 2701bd4fe43Sopenharmony_ci{ 2711bd4fe43Sopenharmony_ci if (host->flags & SDHCI_USE_ADMA) { 2721bd4fe43Sopenharmony_ci SdhciWritel(host, SDHCI_MAKE_BLKSZ(7, blksz), BLOCKSIZE_R); 2731bd4fe43Sopenharmony_ci } else { 2741bd4fe43Sopenharmony_ci SdhciWritel(host, SDHCI_MAKE_BLKSZ(sdmaBoundary, blksz), BLOCKSIZE_R); 2751bd4fe43Sopenharmony_ci } 2761bd4fe43Sopenharmony_ci} 2771bd4fe43Sopenharmony_ci 2781bd4fe43Sopenharmony_cistatic void SdhciAdmaConfig(struct SdhciHost *host) 2791bd4fe43Sopenharmony_ci{ 2801bd4fe43Sopenharmony_ci SdhciWritel(host, 0, (uintptr_t)ADMA_SA_HIGH_R); 2811bd4fe43Sopenharmony_ci SdhciWritel(host, VMM_TO_DMA_ADDR((uintptr_t)host->admaDesc), (uintptr_t)ADMA_SA_LOW_R); 2821bd4fe43Sopenharmony_ci} 2831bd4fe43Sopenharmony_ci 2841bd4fe43Sopenharmony_cistatic void SdhciSetAdmaDesc(struct SdhciHost *host, char *desc, dma_addr_t addr, uint16_t len, uint16_t cmd) 2851bd4fe43Sopenharmony_ci{ 2861bd4fe43Sopenharmony_ci uint16_t *cmdlen = (uint16_t *)desc; 2871bd4fe43Sopenharmony_ci 2881bd4fe43Sopenharmony_ci cmdlen[0] = (cmd); 2891bd4fe43Sopenharmony_ci cmdlen[1] = (len); 2901bd4fe43Sopenharmony_ci 2911bd4fe43Sopenharmony_ci if (host->flags & SDHCI_USE_64BIT_ADMA) { 2921bd4fe43Sopenharmony_ci unsigned long *dataddr = (unsigned long*)(desc + 4); 2931bd4fe43Sopenharmony_ci dataddr[0] = (addr); 2941bd4fe43Sopenharmony_ci } else { 2951bd4fe43Sopenharmony_ci uint32_t *dataddr = (uint32_t *)(desc + 4); 2961bd4fe43Sopenharmony_ci dataddr[0] = (addr); 2971bd4fe43Sopenharmony_ci } 2981bd4fe43Sopenharmony_ci} 2991bd4fe43Sopenharmony_ci 3001bd4fe43Sopenharmony_cistatic void SdhciAdmaMarkEnd(void *desc) 3011bd4fe43Sopenharmony_ci{ 3021bd4fe43Sopenharmony_ci uint16_t *d = (uint16_t *)desc; 3031bd4fe43Sopenharmony_ci 3041bd4fe43Sopenharmony_ci d[0] |= ADMA2_END; 3051bd4fe43Sopenharmony_ci} 3061bd4fe43Sopenharmony_ci 3071bd4fe43Sopenharmony_cistatic int32_t SdhciAdmaTablePre(struct SdhciHost *host, struct MmcData *data) 3081bd4fe43Sopenharmony_ci{ 3091bd4fe43Sopenharmony_ci char *admaDesc = NULL; 3101bd4fe43Sopenharmony_ci dma_addr_t addr; 3111bd4fe43Sopenharmony_ci uint32_t len, i; 3121bd4fe43Sopenharmony_ci uint32_t dmaDir = DMA_TO_DEVICE; 3131bd4fe43Sopenharmony_ci 3141bd4fe43Sopenharmony_ci if (data->dataFlags & DATA_READ) { 3151bd4fe43Sopenharmony_ci dmaDir = DMA_FROM_DEVICE; 3161bd4fe43Sopenharmony_ci } 3171bd4fe43Sopenharmony_ci 3181bd4fe43Sopenharmony_ci admaDesc = host->admaDesc; 3191bd4fe43Sopenharmony_ci (void)memset_s(admaDesc, ALIGN(host->admaDescSize, CACHE_ALIGNED_SIZE), 3201bd4fe43Sopenharmony_ci 0, ALIGN(host->admaDescSize, CACHE_ALIGNED_SIZE)); 3211bd4fe43Sopenharmony_ci 3221bd4fe43Sopenharmony_ci for (i = 0; i < host->dmaSgCount; i++) { 3231bd4fe43Sopenharmony_ci addr = SDHCI_SG_DMA_ADDRESS(&host->sg[i]); 3241bd4fe43Sopenharmony_ci len = SDHCI_SG_DMA_LEN(&host->sg[i]); 3251bd4fe43Sopenharmony_ci if (dmaDir == DMA_TO_DEVICE) { 3261bd4fe43Sopenharmony_ci SdhciDmaCacheClean((void*)addr, len); 3271bd4fe43Sopenharmony_ci } else { 3281bd4fe43Sopenharmony_ci SdhciDmaCacheInv((void*)addr, len); 3291bd4fe43Sopenharmony_ci } 3301bd4fe43Sopenharmony_ci 3311bd4fe43Sopenharmony_ci while (len > 0) { 3321bd4fe43Sopenharmony_ci if (len > SDHCI_DMA_MAX_BUFF_SIZE) { 3331bd4fe43Sopenharmony_ci SdhciSetAdmaDesc(host, admaDesc, addr, SDHCI_DMA_MAX_BUFF_SIZE, 0x21); 3341bd4fe43Sopenharmony_ci len -= SDHCI_DMA_MAX_BUFF_SIZE; 3351bd4fe43Sopenharmony_ci addr += SDHCI_DMA_MAX_BUFF_SIZE; 3361bd4fe43Sopenharmony_ci } else { 3371bd4fe43Sopenharmony_ci SdhciSetAdmaDesc(host, admaDesc, addr, len, 0x21); 3381bd4fe43Sopenharmony_ci len = 0; 3391bd4fe43Sopenharmony_ci } 3401bd4fe43Sopenharmony_ci admaDesc += host->admaDescLineSize; 3411bd4fe43Sopenharmony_ci } 3421bd4fe43Sopenharmony_ci 3431bd4fe43Sopenharmony_ci if ((uint32_t)(admaDesc - host->admaDesc) > host->admaDescSize) { 3441bd4fe43Sopenharmony_ci HDF_LOGE("check wrong!"); 3451bd4fe43Sopenharmony_ci } 3461bd4fe43Sopenharmony_ci } 3471bd4fe43Sopenharmony_ci 3481bd4fe43Sopenharmony_ci if (host->quirks.bits.noEndattrInNopdesc) { 3491bd4fe43Sopenharmony_ci /* Mark the last descriptor as the terminating descriptor */ 3501bd4fe43Sopenharmony_ci if (admaDesc != host->admaDesc) { 3511bd4fe43Sopenharmony_ci admaDesc -= host->admaDescLineSize; 3521bd4fe43Sopenharmony_ci SdhciAdmaMarkEnd(admaDesc); 3531bd4fe43Sopenharmony_ci } 3541bd4fe43Sopenharmony_ci } else { 3551bd4fe43Sopenharmony_ci SdhciSetAdmaDesc(host, admaDesc, 0, 0, 0x3); 3561bd4fe43Sopenharmony_ci } 3571bd4fe43Sopenharmony_ci SdhciDmaCacheClean((void*)VMM_TO_DMA_ADDR((uintptr_t)host->admaDesc), 3581bd4fe43Sopenharmony_ci ALIGN(host->admaDescSize, CACHE_ALIGNED_SIZE)); 3591bd4fe43Sopenharmony_ci 3601bd4fe43Sopenharmony_ci return 0; 3611bd4fe43Sopenharmony_ci} 3621bd4fe43Sopenharmony_ci 3631bd4fe43Sopenharmony_cistatic void SdhciPrepareData(struct SdhciHost *host) 3641bd4fe43Sopenharmony_ci{ 3651bd4fe43Sopenharmony_ci struct MmcCmd *cmd = host->cmd; 3661bd4fe43Sopenharmony_ci struct MmcData *data = cmd->data; 3671bd4fe43Sopenharmony_ci int32_t retval; 3681bd4fe43Sopenharmony_ci 3691bd4fe43Sopenharmony_ci /* set timeout value , use default value. */ 3701bd4fe43Sopenharmony_ci if (data != NULL || (cmd->respType & RESP_BUSY) > 0) { 3711bd4fe43Sopenharmony_ci SdhciWriteb(host, SDHCI_DEFINE_TIMEOUT, TOUT_CTRL_R); 3721bd4fe43Sopenharmony_ci } 3731bd4fe43Sopenharmony_ci if (data == NULL) { 3741bd4fe43Sopenharmony_ci return; 3751bd4fe43Sopenharmony_ci } 3761bd4fe43Sopenharmony_ci 3771bd4fe43Sopenharmony_ci if (host->flags & (SDHCI_USE_ADMA | SDHCI_USE_SDMA)) { 3781bd4fe43Sopenharmony_ci host->flags |= SDHCI_REQ_USE_DMA; 3791bd4fe43Sopenharmony_ci } 3801bd4fe43Sopenharmony_ci 3811bd4fe43Sopenharmony_ci if (host->flags & SDHCI_REQ_USE_DMA) { 3821bd4fe43Sopenharmony_ci if (host->flags & SDHCI_USE_ADMA) { 3831bd4fe43Sopenharmony_ci /* ADMA config */ 3841bd4fe43Sopenharmony_ci retval = SdhciAdmaTablePre(host, data); 3851bd4fe43Sopenharmony_ci if (retval) { 3861bd4fe43Sopenharmony_ci host->flags &= ~SDHCI_REQ_USE_DMA; 3871bd4fe43Sopenharmony_ci } else { 3881bd4fe43Sopenharmony_ci SdhciWritel(host, 0, SDHCI_DMA_ADDRESS); 3891bd4fe43Sopenharmony_ci SdhciAdmaConfig(host); 3901bd4fe43Sopenharmony_ci } 3911bd4fe43Sopenharmony_ci } else { 3921bd4fe43Sopenharmony_ci /* SDMA config */ 3931bd4fe43Sopenharmony_ci SdhciWritel(host, SDHCI_SG_DMA_ADDRESS(&host->sg[0]), SDHCI_DMA_ADDRESS); 3941bd4fe43Sopenharmony_ci } 3951bd4fe43Sopenharmony_ci } 3961bd4fe43Sopenharmony_ci 3971bd4fe43Sopenharmony_ci SdhciSetDmaConfig(host); 3981bd4fe43Sopenharmony_ci SdhciSetTransferIrqs(host); 3991bd4fe43Sopenharmony_ci SdhciSetBlkSizeReg(host, data->blockSize, SDHCI_DEFAULT_BOUNDARY_ARG); 4001bd4fe43Sopenharmony_ci SdhciWritew(host, data->blockNum, BLOCKCOUNT_R); 4011bd4fe43Sopenharmony_ci} 4021bd4fe43Sopenharmony_ci 4031bd4fe43Sopenharmony_cistatic void SdhciExecCmd(struct SdhciHost *host, struct MmcCmd *cmd) 4041bd4fe43Sopenharmony_ci{ 4051bd4fe43Sopenharmony_ci uint32_t mask, flags; 4061bd4fe43Sopenharmony_ci uint32_t timeout = 10; /* 10ms */ 4071bd4fe43Sopenharmony_ci 4081bd4fe43Sopenharmony_ci mask = SDHCI_CMD_INVALID; 4091bd4fe43Sopenharmony_ci if ((cmd->data != NULL) || ((cmd->respType & RESP_BUSY) > 0)) { 4101bd4fe43Sopenharmony_ci mask |= SDHCI_DATA_INVALID; 4111bd4fe43Sopenharmony_ci } 4121bd4fe43Sopenharmony_ci 4131bd4fe43Sopenharmony_ci if ((cmd->data != NULL) && (cmd->data->sendStopCmd == true)) { 4141bd4fe43Sopenharmony_ci mask &= ~SDHCI_DATA_INVALID; 4151bd4fe43Sopenharmony_ci } 4161bd4fe43Sopenharmony_ci 4171bd4fe43Sopenharmony_ci /* wait host ready */ 4181bd4fe43Sopenharmony_ci while (SdhciReadl(host, PSTATE_R) & mask) { 4191bd4fe43Sopenharmony_ci if (timeout == 0) { 4201bd4fe43Sopenharmony_ci HDF_LOGE("exec cmd %u timeout!\n", cmd->cmdCode); 4211bd4fe43Sopenharmony_ci SdhciDumpregs(host); 4221bd4fe43Sopenharmony_ci cmd->returnError = HDF_ERR_IO; 4231bd4fe43Sopenharmony_ci SdhciTaskletFinish(host); 4241bd4fe43Sopenharmony_ci return; 4251bd4fe43Sopenharmony_ci } 4261bd4fe43Sopenharmony_ci timeout--; 4271bd4fe43Sopenharmony_ci OsalMDelay(1); 4281bd4fe43Sopenharmony_ci } 4291bd4fe43Sopenharmony_ci 4301bd4fe43Sopenharmony_ci host->cmd = cmd; 4311bd4fe43Sopenharmony_ci SdhciPrepareData(host); 4321bd4fe43Sopenharmony_ci SdhciWritel(host, cmd->argument, ARGUMENT_R); 4331bd4fe43Sopenharmony_ci SdhciSetTransferMode(host, cmd); 4341bd4fe43Sopenharmony_ci 4351bd4fe43Sopenharmony_ci if ((cmd->respType & RESP_136) && (cmd->respType & RESP_BUSY)) { 4361bd4fe43Sopenharmony_ci HDF_LOGE("host%u: Unsupported response type!", host->hostId); 4371bd4fe43Sopenharmony_ci cmd->returnError = HDF_FAILURE; 4381bd4fe43Sopenharmony_ci SdhciTaskletFinish(host); 4391bd4fe43Sopenharmony_ci return; 4401bd4fe43Sopenharmony_ci } 4411bd4fe43Sopenharmony_ci 4421bd4fe43Sopenharmony_ci flags = SdhciGenerateCmdFlag(cmd); 4431bd4fe43Sopenharmony_ci SdhciWritew(host, SDHCI_GEN_CMD(cmd->cmdCode, flags), CMD_R); 4441bd4fe43Sopenharmony_ci} 4451bd4fe43Sopenharmony_ci 4461bd4fe43Sopenharmony_cistatic bool SdhciCardPlugged(struct MmcCntlr *cntlr) 4471bd4fe43Sopenharmony_ci{ 4481bd4fe43Sopenharmony_ci struct SdhciHost *host = NULL; 4491bd4fe43Sopenharmony_ci 4501bd4fe43Sopenharmony_ci if ((cntlr == NULL) || (cntlr->priv == NULL)) { 4511bd4fe43Sopenharmony_ci return false; 4521bd4fe43Sopenharmony_ci } 4531bd4fe43Sopenharmony_ci 4541bd4fe43Sopenharmony_ci if (cntlr->devType == MMC_DEV_SDIO || cntlr->devType == MMC_DEV_EMMC) { 4551bd4fe43Sopenharmony_ci return true; 4561bd4fe43Sopenharmony_ci } 4571bd4fe43Sopenharmony_ci 4581bd4fe43Sopenharmony_ci host = (struct SdhciHost *)cntlr->priv; 4591bd4fe43Sopenharmony_ci if (host->quirks.bits.brokenCardDetection > 0 || 4601bd4fe43Sopenharmony_ci host->quirks.bits.forceSWDetect > 0) { 4611bd4fe43Sopenharmony_ci return true; 4621bd4fe43Sopenharmony_ci } 4631bd4fe43Sopenharmony_ci return ((SdhciReadl(host, PSTATE_R) & SDHCI_CARD_PRESENT) > 0 ? true : false); 4641bd4fe43Sopenharmony_ci} 4651bd4fe43Sopenharmony_ci 4661bd4fe43Sopenharmony_cistatic int32_t SdhciFillDmaSg(struct SdhciHost *host) 4671bd4fe43Sopenharmony_ci{ 4681bd4fe43Sopenharmony_ci struct MmcData *data = host->cmd->data; 4691bd4fe43Sopenharmony_ci uint32_t len = data->blockNum * data->blockSize; 4701bd4fe43Sopenharmony_ci int32_t ret; 4711bd4fe43Sopenharmony_ci 4721bd4fe43Sopenharmony_ci if (len == 0) { 4731bd4fe43Sopenharmony_ci return HDF_ERR_INVALID_PARAM; 4741bd4fe43Sopenharmony_ci } 4751bd4fe43Sopenharmony_ci 4761bd4fe43Sopenharmony_ci if (data->scatter != NULL && data->dataBuffer == NULL) { 4771bd4fe43Sopenharmony_ci host->sg = data->scatter; 4781bd4fe43Sopenharmony_ci host->dmaSgCount = data->scatterLen; 4791bd4fe43Sopenharmony_ci return HDF_SUCCESS; 4801bd4fe43Sopenharmony_ci } 4811bd4fe43Sopenharmony_ci if (data->dataBuffer == NULL) { 4821bd4fe43Sopenharmony_ci return HDF_ERR_INVALID_PARAM; 4831bd4fe43Sopenharmony_ci } 4841bd4fe43Sopenharmony_ci 4851bd4fe43Sopenharmony_ci host->alignedBuff = (uint8_t *)OsalMemAllocAlign(CACHE_ALIGNED_SIZE, ALIGN(len, CACHE_ALIGNED_SIZE)); 4861bd4fe43Sopenharmony_ci if (host->alignedBuff == NULL) { 4871bd4fe43Sopenharmony_ci HDF_LOGE("out of memory."); 4881bd4fe43Sopenharmony_ci return HDF_ERR_MALLOC_FAIL; 4891bd4fe43Sopenharmony_ci } 4901bd4fe43Sopenharmony_ci 4911bd4fe43Sopenharmony_ci ret = memcpy_s(host->alignedBuff, len, data->dataBuffer, len); 4921bd4fe43Sopenharmony_ci if (ret != EOK) { 4931bd4fe43Sopenharmony_ci HDF_LOGE("memcpy_s fail ret = %d.", ret); 4941bd4fe43Sopenharmony_ci free(host->alignedBuff); 4951bd4fe43Sopenharmony_ci host->alignedBuff = NULL; 4961bd4fe43Sopenharmony_ci return HDF_FAILURE; 4971bd4fe43Sopenharmony_ci } 4981bd4fe43Sopenharmony_ci host->buffLen = len; 4991bd4fe43Sopenharmony_ci sg_init_one(&host->dmaSg, (const void *)host->alignedBuff, len); 5001bd4fe43Sopenharmony_ci host->dmaSgCount = 1; 5011bd4fe43Sopenharmony_ci host->sg = &host->dmaSg; 5021bd4fe43Sopenharmony_ci return HDF_SUCCESS; 5031bd4fe43Sopenharmony_ci} 5041bd4fe43Sopenharmony_ci 5051bd4fe43Sopenharmony_cistatic void SdhciClearDmaSg(struct SdhciHost *host, struct MmcData *data) 5061bd4fe43Sopenharmony_ci{ 5071bd4fe43Sopenharmony_ci uint32_t len; 5081bd4fe43Sopenharmony_ci 5091bd4fe43Sopenharmony_ci if (data == NULL) { 5101bd4fe43Sopenharmony_ci return; 5111bd4fe43Sopenharmony_ci } 5121bd4fe43Sopenharmony_ci 5131bd4fe43Sopenharmony_ci len = data->blockNum * data->blockSize; 5141bd4fe43Sopenharmony_ci if (host->alignedBuff != NULL && data->dataBuffer != NULL && len > 0 && host->buffLen > 0) { 5151bd4fe43Sopenharmony_ci if ((data->dataFlags & DATA_READ) > 0) { 5161bd4fe43Sopenharmony_ci (void)memcpy_s(data->dataBuffer, len, host->alignedBuff, host->buffLen); 5171bd4fe43Sopenharmony_ci } 5181bd4fe43Sopenharmony_ci } 5191bd4fe43Sopenharmony_ci if (host->alignedBuff != NULL) { 5201bd4fe43Sopenharmony_ci OsalMemFree(host->alignedBuff); 5211bd4fe43Sopenharmony_ci host->alignedBuff = NULL; 5221bd4fe43Sopenharmony_ci } 5231bd4fe43Sopenharmony_ci host->buffLen = 0; 5241bd4fe43Sopenharmony_ci host->dmaSgCount = 0; 5251bd4fe43Sopenharmony_ci host->sg = NULL; 5261bd4fe43Sopenharmony_ci} 5271bd4fe43Sopenharmony_ci 5281bd4fe43Sopenharmony_cistatic void SdhciDataSync(struct SdhciHost *host, struct MmcData *data) 5291bd4fe43Sopenharmony_ci{ 5301bd4fe43Sopenharmony_ci uint32_t sgPhyAddr, sgLength, i; 5311bd4fe43Sopenharmony_ci 5321bd4fe43Sopenharmony_ci if ((data->dataFlags & DATA_READ) > 0) { 5331bd4fe43Sopenharmony_ci for (i = 0; i < host->dmaSgCount; i++) { 5341bd4fe43Sopenharmony_ci sgLength = SDHCI_SG_DMA_LEN(&host->sg[i]); 5351bd4fe43Sopenharmony_ci sgPhyAddr = SDHCI_SG_DMA_ADDRESS(&host->sg[i]); 5361bd4fe43Sopenharmony_ci SdhciDmaCacheInv((void *)(uintptr_t)sgPhyAddr, sgLength); 5371bd4fe43Sopenharmony_ci } 5381bd4fe43Sopenharmony_ci } 5391bd4fe43Sopenharmony_ci} 5401bd4fe43Sopenharmony_ci 5411bd4fe43Sopenharmony_cistatic int32_t SdhciDoRequest(struct MmcCntlr *cntlr, struct MmcCmd *cmd) 5421bd4fe43Sopenharmony_ci{ 5431bd4fe43Sopenharmony_ci struct SdhciHost *host = (struct SdhciHost *)cntlr->priv; 5441bd4fe43Sopenharmony_ci int32_t ret; 5451bd4fe43Sopenharmony_ci unsigned long flags = 0; 5461bd4fe43Sopenharmony_ci uint32_t timeout = SDHCI_CMD_DATA_REQ_TIMEOUT; 5471bd4fe43Sopenharmony_ci 5481bd4fe43Sopenharmony_ci (void)OsalMutexLock(&host->mutex); 5491bd4fe43Sopenharmony_ci 5501bd4fe43Sopenharmony_ci host->cmd = cmd; 5511bd4fe43Sopenharmony_ci if (cmd->data != NULL) { 5521bd4fe43Sopenharmony_ci ret = SdhciFillDmaSg(host); 5531bd4fe43Sopenharmony_ci if (ret != HDF_SUCCESS) { 5541bd4fe43Sopenharmony_ci goto _END; 5551bd4fe43Sopenharmony_ci } 5561bd4fe43Sopenharmony_ci } 5571bd4fe43Sopenharmony_ci 5581bd4fe43Sopenharmony_ci if (SdhciCardPlugged(host->mmc) == false || (host->flags & SDHCI_DEVICE_DEAD) > 0) { 5591bd4fe43Sopenharmony_ci cmd->returnError = HDF_ERR_IO; 5601bd4fe43Sopenharmony_ci HDF_LOGE("card is not present!"); 5611bd4fe43Sopenharmony_ci SdhciEnableCardDetection(host); 5621bd4fe43Sopenharmony_ci ret = HDF_ERR_IO; 5631bd4fe43Sopenharmony_ci goto _END; 5641bd4fe43Sopenharmony_ci } else { 5651bd4fe43Sopenharmony_ci SdhciExecCmd(host, cmd); 5661bd4fe43Sopenharmony_ci } 5671bd4fe43Sopenharmony_ci 5681bd4fe43Sopenharmony_ci SDHCI_IRQ_LOCK(&flags); 5691bd4fe43Sopenharmony_ci host->waitForEvent = true; 5701bd4fe43Sopenharmony_ci SDHCI_IRQ_UNLOCK(flags); 5711bd4fe43Sopenharmony_ci 5721bd4fe43Sopenharmony_ci if (cmd->data == NULL && host->quirks.bits.forceSWDetect > 0) { 5731bd4fe43Sopenharmony_ci timeout = SDHCI_CMD_REQ_TIMEOUT; 5741bd4fe43Sopenharmony_ci } 5751bd4fe43Sopenharmony_ci 5761bd4fe43Sopenharmony_ci ret = SDHCI_EVENT_WAIT(&host->sdhciEvent, SDHCI_PEND_REQUEST_DONE | SDHCI_PEND_ACCIDENT, timeout); 5771bd4fe43Sopenharmony_ci 5781bd4fe43Sopenharmony_ci SDHCI_IRQ_LOCK(&flags); 5791bd4fe43Sopenharmony_ci host->waitForEvent = false; 5801bd4fe43Sopenharmony_ci SDHCI_IRQ_UNLOCK(flags); 5811bd4fe43Sopenharmony_ci 5821bd4fe43Sopenharmony_ci if (ret != SDHCI_PEND_REQUEST_DONE) { 5831bd4fe43Sopenharmony_ci SdhciDumpregs(host); 5841bd4fe43Sopenharmony_ci cmd->returnError = HDF_ERR_TIMEOUT; 5851bd4fe43Sopenharmony_ci if (ret == SDHCI_PEND_ACCIDENT) { 5861bd4fe43Sopenharmony_ci cmd->returnError = HDF_ERR_IO; 5871bd4fe43Sopenharmony_ci } 5881bd4fe43Sopenharmony_ci SdhciDoReset(host, SDHCI_RESET_CMD); 5891bd4fe43Sopenharmony_ci SdhciDoReset(host, SDHCI_RESET_DATA); 5901bd4fe43Sopenharmony_ci host->cmd = NULL; 5911bd4fe43Sopenharmony_ci } else if (cmd->data != NULL) { 5921bd4fe43Sopenharmony_ci SdhciDataSync(host, cmd->data); 5931bd4fe43Sopenharmony_ci } 5941bd4fe43Sopenharmony_ci ret = HDF_SUCCESS; 5951bd4fe43Sopenharmony_ci_END: 5961bd4fe43Sopenharmony_ci SdhciClearDmaSg(host, cmd->data); 5971bd4fe43Sopenharmony_ci (void)OsalMutexUnlock(&host->mutex); 5981bd4fe43Sopenharmony_ci return ret; 5991bd4fe43Sopenharmony_ci} 6001bd4fe43Sopenharmony_ci 6011bd4fe43Sopenharmony_civoid SdhciResetDll(struct SdhciHost *host) 6021bd4fe43Sopenharmony_ci{ 6031bd4fe43Sopenharmony_ci uint32_t reg, value; 6041bd4fe43Sopenharmony_ci uint32_t cfgArray[] = { PERI_CRG125, PERI_CRG139 }; 6051bd4fe43Sopenharmony_ci 6061bd4fe43Sopenharmony_ci if (host->hostId >= SDHCI_MAX_HOST_NUM) { 6071bd4fe43Sopenharmony_ci return; 6081bd4fe43Sopenharmony_ci } 6091bd4fe43Sopenharmony_ci 6101bd4fe43Sopenharmony_ci reg = cfgArray[host->hostId]; 6111bd4fe43Sopenharmony_ci value = OSAL_READL((uintptr_t)reg); 6121bd4fe43Sopenharmony_ci value |= SDHCI_EMMC_DLL_RST; 6131bd4fe43Sopenharmony_ci OSAL_WRITEL(value, (uintptr_t)reg); 6141bd4fe43Sopenharmony_ci} 6151bd4fe43Sopenharmony_ci 6161bd4fe43Sopenharmony_cistatic uint32_t SdhciSelectClock(struct SdhciHost *host, uint32_t clock) 6171bd4fe43Sopenharmony_ci{ 6181bd4fe43Sopenharmony_ci uint32_t reg, realClock, value; 6191bd4fe43Sopenharmony_ci uint32_t temp = 0; 6201bd4fe43Sopenharmony_ci uint32_t cfgArray[] = { PERI_CRG125, PERI_CRG139 }; 6211bd4fe43Sopenharmony_ci 6221bd4fe43Sopenharmony_ci if (host->hostId >= SDHCI_MAX_HOST_NUM) { 6231bd4fe43Sopenharmony_ci HDF_LOGE("host id=%u is not supported!", host->hostId); 6241bd4fe43Sopenharmony_ci return 0; 6251bd4fe43Sopenharmony_ci } 6261bd4fe43Sopenharmony_ci 6271bd4fe43Sopenharmony_ci if (host->hostId == 1 && (clock > SDHCI_MMC_FREQ_50M)) { 6281bd4fe43Sopenharmony_ci HDF_LOGE("host%u doesn't support freq %u!", host->hostId, clock); 6291bd4fe43Sopenharmony_ci return 0; 6301bd4fe43Sopenharmony_ci } 6311bd4fe43Sopenharmony_ci 6321bd4fe43Sopenharmony_ci if (clock >= SDHCI_MMC_FREQ_150M) { 6331bd4fe43Sopenharmony_ci temp |= SDHCI_CLK_SEL_150M; 6341bd4fe43Sopenharmony_ci realClock = SDHCI_MMC_FREQ_150M; 6351bd4fe43Sopenharmony_ci } else if (clock >= SDHCI_MMC_FREQ_112P5M) { 6361bd4fe43Sopenharmony_ci temp |= SDHCI_CLK_SEL_112P5M; 6371bd4fe43Sopenharmony_ci realClock = SDHCI_MMC_FREQ_112P5M; 6381bd4fe43Sopenharmony_ci } else if (clock >= SDHCI_MMC_FREQ_90M) { 6391bd4fe43Sopenharmony_ci temp |= SDHCI_CLK_SEL_90M; 6401bd4fe43Sopenharmony_ci realClock = SDHCI_MMC_FREQ_90M; 6411bd4fe43Sopenharmony_ci } else if (clock >= SDHCI_MMC_FREQ_50M) { 6421bd4fe43Sopenharmony_ci temp |= SDHCI_CLK_SEL_50M; 6431bd4fe43Sopenharmony_ci realClock = SDHCI_MMC_FREQ_50M; 6441bd4fe43Sopenharmony_ci } else if (clock >= SDHCI_MMC_FREQ_25M) { 6451bd4fe43Sopenharmony_ci temp |= SDHCI_CLK_SEL_25M; 6461bd4fe43Sopenharmony_ci realClock = SDHCI_MMC_FREQ_25M; 6471bd4fe43Sopenharmony_ci } else if (clock >= SDHCI_MMC_FREQ_400K) { 6481bd4fe43Sopenharmony_ci temp |= SDHCI_CLK_SEL_400K; 6491bd4fe43Sopenharmony_ci realClock = SDHCI_MMC_FREQ_400K; 6501bd4fe43Sopenharmony_ci } else if (clock >= SDHCI_MMC_FREQ_100K) { 6511bd4fe43Sopenharmony_ci temp = SDHCI_CLK_SEL_100K; 6521bd4fe43Sopenharmony_ci realClock = SDHCI_MMC_FREQ_100K; 6531bd4fe43Sopenharmony_ci } else { 6541bd4fe43Sopenharmony_ci temp = SDHCI_CLK_SEL_100K; 6551bd4fe43Sopenharmony_ci realClock = 0; 6561bd4fe43Sopenharmony_ci } 6571bd4fe43Sopenharmony_ci 6581bd4fe43Sopenharmony_ci reg = cfgArray[host->hostId]; 6591bd4fe43Sopenharmony_ci value = OSAL_READL((uintptr_t)reg); 6601bd4fe43Sopenharmony_ci value &= ~(SDHCI_MMC_FREQ_MASK << SDHCI_MMC_FREQ_SHIFT); 6611bd4fe43Sopenharmony_ci value |= ((temp & SDHCI_MMC_FREQ_MASK) << SDHCI_MMC_FREQ_SHIFT); 6621bd4fe43Sopenharmony_ci value |= SDHCI_CKEN; 6631bd4fe43Sopenharmony_ci OSAL_WRITEL(value, (uintptr_t)reg); 6641bd4fe43Sopenharmony_ci 6651bd4fe43Sopenharmony_ci return realClock; 6661bd4fe43Sopenharmony_ci} 6671bd4fe43Sopenharmony_ci 6681bd4fe43Sopenharmony_cistatic void SdhciSetDrvPhase(uint32_t id, uint32_t phase) 6691bd4fe43Sopenharmony_ci{ 6701bd4fe43Sopenharmony_ci uint32_t value; 6711bd4fe43Sopenharmony_ci uint32_t drv[] = { PERI_CRG127, PERI_CRG136 }; 6721bd4fe43Sopenharmony_ci 6731bd4fe43Sopenharmony_ci if (id >= SDHCI_MAX_HOST_NUM) { 6741bd4fe43Sopenharmony_ci return; 6751bd4fe43Sopenharmony_ci } 6761bd4fe43Sopenharmony_ci 6771bd4fe43Sopenharmony_ci value = OSAL_READL(drv[id]); 6781bd4fe43Sopenharmony_ci value &= (~SDHCI_DRV_CLK_PHASE_MASK); 6791bd4fe43Sopenharmony_ci value |= (phase << SDHCI_DRV_CLK_PHASE_SHFT); 6801bd4fe43Sopenharmony_ci OSAL_WRITEL(value, drv[id]); 6811bd4fe43Sopenharmony_ci} 6821bd4fe43Sopenharmony_ci 6831bd4fe43Sopenharmony_cistatic void SdhciEnableSample(struct SdhciHost *host) 6841bd4fe43Sopenharmony_ci{ 6851bd4fe43Sopenharmony_ci uint32_t val; 6861bd4fe43Sopenharmony_ci 6871bd4fe43Sopenharmony_ci val = SdhciReadl(host, AT_CTRL_R); 6881bd4fe43Sopenharmony_ci val |= SDHCI_SW_TUNING_EN; 6891bd4fe43Sopenharmony_ci SdhciWritel(host, val, AT_CTRL_R); 6901bd4fe43Sopenharmony_ci} 6911bd4fe43Sopenharmony_ci 6921bd4fe43Sopenharmony_cistatic void SdhciSetSampPhase(struct SdhciHost *host, uint32_t phase) 6931bd4fe43Sopenharmony_ci{ 6941bd4fe43Sopenharmony_ci uint32_t val; 6951bd4fe43Sopenharmony_ci val = SdhciReadl(host, AT_STAT_R); 6961bd4fe43Sopenharmony_ci val = SdhciReadl(host, AT_STAT_R); 6971bd4fe43Sopenharmony_ci val &= ~SDHCI_CENTER_PH_CODE_MASK; 6981bd4fe43Sopenharmony_ci val |= phase; 6991bd4fe43Sopenharmony_ci SdhciWritel(host, val, AT_STAT_R); 7001bd4fe43Sopenharmony_ci} 7011bd4fe43Sopenharmony_ci 7021bd4fe43Sopenharmony_cistatic void SdhciSetIo(uint32_t offset, uint32_t val) 7031bd4fe43Sopenharmony_ci{ 7041bd4fe43Sopenharmony_ci uint32_t reg; 7051bd4fe43Sopenharmony_ci 7061bd4fe43Sopenharmony_ci reg = OSAL_READL(offset); 7071bd4fe43Sopenharmony_ci reg &= ~IO_DRV_MASK; 7081bd4fe43Sopenharmony_ci reg |= val & IO_DRV_MASK; 7091bd4fe43Sopenharmony_ci OSAL_WRITEL(reg, offset); 7101bd4fe43Sopenharmony_ci} 7111bd4fe43Sopenharmony_ci 7121bd4fe43Sopenharmony_cistatic void SdhciSetIodriver(uint32_t offset, uint32_t pull, uint32_t sr, uint32_t drv) 7131bd4fe43Sopenharmony_ci{ 7141bd4fe43Sopenharmony_ci SdhciSetIo(offset, pull | (sr ? IO_CFG_SR : 0) | IO_DRV_STR_SEL(drv)); 7151bd4fe43Sopenharmony_ci} 7161bd4fe43Sopenharmony_ci 7171bd4fe43Sopenharmony_cistatic void SdhciSetSdiodriver(struct SdhciHost *host) 7181bd4fe43Sopenharmony_ci{ 7191bd4fe43Sopenharmony_ci uint32_t i, count; 7201bd4fe43Sopenharmony_ci uint32_t dataRegs[] = { REG_CTRL_SDIO_DATA0, REG_CTRL_SDIO_DATA1, REG_CTRL_SDIO_DATA2, REG_CTRL_SDIO_DATA3 }; 7211bd4fe43Sopenharmony_ci 7221bd4fe43Sopenharmony_ci count = sizeof(dataRegs) / sizeof(dataRegs[0]); 7231bd4fe43Sopenharmony_ci if (host->mmc->caps.bits.cap4Bit == 0) { 7241bd4fe43Sopenharmony_ci /* only 1 pin can be initialized, because other pins are reserved to configured as other functions. */ 7251bd4fe43Sopenharmony_ci count = 1; 7261bd4fe43Sopenharmony_ci } 7271bd4fe43Sopenharmony_ci SdhciSetIodriver(REG_CTRL_SDIO_CLK, IO_CFG_PULL_DOWN, IO_CFG_SR, IO_DRV_SDIO_CLK); 7281bd4fe43Sopenharmony_ci SdhciSetIodriver(REG_CTRL_SDIO_CMD, IO_CFG_PULL_UP, 0, IO_DRV_SDIO_CMD); 7291bd4fe43Sopenharmony_ci for (i = 0; i < count; i++) { 7301bd4fe43Sopenharmony_ci SdhciSetIodriver(dataRegs[i], IO_CFG_PULL_UP, 0, IO_DRV_SDIO_DATA); 7311bd4fe43Sopenharmony_ci } 7321bd4fe43Sopenharmony_ci} 7331bd4fe43Sopenharmony_ci 7341bd4fe43Sopenharmony_cistatic void SdhciSetSdDriver(struct SdhciHost *host, enum MmcBusTiming timing) 7351bd4fe43Sopenharmony_ci{ 7361bd4fe43Sopenharmony_ci uint32_t i, count; 7371bd4fe43Sopenharmony_ci uint32_t dataRegs[] = { REG_CTRL_SD_DATA0, REG_CTRL_SD_DATA1, REG_CTRL_SD_DATA2, REG_CTRL_SD_DATA3 }; 7381bd4fe43Sopenharmony_ci 7391bd4fe43Sopenharmony_ci count = sizeof(dataRegs) / sizeof(dataRegs[0]); 7401bd4fe43Sopenharmony_ci if (host->mmc->caps.bits.cap4Bit == 0) { 7411bd4fe43Sopenharmony_ci /* only 1-pin GPIO can be initialized, because other pins are reserved to configured as other functions. */ 7421bd4fe43Sopenharmony_ci count = 1; 7431bd4fe43Sopenharmony_ci } 7441bd4fe43Sopenharmony_ci 7451bd4fe43Sopenharmony_ci switch (timing) { 7461bd4fe43Sopenharmony_ci case BUS_TIMING_SD_HS: 7471bd4fe43Sopenharmony_ci SdhciSetIodriver(REG_CTRL_SD_CLK, IO_CFG_PULL_DOWN, IO_CFG_SR, IO_DRV_SD_SDHS_CLK); 7481bd4fe43Sopenharmony_ci SdhciSetIodriver(REG_CTRL_SD_CMD, IO_CFG_PULL_UP, IO_CFG_SR, IO_DRV_SD_SDHS_CMD); 7491bd4fe43Sopenharmony_ci for (i = 0; i < count; i++) { 7501bd4fe43Sopenharmony_ci SdhciSetIodriver(dataRegs[i], IO_CFG_PULL_UP, IO_CFG_SR, IO_DRV_SD_SDHS_DATA); 7511bd4fe43Sopenharmony_ci } 7521bd4fe43Sopenharmony_ci break; 7531bd4fe43Sopenharmony_ci default: 7541bd4fe43Sopenharmony_ci SdhciSetIodriver(REG_CTRL_SD_CLK, IO_CFG_PULL_DOWN, IO_CFG_SR, IO_DRV_SD_OTHER_CLK); 7551bd4fe43Sopenharmony_ci SdhciSetIodriver(REG_CTRL_SD_CMD, IO_CFG_PULL_UP, IO_CFG_SR, IO_DRV_SD_OTHER_CMD); 7561bd4fe43Sopenharmony_ci for (i = 0; i < count; i++) { 7571bd4fe43Sopenharmony_ci SdhciSetIodriver(dataRegs[i], IO_CFG_PULL_UP, IO_CFG_SR, IO_DRV_SD_OTHER_DATA); 7581bd4fe43Sopenharmony_ci } 7591bd4fe43Sopenharmony_ci break; 7601bd4fe43Sopenharmony_ci } 7611bd4fe43Sopenharmony_ci} 7621bd4fe43Sopenharmony_ci 7631bd4fe43Sopenharmony_cistatic void SdhciSetEmmcCtrl(struct SdhciHost *host) 7641bd4fe43Sopenharmony_ci{ 7651bd4fe43Sopenharmony_ci unsigned int val; 7661bd4fe43Sopenharmony_ci 7671bd4fe43Sopenharmony_ci val = SdhciReadl(host, EMMC_CTRL_R); 7681bd4fe43Sopenharmony_ci val |= SDHCI_EMMC_CTRL_EMMC; 7691bd4fe43Sopenharmony_ci SdhciWritel(host, val, EMMC_CTRL_R); 7701bd4fe43Sopenharmony_ci} 7711bd4fe43Sopenharmony_ci 7721bd4fe43Sopenharmony_cistatic void SdhciSetEmmcDriver(struct SdhciHost *host, enum MmcBusTiming timing) 7731bd4fe43Sopenharmony_ci{ 7741bd4fe43Sopenharmony_ci uint32_t i, count; 7751bd4fe43Sopenharmony_ci uint32_t dataRegs[] = { REG_CTRL_EMMC_DATA0, REG_CTRL_EMMC_DATA1, REG_CTRL_EMMC_DATA2, REG_CTRL_EMMC_DATA3 }; 7761bd4fe43Sopenharmony_ci 7771bd4fe43Sopenharmony_ci count = sizeof(dataRegs) / sizeof(dataRegs[0]); 7781bd4fe43Sopenharmony_ci switch (timing) { 7791bd4fe43Sopenharmony_ci case BUS_TIMING_MMC_HS400: 7801bd4fe43Sopenharmony_ci SdhciSetEmmcCtrl(host); 7811bd4fe43Sopenharmony_ci SdhciSetIodriver(REG_CTRL_EMMC_CLK, IO_CFG_PULL_DOWN, 0, IO_DRV_EMMC_HS400_CLK); 7821bd4fe43Sopenharmony_ci SdhciSetIodriver(REG_CTRL_EMMC_CMD, IO_CFG_PULL_UP, 0, IO_DRV_EMMC_HS400_CMD); 7831bd4fe43Sopenharmony_ci for (i = 0; i < count; i++) { 7841bd4fe43Sopenharmony_ci SdhciSetIodriver(dataRegs[i], IO_CFG_PULL_UP, 0, IO_DRV_EMMC_HS400_DATA); 7851bd4fe43Sopenharmony_ci } 7861bd4fe43Sopenharmony_ci SdhciSetIodriver(REG_CTRL_EMMC_DS, IO_CFG_PULL_DOWN, IO_CFG_SR, IO_DRV_EMMC_HS400_DS); 7871bd4fe43Sopenharmony_ci SdhciSetIodriver(REG_CTRL_EMMC_RST, IO_CFG_PULL_UP, IO_CFG_SR, IO_DRV_EMMC_HS400_RST); 7881bd4fe43Sopenharmony_ci break; 7891bd4fe43Sopenharmony_ci case BUS_TIMING_MMC_HS200: 7901bd4fe43Sopenharmony_ci SdhciSetEmmcCtrl(host); 7911bd4fe43Sopenharmony_ci SdhciSetIodriver(REG_CTRL_EMMC_CLK, IO_CFG_PULL_DOWN, 0, IO_DRV_EMMC_HS200_CLK); 7921bd4fe43Sopenharmony_ci SdhciSetIodriver(REG_CTRL_EMMC_CMD, IO_CFG_PULL_UP, IO_CFG_SR, IO_DRV_EMMC_HS200_CMD); 7931bd4fe43Sopenharmony_ci for (i = 0; i < count; i++) { 7941bd4fe43Sopenharmony_ci SdhciSetIodriver(dataRegs[i], IO_CFG_PULL_UP, IO_CFG_SR, IO_DRV_EMMC_HS200_DATA); 7951bd4fe43Sopenharmony_ci } 7961bd4fe43Sopenharmony_ci SdhciSetIodriver(REG_CTRL_EMMC_RST, IO_CFG_PULL_UP, IO_CFG_SR, IO_DRV_EMMC_HS200_RST); 7971bd4fe43Sopenharmony_ci break; 7981bd4fe43Sopenharmony_ci case BUS_TIMING_MMC_HS: 7991bd4fe43Sopenharmony_ci SdhciSetEmmcCtrl(host); 8001bd4fe43Sopenharmony_ci SdhciSetIodriver(REG_CTRL_EMMC_CLK, IO_CFG_PULL_DOWN, IO_CFG_SR, IO_DRV_EMMC_HS_CLK); 8011bd4fe43Sopenharmony_ci SdhciSetIodriver(REG_CTRL_EMMC_CMD, IO_CFG_PULL_UP, IO_CFG_SR, IO_DRV_EMMC_HS_CMD); 8021bd4fe43Sopenharmony_ci for (i = 0; i < count; i++) { 8031bd4fe43Sopenharmony_ci SdhciSetIodriver(dataRegs[i], IO_CFG_PULL_UP, IO_CFG_SR, IO_DRV_EMMC_HS_DATA); 8041bd4fe43Sopenharmony_ci } 8051bd4fe43Sopenharmony_ci SdhciSetIodriver(REG_CTRL_EMMC_RST, IO_CFG_PULL_UP, IO_CFG_SR, IO_DRV_EMMC_HS_RST); 8061bd4fe43Sopenharmony_ci break; 8071bd4fe43Sopenharmony_ci default: 8081bd4fe43Sopenharmony_ci SdhciSetIodriver(REG_CTRL_EMMC_CLK, IO_CFG_PULL_DOWN, IO_CFG_SR, IO_DRV_EMMC_OTHER_CLK); 8091bd4fe43Sopenharmony_ci SdhciSetIodriver(REG_CTRL_EMMC_CMD, IO_CFG_PULL_UP, IO_CFG_SR, IO_DRV_EMMC_OTHER_CMD); 8101bd4fe43Sopenharmony_ci for (i = 0; i < count; i++) { 8111bd4fe43Sopenharmony_ci SdhciSetIodriver(dataRegs[i], IO_CFG_PULL_UP, IO_CFG_SR, IO_DRV_EMMC_OTHER_DATA); 8121bd4fe43Sopenharmony_ci } 8131bd4fe43Sopenharmony_ci SdhciSetIodriver(REG_CTRL_EMMC_RST, IO_CFG_PULL_UP, IO_CFG_SR, IO_DRV_EMMC_OTHER_RST); 8141bd4fe43Sopenharmony_ci break; 8151bd4fe43Sopenharmony_ci } 8161bd4fe43Sopenharmony_ci} 8171bd4fe43Sopenharmony_ci 8181bd4fe43Sopenharmony_cistatic void SdhciSetMmcIoDriver(struct SdhciHost *host, enum MmcBusTiming timing) 8191bd4fe43Sopenharmony_ci{ 8201bd4fe43Sopenharmony_ci uint32_t val; 8211bd4fe43Sopenharmony_ci 8221bd4fe43Sopenharmony_ci if (host->hostId == 0) { 8231bd4fe43Sopenharmony_ci /* mmc0: eMMC or SD card */ 8241bd4fe43Sopenharmony_ci val = OSAL_READL(REG_CTRL_EMMC_CLK) & IO_MUX_MASK; 8251bd4fe43Sopenharmony_ci if (val == IO_MUX_SHIFT(IO_MUX_CLK_TYPE_EMMC)) { 8261bd4fe43Sopenharmony_ci SdhciSetEmmcDriver(host, timing); 8271bd4fe43Sopenharmony_ci } 8281bd4fe43Sopenharmony_ci val = OSAL_READL(REG_CTRL_SD_CLK) & IO_MUX_MASK; 8291bd4fe43Sopenharmony_ci if (val == IO_MUX_SHIFT(IO_MUX_CLK_TYPE_SD)) { 8301bd4fe43Sopenharmony_ci SdhciSetSdDriver(host, timing); 8311bd4fe43Sopenharmony_ci } 8321bd4fe43Sopenharmony_ci } else if (host->hostId == 1) { 8331bd4fe43Sopenharmony_ci /* mmc1: SDIO */ 8341bd4fe43Sopenharmony_ci SdhciSetSdiodriver(host); 8351bd4fe43Sopenharmony_ci } 8361bd4fe43Sopenharmony_ci} 8371bd4fe43Sopenharmony_ci 8381bd4fe43Sopenharmony_cistatic void SdhciSetPhase(struct SdhciHost *host) 8391bd4fe43Sopenharmony_ci{ 8401bd4fe43Sopenharmony_ci uint32_t drvPhase, phase; 8411bd4fe43Sopenharmony_ci enum MmcBusTiming timing; 8421bd4fe43Sopenharmony_ci 8431bd4fe43Sopenharmony_ci if (host->mmc->curDev == NULL) { 8441bd4fe43Sopenharmony_ci return; 8451bd4fe43Sopenharmony_ci } 8461bd4fe43Sopenharmony_ci timing = host->mmc->curDev->workPara.timing; 8471bd4fe43Sopenharmony_ci 8481bd4fe43Sopenharmony_ci if (host->hostId == 0) { 8491bd4fe43Sopenharmony_ci /* eMMC or SD card */ 8501bd4fe43Sopenharmony_ci if (timing == BUS_TIMING_MMC_HS400) { 8511bd4fe43Sopenharmony_ci drvPhase = SDHCI_PHASE_112P5_DEGREE; 8521bd4fe43Sopenharmony_ci phase = host->tuningPhase; 8531bd4fe43Sopenharmony_ci } else if (timing == BUS_TIMING_MMC_HS200) { 8541bd4fe43Sopenharmony_ci drvPhase = SDHCI_PHASE_258P75_DEGREE; 8551bd4fe43Sopenharmony_ci phase = host->tuningPhase; 8561bd4fe43Sopenharmony_ci } else if (timing == BUS_TIMING_MMC_HS) { 8571bd4fe43Sopenharmony_ci drvPhase = SDHCI_PHASE_180_DEGREE; 8581bd4fe43Sopenharmony_ci phase = SDHCI_SAMPLE_PHASE; 8591bd4fe43Sopenharmony_ci } else if (timing == BUS_TIMING_SD_HS) { 8601bd4fe43Sopenharmony_ci drvPhase = SDHCI_PHASE_225_DEGREE; 8611bd4fe43Sopenharmony_ci phase = SDHCI_SAMPLE_PHASE; 8621bd4fe43Sopenharmony_ci } else if (timing == BUS_TIMING_MMC_DS) { 8631bd4fe43Sopenharmony_ci drvPhase = SDHCI_PHASE_180_DEGREE; 8641bd4fe43Sopenharmony_ci phase = 0; 8651bd4fe43Sopenharmony_ci } else { 8661bd4fe43Sopenharmony_ci drvPhase = SDHCI_PHASE_225_DEGREE; 8671bd4fe43Sopenharmony_ci phase = SDHCI_SAMPLE_PHASE; 8681bd4fe43Sopenharmony_ci } 8691bd4fe43Sopenharmony_ci } else { 8701bd4fe43Sopenharmony_ci /* SDIO device */ 8711bd4fe43Sopenharmony_ci if ((timing == BUS_TIMING_SD_HS) || 8721bd4fe43Sopenharmony_ci (timing == BUS_TIMING_UHS_SDR25)) { 8731bd4fe43Sopenharmony_ci drvPhase = SDHCI_PHASE_180_DEGREE; 8741bd4fe43Sopenharmony_ci phase = SDHCI_SAMPLE_PHASE; 8751bd4fe43Sopenharmony_ci } else { 8761bd4fe43Sopenharmony_ci /* UHS_SDR12 */ 8771bd4fe43Sopenharmony_ci drvPhase = SDHCI_PHASE_180_DEGREE; 8781bd4fe43Sopenharmony_ci phase = 0; 8791bd4fe43Sopenharmony_ci } 8801bd4fe43Sopenharmony_ci } 8811bd4fe43Sopenharmony_ci 8821bd4fe43Sopenharmony_ci SdhciSetDrvPhase(host->hostId, drvPhase); 8831bd4fe43Sopenharmony_ci SdhciEnableSample(host); 8841bd4fe43Sopenharmony_ci SdhciSetSampPhase(host, phase); 8851bd4fe43Sopenharmony_ci SdhciSetMmcIoDriver(host, timing); 8861bd4fe43Sopenharmony_ci} 8871bd4fe43Sopenharmony_ci 8881bd4fe43Sopenharmony_cistatic int32_t SdhciSetClock(struct MmcCntlr *cntlr, uint32_t clock) 8891bd4fe43Sopenharmony_ci{ 8901bd4fe43Sopenharmony_ci struct SdhciHost *host = (struct SdhciHost *)cntlr->priv; 8911bd4fe43Sopenharmony_ci uint16_t clk; 8921bd4fe43Sopenharmony_ci uint32_t i, ret; 8931bd4fe43Sopenharmony_ci 8941bd4fe43Sopenharmony_ci /* turn off clk2card_on */ 8951bd4fe43Sopenharmony_ci clk = SdhciReadw(host, CLK_CTRL_R); 8961bd4fe43Sopenharmony_ci clk &= ~(SDHCI_CLK_CTRL_CLK_EN); 8971bd4fe43Sopenharmony_ci SdhciWritew(host, clk, CLK_CTRL_R); 8981bd4fe43Sopenharmony_ci OsalUDelay(SDHCI_OFF_CLK2CARD_ON_DELAY); 8991bd4fe43Sopenharmony_ci 9001bd4fe43Sopenharmony_ci /* turn off card_clk_en */ 9011bd4fe43Sopenharmony_ci clk &= ~(SDHCI_CLK_CTRL_INT_CLK_EN | SDHCI_CLK_CTRL_PLL_EN); 9021bd4fe43Sopenharmony_ci SdhciWritew(host, clk, CLK_CTRL_R); 9031bd4fe43Sopenharmony_ci 9041bd4fe43Sopenharmony_ci if (clock == 0) { 9051bd4fe43Sopenharmony_ci return HDF_FAILURE; 9061bd4fe43Sopenharmony_ci } 9071bd4fe43Sopenharmony_ci if (clock >= host->maxClk) { 9081bd4fe43Sopenharmony_ci clock = host->maxClk; 9091bd4fe43Sopenharmony_ci } 9101bd4fe43Sopenharmony_ci 9111bd4fe43Sopenharmony_ci SdhciResetDll(host); 9121bd4fe43Sopenharmony_ci SdhciSetPhase(host); 9131bd4fe43Sopenharmony_ci 9141bd4fe43Sopenharmony_ci ret = SdhciSelectClock(host, clock); 9151bd4fe43Sopenharmony_ci if (ret == 0) { 9161bd4fe43Sopenharmony_ci HDF_LOGE("Select clock fail!"); 9171bd4fe43Sopenharmony_ci return HDF_FAILURE; 9181bd4fe43Sopenharmony_ci } 9191bd4fe43Sopenharmony_ci host->clock = ret; 9201bd4fe43Sopenharmony_ci if (cntlr->caps.bits.nonremovable == 0) { 9211bd4fe43Sopenharmony_ci SdhciResetDll(host); 9221bd4fe43Sopenharmony_ci } 9231bd4fe43Sopenharmony_ci 9241bd4fe43Sopenharmony_ci /* turn on card_clk_en */ 9251bd4fe43Sopenharmony_ci clk |= SDHCI_CLK_CTRL_INT_CLK_EN | SDHCI_CLK_CTRL_PLL_EN; 9261bd4fe43Sopenharmony_ci SdhciWritew(host, clk, CLK_CTRL_R); 9271bd4fe43Sopenharmony_ci for (i = 0; i < SDHCI_CLK_CTRL_RETRY_TIMES; i++) { 9281bd4fe43Sopenharmony_ci clk = SdhciReadw(host, CLK_CTRL_R); 9291bd4fe43Sopenharmony_ci if ((clk & SDHCI_CLK_CTRL_INT_STABLE) > 0) { 9301bd4fe43Sopenharmony_ci break; 9311bd4fe43Sopenharmony_ci } 9321bd4fe43Sopenharmony_ci OsalMDelay(1); 9331bd4fe43Sopenharmony_ci } 9341bd4fe43Sopenharmony_ci if (i == SDHCI_CLK_CTRL_RETRY_TIMES) { 9351bd4fe43Sopenharmony_ci HDF_LOGE("Internal clock never stabilized."); 9361bd4fe43Sopenharmony_ci return HDF_ERR_TIMEOUT; 9371bd4fe43Sopenharmony_ci } 9381bd4fe43Sopenharmony_ci 9391bd4fe43Sopenharmony_ci SdhciResetDll(host); 9401bd4fe43Sopenharmony_ci /* turn on clk2card_on */ 9411bd4fe43Sopenharmony_ci clk |= SDHCI_CLK_CTRL_CLK_EN; 9421bd4fe43Sopenharmony_ci SdhciWritew(host, clk, CLK_CTRL_R); 9431bd4fe43Sopenharmony_ci return HDF_SUCCESS; 9441bd4fe43Sopenharmony_ci} 9451bd4fe43Sopenharmony_ci 9461bd4fe43Sopenharmony_cistatic void SdhciInit(struct SdhciHost *host, bool resetAll) 9471bd4fe43Sopenharmony_ci{ 9481bd4fe43Sopenharmony_ci uint32_t reg; 9491bd4fe43Sopenharmony_ci if (resetAll == false) { 9501bd4fe43Sopenharmony_ci SdhciDoReset(host, (SDHCI_RESET_CMD | SDHCI_RESET_DATA)); 9511bd4fe43Sopenharmony_ci } else { 9521bd4fe43Sopenharmony_ci SdhciDoReset(host, SDHCI_RESET_ALL); 9531bd4fe43Sopenharmony_ci } 9541bd4fe43Sopenharmony_ci 9551bd4fe43Sopenharmony_ci host->pwr = 0; 9561bd4fe43Sopenharmony_ci host->irqEnable = SDHCI_INTERRUPT_BUS_POWER | SDHCI_INTERRUPT_DATA_END_BIT | SDHCI_INTERRUPT_DATA_CRC | 9571bd4fe43Sopenharmony_ci SDHCI_INTERRUPT_DATA_TIMEOUT | SDHCI_INTERRUPT_INDEX | SDHCI_INTERRUPT_END_BIT | 9581bd4fe43Sopenharmony_ci SDHCI_INTERRUPT_CRC | SDHCI_INTERRUPT_TIMEOUT | SDHCI_INTERRUPT_DATA_END | 9591bd4fe43Sopenharmony_ci SDHCI_INTERRUPT_RESPONSE | SDHCI_INTERRUPT_AUTO_CMD_ERR; 9601bd4fe43Sopenharmony_ci 9611bd4fe43Sopenharmony_ci SdhciEnablePlugIrq(host, host->irqEnable); 9621bd4fe43Sopenharmony_ci 9631bd4fe43Sopenharmony_ci if (resetAll == false) { 9641bd4fe43Sopenharmony_ci host->clock = 0; 9651bd4fe43Sopenharmony_ci } else { 9661bd4fe43Sopenharmony_ci reg = SdhciReadw(host, MSHC_CTRL_R); 9671bd4fe43Sopenharmony_ci reg &= ~SDHC_CMD_CONFLIT_CHECK; 9681bd4fe43Sopenharmony_ci SdhciWritew(host, reg, MSHC_CTRL_R); 9691bd4fe43Sopenharmony_ci 9701bd4fe43Sopenharmony_ci reg = SdhciReadl(host, MBIU_CTRL_R); 9711bd4fe43Sopenharmony_ci reg &= ~(SDHCI_GM_WR_OSRC_LMT_MASK | SDHCI_GM_RD_OSRC_LMT_MASK | SDHCI_UNDEFL_INCR_EN); 9721bd4fe43Sopenharmony_ci reg |= SDHCI_GM_WR_OSRC_LMT_VAL | SDHCI_GM_RD_OSRC_LMT_VAL; 9731bd4fe43Sopenharmony_ci SdhciWritel(host, reg, MBIU_CTRL_R); 9741bd4fe43Sopenharmony_ci 9751bd4fe43Sopenharmony_ci reg = SdhciReadl(host, MULTI_CYCLE_R); 9761bd4fe43Sopenharmony_ci reg |= SDHCI_EDGE_DETECT_EN | SDHCI_DATA_DLY_EN; 9771bd4fe43Sopenharmony_ci reg &= ~SDHCI_CMD_DLY_EN; 9781bd4fe43Sopenharmony_ci SdhciWritel(host, reg, MULTI_CYCLE_R); 9791bd4fe43Sopenharmony_ci } 9801bd4fe43Sopenharmony_ci} 9811bd4fe43Sopenharmony_ci 9821bd4fe43Sopenharmony_cistatic void SdhciReinit(struct SdhciHost *host) 9831bd4fe43Sopenharmony_ci{ 9841bd4fe43Sopenharmony_ci SdhciInit(host, true); 9851bd4fe43Sopenharmony_ci 9861bd4fe43Sopenharmony_ci if (host->flags & SDHCI_USING_RETUNING_TIMER) { 9871bd4fe43Sopenharmony_ci host->flags &= ~SDHCI_USING_RETUNING_TIMER; 9881bd4fe43Sopenharmony_ci host->mmc->maxBlkNum = SDHCI_MAX_BLK_NUM; 9891bd4fe43Sopenharmony_ci } 9901bd4fe43Sopenharmony_ci SdhciEnableCardDetection(host); 9911bd4fe43Sopenharmony_ci} 9921bd4fe43Sopenharmony_ci 9931bd4fe43Sopenharmony_cistatic void SdhciEnablePresetValue(struct SdhciHost *host, bool enable) 9941bd4fe43Sopenharmony_ci{ 9951bd4fe43Sopenharmony_ci uint32_t reg; 9961bd4fe43Sopenharmony_ci 9971bd4fe43Sopenharmony_ci if (host->version < SDHCI_HOST_SPEC_300) { 9981bd4fe43Sopenharmony_ci return; 9991bd4fe43Sopenharmony_ci } 10001bd4fe43Sopenharmony_ci 10011bd4fe43Sopenharmony_ci if (host->presetEnabled != enable) { 10021bd4fe43Sopenharmony_ci reg = SdhciReadw(host, HOST_CTRL2_R); 10031bd4fe43Sopenharmony_ci if (enable == true) { 10041bd4fe43Sopenharmony_ci reg |= SDHCI_PRESET_VAL_ENABLE; 10051bd4fe43Sopenharmony_ci } else { 10061bd4fe43Sopenharmony_ci reg &= ~SDHCI_PRESET_VAL_ENABLE; 10071bd4fe43Sopenharmony_ci } 10081bd4fe43Sopenharmony_ci SdhciWritew(host, reg, HOST_CTRL2_R); 10091bd4fe43Sopenharmony_ci 10101bd4fe43Sopenharmony_ci if (enable == true) { 10111bd4fe43Sopenharmony_ci host->flags |= SDHCI_PV_ENABLED; 10121bd4fe43Sopenharmony_ci } else { 10131bd4fe43Sopenharmony_ci host->flags &= ~SDHCI_PV_ENABLED; 10141bd4fe43Sopenharmony_ci } 10151bd4fe43Sopenharmony_ci host->presetEnabled = enable; 10161bd4fe43Sopenharmony_ci } 10171bd4fe43Sopenharmony_ci} 10181bd4fe43Sopenharmony_ci 10191bd4fe43Sopenharmony_cistatic int32_t SdhciSetPowerMode(struct MmcCntlr *cntlr, enum MmcPowerMode mode) 10201bd4fe43Sopenharmony_ci{ 10211bd4fe43Sopenharmony_ci struct SdhciHost *host = (struct SdhciHost *)cntlr->priv; 10221bd4fe43Sopenharmony_ci uint8_t pwr = SDHCI_POWER_330; 10231bd4fe43Sopenharmony_ci 10241bd4fe43Sopenharmony_ci if (mode == MMC_POWER_MODE_POWER_OFF) { 10251bd4fe43Sopenharmony_ci SdhciWritel(host, 0, NORMAL_INT_SIGNAL_EN_R); 10261bd4fe43Sopenharmony_ci SdhciReinit(host); 10271bd4fe43Sopenharmony_ci } else { 10281bd4fe43Sopenharmony_ci if (host->version >= SDHCI_HOST_SPEC_300) { 10291bd4fe43Sopenharmony_ci SdhciEnablePresetValue(host, false); 10301bd4fe43Sopenharmony_ci } 10311bd4fe43Sopenharmony_ci if (host->pwr == SDHCI_POWER_330) { 10321bd4fe43Sopenharmony_ci return HDF_SUCCESS; 10331bd4fe43Sopenharmony_ci } 10341bd4fe43Sopenharmony_ci 10351bd4fe43Sopenharmony_ci host->pwr = pwr; 10361bd4fe43Sopenharmony_ci 10371bd4fe43Sopenharmony_ci SdhciWriteb(host, 0, PWR_CTRL_R); 10381bd4fe43Sopenharmony_ci SdhciWriteb(host, pwr, PWR_CTRL_R); 10391bd4fe43Sopenharmony_ci pwr |= SDHCI_POWER_ON; 10401bd4fe43Sopenharmony_ci SdhciWriteb(host, pwr, PWR_CTRL_R); 10411bd4fe43Sopenharmony_ci OsalMDelay(10); 10421bd4fe43Sopenharmony_ci } 10431bd4fe43Sopenharmony_ci return HDF_SUCCESS; 10441bd4fe43Sopenharmony_ci} 10451bd4fe43Sopenharmony_ci 10461bd4fe43Sopenharmony_cistatic int32_t SdhciSetBusWidth(struct MmcCntlr *cntlr, enum MmcBusWidth width) 10471bd4fe43Sopenharmony_ci{ 10481bd4fe43Sopenharmony_ci struct SdhciHost *host = (struct SdhciHost *)cntlr->priv; 10491bd4fe43Sopenharmony_ci uint8_t val; 10501bd4fe43Sopenharmony_ci 10511bd4fe43Sopenharmony_ci val = SdhciReadb(host, HOST_CTRL1_R); 10521bd4fe43Sopenharmony_ci if (width == BUS_WIDTH8) { 10531bd4fe43Sopenharmony_ci val &= (~SDHCI_CTRL_4_BIT_BUS); 10541bd4fe43Sopenharmony_ci if (host->version >= SDHCI_HOST_SPEC_300) { 10551bd4fe43Sopenharmony_ci val |= SDHCI_CTRL_8_BIT_BUS; 10561bd4fe43Sopenharmony_ci } 10571bd4fe43Sopenharmony_ci } else { 10581bd4fe43Sopenharmony_ci if (host->version >= SDHCI_HOST_SPEC_300) { 10591bd4fe43Sopenharmony_ci val &= (~SDHCI_CTRL_8_BIT_BUS); 10601bd4fe43Sopenharmony_ci } 10611bd4fe43Sopenharmony_ci if (width == BUS_WIDTH4) { 10621bd4fe43Sopenharmony_ci val |= SDHCI_CTRL_4_BIT_BUS; 10631bd4fe43Sopenharmony_ci } else { 10641bd4fe43Sopenharmony_ci val &= (~SDHCI_CTRL_4_BIT_BUS); 10651bd4fe43Sopenharmony_ci } 10661bd4fe43Sopenharmony_ci } 10671bd4fe43Sopenharmony_ci SdhciWriteb(host, val, HOST_CTRL1_R); 10681bd4fe43Sopenharmony_ci return HDF_SUCCESS; 10691bd4fe43Sopenharmony_ci} 10701bd4fe43Sopenharmony_ci 10711bd4fe43Sopenharmony_cistatic void SdhciSetUhsSignaling(struct SdhciHost *host, enum MmcBusTiming timing) 10721bd4fe43Sopenharmony_ci{ 10731bd4fe43Sopenharmony_ci uint32_t val; 10741bd4fe43Sopenharmony_ci 10751bd4fe43Sopenharmony_ci val = SdhciReadw(host, HOST_CTRL2_R); 10761bd4fe43Sopenharmony_ci 10771bd4fe43Sopenharmony_ci /* Select Bus Speed Mode for host */ 10781bd4fe43Sopenharmony_ci val &= (~SDHCI_UHS_MASK); 10791bd4fe43Sopenharmony_ci if (timing == BUS_TIMING_MMC_HS200 || timing == BUS_TIMING_UHS_SDR104) { 10801bd4fe43Sopenharmony_ci val |= SDHCI_UHS_SDR104; 10811bd4fe43Sopenharmony_ci } else if (timing == BUS_TIMING_UHS_SDR12) { 10821bd4fe43Sopenharmony_ci val |= SDHCI_UHS_SDR12; 10831bd4fe43Sopenharmony_ci } else if (timing == BUS_TIMING_UHS_SDR25) { 10841bd4fe43Sopenharmony_ci val |= SDHCI_UHS_SDR25; 10851bd4fe43Sopenharmony_ci } else if (timing == BUS_TIMING_UHS_SDR50) { 10861bd4fe43Sopenharmony_ci val |= SDHCI_UHS_SDR50; 10871bd4fe43Sopenharmony_ci } else if (timing == BUS_TIMING_UHS_DDR50 || timing == BUS_TIMING_UHS_DDR52) { 10881bd4fe43Sopenharmony_ci val |= SDHCI_UHS_DDR50; 10891bd4fe43Sopenharmony_ci } else if (timing == BUS_TIMING_MMC_HS400) { 10901bd4fe43Sopenharmony_ci val |= SDHCI_HS400; 10911bd4fe43Sopenharmony_ci } 10921bd4fe43Sopenharmony_ci SdhciWritew(host, val, HOST_CTRL2_R); 10931bd4fe43Sopenharmony_ci} 10941bd4fe43Sopenharmony_ci 10951bd4fe43Sopenharmony_cistatic int32_t SdhciSetBusTiming(struct MmcCntlr *cntlr, enum MmcBusTiming timing) 10961bd4fe43Sopenharmony_ci{ 10971bd4fe43Sopenharmony_ci struct SdhciHost *host = (struct SdhciHost *)cntlr->priv; 10981bd4fe43Sopenharmony_ci uint32_t clockVal, ctrl1Val, ctrl2Val; 10991bd4fe43Sopenharmony_ci 11001bd4fe43Sopenharmony_ci ctrl1Val = SdhciReadb(host, HOST_CTRL1_R); 11011bd4fe43Sopenharmony_ci 11021bd4fe43Sopenharmony_ci if (timing >= BUS_TIMING_MMC_HS) { 11031bd4fe43Sopenharmony_ci ctrl1Val |= SDHCI_CTRL_HIGH_SPEED; 11041bd4fe43Sopenharmony_ci } 11051bd4fe43Sopenharmony_ci 11061bd4fe43Sopenharmony_ci if (host->version < SDHCI_HOST_SPEC_300) { 11071bd4fe43Sopenharmony_ci SdhciWriteb(host, ctrl1Val, HOST_CTRL1_R); 11081bd4fe43Sopenharmony_ci return HDF_SUCCESS; 11091bd4fe43Sopenharmony_ci } 11101bd4fe43Sopenharmony_ci 11111bd4fe43Sopenharmony_ci if (host->presetEnabled == false) { 11121bd4fe43Sopenharmony_ci SdhciWriteb(host, ctrl1Val, HOST_CTRL1_R); 11131bd4fe43Sopenharmony_ci ctrl2Val = SdhciReadw(host, HOST_CTRL2_R); 11141bd4fe43Sopenharmony_ci ctrl2Val &= ~SDHCI_DRV_TYPE_MASK; 11151bd4fe43Sopenharmony_ci 11161bd4fe43Sopenharmony_ci SdhciWritew(host, ctrl2Val, HOST_CTRL2_R); 11171bd4fe43Sopenharmony_ci } else { 11181bd4fe43Sopenharmony_ci clockVal = SdhciReadw(host, CLK_CTRL_R); 11191bd4fe43Sopenharmony_ci clockVal &= ~SDHCI_CLK_CTRL_CLK_EN; 11201bd4fe43Sopenharmony_ci SdhciWritew(host, clockVal, CLK_CTRL_R); 11211bd4fe43Sopenharmony_ci 11221bd4fe43Sopenharmony_ci SdhciWriteb(host, ctrl1Val, HOST_CTRL1_R); 11231bd4fe43Sopenharmony_ci (void)SdhciSetClock(cntlr, host->clock); 11241bd4fe43Sopenharmony_ci } 11251bd4fe43Sopenharmony_ci clockVal = SdhciReadw(host, CLK_CTRL_R); 11261bd4fe43Sopenharmony_ci clockVal &= ~SDHCI_CLK_CTRL_CLK_EN; 11271bd4fe43Sopenharmony_ci SdhciWritew(host, clockVal, CLK_CTRL_R); 11281bd4fe43Sopenharmony_ci 11291bd4fe43Sopenharmony_ci SdhciSetUhsSignaling(host, timing); 11301bd4fe43Sopenharmony_ci if (timing > BUS_TIMING_UHS_SDR12 && timing <= BUS_TIMING_UHS_DDR50) { 11311bd4fe43Sopenharmony_ci SdhciEnablePresetValue(host, true); 11321bd4fe43Sopenharmony_ci } 11331bd4fe43Sopenharmony_ci (void)SdhciSetClock(cntlr, host->clock); 11341bd4fe43Sopenharmony_ci return HDF_SUCCESS; 11351bd4fe43Sopenharmony_ci} 11361bd4fe43Sopenharmony_ci 11371bd4fe43Sopenharmony_cistatic int32_t SdhciSetSdioIrq(struct MmcCntlr *cntlr, bool enable) 11381bd4fe43Sopenharmony_ci{ 11391bd4fe43Sopenharmony_ci struct SdhciHost *host = (struct SdhciHost *)cntlr->priv; 11401bd4fe43Sopenharmony_ci 11411bd4fe43Sopenharmony_ci if (enable == true) { 11421bd4fe43Sopenharmony_ci host->flags |= SDHCI_SDIO_IRQ_ENABLED; 11431bd4fe43Sopenharmony_ci } else { 11441bd4fe43Sopenharmony_ci host->flags &= ~SDHCI_SDIO_IRQ_ENABLED; 11451bd4fe43Sopenharmony_ci } 11461bd4fe43Sopenharmony_ci 11471bd4fe43Sopenharmony_ci if ((host->flags & SDHCI_DEVICE_DEAD) == 0) { 11481bd4fe43Sopenharmony_ci if (enable == true) { 11491bd4fe43Sopenharmony_ci host->irqEnable |= SDHCI_INTERRUPT_CARD_INT; 11501bd4fe43Sopenharmony_ci } else { 11511bd4fe43Sopenharmony_ci host->irqEnable &= ~SDHCI_INTERRUPT_CARD_INT; 11521bd4fe43Sopenharmony_ci } 11531bd4fe43Sopenharmony_ci SdhciEnablePlugIrq(host, host->irqEnable); 11541bd4fe43Sopenharmony_ci } 11551bd4fe43Sopenharmony_ci return HDF_SUCCESS; 11561bd4fe43Sopenharmony_ci} 11571bd4fe43Sopenharmony_ci 11581bd4fe43Sopenharmony_cistatic int32_t SdhciHardwareReset(struct MmcCntlr *cntlr) 11591bd4fe43Sopenharmony_ci{ 11601bd4fe43Sopenharmony_ci struct SdhciHost *host = (struct SdhciHost *)cntlr->priv; 11611bd4fe43Sopenharmony_ci 11621bd4fe43Sopenharmony_ci SdhciWritel(host, 0x0, EMMC_HW_RESET_R); 11631bd4fe43Sopenharmony_ci OsalUDelay(10); 11641bd4fe43Sopenharmony_ci SdhciWritel(host, 0x1, EMMC_HW_RESET_R); 11651bd4fe43Sopenharmony_ci OsalUDelay(200); 11661bd4fe43Sopenharmony_ci 11671bd4fe43Sopenharmony_ci return HDF_SUCCESS; 11681bd4fe43Sopenharmony_ci} 11691bd4fe43Sopenharmony_ci 11701bd4fe43Sopenharmony_cistatic int32_t SdhciSystemInit(struct MmcCntlr *cntlr) 11711bd4fe43Sopenharmony_ci{ 11721bd4fe43Sopenharmony_ci struct SdhciHost *host = NULL; 11731bd4fe43Sopenharmony_ci 11741bd4fe43Sopenharmony_ci if (cntlr == NULL) { 11751bd4fe43Sopenharmony_ci return HDF_ERR_INVALID_OBJECT; 11761bd4fe43Sopenharmony_ci } 11771bd4fe43Sopenharmony_ci 11781bd4fe43Sopenharmony_ci host = (struct SdhciHost *)cntlr->priv; 11791bd4fe43Sopenharmony_ci SdhciInit(host, true); 11801bd4fe43Sopenharmony_ci SdhciEnableCardDetection(host); 11811bd4fe43Sopenharmony_ci return HDF_SUCCESS; 11821bd4fe43Sopenharmony_ci} 11831bd4fe43Sopenharmony_ci 11841bd4fe43Sopenharmony_cistatic int32_t SdhciSetEnhanceStrobe(struct MmcCntlr *cntlr, bool enable) 11851bd4fe43Sopenharmony_ci{ 11861bd4fe43Sopenharmony_ci struct SdhciHost *host = (struct SdhciHost *)cntlr->priv; 11871bd4fe43Sopenharmony_ci uint32_t reg; 11881bd4fe43Sopenharmony_ci 11891bd4fe43Sopenharmony_ci reg = SdhciReadl(host, EMMC_CTRL_R); 11901bd4fe43Sopenharmony_ci if (enable == true) { 11911bd4fe43Sopenharmony_ci reg |= SDHCI_EMMC_CTRL_ENH_STROBE_EN; 11921bd4fe43Sopenharmony_ci } else { 11931bd4fe43Sopenharmony_ci reg &= ~SDHCI_EMMC_CTRL_ENH_STROBE_EN; 11941bd4fe43Sopenharmony_ci } 11951bd4fe43Sopenharmony_ci SdhciWritel(host, reg, EMMC_CTRL_R); 11961bd4fe43Sopenharmony_ci 11971bd4fe43Sopenharmony_ci reg = SdhciReadl(host, MULTI_CYCLE_R); 11981bd4fe43Sopenharmony_ci if (enable == true) { 11991bd4fe43Sopenharmony_ci reg |= SDHCI_CMD_DLY_EN; 12001bd4fe43Sopenharmony_ci } else { 12011bd4fe43Sopenharmony_ci reg &= ~SDHCI_CMD_DLY_EN; 12021bd4fe43Sopenharmony_ci } 12031bd4fe43Sopenharmony_ci SdhciWritel(host, reg, MULTI_CYCLE_R); 12041bd4fe43Sopenharmony_ci return HDF_SUCCESS; 12051bd4fe43Sopenharmony_ci} 12061bd4fe43Sopenharmony_ci 12071bd4fe43Sopenharmony_cistatic int32_t SdhciSwitchVoltage(struct MmcCntlr *cntlr, enum MmcVolt volt) 12081bd4fe43Sopenharmony_ci{ 12091bd4fe43Sopenharmony_ci uint16_t ctrl; 12101bd4fe43Sopenharmony_ci struct SdhciHost *host = (struct SdhciHost *)cntlr->priv; 12111bd4fe43Sopenharmony_ci 12121bd4fe43Sopenharmony_ci if (cntlr->devType == MMC_DEV_EMMC) { 12131bd4fe43Sopenharmony_ci ctrl = SdhciReadw(host, HOST_CTRL2_R); 12141bd4fe43Sopenharmony_ci if (volt == VOLT_1V8) { 12151bd4fe43Sopenharmony_ci ctrl |= SDHCI_VDD_180; 12161bd4fe43Sopenharmony_ci SdhciWritew(host, ctrl, HOST_CTRL2_R); 12171bd4fe43Sopenharmony_ci } else { 12181bd4fe43Sopenharmony_ci ctrl &= ~SDHCI_VDD_180; 12191bd4fe43Sopenharmony_ci SdhciWritew(host, ctrl, HOST_CTRL2_R); 12201bd4fe43Sopenharmony_ci } 12211bd4fe43Sopenharmony_ci } else { 12221bd4fe43Sopenharmony_ci if (volt == VOLT_3V3) { 12231bd4fe43Sopenharmony_ci return HDF_SUCCESS; 12241bd4fe43Sopenharmony_ci } 12251bd4fe43Sopenharmony_ci return HDF_FAILURE; 12261bd4fe43Sopenharmony_ci } 12271bd4fe43Sopenharmony_ci return HDF_SUCCESS; 12281bd4fe43Sopenharmony_ci} 12291bd4fe43Sopenharmony_ci 12301bd4fe43Sopenharmony_cistatic bool SdhciDevReadOnly(struct MmcCntlr *cntlr) 12311bd4fe43Sopenharmony_ci{ 12321bd4fe43Sopenharmony_ci uint32_t val; 12331bd4fe43Sopenharmony_ci bool readOnly = true; 12341bd4fe43Sopenharmony_ci struct SdhciHost *host = (struct SdhciHost *)cntlr->priv; 12351bd4fe43Sopenharmony_ci 12361bd4fe43Sopenharmony_ci if (host->flags & SDHCI_DEVICE_DEAD) { 12371bd4fe43Sopenharmony_ci readOnly = false; 12381bd4fe43Sopenharmony_ci } else { 12391bd4fe43Sopenharmony_ci val = SdhciReadl(host, PSTATE_R); 12401bd4fe43Sopenharmony_ci readOnly = ((val & SDHCI_WRITE_PROTECT) > 0 ? false : true); 12411bd4fe43Sopenharmony_ci } 12421bd4fe43Sopenharmony_ci 12431bd4fe43Sopenharmony_ci if (host->quirks.bits.invertedWriteProtect > 0) { 12441bd4fe43Sopenharmony_ci return (!readOnly); 12451bd4fe43Sopenharmony_ci } 12461bd4fe43Sopenharmony_ci return readOnly; 12471bd4fe43Sopenharmony_ci} 12481bd4fe43Sopenharmony_ci 12491bd4fe43Sopenharmony_cistatic bool SdhciDevBusy(struct MmcCntlr *cntlr) 12501bd4fe43Sopenharmony_ci{ 12511bd4fe43Sopenharmony_ci struct SdhciHost *host = (struct SdhciHost *)cntlr->priv; 12521bd4fe43Sopenharmony_ci uint32_t state; 12531bd4fe43Sopenharmony_ci 12541bd4fe43Sopenharmony_ci /* Check whether DAT[0] is 0 */ 12551bd4fe43Sopenharmony_ci state = SdhciReadl(host, PSTATE_R); 12561bd4fe43Sopenharmony_ci return !(state & SDHCI_DATA_0_LEVEL_MASK); 12571bd4fe43Sopenharmony_ci} 12581bd4fe43Sopenharmony_ci 12591bd4fe43Sopenharmony_cistatic void SdhciWaitDrvDllLock(uint32_t id) 12601bd4fe43Sopenharmony_ci{ 12611bd4fe43Sopenharmony_ci uint32_t i, val; 12621bd4fe43Sopenharmony_ci uint32_t offset[] = { PERI_SD_DRV_DLL_CTRL, PERI_SDIO_DRV_DLL_CTRL }; 12631bd4fe43Sopenharmony_ci 12641bd4fe43Sopenharmony_ci if (id >= (sizeof(offset) / sizeof(offset[0]))) { 12651bd4fe43Sopenharmony_ci return; 12661bd4fe43Sopenharmony_ci } 12671bd4fe43Sopenharmony_ci 12681bd4fe43Sopenharmony_ci for (i = 0; i < SDHCI_CLK_CTRL_RETRY_TIMES; i++) { 12691bd4fe43Sopenharmony_ci val = OSAL_READL(offset[id]); 12701bd4fe43Sopenharmony_ci if ((val & SDHCI_DRV_DLL_LOCK) > 0) { 12711bd4fe43Sopenharmony_ci return; 12721bd4fe43Sopenharmony_ci } 12731bd4fe43Sopenharmony_ci OsalMDelay(1); 12741bd4fe43Sopenharmony_ci } 12751bd4fe43Sopenharmony_ci HDF_LOGD("host%u: DRV DLL not locked.", id); 12761bd4fe43Sopenharmony_ci} 12771bd4fe43Sopenharmony_ci 12781bd4fe43Sopenharmony_cistatic void SdhciEnableSamplDll(uint32_t id) 12791bd4fe43Sopenharmony_ci{ 12801bd4fe43Sopenharmony_ci uint32_t val; 12811bd4fe43Sopenharmony_ci uint32_t offset[] = { PERI_CRG125, PERI_CRG139 }; 12821bd4fe43Sopenharmony_ci 12831bd4fe43Sopenharmony_ci if (id >= (sizeof(offset) / sizeof(offset[0]))) { 12841bd4fe43Sopenharmony_ci return; 12851bd4fe43Sopenharmony_ci } 12861bd4fe43Sopenharmony_ci 12871bd4fe43Sopenharmony_ci val = OSAL_READL(offset[id]); 12881bd4fe43Sopenharmony_ci val |= SDHCI_SAMPL_DLL_DEV_EN; 12891bd4fe43Sopenharmony_ci OSAL_WRITEL(val, offset[id]); 12901bd4fe43Sopenharmony_ci} 12911bd4fe43Sopenharmony_ci 12921bd4fe43Sopenharmony_cistatic void SdhciPreTune(struct SdhciHost *host) 12931bd4fe43Sopenharmony_ci{ 12941bd4fe43Sopenharmony_ci uint32_t val; 12951bd4fe43Sopenharmony_ci 12961bd4fe43Sopenharmony_ci val = SdhciReadl(host, NORMAL_INT_STAT_EN_R); 12971bd4fe43Sopenharmony_ci val |= SDHCI_INTERRUPT_DATA_AVAIL; 12981bd4fe43Sopenharmony_ci SdhciWritel(host, val, NORMAL_INT_STAT_EN_R); 12991bd4fe43Sopenharmony_ci 13001bd4fe43Sopenharmony_ci val = SdhciReadl(host, NORMAL_INT_SIGNAL_EN_R); 13011bd4fe43Sopenharmony_ci val |= SDHCI_INTERRUPT_DATA_AVAIL; 13021bd4fe43Sopenharmony_ci SdhciWritel(host, val, NORMAL_INT_SIGNAL_EN_R); 13031bd4fe43Sopenharmony_ci 13041bd4fe43Sopenharmony_ci SdhciWaitDrvDllLock(host->hostId); 13051bd4fe43Sopenharmony_ci SdhciEnableSamplDll(host->hostId); 13061bd4fe43Sopenharmony_ci SdhciEnableSample(host); 13071bd4fe43Sopenharmony_ci} 13081bd4fe43Sopenharmony_ci 13091bd4fe43Sopenharmony_cistatic void SdhciEnableEdgeTune(struct SdhciHost *host) 13101bd4fe43Sopenharmony_ci{ 13111bd4fe43Sopenharmony_ci uint32_t val; 13121bd4fe43Sopenharmony_ci uint32_t offset[] = { PERI_CRG126, PERI_CRG135 }; 13131bd4fe43Sopenharmony_ci 13141bd4fe43Sopenharmony_ci if (host->hostId >= (sizeof(offset) / sizeof(offset[0]))) { 13151bd4fe43Sopenharmony_ci return; 13161bd4fe43Sopenharmony_ci } 13171bd4fe43Sopenharmony_ci val = OSAL_READL(offset[host->hostId]); 13181bd4fe43Sopenharmony_ci val = (val & (~SDHCI_SAMPLB_DLL_CLK_MASK)) | SDHCI_SAMPLB_SEL(SDHCI_SAMPLB_DLL_CLK); 13191bd4fe43Sopenharmony_ci OSAL_WRITEL(val, offset[host->hostId]); 13201bd4fe43Sopenharmony_ci val = SdhciReadl(host, MULTI_CYCLE_R); 13211bd4fe43Sopenharmony_ci val |= SDHCI_EDGE_DETECT_EN | SDHCI_DATA_DLY_EN; 13221bd4fe43Sopenharmony_ci val &= ~SDHCI_CMD_DLY_EN; 13231bd4fe43Sopenharmony_ci SdhciWritel(host, val, MULTI_CYCLE_R); 13241bd4fe43Sopenharmony_ci} 13251bd4fe43Sopenharmony_ci 13261bd4fe43Sopenharmony_civoid SdhciWaitSamplDllReady(uint32_t id) 13271bd4fe43Sopenharmony_ci{ 13281bd4fe43Sopenharmony_ci uint32_t offset[] = { PERI_SD_SAMPL_DLL_STATUS, PERI_SDIO_SAMPL_DLL_STATUS }; 13291bd4fe43Sopenharmony_ci uint32_t i, val; 13301bd4fe43Sopenharmony_ci 13311bd4fe43Sopenharmony_ci if (id >= (sizeof(offset) / sizeof(offset[0]))) { 13321bd4fe43Sopenharmony_ci return; 13331bd4fe43Sopenharmony_ci } 13341bd4fe43Sopenharmony_ci 13351bd4fe43Sopenharmony_ci for (i = 0; i < SDHCI_CLK_CTRL_RETRY_TIMES; i++) { 13361bd4fe43Sopenharmony_ci val = OSAL_READL(offset[id]); 13371bd4fe43Sopenharmony_ci if ((val & SDHCI_SAMPL_DLL_DEV_READY) > 0) { 13381bd4fe43Sopenharmony_ci return; 13391bd4fe43Sopenharmony_ci } 13401bd4fe43Sopenharmony_ci OsalMDelay(1); 13411bd4fe43Sopenharmony_ci } 13421bd4fe43Sopenharmony_ci HDF_LOGD("host%u: SAMPL DLL not ready.", id); 13431bd4fe43Sopenharmony_ci} 13441bd4fe43Sopenharmony_ci 13451bd4fe43Sopenharmony_cistatic void SdhciCardClk(struct SdhciHost *host, bool action) 13461bd4fe43Sopenharmony_ci{ 13471bd4fe43Sopenharmony_ci uint32_t value; 13481bd4fe43Sopenharmony_ci 13491bd4fe43Sopenharmony_ci value = SdhciReadl(host, CLK_CTRL_R); 13501bd4fe43Sopenharmony_ci if (action == false) { 13511bd4fe43Sopenharmony_ci /* close the clock gate */ 13521bd4fe43Sopenharmony_ci value &= ~SDHCI_CLK_CTRL_CLK_EN; 13531bd4fe43Sopenharmony_ci } else { 13541bd4fe43Sopenharmony_ci /* open the clk of interface */ 13551bd4fe43Sopenharmony_ci value |= SDHCI_CLK_CTRL_CLK_EN; 13561bd4fe43Sopenharmony_ci } 13571bd4fe43Sopenharmony_ci SdhciWritel(host, value, CLK_CTRL_R); 13581bd4fe43Sopenharmony_ci} 13591bd4fe43Sopenharmony_ci 13601bd4fe43Sopenharmony_cistatic void SdhciSelectSamplPhase(struct SdhciHost *host, uint32_t phase) 13611bd4fe43Sopenharmony_ci{ 13621bd4fe43Sopenharmony_ci SdhciCardClk(host, false); 13631bd4fe43Sopenharmony_ci SdhciSetSampPhase(host, phase); 13641bd4fe43Sopenharmony_ci SdhciWaitSamplDllReady(host->hostId); 13651bd4fe43Sopenharmony_ci SdhciCardClk(host, true); 13661bd4fe43Sopenharmony_ci OsalUDelay(1); 13671bd4fe43Sopenharmony_ci} 13681bd4fe43Sopenharmony_ci 13691bd4fe43Sopenharmony_cistatic void SdhciDisEdgeTune(struct SdhciHost *host) 13701bd4fe43Sopenharmony_ci{ 13711bd4fe43Sopenharmony_ci uint32_t val; 13721bd4fe43Sopenharmony_ci 13731bd4fe43Sopenharmony_ci val = SdhciReadl(host, MULTI_CYCLE_R); 13741bd4fe43Sopenharmony_ci val &= ~SDHCI_EDGE_DETECT_EN; 13751bd4fe43Sopenharmony_ci SdhciWritel(host, val, MULTI_CYCLE_R); 13761bd4fe43Sopenharmony_ci} 13771bd4fe43Sopenharmony_ci 13781bd4fe43Sopenharmony_cistatic void SdhciPostTune(struct SdhciHost *host) 13791bd4fe43Sopenharmony_ci{ 13801bd4fe43Sopenharmony_ci uint32_t val; 13811bd4fe43Sopenharmony_ci uint16_t ctrl; 13821bd4fe43Sopenharmony_ci 13831bd4fe43Sopenharmony_ci ctrl = SdhciReadw(host, HOST_CTRL2_R); 13841bd4fe43Sopenharmony_ci ctrl |= SDHCI_TUNED_CLK; 13851bd4fe43Sopenharmony_ci SdhciWritew(host, ctrl, HOST_CTRL2_R); 13861bd4fe43Sopenharmony_ci 13871bd4fe43Sopenharmony_ci val = SdhciReadl(host, NORMAL_INT_STAT_EN_R); 13881bd4fe43Sopenharmony_ci val &= ~SDHCI_INTERRUPT_DATA_AVAIL; 13891bd4fe43Sopenharmony_ci SdhciWritel(host, val, NORMAL_INT_STAT_EN_R); 13901bd4fe43Sopenharmony_ci val = SdhciReadl(host, NORMAL_INT_SIGNAL_EN_R); 13911bd4fe43Sopenharmony_ci val &= ~SDHCI_INTERRUPT_DATA_AVAIL; 13921bd4fe43Sopenharmony_ci SdhciWritel(host, val, NORMAL_INT_SIGNAL_EN_R); 13931bd4fe43Sopenharmony_ci} 13941bd4fe43Sopenharmony_ci 13951bd4fe43Sopenharmony_cistatic void SdhciDoTune(struct SdhciHost *host, uint32_t opcode, uint32_t start, uint32_t end) 13961bd4fe43Sopenharmony_ci{ 13971bd4fe43Sopenharmony_ci int32_t err; 13981bd4fe43Sopenharmony_ci int32_t prevError = 0; 13991bd4fe43Sopenharmony_ci uint32_t phase, fall, rise, fallUpdateFlag, index; 14001bd4fe43Sopenharmony_ci 14011bd4fe43Sopenharmony_ci fall = start; 14021bd4fe43Sopenharmony_ci rise = end; 14031bd4fe43Sopenharmony_ci fallUpdateFlag = 0; 14041bd4fe43Sopenharmony_ci for (index = start; index <= end; index++) { 14051bd4fe43Sopenharmony_ci SdhciSelectSamplPhase(host, index % SDHCI_PHASE_SCALE); 14061bd4fe43Sopenharmony_ci err = MmcSendTuning(host->mmc, opcode, true); 14071bd4fe43Sopenharmony_ci if (err != HDF_SUCCESS) { 14081bd4fe43Sopenharmony_ci HDF_LOGD("send tuning CMD%u fail! phase:%u err:%d.", opcode, index, err); 14091bd4fe43Sopenharmony_ci } 14101bd4fe43Sopenharmony_ci if (err && index == start) { 14111bd4fe43Sopenharmony_ci if (!fallUpdateFlag) { 14121bd4fe43Sopenharmony_ci fallUpdateFlag = 1; 14131bd4fe43Sopenharmony_ci fall = start; 14141bd4fe43Sopenharmony_ci } 14151bd4fe43Sopenharmony_ci } else { 14161bd4fe43Sopenharmony_ci if (!prevError && err && !fallUpdateFlag) { 14171bd4fe43Sopenharmony_ci fallUpdateFlag = 1; 14181bd4fe43Sopenharmony_ci fall = index; 14191bd4fe43Sopenharmony_ci } 14201bd4fe43Sopenharmony_ci } 14211bd4fe43Sopenharmony_ci 14221bd4fe43Sopenharmony_ci if (prevError && !err) { 14231bd4fe43Sopenharmony_ci rise = index; 14241bd4fe43Sopenharmony_ci } 14251bd4fe43Sopenharmony_ci 14261bd4fe43Sopenharmony_ci if (err && index == end) { 14271bd4fe43Sopenharmony_ci rise = end; 14281bd4fe43Sopenharmony_ci } 14291bd4fe43Sopenharmony_ci prevError = err; 14301bd4fe43Sopenharmony_ci } 14311bd4fe43Sopenharmony_ci 14321bd4fe43Sopenharmony_ci phase = ((fall + rise) / SDHCI_DIV_MIDDLE + SDHCI_PHASE_SCALE_GAP) % SDHCI_PHASE_SCALE; 14331bd4fe43Sopenharmony_ci host->tuningPhase = phase; 14341bd4fe43Sopenharmony_ci SdhciSelectSamplPhase(host, phase); 14351bd4fe43Sopenharmony_ci SdhciPostTune(host); 14361bd4fe43Sopenharmony_ci} 14371bd4fe43Sopenharmony_ci 14381bd4fe43Sopenharmony_cistatic int32_t SdhciTune(struct MmcCntlr *cntlr, uint32_t cmdCode) 14391bd4fe43Sopenharmony_ci{ 14401bd4fe43Sopenharmony_ci struct SdhciHost *host = (struct SdhciHost *)cntlr->priv; 14411bd4fe43Sopenharmony_ci uint32_t index, val; 14421bd4fe43Sopenharmony_ci bool found = false; 14431bd4fe43Sopenharmony_ci bool prevFound = false; 14441bd4fe43Sopenharmony_ci uint32_t edgeP2F = 0; 14451bd4fe43Sopenharmony_ci uint32_t start = 0; 14461bd4fe43Sopenharmony_ci uint32_t edgeF2P = SDHCI_PHASE_SCALE / SDHCI_PHASE_SCALE_TIMES; 14471bd4fe43Sopenharmony_ci uint32_t end = SDHCI_PHASE_SCALE / SDHCI_PHASE_SCALE_TIMES; 14481bd4fe43Sopenharmony_ci int32_t err; 14491bd4fe43Sopenharmony_ci 14501bd4fe43Sopenharmony_ci SdhciPreTune(host); 14511bd4fe43Sopenharmony_ci SdhciEnableEdgeTune(host); 14521bd4fe43Sopenharmony_ci for (index = 0; index <= end; index++) { 14531bd4fe43Sopenharmony_ci SdhciSelectSamplPhase(host, index * SDHCI_PHASE_SCALE_TIMES); 14541bd4fe43Sopenharmony_ci err = MmcSendTuning(cntlr, cmdCode, true); 14551bd4fe43Sopenharmony_ci if (err == HDF_SUCCESS) { 14561bd4fe43Sopenharmony_ci val = SdhciReadl(host, MULTI_CYCLE_R); 14571bd4fe43Sopenharmony_ci found = ((val & SDHCI_FOUND_EDGE) > 0 ? true : false); 14581bd4fe43Sopenharmony_ci } else { 14591bd4fe43Sopenharmony_ci found = true; 14601bd4fe43Sopenharmony_ci } 14611bd4fe43Sopenharmony_ci 14621bd4fe43Sopenharmony_ci if (prevFound == true && found == false) { 14631bd4fe43Sopenharmony_ci edgeF2P = index; 14641bd4fe43Sopenharmony_ci } else if (prevFound == false && found == true) { 14651bd4fe43Sopenharmony_ci edgeP2F = index; 14661bd4fe43Sopenharmony_ci } 14671bd4fe43Sopenharmony_ci if ((edgeP2F != start) && (edgeF2P != end)) { 14681bd4fe43Sopenharmony_ci break; 14691bd4fe43Sopenharmony_ci } 14701bd4fe43Sopenharmony_ci prevFound = found; 14711bd4fe43Sopenharmony_ci found = false; 14721bd4fe43Sopenharmony_ci } 14731bd4fe43Sopenharmony_ci 14741bd4fe43Sopenharmony_ci if ((edgeP2F == start) && (edgeF2P == end)) { 14751bd4fe43Sopenharmony_ci HDF_LOGE("host%u: tuning failed! can not found edge!", host->hostId); 14761bd4fe43Sopenharmony_ci return HDF_FAILURE; 14771bd4fe43Sopenharmony_ci } 14781bd4fe43Sopenharmony_ci SdhciDisEdgeTune(host); 14791bd4fe43Sopenharmony_ci 14801bd4fe43Sopenharmony_ci start = edgeP2F * SDHCI_PHASE_SCALE_TIMES; 14811bd4fe43Sopenharmony_ci end = edgeF2P * SDHCI_PHASE_SCALE_TIMES; 14821bd4fe43Sopenharmony_ci if (end <= start) { 14831bd4fe43Sopenharmony_ci end += SDHCI_PHASE_SCALE; 14841bd4fe43Sopenharmony_ci } 14851bd4fe43Sopenharmony_ci 14861bd4fe43Sopenharmony_ci SdhciDoTune(host, cmdCode, start, end); 14871bd4fe43Sopenharmony_ci return HDF_SUCCESS; 14881bd4fe43Sopenharmony_ci} 14891bd4fe43Sopenharmony_ci 14901bd4fe43Sopenharmony_cistatic int32_t SdhciRescanSdioDev(struct MmcCntlr *cntlr) 14911bd4fe43Sopenharmony_ci{ 14921bd4fe43Sopenharmony_ci struct SdhciHost *host = NULL; 14931bd4fe43Sopenharmony_ci 14941bd4fe43Sopenharmony_ci if ((cntlr == NULL) || (cntlr->priv == NULL)) { 14951bd4fe43Sopenharmony_ci return HDF_ERR_INVALID_OBJECT; 14961bd4fe43Sopenharmony_ci } 14971bd4fe43Sopenharmony_ci 14981bd4fe43Sopenharmony_ci host = (struct SdhciHost *)cntlr->priv; 14991bd4fe43Sopenharmony_ci if (host->waitForEvent == true) { 15001bd4fe43Sopenharmony_ci (void)SDHCI_EVENT_SIGNAL(&host->sdhciEvent, SDHCI_PEND_ACCIDENT); 15011bd4fe43Sopenharmony_ci } 15021bd4fe43Sopenharmony_ci 15031bd4fe43Sopenharmony_ci return MmcCntlrAddSdioRescanMsgToQueue(cntlr); 15041bd4fe43Sopenharmony_ci} 15051bd4fe43Sopenharmony_ci 15061bd4fe43Sopenharmony_cistatic struct MmcCntlrOps g_sdhciHostOps = { 15071bd4fe43Sopenharmony_ci .request = SdhciDoRequest, 15081bd4fe43Sopenharmony_ci .setClock = SdhciSetClock, 15091bd4fe43Sopenharmony_ci .setPowerMode = SdhciSetPowerMode, 15101bd4fe43Sopenharmony_ci .setBusWidth = SdhciSetBusWidth, 15111bd4fe43Sopenharmony_ci .setBusTiming = SdhciSetBusTiming, 15121bd4fe43Sopenharmony_ci .setSdioIrq = SdhciSetSdioIrq, 15131bd4fe43Sopenharmony_ci .hardwareReset = SdhciHardwareReset, 15141bd4fe43Sopenharmony_ci .systemInit = SdhciSystemInit, 15151bd4fe43Sopenharmony_ci .setEnhanceStrobe = SdhciSetEnhanceStrobe, 15161bd4fe43Sopenharmony_ci .switchVoltage = SdhciSwitchVoltage, 15171bd4fe43Sopenharmony_ci .devReadOnly = SdhciDevReadOnly, 15181bd4fe43Sopenharmony_ci .devPlugged = SdhciCardPlugged, 15191bd4fe43Sopenharmony_ci .devBusy = SdhciDevBusy, 15201bd4fe43Sopenharmony_ci .tune = SdhciTune, 15211bd4fe43Sopenharmony_ci .rescanSdioDev = SdhciRescanSdioDev, 15221bd4fe43Sopenharmony_ci}; 15231bd4fe43Sopenharmony_ci 15241bd4fe43Sopenharmony_cistatic void SdhciDeleteHost(struct SdhciHost *host) 15251bd4fe43Sopenharmony_ci{ 15261bd4fe43Sopenharmony_ci struct MmcCntlr *cntlr = NULL; 15271bd4fe43Sopenharmony_ci 15281bd4fe43Sopenharmony_ci if (host == NULL) { 15291bd4fe43Sopenharmony_ci return; 15301bd4fe43Sopenharmony_ci } 15311bd4fe43Sopenharmony_ci 15321bd4fe43Sopenharmony_ci cntlr = host->mmc; 15331bd4fe43Sopenharmony_ci if (cntlr != NULL) { 15341bd4fe43Sopenharmony_ci if (cntlr->curDev != NULL) { 15351bd4fe43Sopenharmony_ci MmcDeviceRemove(cntlr->curDev); 15361bd4fe43Sopenharmony_ci OsalMemFree(cntlr->curDev); 15371bd4fe43Sopenharmony_ci cntlr->curDev = NULL; 15381bd4fe43Sopenharmony_ci } 15391bd4fe43Sopenharmony_ci MmcCntlrRemove(cntlr); 15401bd4fe43Sopenharmony_ci cntlr->hdfDevObj = NULL; 15411bd4fe43Sopenharmony_ci cntlr->priv = NULL; 15421bd4fe43Sopenharmony_ci cntlr->ops = NULL; 15431bd4fe43Sopenharmony_ci OsalMemFree(cntlr); 15441bd4fe43Sopenharmony_ci host->mmc = NULL; 15451bd4fe43Sopenharmony_ci } 15461bd4fe43Sopenharmony_ci 15471bd4fe43Sopenharmony_ci OsalUnregisterIrq(host->irqNum, host); 15481bd4fe43Sopenharmony_ci if (host->admaDesc != NULL) { 15491bd4fe43Sopenharmony_ci OsalMemFree(host->admaDesc); 15501bd4fe43Sopenharmony_ci host->admaDesc = NULL; 15511bd4fe43Sopenharmony_ci } 15521bd4fe43Sopenharmony_ci if (host->base != NULL) { 15531bd4fe43Sopenharmony_ci OsalIoUnmap(host->base); 15541bd4fe43Sopenharmony_ci } 15551bd4fe43Sopenharmony_ci 15561bd4fe43Sopenharmony_ci (void)SDHCI_EVENT_DELETE(&host->sdhciEvent); 15571bd4fe43Sopenharmony_ci (void)OsalMutexDestroy(&host->mutex); 15581bd4fe43Sopenharmony_ci OsalMemFree(host); 15591bd4fe43Sopenharmony_ci} 15601bd4fe43Sopenharmony_ci 15611bd4fe43Sopenharmony_cistatic int32_t SdhciHostParse(struct SdhciHost *host, struct HdfDeviceObject *obj) 15621bd4fe43Sopenharmony_ci{ 15631bd4fe43Sopenharmony_ci const struct DeviceResourceNode *node = NULL; 15641bd4fe43Sopenharmony_ci struct DeviceResourceIface *drsOps = NULL; 15651bd4fe43Sopenharmony_ci int32_t ret; 15661bd4fe43Sopenharmony_ci uint32_t regBase, regSize; 15671bd4fe43Sopenharmony_ci 15681bd4fe43Sopenharmony_ci if (obj == NULL || host == NULL) { 15691bd4fe43Sopenharmony_ci HDF_LOGE("%s: input param is NULL.", __func__); 15701bd4fe43Sopenharmony_ci return HDF_FAILURE; 15711bd4fe43Sopenharmony_ci } 15721bd4fe43Sopenharmony_ci 15731bd4fe43Sopenharmony_ci node = obj->property; 15741bd4fe43Sopenharmony_ci if (node == NULL) { 15751bd4fe43Sopenharmony_ci HDF_LOGE("%s: drs node is NULL.", __func__); 15761bd4fe43Sopenharmony_ci return HDF_FAILURE; 15771bd4fe43Sopenharmony_ci } 15781bd4fe43Sopenharmony_ci drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE); 15791bd4fe43Sopenharmony_ci if (drsOps == NULL || drsOps->GetUint32 == NULL) { 15801bd4fe43Sopenharmony_ci HDF_LOGE("%s: invalid drs ops fail!", __func__); 15811bd4fe43Sopenharmony_ci return HDF_FAILURE; 15821bd4fe43Sopenharmony_ci } 15831bd4fe43Sopenharmony_ci 15841bd4fe43Sopenharmony_ci ret = drsOps->GetUint32(node, "regBasePhy", ®Base, 0); 15851bd4fe43Sopenharmony_ci if (ret != HDF_SUCCESS) { 15861bd4fe43Sopenharmony_ci HDF_LOGE("%s: read regBasePhy fail!", __func__); 15871bd4fe43Sopenharmony_ci return ret; 15881bd4fe43Sopenharmony_ci } 15891bd4fe43Sopenharmony_ci ret = drsOps->GetUint32(node, "regSize", ®Size, 0); 15901bd4fe43Sopenharmony_ci if (ret != HDF_SUCCESS) { 15911bd4fe43Sopenharmony_ci HDF_LOGE("%s: read regSize fail!", __func__); 15921bd4fe43Sopenharmony_ci return ret; 15931bd4fe43Sopenharmony_ci } 15941bd4fe43Sopenharmony_ci host->base = OsalIoRemap(regBase, regSize); 15951bd4fe43Sopenharmony_ci if (host->base == NULL) { 15961bd4fe43Sopenharmony_ci HDF_LOGE("%s: ioremap regBase fail!", __func__); 15971bd4fe43Sopenharmony_ci return HDF_ERR_IO; 15981bd4fe43Sopenharmony_ci } 15991bd4fe43Sopenharmony_ci 16001bd4fe43Sopenharmony_ci ret = drsOps->GetUint32(node, "irqNum", &(host->irqNum), 0); 16011bd4fe43Sopenharmony_ci if (ret != HDF_SUCCESS) { 16021bd4fe43Sopenharmony_ci HDF_LOGE("%s: read irqNum fail!", __func__); 16031bd4fe43Sopenharmony_ci } 16041bd4fe43Sopenharmony_ci 16051bd4fe43Sopenharmony_ci ret = drsOps->GetUint32(node, "quirks", &(host->quirks.quirksData), 0); 16061bd4fe43Sopenharmony_ci if (ret != HDF_SUCCESS) { 16071bd4fe43Sopenharmony_ci HDF_LOGD("%s: read quirks fail!", __func__); 16081bd4fe43Sopenharmony_ci host->quirks.quirksData = 0; 16091bd4fe43Sopenharmony_ci } 16101bd4fe43Sopenharmony_ci return ret; 16111bd4fe43Sopenharmony_ci} 16121bd4fe43Sopenharmony_ci 16131bd4fe43Sopenharmony_cistatic void SdhciCrgInit(struct SdhciHost *host) 16141bd4fe43Sopenharmony_ci{ 16151bd4fe43Sopenharmony_ci uint32_t value, reg; 16161bd4fe43Sopenharmony_ci uint32_t cfgArray[] = {PERI_CRG125, PERI_CRG139}; 16171bd4fe43Sopenharmony_ci if (host->hostId >= SDHCI_MAX_HOST_NUM) { 16181bd4fe43Sopenharmony_ci return; 16191bd4fe43Sopenharmony_ci } 16201bd4fe43Sopenharmony_ci 16211bd4fe43Sopenharmony_ci /* open the clock gate */ 16221bd4fe43Sopenharmony_ci reg = cfgArray[host->hostId]; 16231bd4fe43Sopenharmony_ci value = OSAL_READL(reg); 16241bd4fe43Sopenharmony_ci value |= SDHCI_EMMC_CKEN; 16251bd4fe43Sopenharmony_ci OSAL_WRITEL(value, reg); 16261bd4fe43Sopenharmony_ci 16271bd4fe43Sopenharmony_ci /* crg_reset, dll_reset, sampl_reset */ 16281bd4fe43Sopenharmony_ci reg = cfgArray[host->hostId]; 16291bd4fe43Sopenharmony_ci value = OSAL_READL(reg); 16301bd4fe43Sopenharmony_ci value |= SDHCI_EMMC_CRG_REQ; 16311bd4fe43Sopenharmony_ci value |= SDHCI_EMMC_DLL_RST; 16321bd4fe43Sopenharmony_ci OSAL_WRITEL(value, reg); 16331bd4fe43Sopenharmony_ci 16341bd4fe43Sopenharmony_ci /* wait the card clk close for 25us */ 16351bd4fe43Sopenharmony_ci HalDelayUs(25); 16361bd4fe43Sopenharmony_ci 16371bd4fe43Sopenharmony_ci /* reset of host contorl is done */ 16381bd4fe43Sopenharmony_ci value = OSAL_READL(reg); 16391bd4fe43Sopenharmony_ci value &= ~SDHCI_EMMC_CRG_REQ; 16401bd4fe43Sopenharmony_ci OSAL_WRITEL(value, reg); 16411bd4fe43Sopenharmony_ci HalDelayUs(25); 16421bd4fe43Sopenharmony_ci 16431bd4fe43Sopenharmony_ci /* close the clock gate */ 16441bd4fe43Sopenharmony_ci SdhciCardClk(host, false); 16451bd4fe43Sopenharmony_ci 16461bd4fe43Sopenharmony_ci if (host->mmc->devType == MMC_DEV_EMMC) { 16471bd4fe43Sopenharmony_ci (void)SdhciSelectClock(host, SDHCI_MMC_FREQ_150M); 16481bd4fe43Sopenharmony_ci } else { 16491bd4fe43Sopenharmony_ci (void)SdhciSelectClock(host, SDHCI_MMC_FREQ_50M); 16501bd4fe43Sopenharmony_ci } 16511bd4fe43Sopenharmony_ci 16521bd4fe43Sopenharmony_ci /* SAM/DRV */ 16531bd4fe43Sopenharmony_ci SdhciSetDrvPhase(host->hostId, 0x10); 16541bd4fe43Sopenharmony_ci /* wait the clock switch over for 25us */ 16551bd4fe43Sopenharmony_ci OsalUDelay(25); 16561bd4fe43Sopenharmony_ci 16571bd4fe43Sopenharmony_ci /* open the clk of interface */ 16581bd4fe43Sopenharmony_ci SdhciCardClk(host, true); 16591bd4fe43Sopenharmony_ci 16601bd4fe43Sopenharmony_ci /* open the clk of card */ 16611bd4fe43Sopenharmony_ci value = SdhciReadl(host, CLK_CTRL_R); 16621bd4fe43Sopenharmony_ci value |= (SDHCI_CLK_CTRL_INT_CLK_EN | SDHCI_CLK_CTRL_CLK_EN | SDHCI_CLK_CTRL_PLL_EN); 16631bd4fe43Sopenharmony_ci SdhciWritel(host, value, CLK_CTRL_R); 16641bd4fe43Sopenharmony_ci /* wait the phase switch over, 75us */ 16651bd4fe43Sopenharmony_ci OsalUDelay(75); 16661bd4fe43Sopenharmony_ci} 16671bd4fe43Sopenharmony_ci 16681bd4fe43Sopenharmony_cistatic void SdhciUpdateCapFlag(struct SdhciHost *host, uint32_t cap) 16691bd4fe43Sopenharmony_ci{ 16701bd4fe43Sopenharmony_ci struct MmcCntlr *mmc = host->mmc; 16711bd4fe43Sopenharmony_ci 16721bd4fe43Sopenharmony_ci if (cap & SDHCI_SUPPORT_SDMA) { 16731bd4fe43Sopenharmony_ci host->flags |= SDHCI_USE_SDMA; 16741bd4fe43Sopenharmony_ci } 16751bd4fe43Sopenharmony_ci 16761bd4fe43Sopenharmony_ci if ((host->version >= SDHCI_HOST_SPEC_200) && (cap & SDHCI_SUPPORT_ADMA2)) { 16771bd4fe43Sopenharmony_ci host->flags |= SDHCI_USE_ADMA; 16781bd4fe43Sopenharmony_ci if (cap & SDHCI_SUPPORT_64BIT) { 16791bd4fe43Sopenharmony_ci host->flags |= SDHCI_USE_64BIT_ADMA; 16801bd4fe43Sopenharmony_ci } 16811bd4fe43Sopenharmony_ci } 16821bd4fe43Sopenharmony_ci 16831bd4fe43Sopenharmony_ci if ((host->version >= SDHCI_HOST_SPEC_300 && (host->flags & SDHCI_USE_ADMA) > 0) || 16841bd4fe43Sopenharmony_ci (host->flags & SDHCI_USE_SDMA) == 0) { 16851bd4fe43Sopenharmony_ci host->flags |= SDHCI_AUTO_CMD23; 16861bd4fe43Sopenharmony_ci HDF_LOGD("Auto-CMD23 available!"); 16871bd4fe43Sopenharmony_ci } 16881bd4fe43Sopenharmony_ci 16891bd4fe43Sopenharmony_ci host->flags |= SDHCI_HOST_IRQ_STATUS; 16901bd4fe43Sopenharmony_ci if (mmc->devType == MMC_DEV_SDIO) { 16911bd4fe43Sopenharmony_ci host->flags &= ~(SDHCI_SUPPORT_SDMA | SDHCI_AUTO_CMD23 | SDHCI_AUTO_CMD12); 16921bd4fe43Sopenharmony_ci } else { 16931bd4fe43Sopenharmony_ci host->flags &= ~(SDHCI_SUPPORT_SDMA); 16941bd4fe43Sopenharmony_ci host->flags |= SDHCI_AUTO_CMD23; 16951bd4fe43Sopenharmony_ci } 16961bd4fe43Sopenharmony_ci} 16971bd4fe43Sopenharmony_ci 16981bd4fe43Sopenharmony_cistatic int32_t SdhciFillAdmaInfo(struct SdhciHost *host) 16991bd4fe43Sopenharmony_ci{ 17001bd4fe43Sopenharmony_ci if (host->flags & SDHCI_USE_ADMA) { 17011bd4fe43Sopenharmony_ci host->admaMaxDesc = SDHCI_ADMA_MAX_DESC; 17021bd4fe43Sopenharmony_ci host->admaDescSize = SDHCI_ADMA_DEF_SIZE; 17031bd4fe43Sopenharmony_ci 17041bd4fe43Sopenharmony_ci if (host->flags & SDHCI_USE_64BIT_ADMA) { 17051bd4fe43Sopenharmony_ci host->admaDescLineSize = SDHCI_ADMA_64BIT_LINE_SIZE; 17061bd4fe43Sopenharmony_ci } else { 17071bd4fe43Sopenharmony_ci host->admaDescLineSize = SDHCI_ADMA_LINE_SIZE; 17081bd4fe43Sopenharmony_ci } 17091bd4fe43Sopenharmony_ci host->admaDescSize = (host->admaMaxDesc * 2 + 1) * host->admaDescLineSize; 17101bd4fe43Sopenharmony_ci host->admaDesc = (void *)OsalMemAllocAlign(CACHE_ALIGNED_SIZE, ALIGN(host->admaDescSize, CACHE_ALIGNED_SIZE)); 17111bd4fe43Sopenharmony_ci if (host->admaDesc == NULL) { 17121bd4fe43Sopenharmony_ci HDF_LOGE("SdhciFillAdmaInfo: allocate ADMA buffer fail!"); 17131bd4fe43Sopenharmony_ci return HDF_ERR_MALLOC_FAIL; 17141bd4fe43Sopenharmony_ci } 17151bd4fe43Sopenharmony_ci } else { 17161bd4fe43Sopenharmony_ci HDF_LOGE("SdhciFillAdmaInfo: Warning! ADMA not support!"); 17171bd4fe43Sopenharmony_ci return HDF_ERR_NOT_SUPPORT; 17181bd4fe43Sopenharmony_ci } 17191bd4fe43Sopenharmony_ci return HDF_SUCCESS; 17201bd4fe43Sopenharmony_ci} 17211bd4fe43Sopenharmony_ci 17221bd4fe43Sopenharmony_cistatic void SdhciFillClkInfo(struct SdhciHost *host, uint32_t cap1, uint32_t cap2) 17231bd4fe43Sopenharmony_ci{ 17241bd4fe43Sopenharmony_ci struct MmcCntlr *mmc = host->mmc; 17251bd4fe43Sopenharmony_ci 17261bd4fe43Sopenharmony_ci if (host->version >= SDHCI_HOST_SPEC_300) { 17271bd4fe43Sopenharmony_ci host->maxClk = (cap1 & SDHCI_BASIC_FREQ_OF_CLK_MASK) >> SDHCI_BASIC_FREQ_OF_CLK_SHIFT; 17281bd4fe43Sopenharmony_ci } else { 17291bd4fe43Sopenharmony_ci host->maxClk = (cap1 & SDHCI_CLK_BASE_MASK) >> SDHCI_BASIC_FREQ_OF_CLK_SHIFT; 17301bd4fe43Sopenharmony_ci } 17311bd4fe43Sopenharmony_ci /* unit: MHz */ 17321bd4fe43Sopenharmony_ci host->maxClk *= 1000000; 17331bd4fe43Sopenharmony_ci host->clkMul = (cap2 & SDHCI_CLK_MUL_MASK) >> SDHCI_CLK_MUL_SHIFT; 17341bd4fe43Sopenharmony_ci 17351bd4fe43Sopenharmony_ci if (host->clkMul) { 17361bd4fe43Sopenharmony_ci host->clkMul += 1; 17371bd4fe43Sopenharmony_ci } 17381bd4fe43Sopenharmony_ci if (mmc->freqMax == 0) { 17391bd4fe43Sopenharmony_ci mmc->freqMax = host->maxClk; 17401bd4fe43Sopenharmony_ci } else { 17411bd4fe43Sopenharmony_ci host->maxClk = mmc->freqMax; 17421bd4fe43Sopenharmony_ci } 17431bd4fe43Sopenharmony_ci 17441bd4fe43Sopenharmony_ci if (mmc->freqMin == 0) { 17451bd4fe43Sopenharmony_ci if (host->version >= SDHCI_HOST_SPEC_300) { 17461bd4fe43Sopenharmony_ci if (host->clkMul) { 17471bd4fe43Sopenharmony_ci mmc->freqMin = (host->maxClk * host->clkMul) / 1024; 17481bd4fe43Sopenharmony_ci mmc->freqMax = host->maxClk * host->clkMul; 17491bd4fe43Sopenharmony_ci } else { 17501bd4fe43Sopenharmony_ci mmc->freqMin = host->maxClk / SDHCI_MAX_DIV_SPEC_300; 17511bd4fe43Sopenharmony_ci } 17521bd4fe43Sopenharmony_ci } else { 17531bd4fe43Sopenharmony_ci mmc->freqMin = host->maxClk / SDHCI_MAX_DIV_SPEC_200; 17541bd4fe43Sopenharmony_ci } 17551bd4fe43Sopenharmony_ci } 17561bd4fe43Sopenharmony_ci} 17571bd4fe43Sopenharmony_ci 17581bd4fe43Sopenharmony_cistatic void SdhciUpdateDrvCap(struct SdhciHost *host, uint32_t cap1, uint32_t cap2) 17591bd4fe43Sopenharmony_ci{ 17601bd4fe43Sopenharmony_ci struct MmcCntlr *mmc = host->mmc; 17611bd4fe43Sopenharmony_ci 17621bd4fe43Sopenharmony_ci if (cap1 & SDHCI_SUPPORT_HISPD) { 17631bd4fe43Sopenharmony_ci mmc->caps.bits.highSpeed = 1; 17641bd4fe43Sopenharmony_ci } 17651bd4fe43Sopenharmony_ci 17661bd4fe43Sopenharmony_ci if (cap2 & SDHCI_SUPPORT_DRIVER_TYPE_A) { 17671bd4fe43Sopenharmony_ci mmc->caps.bits.driverTypeA = 1; 17681bd4fe43Sopenharmony_ci } 17691bd4fe43Sopenharmony_ci if (cap2 & SDHCI_SUPPORT_DRIVER_TYPE_C) { 17701bd4fe43Sopenharmony_ci mmc->caps.bits.driverTypeC = 1; 17711bd4fe43Sopenharmony_ci } 17721bd4fe43Sopenharmony_ci if (cap2 & SDHCI_SUPPORT_DRIVER_TYPE_D) { 17731bd4fe43Sopenharmony_ci mmc->caps.bits.driverTypeD = 1; 17741bd4fe43Sopenharmony_ci } 17751bd4fe43Sopenharmony_ci 17761bd4fe43Sopenharmony_ci if (mmc->devType == MMC_DEV_EMMC) { 17771bd4fe43Sopenharmony_ci if (cap1 & SDHCI_SUPPORT_VDD_180) { 17781bd4fe43Sopenharmony_ci mmc->ocrDef.bits.vdd1v65To1v95 = 1; 17791bd4fe43Sopenharmony_ci HDF_LOGD("VDD1.8 support."); 17801bd4fe43Sopenharmony_ci } 17811bd4fe43Sopenharmony_ci } 17821bd4fe43Sopenharmony_ci 17831bd4fe43Sopenharmony_ci if (host->flags & SDHCI_USE_ADMA) { 17841bd4fe43Sopenharmony_ci mmc->maxReqSize = host->admaMaxDesc * 65536; 17851bd4fe43Sopenharmony_ci } 17861bd4fe43Sopenharmony_ci 17871bd4fe43Sopenharmony_ci mmc->maxBlkSize = (cap1 & SDHCI_MAX_BLOCK_SIZE_MASK) >> SDHCI_MAX_BLOCK_SIZE_SHIFT; 17881bd4fe43Sopenharmony_ci mmc->maxBlkSize = MMC_SEC_SIZE << mmc->maxBlkSize; 17891bd4fe43Sopenharmony_ci mmc->maxBlkNum = (mmc->maxReqSize / mmc->maxBlkSize); 17901bd4fe43Sopenharmony_ci} 17911bd4fe43Sopenharmony_ci 17921bd4fe43Sopenharmony_cistatic void SdhciEnableSdioIrqNoLock(struct SdhciHost *host, bool enable) 17931bd4fe43Sopenharmony_ci{ 17941bd4fe43Sopenharmony_ci if (!(host->flags & SDHCI_DEVICE_DEAD)) { 17951bd4fe43Sopenharmony_ci if (enable == true) { 17961bd4fe43Sopenharmony_ci host->irqEnable |= SDHCI_INTERRUPT_CARD_INT; 17971bd4fe43Sopenharmony_ci } else { 17981bd4fe43Sopenharmony_ci host->irqEnable &= ~SDHCI_INTERRUPT_CARD_INT; 17991bd4fe43Sopenharmony_ci } 18001bd4fe43Sopenharmony_ci SdhciEnablePlugIrq(host, host->irqEnable); 18011bd4fe43Sopenharmony_ci } 18021bd4fe43Sopenharmony_ci} 18031bd4fe43Sopenharmony_ci 18041bd4fe43Sopenharmony_cistatic void SdhciSaveCommandResp(struct SdhciHost *host, struct MmcCmd *cmd) 18051bd4fe43Sopenharmony_ci{ 18061bd4fe43Sopenharmony_ci uint32_t i; 18071bd4fe43Sopenharmony_ci 18081bd4fe43Sopenharmony_ci for (i = 0; i < MMC_CMD_RESP_SIZE; i++) { 18091bd4fe43Sopenharmony_ci cmd->resp[i] = SdhciReadl(host, RESP01_R + (3 - i) * 4) << 8; 18101bd4fe43Sopenharmony_ci if (i != 3) { 18111bd4fe43Sopenharmony_ci cmd->resp[i] |= SdhciReadb(host, RESP01_R + (3 - i) * 4 - 1); 18121bd4fe43Sopenharmony_ci } 18131bd4fe43Sopenharmony_ci } 18141bd4fe43Sopenharmony_ci} 18151bd4fe43Sopenharmony_ci 18161bd4fe43Sopenharmony_cistatic void SdhciFinishCommand(struct SdhciHost *host) 18171bd4fe43Sopenharmony_ci{ 18181bd4fe43Sopenharmony_ci struct MmcCmd *cmd = host->cmd; 18191bd4fe43Sopenharmony_ci 18201bd4fe43Sopenharmony_ci if (cmd == NULL) { 18211bd4fe43Sopenharmony_ci return; 18221bd4fe43Sopenharmony_ci } 18231bd4fe43Sopenharmony_ci 18241bd4fe43Sopenharmony_ci if (cmd->respType & RESP_PRESENT) { 18251bd4fe43Sopenharmony_ci if (cmd->respType & RESP_136) { 18261bd4fe43Sopenharmony_ci SdhciSaveCommandResp(host, cmd); 18271bd4fe43Sopenharmony_ci } else { 18281bd4fe43Sopenharmony_ci cmd->resp[0] = SdhciReadl(host, RESP01_R); 18291bd4fe43Sopenharmony_ci } 18301bd4fe43Sopenharmony_ci } 18311bd4fe43Sopenharmony_ci 18321bd4fe43Sopenharmony_ci if (cmd->data == NULL || cmd->cmdCode == STOP_TRANSMISSION) { 18331bd4fe43Sopenharmony_ci SdhciTaskletFinish(host); 18341bd4fe43Sopenharmony_ci } 18351bd4fe43Sopenharmony_ci} 18361bd4fe43Sopenharmony_ci 18371bd4fe43Sopenharmony_cistatic void SdhciCmdIrq(struct SdhciHost *host, uint32_t intMask) 18381bd4fe43Sopenharmony_ci{ 18391bd4fe43Sopenharmony_ci if (host->cmd == NULL) { 18401bd4fe43Sopenharmony_ci return; 18411bd4fe43Sopenharmony_ci } 18421bd4fe43Sopenharmony_ci 18431bd4fe43Sopenharmony_ci if (intMask & SDHCI_INTERRUPT_TIMEOUT) { 18441bd4fe43Sopenharmony_ci host->cmd->returnError = HDF_ERR_TIMEOUT; 18451bd4fe43Sopenharmony_ci } else if (intMask & (SDHCI_INTERRUPT_CRC | SDHCI_INTERRUPT_END_BIT | SDHCI_INTERRUPT_INDEX)) { 18461bd4fe43Sopenharmony_ci host->cmd->returnError = HDF_MMC_ERR_ILLEGAL_SEQ; 18471bd4fe43Sopenharmony_ci } 18481bd4fe43Sopenharmony_ci 18491bd4fe43Sopenharmony_ci if (host->cmd->data == NULL && host->cmd->returnError != HDF_SUCCESS) { 18501bd4fe43Sopenharmony_ci SdhciTaskletFinish(host); 18511bd4fe43Sopenharmony_ci return; 18521bd4fe43Sopenharmony_ci } 18531bd4fe43Sopenharmony_ci 18541bd4fe43Sopenharmony_ci if (host->cmd->respType & RESP_BUSY) { 18551bd4fe43Sopenharmony_ci return; 18561bd4fe43Sopenharmony_ci } 18571bd4fe43Sopenharmony_ci 18581bd4fe43Sopenharmony_ci if (intMask & SDHCI_INTERRUPT_RESPONSE) { 18591bd4fe43Sopenharmony_ci SdhciFinishCommand(host); 18601bd4fe43Sopenharmony_ci } 18611bd4fe43Sopenharmony_ci} 18621bd4fe43Sopenharmony_ci 18631bd4fe43Sopenharmony_cistatic void SdhciFinishData(struct SdhciHost *host) 18641bd4fe43Sopenharmony_ci{ 18651bd4fe43Sopenharmony_ci struct MmcData *data = host->cmd->data; 18661bd4fe43Sopenharmony_ci 18671bd4fe43Sopenharmony_ci if (data->sendStopCmd == true) { 18681bd4fe43Sopenharmony_ci if (data->returnError != HDF_SUCCESS) { 18691bd4fe43Sopenharmony_ci SdhciDoReset(host, SDHCI_RESET_CMD); 18701bd4fe43Sopenharmony_ci SdhciDoReset(host, SDHCI_RESET_DATA); 18711bd4fe43Sopenharmony_ci } 18721bd4fe43Sopenharmony_ci SdhciExecCmd(host, &(data->stopCmd)); 18731bd4fe43Sopenharmony_ci } else { 18741bd4fe43Sopenharmony_ci SdhciTaskletFinish(host); 18751bd4fe43Sopenharmony_ci } 18761bd4fe43Sopenharmony_ci} 18771bd4fe43Sopenharmony_ci 18781bd4fe43Sopenharmony_cistatic void SdhciDataIrq(struct SdhciHost *host, uint32_t intMask) 18791bd4fe43Sopenharmony_ci{ 18801bd4fe43Sopenharmony_ci uint32_t command; 18811bd4fe43Sopenharmony_ci struct MmcCmd *cmd = host->cmd; 18821bd4fe43Sopenharmony_ci 18831bd4fe43Sopenharmony_ci if (cmd->data == NULL || (cmd->cmdCode == STOP_TRANSMISSION)) { 18841bd4fe43Sopenharmony_ci if ((cmd->respType & RESP_BUSY)) { 18851bd4fe43Sopenharmony_ci if (intMask & SDHCI_INTERRUPT_DATA_TIMEOUT) { 18861bd4fe43Sopenharmony_ci cmd->returnError = HDF_ERR_TIMEOUT; 18871bd4fe43Sopenharmony_ci SdhciTaskletFinish(host); 18881bd4fe43Sopenharmony_ci return; 18891bd4fe43Sopenharmony_ci } 18901bd4fe43Sopenharmony_ci if (intMask & SDHCI_INTERRUPT_DATA_END) { 18911bd4fe43Sopenharmony_ci SdhciFinishCommand(host); 18921bd4fe43Sopenharmony_ci return; 18931bd4fe43Sopenharmony_ci } 18941bd4fe43Sopenharmony_ci } 18951bd4fe43Sopenharmony_ci } 18961bd4fe43Sopenharmony_ci if (cmd->data == NULL) { 18971bd4fe43Sopenharmony_ci return; 18981bd4fe43Sopenharmony_ci } 18991bd4fe43Sopenharmony_ci 19001bd4fe43Sopenharmony_ci if (intMask & SDHCI_INTERRUPT_DATA_TIMEOUT) { 19011bd4fe43Sopenharmony_ci cmd->data->returnError = HDF_ERR_TIMEOUT; 19021bd4fe43Sopenharmony_ci } else if (intMask & SDHCI_INTERRUPT_END_BIT) { 19031bd4fe43Sopenharmony_ci cmd->data->returnError = HDF_MMC_ERR_ILLEGAL_SEQ; 19041bd4fe43Sopenharmony_ci } else if ((intMask & SDHCI_INTERRUPT_DATA_CRC)) { 19051bd4fe43Sopenharmony_ci cmd->data->returnError = HDF_MMC_ERR_ILLEGAL_SEQ; 19061bd4fe43Sopenharmony_ci } else if (intMask & SDHCI_INTERRUPT_ADMA_ERROR) { 19071bd4fe43Sopenharmony_ci cmd->data->returnError = HDF_ERR_IO; 19081bd4fe43Sopenharmony_ci } 19091bd4fe43Sopenharmony_ci 19101bd4fe43Sopenharmony_ci if (cmd->data->returnError != HDF_SUCCESS) { 19111bd4fe43Sopenharmony_ci command = SDHCI_PARSE_CMD(SdhciReadw(host, CMD_R)); 19121bd4fe43Sopenharmony_ci if (command != SD_CMD_SEND_TUNING_BLOCK && command != SEND_TUNING_BLOCK_HS200) { 19131bd4fe43Sopenharmony_ci HDF_LOGE("err = 0x%x, cmd = %u, interrupt = 0x%x.", cmd->data->returnError, command, intMask); 19141bd4fe43Sopenharmony_ci SdhciDumpregs(host); 19151bd4fe43Sopenharmony_ci } 19161bd4fe43Sopenharmony_ci SdhciFinishData(host); 19171bd4fe43Sopenharmony_ci } else { 19181bd4fe43Sopenharmony_ci if (intMask & SDHCI_INTERRUPT_DATA_END) { 19191bd4fe43Sopenharmony_ci SdhciFinishData(host); 19201bd4fe43Sopenharmony_ci } else { 19211bd4fe43Sopenharmony_ci HDF_LOGE("do check here! intmask = 0x%x.", intMask); 19221bd4fe43Sopenharmony_ci } 19231bd4fe43Sopenharmony_ci } 19241bd4fe43Sopenharmony_ci} 19251bd4fe43Sopenharmony_ci 19261bd4fe43Sopenharmony_cistatic uint32_t SdhciIrqHandler(uint32_t irq, void *data) 19271bd4fe43Sopenharmony_ci{ 19281bd4fe43Sopenharmony_ci struct SdhciHost *host = (struct SdhciHost *)data; 19291bd4fe43Sopenharmony_ci uint32_t intMask; 19301bd4fe43Sopenharmony_ci (void)irq; 19311bd4fe43Sopenharmony_ci 19321bd4fe43Sopenharmony_ci if (host == NULL || host->mmc == NULL) { 19331bd4fe43Sopenharmony_ci HDF_LOGE("SdhciIrqHandler: data is null!"); 19341bd4fe43Sopenharmony_ci return HDF_SUCCESS; 19351bd4fe43Sopenharmony_ci } 19361bd4fe43Sopenharmony_ci 19371bd4fe43Sopenharmony_ci while ((intMask = SdhciReadl(host, NORMAL_INT_STAT_R)) != 0) { 19381bd4fe43Sopenharmony_ci SdhciWritel(host, intMask, NORMAL_INT_STAT_R); 19391bd4fe43Sopenharmony_ci if (intMask & SDHCI_CART_PLUG_STATE) { 19401bd4fe43Sopenharmony_ci host->irqEnable &= ~SDHCI_CART_PLUG_STATE; 19411bd4fe43Sopenharmony_ci host->irqEnable |= SDHCI_PLUG_STATE(host) ? SDHCI_INTERRUPT_CARD_REMOVE : SDHCI_INTERRUPT_CARD_INSERT; 19421bd4fe43Sopenharmony_ci SdhciEnablePlugIrq(host, host->irqEnable); 19431bd4fe43Sopenharmony_ci SdhciWritel(host, intMask & SDHCI_CART_PLUG_STATE, NORMAL_INT_STAT_R); 19441bd4fe43Sopenharmony_ci MmcCntlrAddPlugMsgToQueue(host->mmc); 19451bd4fe43Sopenharmony_ci if (host->waitForEvent) { 19461bd4fe43Sopenharmony_ci (void)SDHCI_EVENT_SIGNAL(&host->sdhciEvent, SDHCI_PEND_ACCIDENT); 19471bd4fe43Sopenharmony_ci } 19481bd4fe43Sopenharmony_ci } 19491bd4fe43Sopenharmony_ci 19501bd4fe43Sopenharmony_ci if (intMask & SDHCI_INT_CMD_MASK) { 19511bd4fe43Sopenharmony_ci SdhciCmdIrq(host, (intMask & SDHCI_INT_CMD_MASK)); 19521bd4fe43Sopenharmony_ci } 19531bd4fe43Sopenharmony_ci if (intMask & SDHCI_INT_DATA_MASK) { 19541bd4fe43Sopenharmony_ci SdhciDataIrq(host, (intMask & SDHCI_INT_DATA_MASK)); 19551bd4fe43Sopenharmony_ci } 19561bd4fe43Sopenharmony_ci if (intMask & SDHCI_INTERRUPT_BUS_POWER) { 19571bd4fe43Sopenharmony_ci HDF_LOGD("host%u: card is consuming too much power!", host->hostId); 19581bd4fe43Sopenharmony_ci } 19591bd4fe43Sopenharmony_ci if (intMask & SDHCI_INTERRUPT_CARD_INT) { 19601bd4fe43Sopenharmony_ci SdhciEnableSdioIrqNoLock(host, false); 19611bd4fe43Sopenharmony_ci MmcCntlrNotifySdioIrqThread(host->mmc); 19621bd4fe43Sopenharmony_ci } 19631bd4fe43Sopenharmony_ci } 19641bd4fe43Sopenharmony_ci return HDF_SUCCESS; 19651bd4fe43Sopenharmony_ci} 19661bd4fe43Sopenharmony_ci 19671bd4fe43Sopenharmony_cistatic int32_t SdhciHostInit(struct SdhciHost *host, struct MmcCntlr *cntlr) 19681bd4fe43Sopenharmony_ci{ 19691bd4fe43Sopenharmony_ci int32_t ret; 19701bd4fe43Sopenharmony_ci uint32_t Capability1; 19711bd4fe43Sopenharmony_ci uint32_t Capability2 = 0; 19721bd4fe43Sopenharmony_ci 19731bd4fe43Sopenharmony_ci host->hostId = (uint32_t)cntlr->index; 19741bd4fe43Sopenharmony_ci if (SDHCI_EVENT_INIT(&host->sdhciEvent) != HDF_SUCCESS) { 19751bd4fe43Sopenharmony_ci HDF_LOGE("SdhciHostInit: sdhciEvent init fail!\n"); 19761bd4fe43Sopenharmony_ci return HDF_FAILURE; 19771bd4fe43Sopenharmony_ci } 19781bd4fe43Sopenharmony_ci if (OsalMutexInit(&host->mutex) != HDF_SUCCESS) { 19791bd4fe43Sopenharmony_ci HDF_LOGE("SdhciHostInit: init mutex lock fail!"); 19801bd4fe43Sopenharmony_ci return HDF_FAILURE; 19811bd4fe43Sopenharmony_ci } 19821bd4fe43Sopenharmony_ci 19831bd4fe43Sopenharmony_ci SdhciCrgInit(host); 19841bd4fe43Sopenharmony_ci host->version = SdhciReadw(host, HOST_VERSION_R); 19851bd4fe43Sopenharmony_ci host->version = (host->version & SDHCI_HOST_SPEC_VER_MASK); 19861bd4fe43Sopenharmony_ci Capability1 = SdhciReadl(host, CAPABILITIES1_R); 19871bd4fe43Sopenharmony_ci if (host->version >= SDHCI_HOST_SPEC_300) { 19881bd4fe43Sopenharmony_ci Capability2 = SdhciReadl(host, CAPABILITIES2_R); 19891bd4fe43Sopenharmony_ci } 19901bd4fe43Sopenharmony_ci 19911bd4fe43Sopenharmony_ci SdhciUpdateCapFlag(host, Capability1); 19921bd4fe43Sopenharmony_ci ret = SdhciFillAdmaInfo(host); 19931bd4fe43Sopenharmony_ci if (ret != HDF_SUCCESS) { 19941bd4fe43Sopenharmony_ci return ret; 19951bd4fe43Sopenharmony_ci } 19961bd4fe43Sopenharmony_ci 19971bd4fe43Sopenharmony_ci Capability2 &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_ADMA3); 19981bd4fe43Sopenharmony_ci Capability2 |= SDHCI_USE_SDR50_TUNING; 19991bd4fe43Sopenharmony_ci SdhciFillClkInfo(host, Capability1, Capability2); 20001bd4fe43Sopenharmony_ci SdhciUpdateDrvCap(host, Capability1, Capability2); 20011bd4fe43Sopenharmony_ci ret = SdhciSystemInit(host->mmc); 20021bd4fe43Sopenharmony_ci if (ret != HDF_SUCCESS) { 20031bd4fe43Sopenharmony_ci return ret; 20041bd4fe43Sopenharmony_ci } 20051bd4fe43Sopenharmony_ci 20061bd4fe43Sopenharmony_ci ret = OsalRegisterIrq(host->irqNum, 0, (OsalIRQHandle)SdhciIrqHandler, "MMC_IRQ", host); 20071bd4fe43Sopenharmony_ci if (ret) { 20081bd4fe43Sopenharmony_ci HDF_LOGE("SdhciHostInit: request irq for sdhci is err."); 20091bd4fe43Sopenharmony_ci return HDF_FAILURE; 20101bd4fe43Sopenharmony_ci } 20111bd4fe43Sopenharmony_ci return HDF_SUCCESS; 20121bd4fe43Sopenharmony_ci} 20131bd4fe43Sopenharmony_ci 20141bd4fe43Sopenharmony_cistatic int32_t SdhciMmcBind(struct HdfDeviceObject *obj) 20151bd4fe43Sopenharmony_ci{ 20161bd4fe43Sopenharmony_ci struct MmcCntlr *cntlr = NULL; 20171bd4fe43Sopenharmony_ci struct SdhciHost *host = NULL; 20181bd4fe43Sopenharmony_ci int32_t ret; 20191bd4fe43Sopenharmony_ci 20201bd4fe43Sopenharmony_ci if (obj == NULL) { 20211bd4fe43Sopenharmony_ci HDF_LOGE("SdhciMmcBind: Fail, device is NULL."); 20221bd4fe43Sopenharmony_ci return HDF_ERR_INVALID_OBJECT; 20231bd4fe43Sopenharmony_ci } 20241bd4fe43Sopenharmony_ci cntlr = (struct MmcCntlr *)OsalMemCalloc(sizeof(struct MmcCntlr)); 20251bd4fe43Sopenharmony_ci if (cntlr == NULL) { 20261bd4fe43Sopenharmony_ci HDF_LOGE("SdhciMmcBind: no mem for MmcCntlr."); 20271bd4fe43Sopenharmony_ci return HDF_ERR_MALLOC_FAIL; 20281bd4fe43Sopenharmony_ci } 20291bd4fe43Sopenharmony_ci host = (struct SdhciHost *)OsalMemCalloc(sizeof(struct SdhciHost)); 20301bd4fe43Sopenharmony_ci if (host == NULL) { 20311bd4fe43Sopenharmony_ci HDF_LOGE("SdhciMmcBind: no mem for SdhciHost."); 20321bd4fe43Sopenharmony_ci OsalMemFree(cntlr); 20331bd4fe43Sopenharmony_ci return HDF_ERR_MALLOC_FAIL; 20341bd4fe43Sopenharmony_ci } 20351bd4fe43Sopenharmony_ci 20361bd4fe43Sopenharmony_ci host->mmc = cntlr; 20371bd4fe43Sopenharmony_ci cntlr->priv = (void *)host; 20381bd4fe43Sopenharmony_ci cntlr->ops = &g_sdhciHostOps; 20391bd4fe43Sopenharmony_ci cntlr->hdfDevObj = obj; 20401bd4fe43Sopenharmony_ci obj->service = &cntlr->service; 20411bd4fe43Sopenharmony_ci /* init cntlr. */ 20421bd4fe43Sopenharmony_ci ret = MmcCntlrParse(cntlr, obj); 20431bd4fe43Sopenharmony_ci if (ret != HDF_SUCCESS) { 20441bd4fe43Sopenharmony_ci goto _ERR; 20451bd4fe43Sopenharmony_ci } 20461bd4fe43Sopenharmony_ci ret = SdhciHostParse(host, obj); 20471bd4fe43Sopenharmony_ci if (ret != HDF_SUCCESS) { 20481bd4fe43Sopenharmony_ci goto _ERR; 20491bd4fe43Sopenharmony_ci } 20501bd4fe43Sopenharmony_ci ret = SdhciHostInit(host, cntlr); 20511bd4fe43Sopenharmony_ci if (ret != HDF_SUCCESS) { 20521bd4fe43Sopenharmony_ci goto _ERR; 20531bd4fe43Sopenharmony_ci } 20541bd4fe43Sopenharmony_ci ret = MmcCntlrAdd(cntlr, true); 20551bd4fe43Sopenharmony_ci if (ret != HDF_SUCCESS) { 20561bd4fe43Sopenharmony_ci goto _ERR; 20571bd4fe43Sopenharmony_ci } 20581bd4fe43Sopenharmony_ci 20591bd4fe43Sopenharmony_ci (void)MmcCntlrAddDetectMsgToQueue(cntlr); 20601bd4fe43Sopenharmony_ci HDF_LOGI("%s: mmc bind success.", __func__); 20611bd4fe43Sopenharmony_ci return HDF_SUCCESS; 20621bd4fe43Sopenharmony_ci_ERR: 20631bd4fe43Sopenharmony_ci SdhciDeleteHost(host); 20641bd4fe43Sopenharmony_ci HDF_LOGE("SdhciMmcBind: fail, err = %d.", ret); 20651bd4fe43Sopenharmony_ci return ret; 20661bd4fe43Sopenharmony_ci} 20671bd4fe43Sopenharmony_ci 20681bd4fe43Sopenharmony_cistatic int32_t SdhciMmcInit(struct HdfDeviceObject *obj) 20691bd4fe43Sopenharmony_ci{ 20701bd4fe43Sopenharmony_ci static bool procInit = false; 20711bd4fe43Sopenharmony_ci 20721bd4fe43Sopenharmony_ci (void)obj; 20731bd4fe43Sopenharmony_ci if (procInit == false) { 20741bd4fe43Sopenharmony_ci if (ProcMciInit() == HDF_SUCCESS) { 20751bd4fe43Sopenharmony_ci procInit = true; 20761bd4fe43Sopenharmony_ci HDF_LOGD("SdhciMmcInit: proc init success."); 20771bd4fe43Sopenharmony_ci } 20781bd4fe43Sopenharmony_ci } 20791bd4fe43Sopenharmony_ci HDF_LOGI("%s: mmc init success.", __func__); 20801bd4fe43Sopenharmony_ci return HDF_SUCCESS; 20811bd4fe43Sopenharmony_ci} 20821bd4fe43Sopenharmony_ci 20831bd4fe43Sopenharmony_cistatic void SdhciMmcRelease(struct HdfDeviceObject *obj) 20841bd4fe43Sopenharmony_ci{ 20851bd4fe43Sopenharmony_ci struct MmcCntlr *cntlr = NULL; 20861bd4fe43Sopenharmony_ci 20871bd4fe43Sopenharmony_ci HDF_LOGI("%s: enter", __func__); 20881bd4fe43Sopenharmony_ci if (obj == NULL) { 20891bd4fe43Sopenharmony_ci return; 20901bd4fe43Sopenharmony_ci } 20911bd4fe43Sopenharmony_ci 20921bd4fe43Sopenharmony_ci cntlr = (struct MmcCntlr *)obj->service; 20931bd4fe43Sopenharmony_ci if (cntlr == NULL) { 20941bd4fe43Sopenharmony_ci return; 20951bd4fe43Sopenharmony_ci } 20961bd4fe43Sopenharmony_ci SdhciDeleteHost((struct SdhciHost *)cntlr->priv); 20971bd4fe43Sopenharmony_ci} 20981bd4fe43Sopenharmony_ci 20991bd4fe43Sopenharmony_cistruct HdfDriverEntry g_mmcDriverEntry = { 21001bd4fe43Sopenharmony_ci .moduleVersion = 1, 21011bd4fe43Sopenharmony_ci .Bind = SdhciMmcBind, 21021bd4fe43Sopenharmony_ci .Init = SdhciMmcInit, 21031bd4fe43Sopenharmony_ci .Release = SdhciMmcRelease, 21041bd4fe43Sopenharmony_ci .moduleName = "hi3518_mmc_driver", 21051bd4fe43Sopenharmony_ci}; 21061bd4fe43Sopenharmony_ciHDF_INIT(g_mmcDriverEntry); 2107