diff options
Diffstat (limited to 'roms/u-boot/drivers/mmc/tmio-common.c')
-rw-r--r-- | roms/u-boot/drivers/mmc/tmio-common.c | 783 |
1 files changed, 783 insertions, 0 deletions
diff --git a/roms/u-boot/drivers/mmc/tmio-common.c b/roms/u-boot/drivers/mmc/tmio-common.c new file mode 100644 index 000000000..e9c7d3a2e --- /dev/null +++ b/roms/u-boot/drivers/mmc/tmio-common.c @@ -0,0 +1,783 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Socionext Inc. + * Author: Masahiro Yamada <yamada.masahiro@socionext.com> + */ + +#include <common.h> +#include <clk.h> +#include <cpu_func.h> +#include <fdtdec.h> +#include <mmc.h> +#include <dm.h> +#include <asm/global_data.h> +#include <dm/device_compat.h> +#include <dm/pinctrl.h> +#include <linux/compat.h> +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/io.h> +#include <linux/sizes.h> +#include <power/regulator.h> +#include <asm/unaligned.h> + +#include "tmio-common.h" + +DECLARE_GLOBAL_DATA_PTR; + +static u64 tmio_sd_readq(struct tmio_sd_priv *priv, unsigned int reg) +{ + return readq(priv->regbase + (reg << 1)); +} + +static void tmio_sd_writeq(struct tmio_sd_priv *priv, + u64 val, unsigned int reg) +{ + writeq(val, priv->regbase + (reg << 1)); +} + +static u16 tmio_sd_readw(struct tmio_sd_priv *priv, unsigned int reg) +{ + return readw(priv->regbase + (reg >> 1)); +} + +static void tmio_sd_writew(struct tmio_sd_priv *priv, + u16 val, unsigned int reg) +{ + writew(val, priv->regbase + (reg >> 1)); +} + +u32 tmio_sd_readl(struct tmio_sd_priv *priv, unsigned int reg) +{ + u32 val; + + if (priv->caps & TMIO_SD_CAP_64BIT) + return readl(priv->regbase + (reg << 1)); + else if (priv->caps & TMIO_SD_CAP_16BIT) { + val = readw(priv->regbase + (reg >> 1)) & 0xffff; + if ((reg == TMIO_SD_RSP10) || (reg == TMIO_SD_RSP32) || + (reg == TMIO_SD_RSP54) || (reg == TMIO_SD_RSP76)) { + val |= readw(priv->regbase + (reg >> 1) + 2) << 16; + } + return val; + } else + return readl(priv->regbase + reg); +} + +void tmio_sd_writel(struct tmio_sd_priv *priv, + u32 val, unsigned int reg) +{ + if (priv->caps & TMIO_SD_CAP_64BIT) + writel(val, priv->regbase + (reg << 1)); + else if (priv->caps & TMIO_SD_CAP_16BIT) { + writew(val & 0xffff, priv->regbase + (reg >> 1)); + if (reg == TMIO_SD_INFO1 || reg == TMIO_SD_INFO1_MASK || + reg == TMIO_SD_INFO2 || reg == TMIO_SD_INFO2_MASK || + reg == TMIO_SD_ARG) + writew(val >> 16, priv->regbase + (reg >> 1) + 2); + } else + writel(val, priv->regbase + reg); +} + +static int tmio_sd_check_error(struct udevice *dev, struct mmc_cmd *cmd) +{ + struct tmio_sd_priv *priv = dev_get_priv(dev); + u32 info2 = tmio_sd_readl(priv, TMIO_SD_INFO2); + + if (info2 & TMIO_SD_INFO2_ERR_RTO) { + /* + * TIMEOUT must be returned for unsupported command. Do not + * display error log since this might be a part of sequence to + * distinguish between SD and MMC. + */ + return -ETIMEDOUT; + } + + if (info2 & TMIO_SD_INFO2_ERR_TO) { + dev_err(dev, "timeout error\n"); + return -ETIMEDOUT; + } + + if (info2 & (TMIO_SD_INFO2_ERR_END | TMIO_SD_INFO2_ERR_CRC | + TMIO_SD_INFO2_ERR_IDX)) { + if ((cmd->cmdidx != MMC_CMD_SEND_TUNING_BLOCK) && + (cmd->cmdidx != MMC_CMD_SEND_TUNING_BLOCK_HS200)) + dev_err(dev, "communication out of sync\n"); + return -EILSEQ; + } + + if (info2 & (TMIO_SD_INFO2_ERR_ILA | TMIO_SD_INFO2_ERR_ILR | + TMIO_SD_INFO2_ERR_ILW)) { + dev_err(dev, "illegal access\n"); + return -EIO; + } + + return 0; +} + +static int tmio_sd_wait_for_irq(struct udevice *dev, struct mmc_cmd *cmd, + unsigned int reg, u32 flag) +{ + struct tmio_sd_priv *priv = dev_get_priv(dev); + long wait = 1000000; + int ret; + + while (!(tmio_sd_readl(priv, reg) & flag)) { + if (wait-- < 0) { + dev_err(dev, "timeout\n"); + return -ETIMEDOUT; + } + + ret = tmio_sd_check_error(dev, cmd); + if (ret) + return ret; + + udelay(1); + } + + return 0; +} + +#define tmio_pio_read_fifo(__width, __suffix) \ +static void tmio_pio_read_fifo_##__width(struct tmio_sd_priv *priv, \ + char *pbuf, uint blksz) \ +{ \ + u##__width *buf = (u##__width *)pbuf; \ + int i; \ + \ + if (likely(IS_ALIGNED((uintptr_t)buf, ((__width) / 8)))) { \ + for (i = 0; i < blksz / ((__width) / 8); i++) { \ + *buf++ = tmio_sd_read##__suffix(priv, \ + TMIO_SD_BUF); \ + } \ + } else { \ + for (i = 0; i < blksz / ((__width) / 8); i++) { \ + u##__width data; \ + data = tmio_sd_read##__suffix(priv, \ + TMIO_SD_BUF); \ + put_unaligned(data, buf++); \ + } \ + } \ +} + +tmio_pio_read_fifo(64, q) +tmio_pio_read_fifo(32, l) +tmio_pio_read_fifo(16, w) + +static int tmio_sd_pio_read_one_block(struct udevice *dev, struct mmc_cmd *cmd, + char *pbuf, uint blocksize) +{ + struct tmio_sd_priv *priv = dev_get_priv(dev); + int ret; + + /* wait until the buffer is filled with data */ + ret = tmio_sd_wait_for_irq(dev, cmd, TMIO_SD_INFO2, + TMIO_SD_INFO2_BRE); + if (ret) + return ret; + + /* + * Clear the status flag _before_ read the buffer out because + * TMIO_SD_INFO2_BRE is edge-triggered, not level-triggered. + */ + tmio_sd_writel(priv, 0, TMIO_SD_INFO2); + + if (priv->caps & TMIO_SD_CAP_64BIT) + tmio_pio_read_fifo_64(priv, pbuf, blocksize); + else if (priv->caps & TMIO_SD_CAP_16BIT) + tmio_pio_read_fifo_16(priv, pbuf, blocksize); + else + tmio_pio_read_fifo_32(priv, pbuf, blocksize); + + return 0; +} + +#define tmio_pio_write_fifo(__width, __suffix) \ +static void tmio_pio_write_fifo_##__width(struct tmio_sd_priv *priv, \ + const char *pbuf, uint blksz)\ +{ \ + const u##__width *buf = (const u##__width *)pbuf; \ + int i; \ + \ + if (likely(IS_ALIGNED((uintptr_t)buf, ((__width) / 8)))) { \ + for (i = 0; i < blksz / ((__width) / 8); i++) { \ + tmio_sd_write##__suffix(priv, *buf++, \ + TMIO_SD_BUF); \ + } \ + } else { \ + for (i = 0; i < blksz / ((__width) / 8); i++) { \ + u##__width data = get_unaligned(buf++); \ + tmio_sd_write##__suffix(priv, data, \ + TMIO_SD_BUF); \ + } \ + } \ +} + +tmio_pio_write_fifo(64, q) +tmio_pio_write_fifo(32, l) +tmio_pio_write_fifo(16, w) + +static int tmio_sd_pio_write_one_block(struct udevice *dev, struct mmc_cmd *cmd, + const char *pbuf, uint blocksize) +{ + struct tmio_sd_priv *priv = dev_get_priv(dev); + int ret; + + /* wait until the buffer becomes empty */ + ret = tmio_sd_wait_for_irq(dev, cmd, TMIO_SD_INFO2, + TMIO_SD_INFO2_BWE); + if (ret) + return ret; + + tmio_sd_writel(priv, 0, TMIO_SD_INFO2); + + if (priv->caps & TMIO_SD_CAP_64BIT) + tmio_pio_write_fifo_64(priv, pbuf, blocksize); + else if (priv->caps & TMIO_SD_CAP_16BIT) + tmio_pio_write_fifo_16(priv, pbuf, blocksize); + else + tmio_pio_write_fifo_32(priv, pbuf, blocksize); + + return 0; +} + +static int tmio_sd_pio_xfer(struct udevice *dev, struct mmc_cmd *cmd, + struct mmc_data *data) +{ + const char *src = data->src; + char *dest = data->dest; + int i, ret; + + for (i = 0; i < data->blocks; i++) { + if (data->flags & MMC_DATA_READ) + ret = tmio_sd_pio_read_one_block(dev, cmd, dest, + data->blocksize); + else + ret = tmio_sd_pio_write_one_block(dev, cmd, src, + data->blocksize); + if (ret) + return ret; + + if (data->flags & MMC_DATA_READ) + dest += data->blocksize; + else + src += data->blocksize; + } + + return 0; +} + +static void tmio_sd_dma_start(struct tmio_sd_priv *priv, + dma_addr_t dma_addr) +{ + u32 tmp; + + tmio_sd_writel(priv, 0, TMIO_SD_DMA_INFO1); + tmio_sd_writel(priv, 0, TMIO_SD_DMA_INFO2); + + /* enable DMA */ + tmp = tmio_sd_readl(priv, TMIO_SD_EXTMODE); + tmp |= TMIO_SD_EXTMODE_DMA_EN; + tmio_sd_writel(priv, tmp, TMIO_SD_EXTMODE); + + tmio_sd_writel(priv, dma_addr & U32_MAX, TMIO_SD_DMA_ADDR_L); + + /* suppress the warning "right shift count >= width of type" */ + dma_addr >>= min_t(int, 32, 8 * sizeof(dma_addr)); + + tmio_sd_writel(priv, dma_addr & U32_MAX, TMIO_SD_DMA_ADDR_H); + + tmio_sd_writel(priv, TMIO_SD_DMA_CTL_START, TMIO_SD_DMA_CTL); +} + +static int tmio_sd_dma_wait_for_irq(struct udevice *dev, u32 flag, + unsigned int blocks) +{ + struct tmio_sd_priv *priv = dev_get_priv(dev); + long wait = 1000000 + 10 * blocks; + + while (!(tmio_sd_readl(priv, TMIO_SD_DMA_INFO1) & flag)) { + if (wait-- < 0) { + dev_err(dev, "timeout during DMA\n"); + return -ETIMEDOUT; + } + + udelay(10); + } + + if (tmio_sd_readl(priv, TMIO_SD_DMA_INFO2)) { + dev_err(dev, "error during DMA\n"); + return -EIO; + } + + return 0; +} + +static int tmio_sd_dma_xfer(struct udevice *dev, struct mmc_data *data) +{ + struct tmio_sd_priv *priv = dev_get_priv(dev); + size_t len = data->blocks * data->blocksize; + void *buf; + enum dma_data_direction dir; + dma_addr_t dma_addr; + u32 poll_flag, tmp; + int ret; + + tmp = tmio_sd_readl(priv, TMIO_SD_DMA_MODE); + + tmp |= priv->idma_bus_width; + + if (data->flags & MMC_DATA_READ) { + buf = data->dest; + dir = DMA_FROM_DEVICE; + /* + * The DMA READ completion flag position differs on Socionext + * and Renesas SoCs. It is bit 20 on Socionext SoCs and using + * bit 17 is a hardware bug and forbidden. It is either bit 17 + * or bit 20 on Renesas SoCs, depending on SoC. + */ + poll_flag = priv->read_poll_flag; + tmp |= TMIO_SD_DMA_MODE_DIR_RD; + } else { + buf = (void *)data->src; + dir = DMA_TO_DEVICE; + poll_flag = TMIO_SD_DMA_INFO1_END_WR; + tmp &= ~TMIO_SD_DMA_MODE_DIR_RD; + } + + tmio_sd_writel(priv, tmp, TMIO_SD_DMA_MODE); + + dma_addr = dma_map_single(buf, len, dir); + + tmio_sd_dma_start(priv, dma_addr); + + ret = tmio_sd_dma_wait_for_irq(dev, poll_flag, data->blocks); + + if (poll_flag == TMIO_SD_DMA_INFO1_END_RD) + udelay(1); + + dma_unmap_single(dma_addr, len, dir); + + return ret; +} + +/* check if the address is DMA'able */ +static bool tmio_sd_addr_is_dmaable(struct mmc_data *data) +{ + uintptr_t addr = (uintptr_t)data->src; + + if (!IS_ALIGNED(addr, TMIO_SD_DMA_MINALIGN)) + return false; + +#if defined(CONFIG_RCAR_GEN3) + if (!(data->flags & MMC_DATA_READ) && !IS_ALIGNED(addr, 128)) + return false; + /* Gen3 DMA has 32bit limit */ + if (addr >> 32) + return false; +#endif + +#if defined(CONFIG_ARCH_UNIPHIER) && !defined(CONFIG_ARM64) && \ + defined(CONFIG_SPL_BUILD) + /* + * For UniPhier ARMv7 SoCs, the stack is allocated in the locked ways + * of L2, which is unreachable from the DMA engine. + */ + if (addr < CONFIG_SPL_STACK) + return false; +#endif + + return true; +} + +int tmio_sd_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, + struct mmc_data *data) +{ + struct tmio_sd_priv *priv = dev_get_priv(dev); + int ret; + u32 tmp; + + if (tmio_sd_readl(priv, TMIO_SD_INFO2) & TMIO_SD_INFO2_CBSY) { + dev_err(dev, "command busy\n"); + return -EBUSY; + } + + /* clear all status flags */ + tmio_sd_writel(priv, 0, TMIO_SD_INFO1); + tmio_sd_writel(priv, 0, TMIO_SD_INFO2); + + /* disable DMA once */ + tmp = tmio_sd_readl(priv, TMIO_SD_EXTMODE); + tmp &= ~TMIO_SD_EXTMODE_DMA_EN; + tmio_sd_writel(priv, tmp, TMIO_SD_EXTMODE); + + tmio_sd_writel(priv, cmd->cmdarg, TMIO_SD_ARG); + + tmp = cmd->cmdidx; + + if (data) { + tmio_sd_writel(priv, data->blocksize, TMIO_SD_SIZE); + tmio_sd_writel(priv, data->blocks, TMIO_SD_SECCNT); + + /* Do not send CMD12 automatically */ + tmp |= TMIO_SD_CMD_NOSTOP | TMIO_SD_CMD_DATA; + + if (data->blocks > 1) + tmp |= TMIO_SD_CMD_MULTI; + + if (data->flags & MMC_DATA_READ) + tmp |= TMIO_SD_CMD_RD; + } + + /* + * Do not use the response type auto-detection on this hardware. + * CMD8, for example, has different response types on SD and eMMC, + * while this controller always assumes the response type for SD. + * Set the response type manually. + */ + switch (cmd->resp_type) { + case MMC_RSP_NONE: + tmp |= TMIO_SD_CMD_RSP_NONE; + break; + case MMC_RSP_R1: + tmp |= TMIO_SD_CMD_RSP_R1; + break; + case MMC_RSP_R1b: + tmp |= TMIO_SD_CMD_RSP_R1B; + break; + case MMC_RSP_R2: + tmp |= TMIO_SD_CMD_RSP_R2; + break; + case MMC_RSP_R3: + tmp |= TMIO_SD_CMD_RSP_R3; + break; + default: + dev_err(dev, "unknown response type\n"); + return -EINVAL; + } + + dev_dbg(dev, "sending CMD%d (SD_CMD=%08x, SD_ARG=%08x)\n", + cmd->cmdidx, tmp, cmd->cmdarg); + tmio_sd_writel(priv, tmp, TMIO_SD_CMD); + + ret = tmio_sd_wait_for_irq(dev, cmd, TMIO_SD_INFO1, + TMIO_SD_INFO1_RSP); + if (ret) + return ret; + + if (cmd->resp_type & MMC_RSP_136) { + u32 rsp_127_104 = tmio_sd_readl(priv, TMIO_SD_RSP76); + u32 rsp_103_72 = tmio_sd_readl(priv, TMIO_SD_RSP54); + u32 rsp_71_40 = tmio_sd_readl(priv, TMIO_SD_RSP32); + u32 rsp_39_8 = tmio_sd_readl(priv, TMIO_SD_RSP10); + + cmd->response[0] = ((rsp_127_104 & 0x00ffffff) << 8) | + ((rsp_103_72 & 0xff000000) >> 24); + cmd->response[1] = ((rsp_103_72 & 0x00ffffff) << 8) | + ((rsp_71_40 & 0xff000000) >> 24); + cmd->response[2] = ((rsp_71_40 & 0x00ffffff) << 8) | + ((rsp_39_8 & 0xff000000) >> 24); + cmd->response[3] = (rsp_39_8 & 0xffffff) << 8; + } else { + /* bit 39-8 */ + cmd->response[0] = tmio_sd_readl(priv, TMIO_SD_RSP10); + } + + if (data) { + /* use DMA if the HW supports it and the buffer is aligned */ + if (priv->caps & TMIO_SD_CAP_DMA_INTERNAL && + tmio_sd_addr_is_dmaable(data)) + ret = tmio_sd_dma_xfer(dev, data); + else + ret = tmio_sd_pio_xfer(dev, cmd, data); + if (ret) + return ret; + + ret = tmio_sd_wait_for_irq(dev, cmd, TMIO_SD_INFO1, + TMIO_SD_INFO1_CMP); + if (ret) + return ret; + } + + return tmio_sd_wait_for_irq(dev, cmd, TMIO_SD_INFO2, + TMIO_SD_INFO2_SCLKDIVEN); +} + +static int tmio_sd_set_bus_width(struct tmio_sd_priv *priv, + struct mmc *mmc) +{ + u32 val, tmp; + + switch (mmc->bus_width) { + case 0: + case 1: + val = TMIO_SD_OPTION_WIDTH_1; + break; + case 4: + val = TMIO_SD_OPTION_WIDTH_4; + break; + case 8: + val = TMIO_SD_OPTION_WIDTH_8; + break; + default: + return -EINVAL; + } + + tmp = tmio_sd_readl(priv, TMIO_SD_OPTION); + tmp &= ~TMIO_SD_OPTION_WIDTH_MASK; + tmp |= val; + tmio_sd_writel(priv, tmp, TMIO_SD_OPTION); + + return 0; +} + +static void tmio_sd_set_ddr_mode(struct tmio_sd_priv *priv, + struct mmc *mmc) +{ + u32 tmp; + + tmp = tmio_sd_readl(priv, TMIO_SD_IF_MODE); + if (mmc->ddr_mode) + tmp |= TMIO_SD_IF_MODE_DDR; + else + tmp &= ~TMIO_SD_IF_MODE_DDR; + tmio_sd_writel(priv, tmp, TMIO_SD_IF_MODE); +} + +static ulong tmio_sd_clk_get_rate(struct tmio_sd_priv *priv) +{ + return priv->clk_get_rate(priv); +} + +static void tmio_sd_set_clk_rate(struct tmio_sd_priv *priv, struct mmc *mmc) +{ + unsigned int divisor; + u32 tmp, val = 0; + ulong mclk; + + if (mmc->clock) { + mclk = tmio_sd_clk_get_rate(priv); + + divisor = DIV_ROUND_UP(mclk, mmc->clock); + + /* Do not set divider to 0xff in DDR mode */ + if (mmc->ddr_mode && (divisor == 1)) + divisor = 2; + + if (divisor <= 1) + val = (priv->caps & TMIO_SD_CAP_RCAR) ? + TMIO_SD_CLKCTL_RCAR_DIV1 : TMIO_SD_CLKCTL_DIV1; + else if (divisor <= 2) + val = TMIO_SD_CLKCTL_DIV2; + else if (divisor <= 4) + val = TMIO_SD_CLKCTL_DIV4; + else if (divisor <= 8) + val = TMIO_SD_CLKCTL_DIV8; + else if (divisor <= 16) + val = TMIO_SD_CLKCTL_DIV16; + else if (divisor <= 32) + val = TMIO_SD_CLKCTL_DIV32; + else if (divisor <= 64) + val = TMIO_SD_CLKCTL_DIV64; + else if (divisor <= 128) + val = TMIO_SD_CLKCTL_DIV128; + else if (divisor <= 256) + val = TMIO_SD_CLKCTL_DIV256; + else if (divisor <= 512 || !(priv->caps & TMIO_SD_CAP_DIV1024)) + val = TMIO_SD_CLKCTL_DIV512; + else + val = TMIO_SD_CLKCTL_DIV1024; + } + + tmp = tmio_sd_readl(priv, TMIO_SD_CLKCTL); + if (mmc->clock && + !((tmp & TMIO_SD_CLKCTL_SCLKEN) && + ((tmp & TMIO_SD_CLKCTL_DIV_MASK) == val))) { + /* + * Stop the clock before changing its rate + * to avoid a glitch signal + */ + tmp &= ~TMIO_SD_CLKCTL_SCLKEN; + tmio_sd_writel(priv, tmp, TMIO_SD_CLKCTL); + + /* Change the clock rate. */ + tmp &= ~TMIO_SD_CLKCTL_DIV_MASK; + tmp |= val; + } + + /* Enable or Disable the clock */ + if (mmc->clk_disable) { + tmp |= TMIO_SD_CLKCTL_OFFEN; + tmp &= ~TMIO_SD_CLKCTL_SCLKEN; + } else { + tmp &= ~TMIO_SD_CLKCTL_OFFEN; + tmp |= TMIO_SD_CLKCTL_SCLKEN; + } + + tmio_sd_writel(priv, tmp, TMIO_SD_CLKCTL); + + udelay(1000); +} + +static void tmio_sd_set_pins(struct udevice *dev) +{ + __maybe_unused struct mmc *mmc = mmc_get_mmc_dev(dev); + +#ifdef CONFIG_DM_REGULATOR + struct tmio_sd_priv *priv = dev_get_priv(dev); + + if (priv->vqmmc_dev) { + if (mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180) + regulator_set_value(priv->vqmmc_dev, 1800000); + else + regulator_set_value(priv->vqmmc_dev, 3300000); + regulator_set_enable(priv->vqmmc_dev, true); + } +#endif + +#ifdef CONFIG_PINCTRL + if (mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180) + pinctrl_select_state(dev, "state_uhs"); + else + pinctrl_select_state(dev, "default"); +#endif +} + +int tmio_sd_set_ios(struct udevice *dev) +{ + struct tmio_sd_priv *priv = dev_get_priv(dev); + struct mmc *mmc = mmc_get_mmc_dev(dev); + int ret; + + dev_dbg(dev, "clock %uHz, DDRmode %d, width %u\n", + mmc->clock, mmc->ddr_mode, mmc->bus_width); + + tmio_sd_set_clk_rate(priv, mmc); + ret = tmio_sd_set_bus_width(priv, mmc); + if (ret) + return ret; + tmio_sd_set_ddr_mode(priv, mmc); + tmio_sd_set_pins(dev); + + return 0; +} + +int tmio_sd_get_cd(struct udevice *dev) +{ + struct tmio_sd_priv *priv = dev_get_priv(dev); + + if (priv->caps & TMIO_SD_CAP_NONREMOVABLE) + return 1; + + return !!(tmio_sd_readl(priv, TMIO_SD_INFO1) & + TMIO_SD_INFO1_CD); +} + +static void tmio_sd_host_init(struct tmio_sd_priv *priv) +{ + u32 tmp; + + /* soft reset of the host */ + tmp = tmio_sd_readl(priv, TMIO_SD_SOFT_RST); + tmp &= ~TMIO_SD_SOFT_RST_RSTX; + tmio_sd_writel(priv, tmp, TMIO_SD_SOFT_RST); + tmp |= TMIO_SD_SOFT_RST_RSTX; + tmio_sd_writel(priv, tmp, TMIO_SD_SOFT_RST); + + /* FIXME: implement eMMC hw_reset */ + + tmio_sd_writel(priv, TMIO_SD_STOP_SEC, TMIO_SD_STOP); + + /* + * Connected to 32bit AXI. + * This register dropped backward compatibility at version 0x10. + * Write an appropriate value depending on the IP version. + */ + if (priv->version >= 0x10) { + if (priv->caps & TMIO_SD_CAP_64BIT) + tmio_sd_writel(priv, 0x000, TMIO_SD_HOST_MODE); + else + tmio_sd_writel(priv, 0x101, TMIO_SD_HOST_MODE); + } else { + tmio_sd_writel(priv, 0x0, TMIO_SD_HOST_MODE); + } + + if (priv->caps & TMIO_SD_CAP_DMA_INTERNAL) { + tmp = tmio_sd_readl(priv, TMIO_SD_DMA_MODE); + tmp |= TMIO_SD_DMA_MODE_ADDR_INC; + tmp |= priv->idma_bus_width; + tmio_sd_writel(priv, tmp, TMIO_SD_DMA_MODE); + } +} + +int tmio_sd_bind(struct udevice *dev) +{ + struct tmio_sd_plat *plat = dev_get_plat(dev); + + return mmc_bind(dev, &plat->mmc, &plat->cfg); +} + +int tmio_sd_probe(struct udevice *dev, u32 quirks) +{ + struct tmio_sd_plat *plat = dev_get_plat(dev); + struct tmio_sd_priv *priv = dev_get_priv(dev); + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); + fdt_addr_t base; + ulong mclk; + int ret; + + base = dev_read_addr(dev); + if (base == FDT_ADDR_T_NONE) + return -EINVAL; + + priv->regbase = devm_ioremap(dev, base, SZ_2K); + if (!priv->regbase) + return -ENOMEM; + +#ifdef CONFIG_DM_REGULATOR + device_get_supply_regulator(dev, "vqmmc-supply", &priv->vqmmc_dev); + if (priv->vqmmc_dev) + regulator_set_value(priv->vqmmc_dev, 3300000); +#endif + + ret = mmc_of_parse(dev, &plat->cfg); + if (ret < 0) { + dev_err(dev, "failed to parse host caps\n"); + return ret; + } + + plat->cfg.name = dev->name; + plat->cfg.host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; + + if (quirks) + priv->caps = quirks; + + priv->version = tmio_sd_readl(priv, TMIO_SD_VERSION) & + TMIO_SD_VERSION_IP; + dev_dbg(dev, "version %x\n", priv->version); + if (priv->version >= 0x10) { + priv->caps |= TMIO_SD_CAP_DMA_INTERNAL; + priv->caps |= TMIO_SD_CAP_DIV1024; + } + + if (fdt_get_property(gd->fdt_blob, dev_of_offset(dev), "non-removable", + NULL)) + priv->caps |= TMIO_SD_CAP_NONREMOVABLE; + + tmio_sd_host_init(priv); + + mclk = tmio_sd_clk_get_rate(priv); + + plat->cfg.voltages = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34; + plat->cfg.f_min = mclk / + (priv->caps & TMIO_SD_CAP_DIV1024 ? 1024 : 512); + plat->cfg.f_max = mclk; + if (quirks & TMIO_SD_CAP_16BIT) + plat->cfg.b_max = U16_MAX; /* max value of TMIO_SD_SECCNT */ + else + plat->cfg.b_max = U32_MAX; /* max value of TMIO_SD_SECCNT */ + + upriv->mmc = &plat->mmc; + + return 0; +} |