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", &regBase, 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", &regSize, 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