1757bff49SJaehoon Chung /* 2757bff49SJaehoon Chung * (C) Copyright 2012 SAMSUNG Electronics 3757bff49SJaehoon Chung * Jaehoon Chung <jh80.chung@samsung.com> 4757bff49SJaehoon Chung * Rajeshawari Shinde <rajeshwari.s@samsung.com> 5757bff49SJaehoon Chung * 61a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 7757bff49SJaehoon Chung */ 8757bff49SJaehoon Chung 92a7a210eSAlexey Brodkin #include <bouncebuf.h> 10757bff49SJaehoon Chung #include <common.h> 111c87ffe8SSimon Glass #include <errno.h> 12757bff49SJaehoon Chung #include <malloc.h> 13757bff49SJaehoon Chung #include <mmc.h> 14757bff49SJaehoon Chung #include <dwmmc.h> 15757bff49SJaehoon Chung #include <asm-generic/errno.h> 16757bff49SJaehoon Chung 17757bff49SJaehoon Chung #define PAGE_SIZE 4096 18757bff49SJaehoon Chung 19757bff49SJaehoon Chung static int dwmci_wait_reset(struct dwmci_host *host, u32 value) 20757bff49SJaehoon Chung { 21757bff49SJaehoon Chung unsigned long timeout = 1000; 22757bff49SJaehoon Chung u32 ctrl; 23757bff49SJaehoon Chung 24757bff49SJaehoon Chung dwmci_writel(host, DWMCI_CTRL, value); 25757bff49SJaehoon Chung 26757bff49SJaehoon Chung while (timeout--) { 27757bff49SJaehoon Chung ctrl = dwmci_readl(host, DWMCI_CTRL); 28757bff49SJaehoon Chung if (!(ctrl & DWMCI_RESET_ALL)) 29757bff49SJaehoon Chung return 1; 30757bff49SJaehoon Chung } 31757bff49SJaehoon Chung return 0; 32757bff49SJaehoon Chung } 33757bff49SJaehoon Chung 34757bff49SJaehoon Chung static void dwmci_set_idma_desc(struct dwmci_idmac *idmac, 35757bff49SJaehoon Chung u32 desc0, u32 desc1, u32 desc2) 36757bff49SJaehoon Chung { 37757bff49SJaehoon Chung struct dwmci_idmac *desc = idmac; 38757bff49SJaehoon Chung 39757bff49SJaehoon Chung desc->flags = desc0; 40757bff49SJaehoon Chung desc->cnt = desc1; 41757bff49SJaehoon Chung desc->addr = desc2; 42757bff49SJaehoon Chung desc->next_addr = (unsigned int)desc + sizeof(struct dwmci_idmac); 43757bff49SJaehoon Chung } 44757bff49SJaehoon Chung 45757bff49SJaehoon Chung static void dwmci_prepare_data(struct dwmci_host *host, 462a7a210eSAlexey Brodkin struct mmc_data *data, 472a7a210eSAlexey Brodkin struct dwmci_idmac *cur_idmac, 482a7a210eSAlexey Brodkin void *bounce_buffer) 49757bff49SJaehoon Chung { 50757bff49SJaehoon Chung unsigned long ctrl; 51757bff49SJaehoon Chung unsigned int i = 0, flags, cnt, blk_cnt; 522a7a210eSAlexey Brodkin ulong data_start, data_end; 53757bff49SJaehoon Chung 54757bff49SJaehoon Chung 55757bff49SJaehoon Chung blk_cnt = data->blocks; 56757bff49SJaehoon Chung 57757bff49SJaehoon Chung dwmci_wait_reset(host, DWMCI_CTRL_FIFO_RESET); 58757bff49SJaehoon Chung 59757bff49SJaehoon Chung data_start = (ulong)cur_idmac; 60757bff49SJaehoon Chung dwmci_writel(host, DWMCI_DBADDR, (unsigned int)cur_idmac); 61757bff49SJaehoon Chung 62757bff49SJaehoon Chung do { 63757bff49SJaehoon Chung flags = DWMCI_IDMAC_OWN | DWMCI_IDMAC_CH ; 64757bff49SJaehoon Chung flags |= (i == 0) ? DWMCI_IDMAC_FS : 0; 65757bff49SJaehoon Chung if (blk_cnt <= 8) { 66757bff49SJaehoon Chung flags |= DWMCI_IDMAC_LD; 67757bff49SJaehoon Chung cnt = data->blocksize * blk_cnt; 68757bff49SJaehoon Chung } else 69757bff49SJaehoon Chung cnt = data->blocksize * 8; 70757bff49SJaehoon Chung 71757bff49SJaehoon Chung dwmci_set_idma_desc(cur_idmac, flags, cnt, 722a7a210eSAlexey Brodkin (u32)bounce_buffer + (i * PAGE_SIZE)); 73757bff49SJaehoon Chung 7421bd5761SMischa Jonker if (blk_cnt <= 8) 75757bff49SJaehoon Chung break; 76757bff49SJaehoon Chung blk_cnt -= 8; 77757bff49SJaehoon Chung cur_idmac++; 78757bff49SJaehoon Chung i++; 79757bff49SJaehoon Chung } while(1); 80757bff49SJaehoon Chung 81757bff49SJaehoon Chung data_end = (ulong)cur_idmac; 82757bff49SJaehoon Chung flush_dcache_range(data_start, data_end + ARCH_DMA_MINALIGN); 83757bff49SJaehoon Chung 84757bff49SJaehoon Chung ctrl = dwmci_readl(host, DWMCI_CTRL); 85757bff49SJaehoon Chung ctrl |= DWMCI_IDMAC_EN | DWMCI_DMA_EN; 86757bff49SJaehoon Chung dwmci_writel(host, DWMCI_CTRL, ctrl); 87757bff49SJaehoon Chung 88757bff49SJaehoon Chung ctrl = dwmci_readl(host, DWMCI_BMOD); 89757bff49SJaehoon Chung ctrl |= DWMCI_BMOD_IDMAC_FB | DWMCI_BMOD_IDMAC_EN; 90757bff49SJaehoon Chung dwmci_writel(host, DWMCI_BMOD, ctrl); 91757bff49SJaehoon Chung 92757bff49SJaehoon Chung dwmci_writel(host, DWMCI_BLKSIZ, data->blocksize); 93757bff49SJaehoon Chung dwmci_writel(host, DWMCI_BYTCNT, data->blocksize * data->blocks); 94757bff49SJaehoon Chung } 95757bff49SJaehoon Chung 96757bff49SJaehoon Chung static int dwmci_set_transfer_mode(struct dwmci_host *host, 97757bff49SJaehoon Chung struct mmc_data *data) 98757bff49SJaehoon Chung { 99757bff49SJaehoon Chung unsigned long mode; 100757bff49SJaehoon Chung 101757bff49SJaehoon Chung mode = DWMCI_CMD_DATA_EXP; 102757bff49SJaehoon Chung if (data->flags & MMC_DATA_WRITE) 103757bff49SJaehoon Chung mode |= DWMCI_CMD_RW; 104757bff49SJaehoon Chung 105757bff49SJaehoon Chung return mode; 106757bff49SJaehoon Chung } 107757bff49SJaehoon Chung 108757bff49SJaehoon Chung static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, 109757bff49SJaehoon Chung struct mmc_data *data) 110757bff49SJaehoon Chung { 11193bfd616SPantelis Antoniou struct dwmci_host *host = mmc->priv; 1122136d226SMischa Jonker ALLOC_CACHE_ALIGN_BUFFER(struct dwmci_idmac, cur_idmac, 11321bd5761SMischa Jonker data ? DIV_ROUND_UP(data->blocks, 8) : 0); 1149042d974SMarek Vasut int ret = 0, flags = 0, i; 115757bff49SJaehoon Chung unsigned int timeout = 100000; 116757bff49SJaehoon Chung u32 retry = 10000; 117757bff49SJaehoon Chung u32 mask, ctrl; 1189c50e35fSAmar ulong start = get_timer(0); 1192a7a210eSAlexey Brodkin struct bounce_buffer bbstate; 120757bff49SJaehoon Chung 121757bff49SJaehoon Chung while (dwmci_readl(host, DWMCI_STATUS) & DWMCI_BUSY) { 1229c50e35fSAmar if (get_timer(start) > timeout) { 1231c87ffe8SSimon Glass debug("%s: Timeout on data busy\n", __func__); 124757bff49SJaehoon Chung return TIMEOUT; 125757bff49SJaehoon Chung } 126757bff49SJaehoon Chung } 127757bff49SJaehoon Chung 128757bff49SJaehoon Chung dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_ALL); 129757bff49SJaehoon Chung 1302a7a210eSAlexey Brodkin if (data) { 1312a7a210eSAlexey Brodkin if (data->flags == MMC_DATA_READ) { 1322a7a210eSAlexey Brodkin bounce_buffer_start(&bbstate, (void*)data->dest, 1332a7a210eSAlexey Brodkin data->blocksize * 1342a7a210eSAlexey Brodkin data->blocks, GEN_BB_WRITE); 1352a7a210eSAlexey Brodkin } else { 1362a7a210eSAlexey Brodkin bounce_buffer_start(&bbstate, (void*)data->src, 1372a7a210eSAlexey Brodkin data->blocksize * 1382a7a210eSAlexey Brodkin data->blocks, GEN_BB_READ); 1392a7a210eSAlexey Brodkin } 1402a7a210eSAlexey Brodkin dwmci_prepare_data(host, data, cur_idmac, 1412a7a210eSAlexey Brodkin bbstate.bounce_buffer); 1422a7a210eSAlexey Brodkin } 143757bff49SJaehoon Chung 144757bff49SJaehoon Chung dwmci_writel(host, DWMCI_CMDARG, cmd->cmdarg); 145757bff49SJaehoon Chung 146757bff49SJaehoon Chung if (data) 147757bff49SJaehoon Chung flags = dwmci_set_transfer_mode(host, data); 148757bff49SJaehoon Chung 149757bff49SJaehoon Chung if ((cmd->resp_type & MMC_RSP_136) && (cmd->resp_type & MMC_RSP_BUSY)) 150757bff49SJaehoon Chung return -1; 151757bff49SJaehoon Chung 152757bff49SJaehoon Chung if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) 153757bff49SJaehoon Chung flags |= DWMCI_CMD_ABORT_STOP; 154757bff49SJaehoon Chung else 155757bff49SJaehoon Chung flags |= DWMCI_CMD_PRV_DAT_WAIT; 156757bff49SJaehoon Chung 157757bff49SJaehoon Chung if (cmd->resp_type & MMC_RSP_PRESENT) { 158757bff49SJaehoon Chung flags |= DWMCI_CMD_RESP_EXP; 159757bff49SJaehoon Chung if (cmd->resp_type & MMC_RSP_136) 160757bff49SJaehoon Chung flags |= DWMCI_CMD_RESP_LENGTH; 161757bff49SJaehoon Chung } 162757bff49SJaehoon Chung 163757bff49SJaehoon Chung if (cmd->resp_type & MMC_RSP_CRC) 164757bff49SJaehoon Chung flags |= DWMCI_CMD_CHECK_CRC; 165757bff49SJaehoon Chung 166757bff49SJaehoon Chung flags |= (cmd->cmdidx | DWMCI_CMD_START | DWMCI_CMD_USE_HOLD_REG); 167757bff49SJaehoon Chung 168757bff49SJaehoon Chung debug("Sending CMD%d\n",cmd->cmdidx); 169757bff49SJaehoon Chung 170757bff49SJaehoon Chung dwmci_writel(host, DWMCI_CMD, flags); 171757bff49SJaehoon Chung 172757bff49SJaehoon Chung for (i = 0; i < retry; i++) { 173757bff49SJaehoon Chung mask = dwmci_readl(host, DWMCI_RINTSTS); 174757bff49SJaehoon Chung if (mask & DWMCI_INTMSK_CDONE) { 175757bff49SJaehoon Chung if (!data) 176757bff49SJaehoon Chung dwmci_writel(host, DWMCI_RINTSTS, mask); 177757bff49SJaehoon Chung break; 178757bff49SJaehoon Chung } 179757bff49SJaehoon Chung } 180757bff49SJaehoon Chung 181f33c9305SPavel Machek if (i == retry) { 1821c87ffe8SSimon Glass debug("%s: Timeout.\n", __func__); 183757bff49SJaehoon Chung return TIMEOUT; 184f33c9305SPavel Machek } 185757bff49SJaehoon Chung 186757bff49SJaehoon Chung if (mask & DWMCI_INTMSK_RTO) { 187f33c9305SPavel Machek /* 188f33c9305SPavel Machek * Timeout here is not necessarily fatal. (e)MMC cards 189f33c9305SPavel Machek * will splat here when they receive CMD55 as they do 190f33c9305SPavel Machek * not support this command and that is exactly the way 191f33c9305SPavel Machek * to tell them apart from SD cards. Thus, this output 192f33c9305SPavel Machek * below shall be debug(). eMMC cards also do not favor 193f33c9305SPavel Machek * CMD8, please keep that in mind. 194f33c9305SPavel Machek */ 195f33c9305SPavel Machek debug("%s: Response Timeout.\n", __func__); 196757bff49SJaehoon Chung return TIMEOUT; 197757bff49SJaehoon Chung } else if (mask & DWMCI_INTMSK_RE) { 1981c87ffe8SSimon Glass debug("%s: Response Error.\n", __func__); 1991c87ffe8SSimon Glass return -EIO; 200757bff49SJaehoon Chung } 201757bff49SJaehoon Chung 202757bff49SJaehoon Chung 203757bff49SJaehoon Chung if (cmd->resp_type & MMC_RSP_PRESENT) { 204757bff49SJaehoon Chung if (cmd->resp_type & MMC_RSP_136) { 205757bff49SJaehoon Chung cmd->response[0] = dwmci_readl(host, DWMCI_RESP3); 206757bff49SJaehoon Chung cmd->response[1] = dwmci_readl(host, DWMCI_RESP2); 207757bff49SJaehoon Chung cmd->response[2] = dwmci_readl(host, DWMCI_RESP1); 208757bff49SJaehoon Chung cmd->response[3] = dwmci_readl(host, DWMCI_RESP0); 209757bff49SJaehoon Chung } else { 210757bff49SJaehoon Chung cmd->response[0] = dwmci_readl(host, DWMCI_RESP0); 211757bff49SJaehoon Chung } 212757bff49SJaehoon Chung } 213757bff49SJaehoon Chung 214757bff49SJaehoon Chung if (data) { 215d9dbb97bSMarek Vasut start = get_timer(0); 216d9dbb97bSMarek Vasut timeout = 1000; 217d9dbb97bSMarek Vasut for (;;) { 218757bff49SJaehoon Chung mask = dwmci_readl(host, DWMCI_RINTSTS); 219d9dbb97bSMarek Vasut /* Error during data transfer. */ 220757bff49SJaehoon Chung if (mask & (DWMCI_DATA_ERR | DWMCI_DATA_TOUT)) { 2211c87ffe8SSimon Glass debug("%s: DATA ERROR!\n", __func__); 2229042d974SMarek Vasut ret = -EINVAL; 2239042d974SMarek Vasut break; 224757bff49SJaehoon Chung } 225d9dbb97bSMarek Vasut 226d9dbb97bSMarek Vasut /* Data arrived correctly. */ 2279042d974SMarek Vasut if (mask & DWMCI_INTMSK_DTO) { 2289042d974SMarek Vasut ret = 0; 229d9dbb97bSMarek Vasut break; 2309042d974SMarek Vasut } 231d9dbb97bSMarek Vasut 232d9dbb97bSMarek Vasut /* Check for timeout. */ 233d9dbb97bSMarek Vasut if (get_timer(start) > timeout) { 2341c87ffe8SSimon Glass debug("%s: Timeout waiting for data!\n", 235d9dbb97bSMarek Vasut __func__); 2369042d974SMarek Vasut ret = TIMEOUT; 2379042d974SMarek Vasut break; 238d9dbb97bSMarek Vasut } 239d9dbb97bSMarek Vasut } 240757bff49SJaehoon Chung 241757bff49SJaehoon Chung dwmci_writel(host, DWMCI_RINTSTS, mask); 242757bff49SJaehoon Chung 243757bff49SJaehoon Chung ctrl = dwmci_readl(host, DWMCI_CTRL); 244757bff49SJaehoon Chung ctrl &= ~(DWMCI_DMA_EN); 245757bff49SJaehoon Chung dwmci_writel(host, DWMCI_CTRL, ctrl); 2462a7a210eSAlexey Brodkin 2472a7a210eSAlexey Brodkin bounce_buffer_stop(&bbstate); 248757bff49SJaehoon Chung } 249757bff49SJaehoon Chung 250757bff49SJaehoon Chung udelay(100); 251757bff49SJaehoon Chung 2529042d974SMarek Vasut return ret; 253757bff49SJaehoon Chung } 254757bff49SJaehoon Chung 255757bff49SJaehoon Chung static int dwmci_setup_bus(struct dwmci_host *host, u32 freq) 256757bff49SJaehoon Chung { 257757bff49SJaehoon Chung u32 div, status; 258757bff49SJaehoon Chung int timeout = 10000; 259757bff49SJaehoon Chung unsigned long sclk; 260757bff49SJaehoon Chung 2619c50e35fSAmar if ((freq == host->clock) || (freq == 0)) 262757bff49SJaehoon Chung return 0; 263757bff49SJaehoon Chung /* 264f33c9305SPavel Machek * If host->get_mmc_clk isn't defined, 265757bff49SJaehoon Chung * then assume that host->bus_hz is source clock value. 266f33c9305SPavel Machek * host->bus_hz should be set by user. 267757bff49SJaehoon Chung */ 268b44fe83aSJaehoon Chung if (host->get_mmc_clk) 269d3e016ccSRajeshwari S Shinde sclk = host->get_mmc_clk(host); 270757bff49SJaehoon Chung else if (host->bus_hz) 271757bff49SJaehoon Chung sclk = host->bus_hz; 272757bff49SJaehoon Chung else { 2731c87ffe8SSimon Glass debug("%s: Didn't get source clock value.\n", __func__); 274757bff49SJaehoon Chung return -EINVAL; 275757bff49SJaehoon Chung } 276757bff49SJaehoon Chung 2776ace153dSChin Liang See if (sclk == freq) 2786ace153dSChin Liang See div = 0; /* bypass mode */ 2796ace153dSChin Liang See else 280757bff49SJaehoon Chung div = DIV_ROUND_UP(sclk, 2 * freq); 281757bff49SJaehoon Chung 282757bff49SJaehoon Chung dwmci_writel(host, DWMCI_CLKENA, 0); 283757bff49SJaehoon Chung dwmci_writel(host, DWMCI_CLKSRC, 0); 284757bff49SJaehoon Chung 285757bff49SJaehoon Chung dwmci_writel(host, DWMCI_CLKDIV, div); 286757bff49SJaehoon Chung dwmci_writel(host, DWMCI_CMD, DWMCI_CMD_PRV_DAT_WAIT | 287757bff49SJaehoon Chung DWMCI_CMD_UPD_CLK | DWMCI_CMD_START); 288757bff49SJaehoon Chung 289757bff49SJaehoon Chung do { 290757bff49SJaehoon Chung status = dwmci_readl(host, DWMCI_CMD); 291757bff49SJaehoon Chung if (timeout-- < 0) { 2921c87ffe8SSimon Glass debug("%s: Timeout!\n", __func__); 293757bff49SJaehoon Chung return -ETIMEDOUT; 294757bff49SJaehoon Chung } 295757bff49SJaehoon Chung } while (status & DWMCI_CMD_START); 296757bff49SJaehoon Chung 297757bff49SJaehoon Chung dwmci_writel(host, DWMCI_CLKENA, DWMCI_CLKEN_ENABLE | 298757bff49SJaehoon Chung DWMCI_CLKEN_LOW_PWR); 299757bff49SJaehoon Chung 300757bff49SJaehoon Chung dwmci_writel(host, DWMCI_CMD, DWMCI_CMD_PRV_DAT_WAIT | 301757bff49SJaehoon Chung DWMCI_CMD_UPD_CLK | DWMCI_CMD_START); 302757bff49SJaehoon Chung 303757bff49SJaehoon Chung timeout = 10000; 304757bff49SJaehoon Chung do { 305757bff49SJaehoon Chung status = dwmci_readl(host, DWMCI_CMD); 306757bff49SJaehoon Chung if (timeout-- < 0) { 3071c87ffe8SSimon Glass debug("%s: Timeout!\n", __func__); 308757bff49SJaehoon Chung return -ETIMEDOUT; 309757bff49SJaehoon Chung } 310757bff49SJaehoon Chung } while (status & DWMCI_CMD_START); 311757bff49SJaehoon Chung 312757bff49SJaehoon Chung host->clock = freq; 313757bff49SJaehoon Chung 314757bff49SJaehoon Chung return 0; 315757bff49SJaehoon Chung } 316757bff49SJaehoon Chung 317757bff49SJaehoon Chung static void dwmci_set_ios(struct mmc *mmc) 318757bff49SJaehoon Chung { 319045bdcd0SJaehoon Chung struct dwmci_host *host = (struct dwmci_host *)mmc->priv; 320045bdcd0SJaehoon Chung u32 ctype, regs; 321757bff49SJaehoon Chung 322757bff49SJaehoon Chung debug("Buswidth = %d, clock: %d\n", mmc->bus_width, mmc->clock); 323757bff49SJaehoon Chung 324757bff49SJaehoon Chung dwmci_setup_bus(host, mmc->clock); 325757bff49SJaehoon Chung switch (mmc->bus_width) { 326757bff49SJaehoon Chung case 8: 327757bff49SJaehoon Chung ctype = DWMCI_CTYPE_8BIT; 328757bff49SJaehoon Chung break; 329757bff49SJaehoon Chung case 4: 330757bff49SJaehoon Chung ctype = DWMCI_CTYPE_4BIT; 331757bff49SJaehoon Chung break; 332757bff49SJaehoon Chung default: 333757bff49SJaehoon Chung ctype = DWMCI_CTYPE_1BIT; 334757bff49SJaehoon Chung break; 335757bff49SJaehoon Chung } 336757bff49SJaehoon Chung 337757bff49SJaehoon Chung dwmci_writel(host, DWMCI_CTYPE, ctype); 338757bff49SJaehoon Chung 339045bdcd0SJaehoon Chung regs = dwmci_readl(host, DWMCI_UHS_REG); 3402b8a9692SAndrew Gabbasov if (mmc->ddr_mode) 341045bdcd0SJaehoon Chung regs |= DWMCI_DDR_MODE; 342045bdcd0SJaehoon Chung else 343afc9e2b5SJaehoon Chung regs &= ~DWMCI_DDR_MODE; 344045bdcd0SJaehoon Chung 345045bdcd0SJaehoon Chung dwmci_writel(host, DWMCI_UHS_REG, regs); 346045bdcd0SJaehoon Chung 347757bff49SJaehoon Chung if (host->clksel) 348757bff49SJaehoon Chung host->clksel(host); 349757bff49SJaehoon Chung } 350757bff49SJaehoon Chung 351757bff49SJaehoon Chung static int dwmci_init(struct mmc *mmc) 352757bff49SJaehoon Chung { 35393bfd616SPantelis Antoniou struct dwmci_host *host = mmc->priv; 354757bff49SJaehoon Chung 35518ab6755SJaehoon Chung if (host->board_init) 35618ab6755SJaehoon Chung host->board_init(host); 3576f0b7caaSRajeshwari Shinde 358757bff49SJaehoon Chung dwmci_writel(host, DWMCI_PWREN, 1); 359757bff49SJaehoon Chung 360757bff49SJaehoon Chung if (!dwmci_wait_reset(host, DWMCI_RESET_ALL)) { 3611c87ffe8SSimon Glass debug("%s[%d] Fail-reset!!\n", __func__, __LINE__); 3621c87ffe8SSimon Glass return -EIO; 363757bff49SJaehoon Chung } 364757bff49SJaehoon Chung 3659c50e35fSAmar /* Enumerate at 400KHz */ 36693bfd616SPantelis Antoniou dwmci_setup_bus(host, mmc->cfg->f_min); 3679c50e35fSAmar 368757bff49SJaehoon Chung dwmci_writel(host, DWMCI_RINTSTS, 0xFFFFFFFF); 369757bff49SJaehoon Chung dwmci_writel(host, DWMCI_INTMASK, 0); 370757bff49SJaehoon Chung 371757bff49SJaehoon Chung dwmci_writel(host, DWMCI_TMOUT, 0xFFFFFFFF); 372757bff49SJaehoon Chung 373757bff49SJaehoon Chung dwmci_writel(host, DWMCI_IDINTEN, 0); 374757bff49SJaehoon Chung dwmci_writel(host, DWMCI_BMOD, 1); 375757bff49SJaehoon Chung 376*760177dfSSimon Glass if (!host->fifoth_val) { 377*760177dfSSimon Glass uint32_t fifo_size; 378*760177dfSSimon Glass 379*760177dfSSimon Glass fifo_size = dwmci_readl(host, DWMCI_FIFOTH); 380*760177dfSSimon Glass fifo_size = ((fifo_size & RX_WMARK_MASK) >> RX_WMARK_SHIFT) + 1; 381*760177dfSSimon Glass host->fifoth_val = MSIZE(0x2) | RX_WMARK(fifo_size / 2 - 1) | 382*760177dfSSimon Glass TX_WMARK(fifo_size / 2); 3839108b315SAlexey Brodkin } 384*760177dfSSimon Glass dwmci_writel(host, DWMCI_FIFOTH, host->fifoth_val); 385757bff49SJaehoon Chung 386757bff49SJaehoon Chung dwmci_writel(host, DWMCI_CLKENA, 0); 387757bff49SJaehoon Chung dwmci_writel(host, DWMCI_CLKSRC, 0); 388757bff49SJaehoon Chung 389757bff49SJaehoon Chung return 0; 390757bff49SJaehoon Chung } 391757bff49SJaehoon Chung 392ab769f22SPantelis Antoniou static const struct mmc_ops dwmci_ops = { 393ab769f22SPantelis Antoniou .send_cmd = dwmci_send_cmd, 394ab769f22SPantelis Antoniou .set_ios = dwmci_set_ios, 395ab769f22SPantelis Antoniou .init = dwmci_init, 396ab769f22SPantelis Antoniou }; 397ab769f22SPantelis Antoniou 398757bff49SJaehoon Chung int add_dwmci(struct dwmci_host *host, u32 max_clk, u32 min_clk) 399757bff49SJaehoon Chung { 40093bfd616SPantelis Antoniou host->cfg.name = host->name; 40193bfd616SPantelis Antoniou host->cfg.ops = &dwmci_ops; 40293bfd616SPantelis Antoniou host->cfg.f_min = min_clk; 40393bfd616SPantelis Antoniou host->cfg.f_max = max_clk; 404757bff49SJaehoon Chung 40593bfd616SPantelis Antoniou host->cfg.voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; 406757bff49SJaehoon Chung 40793bfd616SPantelis Antoniou host->cfg.host_caps = host->caps; 408757bff49SJaehoon Chung 409757bff49SJaehoon Chung if (host->buswidth == 8) { 41093bfd616SPantelis Antoniou host->cfg.host_caps |= MMC_MODE_8BIT; 41193bfd616SPantelis Antoniou host->cfg.host_caps &= ~MMC_MODE_4BIT; 412757bff49SJaehoon Chung } else { 41393bfd616SPantelis Antoniou host->cfg.host_caps |= MMC_MODE_4BIT; 41493bfd616SPantelis Antoniou host->cfg.host_caps &= ~MMC_MODE_8BIT; 415757bff49SJaehoon Chung } 4165a20397bSRob Herring host->cfg.host_caps |= MMC_MODE_HS | MMC_MODE_HS_52MHz; 417757bff49SJaehoon Chung 41893bfd616SPantelis Antoniou host->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; 419757bff49SJaehoon Chung 42093bfd616SPantelis Antoniou host->mmc = mmc_create(&host->cfg, host); 42193bfd616SPantelis Antoniou if (host->mmc == NULL) 42293bfd616SPantelis Antoniou return -1; 42393bfd616SPantelis Antoniou 42493bfd616SPantelis Antoniou return 0; 425757bff49SJaehoon Chung } 426