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 "himci.h"
171bd4fe43Sopenharmony_ci#include "himci_proc.h"
181bd4fe43Sopenharmony_ci
191bd4fe43Sopenharmony_ci#define HDF_LOG_TAG himci_adapter
201bd4fe43Sopenharmony_ci
211bd4fe43Sopenharmony_ci#define HIMCI_PIN_NUM 6
221bd4fe43Sopenharmony_ci#define HIMCI_VOLT_SWITCH_TIMEOUT 10
231bd4fe43Sopenharmony_ci#define HIMCI_PHASE_DLL_START_ELEMENT 2
241bd4fe43Sopenharmony_ci
251bd4fe43Sopenharmony_cistatic void HimciDumpRegs(struct HimciHost *host)
261bd4fe43Sopenharmony_ci{
271bd4fe43Sopenharmony_ci    HDF_LOGE(": =========== DUMP (host%u) REGISTER===========", host->id);
281bd4fe43Sopenharmony_ci    HDF_LOGE(": CTRL : 0x%08x | PWREN:  0x%04x",
291bd4fe43Sopenharmony_ci        HIMCI_READL((uintptr_t)host->base + MMC_CTRL), HIMCI_READL((uintptr_t)host->base + MMC_PWREN));
301bd4fe43Sopenharmony_ci    HDF_LOGE(": CLKDIV : 0x%08x | CLKENA:  0x%04x",
311bd4fe43Sopenharmony_ci        HIMCI_READL((uintptr_t)host->base + MMC_CLKDIV), HIMCI_READL((uintptr_t)host->base + MMC_CLKENA));
321bd4fe43Sopenharmony_ci    HDF_LOGE(": TMOUT : 0x%08x | CTYPE:  0x%04x",
331bd4fe43Sopenharmony_ci        HIMCI_READL((uintptr_t)host->base + MMC_TMOUT), HIMCI_READL((uintptr_t)host->base + MMC_CTYPE));
341bd4fe43Sopenharmony_ci    HDF_LOGE(": BLKSIZ : 0x%08x | BYTCNT:  0x%04x",
351bd4fe43Sopenharmony_ci        HIMCI_READL((uintptr_t)host->base + MMC_BLKSIZ), HIMCI_READL((uintptr_t)host->base + MMC_BYTCNT));
361bd4fe43Sopenharmony_ci    HDF_LOGE(": CMD : 0x%08x | CMDARG:  0x%04x",
371bd4fe43Sopenharmony_ci        HIMCI_READL((uintptr_t)host->base + MMC_CMD), HIMCI_READL((uintptr_t)host->base + MMC_CMDARG));
381bd4fe43Sopenharmony_ci    HDF_LOGE(": RESP0 : 0x%08x | RESP1:  0x%04x",
391bd4fe43Sopenharmony_ci        HIMCI_READL((uintptr_t)host->base + MMC_RESP0), HIMCI_READL((uintptr_t)host->base + MMC_RESP1));
401bd4fe43Sopenharmony_ci    HDF_LOGE(": RESP2 : 0x%08x | RESP3:  0x%04x",
411bd4fe43Sopenharmony_ci        HIMCI_READL((uintptr_t)host->base + MMC_RESP2), HIMCI_READL((uintptr_t)host->base + MMC_RESP3));
421bd4fe43Sopenharmony_ci    HDF_LOGE(": RINTSTS : 0x%08x | STATUS:  0x%04x",
431bd4fe43Sopenharmony_ci        HIMCI_READL((uintptr_t)host->base + MMC_RINTSTS), HIMCI_READL((uintptr_t)host->base + MMC_STATUS));
441bd4fe43Sopenharmony_ci    HDF_LOGE(": BMOD : 0x%08x | IDSTS:  0x%04x",
451bd4fe43Sopenharmony_ci        HIMCI_READL((uintptr_t)host->base + MMC_BMOD), HIMCI_READL((uintptr_t)host->base + MMC_IDSTS));
461bd4fe43Sopenharmony_ci    HDF_LOGE(": IDINTEN : 0x%08x | CARDTHRCTL : 0x%08x",
471bd4fe43Sopenharmony_ci        HIMCI_READL((uintptr_t)host->base + MMC_IDINTEN), HIMCI_READL((uintptr_t)host->base + MMC_CARDTHRCTL));
481bd4fe43Sopenharmony_ci    HDF_LOGE(": DDR_REG:  0x%04x | ENABLE_SHIFT : 0x%08x",
491bd4fe43Sopenharmony_ci        HIMCI_READL((uintptr_t)host->base + MMC_EMMC_DDR_REG), HIMCI_READL((uintptr_t)host->base + MMC_ENABLE_SHIFT));
501bd4fe43Sopenharmony_ci    HDF_LOGE(": =============================================");
511bd4fe43Sopenharmony_ci}
521bd4fe43Sopenharmony_ci
531bd4fe43Sopenharmony_cistatic void HimciSetEmmcDrvCap(struct MmcCntlr *cntlr)
541bd4fe43Sopenharmony_ci{
551bd4fe43Sopenharmony_ci    uint32_t i, j, val;
561bd4fe43Sopenharmony_ci    uint32_t *pinDrvCap = NULL;
571bd4fe43Sopenharmony_ci    /*  clk   cmd   data0  data1  data2  data3 */
581bd4fe43Sopenharmony_ci    uint32_t emmcHs200Drv[] = { 0x2b0, 0x1c0, 0x1c0, 0x1c0, 0x1c0, 0x1c0 };
591bd4fe43Sopenharmony_ci    uint32_t emmcHsDrv[] = { 0x6b0, 0x5e0, 0x5e0, 0x5e0, 0x5e0, 0x5e0 };
601bd4fe43Sopenharmony_ci    uint32_t emmcDsDrv[] = { 0x6b0, 0x5f0, 0x5f0, 0x5f0, 0x5f0, 0x5f0 };
611bd4fe43Sopenharmony_ci    uint32_t emmcDs400kDrv[] = { 0x6c0, 0x5f0, 0x5f0, 0x5f0, 0x5f0, 0x5f0 };
621bd4fe43Sopenharmony_ci
631bd4fe43Sopenharmony_ci    if (cntlr->curDev->workPara.timing == BUS_TIMING_MMC_HS200) {
641bd4fe43Sopenharmony_ci        pinDrvCap = emmcHs200Drv;
651bd4fe43Sopenharmony_ci    } else if (cntlr->curDev->workPara.timing == BUS_TIMING_MMC_HS) {
661bd4fe43Sopenharmony_ci        pinDrvCap = emmcHsDrv;
671bd4fe43Sopenharmony_ci    } else {
681bd4fe43Sopenharmony_ci        if (cntlr->curDev->workPara.clock == 400000) {
691bd4fe43Sopenharmony_ci            pinDrvCap = emmcDs400kDrv;
701bd4fe43Sopenharmony_ci        } else {
711bd4fe43Sopenharmony_ci            pinDrvCap = emmcDsDrv;
721bd4fe43Sopenharmony_ci        }
731bd4fe43Sopenharmony_ci    }
741bd4fe43Sopenharmony_ci
751bd4fe43Sopenharmony_ci    for (i = REG_CTRL_EMMC_START, j = 0; j < HIMCI_PIN_NUM; i = i + REG_CTRL_NUM, j++) {
761bd4fe43Sopenharmony_ci        val = HIMCI_READL(i);
771bd4fe43Sopenharmony_ci        /*
781bd4fe43Sopenharmony_ci         * [10]:SR
791bd4fe43Sopenharmony_ci         * [9]:internel pull down
801bd4fe43Sopenharmony_ci         * [8]:internel pull up
811bd4fe43Sopenharmony_ci         */
821bd4fe43Sopenharmony_ci        val = val & (~(0x7f0));
831bd4fe43Sopenharmony_ci        val |= pinDrvCap[j];
841bd4fe43Sopenharmony_ci        HIMCI_WRITEL(val, i);
851bd4fe43Sopenharmony_ci    }
861bd4fe43Sopenharmony_ci}
871bd4fe43Sopenharmony_ci
881bd4fe43Sopenharmony_cistatic void HimciSetSdDrvCap(struct MmcCntlr *cntlr)
891bd4fe43Sopenharmony_ci{
901bd4fe43Sopenharmony_ci    uint32_t i, j, val;
911bd4fe43Sopenharmony_ci    uint32_t *pinDrvCap = NULL;
921bd4fe43Sopenharmony_ci    /*  clk   cmd   data0  data1  data2  data3 */
931bd4fe43Sopenharmony_ci    uint32_t sdSdr104Drv[] = { 0x290, 0x1c0, 0x1c0, 0x1c0, 0x1c0, 0x1c0 };
941bd4fe43Sopenharmony_ci    uint32_t sdSdr50Drv[] = { 0x290, 0x1c0, 0x1c0, 0x1c0, 0x1c0, 0x1c0 };
951bd4fe43Sopenharmony_ci    uint32_t sdSdr25Drv[] = { 0x6b0, 0x5d0, 0x5d0, 0x5d0, 0x5d0, 0x5d0 };
961bd4fe43Sopenharmony_ci    uint32_t sdSdr12Drv[] = { 0x6b0, 0x5e0, 0x5e0, 0x5e0, 0x5e0, 0x5e0 };
971bd4fe43Sopenharmony_ci    uint32_t sdHsDrv[] = { 0x6d0, 0x5f0, 0x5f0, 0x5f0, 0x5f0, 0x5f0 };
981bd4fe43Sopenharmony_ci    uint32_t sdDsDrv[] = { 0x6b0, 0x5e0, 0x5e0, 0x5e0, 0x5e0, 0x5e0 };
991bd4fe43Sopenharmony_ci
1001bd4fe43Sopenharmony_ci    if (cntlr->curDev->workPara.timing == BUS_TIMING_UHS_SDR104) {
1011bd4fe43Sopenharmony_ci        pinDrvCap = sdSdr104Drv;
1021bd4fe43Sopenharmony_ci    } else if (cntlr->curDev->workPara.timing == BUS_TIMING_UHS_SDR50) {
1031bd4fe43Sopenharmony_ci        pinDrvCap = sdSdr50Drv;
1041bd4fe43Sopenharmony_ci    } else if (cntlr->curDev->workPara.timing == BUS_TIMING_UHS_SDR25) {
1051bd4fe43Sopenharmony_ci        pinDrvCap = sdSdr25Drv;
1061bd4fe43Sopenharmony_ci    } else if (cntlr->curDev->workPara.timing == BUS_TIMING_UHS_SDR12) {
1071bd4fe43Sopenharmony_ci        pinDrvCap = sdSdr12Drv;
1081bd4fe43Sopenharmony_ci    } else if (cntlr->curDev->workPara.timing == BUS_TIMING_SD_HS) {
1091bd4fe43Sopenharmony_ci        pinDrvCap = sdHsDrv;
1101bd4fe43Sopenharmony_ci    } else {
1111bd4fe43Sopenharmony_ci        pinDrvCap = sdDsDrv;
1121bd4fe43Sopenharmony_ci    }
1131bd4fe43Sopenharmony_ci
1141bd4fe43Sopenharmony_ci    for (i = REG_CTRL_SD_START, j = 0; j < HIMCI_PIN_NUM; i = i + REG_CTRL_NUM, j++) {
1151bd4fe43Sopenharmony_ci        val = HIMCI_READL(i);
1161bd4fe43Sopenharmony_ci        /*
1171bd4fe43Sopenharmony_ci         * [10]:SR
1181bd4fe43Sopenharmony_ci         * [9]:internel pull down
1191bd4fe43Sopenharmony_ci         * [8]:internel pull up
1201bd4fe43Sopenharmony_ci         */
1211bd4fe43Sopenharmony_ci        val = val & (~(0x7f0));
1221bd4fe43Sopenharmony_ci        val |= pinDrvCap[j];
1231bd4fe43Sopenharmony_ci        HIMCI_WRITEL(val, i);
1241bd4fe43Sopenharmony_ci    }
1251bd4fe43Sopenharmony_ci}
1261bd4fe43Sopenharmony_ci
1271bd4fe43Sopenharmony_cistatic void HimciSetSdioDrvCap(struct MmcCntlr *cntlr)
1281bd4fe43Sopenharmony_ci{
1291bd4fe43Sopenharmony_ci    uint32_t i, j, val;
1301bd4fe43Sopenharmony_ci    uint32_t *pinDrvCap = NULL;
1311bd4fe43Sopenharmony_ci    /*  clk   cmd   data0  data1  data2  data3 */
1321bd4fe43Sopenharmony_ci    uint32_t sdioSdr104Drv[] = { 0x290, 0x1c0, 0x1c0, 0x1c0, 0x1c0, 0x1c0 };
1331bd4fe43Sopenharmony_ci    uint32_t sdioSdr50Drv[] = { 0x290, 0x1c0, 0x1c0, 0x1c0, 0x1c0, 0x1c0 };
1341bd4fe43Sopenharmony_ci    uint32_t sdioSdr25Drv[] = { 0x6b0, 0x5d0, 0x5d0, 0x5d0, 0x5d0, 0x5d0 };
1351bd4fe43Sopenharmony_ci    uint32_t sdioSdr12Drv[] = { 0x6b0, 0x5e0, 0x5e0, 0x5e0, 0x5e0, 0x5e0 };
1361bd4fe43Sopenharmony_ci    uint32_t sdioHsDrv[] = { 0x6d0, 0x5f0, 0x5f0, 0x5f0, 0x5f0, 0x5f0 };
1371bd4fe43Sopenharmony_ci    uint32_t sdioDsDrv[] = { 0x6b0, 0x5e0, 0x5e0, 0x5e0, 0x5e0, 0x5e0 };
1381bd4fe43Sopenharmony_ci
1391bd4fe43Sopenharmony_ci    if (cntlr->curDev->workPara.timing == BUS_TIMING_UHS_SDR104) {
1401bd4fe43Sopenharmony_ci        pinDrvCap = sdioSdr104Drv;
1411bd4fe43Sopenharmony_ci    } else if (cntlr->curDev->workPara.timing == BUS_TIMING_UHS_SDR50) {
1421bd4fe43Sopenharmony_ci        pinDrvCap = sdioSdr50Drv;
1431bd4fe43Sopenharmony_ci    } else if (cntlr->curDev->workPara.timing == BUS_TIMING_UHS_SDR25) {
1441bd4fe43Sopenharmony_ci        pinDrvCap = sdioSdr25Drv;
1451bd4fe43Sopenharmony_ci    } else if (cntlr->curDev->workPara.timing == BUS_TIMING_UHS_SDR12) {
1461bd4fe43Sopenharmony_ci        pinDrvCap = sdioSdr12Drv;
1471bd4fe43Sopenharmony_ci    } else if (cntlr->curDev->workPara.timing == BUS_TIMING_SD_HS) {
1481bd4fe43Sopenharmony_ci        pinDrvCap = sdioHsDrv;
1491bd4fe43Sopenharmony_ci    } else {
1501bd4fe43Sopenharmony_ci        pinDrvCap = sdioDsDrv;
1511bd4fe43Sopenharmony_ci    }
1521bd4fe43Sopenharmony_ci
1531bd4fe43Sopenharmony_ci    for (i = REG_CTRL_SDIO_START, j = 0; j < HIMCI_PIN_NUM; i = i + REG_CTRL_NUM, j++) {
1541bd4fe43Sopenharmony_ci        val = HIMCI_READL(i);
1551bd4fe43Sopenharmony_ci        /*
1561bd4fe43Sopenharmony_ci         * [10]:SR
1571bd4fe43Sopenharmony_ci         * [9]:internel pull down
1581bd4fe43Sopenharmony_ci         * [8]:internel pull up
1591bd4fe43Sopenharmony_ci         */
1601bd4fe43Sopenharmony_ci        val = val & (~(0x7f0));
1611bd4fe43Sopenharmony_ci        val |= pinDrvCap[j];
1621bd4fe43Sopenharmony_ci        HIMCI_WRITEL(val, i);
1631bd4fe43Sopenharmony_ci    }
1641bd4fe43Sopenharmony_ci}
1651bd4fe43Sopenharmony_ci
1661bd4fe43Sopenharmony_cistatic void HimciSetDrvCap(struct MmcCntlr *cntlr)
1671bd4fe43Sopenharmony_ci{
1681bd4fe43Sopenharmony_ci    if (cntlr == NULL) {
1691bd4fe43Sopenharmony_ci        return;
1701bd4fe43Sopenharmony_ci    }
1711bd4fe43Sopenharmony_ci
1721bd4fe43Sopenharmony_ci    if (cntlr->devType == MMC_DEV_EMMC) {
1731bd4fe43Sopenharmony_ci        HimciSetEmmcDrvCap(cntlr);
1741bd4fe43Sopenharmony_ci    } else if (cntlr->devType == MMC_DEV_SD) {
1751bd4fe43Sopenharmony_ci        HimciSetSdDrvCap(cntlr);
1761bd4fe43Sopenharmony_ci    } else {
1771bd4fe43Sopenharmony_ci        HimciSetSdioDrvCap(cntlr);
1781bd4fe43Sopenharmony_ci    }
1791bd4fe43Sopenharmony_ci}
1801bd4fe43Sopenharmony_ci
1811bd4fe43Sopenharmony_cistatic uint32_t HimciClkDiv(struct HimciHost *host, uint32_t clock)
1821bd4fe43Sopenharmony_ci{
1831bd4fe43Sopenharmony_ci    uint32_t clkDiv = 0;
1841bd4fe43Sopenharmony_ci    uint32_t val, hostClk, debounce;
1851bd4fe43Sopenharmony_ci    uint32_t regs[] = { PERI_CRG82, PERI_CRG88, PERI_CRG85 };
1861bd4fe43Sopenharmony_ci
1871bd4fe43Sopenharmony_ci    val = HIMCI_READL(regs[host->id]);
1881bd4fe43Sopenharmony_ci    val &= ~(HIMCI_CLK_SEL_MASK);
1891bd4fe43Sopenharmony_ci    if (clock >= HIMCI_MMC_FREQ_150M) {
1901bd4fe43Sopenharmony_ci        hostClk = HIMCI_MMC_FREQ_150M;
1911bd4fe43Sopenharmony_ci        debounce = DEBOUNCE_E;
1921bd4fe43Sopenharmony_ci    } else if (clock >= HIMCI_MMC_FREQ_100M) {
1931bd4fe43Sopenharmony_ci        hostClk = HIMCI_MMC_FREQ_100M;
1941bd4fe43Sopenharmony_ci        val |= HIMCI_CLK_SEL_100M;
1951bd4fe43Sopenharmony_ci        debounce = DEBOUNCE_H;
1961bd4fe43Sopenharmony_ci    } else if (clock >= HIMCI_MMC_FREQ_50M) {
1971bd4fe43Sopenharmony_ci        hostClk = HIMCI_MMC_FREQ_50M;
1981bd4fe43Sopenharmony_ci        val |= HIMCI_CLK_SEL_50M;
1991bd4fe43Sopenharmony_ci        debounce = DEBOUNCE_M;
2001bd4fe43Sopenharmony_ci    } else if (clock >= HIMCI_MMC_FREQ_25M) {
2011bd4fe43Sopenharmony_ci        hostClk = HIMCI_MMC_FREQ_25M;
2021bd4fe43Sopenharmony_ci        val |= HIMCI_CLK_SEL_25M;
2031bd4fe43Sopenharmony_ci        debounce = DEBOUNCE_L;
2041bd4fe43Sopenharmony_ci    } else {
2051bd4fe43Sopenharmony_ci        if (clock > (HIMCI_MMC_FREQ_150M / CLK_DIVIDER)) {
2061bd4fe43Sopenharmony_ci            hostClk = HIMCI_MMC_FREQ_150M;
2071bd4fe43Sopenharmony_ci            debounce = DEBOUNCE_E;
2081bd4fe43Sopenharmony_ci        } else if (clock > (HIMCI_MMC_FREQ_100M / CLK_DIVIDER)) {
2091bd4fe43Sopenharmony_ci            val |= HIMCI_CLK_SEL_100M;
2101bd4fe43Sopenharmony_ci            hostClk = HIMCI_MMC_FREQ_100M;
2111bd4fe43Sopenharmony_ci            debounce = DEBOUNCE_H;
2121bd4fe43Sopenharmony_ci        } else if (clock > (HIMCI_MMC_FREQ_50M / CLK_DIVIDER)) {
2131bd4fe43Sopenharmony_ci            val |= HIMCI_CLK_SEL_50M;
2141bd4fe43Sopenharmony_ci            hostClk = HIMCI_MMC_FREQ_50M;
2151bd4fe43Sopenharmony_ci            debounce = DEBOUNCE_M;
2161bd4fe43Sopenharmony_ci        } else {
2171bd4fe43Sopenharmony_ci            val |= HIMCI_CLK_SEL_25M;
2181bd4fe43Sopenharmony_ci            hostClk = HIMCI_MMC_FREQ_25M;
2191bd4fe43Sopenharmony_ci            debounce = DEBOUNCE_L;
2201bd4fe43Sopenharmony_ci        }
2211bd4fe43Sopenharmony_ci        clkDiv = hostClk / (clock * 2);
2221bd4fe43Sopenharmony_ci        if (hostClk % (clock * 2) > 0) {
2231bd4fe43Sopenharmony_ci            clkDiv++;
2241bd4fe43Sopenharmony_ci        }
2251bd4fe43Sopenharmony_ci        if (clkDiv > MAX_CLKDIV_VAL) {
2261bd4fe43Sopenharmony_ci            clkDiv = MAX_CLKDIV_VAL;
2271bd4fe43Sopenharmony_ci        }
2281bd4fe43Sopenharmony_ci    }
2291bd4fe43Sopenharmony_ci    HIMCI_WRITEL(debounce, (uintptr_t)host->base + MMC_DEBNCE);
2301bd4fe43Sopenharmony_ci    HIMCI_WRITEL(val, regs[host->id]);
2311bd4fe43Sopenharmony_ci    HIMCI_WRITEL(clkDiv, (uintptr_t)host->base + MMC_CLKDIV);
2321bd4fe43Sopenharmony_ci
2331bd4fe43Sopenharmony_ci    return hostClk;
2341bd4fe43Sopenharmony_ci}
2351bd4fe43Sopenharmony_ci
2361bd4fe43Sopenharmony_cistatic void HimciDmaReset(struct HimciHost *host)
2371bd4fe43Sopenharmony_ci{
2381bd4fe43Sopenharmony_ci    uint32_t val;
2391bd4fe43Sopenharmony_ci
2401bd4fe43Sopenharmony_ci    val = HIMCI_READL((uintptr_t)host->base + MMC_BMOD);
2411bd4fe43Sopenharmony_ci    val |= BMOD_SWR;
2421bd4fe43Sopenharmony_ci    HIMCI_WRITEL(val, (uintptr_t)host->base + MMC_BMOD);
2431bd4fe43Sopenharmony_ci
2441bd4fe43Sopenharmony_ci    val = HIMCI_READL((uintptr_t)host->base + MMC_CTRL);
2451bd4fe43Sopenharmony_ci    val |= CTRL_RESET | FIFO_RESET | DMA_RESET;
2461bd4fe43Sopenharmony_ci    HIMCI_WRITEL(val, (uintptr_t)host->base + MMC_CTRL);
2471bd4fe43Sopenharmony_ci
2481bd4fe43Sopenharmony_ci    OsalUDelay(1);
2491bd4fe43Sopenharmony_ci    HIMCI_WRITEL(ALL_INT_CLR, (uintptr_t)host->base + MMC_RINTSTS);
2501bd4fe43Sopenharmony_ci}
2511bd4fe43Sopenharmony_ci
2521bd4fe43Sopenharmony_cistatic void HimciDmaStart(struct HimciHost *host)
2531bd4fe43Sopenharmony_ci{
2541bd4fe43Sopenharmony_ci    uint32_t val;
2551bd4fe43Sopenharmony_ci
2561bd4fe43Sopenharmony_ci    HIMCI_WRITEL(host->dmaPaddr, (uintptr_t)host->base + MMC_DBADDR);
2571bd4fe43Sopenharmony_ci    val = HIMCI_READL((uintptr_t)host->base + MMC_BMOD);
2581bd4fe43Sopenharmony_ci    val |= BMOD_DMA_EN;
2591bd4fe43Sopenharmony_ci    HIMCI_WRITEL(val, (uintptr_t)host->base + MMC_BMOD);
2601bd4fe43Sopenharmony_ci}
2611bd4fe43Sopenharmony_ci
2621bd4fe43Sopenharmony_cistatic void HimciDmaStop(struct HimciHost *host)
2631bd4fe43Sopenharmony_ci{
2641bd4fe43Sopenharmony_ci    uint32_t val;
2651bd4fe43Sopenharmony_ci
2661bd4fe43Sopenharmony_ci    val = HIMCI_READL((uintptr_t)host->base + MMC_BMOD);
2671bd4fe43Sopenharmony_ci    val &= (~BMOD_DMA_EN);
2681bd4fe43Sopenharmony_ci    HIMCI_WRITEL(val, (uintptr_t)host->base + MMC_BMOD);
2691bd4fe43Sopenharmony_ci}
2701bd4fe43Sopenharmony_ci
2711bd4fe43Sopenharmony_cistatic void HimciDmaCacheClean(void *addr, uint32_t size)
2721bd4fe43Sopenharmony_ci{
2731bd4fe43Sopenharmony_ci    addr = (void *)(uintptr_t)DMA_TO_VMM_ADDR((paddr_t)(uintptr_t)addr);
2741bd4fe43Sopenharmony_ci    uint32_t start = (uintptr_t)addr & ~(CACHE_ALIGNED_SIZE - 1);
2751bd4fe43Sopenharmony_ci    uint32_t end = (uintptr_t)addr + size;
2761bd4fe43Sopenharmony_ci
2771bd4fe43Sopenharmony_ci    end = ALIGN(end, CACHE_ALIGNED_SIZE);
2781bd4fe43Sopenharmony_ci    DCacheFlushRange(start, end);
2791bd4fe43Sopenharmony_ci}
2801bd4fe43Sopenharmony_ci
2811bd4fe43Sopenharmony_cistatic void HimciDmaCacheInv(void *addr, uint32_t size)
2821bd4fe43Sopenharmony_ci{
2831bd4fe43Sopenharmony_ci    addr = (void *)(uintptr_t)DMA_TO_VMM_ADDR((paddr_t)(uintptr_t)addr);
2841bd4fe43Sopenharmony_ci    uint32_t start = (uintptr_t)addr & ~(CACHE_ALIGNED_SIZE - 1);
2851bd4fe43Sopenharmony_ci    uint32_t end = (uintptr_t)addr + size;
2861bd4fe43Sopenharmony_ci
2871bd4fe43Sopenharmony_ci    end = ALIGN(end, CACHE_ALIGNED_SIZE);
2881bd4fe43Sopenharmony_ci    DCacheInvRange(start, end);
2891bd4fe43Sopenharmony_ci}
2901bd4fe43Sopenharmony_ci
2911bd4fe43Sopenharmony_cistatic bool HimciIsMultiBlock(struct MmcCmd *cmd)
2921bd4fe43Sopenharmony_ci{
2931bd4fe43Sopenharmony_ci    if (cmd->cmdCode == WRITE_MULTIPLE_BLOCK || cmd->cmdCode == READ_MULTIPLE_BLOCK) {
2941bd4fe43Sopenharmony_ci        return true;
2951bd4fe43Sopenharmony_ci    }
2961bd4fe43Sopenharmony_ci    if (cmd->data->blockNum > 1) {
2971bd4fe43Sopenharmony_ci        return true;
2981bd4fe43Sopenharmony_ci    }
2991bd4fe43Sopenharmony_ci    return false;
3001bd4fe43Sopenharmony_ci}
3011bd4fe43Sopenharmony_ci
3021bd4fe43Sopenharmony_cistatic bool HimciNeedAutoStop(struct MmcCntlr *cntlr)
3031bd4fe43Sopenharmony_ci{
3041bd4fe43Sopenharmony_ci    if (cntlr->curDev->type == MMC_DEV_SDIO) {
3051bd4fe43Sopenharmony_ci        return false;
3061bd4fe43Sopenharmony_ci    }
3071bd4fe43Sopenharmony_ci
3081bd4fe43Sopenharmony_ci    if (((cntlr->curDev->type == MMC_DEV_SD || cntlr->curDev->type == MMC_DEV_COMBO) &&
3091bd4fe43Sopenharmony_ci        MmcCntlrSdSupportCmd23(cntlr) == false) ||
3101bd4fe43Sopenharmony_ci        (cntlr->curDev->type == MMC_DEV_EMMC && MmcCntlrEmmcSupportCmd23(cntlr) == false)) {
3111bd4fe43Sopenharmony_ci        return true;
3121bd4fe43Sopenharmony_ci    }
3131bd4fe43Sopenharmony_ci    if (cntlr->caps.bits.cmd23 > 0) {
3141bd4fe43Sopenharmony_ci        /* both host and device support cmd23. */
3151bd4fe43Sopenharmony_ci        return false;
3161bd4fe43Sopenharmony_ci    }
3171bd4fe43Sopenharmony_ci
3181bd4fe43Sopenharmony_ci    /* the device support cmd23 but host doesn't support cmd23 */
3191bd4fe43Sopenharmony_ci    return true;
3201bd4fe43Sopenharmony_ci}
3211bd4fe43Sopenharmony_ci
3221bd4fe43Sopenharmony_cistatic int32_t HimciFillCmdReg(union HimciCmdRegArg *reg, struct MmcCmd *cmd)
3231bd4fe43Sopenharmony_ci{
3241bd4fe43Sopenharmony_ci    if (cmd->cmdCode == STOP_TRANSMISSION) {
3251bd4fe43Sopenharmony_ci        reg->bits.stopAbortCmd = 1;
3261bd4fe43Sopenharmony_ci        reg->bits.waitDataComplete = 0;
3271bd4fe43Sopenharmony_ci    } else {
3281bd4fe43Sopenharmony_ci        reg->bits.stopAbortCmd = 0;
3291bd4fe43Sopenharmony_ci        reg->bits.waitDataComplete = 1;
3301bd4fe43Sopenharmony_ci    }
3311bd4fe43Sopenharmony_ci
3321bd4fe43Sopenharmony_ci    switch (MMC_RESP_TYPE(cmd)) {
3331bd4fe43Sopenharmony_ci        case MMC_RESP_NONE:
3341bd4fe43Sopenharmony_ci            reg->bits.rspExpect = 0;
3351bd4fe43Sopenharmony_ci            reg->bits.rspLen = 0;
3361bd4fe43Sopenharmony_ci            reg->bits.checkRspCrc = 0;
3371bd4fe43Sopenharmony_ci            break;
3381bd4fe43Sopenharmony_ci        case MMC_RESP_R1:
3391bd4fe43Sopenharmony_ci        case MMC_RESP_R1B:
3401bd4fe43Sopenharmony_ci            reg->bits.rspExpect = 1;
3411bd4fe43Sopenharmony_ci            reg->bits.rspLen = 0;
3421bd4fe43Sopenharmony_ci            reg->bits.checkRspCrc = 1;
3431bd4fe43Sopenharmony_ci            break;
3441bd4fe43Sopenharmony_ci        case MMC_RESP_R2:
3451bd4fe43Sopenharmony_ci            reg->bits.rspExpect = 1;
3461bd4fe43Sopenharmony_ci            reg->bits.rspLen = 1;
3471bd4fe43Sopenharmony_ci            reg->bits.checkRspCrc = 1;
3481bd4fe43Sopenharmony_ci            break;
3491bd4fe43Sopenharmony_ci        case MMC_RESP_R3:
3501bd4fe43Sopenharmony_ci        case MMC_RESP_R1 & (~RESP_CRC):
3511bd4fe43Sopenharmony_ci            reg->bits.rspExpect = 1;
3521bd4fe43Sopenharmony_ci            reg->bits.rspLen = 0;
3531bd4fe43Sopenharmony_ci            reg->bits.checkRspCrc = 0;
3541bd4fe43Sopenharmony_ci            break;
3551bd4fe43Sopenharmony_ci        default:
3561bd4fe43Sopenharmony_ci            cmd->returnError = HDF_ERR_INVALID_PARAM;
3571bd4fe43Sopenharmony_ci            HDF_LOGE("unhandled response type 0x%x", MMC_RESP_TYPE(cmd));
3581bd4fe43Sopenharmony_ci            return HDF_ERR_INVALID_PARAM;
3591bd4fe43Sopenharmony_ci    }
3601bd4fe43Sopenharmony_ci
3611bd4fe43Sopenharmony_ci    reg->bits.sendInitialization = 0;
3621bd4fe43Sopenharmony_ci    if (cmd->cmdCode == GO_IDLE_STATE) {
3631bd4fe43Sopenharmony_ci        reg->bits.sendInitialization = 1;
3641bd4fe43Sopenharmony_ci    }
3651bd4fe43Sopenharmony_ci    /* CMD 11 check switch voltage */
3661bd4fe43Sopenharmony_ci    reg->bits.voltSwitch = 0;
3671bd4fe43Sopenharmony_ci    if (cmd->cmdCode == SD_CMD_SWITCH_VOLTAGE) {
3681bd4fe43Sopenharmony_ci        reg->bits.voltSwitch = 1;
3691bd4fe43Sopenharmony_ci    }
3701bd4fe43Sopenharmony_ci
3711bd4fe43Sopenharmony_ci    reg->bits.cardNumber = 0;
3721bd4fe43Sopenharmony_ci    reg->bits.cmdIndex = cmd->cmdCode;
3731bd4fe43Sopenharmony_ci    reg->bits.startCmd = 1;
3741bd4fe43Sopenharmony_ci    reg->bits.updateClkRegOnly = 0;
3751bd4fe43Sopenharmony_ci    return HDF_SUCCESS;
3761bd4fe43Sopenharmony_ci}
3771bd4fe43Sopenharmony_ci
3781bd4fe43Sopenharmony_cistatic int32_t HimciUpdateCmdReg(union HimciCmdRegArg *reg, struct HimciHost *host)
3791bd4fe43Sopenharmony_ci{
3801bd4fe43Sopenharmony_ci    struct MmcCmd *cmd = host->cmd;
3811bd4fe43Sopenharmony_ci    struct MmcData *data = cmd->data;
3821bd4fe43Sopenharmony_ci
3831bd4fe43Sopenharmony_ci    if (data != NULL) {
3841bd4fe43Sopenharmony_ci        reg->bits.dataTransferExpected = 1;
3851bd4fe43Sopenharmony_ci        if ((data->dataFlags & (DATA_WRITE | DATA_READ)) > 0) {
3861bd4fe43Sopenharmony_ci            reg->bits.transferMode = 0;
3871bd4fe43Sopenharmony_ci        }
3881bd4fe43Sopenharmony_ci        if ((data->dataFlags & DATA_STREAM) > 0) {
3891bd4fe43Sopenharmony_ci            reg->bits.transferMode = 1;
3901bd4fe43Sopenharmony_ci        }
3911bd4fe43Sopenharmony_ci        if ((data->dataFlags & DATA_WRITE) > 0) {
3921bd4fe43Sopenharmony_ci            reg->bits.readWrite = 1;
3931bd4fe43Sopenharmony_ci        } else if ((data->dataFlags & DATA_READ) > 0) {
3941bd4fe43Sopenharmony_ci            reg->bits.readWrite = 0;
3951bd4fe43Sopenharmony_ci        }
3961bd4fe43Sopenharmony_ci        reg->bits.sendAutoStop = 0;
3971bd4fe43Sopenharmony_ci        if (HimciIsMultiBlock(cmd) == true && HimciNeedAutoStop(host->mmc) == true) {
3981bd4fe43Sopenharmony_ci            reg->bits.sendAutoStop = 1;
3991bd4fe43Sopenharmony_ci        }
4001bd4fe43Sopenharmony_ci    } else {
4011bd4fe43Sopenharmony_ci        reg->bits.dataTransferExpected = 0;
4021bd4fe43Sopenharmony_ci        reg->bits.transferMode = 0;
4031bd4fe43Sopenharmony_ci        reg->bits.readWrite = 0;
4041bd4fe43Sopenharmony_ci    }
4051bd4fe43Sopenharmony_ci
4061bd4fe43Sopenharmony_ci    if (HimciFillCmdReg(reg, cmd) != HDF_SUCCESS) {
4071bd4fe43Sopenharmony_ci        return HDF_FAILURE;
4081bd4fe43Sopenharmony_ci    }
4091bd4fe43Sopenharmony_ci    return HDF_SUCCESS;
4101bd4fe43Sopenharmony_ci}
4111bd4fe43Sopenharmony_ci
4121bd4fe43Sopenharmony_cistatic int32_t HimciExecCmd(struct HimciHost *host)
4131bd4fe43Sopenharmony_ci{
4141bd4fe43Sopenharmony_ci    union HimciCmdRegArg cmdRegs;
4151bd4fe43Sopenharmony_ci    int32_t ret;
4161bd4fe43Sopenharmony_ci    struct MmcCmd *cmd = host->cmd;
4171bd4fe43Sopenharmony_ci
4181bd4fe43Sopenharmony_ci    HIMCI_WRITEL(cmd->argument, (uintptr_t)host->base + MMC_CMDARG);
4191bd4fe43Sopenharmony_ci    cmdRegs.arg = HIMCI_READL((uintptr_t)host->base + MMC_CMD);
4201bd4fe43Sopenharmony_ci    ret = HimciUpdateCmdReg(&cmdRegs, host);
4211bd4fe43Sopenharmony_ci    if (ret != HDF_SUCCESS) {
4221bd4fe43Sopenharmony_ci        return ret;
4231bd4fe43Sopenharmony_ci    }
4241bd4fe43Sopenharmony_ci    HIMCI_WRITEL(cmdRegs.arg, (uintptr_t)host->base + MMC_CMD);
4251bd4fe43Sopenharmony_ci    return HDF_SUCCESS;
4261bd4fe43Sopenharmony_ci}
4271bd4fe43Sopenharmony_ci
4281bd4fe43Sopenharmony_cistatic int32_t HimciWaitCmd(struct HimciHost *host)
4291bd4fe43Sopenharmony_ci{
4301bd4fe43Sopenharmony_ci    int32_t reties = 0;
4311bd4fe43Sopenharmony_ci    uint32_t val;
4321bd4fe43Sopenharmony_ci    unsigned long flags = 0;
4331bd4fe43Sopenharmony_ci
4341bd4fe43Sopenharmony_ci    while (true) {
4351bd4fe43Sopenharmony_ci        /*
4361bd4fe43Sopenharmony_ci         * Check if CMD start_cmd bit is clear.
4371bd4fe43Sopenharmony_ci         * start_cmd = 0 means MMC Host controller has loaded registers and next command can be loaded in.
4381bd4fe43Sopenharmony_ci         */
4391bd4fe43Sopenharmony_ci        val = HIMCI_READL((uintptr_t)host->base + MMC_CMD);
4401bd4fe43Sopenharmony_ci        if ((val & START_CMD) == 0) {
4411bd4fe43Sopenharmony_ci            break;
4421bd4fe43Sopenharmony_ci        }
4431bd4fe43Sopenharmony_ci        /* Check if Raw_Intr_Status HLE bit is set. */
4441bd4fe43Sopenharmony_ci        HIMCI_IRQ_LOCK(&flags);
4451bd4fe43Sopenharmony_ci        val = HIMCI_READL((uintptr_t)host->base + MMC_RINTSTS);
4461bd4fe43Sopenharmony_ci        if ((val & HLE_INT_STATUS) > 0) {
4471bd4fe43Sopenharmony_ci            val |= HLE_INT_STATUS;
4481bd4fe43Sopenharmony_ci            HIMCI_WRITEL(val, (uintptr_t)host->base + MMC_RINTSTS);
4491bd4fe43Sopenharmony_ci            HIMCI_IRQ_UNLOCK(flags);
4501bd4fe43Sopenharmony_ci            HDF_LOGE("host%u: Other CMD is running! please operate cmd again!", host->id);
4511bd4fe43Sopenharmony_ci            return HDF_MMC_ERR_OTHER_CMD_IS_RUNNING;
4521bd4fe43Sopenharmony_ci        }
4531bd4fe43Sopenharmony_ci        HIMCI_IRQ_UNLOCK(flags);
4541bd4fe43Sopenharmony_ci        OsalUDelay(100);
4551bd4fe43Sopenharmony_ci
4561bd4fe43Sopenharmony_ci        /* Check if number of retries for this are over. */
4571bd4fe43Sopenharmony_ci        reties++;
4581bd4fe43Sopenharmony_ci        if (reties >= HIMCI_MAX_RETRY_COUNT) {
4591bd4fe43Sopenharmony_ci            if (host->cmd != NULL) {
4601bd4fe43Sopenharmony_ci                HDF_LOGE("wait cmd[%u] complete is timeout!", host->cmd->cmdCode);
4611bd4fe43Sopenharmony_ci            } else {
4621bd4fe43Sopenharmony_ci                HDF_LOGE("timeout!");
4631bd4fe43Sopenharmony_ci            }
4641bd4fe43Sopenharmony_ci            return HDF_FAILURE;
4651bd4fe43Sopenharmony_ci        }
4661bd4fe43Sopenharmony_ci    }
4671bd4fe43Sopenharmony_ci    return HDF_SUCCESS;
4681bd4fe43Sopenharmony_ci}
4691bd4fe43Sopenharmony_ci
4701bd4fe43Sopenharmony_cistatic void HimciCmdDone(struct HimciHost *host)
4711bd4fe43Sopenharmony_ci{
4721bd4fe43Sopenharmony_ci    uint32_t i;
4731bd4fe43Sopenharmony_ci    struct MmcCmd *cmd = host->cmd;
4741bd4fe43Sopenharmony_ci
4751bd4fe43Sopenharmony_ci    if ((cmd->respType & RESP_PRESENT) == 0) {
4761bd4fe43Sopenharmony_ci        return;
4771bd4fe43Sopenharmony_ci    }
4781bd4fe43Sopenharmony_ci
4791bd4fe43Sopenharmony_ci    if (MMC_RESP_TYPE(cmd) != MMC_RESP_R2) {
4801bd4fe43Sopenharmony_ci        cmd->resp[0] = HIMCI_READL((uintptr_t)host->base + MMC_RESP0);
4811bd4fe43Sopenharmony_ci        return;
4821bd4fe43Sopenharmony_ci    }
4831bd4fe43Sopenharmony_ci
4841bd4fe43Sopenharmony_ci    for (i = 0; i < MMC_CMD_RESP_SIZE; i++) {
4851bd4fe43Sopenharmony_ci        cmd->resp[i] = HIMCI_READL((uintptr_t)host->base + MMC_RESP3 - i * 0x4);
4861bd4fe43Sopenharmony_ci        /* R2 must delay some time here when use UHI card. */
4871bd4fe43Sopenharmony_ci        OsalUDelay(1000);
4881bd4fe43Sopenharmony_ci    }
4891bd4fe43Sopenharmony_ci}
4901bd4fe43Sopenharmony_ci
4911bd4fe43Sopenharmony_cistatic void HimciDataSync(struct HimciHost *host, struct MmcData *data)
4921bd4fe43Sopenharmony_ci{
4931bd4fe43Sopenharmony_ci    uint32_t sgPhyAddr, sgLength, i;
4941bd4fe43Sopenharmony_ci
4951bd4fe43Sopenharmony_ci    if ((data->dataFlags & DATA_READ) > 0) {
4961bd4fe43Sopenharmony_ci        for (i = 0; i < host->dmaSgNum; i++) {
4971bd4fe43Sopenharmony_ci            sgLength = HIMCI_SG_DMA_LEN(&host->sg[i]);
4981bd4fe43Sopenharmony_ci            sgPhyAddr = HIMCI_SG_DMA_ADDRESS(&host->sg[i]);
4991bd4fe43Sopenharmony_ci            HimciDmaCacheInv((void *)(uintptr_t)sgPhyAddr, sgLength);
5001bd4fe43Sopenharmony_ci        }
5011bd4fe43Sopenharmony_ci    }
5021bd4fe43Sopenharmony_ci}
5031bd4fe43Sopenharmony_ci
5041bd4fe43Sopenharmony_cistatic void HimciDataDone(struct HimciHost *host, uint32_t state)
5051bd4fe43Sopenharmony_ci{
5061bd4fe43Sopenharmony_ci    struct MmcData *data = NULL;
5071bd4fe43Sopenharmony_ci
5081bd4fe43Sopenharmony_ci    if (host->cmd == NULL) {
5091bd4fe43Sopenharmony_ci        return;
5101bd4fe43Sopenharmony_ci    }
5111bd4fe43Sopenharmony_ci    if (host->cmd->data == NULL) {
5121bd4fe43Sopenharmony_ci        return;
5131bd4fe43Sopenharmony_ci    }
5141bd4fe43Sopenharmony_ci
5151bd4fe43Sopenharmony_ci    data = host->cmd->data;
5161bd4fe43Sopenharmony_ci    if ((state & (HTO_INT_STATUS | DRTO_INT_STATUS | RTO_INT_STATUS)) > 0) {
5171bd4fe43Sopenharmony_ci        data->returnError = HDF_ERR_TIMEOUT;
5181bd4fe43Sopenharmony_ci    } else if ((state & (EBE_INT_STATUS | SBE_INT_STATUS | FRUN_INT_STATUS | DCRC_INT_STATUS)) > 0) {
5191bd4fe43Sopenharmony_ci        data->returnError = HDF_MMC_ERR_ILLEGAL_SEQ;
5201bd4fe43Sopenharmony_ci    }
5211bd4fe43Sopenharmony_ci}
5221bd4fe43Sopenharmony_ci
5231bd4fe43Sopenharmony_cistatic void HimciWaitCmdComplete(struct HimciHost *host)
5241bd4fe43Sopenharmony_ci{
5251bd4fe43Sopenharmony_ci    struct MmcCmd *cmd = host->cmd;
5261bd4fe43Sopenharmony_ci    uint32_t timeout, status;
5271bd4fe43Sopenharmony_ci    unsigned long flags = 0;
5281bd4fe43Sopenharmony_ci
5291bd4fe43Sopenharmony_ci    if (host->isTuning == true) {
5301bd4fe43Sopenharmony_ci        timeout = HIMCI_TUNINT_REQ_TIMEOUT;
5311bd4fe43Sopenharmony_ci    } else {
5321bd4fe43Sopenharmony_ci        timeout = HIMCI_REQUEST_TIMEOUT;
5331bd4fe43Sopenharmony_ci    }
5341bd4fe43Sopenharmony_ci
5351bd4fe43Sopenharmony_ci    HIMCI_IRQ_LOCK(&flags);
5361bd4fe43Sopenharmony_ci    host->waitForEvent = true;
5371bd4fe43Sopenharmony_ci    HIMCI_IRQ_UNLOCK(flags);
5381bd4fe43Sopenharmony_ci
5391bd4fe43Sopenharmony_ci    status = HIMCI_EVENT_WAIT(&host->himciEvent, (HIMCI_PEND_DTO_M | HIMCI_PEND_ACCIDENT), timeout);
5401bd4fe43Sopenharmony_ci    if (status == LOS_ERRNO_EVENT_READ_TIMEOUT || status == HIMCI_PEND_ACCIDENT) {
5411bd4fe43Sopenharmony_ci        if (status == HIMCI_PEND_ACCIDENT) {
5421bd4fe43Sopenharmony_ci            cmd->returnError = HDF_ERR_IO;
5431bd4fe43Sopenharmony_ci        } else {
5441bd4fe43Sopenharmony_ci            cmd->returnError = HDF_ERR_TIMEOUT;
5451bd4fe43Sopenharmony_ci            if (host->isTuning == false) {
5461bd4fe43Sopenharmony_ci                HimciDumpRegs(host);
5471bd4fe43Sopenharmony_ci                HDF_LOGE("host%u cmd%u(arg 0x%x) timeout!", host->id, cmd->cmdCode, cmd->argument);
5481bd4fe43Sopenharmony_ci            }
5491bd4fe43Sopenharmony_ci        }
5501bd4fe43Sopenharmony_ci        if (host->cmd->data != NULL) {
5511bd4fe43Sopenharmony_ci            HimciDmaStop(host);
5521bd4fe43Sopenharmony_ci            HimciDataDone(host, 0);
5531bd4fe43Sopenharmony_ci        }
5541bd4fe43Sopenharmony_ci    } else if (host->cmd->data != NULL) {
5551bd4fe43Sopenharmony_ci        HimciDataSync(host, host->cmd->data);
5561bd4fe43Sopenharmony_ci    }
5571bd4fe43Sopenharmony_ci
5581bd4fe43Sopenharmony_ci    HIMCI_IRQ_LOCK(&flags);
5591bd4fe43Sopenharmony_ci    host->waitForEvent = false;
5601bd4fe43Sopenharmony_ci    HIMCI_IRQ_UNLOCK(flags);
5611bd4fe43Sopenharmony_ci    HimciCmdDone(host);
5621bd4fe43Sopenharmony_ci}
5631bd4fe43Sopenharmony_ci
5641bd4fe43Sopenharmony_cistatic bool HimciCardPlugged(struct MmcCntlr *cntlr)
5651bd4fe43Sopenharmony_ci{
5661bd4fe43Sopenharmony_ci    unsigned int status;
5671bd4fe43Sopenharmony_ci    struct HimciHost *host = NULL;
5681bd4fe43Sopenharmony_ci
5691bd4fe43Sopenharmony_ci    if ((cntlr == NULL) || (cntlr->priv == NULL)) {
5701bd4fe43Sopenharmony_ci        return false;
5711bd4fe43Sopenharmony_ci    }
5721bd4fe43Sopenharmony_ci
5731bd4fe43Sopenharmony_ci    if (cntlr->devType == MMC_DEV_SDIO || cntlr->devType == MMC_DEV_EMMC) {
5741bd4fe43Sopenharmony_ci        return true;
5751bd4fe43Sopenharmony_ci    }
5761bd4fe43Sopenharmony_ci
5771bd4fe43Sopenharmony_ci    host = (struct HimciHost *)cntlr->priv;
5781bd4fe43Sopenharmony_ci    status = HIMCI_READL((uintptr_t)host->base + MMC_CDETECT);
5791bd4fe43Sopenharmony_ci    if ((status & CARD_UNPLUGED) == 0) {
5801bd4fe43Sopenharmony_ci        return true;
5811bd4fe43Sopenharmony_ci    }
5821bd4fe43Sopenharmony_ci    return false;
5831bd4fe43Sopenharmony_ci}
5841bd4fe43Sopenharmony_ci
5851bd4fe43Sopenharmony_cistatic int32_t HimciSendCmd23(struct HimciHost *host, uint32_t blockNum)
5861bd4fe43Sopenharmony_ci{
5871bd4fe43Sopenharmony_ci    int32_t ret;
5881bd4fe43Sopenharmony_ci    struct MmcCmd cmd = {0};
5891bd4fe43Sopenharmony_ci
5901bd4fe43Sopenharmony_ci    cmd.cmdCode = SET_BLOCK_COUNT;
5911bd4fe43Sopenharmony_ci    cmd.argument = blockNum;
5921bd4fe43Sopenharmony_ci    host->cmd = &cmd;
5931bd4fe43Sopenharmony_ci    ret = HimciExecCmd(host);
5941bd4fe43Sopenharmony_ci    if (ret != HDF_SUCCESS) {
5951bd4fe43Sopenharmony_ci        host->cmd = NULL;
5961bd4fe43Sopenharmony_ci        HDF_LOGE("cmd23 failed, ret = %d!", ret);
5971bd4fe43Sopenharmony_ci        return ret;
5981bd4fe43Sopenharmony_ci    }
5991bd4fe43Sopenharmony_ci
6001bd4fe43Sopenharmony_ci    HimciWaitCmdComplete(host);
6011bd4fe43Sopenharmony_ci    host->cmd = NULL;
6021bd4fe43Sopenharmony_ci    return cmd.returnError;
6031bd4fe43Sopenharmony_ci}
6041bd4fe43Sopenharmony_ci
6051bd4fe43Sopenharmony_cistatic int32_t HimciFifoReset(struct HimciHost *host)
6061bd4fe43Sopenharmony_ci{
6071bd4fe43Sopenharmony_ci    uint32_t i;
6081bd4fe43Sopenharmony_ci
6091bd4fe43Sopenharmony_ci    HIMCI_SETL(host, MMC_CTRL, FIFO_RESET);
6101bd4fe43Sopenharmony_ci    for (i = 0; i < HIMCI_MAX_RETRY_COUNT; i++) {
6111bd4fe43Sopenharmony_ci        if ((HIMCI_READL((uintptr_t)host->base + MMC_CTRL) & FIFO_RESET) == 0) {
6121bd4fe43Sopenharmony_ci            return HDF_SUCCESS;
6131bd4fe43Sopenharmony_ci        }
6141bd4fe43Sopenharmony_ci    }
6151bd4fe43Sopenharmony_ci    return HDF_ERR_TIMEOUT;
6161bd4fe43Sopenharmony_ci}
6171bd4fe43Sopenharmony_ci
6181bd4fe43Sopenharmony_cistatic int32_t HimciFillDmaSg(struct HimciHost *host, struct MmcData *data)
6191bd4fe43Sopenharmony_ci{
6201bd4fe43Sopenharmony_ci    uint32_t len = data->blockNum * data->blockSize;
6211bd4fe43Sopenharmony_ci    int32_t ret;
6221bd4fe43Sopenharmony_ci
6231bd4fe43Sopenharmony_ci    if (len == 0) {
6241bd4fe43Sopenharmony_ci        return HDF_ERR_INVALID_PARAM;
6251bd4fe43Sopenharmony_ci    }
6261bd4fe43Sopenharmony_ci
6271bd4fe43Sopenharmony_ci    if (data->scatter != NULL && data->dataBuffer == NULL) {
6281bd4fe43Sopenharmony_ci        host->sg = data->scatter;
6291bd4fe43Sopenharmony_ci        host->dmaSgNum = data->scatterLen;
6301bd4fe43Sopenharmony_ci        return HDF_SUCCESS;
6311bd4fe43Sopenharmony_ci    }
6321bd4fe43Sopenharmony_ci    if (data->dataBuffer == NULL) {
6331bd4fe43Sopenharmony_ci        return HDF_ERR_INVALID_PARAM;
6341bd4fe43Sopenharmony_ci    }
6351bd4fe43Sopenharmony_ci
6361bd4fe43Sopenharmony_ci    host->alignedBuff = (uint8_t *)OsalMemAllocAlign(CACHE_ALIGNED_SIZE, ALIGN(len, CACHE_ALIGNED_SIZE));
6371bd4fe43Sopenharmony_ci    if (host->alignedBuff == NULL) {
6381bd4fe43Sopenharmony_ci        HDF_LOGE("HimciFillDmaSg: alloc fail.");
6391bd4fe43Sopenharmony_ci        return HDF_ERR_MALLOC_FAIL;
6401bd4fe43Sopenharmony_ci    }
6411bd4fe43Sopenharmony_ci
6421bd4fe43Sopenharmony_ci    ret = memcpy_s(host->alignedBuff, len, data->dataBuffer, len);
6431bd4fe43Sopenharmony_ci    if (ret != EOK) {
6441bd4fe43Sopenharmony_ci        HDF_LOGE("memcpy_s fail ret = %d.", ret);
6451bd4fe43Sopenharmony_ci        OsalMemFree(host->alignedBuff);
6461bd4fe43Sopenharmony_ci        host->alignedBuff = NULL;
6471bd4fe43Sopenharmony_ci        return HDF_FAILURE;
6481bd4fe43Sopenharmony_ci    }
6491bd4fe43Sopenharmony_ci    host->buffLen = len;
6501bd4fe43Sopenharmony_ci    sg_init_one(&host->dmaSg, (const void *)host->alignedBuff, len);
6511bd4fe43Sopenharmony_ci    host->dmaSgNum = 1;
6521bd4fe43Sopenharmony_ci    host->sg = &host->dmaSg;
6531bd4fe43Sopenharmony_ci    return HDF_SUCCESS;
6541bd4fe43Sopenharmony_ci}
6551bd4fe43Sopenharmony_ci
6561bd4fe43Sopenharmony_cistatic void HimciClearDmaSg(struct HimciHost *host, struct MmcData *data)
6571bd4fe43Sopenharmony_ci{
6581bd4fe43Sopenharmony_ci    uint32_t len;
6591bd4fe43Sopenharmony_ci
6601bd4fe43Sopenharmony_ci    if (data == NULL) {
6611bd4fe43Sopenharmony_ci        return;
6621bd4fe43Sopenharmony_ci    }
6631bd4fe43Sopenharmony_ci
6641bd4fe43Sopenharmony_ci    len = data->blockNum * data->blockSize;
6651bd4fe43Sopenharmony_ci    if (host->alignedBuff != NULL && data->dataBuffer != NULL && len > 0 && host->buffLen > 0) {
6661bd4fe43Sopenharmony_ci        if ((data->dataFlags & DATA_READ) > 0) {
6671bd4fe43Sopenharmony_ci            if (memcpy_s(data->dataBuffer, len, host->alignedBuff, host->buffLen) != EOK) {
6681bd4fe43Sopenharmony_ci                HDF_LOGE("%s: memcpy_s failed!", __func__);
6691bd4fe43Sopenharmony_ci            }
6701bd4fe43Sopenharmony_ci        }
6711bd4fe43Sopenharmony_ci    }
6721bd4fe43Sopenharmony_ci    if (host->alignedBuff != NULL) {
6731bd4fe43Sopenharmony_ci        OsalMemFree(host->alignedBuff);
6741bd4fe43Sopenharmony_ci        host->alignedBuff = NULL;
6751bd4fe43Sopenharmony_ci    }
6761bd4fe43Sopenharmony_ci    host->dmaSgNum = 0;
6771bd4fe43Sopenharmony_ci    host->buffLen = 0;
6781bd4fe43Sopenharmony_ci    host->sg = NULL;
6791bd4fe43Sopenharmony_ci}
6801bd4fe43Sopenharmony_ci
6811bd4fe43Sopenharmony_cistatic int32_t HimciSetupData(struct HimciHost *host, struct MmcData *data)
6821bd4fe43Sopenharmony_ci{
6831bd4fe43Sopenharmony_ci    int32_t ret;
6841bd4fe43Sopenharmony_ci    uint32_t sgPhyAddr, sgLength, i;
6851bd4fe43Sopenharmony_ci    uint32_t desCnt = 0;
6861bd4fe43Sopenharmony_ci    uint32_t maximum = HIMCI_PAGE_SIZE / sizeof(struct HimciDes);
6871bd4fe43Sopenharmony_ci    struct HimciDes *des = NULL;
6881bd4fe43Sopenharmony_ci    uint32_t dmaDir = DMA_TO_DEVICE;
6891bd4fe43Sopenharmony_ci
6901bd4fe43Sopenharmony_ci    if ((data->dataFlags & DATA_READ) > 0) {
6911bd4fe43Sopenharmony_ci        dmaDir = DMA_FROM_DEVICE;
6921bd4fe43Sopenharmony_ci    }
6931bd4fe43Sopenharmony_ci
6941bd4fe43Sopenharmony_ci    des = (struct HimciDes *)host->dmaVaddr;
6951bd4fe43Sopenharmony_ci    for (i = 0; (i < host->dmaSgNum) && (desCnt < maximum); i++) {
6961bd4fe43Sopenharmony_ci        sgLength = HIMCI_SG_DMA_LEN(&host->sg[i]);
6971bd4fe43Sopenharmony_ci        sgPhyAddr = HIMCI_SG_DMA_ADDRESS(&host->sg[i]);
6981bd4fe43Sopenharmony_ci        if ((sgPhyAddr & (CACHE_ALIGNED_SIZE - 1)) != 0) {
6991bd4fe43Sopenharmony_ci            HDF_LOGE("host%u:sg_phyaddr:0x%x sg_length:0x%x.", host->id, sgPhyAddr, sgLength);
7001bd4fe43Sopenharmony_ci            return HDF_FAILURE;
7011bd4fe43Sopenharmony_ci        }
7021bd4fe43Sopenharmony_ci        if (dmaDir == DMA_TO_DEVICE) {
7031bd4fe43Sopenharmony_ci            HimciDmaCacheClean((void *)(uintptr_t)sgPhyAddr, sgLength);
7041bd4fe43Sopenharmony_ci        } else {
7051bd4fe43Sopenharmony_ci            HimciDmaCacheInv((void *)(uintptr_t)sgPhyAddr, sgLength);
7061bd4fe43Sopenharmony_ci        }
7071bd4fe43Sopenharmony_ci        while (sgLength && (desCnt < maximum)) {
7081bd4fe43Sopenharmony_ci            des[desCnt].dmaDesCtrl = DMA_DES_OWN | DMA_DES_NEXT_DES;
7091bd4fe43Sopenharmony_ci            des[desCnt].dmaDesBufAddr = sgPhyAddr;
7101bd4fe43Sopenharmony_ci            /* idmac_des_next_addr is paddr for dma */
7111bd4fe43Sopenharmony_ci            des[desCnt].dmaDesNextAddr = host->dmaPaddr + (desCnt + 1) * sizeof(struct HimciDes);
7121bd4fe43Sopenharmony_ci            if (sgLength >= HIMCI_DMA_MAX_BUFF_SIZE) {
7131bd4fe43Sopenharmony_ci                des[desCnt].dmaDesBufSize = HIMCI_DMA_MAX_BUFF_SIZE;
7141bd4fe43Sopenharmony_ci                sgLength -= HIMCI_DMA_MAX_BUFF_SIZE;
7151bd4fe43Sopenharmony_ci                sgPhyAddr += HIMCI_DMA_MAX_BUFF_SIZE;
7161bd4fe43Sopenharmony_ci            } else {
7171bd4fe43Sopenharmony_ci                /* data alignment */
7181bd4fe43Sopenharmony_ci                des[desCnt].dmaDesBufSize = sgLength;
7191bd4fe43Sopenharmony_ci                sgLength = 0;
7201bd4fe43Sopenharmony_ci            }
7211bd4fe43Sopenharmony_ci            desCnt++;
7221bd4fe43Sopenharmony_ci        }
7231bd4fe43Sopenharmony_ci    }
7241bd4fe43Sopenharmony_ci    des[0].dmaDesCtrl |= DMA_DES_FIRST_DES;
7251bd4fe43Sopenharmony_ci    des[desCnt - 1].dmaDesCtrl |= DMA_DES_LAST_DES;
7261bd4fe43Sopenharmony_ci    des[desCnt - 1].dmaDesNextAddr = 0;
7271bd4fe43Sopenharmony_ci
7281bd4fe43Sopenharmony_ci    HimciDmaCacheClean((void *)(uintptr_t)host->dmaPaddr, HIMCI_PAGE_SIZE);
7291bd4fe43Sopenharmony_ci
7301bd4fe43Sopenharmony_ci    desCnt = data->blockSize * data->blockNum;
7311bd4fe43Sopenharmony_ci    HIMCI_WRITEL(desCnt, (uintptr_t)host->base + MMC_BYTCNT);
7321bd4fe43Sopenharmony_ci    HIMCI_WRITEL(data->blockSize, (uintptr_t)host->base + MMC_BLKSIZ);
7331bd4fe43Sopenharmony_ci
7341bd4fe43Sopenharmony_ci    ret = HimciFifoReset(host);
7351bd4fe43Sopenharmony_ci    if (ret != HDF_SUCCESS) {
7361bd4fe43Sopenharmony_ci        return ret;
7371bd4fe43Sopenharmony_ci    }
7381bd4fe43Sopenharmony_ci    HimciDmaStart(host);
7391bd4fe43Sopenharmony_ci    return HDF_SUCCESS;
7401bd4fe43Sopenharmony_ci}
7411bd4fe43Sopenharmony_ci
7421bd4fe43Sopenharmony_cistatic bool HimciWaitCardComplete(struct HimciHost *host)
7431bd4fe43Sopenharmony_ci{
7441bd4fe43Sopenharmony_ci    uint64_t timeout;
7451bd4fe43Sopenharmony_ci    uint32_t cycle, busy;
7461bd4fe43Sopenharmony_ci
7471bd4fe43Sopenharmony_ci    timeout = LOS_TickCountGet() + HIMCI_CARD_COMPLETE_TIMEOUT;
7481bd4fe43Sopenharmony_ci    do {
7491bd4fe43Sopenharmony_ci        for (cycle = 0; cycle < HIMCI_MAX_RETRY_COUNT; cycle++) {
7501bd4fe43Sopenharmony_ci            busy = HIMCI_READL((uintptr_t)host->base + MMC_STATUS);
7511bd4fe43Sopenharmony_ci            if ((busy & DATA_BUSY) == 0) {
7521bd4fe43Sopenharmony_ci                return true;
7531bd4fe43Sopenharmony_ci            }
7541bd4fe43Sopenharmony_ci        }
7551bd4fe43Sopenharmony_ci        if (HimciCardPlugged(host->mmc) == false) {
7561bd4fe43Sopenharmony_ci            HDF_LOGE("card is unplugged.");
7571bd4fe43Sopenharmony_ci            return false;
7581bd4fe43Sopenharmony_ci        }
7591bd4fe43Sopenharmony_ci        LOS_Schedule();
7601bd4fe43Sopenharmony_ci    } while (LOS_TickCountGet() < timeout);
7611bd4fe43Sopenharmony_ci
7621bd4fe43Sopenharmony_ci    return false;
7631bd4fe43Sopenharmony_ci}
7641bd4fe43Sopenharmony_ci
7651bd4fe43Sopenharmony_cistatic int32_t HimciCmdDatePrepare(struct MmcCntlr *cntlr, struct MmcCmd *cmd, struct HimciHost *host)
7661bd4fe43Sopenharmony_ci{
7671bd4fe43Sopenharmony_ci    int32_t ret;
7681bd4fe43Sopenharmony_ci    host->cmd = cmd;
7691bd4fe43Sopenharmony_ci    if (cmd->data != NULL) {
7701bd4fe43Sopenharmony_ci        if (HimciIsMultiBlock(cmd) == true && HimciNeedAutoStop(cntlr) == false) {
7711bd4fe43Sopenharmony_ci            ret = HimciSendCmd23(host, cmd->data->blockNum);
7721bd4fe43Sopenharmony_ci            if (ret != HDF_SUCCESS) {
7731bd4fe43Sopenharmony_ci                cmd->returnError = ret;
7741bd4fe43Sopenharmony_ci                return ret;
7751bd4fe43Sopenharmony_ci            }
7761bd4fe43Sopenharmony_ci        }
7771bd4fe43Sopenharmony_ci        host->cmd = cmd;
7781bd4fe43Sopenharmony_ci        ret = HimciFillDmaSg(host, cmd->data);
7791bd4fe43Sopenharmony_ci        if (ret != HDF_SUCCESS) {
7801bd4fe43Sopenharmony_ci            return ret;
7811bd4fe43Sopenharmony_ci        }
7821bd4fe43Sopenharmony_ci        ret = HimciSetupData(host, cmd->data);
7831bd4fe43Sopenharmony_ci        if (ret != HDF_SUCCESS) {
7841bd4fe43Sopenharmony_ci            cmd->data->returnError = ret;
7851bd4fe43Sopenharmony_ci            HDF_LOGE("setup data fail, err = %d.", ret);
7861bd4fe43Sopenharmony_ci            return ret;
7871bd4fe43Sopenharmony_ci        }
7881bd4fe43Sopenharmony_ci    } else {
7891bd4fe43Sopenharmony_ci        HIMCI_WRITEL(0, (uintptr_t)host->base + MMC_BYTCNT);
7901bd4fe43Sopenharmony_ci        HIMCI_WRITEL(0, (uintptr_t)host->base + MMC_BLKSIZ);
7911bd4fe43Sopenharmony_ci    }
7921bd4fe43Sopenharmony_ci    return HDF_SUCCESS;
7931bd4fe43Sopenharmony_ci}
7941bd4fe43Sopenharmony_ci
7951bd4fe43Sopenharmony_cistatic int32_t HimciDoRequest(struct MmcCntlr *cntlr, struct MmcCmd *cmd)
7961bd4fe43Sopenharmony_ci{
7971bd4fe43Sopenharmony_ci    struct HimciHost *host = NULL;
7981bd4fe43Sopenharmony_ci    int32_t ret = HDF_SUCCESS;
7991bd4fe43Sopenharmony_ci
8001bd4fe43Sopenharmony_ci    if ((cntlr == NULL) || (cntlr->priv == NULL) || (cmd == NULL)) {
8011bd4fe43Sopenharmony_ci        return HDF_ERR_INVALID_OBJECT;
8021bd4fe43Sopenharmony_ci    }
8031bd4fe43Sopenharmony_ci
8041bd4fe43Sopenharmony_ci    host = (struct HimciHost *)cntlr->priv;
8051bd4fe43Sopenharmony_ci    (void)OsalMutexLock(&host->mutex);
8061bd4fe43Sopenharmony_ci    if (HimciCardPlugged(cntlr) == false) {
8071bd4fe43Sopenharmony_ci        cmd->returnError = HDF_PLT_ERR_NO_DEV;
8081bd4fe43Sopenharmony_ci        goto _END;
8091bd4fe43Sopenharmony_ci    }
8101bd4fe43Sopenharmony_ci
8111bd4fe43Sopenharmony_ci    if (HimciWaitCardComplete(host) == false) {
8121bd4fe43Sopenharmony_ci        HDF_LOGE("card is busy, can not send cmd.");
8131bd4fe43Sopenharmony_ci        cmd->returnError = HDF_ERR_TIMEOUT;
8141bd4fe43Sopenharmony_ci        goto _END;
8151bd4fe43Sopenharmony_ci    }
8161bd4fe43Sopenharmony_ci
8171bd4fe43Sopenharmony_ci    if (HimciCmdDatePrepare(cntlr, cmd, host) !=  HDF_SUCCESS) {
8181bd4fe43Sopenharmony_ci        goto _END;
8191bd4fe43Sopenharmony_ci    }
8201bd4fe43Sopenharmony_ci
8211bd4fe43Sopenharmony_ci    ret = HimciExecCmd(host);
8221bd4fe43Sopenharmony_ci    if (ret != HDF_SUCCESS) {
8231bd4fe43Sopenharmony_ci        cmd->returnError = ret;
8241bd4fe43Sopenharmony_ci        HimciDmaStop(host);
8251bd4fe43Sopenharmony_ci        HDF_LOGE("cmd%u exec fail, err = %d!", cmd->cmdCode, ret);
8261bd4fe43Sopenharmony_ci        goto _END;
8271bd4fe43Sopenharmony_ci    }
8281bd4fe43Sopenharmony_ci    HimciWaitCmdComplete(host);
8291bd4fe43Sopenharmony_ci
8301bd4fe43Sopenharmony_ci_END:
8311bd4fe43Sopenharmony_ci    HimciClearDmaSg(host, cmd->data);
8321bd4fe43Sopenharmony_ci    host->cmd = NULL;
8331bd4fe43Sopenharmony_ci    (void)OsalMutexUnlock(&host->mutex);
8341bd4fe43Sopenharmony_ci    return ret;
8351bd4fe43Sopenharmony_ci}
8361bd4fe43Sopenharmony_ci
8371bd4fe43Sopenharmony_cistatic void HimciControlClock(struct HimciHost *host, bool enableClk)
8381bd4fe43Sopenharmony_ci{
8391bd4fe43Sopenharmony_ci    uint32_t value;
8401bd4fe43Sopenharmony_ci    union HimciCmdRegArg cmdArg;
8411bd4fe43Sopenharmony_ci
8421bd4fe43Sopenharmony_ci    value = HIMCI_READL((uintptr_t)host->base + MMC_CLKENA);
8431bd4fe43Sopenharmony_ci    if (enableClk == true) {
8441bd4fe43Sopenharmony_ci        value |= CCLK_ENABLE;
8451bd4fe43Sopenharmony_ci        /* Do not set/clear CCLK_LOW_POWER here,or the cmd18 will timeout. */
8461bd4fe43Sopenharmony_ci    } else {
8471bd4fe43Sopenharmony_ci        value &= (~CCLK_ENABLE);
8481bd4fe43Sopenharmony_ci    }
8491bd4fe43Sopenharmony_ci    if (host->mmc->devType == MMC_DEV_SDIO) {
8501bd4fe43Sopenharmony_ci        value &= (~CCLK_LOW_POWER);
8511bd4fe43Sopenharmony_ci    }
8521bd4fe43Sopenharmony_ci    HIMCI_WRITEL(value, (uintptr_t)host->base + MMC_CLKENA);
8531bd4fe43Sopenharmony_ci
8541bd4fe43Sopenharmony_ci    cmdArg.arg = HIMCI_READL((uintptr_t)host->base + MMC_CMD);
8551bd4fe43Sopenharmony_ci    cmdArg.bits.startCmd = 1;
8561bd4fe43Sopenharmony_ci    cmdArg.bits.cardNumber = 0;
8571bd4fe43Sopenharmony_ci    cmdArg.bits.cmdIndex = 0;
8581bd4fe43Sopenharmony_ci    cmdArg.bits.dataTransferExpected = 0;
8591bd4fe43Sopenharmony_ci    cmdArg.bits.useHoldReg = 1;
8601bd4fe43Sopenharmony_ci    cmdArg.bits.updateClkRegOnly = 1;
8611bd4fe43Sopenharmony_ci    HIMCI_WRITEL(cmdArg.arg, (uintptr_t)host->base + MMC_CMD);
8621bd4fe43Sopenharmony_ci
8631bd4fe43Sopenharmony_ci    if (HimciWaitCmd(host) != HDF_SUCCESS) {
8641bd4fe43Sopenharmony_ci        HDF_LOGE("dis/enable clk is err!");
8651bd4fe43Sopenharmony_ci    }
8661bd4fe43Sopenharmony_ci}
8671bd4fe43Sopenharmony_ci
8681bd4fe43Sopenharmony_cistatic void HimciSetCClk(struct HimciHost *host, uint32_t clock)
8691bd4fe43Sopenharmony_ci{
8701bd4fe43Sopenharmony_ci    uint32_t clk = 0;
8711bd4fe43Sopenharmony_ci    union HimciCmdRegArg cmdArg;
8721bd4fe43Sopenharmony_ci    struct MmcCntlr *mmc = host->mmc;
8731bd4fe43Sopenharmony_ci    struct MmcDevice *dev = mmc->curDev;
8741bd4fe43Sopenharmony_ci
8751bd4fe43Sopenharmony_ci    (void)OsalMutexLock(&host->mutex);
8761bd4fe43Sopenharmony_ci    if (host->id < MMC_CNTLR_NR_MAX) {
8771bd4fe43Sopenharmony_ci        clk = HimciClkDiv(host, clock);
8781bd4fe43Sopenharmony_ci    }
8791bd4fe43Sopenharmony_ci    (void)OsalMutexUnlock(&host->mutex);
8801bd4fe43Sopenharmony_ci    dev->workPara.clock = clk;
8811bd4fe43Sopenharmony_ci
8821bd4fe43Sopenharmony_ci    cmdArg.arg = HIMCI_READL((uintptr_t)host->base + MMC_CMD);
8831bd4fe43Sopenharmony_ci    cmdArg.bits.startCmd = 1;
8841bd4fe43Sopenharmony_ci    cmdArg.bits.cardNumber = 0;
8851bd4fe43Sopenharmony_ci    cmdArg.bits.updateClkRegOnly = 1;
8861bd4fe43Sopenharmony_ci    cmdArg.bits.cmdIndex = 0;
8871bd4fe43Sopenharmony_ci    cmdArg.bits.dataTransferExpected = 0;
8881bd4fe43Sopenharmony_ci    HIMCI_WRITEL(cmdArg.arg, (uintptr_t)host->base + MMC_CMD);
8891bd4fe43Sopenharmony_ci
8901bd4fe43Sopenharmony_ci    if (HimciWaitCmd(host) != HDF_SUCCESS) {
8911bd4fe43Sopenharmony_ci        HDF_LOGE("host%u: set card clk divider is failed!", host->id);
8921bd4fe43Sopenharmony_ci    }
8931bd4fe43Sopenharmony_ci}
8941bd4fe43Sopenharmony_ci
8951bd4fe43Sopenharmony_cistatic int32_t HimciSetClock(struct MmcCntlr *cntlr, uint32_t clock)
8961bd4fe43Sopenharmony_ci{
8971bd4fe43Sopenharmony_ci    struct HimciHost *host = NULL;
8981bd4fe43Sopenharmony_ci    uint32_t curClock = clock;
8991bd4fe43Sopenharmony_ci
9001bd4fe43Sopenharmony_ci    if ((cntlr == NULL) || (cntlr->priv == NULL)) {
9011bd4fe43Sopenharmony_ci        return HDF_ERR_INVALID_OBJECT;
9021bd4fe43Sopenharmony_ci    }
9031bd4fe43Sopenharmony_ci    /* can not greater than max of host. */
9041bd4fe43Sopenharmony_ci    if (curClock > cntlr->freqMax) {
9051bd4fe43Sopenharmony_ci        curClock = cntlr->freqMax;
9061bd4fe43Sopenharmony_ci    }
9071bd4fe43Sopenharmony_ci
9081bd4fe43Sopenharmony_ci    host = (struct HimciHost *)cntlr->priv;
9091bd4fe43Sopenharmony_ci    HimciControlClock(host, false);
9101bd4fe43Sopenharmony_ci    if (curClock > 0) {
9111bd4fe43Sopenharmony_ci        HimciSetCClk(host, curClock);
9121bd4fe43Sopenharmony_ci        HimciControlClock(host, true);
9131bd4fe43Sopenharmony_ci    }
9141bd4fe43Sopenharmony_ci    return HDF_SUCCESS;
9151bd4fe43Sopenharmony_ci}
9161bd4fe43Sopenharmony_ci
9171bd4fe43Sopenharmony_cistatic void HimciControlPower(struct HimciHost *host, enum HimciPowerStatus status, bool forceEnable)
9181bd4fe43Sopenharmony_ci{
9191bd4fe43Sopenharmony_ci    uint32_t value;
9201bd4fe43Sopenharmony_ci
9211bd4fe43Sopenharmony_ci    if (host->powerStatus != status || forceEnable == true) {
9221bd4fe43Sopenharmony_ci        value = HIMCI_READL((uintptr_t)host->base + MMC_PWREN);
9231bd4fe43Sopenharmony_ci        if (status == HOST_POWER_OFF) {
9241bd4fe43Sopenharmony_ci            value &= (~POWER_ENABLE);
9251bd4fe43Sopenharmony_ci        } else {
9261bd4fe43Sopenharmony_ci            value |= POWER_ENABLE;
9271bd4fe43Sopenharmony_ci        }
9281bd4fe43Sopenharmony_ci        HIMCI_WRITEL(value, (uintptr_t)host->base + MMC_PWREN);
9291bd4fe43Sopenharmony_ci        OsalMDelay(50);
9301bd4fe43Sopenharmony_ci        host->powerStatus = status;
9311bd4fe43Sopenharmony_ci    }
9321bd4fe43Sopenharmony_ci}
9331bd4fe43Sopenharmony_ci
9341bd4fe43Sopenharmony_cistatic int32_t HimciSetPowerMode(struct MmcCntlr *cntlr, enum MmcPowerMode mode)
9351bd4fe43Sopenharmony_ci{
9361bd4fe43Sopenharmony_ci    struct HimciHost *host = NULL;
9371bd4fe43Sopenharmony_ci    uint32_t value;
9381bd4fe43Sopenharmony_ci    if ((cntlr == NULL) || (cntlr->priv == NULL)) {
9391bd4fe43Sopenharmony_ci        return HDF_ERR_INVALID_OBJECT;
9401bd4fe43Sopenharmony_ci    }
9411bd4fe43Sopenharmony_ci
9421bd4fe43Sopenharmony_ci    host = (struct HimciHost *)cntlr->priv;
9431bd4fe43Sopenharmony_ci    if (mode == MMC_POWER_MODE_POWER_OFF) {
9441bd4fe43Sopenharmony_ci        value = HIMCI_READL((uintptr_t)host->base + MMC_UHS_REG);
9451bd4fe43Sopenharmony_ci        value &= (~HI_SDXC_CTRL_VDD_180);
9461bd4fe43Sopenharmony_ci        HIMCI_WRITEL(value, (uintptr_t)host->base + MMC_UHS_REG);
9471bd4fe43Sopenharmony_ci        HimciControlPower(host, HOST_POWER_OFF, false);
9481bd4fe43Sopenharmony_ci    } else {
9491bd4fe43Sopenharmony_ci        HimciControlPower(host, HOST_POWER_ON, true);
9501bd4fe43Sopenharmony_ci    }
9511bd4fe43Sopenharmony_ci    return HDF_SUCCESS;
9521bd4fe43Sopenharmony_ci}
9531bd4fe43Sopenharmony_ci
9541bd4fe43Sopenharmony_cistatic int32_t HimciSetBusWidth(struct MmcCntlr *cntlr, enum MmcBusWidth width)
9551bd4fe43Sopenharmony_ci{
9561bd4fe43Sopenharmony_ci    struct HimciHost *host = NULL;
9571bd4fe43Sopenharmony_ci    uint32_t value;
9581bd4fe43Sopenharmony_ci
9591bd4fe43Sopenharmony_ci    if ((cntlr == NULL) || (cntlr->priv == NULL)) {
9601bd4fe43Sopenharmony_ci        return HDF_ERR_INVALID_OBJECT;
9611bd4fe43Sopenharmony_ci    }
9621bd4fe43Sopenharmony_ci
9631bd4fe43Sopenharmony_ci    host = (struct HimciHost *)cntlr->priv;
9641bd4fe43Sopenharmony_ci    value = HIMCI_READL((uintptr_t)host->base + MMC_CTYPE);
9651bd4fe43Sopenharmony_ci    value &= (~(CARD_WIDTH_0 | CARD_WIDTH_1));
9661bd4fe43Sopenharmony_ci
9671bd4fe43Sopenharmony_ci    if (width == BUS_WIDTH8) {
9681bd4fe43Sopenharmony_ci        value |= CARD_WIDTH_0;
9691bd4fe43Sopenharmony_ci        HIMCI_WRITEL(value, (uintptr_t)host->base + MMC_CTYPE);
9701bd4fe43Sopenharmony_ci    } else if (width == BUS_WIDTH4) {
9711bd4fe43Sopenharmony_ci        value |= CARD_WIDTH_1;
9721bd4fe43Sopenharmony_ci        HIMCI_WRITEL(value, (uintptr_t)host->base + MMC_CTYPE);
9731bd4fe43Sopenharmony_ci    } else {
9741bd4fe43Sopenharmony_ci        HIMCI_WRITEL(value, (uintptr_t)host->base + MMC_CTYPE);
9751bd4fe43Sopenharmony_ci    }
9761bd4fe43Sopenharmony_ci    return HDF_SUCCESS;
9771bd4fe43Sopenharmony_ci}
9781bd4fe43Sopenharmony_ci
9791bd4fe43Sopenharmony_cistatic void HimciCfgPhase(struct HimciHost *host, enum MmcBusTiming timing)
9801bd4fe43Sopenharmony_ci{
9811bd4fe43Sopenharmony_ci    uint32_t value;
9821bd4fe43Sopenharmony_ci    uint32_t phase;
9831bd4fe43Sopenharmony_ci    struct MmcDevice *dev = host->mmc->curDev;
9841bd4fe43Sopenharmony_ci
9851bd4fe43Sopenharmony_ci    if (dev->type == MMC_DEV_EMMC) {
9861bd4fe43Sopenharmony_ci        if (timing == BUS_TIMING_MMC_HS200) {
9871bd4fe43Sopenharmony_ci            phase = DRV_PHASE_135 | SMP_PHASE_0;
9881bd4fe43Sopenharmony_ci        } else if (timing == BUS_TIMING_MMC_HS) {
9891bd4fe43Sopenharmony_ci            phase = DRV_PHASE_180 | SMP_PHASE_45;
9901bd4fe43Sopenharmony_ci        } else {
9911bd4fe43Sopenharmony_ci            phase = DRV_PHASE_180 | SMP_PHASE_0;
9921bd4fe43Sopenharmony_ci        }
9931bd4fe43Sopenharmony_ci    } else {
9941bd4fe43Sopenharmony_ci        if (timing == BUS_TIMING_UHS_SDR104) {
9951bd4fe43Sopenharmony_ci            phase = DRV_PHASE_135 | SMP_PHASE_0;
9961bd4fe43Sopenharmony_ci        } else if (timing == BUS_TIMING_UHS_SDR50) {
9971bd4fe43Sopenharmony_ci            phase = DRV_PHASE_90 | SMP_PHASE_0;
9981bd4fe43Sopenharmony_ci        } else if (timing == BUS_TIMING_UHS_SDR25) {
9991bd4fe43Sopenharmony_ci            phase = DRV_PHASE_180 | SMP_PHASE_45;
10001bd4fe43Sopenharmony_ci        } else if (timing == BUS_TIMING_SD_HS) {
10011bd4fe43Sopenharmony_ci            phase = DRV_PHASE_135 | SMP_PHASE_45;
10021bd4fe43Sopenharmony_ci        } else {
10031bd4fe43Sopenharmony_ci            phase = DRV_PHASE_180 | SMP_PHASE_0;
10041bd4fe43Sopenharmony_ci        }
10051bd4fe43Sopenharmony_ci    }
10061bd4fe43Sopenharmony_ci    value = HIMCI_READL((uintptr_t)host->base + MMC_UHS_REG_EXT);
10071bd4fe43Sopenharmony_ci    value &= ~CLK_SMPL_PHS_MASK;
10081bd4fe43Sopenharmony_ci    value &= ~CLK_DRV_PHS_MASK;
10091bd4fe43Sopenharmony_ci    value |= phase;
10101bd4fe43Sopenharmony_ci    HIMCI_WRITEL(value, (uintptr_t)host->base + MMC_UHS_REG_EXT);
10111bd4fe43Sopenharmony_ci}
10121bd4fe43Sopenharmony_ci
10131bd4fe43Sopenharmony_cistatic int32_t HimciSetBusTiming(struct MmcCntlr *cntlr, enum MmcBusTiming timing)
10141bd4fe43Sopenharmony_ci{
10151bd4fe43Sopenharmony_ci    struct HimciHost *host = NULL;
10161bd4fe43Sopenharmony_ci    uint32_t value;
10171bd4fe43Sopenharmony_ci
10181bd4fe43Sopenharmony_ci    if ((cntlr == NULL) || (cntlr->priv == NULL)) {
10191bd4fe43Sopenharmony_ci        return HDF_ERR_INVALID_OBJECT;
10201bd4fe43Sopenharmony_ci    }
10211bd4fe43Sopenharmony_ci
10221bd4fe43Sopenharmony_ci    host = (struct HimciHost *)cntlr->priv;
10231bd4fe43Sopenharmony_ci    value = HIMCI_READL((uintptr_t)host->base + MMC_UHS_REG);
10241bd4fe43Sopenharmony_ci    /* speed mode check ,if it is DDR50 set DDR mode */
10251bd4fe43Sopenharmony_ci    if (timing == BUS_TIMING_UHS_DDR50) {
10261bd4fe43Sopenharmony_ci        if ((value & HI_SDXC_CTRL_DDR_REG) == 0) {
10271bd4fe43Sopenharmony_ci            value |= HI_SDXC_CTRL_DDR_REG;
10281bd4fe43Sopenharmony_ci        }
10291bd4fe43Sopenharmony_ci    } else {
10301bd4fe43Sopenharmony_ci        if ((value & HI_SDXC_CTRL_DDR_REG) > 0) {
10311bd4fe43Sopenharmony_ci            value &= (~HI_SDXC_CTRL_DDR_REG);
10321bd4fe43Sopenharmony_ci        }
10331bd4fe43Sopenharmony_ci    }
10341bd4fe43Sopenharmony_ci    HIMCI_WRITEL(value, (uintptr_t)host->base + MMC_UHS_REG);
10351bd4fe43Sopenharmony_ci    HimciCfgPhase(host, timing);
10361bd4fe43Sopenharmony_ci    return HDF_SUCCESS;
10371bd4fe43Sopenharmony_ci}
10381bd4fe43Sopenharmony_ci
10391bd4fe43Sopenharmony_cistatic int32_t HimciSetSdioIrq(struct MmcCntlr *cntlr, bool enable)
10401bd4fe43Sopenharmony_ci{
10411bd4fe43Sopenharmony_ci    struct HimciHost *host = NULL;
10421bd4fe43Sopenharmony_ci    uint32_t value;
10431bd4fe43Sopenharmony_ci    unsigned long flags = 0;
10441bd4fe43Sopenharmony_ci
10451bd4fe43Sopenharmony_ci    if ((cntlr == NULL) || (cntlr->priv == NULL)) {
10461bd4fe43Sopenharmony_ci        return HDF_ERR_INVALID_OBJECT;
10471bd4fe43Sopenharmony_ci    }
10481bd4fe43Sopenharmony_ci
10491bd4fe43Sopenharmony_ci    host = (struct HimciHost *)cntlr->priv;
10501bd4fe43Sopenharmony_ci    HIMCI_IRQ_LOCK(&flags);
10511bd4fe43Sopenharmony_ci    value = HIMCI_READL((uintptr_t)host->base + MMC_INTMASK);
10521bd4fe43Sopenharmony_ci    if (enable == true) {
10531bd4fe43Sopenharmony_ci        value |= SDIO_INT_MASK;
10541bd4fe43Sopenharmony_ci    } else {
10551bd4fe43Sopenharmony_ci        value &= (~SDIO_INT_MASK);
10561bd4fe43Sopenharmony_ci    }
10571bd4fe43Sopenharmony_ci    HIMCI_WRITEL(value, (uintptr_t)host->base + MMC_INTMASK);
10581bd4fe43Sopenharmony_ci    HIMCI_IRQ_UNLOCK(flags);
10591bd4fe43Sopenharmony_ci    return HDF_SUCCESS;
10601bd4fe43Sopenharmony_ci}
10611bd4fe43Sopenharmony_ci
10621bd4fe43Sopenharmony_cistatic int32_t HimciHardwareReset(struct MmcCntlr *cntlr)
10631bd4fe43Sopenharmony_ci{
10641bd4fe43Sopenharmony_ci    uint32_t val;
10651bd4fe43Sopenharmony_ci    struct HimciHost *host = NULL;
10661bd4fe43Sopenharmony_ci
10671bd4fe43Sopenharmony_ci    if ((cntlr == NULL) || (cntlr->priv == NULL)) {
10681bd4fe43Sopenharmony_ci        return HDF_ERR_INVALID_OBJECT;
10691bd4fe43Sopenharmony_ci    }
10701bd4fe43Sopenharmony_ci
10711bd4fe43Sopenharmony_ci    host = (struct HimciHost *)cntlr->priv;
10721bd4fe43Sopenharmony_ci    val = HIMCI_READL((uintptr_t)host->base + MMC_CARD_RSTN);
10731bd4fe43Sopenharmony_ci    val &= (~CARD_RESET);
10741bd4fe43Sopenharmony_ci    HIMCI_WRITEL(val, (uintptr_t)host->base + MMC_CARD_RSTN);
10751bd4fe43Sopenharmony_ci
10761bd4fe43Sopenharmony_ci    /* For eMMC, minimum is 1us but give it 10us for good measure */
10771bd4fe43Sopenharmony_ci    OsalUDelay(10);
10781bd4fe43Sopenharmony_ci    val = HIMCI_READL((uintptr_t)host->base + MMC_CARD_RSTN);
10791bd4fe43Sopenharmony_ci    val |= CARD_RESET;
10801bd4fe43Sopenharmony_ci    HIMCI_WRITEL(val, (uintptr_t)host->base + MMC_CARD_RSTN);
10811bd4fe43Sopenharmony_ci    OsalUDelay(300);
10821bd4fe43Sopenharmony_ci    return HDF_SUCCESS;
10831bd4fe43Sopenharmony_ci}
10841bd4fe43Sopenharmony_ci
10851bd4fe43Sopenharmony_cistatic int32_t HimciSetEnhanceStrobe(struct MmcCntlr *cntlr, bool enable)
10861bd4fe43Sopenharmony_ci{
10871bd4fe43Sopenharmony_ci    (void)cntlr;
10881bd4fe43Sopenharmony_ci    (void)enable;
10891bd4fe43Sopenharmony_ci    return HDF_SUCCESS;
10901bd4fe43Sopenharmony_ci}
10911bd4fe43Sopenharmony_ci
10921bd4fe43Sopenharmony_cistatic int32_t HimciVoltageSwitchTo3v3(struct MmcCntlr *cntlr, struct HimciHost *host)
10931bd4fe43Sopenharmony_ci{
10941bd4fe43Sopenharmony_ci    uint32_t ctrl;
10951bd4fe43Sopenharmony_ci
10961bd4fe43Sopenharmony_ci    HIMCI_CLEARL(host, MMC_UHS_REG, HI_SDXC_CTRL_VDD_180);
10971bd4fe43Sopenharmony_ci    OsalMSleep(10);
10981bd4fe43Sopenharmony_ci    ctrl = HIMCI_READL((uintptr_t)host->base + MMC_UHS_REG);
10991bd4fe43Sopenharmony_ci    if ((ctrl & HI_SDXC_CTRL_VDD_180) > 0) {
11001bd4fe43Sopenharmony_ci        HDF_LOGE("host%u: Switching to 3.3V failed\n", host->id);
11011bd4fe43Sopenharmony_ci        return HDF_ERR_IO;
11021bd4fe43Sopenharmony_ci    }
11031bd4fe43Sopenharmony_ci    HimciSetDrvCap(cntlr);
11041bd4fe43Sopenharmony_ci    return HDF_SUCCESS;
11051bd4fe43Sopenharmony_ci}
11061bd4fe43Sopenharmony_ci
11071bd4fe43Sopenharmony_cistatic int32_t HimciVoltageSwitchTo1v8(struct MmcCntlr *cntlr, struct HimciHost *host)
11081bd4fe43Sopenharmony_ci{
11091bd4fe43Sopenharmony_ci    uint32_t ctrl;
11101bd4fe43Sopenharmony_ci
11111bd4fe43Sopenharmony_ci    ctrl = HIMCI_READL((uintptr_t)host->base + MMC_UHS_REG);
11121bd4fe43Sopenharmony_ci    if ((ctrl & HI_SDXC_CTRL_VDD_180) > 0) {
11131bd4fe43Sopenharmony_ci        return HDF_SUCCESS;
11141bd4fe43Sopenharmony_ci    }
11151bd4fe43Sopenharmony_ci
11161bd4fe43Sopenharmony_ci    HimciControlClock(host, false);
11171bd4fe43Sopenharmony_ci    HIMCI_SETL(host, MMC_UHS_REG, HI_SDXC_CTRL_VDD_180);
11181bd4fe43Sopenharmony_ci    OsalMSleep(10);
11191bd4fe43Sopenharmony_ci    ctrl = HIMCI_READL((uintptr_t)host->base + MMC_UHS_REG);
11201bd4fe43Sopenharmony_ci    if ((ctrl & HI_SDXC_CTRL_VDD_180) > 0) {
11211bd4fe43Sopenharmony_ci        HimciControlClock(host, true);
11221bd4fe43Sopenharmony_ci        OsalMSleep(10);
11231bd4fe43Sopenharmony_ci        if (host->mmc->caps2.bits.hs200Sdr1v8 || host->mmc->caps2.bits.hs200Sdr1v2) {
11241bd4fe43Sopenharmony_ci            /* emmc needn't to check the int status. */
11251bd4fe43Sopenharmony_ci            return HDF_SUCCESS;
11261bd4fe43Sopenharmony_ci        }
11271bd4fe43Sopenharmony_ci        /* If CMD11 return CMD down, then the card was successfully switched to 1.8V signaling. */
11281bd4fe43Sopenharmony_ci        ctrl = HIMCI_EVENT_WAIT(&host->himciEvent, HIMCI_PEND_DTO_M, HIMCI_VOLT_SWITCH_TIMEOUT);
11291bd4fe43Sopenharmony_ci        if ((ctrl & HIMCI_PEND_DTO_M) > 0) {
11301bd4fe43Sopenharmony_ci            /* config Pin drive capability */
11311bd4fe43Sopenharmony_ci            HimciSetDrvCap(cntlr);
11321bd4fe43Sopenharmony_ci            return HDF_SUCCESS;
11331bd4fe43Sopenharmony_ci        }
11341bd4fe43Sopenharmony_ci    }
11351bd4fe43Sopenharmony_ci
11361bd4fe43Sopenharmony_ci    ctrl &= (~HI_SDXC_CTRL_VDD_180);
11371bd4fe43Sopenharmony_ci    HIMCI_WRITEL(ctrl, (uintptr_t)host->base + MMC_UHS_REG);
11381bd4fe43Sopenharmony_ci    OsalMSleep(10);
11391bd4fe43Sopenharmony_ci    HimciControlPower(host, HOST_POWER_OFF, false);
11401bd4fe43Sopenharmony_ci    OsalMSleep(10);
11411bd4fe43Sopenharmony_ci    HimciControlPower(host, HOST_POWER_ON, false);
11421bd4fe43Sopenharmony_ci    HimciControlClock(host, false);
11431bd4fe43Sopenharmony_ci    OsalMSleep(1);
11441bd4fe43Sopenharmony_ci    HimciControlClock(host, true);
11451bd4fe43Sopenharmony_ci    ctrl = HIMCI_EVENT_WAIT(&host->himciEvent, HIMCI_PEND_DTO_M, 10);
11461bd4fe43Sopenharmony_ci    if ((ctrl & HIMCI_PEND_DTO_M) > 0) {
11471bd4fe43Sopenharmony_ci        /* config Pin drive capability */
11481bd4fe43Sopenharmony_ci        HimciSetDrvCap(cntlr);
11491bd4fe43Sopenharmony_ci        return HDF_SUCCESS;
11501bd4fe43Sopenharmony_ci    }
11511bd4fe43Sopenharmony_ci
11521bd4fe43Sopenharmony_ci    HDF_LOGD("Switching to 1.8V failed, retrying with S18R set to 0.");
11531bd4fe43Sopenharmony_ci    return HDF_FAILURE;
11541bd4fe43Sopenharmony_ci}
11551bd4fe43Sopenharmony_ci
11561bd4fe43Sopenharmony_cistatic int32_t HimciSwitchVoltage(struct MmcCntlr *cntlr, enum MmcVolt volt)
11571bd4fe43Sopenharmony_ci{
11581bd4fe43Sopenharmony_ci    struct HimciHost *host = NULL;
11591bd4fe43Sopenharmony_ci
11601bd4fe43Sopenharmony_ci    if ((cntlr == NULL) || (cntlr->priv == NULL)) {
11611bd4fe43Sopenharmony_ci        return HDF_ERR_INVALID_OBJECT;
11621bd4fe43Sopenharmony_ci    }
11631bd4fe43Sopenharmony_ci
11641bd4fe43Sopenharmony_ci    host = (struct HimciHost *)cntlr->priv;
11651bd4fe43Sopenharmony_ci    if (volt == VOLT_3V3) {
11661bd4fe43Sopenharmony_ci        return HimciVoltageSwitchTo3v3(cntlr, host);
11671bd4fe43Sopenharmony_ci    } else if (volt == VOLT_1V8) {
11681bd4fe43Sopenharmony_ci        return HimciVoltageSwitchTo1v8(cntlr, host);
11691bd4fe43Sopenharmony_ci    }
11701bd4fe43Sopenharmony_ci    return HDF_SUCCESS;
11711bd4fe43Sopenharmony_ci}
11721bd4fe43Sopenharmony_ci
11731bd4fe43Sopenharmony_cistatic bool HimciDevReadOnly(struct MmcCntlr *cntlr)
11741bd4fe43Sopenharmony_ci{
11751bd4fe43Sopenharmony_ci    struct HimciHost *host = NULL;
11761bd4fe43Sopenharmony_ci    uint32_t val;
11771bd4fe43Sopenharmony_ci
11781bd4fe43Sopenharmony_ci    if ((cntlr == NULL) || (cntlr->priv == NULL)) {
11791bd4fe43Sopenharmony_ci        return false;
11801bd4fe43Sopenharmony_ci    }
11811bd4fe43Sopenharmony_ci
11821bd4fe43Sopenharmony_ci    host = (struct HimciHost *)cntlr->priv;
11831bd4fe43Sopenharmony_ci    val = HIMCI_READL((uintptr_t)host->base + MMC_WRTPRT);
11841bd4fe43Sopenharmony_ci    if ((val & CARD_READONLY) > 0) {
11851bd4fe43Sopenharmony_ci        return true;
11861bd4fe43Sopenharmony_ci    }
11871bd4fe43Sopenharmony_ci    return false;
11881bd4fe43Sopenharmony_ci}
11891bd4fe43Sopenharmony_ci
11901bd4fe43Sopenharmony_cistatic bool HimciDevBusy(struct MmcCntlr *cntlr)
11911bd4fe43Sopenharmony_ci{
11921bd4fe43Sopenharmony_ci    (void)cntlr;
11931bd4fe43Sopenharmony_ci    return false;
11941bd4fe43Sopenharmony_ci}
11951bd4fe43Sopenharmony_ci
11961bd4fe43Sopenharmony_cistatic void HimciEdgeTuningEnable(struct HimciHost *host)
11971bd4fe43Sopenharmony_ci{
11981bd4fe43Sopenharmony_ci    uint32_t val;
11991bd4fe43Sopenharmony_ci    uint32_t regs[] = { PERI_CRG83, PERI_CRG89, PERI_CRG86 };
12001bd4fe43Sopenharmony_ci
12011bd4fe43Sopenharmony_ci    if (host->id >= MMC_CNTLR_NR_MAX) {
12021bd4fe43Sopenharmony_ci        HDF_LOGE("host%u id error", host->id);
12031bd4fe43Sopenharmony_ci        return;
12041bd4fe43Sopenharmony_ci    }
12051bd4fe43Sopenharmony_ci
12061bd4fe43Sopenharmony_ci    HIMCI_WRITEL((HIMCI_SAP_DLL_SOFT_RESET | HIMCI_SAP_DLL_DEVICE_DELAY_ENABLE), regs[host->id]);
12071bd4fe43Sopenharmony_ci
12081bd4fe43Sopenharmony_ci    val = HIMCI_READL((uintptr_t)host->base + MMC_TUNING_CTRL);
12091bd4fe43Sopenharmony_ci    val |= HW_TUNING_EN;
12101bd4fe43Sopenharmony_ci    HIMCI_WRITEL(val, (uintptr_t)host->base + MMC_TUNING_CTRL);
12111bd4fe43Sopenharmony_ci}
12121bd4fe43Sopenharmony_ci
12131bd4fe43Sopenharmony_cistatic void HimciSetSapPhase(struct HimciHost *host, uint32_t phase)
12141bd4fe43Sopenharmony_ci{
12151bd4fe43Sopenharmony_ci    uint32_t val;
12161bd4fe43Sopenharmony_ci
12171bd4fe43Sopenharmony_ci    val = HIMCI_READL((uintptr_t)host->base + MMC_UHS_REG_EXT);
12181bd4fe43Sopenharmony_ci    val &= ~CLK_SMPL_PHS_MASK;
12191bd4fe43Sopenharmony_ci    val |= (phase << CLK_SMPL_PHS_OFFSET);
12201bd4fe43Sopenharmony_ci    HIMCI_WRITEL(val, (uintptr_t)host->base + MMC_UHS_REG_EXT);
12211bd4fe43Sopenharmony_ci}
12221bd4fe43Sopenharmony_ci
12231bd4fe43Sopenharmony_cistatic void HimciEdgeTuningDisable(struct HimciHost *host)
12241bd4fe43Sopenharmony_ci{
12251bd4fe43Sopenharmony_ci    uint32_t val;
12261bd4fe43Sopenharmony_ci    uint32_t regs[] = { PERI_CRG83, PERI_CRG89, PERI_CRG86 };
12271bd4fe43Sopenharmony_ci
12281bd4fe43Sopenharmony_ci    if (host->id >= MMC_CNTLR_NR_MAX) {
12291bd4fe43Sopenharmony_ci        HDF_LOGE("host%u id error", host->id);
12301bd4fe43Sopenharmony_ci        return;
12311bd4fe43Sopenharmony_ci    }
12321bd4fe43Sopenharmony_ci
12331bd4fe43Sopenharmony_ci    val = HIMCI_READL(regs[host->id]);
12341bd4fe43Sopenharmony_ci    val |= HIMCI_SAP_DLL_MODE_DLLSSEL;
12351bd4fe43Sopenharmony_ci    HIMCI_WRITEL(val, regs[host->id]);
12361bd4fe43Sopenharmony_ci
12371bd4fe43Sopenharmony_ci    val = HIMCI_READL((uintptr_t)host->base + MMC_TUNING_CTRL);
12381bd4fe43Sopenharmony_ci    val &= ~HW_TUNING_EN;
12391bd4fe43Sopenharmony_ci    HIMCI_WRITEL(val, (uintptr_t)host->base + MMC_TUNING_CTRL);
12401bd4fe43Sopenharmony_ci}
12411bd4fe43Sopenharmony_ci
12421bd4fe43Sopenharmony_cistatic int32_t HimciSendTuning(struct MmcCntlr *cntlr, uint32_t opcode)
12431bd4fe43Sopenharmony_ci{
12441bd4fe43Sopenharmony_ci    int32_t err;
12451bd4fe43Sopenharmony_ci    uint32_t result;
12461bd4fe43Sopenharmony_ci    struct HimciHost *host = (struct HimciHost *)cntlr->priv;
12471bd4fe43Sopenharmony_ci
12481bd4fe43Sopenharmony_ci    (void)OsalMutexLock(&host->mutex);
12491bd4fe43Sopenharmony_ci    HimciControlClock(host, false);
12501bd4fe43Sopenharmony_ci    HimciDmaReset(host);
12511bd4fe43Sopenharmony_ci    HimciControlClock(host, true);
12521bd4fe43Sopenharmony_ci    (void)OsalMutexUnlock(&host->mutex);
12531bd4fe43Sopenharmony_ci
12541bd4fe43Sopenharmony_ci    err = MmcSendTuning(cntlr, opcode, true);
12551bd4fe43Sopenharmony_ci    (void)MmcStopTransmission(cntlr, true, &result);
12561bd4fe43Sopenharmony_ci    (void)MmcSendStatus(cntlr, &result);
12571bd4fe43Sopenharmony_ci    return err;
12581bd4fe43Sopenharmony_ci}
12591bd4fe43Sopenharmony_ci
12601bd4fe43Sopenharmony_cistatic void HimciSysReset(struct HimciHost *host)
12611bd4fe43Sopenharmony_ci{
12621bd4fe43Sopenharmony_ci    uint32_t value;
12631bd4fe43Sopenharmony_ci
12641bd4fe43Sopenharmony_ci    value = HIMCI_READL((uintptr_t)host->base + MMC_BMOD);
12651bd4fe43Sopenharmony_ci    value |= BMOD_SWR;
12661bd4fe43Sopenharmony_ci    HIMCI_WRITEL(value, (uintptr_t)host->base + MMC_BMOD);
12671bd4fe43Sopenharmony_ci    OsalUDelay(10);
12681bd4fe43Sopenharmony_ci
12691bd4fe43Sopenharmony_ci    value = HIMCI_READL((uintptr_t)host->base + MMC_BMOD);
12701bd4fe43Sopenharmony_ci    value |= (BURST_INCR | BURST_16);
12711bd4fe43Sopenharmony_ci    HIMCI_WRITEL(value, (uintptr_t)host->base + MMC_BMOD);
12721bd4fe43Sopenharmony_ci
12731bd4fe43Sopenharmony_ci    value = HIMCI_READL((uintptr_t)host->base + MMC_CTRL);
12741bd4fe43Sopenharmony_ci    value |=  (CTRL_RESET | FIFO_RESET | DMA_RESET);
12751bd4fe43Sopenharmony_ci    HIMCI_WRITEL(value, (uintptr_t)host->base + MMC_CTRL);
12761bd4fe43Sopenharmony_ci}
12771bd4fe43Sopenharmony_ci
12781bd4fe43Sopenharmony_cistatic void HimciTuningFeedback(struct MmcCntlr *cntlr)
12791bd4fe43Sopenharmony_ci{
12801bd4fe43Sopenharmony_ci    struct HimciHost *host = (struct HimciHost *)cntlr->priv;
12811bd4fe43Sopenharmony_ci
12821bd4fe43Sopenharmony_ci    (void)OsalMutexLock(&host->mutex);
12831bd4fe43Sopenharmony_ci    HimciControlClock(host, false);
12841bd4fe43Sopenharmony_ci    OsalMDelay(1);
12851bd4fe43Sopenharmony_ci    HimciSysReset(host);
12861bd4fe43Sopenharmony_ci    OsalMDelay(1);
12871bd4fe43Sopenharmony_ci    HIMCI_WRITEL(ALL_INT_CLR, (uintptr_t)host->base + MMC_RINTSTS);
12881bd4fe43Sopenharmony_ci    HimciControlClock(host, true);
12891bd4fe43Sopenharmony_ci    OsalMDelay(1);
12901bd4fe43Sopenharmony_ci    (void)OsalMutexUnlock(&host->mutex);
12911bd4fe43Sopenharmony_ci}
12921bd4fe43Sopenharmony_ci
12931bd4fe43Sopenharmony_cistatic uint32_t HimciGetSapDllTaps(struct HimciHost *host)
12941bd4fe43Sopenharmony_ci{
12951bd4fe43Sopenharmony_ci    uint32_t val;
12961bd4fe43Sopenharmony_ci    uint32_t regs[] = { PERI_CRG84, PERI_CRG90, PERI_CRG87 };
12971bd4fe43Sopenharmony_ci
12981bd4fe43Sopenharmony_ci    if (host->id >= MMC_CNTLR_NR_MAX) {
12991bd4fe43Sopenharmony_ci        HDF_LOGE("host%u id error", host->id);
13001bd4fe43Sopenharmony_ci        return 0;
13011bd4fe43Sopenharmony_ci    }
13021bd4fe43Sopenharmony_ci
13031bd4fe43Sopenharmony_ci    val = HIMCI_READL(regs[host->id]);
13041bd4fe43Sopenharmony_ci    return (val & 0xff);
13051bd4fe43Sopenharmony_ci}
13061bd4fe43Sopenharmony_ci
13071bd4fe43Sopenharmony_cistatic void HimciSetDllElement(struct HimciHost *host, uint32_t element)
13081bd4fe43Sopenharmony_ci{
13091bd4fe43Sopenharmony_ci    uint32_t val;
13101bd4fe43Sopenharmony_ci    uint32_t regs[] = { PERI_CRG83, PERI_CRG89, PERI_CRG86 };
13111bd4fe43Sopenharmony_ci
13121bd4fe43Sopenharmony_ci    if (host->id >= MMC_CNTLR_NR_MAX) {
13131bd4fe43Sopenharmony_ci        HDF_LOGE("host%u id error", host->id);
13141bd4fe43Sopenharmony_ci        return;
13151bd4fe43Sopenharmony_ci    }
13161bd4fe43Sopenharmony_ci
13171bd4fe43Sopenharmony_ci    val = HIMCI_READL(regs[host->id]);
13181bd4fe43Sopenharmony_ci    val &= ~(0xFF << HIMCI_SAP_DLL_ELEMENT_SHIFT);
13191bd4fe43Sopenharmony_ci    val |= (element << HIMCI_SAP_DLL_ELEMENT_SHIFT);
13201bd4fe43Sopenharmony_ci    HIMCI_WRITEL(val, regs[host->id]);
13211bd4fe43Sopenharmony_ci}
13221bd4fe43Sopenharmony_ci
13231bd4fe43Sopenharmony_cistatic void HimciEdgedllModeATuning(struct HimciHost *host, struct HimciTuneParam *param,
13241bd4fe43Sopenharmony_ci    uint32_t phaseDllElements)
13251bd4fe43Sopenharmony_ci{
13261bd4fe43Sopenharmony_ci    uint32_t index, ele, phaseOffset;
13271bd4fe43Sopenharmony_ci    int32_t prevErr = HDF_SUCCESS;
13281bd4fe43Sopenharmony_ci    int32_t err;
13291bd4fe43Sopenharmony_ci
13301bd4fe43Sopenharmony_ci    if (host == NULL || param == NULL) {
13311bd4fe43Sopenharmony_ci        return;
13321bd4fe43Sopenharmony_ci    }
13331bd4fe43Sopenharmony_ci
13341bd4fe43Sopenharmony_ci    phaseOffset = param->edgeP2f * phaseDllElements;
13351bd4fe43Sopenharmony_ci    for (index = param->edgeP2f; index < param->edgeF2p; index++) {
13361bd4fe43Sopenharmony_ci        HimciSetSapPhase(host, index);
13371bd4fe43Sopenharmony_ci        for (ele = HIMCI_PHASE_DLL_START_ELEMENT; ele <= phaseDllElements; ele++) {
13381bd4fe43Sopenharmony_ci            HimciSetDllElement(host, ele);
13391bd4fe43Sopenharmony_ci            err = HimciSendTuning(host->mmc, param->cmdCode);
13401bd4fe43Sopenharmony_ci            if (prevErr == HDF_SUCCESS && err != HDF_SUCCESS && (param->endp == param->endpInit)) {
13411bd4fe43Sopenharmony_ci                param->endp = phaseOffset + ele;
13421bd4fe43Sopenharmony_ci            }
13431bd4fe43Sopenharmony_ci
13441bd4fe43Sopenharmony_ci            if (err != HDF_SUCCESS) {
13451bd4fe43Sopenharmony_ci                param->startp = phaseOffset + ele;
13461bd4fe43Sopenharmony_ci            }
13471bd4fe43Sopenharmony_ci            prevErr = err;
13481bd4fe43Sopenharmony_ci            err = HDF_SUCCESS;
13491bd4fe43Sopenharmony_ci        }
13501bd4fe43Sopenharmony_ci        phaseOffset += phaseDllElements;
13511bd4fe43Sopenharmony_ci    }
13521bd4fe43Sopenharmony_ci}
13531bd4fe43Sopenharmony_ci
13541bd4fe43Sopenharmony_cistatic void HimciEdgedllModeBTuning(struct HimciHost *host, struct HimciTuneParam *param,
13551bd4fe43Sopenharmony_ci    uint32_t phaseDllElements)
13561bd4fe43Sopenharmony_ci{
13571bd4fe43Sopenharmony_ci    uint32_t index, ele, phaseOffset;
13581bd4fe43Sopenharmony_ci    int32_t prevErr = HDF_SUCCESS;
13591bd4fe43Sopenharmony_ci    int32_t err;
13601bd4fe43Sopenharmony_ci
13611bd4fe43Sopenharmony_ci    if (host == NULL || param == NULL) {
13621bd4fe43Sopenharmony_ci        return;
13631bd4fe43Sopenharmony_ci    }
13641bd4fe43Sopenharmony_ci
13651bd4fe43Sopenharmony_ci    phaseOffset = param->edgeP2f * phaseDllElements;
13661bd4fe43Sopenharmony_ci    for (index = param->edgeP2f; index < HIMCI_PHASE_SCALE; index++) {
13671bd4fe43Sopenharmony_ci        HimciSetSapPhase(host, index);
13681bd4fe43Sopenharmony_ci        for (ele = HIMCI_PHASE_DLL_START_ELEMENT; ele <= phaseDllElements; ele++) {
13691bd4fe43Sopenharmony_ci            HimciSetDllElement(host, ele);
13701bd4fe43Sopenharmony_ci            err = HimciSendTuning(host->mmc, param->cmdCode);
13711bd4fe43Sopenharmony_ci            if (prevErr == HDF_SUCCESS && err != HDF_SUCCESS && (param->endp == param->endpInit)) {
13721bd4fe43Sopenharmony_ci                param->endp = phaseOffset + ele;
13731bd4fe43Sopenharmony_ci            }
13741bd4fe43Sopenharmony_ci            if (err != HDF_SUCCESS) {
13751bd4fe43Sopenharmony_ci                param->startp = phaseOffset + ele;
13761bd4fe43Sopenharmony_ci            }
13771bd4fe43Sopenharmony_ci            prevErr = err;
13781bd4fe43Sopenharmony_ci            err = HDF_SUCCESS;
13791bd4fe43Sopenharmony_ci        }
13801bd4fe43Sopenharmony_ci        phaseOffset += phaseDllElements;
13811bd4fe43Sopenharmony_ci    }
13821bd4fe43Sopenharmony_ci
13831bd4fe43Sopenharmony_ci    phaseOffset = 0;
13841bd4fe43Sopenharmony_ci    for (index = 0; index < param->edgeF2p; index++) {
13851bd4fe43Sopenharmony_ci        HimciSetSapPhase(host, index);
13861bd4fe43Sopenharmony_ci        for (ele = HIMCI_PHASE_DLL_START_ELEMENT; ele <= phaseDllElements; ele++) {
13871bd4fe43Sopenharmony_ci            HimciSetDllElement(host, ele);
13881bd4fe43Sopenharmony_ci            err = HimciSendTuning(host->mmc, param->cmdCode);
13891bd4fe43Sopenharmony_ci            if (prevErr == HDF_SUCCESS && err != HDF_SUCCESS && (param->endp == param->endpInit)) {
13901bd4fe43Sopenharmony_ci                param->endp = phaseOffset + ele;
13911bd4fe43Sopenharmony_ci            }
13921bd4fe43Sopenharmony_ci            if (err != HDF_SUCCESS) {
13931bd4fe43Sopenharmony_ci                param->startp = phaseOffset + ele;
13941bd4fe43Sopenharmony_ci            }
13951bd4fe43Sopenharmony_ci            prevErr = err;
13961bd4fe43Sopenharmony_ci            err = HDF_SUCCESS;
13971bd4fe43Sopenharmony_ci        }
13981bd4fe43Sopenharmony_ci        phaseOffset += phaseDllElements;
13991bd4fe43Sopenharmony_ci    }
14001bd4fe43Sopenharmony_ci}
14011bd4fe43Sopenharmony_ci
14021bd4fe43Sopenharmony_cistatic int32_t HimciEdgedllModeTuning(struct HimciHost *host,
14031bd4fe43Sopenharmony_ci    uint32_t cmdCode, uint32_t edgeP2f, uint32_t edgeF2p)
14041bd4fe43Sopenharmony_ci{
14051bd4fe43Sopenharmony_ci    uint32_t index, ele, phaseOffset, totalPhases, phaseDllElements;
14061bd4fe43Sopenharmony_ci    struct HimciTuneParam param = {0};
14071bd4fe43Sopenharmony_ci
14081bd4fe43Sopenharmony_ci    phaseDllElements = HimciGetSapDllTaps(host) / HIMCI_PHASE_SCALE;
14091bd4fe43Sopenharmony_ci    totalPhases = phaseDllElements * HIMCI_PHASE_SCALE;
14101bd4fe43Sopenharmony_ci    /*
14111bd4fe43Sopenharmony_ci     *  EdgeMode A:
14121bd4fe43Sopenharmony_ci     * |<---- totalphases(ele) ---->|
14131bd4fe43Sopenharmony_ci     *       _____________
14141bd4fe43Sopenharmony_ci     * ______|||||||||||||||_______
14151bd4fe43Sopenharmony_ci     * edge_p2f       edge_f2p
14161bd4fe43Sopenharmony_ci     * (endp)         (startp)
14171bd4fe43Sopenharmony_ci     *
14181bd4fe43Sopenharmony_ci     * EdgeMode B:
14191bd4fe43Sopenharmony_ci     * |<---- totalphases(ele) ---->|
14201bd4fe43Sopenharmony_ci     * ________           _________
14211bd4fe43Sopenharmony_ci     * ||||||||||_________|||||||||||
14221bd4fe43Sopenharmony_ci     * edge_f2p     edge_p2f
14231bd4fe43Sopenharmony_ci     * (startp)     (endp)
14241bd4fe43Sopenharmony_ci     *
14251bd4fe43Sopenharmony_ci     * BestPhase:
14261bd4fe43Sopenharmony_ci     * if(endp < startp)
14271bd4fe43Sopenharmony_ci     * endp = endp + totalphases;
14281bd4fe43Sopenharmony_ci     * Best = ((startp + endp) / 2) % totalphases
14291bd4fe43Sopenharmony_ci     */
14301bd4fe43Sopenharmony_ci    param.cmdCode = cmdCode;
14311bd4fe43Sopenharmony_ci    param.edgeF2p = edgeF2p;
14321bd4fe43Sopenharmony_ci    param.edgeP2f = edgeP2f;
14331bd4fe43Sopenharmony_ci    param.endpInit = edgeP2f * phaseDllElements;
14341bd4fe43Sopenharmony_ci    param.startp = edgeF2p * phaseDllElements;
14351bd4fe43Sopenharmony_ci    param.endp = param.endpInit;
14361bd4fe43Sopenharmony_ci    if (edgeF2p >= edgeP2f) {
14371bd4fe43Sopenharmony_ci        HimciEdgedllModeATuning(host, &param, phaseDllElements);
14381bd4fe43Sopenharmony_ci    } else {
14391bd4fe43Sopenharmony_ci        HimciEdgedllModeBTuning(host, &param, phaseDllElements);
14401bd4fe43Sopenharmony_ci    }
14411bd4fe43Sopenharmony_ci
14421bd4fe43Sopenharmony_ci    if (param.endp <= param.startp) {
14431bd4fe43Sopenharmony_ci        param.endp += totalPhases;
14441bd4fe43Sopenharmony_ci    }
14451bd4fe43Sopenharmony_ci    if (totalPhases == 0) {
14461bd4fe43Sopenharmony_ci        HDF_LOGE("host%u:total phases is zero.", host->id);
14471bd4fe43Sopenharmony_ci        return HDF_FAILURE;
14481bd4fe43Sopenharmony_ci    }
14491bd4fe43Sopenharmony_ci    phaseOffset = ((param.startp + param.endp) / 2) % totalPhases;
14501bd4fe43Sopenharmony_ci    index = (phaseOffset / phaseDllElements);
14511bd4fe43Sopenharmony_ci    ele = (phaseOffset % phaseDllElements);
14521bd4fe43Sopenharmony_ci    ele = ((ele > HIMCI_PHASE_DLL_START_ELEMENT) ? ele : HIMCI_PHASE_DLL_START_ELEMENT);
14531bd4fe43Sopenharmony_ci    HimciSetSapPhase(host, index);
14541bd4fe43Sopenharmony_ci    HimciSetDllElement(host, ele);
14551bd4fe43Sopenharmony_ci    HIMCI_WRITEL(ALL_INT_CLR, (uintptr_t)host->base + MMC_RINTSTS);
14561bd4fe43Sopenharmony_ci    return HDF_SUCCESS;
14571bd4fe43Sopenharmony_ci}
14581bd4fe43Sopenharmony_ci
14591bd4fe43Sopenharmony_cistatic int32_t HimciTune(struct MmcCntlr *cntlr, uint32_t cmdCode)
14601bd4fe43Sopenharmony_ci{
14611bd4fe43Sopenharmony_ci    struct HimciHost *host = NULL;
14621bd4fe43Sopenharmony_ci    uint32_t index, val;
14631bd4fe43Sopenharmony_ci    bool found = false;
14641bd4fe43Sopenharmony_ci    bool prevFound = false;
14651bd4fe43Sopenharmony_ci    uint32_t edgeP2f = 0;
14661bd4fe43Sopenharmony_ci    uint32_t phaseNum = HIMCI_PHASE_SCALE;
14671bd4fe43Sopenharmony_ci    uint32_t edgeF2p = HIMCI_PHASE_SCALE;
14681bd4fe43Sopenharmony_ci    int32_t err;
14691bd4fe43Sopenharmony_ci
14701bd4fe43Sopenharmony_ci    if ((cntlr == NULL) || (cntlr->priv == NULL)) {
14711bd4fe43Sopenharmony_ci        return HDF_ERR_INVALID_OBJECT;
14721bd4fe43Sopenharmony_ci    }
14731bd4fe43Sopenharmony_ci
14741bd4fe43Sopenharmony_ci    host = (struct HimciHost *)cntlr->priv;
14751bd4fe43Sopenharmony_ci    host->isTuning = true;
14761bd4fe43Sopenharmony_ci    HimciEdgeTuningEnable(host);
14771bd4fe43Sopenharmony_ci    for (index = 0; index < HIMCI_PHASE_SCALE; index++) {
14781bd4fe43Sopenharmony_ci        found = true;
14791bd4fe43Sopenharmony_ci        HimciSetSapPhase(host, index);
14801bd4fe43Sopenharmony_ci        err = HimciSendTuning(cntlr, cmdCode);
14811bd4fe43Sopenharmony_ci        if (err == HDF_SUCCESS) {
14821bd4fe43Sopenharmony_ci            val = HIMCI_READL((uintptr_t)host->base + MMC_TUNING_CTRL);
14831bd4fe43Sopenharmony_ci            found = ((val & FOUND_EDGE) == FOUND_EDGE);
14841bd4fe43Sopenharmony_ci        }
14851bd4fe43Sopenharmony_ci
14861bd4fe43Sopenharmony_ci        if (prevFound == true && found == false) {
14871bd4fe43Sopenharmony_ci            edgeF2p = index;
14881bd4fe43Sopenharmony_ci        } else if (prevFound == false && found == true) {
14891bd4fe43Sopenharmony_ci            edgeP2f = index;
14901bd4fe43Sopenharmony_ci        }
14911bd4fe43Sopenharmony_ci
14921bd4fe43Sopenharmony_ci        if ((edgeP2f != 0) && (edgeF2p != phaseNum)) {
14931bd4fe43Sopenharmony_ci            break;
14941bd4fe43Sopenharmony_ci        }
14951bd4fe43Sopenharmony_ci        prevFound = found;
14961bd4fe43Sopenharmony_ci    }
14971bd4fe43Sopenharmony_ci
14981bd4fe43Sopenharmony_ci    if ((edgeP2f == 0) && (edgeF2p == phaseNum)) {
14991bd4fe43Sopenharmony_ci        host->isTuning = false;
15001bd4fe43Sopenharmony_ci        return HDF_FAILURE;
15011bd4fe43Sopenharmony_ci    }
15021bd4fe43Sopenharmony_ci
15031bd4fe43Sopenharmony_ci    index = (edgeF2p + phaseNum + edgeP2f) / 2 % phaseNum;
15041bd4fe43Sopenharmony_ci    if (edgeF2p < edgeP2f) {
15051bd4fe43Sopenharmony_ci        index = (edgeF2p + edgeP2f) / 2 % phaseNum;
15061bd4fe43Sopenharmony_ci    }
15071bd4fe43Sopenharmony_ci    HimciSetSapPhase(host, index);
15081bd4fe43Sopenharmony_ci    err = HimciSendTuning(cntlr, cmdCode);
15091bd4fe43Sopenharmony_ci    HimciEdgeTuningDisable(host);
15101bd4fe43Sopenharmony_ci
15111bd4fe43Sopenharmony_ci    err = HimciEdgedllModeTuning(host, cmdCode, edgeP2f, edgeF2p);
15121bd4fe43Sopenharmony_ci    HimciTuningFeedback(cntlr);
15131bd4fe43Sopenharmony_ci    if (err == HDF_SUCCESS) {
15141bd4fe43Sopenharmony_ci        (void)HimciSendTuning(cntlr, cmdCode);
15151bd4fe43Sopenharmony_ci    }
15161bd4fe43Sopenharmony_ci
15171bd4fe43Sopenharmony_ci    host->isTuning = false;
15181bd4fe43Sopenharmony_ci    return HDF_SUCCESS;
15191bd4fe43Sopenharmony_ci}
15201bd4fe43Sopenharmony_ci
15211bd4fe43Sopenharmony_cistatic void HimciClockCfg(uint32_t devId)
15221bd4fe43Sopenharmony_ci{
15231bd4fe43Sopenharmony_ci    uint32_t val;
15241bd4fe43Sopenharmony_ci    uint32_t regs[] = { PERI_CRG82, PERI_CRG88, PERI_CRG85 };
15251bd4fe43Sopenharmony_ci
15261bd4fe43Sopenharmony_ci    if (devId < MMC_CNTLR_NR_MAX) {
15271bd4fe43Sopenharmony_ci        val = HIMCI_READL((uintptr_t)regs[devId]);
15281bd4fe43Sopenharmony_ci        val |= HIMCI_CLK_SEL_100M;
15291bd4fe43Sopenharmony_ci        val |= HIMCI_CKEN;
15301bd4fe43Sopenharmony_ci        HIMCI_WRITEL(val, (uintptr_t)regs[devId]);
15311bd4fe43Sopenharmony_ci    }
15321bd4fe43Sopenharmony_ci}
15331bd4fe43Sopenharmony_ci
15341bd4fe43Sopenharmony_cistatic void HimciSoftReset(uint32_t devId)
15351bd4fe43Sopenharmony_ci{
15361bd4fe43Sopenharmony_ci    uint32_t regs[] = { PERI_CRG82, PERI_CRG88, PERI_CRG85 };
15371bd4fe43Sopenharmony_ci    uint32_t val;
15381bd4fe43Sopenharmony_ci
15391bd4fe43Sopenharmony_ci    if (devId < MMC_CNTLR_NR_MAX) {
15401bd4fe43Sopenharmony_ci        val = HIMCI_READL((uintptr_t)regs[devId]);
15411bd4fe43Sopenharmony_ci        OsalUDelay(1000);
15421bd4fe43Sopenharmony_ci        val |= HIMCI_RESET;
15431bd4fe43Sopenharmony_ci        HIMCI_WRITEL(val, (uintptr_t)regs[devId]);
15441bd4fe43Sopenharmony_ci        val &= ~HIMCI_RESET;
15451bd4fe43Sopenharmony_ci        HIMCI_WRITEL(val, (uintptr_t)regs[devId]);
15461bd4fe43Sopenharmony_ci    }
15471bd4fe43Sopenharmony_ci}
15481bd4fe43Sopenharmony_ci
15491bd4fe43Sopenharmony_cistatic void HimciSysCtrlInit(struct HimciHost *host)
15501bd4fe43Sopenharmony_ci{
15511bd4fe43Sopenharmony_ci    HIMCI_TASK_LOCK();
15521bd4fe43Sopenharmony_ci    HimciClockCfg(host->id);
15531bd4fe43Sopenharmony_ci    HimciSoftReset(host->id);
15541bd4fe43Sopenharmony_ci    HIMCI_TASK_UNLOCK();
15551bd4fe43Sopenharmony_ci}
15561bd4fe43Sopenharmony_ci
15571bd4fe43Sopenharmony_cistatic void HimciHostRegistersInit(struct HimciHost *host)
15581bd4fe43Sopenharmony_ci{
15591bd4fe43Sopenharmony_ci    uint32_t value;
15601bd4fe43Sopenharmony_ci
15611bd4fe43Sopenharmony_ci    HimciSysReset(host);
15621bd4fe43Sopenharmony_ci    HimciControlPower(host, HOST_POWER_OFF, true);
15631bd4fe43Sopenharmony_ci    /* host power on */
15641bd4fe43Sopenharmony_ci    HimciControlPower(host, HOST_POWER_ON, true);
15651bd4fe43Sopenharmony_ci
15661bd4fe43Sopenharmony_ci    /*
15671bd4fe43Sopenharmony_ci     * Walkaround: controller config gpio
15681bd4fe43Sopenharmony_ci     * the value of this register should be 0x80a400,
15691bd4fe43Sopenharmony_ci     * but the reset value is 0xa400.
15701bd4fe43Sopenharmony_ci     */
15711bd4fe43Sopenharmony_ci    value = HIMCI_READL((uintptr_t)host->base + MMC_GPIO);
15721bd4fe43Sopenharmony_ci    value |= DTO_FIX_ENABLE;
15731bd4fe43Sopenharmony_ci    HIMCI_WRITEL(value, (uintptr_t)host->base + MMC_GPIO);
15741bd4fe43Sopenharmony_ci
15751bd4fe43Sopenharmony_ci    value = ((DRV_PHASE_SHIFT << CLK_DRV_PHS_OFFSET)
15761bd4fe43Sopenharmony_ci           | (SMPL_PHASE_SHIFT << CLK_SMPL_PHS_OFFSET));
15771bd4fe43Sopenharmony_ci    HIMCI_WRITEL(value, (uintptr_t)host->base + MMC_UHS_REG_EXT);
15781bd4fe43Sopenharmony_ci
15791bd4fe43Sopenharmony_ci    HIMCI_WRITEL((READ_THRESHOLD_SIZE | BUSY_CLEAR_INT_ENABLE), (uintptr_t)host->base + MMC_CARDTHRCTL);
15801bd4fe43Sopenharmony_ci
15811bd4fe43Sopenharmony_ci    /* clear MMC host intr */
15821bd4fe43Sopenharmony_ci    HIMCI_WRITEL(ALL_INT_CLR, (uintptr_t)host->base + MMC_RINTSTS);
15831bd4fe43Sopenharmony_ci
15841bd4fe43Sopenharmony_ci    /*
15851bd4fe43Sopenharmony_ci     * data transfer over(DTO) interrupt comes after ACD
15861bd4fe43Sopenharmony_ci     * we'd use DTO with or without auto_cmd is enabled.
15871bd4fe43Sopenharmony_ci     */
15881bd4fe43Sopenharmony_ci    value = ALL_INT_MASK & (~(ACD_INT_STATUS | RXDR_INT_STATUS | TXDR_INT_STATUS | SDIO_INT_MASK));
15891bd4fe43Sopenharmony_ci    HIMCI_WRITEL(value, (uintptr_t)host->base + MMC_INTMASK);
15901bd4fe43Sopenharmony_ci    HIMCI_WRITEL(DEBNCE_MS, (uintptr_t)host->base + MMC_DEBNCE);
15911bd4fe43Sopenharmony_ci
15921bd4fe43Sopenharmony_ci    /* enable inner DMA mode and close intr of MMC host controler */
15931bd4fe43Sopenharmony_ci    value = HIMCI_READL((uintptr_t)host->base + MMC_CTRL);
15941bd4fe43Sopenharmony_ci    value |= USE_INTERNAL_DMA | INTR_EN;
15951bd4fe43Sopenharmony_ci    HIMCI_WRITEL(value, (uintptr_t)host->base + MMC_CTRL);
15961bd4fe43Sopenharmony_ci
15971bd4fe43Sopenharmony_ci    /* set timeout param */
15981bd4fe43Sopenharmony_ci    HIMCI_WRITEL(DATA_TIMEOUT | RESPONSE_TIMEOUT, (uintptr_t)host->base + MMC_TMOUT);
15991bd4fe43Sopenharmony_ci
16001bd4fe43Sopenharmony_ci    /* set FIFO param */
16011bd4fe43Sopenharmony_ci    value = BURST_SIZE | RX_WMARK | TX_WMARK;
16021bd4fe43Sopenharmony_ci    HIMCI_WRITEL(value, (uintptr_t)host->base + MMC_FIFOTH);
16031bd4fe43Sopenharmony_ci}
16041bd4fe43Sopenharmony_ci
16051bd4fe43Sopenharmony_cistatic int32_t HimciRescanSdioDev(struct MmcCntlr *cntlr)
16061bd4fe43Sopenharmony_ci{
16071bd4fe43Sopenharmony_ci    struct HimciHost *host = NULL;
16081bd4fe43Sopenharmony_ci
16091bd4fe43Sopenharmony_ci    if ((cntlr == NULL) || (cntlr->priv == NULL)) {
16101bd4fe43Sopenharmony_ci        return HDF_ERR_INVALID_OBJECT;
16111bd4fe43Sopenharmony_ci    }
16121bd4fe43Sopenharmony_ci
16131bd4fe43Sopenharmony_ci    host = (struct HimciHost *)cntlr->priv;
16141bd4fe43Sopenharmony_ci    if (host->waitForEvent == true) {
16151bd4fe43Sopenharmony_ci        (void)HIMCI_EVENT_SIGNAL(&host->himciEvent, HIMCI_PEND_ACCIDENT);
16161bd4fe43Sopenharmony_ci    }
16171bd4fe43Sopenharmony_ci
16181bd4fe43Sopenharmony_ci    return MmcCntlrAddSdioRescanMsgToQueue(cntlr);
16191bd4fe43Sopenharmony_ci}
16201bd4fe43Sopenharmony_ci
16211bd4fe43Sopenharmony_cistatic int32_t HimciSystemInit(struct MmcCntlr *cntlr)
16221bd4fe43Sopenharmony_ci{
16231bd4fe43Sopenharmony_ci    struct HimciHost *host = NULL;
16241bd4fe43Sopenharmony_ci
16251bd4fe43Sopenharmony_ci    if ((cntlr == NULL) || (cntlr->priv == NULL)) {
16261bd4fe43Sopenharmony_ci        return HDF_ERR_INVALID_OBJECT;
16271bd4fe43Sopenharmony_ci    }
16281bd4fe43Sopenharmony_ci
16291bd4fe43Sopenharmony_ci    host = (struct HimciHost *)cntlr->priv;
16301bd4fe43Sopenharmony_ci    HimciSysCtrlInit(host);
16311bd4fe43Sopenharmony_ci    HimciHostRegistersInit(host);
16321bd4fe43Sopenharmony_ci    return HDF_SUCCESS;
16331bd4fe43Sopenharmony_ci}
16341bd4fe43Sopenharmony_ci
16351bd4fe43Sopenharmony_cistatic struct MmcCntlrOps g_himciHostOps = {
16361bd4fe43Sopenharmony_ci    .request = HimciDoRequest,
16371bd4fe43Sopenharmony_ci    .setClock = HimciSetClock,
16381bd4fe43Sopenharmony_ci    .setPowerMode = HimciSetPowerMode,
16391bd4fe43Sopenharmony_ci    .setBusWidth = HimciSetBusWidth,
16401bd4fe43Sopenharmony_ci    .setBusTiming = HimciSetBusTiming,
16411bd4fe43Sopenharmony_ci    .setSdioIrq = HimciSetSdioIrq,
16421bd4fe43Sopenharmony_ci    .hardwareReset = HimciHardwareReset,
16431bd4fe43Sopenharmony_ci    .systemInit = HimciSystemInit,
16441bd4fe43Sopenharmony_ci    .setEnhanceStrobe = HimciSetEnhanceStrobe,
16451bd4fe43Sopenharmony_ci    .switchVoltage = HimciSwitchVoltage,
16461bd4fe43Sopenharmony_ci    .devReadOnly = HimciDevReadOnly,
16471bd4fe43Sopenharmony_ci    .devPlugged = HimciCardPlugged,
16481bd4fe43Sopenharmony_ci    .devBusy = HimciDevBusy,
16491bd4fe43Sopenharmony_ci    .tune = HimciTune,
16501bd4fe43Sopenharmony_ci    .rescanSdioDev = HimciRescanSdioDev,
16511bd4fe43Sopenharmony_ci};
16521bd4fe43Sopenharmony_ci
16531bd4fe43Sopenharmony_cistatic uint32_t HimciCmdIrq(struct HimciHost *host, uint32_t state)
16541bd4fe43Sopenharmony_ci{
16551bd4fe43Sopenharmony_ci    struct MmcCmd *cmd = host->cmd;
16561bd4fe43Sopenharmony_ci    struct MmcData *data = NULL;
16571bd4fe43Sopenharmony_ci    uint32_t writeEvent = 0;
16581bd4fe43Sopenharmony_ci    uint32_t mask;
16591bd4fe43Sopenharmony_ci    int32_t error = HDF_SUCCESS;
16601bd4fe43Sopenharmony_ci
16611bd4fe43Sopenharmony_ci    if ((state & RTO_INT_STATUS) > 0) {
16621bd4fe43Sopenharmony_ci        error = HDF_ERR_TIMEOUT;
16631bd4fe43Sopenharmony_ci    } else if ((state & (RCRC_INT_STATUS | RE_INT_STATUS)) > 0) {
16641bd4fe43Sopenharmony_ci        error = HDF_MMC_ERR_ILLEGAL_SEQ;
16651bd4fe43Sopenharmony_ci    }
16661bd4fe43Sopenharmony_ci
16671bd4fe43Sopenharmony_ci    mask = (CD_INT_STATUS | VOLT_SWITCH_INT_STATUS);
16681bd4fe43Sopenharmony_ci    if (cmd != NULL) {
16691bd4fe43Sopenharmony_ci        data = cmd->data;
16701bd4fe43Sopenharmony_ci    }
16711bd4fe43Sopenharmony_ci    if (data == NULL && (state & mask) > 0) {
16721bd4fe43Sopenharmony_ci        writeEvent = 1;
16731bd4fe43Sopenharmony_ci    }
16741bd4fe43Sopenharmony_ci
16751bd4fe43Sopenharmony_ci    /*
16761bd4fe43Sopenharmony_ci     * If there is a response timeout(RTO) error,
16771bd4fe43Sopenharmony_ci     * then the DWC_mobile_storage does not attempt any data transfer and
16781bd4fe43Sopenharmony_ci     * the "data Transfer Over" bit is never set.
16791bd4fe43Sopenharmony_ci     */
16801bd4fe43Sopenharmony_ci    mask = (CD_INT_STATUS | RTO_INT_STATUS);
16811bd4fe43Sopenharmony_ci    if ((state & mask) == mask) {
16821bd4fe43Sopenharmony_ci        writeEvent = 1;
16831bd4fe43Sopenharmony_ci    }
16841bd4fe43Sopenharmony_ci    if (cmd != NULL) {
16851bd4fe43Sopenharmony_ci        cmd->returnError = error;
16861bd4fe43Sopenharmony_ci    }
16871bd4fe43Sopenharmony_ci    return writeEvent;
16881bd4fe43Sopenharmony_ci}
16891bd4fe43Sopenharmony_ci
16901bd4fe43Sopenharmony_cistatic uint32_t HimciDataIrq(struct HimciHost *host, struct MmcData *data, uint32_t state)
16911bd4fe43Sopenharmony_ci{
16921bd4fe43Sopenharmony_ci    uint32_t writeEvent = 0;
16931bd4fe43Sopenharmony_ci
16941bd4fe43Sopenharmony_ci    if (host == NULL || data == NULL) {
16951bd4fe43Sopenharmony_ci        return writeEvent;
16961bd4fe43Sopenharmony_ci    }
16971bd4fe43Sopenharmony_ci
16981bd4fe43Sopenharmony_ci    if ((data->dataFlags & DATA_READ) == 0) {
16991bd4fe43Sopenharmony_ci        if ((state & SBE_INT_STATUS) > 0) {
17001bd4fe43Sopenharmony_ci            HimciDmaStop(host);
17011bd4fe43Sopenharmony_ci            HimciDataDone(host, state & (~SBE_INT_STATUS));
17021bd4fe43Sopenharmony_ci            writeEvent++;
17031bd4fe43Sopenharmony_ci        }
17041bd4fe43Sopenharmony_ci    } else {
17051bd4fe43Sopenharmony_ci        HimciDmaStop(host);
17061bd4fe43Sopenharmony_ci        HimciDataDone(host, state);
17071bd4fe43Sopenharmony_ci        writeEvent++;
17081bd4fe43Sopenharmony_ci    }
17091bd4fe43Sopenharmony_ci    return writeEvent;
17101bd4fe43Sopenharmony_ci}
17111bd4fe43Sopenharmony_ci
17121bd4fe43Sopenharmony_cistatic uint32_t HimciIrqHandler(uint32_t irq, void *data)
17131bd4fe43Sopenharmony_ci{
17141bd4fe43Sopenharmony_ci    struct HimciHost *host = (struct HimciHost *)data;
17151bd4fe43Sopenharmony_ci    struct MmcCmd *cmd = NULL;
17161bd4fe43Sopenharmony_ci    uint32_t writeEvent = 0;
17171bd4fe43Sopenharmony_ci    uint32_t state;
17181bd4fe43Sopenharmony_ci    (void)irq;
17191bd4fe43Sopenharmony_ci
17201bd4fe43Sopenharmony_ci    if (host == NULL) {
17211bd4fe43Sopenharmony_ci        HDF_LOGE("HimciIrqHandler: data is null!");
17221bd4fe43Sopenharmony_ci        return HDF_SUCCESS;
17231bd4fe43Sopenharmony_ci    }
17241bd4fe43Sopenharmony_ci    state = HIMCI_READL((uintptr_t)host->base + MMC_RINTSTS);
17251bd4fe43Sopenharmony_ci    HIMCI_WRITEL(state, (uintptr_t)host->base + MMC_RINTSTS);
17261bd4fe43Sopenharmony_ci    if ((state & SDIO_INT_STATUS) > 0) {
17271bd4fe43Sopenharmony_ci        HIMCI_CLEARL(host, MMC_INTMASK, SDIO_INT_MASK);
17281bd4fe43Sopenharmony_ci        (void)MmcCntlrNotifySdioIrqThread(host->mmc);
17291bd4fe43Sopenharmony_ci    }
17301bd4fe43Sopenharmony_ci
17311bd4fe43Sopenharmony_ci    if ((state & CARD_DETECT_INT_STATUS) > 0) {
17321bd4fe43Sopenharmony_ci        (void)MmcCntlrAddPlugMsgToQueue(host->mmc);
17331bd4fe43Sopenharmony_ci        if (host->waitForEvent == true) {
17341bd4fe43Sopenharmony_ci            (void)HIMCI_EVENT_SIGNAL(&host->himciEvent, HIMCI_PEND_ACCIDENT);
17351bd4fe43Sopenharmony_ci            return HDF_SUCCESS;
17361bd4fe43Sopenharmony_ci        }
17371bd4fe43Sopenharmony_ci    }
17381bd4fe43Sopenharmony_ci
17391bd4fe43Sopenharmony_ci    cmd = host->cmd;
17401bd4fe43Sopenharmony_ci    if (cmd == NULL) {
17411bd4fe43Sopenharmony_ci        return HDF_SUCCESS;
17421bd4fe43Sopenharmony_ci    }
17431bd4fe43Sopenharmony_ci
17441bd4fe43Sopenharmony_ci    if ((state & CMD_INT_MASK) > 0) {
17451bd4fe43Sopenharmony_ci        writeEvent += HimciCmdIrq(host, state);
17461bd4fe43Sopenharmony_ci    }
17471bd4fe43Sopenharmony_ci
17481bd4fe43Sopenharmony_ci    if ((state & DATA_INT_MASK) > 0) {
17491bd4fe43Sopenharmony_ci        /*
17501bd4fe43Sopenharmony_ci         * SBE_INT_STATUS:
17511bd4fe43Sopenharmony_ci         * Busy Clear Interrupt when data is written to the card
17521bd4fe43Sopenharmony_ci         * In this case, we'd wait for it.
17531bd4fe43Sopenharmony_ci         * Error in data start bit when data is read from a card
17541bd4fe43Sopenharmony_ci         * In this case, we don't need to wait for it. if it's triggered, something is wrong
17551bd4fe43Sopenharmony_ci         */
17561bd4fe43Sopenharmony_ci        if (cmd->data != NULL) {
17571bd4fe43Sopenharmony_ci            writeEvent += HimciDataIrq(host, cmd->data, state);
17581bd4fe43Sopenharmony_ci        } else {
17591bd4fe43Sopenharmony_ci            writeEvent += HimciCmdIrq(host, state);
17601bd4fe43Sopenharmony_ci        }
17611bd4fe43Sopenharmony_ci    }
17621bd4fe43Sopenharmony_ci    if (writeEvent != 0) {
17631bd4fe43Sopenharmony_ci        (void)HIMCI_EVENT_SIGNAL(&host->himciEvent, HIMCI_PEND_DTO_M);
17641bd4fe43Sopenharmony_ci    }
17651bd4fe43Sopenharmony_ci    return HDF_SUCCESS;
17661bd4fe43Sopenharmony_ci}
17671bd4fe43Sopenharmony_ci
17681bd4fe43Sopenharmony_cistatic int32_t HimciHostInit(struct HimciHost *host, struct MmcCntlr *cntlr)
17691bd4fe43Sopenharmony_ci{
17701bd4fe43Sopenharmony_ci    int32_t ret;
17711bd4fe43Sopenharmony_ci
17721bd4fe43Sopenharmony_ci    host->id = (uint32_t)cntlr->index;
17731bd4fe43Sopenharmony_ci    host->dmaVaddr = (uint32_t *)LOS_DmaMemAlloc(&host->dmaPaddr, HIMCI_PAGE_SIZE, CACHE_ALIGNED_SIZE, DMA_CACHE);
17741bd4fe43Sopenharmony_ci    if (host->dmaVaddr == NULL) {
17751bd4fe43Sopenharmony_ci        HDF_LOGE("HimciHostInit: no mem for himci dma!");
17761bd4fe43Sopenharmony_ci        return HDF_ERR_MALLOC_FAIL;
17771bd4fe43Sopenharmony_ci    }
17781bd4fe43Sopenharmony_ci
17791bd4fe43Sopenharmony_ci    if (HIMCI_EVENT_INIT(&host->himciEvent) != HDF_SUCCESS) {
17801bd4fe43Sopenharmony_ci        HDF_LOGE("HimciHostInit: himciEvent init fail!");
17811bd4fe43Sopenharmony_ci        return HDF_FAILURE;
17821bd4fe43Sopenharmony_ci    }
17831bd4fe43Sopenharmony_ci    if (OsalMutexInit(&host->mutex) != HDF_SUCCESS) {
17841bd4fe43Sopenharmony_ci        HDF_LOGE("HimciHostInit: init mutex lock fail!");
17851bd4fe43Sopenharmony_ci        return HDF_FAILURE;
17861bd4fe43Sopenharmony_ci    }
17871bd4fe43Sopenharmony_ci
17881bd4fe43Sopenharmony_ci    HimciSysCtrlInit(host);
17891bd4fe43Sopenharmony_ci    HimciHostRegistersInit(host);
17901bd4fe43Sopenharmony_ci
17911bd4fe43Sopenharmony_ci    ret = OsalRegisterIrq(host->irqNum, 0, HimciIrqHandler, "MMC_IRQ", host);
17921bd4fe43Sopenharmony_ci    if (ret != HDF_SUCCESS) {
17931bd4fe43Sopenharmony_ci        HDF_LOGE("HimciHostInit: request irq for himci is err.");
17941bd4fe43Sopenharmony_ci        return HDF_FAILURE;
17951bd4fe43Sopenharmony_ci    }
17961bd4fe43Sopenharmony_ci    return HDF_SUCCESS;
17971bd4fe43Sopenharmony_ci}
17981bd4fe43Sopenharmony_ci
17991bd4fe43Sopenharmony_cistatic int32_t HimciHostParse(struct HimciHost *host, struct HdfDeviceObject *obj)
18001bd4fe43Sopenharmony_ci{
18011bd4fe43Sopenharmony_ci    const struct DeviceResourceNode *node = NULL;
18021bd4fe43Sopenharmony_ci    struct DeviceResourceIface *drsOps = NULL;
18031bd4fe43Sopenharmony_ci    int32_t ret;
18041bd4fe43Sopenharmony_ci    uint32_t regBase, regSize;
18051bd4fe43Sopenharmony_ci
18061bd4fe43Sopenharmony_ci    if (obj == NULL || host == NULL) {
18071bd4fe43Sopenharmony_ci        HDF_LOGE("%s: input param is NULL.", __func__);
18081bd4fe43Sopenharmony_ci        return HDF_FAILURE;
18091bd4fe43Sopenharmony_ci    }
18101bd4fe43Sopenharmony_ci
18111bd4fe43Sopenharmony_ci    node = obj->property;
18121bd4fe43Sopenharmony_ci    if (node == NULL) {
18131bd4fe43Sopenharmony_ci        HDF_LOGE("%s: drs node is NULL.", __func__);
18141bd4fe43Sopenharmony_ci        return HDF_FAILURE;
18151bd4fe43Sopenharmony_ci    }
18161bd4fe43Sopenharmony_ci    drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
18171bd4fe43Sopenharmony_ci    if (drsOps == NULL || drsOps->GetUint32 == NULL) {
18181bd4fe43Sopenharmony_ci        HDF_LOGE("%s: invalid drs ops fail!", __func__);
18191bd4fe43Sopenharmony_ci        return HDF_FAILURE;
18201bd4fe43Sopenharmony_ci    }
18211bd4fe43Sopenharmony_ci
18221bd4fe43Sopenharmony_ci    ret = drsOps->GetUint32(node, "regBasePhy", &regBase, 0);
18231bd4fe43Sopenharmony_ci    if (ret != HDF_SUCCESS) {
18241bd4fe43Sopenharmony_ci        HDF_LOGE("%s: read regBasePhy fail!", __func__);
18251bd4fe43Sopenharmony_ci        return ret;
18261bd4fe43Sopenharmony_ci    }
18271bd4fe43Sopenharmony_ci
18281bd4fe43Sopenharmony_ci    ret = drsOps->GetUint32(node, "regSize", &regSize, 0);
18291bd4fe43Sopenharmony_ci    if (ret != HDF_SUCCESS) {
18301bd4fe43Sopenharmony_ci        HDF_LOGE("%s: read regSize fail!", __func__);
18311bd4fe43Sopenharmony_ci        return ret;
18321bd4fe43Sopenharmony_ci    }
18331bd4fe43Sopenharmony_ci
18341bd4fe43Sopenharmony_ci    host->base = OsalIoRemap(regBase, regSize);
18351bd4fe43Sopenharmony_ci    if (host->base == NULL) {
18361bd4fe43Sopenharmony_ci        HDF_LOGE("%s: ioremap regBase fail!", __func__);
18371bd4fe43Sopenharmony_ci        return HDF_ERR_IO;
18381bd4fe43Sopenharmony_ci    }
18391bd4fe43Sopenharmony_ci
18401bd4fe43Sopenharmony_ci    ret = drsOps->GetUint32(node, "irqNum", &(host->irqNum), 0);
18411bd4fe43Sopenharmony_ci    if (ret != HDF_SUCCESS) {
18421bd4fe43Sopenharmony_ci        HDF_LOGE("%s: read irqNum fail!", __func__);
18431bd4fe43Sopenharmony_ci    }
18441bd4fe43Sopenharmony_ci    return ret;
18451bd4fe43Sopenharmony_ci}
18461bd4fe43Sopenharmony_ci
18471bd4fe43Sopenharmony_cistatic void HimciDeleteHost(struct HimciHost *host)
18481bd4fe43Sopenharmony_ci{
18491bd4fe43Sopenharmony_ci    struct MmcCntlr *cntlr = NULL;
18501bd4fe43Sopenharmony_ci
18511bd4fe43Sopenharmony_ci    if (host == NULL) {
18521bd4fe43Sopenharmony_ci        return;
18531bd4fe43Sopenharmony_ci    }
18541bd4fe43Sopenharmony_ci
18551bd4fe43Sopenharmony_ci    cntlr = host->mmc;
18561bd4fe43Sopenharmony_ci    if (cntlr != NULL) {
18571bd4fe43Sopenharmony_ci        if (cntlr->curDev != NULL) {
18581bd4fe43Sopenharmony_ci            MmcDeviceRemove(cntlr->curDev);
18591bd4fe43Sopenharmony_ci            OsalMemFree(cntlr->curDev);
18601bd4fe43Sopenharmony_ci            cntlr->curDev = NULL;
18611bd4fe43Sopenharmony_ci        }
18621bd4fe43Sopenharmony_ci        MmcCntlrRemove(cntlr);
18631bd4fe43Sopenharmony_ci        cntlr->hdfDevObj = NULL;
18641bd4fe43Sopenharmony_ci        cntlr->priv = NULL;
18651bd4fe43Sopenharmony_ci        cntlr->ops = NULL;
18661bd4fe43Sopenharmony_ci        OsalMemFree(cntlr);
18671bd4fe43Sopenharmony_ci        host->mmc = NULL;
18681bd4fe43Sopenharmony_ci    }
18691bd4fe43Sopenharmony_ci
18701bd4fe43Sopenharmony_ci    OsalUnregisterIrq(host->irqNum, host);
18711bd4fe43Sopenharmony_ci    if (host->dmaVaddr != NULL) {
18721bd4fe43Sopenharmony_ci        LOS_DmaMemFree(host->dmaVaddr);
18731bd4fe43Sopenharmony_ci    }
18741bd4fe43Sopenharmony_ci    if (host->base != NULL) {
18751bd4fe43Sopenharmony_ci        OsalIoUnmap(host->base);
18761bd4fe43Sopenharmony_ci    }
18771bd4fe43Sopenharmony_ci
18781bd4fe43Sopenharmony_ci    (void)HIMCI_EVENT_DELETE(&host->himciEvent);
18791bd4fe43Sopenharmony_ci    (void)OsalMutexDestroy(&host->mutex);
18801bd4fe43Sopenharmony_ci    OsalMemFree(host);
18811bd4fe43Sopenharmony_ci}
18821bd4fe43Sopenharmony_ci
18831bd4fe43Sopenharmony_cistatic int32_t HimciMmcBind(struct HdfDeviceObject *obj)
18841bd4fe43Sopenharmony_ci{
18851bd4fe43Sopenharmony_ci    struct MmcCntlr *cntlr = NULL;
18861bd4fe43Sopenharmony_ci    struct HimciHost *host = NULL;
18871bd4fe43Sopenharmony_ci    int32_t ret;
18881bd4fe43Sopenharmony_ci
18891bd4fe43Sopenharmony_ci    if (obj == NULL) {
18901bd4fe43Sopenharmony_ci        HDF_LOGE("HimciMmcBind: Fail, device is NULL.");
18911bd4fe43Sopenharmony_ci        return HDF_ERR_INVALID_OBJECT;
18921bd4fe43Sopenharmony_ci    }
18931bd4fe43Sopenharmony_ci    cntlr = (struct MmcCntlr *)OsalMemCalloc(sizeof(struct MmcCntlr));
18941bd4fe43Sopenharmony_ci    if (cntlr == NULL) {
18951bd4fe43Sopenharmony_ci        HDF_LOGE("HimciMmcBind: no mem for MmcCntlr.");
18961bd4fe43Sopenharmony_ci        return HDF_ERR_MALLOC_FAIL;
18971bd4fe43Sopenharmony_ci    }
18981bd4fe43Sopenharmony_ci    host = (struct HimciHost *)OsalMemCalloc(sizeof(struct HimciHost));
18991bd4fe43Sopenharmony_ci    if (host == NULL) {
19001bd4fe43Sopenharmony_ci        HDF_LOGE("HimciMmcBind: no mem for HimciHost.");
19011bd4fe43Sopenharmony_ci        OsalMemFree(cntlr);
19021bd4fe43Sopenharmony_ci        return HDF_ERR_MALLOC_FAIL;
19031bd4fe43Sopenharmony_ci    }
19041bd4fe43Sopenharmony_ci
19051bd4fe43Sopenharmony_ci    host->mmc = cntlr;
19061bd4fe43Sopenharmony_ci    cntlr->priv = (void *)host;
19071bd4fe43Sopenharmony_ci    cntlr->ops = &g_himciHostOps;
19081bd4fe43Sopenharmony_ci    cntlr->hdfDevObj = obj;
19091bd4fe43Sopenharmony_ci    obj->service = &cntlr->service;
19101bd4fe43Sopenharmony_ci    /* init cntlr. */
19111bd4fe43Sopenharmony_ci    ret = MmcCntlrParse(cntlr, obj);
19121bd4fe43Sopenharmony_ci    if (ret != HDF_SUCCESS) {
19131bd4fe43Sopenharmony_ci        goto _ERR;
19141bd4fe43Sopenharmony_ci    }
19151bd4fe43Sopenharmony_ci    /* init host. */
19161bd4fe43Sopenharmony_ci    ret = HimciHostParse(host, obj);
19171bd4fe43Sopenharmony_ci    if (ret != HDF_SUCCESS) {
19181bd4fe43Sopenharmony_ci        goto _ERR;
19191bd4fe43Sopenharmony_ci    }
19201bd4fe43Sopenharmony_ci    ret = HimciHostInit(host, cntlr);
19211bd4fe43Sopenharmony_ci    if (ret != HDF_SUCCESS) {
19221bd4fe43Sopenharmony_ci        goto _ERR;
19231bd4fe43Sopenharmony_ci    }
19241bd4fe43Sopenharmony_ci    ret = MmcCntlrAdd(cntlr, true);
19251bd4fe43Sopenharmony_ci    if (ret != HDF_SUCCESS) {
19261bd4fe43Sopenharmony_ci        goto _ERR;
19271bd4fe43Sopenharmony_ci    }
19281bd4fe43Sopenharmony_ci
19291bd4fe43Sopenharmony_ci    /* add card detect msg to queue. */
19301bd4fe43Sopenharmony_ci    (void)MmcCntlrAddDetectMsgToQueue(cntlr);
19311bd4fe43Sopenharmony_ci    HDF_LOGI("%s: mmc bind success.", __func__);
19321bd4fe43Sopenharmony_ci    return HDF_SUCCESS;
19331bd4fe43Sopenharmony_ci_ERR:
19341bd4fe43Sopenharmony_ci    HimciDeleteHost(host);
19351bd4fe43Sopenharmony_ci    HDF_LOGE("HimciMmcBind: fail, err = %d.", ret);
19361bd4fe43Sopenharmony_ci    return ret;
19371bd4fe43Sopenharmony_ci}
19381bd4fe43Sopenharmony_ci
19391bd4fe43Sopenharmony_cistatic int32_t HimciMmcInit(struct HdfDeviceObject *obj)
19401bd4fe43Sopenharmony_ci{
19411bd4fe43Sopenharmony_ci    static bool procInit = false;
19421bd4fe43Sopenharmony_ci
19431bd4fe43Sopenharmony_ci    (void)obj;
19441bd4fe43Sopenharmony_ci    if (procInit == false) {
19451bd4fe43Sopenharmony_ci        if (ProcMciInit() == HDF_SUCCESS) {
19461bd4fe43Sopenharmony_ci            procInit = true;
19471bd4fe43Sopenharmony_ci        }
19481bd4fe43Sopenharmony_ci    }
19491bd4fe43Sopenharmony_ci    HDF_LOGI("%s: mmc init success.", __func__);
19501bd4fe43Sopenharmony_ci    return HDF_SUCCESS;
19511bd4fe43Sopenharmony_ci}
19521bd4fe43Sopenharmony_ci
19531bd4fe43Sopenharmony_cistatic void HimciMmcRelease(struct HdfDeviceObject *obj)
19541bd4fe43Sopenharmony_ci{
19551bd4fe43Sopenharmony_ci    struct MmcCntlr *cntlr = NULL;
19561bd4fe43Sopenharmony_ci
19571bd4fe43Sopenharmony_ci    HDF_LOGI("%s: enter", __func__);
19581bd4fe43Sopenharmony_ci    if (obj == NULL) {
19591bd4fe43Sopenharmony_ci        return;
19601bd4fe43Sopenharmony_ci    }
19611bd4fe43Sopenharmony_ci
19621bd4fe43Sopenharmony_ci    cntlr = (struct MmcCntlr *)obj->service;
19631bd4fe43Sopenharmony_ci    if (cntlr == NULL) {
19641bd4fe43Sopenharmony_ci        return;
19651bd4fe43Sopenharmony_ci    }
19661bd4fe43Sopenharmony_ci    HimciDeleteHost((struct HimciHost *)cntlr->priv);
19671bd4fe43Sopenharmony_ci}
19681bd4fe43Sopenharmony_ci
19691bd4fe43Sopenharmony_cistruct HdfDriverEntry g_mmcDriverEntry = {
19701bd4fe43Sopenharmony_ci    .moduleVersion = 1,
19711bd4fe43Sopenharmony_ci    .Bind = HimciMmcBind,
19721bd4fe43Sopenharmony_ci    .Init = HimciMmcInit,
19731bd4fe43Sopenharmony_ci    .Release = HimciMmcRelease,
19741bd4fe43Sopenharmony_ci    .moduleName = "hi3516_mmc_driver",
19751bd4fe43Sopenharmony_ci};
19761bd4fe43Sopenharmony_ciHDF_INIT(g_mmcDriverEntry);
1977