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, ¶m, phaseDllElements); 14381bd4fe43Sopenharmony_ci } else { 14391bd4fe43Sopenharmony_ci HimciEdgedllModeBTuning(host, ¶m, 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", ®Base, 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", ®Size, 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