diff options
Diffstat (limited to 'drivers/mmc/dw_mmc.c')
-rw-r--r-- | drivers/mmc/dw_mmc.c | 550 |
1 files changed, 351 insertions, 199 deletions
diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c index e1036641452..8551eac7018 100644 --- a/drivers/mmc/dw_mmc.c +++ b/drivers/mmc/dw_mmc.c @@ -6,7 +6,6 @@ */ #include <bouncebuf.h> -#include <common.h> #include <cpu_func.h> #include <errno.h> #include <log.h> @@ -21,6 +20,47 @@ #define PAGE_SIZE 4096 +/* Internal DMA Controller (IDMAC) descriptor for 32-bit addressing mode */ +struct dwmci_idmac32 { + u32 des0; /* Control descriptor */ + u32 des1; /* Buffer size */ + u32 des2; /* Buffer physical address */ + u32 des3; /* Next descriptor physical address */ +} __aligned(ARCH_DMA_MINALIGN); + +/* Internal DMA Controller (IDMAC) descriptor for 64-bit addressing mode */ +struct dwmci_idmac64 { + u32 des0; /* Control descriptor */ + u32 des1; /* Reserved */ + u32 des2; /* Buffer sizes */ + u32 des3; /* Reserved */ + u32 des4; /* Lower 32-bits of Buffer Address Pointer 1 */ + u32 des5; /* Upper 32-bits of Buffer Address Pointer 1 */ + u32 des6; /* Lower 32-bits of Next Descriptor Address */ + u32 des7; /* Upper 32-bits of Next Descriptor Address */ +} __aligned(ARCH_DMA_MINALIGN); + +/* Register offsets for DW MMC blocks with 32-bit IDMAC */ +static const struct dwmci_idmac_regs dwmci_idmac_regs32 = { + .dbaddrl = DWMCI_DBADDR, + .idsts = DWMCI_IDSTS, + .idinten = DWMCI_IDINTEN, + .dscaddrl = DWMCI_DSCADDR, + .bufaddrl = DWMCI_BUFADDR, +}; + +/* Register offsets for DW MMC blocks with 64-bit IDMAC */ +static const struct dwmci_idmac_regs dwmci_idmac_regs64 = { + .dbaddrl = DWMCI_DBADDRL, + .dbaddru = DWMCI_DBADDRU, + .idsts = DWMCI_IDSTS64, + .idinten = DWMCI_IDINTEN64, + .dscaddrl = DWMCI_DSCADDRL, + .dscaddru = DWMCI_DSCADDRU, + .bufaddrl = DWMCI_BUFADDRL, + .bufaddru = DWMCI_BUFADDRU, +}; + static int dwmci_wait_reset(struct dwmci_host *host, u32 value) { unsigned long timeout = 1000; @@ -36,58 +76,98 @@ static int dwmci_wait_reset(struct dwmci_host *host, u32 value) return 0; } -static void dwmci_set_idma_desc(struct dwmci_idmac *idmac, - u32 desc0, u32 desc1, u32 desc2) +static void dwmci_set_idma_desc32(struct dwmci_idmac32 *desc, u32 control, + u32 buf_size, u32 buf_addr) { - struct dwmci_idmac *desc = idmac; + phys_addr_t desc_phys = virt_to_phys(desc); + u32 next_desc_phys = desc_phys + sizeof(struct dwmci_idmac32); - desc->flags = desc0; - desc->cnt = desc1; - desc->addr = desc2; - desc->next_addr = (ulong)desc + sizeof(struct dwmci_idmac); + desc->des0 = control; + desc->des1 = buf_size; + desc->des2 = buf_addr; + desc->des3 = next_desc_phys; } -static void dwmci_prepare_data(struct dwmci_host *host, - struct mmc_data *data, - struct dwmci_idmac *cur_idmac, - void *bounce_buffer) +static void dwmci_set_idma_desc64(struct dwmci_idmac64 *desc, u32 control, + u32 buf_size, u64 buf_addr) { - unsigned long ctrl; - unsigned int i = 0, flags, cnt, blk_cnt; - ulong data_start, data_end; + phys_addr_t desc_phys = virt_to_phys(desc); + u64 next_desc_phys = desc_phys + sizeof(struct dwmci_idmac64); + + desc->des0 = control; + desc->des1 = 0; + desc->des2 = buf_size; + desc->des3 = 0; + desc->des4 = buf_addr & 0xffffffff; + desc->des5 = buf_addr >> 32; + desc->des6 = next_desc_phys & 0xffffffff; + desc->des7 = next_desc_phys >> 32; +} +static void dwmci_prepare_desc(struct dwmci_host *host, struct mmc_data *data, + void *cur_idmac, void *bounce_buffer) +{ + struct dwmci_idmac32 *desc32 = cur_idmac; + struct dwmci_idmac64 *desc64 = cur_idmac; + ulong data_start, data_end; + unsigned int blk_cnt, i; + data_start = (ulong)cur_idmac; blk_cnt = data->blocks; - dwmci_wait_reset(host, DWMCI_CTRL_FIFO_RESET); + for (i = 0;; i++) { + phys_addr_t buf_phys = virt_to_phys(bounce_buffer); + unsigned int flags, cnt; - /* Clear IDMAC interrupt */ - dwmci_writel(host, DWMCI_IDSTS, 0xFFFFFFFF); - - data_start = (ulong)cur_idmac; - dwmci_writel(host, DWMCI_DBADDR, (ulong)cur_idmac); - - do { - flags = DWMCI_IDMAC_OWN | DWMCI_IDMAC_CH ; - flags |= (i == 0) ? DWMCI_IDMAC_FS : 0; + flags = DWMCI_IDMAC_OWN | DWMCI_IDMAC_CH; + if (i == 0) + flags |= DWMCI_IDMAC_FS; if (blk_cnt <= 8) { flags |= DWMCI_IDMAC_LD; cnt = data->blocksize * blk_cnt; - } else + } else { cnt = data->blocksize * 8; + } - dwmci_set_idma_desc(cur_idmac, flags, cnt, - (ulong)bounce_buffer + (i * PAGE_SIZE)); + if (host->dma_64bit_address) { + dwmci_set_idma_desc64(desc64, flags, cnt, + buf_phys + i * PAGE_SIZE); + desc64++; + } else { + dwmci_set_idma_desc32(desc32, flags, cnt, + buf_phys + i * PAGE_SIZE); + desc32++; + } - cur_idmac++; if (blk_cnt <= 8) break; blk_cnt -= 8; - i++; - } while(1); + } - data_end = (ulong)cur_idmac; + if (host->dma_64bit_address) + data_end = (ulong)desc64; + else + data_end = (ulong)desc32; flush_dcache_range(data_start, roundup(data_end, ARCH_DMA_MINALIGN)); +} + +static void dwmci_prepare_data(struct dwmci_host *host, struct mmc_data *data, + void *cur_idmac, void *bounce_buffer) +{ + const u32 idmacl = virt_to_phys(cur_idmac) & 0xffffffff; + const u32 idmacu = (u64)virt_to_phys(cur_idmac) >> 32; + unsigned long ctrl; + + dwmci_wait_reset(host, DWMCI_CTRL_FIFO_RESET); + + /* Clear IDMAC interrupt */ + dwmci_writel(host, host->regs->idsts, 0xffffffff); + + dwmci_writel(host, host->regs->dbaddrl, idmacl); + if (host->dma_64bit_address) + dwmci_writel(host, host->regs->dbaddru, idmacu); + + dwmci_prepare_desc(host, data, cur_idmac, bounce_buffer); ctrl = dwmci_readl(host, DWMCI_CTRL); ctrl |= DWMCI_IDMAC_EN | DWMCI_DMA_EN; @@ -134,90 +214,86 @@ static unsigned int dwmci_get_timeout(struct mmc *mmc, const unsigned int size) return timeout; } -static int dwmci_data_transfer(struct dwmci_host *host, struct mmc_data *data) +static int dwmci_data_transfer_fifo(struct dwmci_host *host, + struct mmc_data *data, u32 mask) { - struct mmc *mmc = host->mmc; + const u32 int_rx = mask & (DWMCI_INTMSK_RXDR | DWMCI_INTMSK_DTO); + const u32 int_tx = mask & DWMCI_INTMSK_TXDR; int ret = 0; - u32 timeout, mask, size, i, len = 0; - u32 *buf = NULL; - ulong start = get_timer(0); - u32 fifo_depth = (((host->fifoth_val & RX_WMARK_MASK) >> - RX_WMARK_SHIFT) + 1) * 2; + u32 len = 0, size, i; + u32 *buf; + + size = (data->blocksize * data->blocks) / 4; + if (!host->fifo_mode || !size) + return 0; - size = data->blocksize * data->blocks; if (data->flags == MMC_DATA_READ) buf = (unsigned int *)data->dest; else buf = (unsigned int *)data->src; - timeout = dwmci_get_timeout(mmc, size); + if (data->flags == MMC_DATA_READ && int_rx) { + dwmci_writel(host, DWMCI_RINTSTS, int_rx); + while (size) { + ret = dwmci_fifo_ready(host, DWMCI_FIFO_EMPTY, &len); + if (ret < 0) + break; + + len = (len >> DWMCI_FIFO_SHIFT) & DWMCI_FIFO_MASK; + len = min(size, len); + for (i = 0; i < len; i++) + *buf++ = dwmci_readl(host, DWMCI_DATA); + size = size > len ? (size - len) : 0; + } + } else if (data->flags == MMC_DATA_WRITE && int_tx) { + while (size) { + ret = dwmci_fifo_ready(host, DWMCI_FIFO_FULL, &len); + if (ret < 0) + break; + + len = host->fifo_depth - ((len >> DWMCI_FIFO_SHIFT) & + DWMCI_FIFO_MASK); + len = min(size, len); + for (i = 0; i < len; i++) + dwmci_writel(host, DWMCI_DATA, *buf++); + size = size > len ? (size - len) : 0; + } + dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_TXDR); + } + + return ret; +} - size /= 4; +static int dwmci_data_transfer(struct dwmci_host *host, struct mmc_data *data) +{ + struct mmc *mmc = host->mmc; + int ret = 0; + u32 timeout, mask, size; + ulong start = get_timer(0); + + size = data->blocksize * data->blocks; + timeout = dwmci_get_timeout(mmc, size); for (;;) { mask = dwmci_readl(host, DWMCI_RINTSTS); - /* Error during data transfer. */ + /* Error during data transfer */ if (mask & (DWMCI_DATA_ERR | DWMCI_DATA_TOUT)) { debug("%s: DATA ERROR!\n", __func__); ret = -EINVAL; break; } - if (host->fifo_mode && size) { - len = 0; - if (data->flags == MMC_DATA_READ && - (mask & (DWMCI_INTMSK_RXDR | DWMCI_INTMSK_DTO))) { - dwmci_writel(host, DWMCI_RINTSTS, - mask & (DWMCI_INTMSK_RXDR | - DWMCI_INTMSK_DTO)); - while (size) { - ret = dwmci_fifo_ready(host, - DWMCI_FIFO_EMPTY, - &len); - if (ret < 0) - break; - - len = (len >> DWMCI_FIFO_SHIFT) & - DWMCI_FIFO_MASK; - len = min(size, len); - for (i = 0; i < len; i++) - *buf++ = - dwmci_readl(host, DWMCI_DATA); - size = size > len ? (size - len) : 0; - } - } else if (data->flags == MMC_DATA_WRITE && - (mask & DWMCI_INTMSK_TXDR)) { - while (size) { - ret = dwmci_fifo_ready(host, - DWMCI_FIFO_FULL, - &len); - if (ret < 0) - break; - - len = fifo_depth - ((len >> - DWMCI_FIFO_SHIFT) & - DWMCI_FIFO_MASK); - len = min(size, len); - for (i = 0; i < len; i++) - dwmci_writel(host, DWMCI_DATA, - *buf++); - size = size > len ? (size - len) : 0; - } - dwmci_writel(host, DWMCI_RINTSTS, - DWMCI_INTMSK_TXDR); - } - } + ret = dwmci_data_transfer_fifo(host, data, mask); - /* Data arrived correctly. */ + /* Data arrived correctly */ if (mask & DWMCI_INTMSK_DTO) { ret = 0; break; } - /* Check for timeout. */ + /* Check for timeout */ if (get_timer(start) > timeout) { - debug("%s: Timeout waiting for data!\n", - __func__); + debug("%s: Timeout waiting for data!\n", __func__); ret = -ETIMEDOUT; break; } @@ -228,8 +304,35 @@ static int dwmci_data_transfer(struct dwmci_host *host, struct mmc_data *data) return ret; } +static int dwmci_dma_transfer(struct dwmci_host *host, uint flags, + struct bounce_buffer *bbstate) +{ + int ret; + u32 mask, ctrl; + + if (flags == MMC_DATA_READ) + mask = DWMCI_IDINTEN_RI; + else + mask = DWMCI_IDINTEN_TI; + + ret = wait_for_bit_le32(host->ioaddr + host->regs->idsts, mask, true, + 1000, false); + if (ret) + debug("%s: DWMCI_IDINTEN mask 0x%x timeout\n", __func__, mask); + + /* Clear interrupts */ + dwmci_writel(host, host->regs->idsts, DWMCI_IDINTEN_MASK); + + ctrl = dwmci_readl(host, DWMCI_CTRL); + ctrl &= ~DWMCI_DMA_EN; + dwmci_writel(host, DWMCI_CTRL, ctrl); + + bounce_buffer_stop(bbstate); + return ret; +} + static int dwmci_set_transfer_mode(struct dwmci_host *host, - struct mmc_data *data) + struct mmc_data *data) { unsigned long mode; @@ -240,33 +343,30 @@ static int dwmci_set_transfer_mode(struct dwmci_host *host, return mode; } -#ifdef CONFIG_DM_MMC -static int dwmci_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, - struct mmc_data *data) +static void dwmci_wait_while_busy(struct dwmci_host *host, struct mmc_cmd *cmd) { - struct mmc *mmc = mmc_get_mmc_dev(dev); -#else -static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, - struct mmc_data *data) -{ -#endif - struct dwmci_host *host = mmc->priv; - ALLOC_CACHE_ALIGN_BUFFER(struct dwmci_idmac, cur_idmac, - data ? DIV_ROUND_UP(data->blocks, 8) : 0); - int ret = 0, flags = 0, i; - unsigned int timeout = 500; - u32 retry = 100000; - u32 mask, ctrl; - ulong start = get_timer(0); - struct bounce_buffer bbstate; + unsigned int timeout = 500; /* msec */ + ulong start; + start = get_timer(0); while (dwmci_readl(host, DWMCI_STATUS) & DWMCI_BUSY) { if (get_timer(start) > timeout) { - debug("%s: Timeout on data busy, continue anyway\n", __func__); + debug("%s: Timeout on data busy, continue anyway\n", + __func__); break; } } +} +static int dwmci_send_cmd_common(struct dwmci_host *host, struct mmc_cmd *cmd, + struct mmc_data *data, void *cur_idmac) +{ + int ret, flags = 0, i; + u32 retry = 100000; + u32 mask; + struct bounce_buffer bbstate; + + dwmci_wait_while_busy(host, cmd); dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_ALL); if (data) { @@ -278,12 +378,12 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, } else { if (data->flags == MMC_DATA_READ) { ret = bounce_buffer_start(&bbstate, - (void*)data->dest, + (void *)data->dest, data->blocksize * data->blocks, GEN_BB_WRITE); } else { ret = bounce_buffer_start(&bbstate, - (void*)data->src, + (void *)data->src, data->blocksize * data->blocks, GEN_BB_READ); } @@ -318,9 +418,9 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, if (cmd->resp_type & MMC_RSP_CRC) flags |= DWMCI_CMD_CHECK_CRC; - flags |= (cmd->cmdidx | DWMCI_CMD_START | DWMCI_CMD_USE_HOLD_REG); + flags |= cmd->cmdidx | DWMCI_CMD_START | DWMCI_CMD_USE_HOLD_REG; - debug("Sending CMD%d\n",cmd->cmdidx); + debug("Sending CMD%d\n", cmd->cmdidx); dwmci_writel(host, DWMCI_CMD, flags); @@ -334,7 +434,7 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, } if (i == retry) { - debug("%s: Timeout.\n", __func__); + debug("%s: Timeout\n", __func__); return -ETIMEDOUT; } @@ -347,18 +447,17 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, * below shall be debug(). eMMC cards also do not favor * CMD8, please keep that in mind. */ - debug("%s: Response Timeout.\n", __func__); + debug("%s: Response Timeout\n", __func__); return -ETIMEDOUT; } else if (mask & DWMCI_INTMSK_RE) { - debug("%s: Response Error.\n", __func__); + debug("%s: Response Error\n", __func__); return -EIO; } else if ((cmd->resp_type & MMC_RSP_CRC) && (mask & DWMCI_INTMSK_RCRC)) { - debug("%s: Response CRC Error.\n", __func__); + debug("%s: Response CRC Error\n", __func__); return -EIO; } - if (cmd->resp_type & MMC_RSP_PRESENT) { if (cmd->resp_type & MMC_RSP_136) { cmd->response[0] = dwmci_readl(host, DWMCI_RESP3); @@ -372,26 +471,8 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, if (data) { ret = dwmci_data_transfer(host, data); - - /* only dma mode need it */ - if (!host->fifo_mode) { - if (data->flags == MMC_DATA_READ) - mask = DWMCI_IDINTEN_RI; - else - mask = DWMCI_IDINTEN_TI; - ret = wait_for_bit_le32(host->ioaddr + DWMCI_IDSTS, - mask, true, 1000, false); - if (ret) - debug("%s: DWMCI_IDINTEN mask 0x%x timeout.\n", - __func__, mask); - /* clear interrupts */ - dwmci_writel(host, DWMCI_IDSTS, DWMCI_IDINTEN_MASK); - - ctrl = dwmci_readl(host, DWMCI_CTRL); - ctrl &= ~(DWMCI_DMA_EN); - dwmci_writel(host, DWMCI_CTRL, ctrl); - bounce_buffer_stop(&bbstate); - } + if (!host->fifo_mode) + ret = dwmci_dma_transfer(host, data->flags, &bbstate); } udelay(100); @@ -399,40 +480,39 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, return ret; } -static int dwmci_setup_bus(struct dwmci_host *host, u32 freq) +#ifdef CONFIG_DM_MMC +static int dwmci_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, + struct mmc_data *data) { - u32 div, status; - int timeout = 10000; - unsigned long sclk; + struct mmc *mmc = mmc_get_mmc_dev(dev); +#else +static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, + struct mmc_data *data) +{ +#endif + struct dwmci_host *host = mmc->priv; + const size_t buf_size = data ? DIV_ROUND_UP(data->blocks, 8) : 0; - if ((freq == host->clock) || (freq == 0)) - return 0; - /* - * If host->get_mmc_clk isn't defined, - * then assume that host->bus_hz is source clock value. - * host->bus_hz should be set by user. - */ - if (host->get_mmc_clk) - sclk = host->get_mmc_clk(host, freq); - else if (host->bus_hz) - sclk = host->bus_hz; - else { - debug("%s: Didn't get source clock value.\n", __func__); - return -EINVAL; + if (host->dma_64bit_address) { + ALLOC_CACHE_ALIGN_BUFFER(struct dwmci_idmac64, idmac, buf_size); + return dwmci_send_cmd_common(host, cmd, data, idmac); + } else { + ALLOC_CACHE_ALIGN_BUFFER(struct dwmci_idmac32, idmac, buf_size); + return dwmci_send_cmd_common(host, cmd, data, idmac); } +} - if (sclk == freq) - div = 0; /* bypass mode */ - else - div = DIV_ROUND_UP(sclk, 2 * freq); - - dwmci_writel(host, DWMCI_CLKENA, 0); - dwmci_writel(host, DWMCI_CLKSRC, 0); +static int dwmci_control_clken(struct dwmci_host *host, bool on) +{ + const u32 val = on ? DWMCI_CLKEN_ENABLE | DWMCI_CLKEN_LOW_PWR : 0; + const u32 cmd_only_clk = DWMCI_CMD_PRV_DAT_WAIT | DWMCI_CMD_UPD_CLK; + int timeout = 10000; + u32 status; - dwmci_writel(host, DWMCI_CLKDIV, div); - dwmci_writel(host, DWMCI_CMD, DWMCI_CMD_PRV_DAT_WAIT | - DWMCI_CMD_UPD_CLK | DWMCI_CMD_START); + dwmci_writel(host, DWMCI_CLKENA, val); + /* Inform CIU */ + dwmci_writel(host, DWMCI_CMD, DWMCI_CMD_START | cmd_only_clk); do { status = dwmci_readl(host, DWMCI_CMD); if (timeout-- < 0) { @@ -441,20 +521,62 @@ static int dwmci_setup_bus(struct dwmci_host *host, u32 freq) } } while (status & DWMCI_CMD_START); - dwmci_writel(host, DWMCI_CLKENA, DWMCI_CLKEN_ENABLE | - DWMCI_CLKEN_LOW_PWR); + return 0; +} + +/* + * Update the clock divider. + * + * To prevent a clock glitch keep the clock stopped during the update of + * clock divider and clock source. + */ +static int dwmci_update_div(struct dwmci_host *host, u32 div) +{ + int ret; + + /* Disable clock */ + ret = dwmci_control_clken(host, false); + if (ret) + return ret; - dwmci_writel(host, DWMCI_CMD, DWMCI_CMD_PRV_DAT_WAIT | - DWMCI_CMD_UPD_CLK | DWMCI_CMD_START); + /* Set clock to desired speed */ + dwmci_writel(host, DWMCI_CLKDIV, div); + dwmci_writel(host, DWMCI_CLKSRC, 0); - timeout = 10000; - do { - status = dwmci_readl(host, DWMCI_CMD); - if (timeout-- < 0) { - debug("%s: Timeout!\n", __func__); - return -ETIMEDOUT; - } - } while (status & DWMCI_CMD_START); + /* Enable clock */ + return dwmci_control_clken(host, true); +} + +static int dwmci_setup_bus(struct dwmci_host *host, u32 freq) +{ + u32 div; + unsigned long sclk; + int ret; + + if (freq == host->clock || freq == 0) + return 0; + + /* + * If host->get_mmc_clk isn't defined, then assume that host->bus_hz is + * source clock value. host->bus_hz should be set by user. + */ + if (host->get_mmc_clk) { + sclk = host->get_mmc_clk(host, freq); + } else if (host->bus_hz) { + sclk = host->bus_hz; + } else { + debug("%s: Didn't get source clock value\n", __func__); + return -EINVAL; + } + + if (sclk == freq) + div = 0; /* bypass mode */ + else + div = DIV_ROUND_UP(sclk, 2 * freq); + + ret = dwmci_update_div(host, div); + if (ret) + return ret; host->clock = freq; @@ -472,7 +594,7 @@ static int dwmci_set_ios(struct mmc *mmc) struct dwmci_host *host = (struct dwmci_host *)mmc->priv; u32 ctype, regs; - debug("Buswidth = %d, clock: %d\n", mmc->bus_width, mmc->clock); + debug("Bus width = %d, clock: %d\n", mmc->bus_width, mmc->clock); dwmci_setup_bus(host, mmc->clock); switch (mmc->bus_width) { @@ -527,6 +649,48 @@ static int dwmci_set_ios(struct mmc *mmc) return 0; } +static void dwmci_init_fifo(struct dwmci_host *host) +{ + u32 fifo_thr, fifoth_val; + + if (!host->fifo_depth) { + u32 fifo_size; + + /* + * Automatically detect FIFO depth from FIFOTH register. + * Power-on value of RX_WMark is FIFO_DEPTH-1. + */ + fifo_size = dwmci_readl(host, DWMCI_FIFOTH); + fifo_size = ((fifo_size & RX_WMARK_MASK) >> RX_WMARK_SHIFT) + 1; + host->fifo_depth = fifo_size; + } + + fifo_thr = host->fifo_depth / 2; + fifoth_val = MSIZE(0x2) | RX_WMARK(fifo_thr - 1) | TX_WMARK(fifo_thr); + dwmci_writel(host, DWMCI_FIFOTH, fifoth_val); +} + +static void dwmci_init_dma(struct dwmci_host *host) +{ + int addr_config; + + if (host->fifo_mode) + return; + + addr_config = (dwmci_readl(host, DWMCI_HCON) >> 27) & 0x1; + if (addr_config == 1) { + host->dma_64bit_address = true; + host->regs = &dwmci_idmac_regs64; + debug("%s: IDMAC supports 64-bit address mode\n", __func__); + } else { + host->dma_64bit_address = false; + host->regs = &dwmci_idmac_regs32; + debug("%s: IDMAC supports 32-bit address mode\n", __func__); + } + + dwmci_writel(host, host->regs->idinten, DWMCI_IDINTEN_MASK); +} + static int dwmci_init(struct mmc *mmc) { struct dwmci_host *host = mmc->priv; @@ -544,30 +708,18 @@ static int dwmci_init(struct mmc *mmc) /* Enumerate at 400KHz */ dwmci_setup_bus(host, mmc->cfg->f_min); - dwmci_writel(host, DWMCI_RINTSTS, 0xFFFFFFFF); + dwmci_writel(host, DWMCI_RINTSTS, 0xffffffff); dwmci_writel(host, DWMCI_INTMASK, 0); - dwmci_writel(host, DWMCI_TMOUT, 0xFFFFFFFF); + dwmci_writel(host, DWMCI_TMOUT, 0xffffffff); - dwmci_writel(host, DWMCI_IDINTEN, 0); dwmci_writel(host, DWMCI_BMOD, 1); - - if (!host->fifoth_val) { - uint32_t fifo_size; - - fifo_size = dwmci_readl(host, DWMCI_FIFOTH); - fifo_size = ((fifo_size & RX_WMARK_MASK) >> RX_WMARK_SHIFT) + 1; - host->fifoth_val = MSIZE(0x2) | RX_WMARK(fifo_size / 2 - 1) | - TX_WMARK(fifo_size / 2); - } - dwmci_writel(host, DWMCI_FIFOTH, host->fifoth_val); + dwmci_init_fifo(host); + dwmci_init_dma(host); dwmci_writel(host, DWMCI_CLKENA, 0); dwmci_writel(host, DWMCI_CLKSRC, 0); - if (!host->fifo_mode) - dwmci_writel(host, DWMCI_IDINTEN, DWMCI_IDINTEN_MASK); - return 0; } @@ -593,7 +745,7 @@ static const struct mmc_ops dwmci_ops = { #endif void dwmci_setup_cfg(struct mmc_config *cfg, struct dwmci_host *host, - u32 max_clk, u32 min_clk) + u32 max_clk, u32 min_clk) { cfg->name = host->name; #ifndef CONFIG_DM_MMC @@ -629,7 +781,7 @@ int add_dwmci(struct dwmci_host *host, u32 max_clk, u32 min_clk) dwmci_setup_cfg(&host->cfg, host, max_clk, min_clk); host->mmc = mmc_create(&host->cfg, host); - if (host->mmc == NULL) + if (!host->mmc) return -1; return 0; |