[U-Boot] [PATCH v2 0/3] UniPhier SD/eMMC controller driver

Masahiro Yamada (3): mmc: uniphier: add driver for UniPhier SD/MMC host controller ARM: uniphier: enable UniPhier SD/MMC host driver ARM: dts: uniphier: add SD/MMC host controller nodes
arch/arm/Kconfig | 1 + arch/arm/dts/uniphier-ph1-ld4-ref.dts | 4 + arch/arm/dts/uniphier-ph1-ld4.dtsi | 25 + arch/arm/dts/uniphier-ph1-ld6b-ref.dts | 4 + arch/arm/dts/uniphier-ph1-pro4-ref.dts | 8 + arch/arm/dts/uniphier-ph1-pro4.dtsi | 37 ++ arch/arm/dts/uniphier-ph1-pro5-4kbox.dts | 8 + arch/arm/dts/uniphier-ph1-pro5.dtsi | 24 + arch/arm/dts/uniphier-ph1-sld3-ref.dts | 4 + arch/arm/dts/uniphier-ph1-sld3.dtsi | 19 + arch/arm/dts/uniphier-ph1-sld8-ref.dts | 4 + arch/arm/dts/uniphier-ph1-sld8.dtsi | 25 + arch/arm/dts/uniphier-pinctrl.dtsi | 15 + arch/arm/dts/uniphier-proxstream2-gentil.dts | 4 + arch/arm/dts/uniphier-proxstream2-vodka.dts | 4 + arch/arm/dts/uniphier-proxstream2.dtsi | 24 + configs/uniphier_ld4_sld8_defconfig | 1 + configs/uniphier_pro4_defconfig | 1 + configs/uniphier_pro5_defconfig | 1 + configs/uniphier_pxs2_ld6b_defconfig | 1 + configs/uniphier_sld3_defconfig | 1 + doc/README.uniphier | 1 + drivers/mmc/Kconfig | 6 + drivers/mmc/Makefile | 1 + drivers/mmc/uniphier-sd.c | 721 +++++++++++++++++++++++++++ include/configs/uniphier.h | 4 + 26 files changed, 948 insertions(+) create mode 100644 drivers/mmc/uniphier-sd.c

Add a driver for the on-chip SD/eMMC host controller used by UniPhier SoC family.
Signed-off-by: Masahiro Yamada yamada.masahiro@socionext.com ---
Changes in v2: - Fix the divisor bug on the older IP (on PH1-LD4, PH1-sLD8, PH1-Pro4) - Increase time out because "mmc erase" can sometimes take long - Move HOST_MODE register setting to uniphier_sd_init() because this register does not need setting multipule times.
doc/README.uniphier | 1 + drivers/mmc/Kconfig | 6 + drivers/mmc/Makefile | 1 + drivers/mmc/uniphier-sd.c | 721 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 729 insertions(+) create mode 100644 drivers/mmc/uniphier-sd.c
diff --git a/doc/README.uniphier b/doc/README.uniphier index bcf0ac3..7cfff97 100644 --- a/doc/README.uniphier +++ b/doc/README.uniphier @@ -93,6 +93,7 @@ Supported devices
- UART (on-chip) - NAND + - SD/eMMC - USB 2.0 (EHCI) - USB 3.0 (xHCI) - LAN (on-board SMSC9118) diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 9f4b766..faffefd 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -37,4 +37,10 @@ config PIC32_SDHCI help Support for Microchip PIC32 SDHCI controller.
+config MMC_UNIPHIER + bool "UniPhier SD/MMC Host Controller support" + depends on ARCH_UNIPHIER + help + This selects support for the SD/MMC Host Controller on UniPhier SoCs. + endmenu diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index c9c3e3e..b85e4bf 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_SH_SDHI) += sh_sdhi.o obj-$(CONFIG_SOCFPGA_DWMMC) += socfpga_dw_mmc.o obj-$(CONFIG_SPEAR_SDHCI) += spear_sdhci.o obj-$(CONFIG_TEGRA_MMC) += tegra_mmc.o +obj-$(CONFIG_MMC_UNIPHIER) += uniphier-sd.o obj-$(CONFIG_ZYNQ_SDHCI) += zynq_sdhci.o
ifdef CONFIG_SPL_BUILD diff --git a/drivers/mmc/uniphier-sd.c b/drivers/mmc/uniphier-sd.c new file mode 100644 index 0000000..2974c68 --- /dev/null +++ b/drivers/mmc/uniphier-sd.c @@ -0,0 +1,721 @@ +/* + * Copyright (C) 2016 Masahiro Yamada yamada.masahiro@socionext.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <clk.h> +#include <fdtdec.h> +#include <mapmem.h> +#include <mmc.h> +#include <dm/device.h> +#include <linux/compat.h> +#include <linux/io.h> +#include <asm/unaligned.h> +#include <asm/dma-mapping.h> + +#define pr_err printf +#define pr_warn printf +#ifdef DEBUG +#define pr_debug printf +#else +#define pr_debug(...) +#endif +DECLARE_GLOBAL_DATA_PTR; + +#define UNIPHIER_SD_CMD 0x000 /* command */ +#define UNIPHIER_SD_CMD_NOSTOP BIT(14) /* No automatic CMD12 issue */ +#define UNIPHIER_SD_CMD_MULTI BIT(13) /* multiple block transfer */ +#define UNIPHIER_SD_CMD_RD BIT(12) /* 1: read, 0: write */ +#define UNIPHIER_SD_CMD_DATA BIT(11) /* data transfer */ +#define UNIPHIER_SD_CMD_APP BIT(6) /* ACMD preceded by CMD55 */ +#define UNIPHIER_SD_CMD_NORMAL (0 << 8)/* auto-detect of resp-type */ +#define UNIPHIER_SD_CMD_RSP_NONE (3 << 8)/* response: none */ +#define UNIPHIER_SD_CMD_RSP_R1 (4 << 8)/* response: R1, R5, R6, R7 */ +#define UNIPHIER_SD_CMD_RSP_R1B (5 << 8)/* response: R1b, R5b */ +#define UNIPHIER_SD_CMD_RSP_R2 (6 << 8)/* response: R2 */ +#define UNIPHIER_SD_CMD_RSP_R3 (7 << 8)/* response: R3, R4 */ +#define UNIPHIER_SD_ARG 0x008 /* command argument */ +#define UNIPHIER_SD_STOP 0x010 /* stop action control */ +#define UNIPHIER_SD_STOP_SEC BIT(8) /* use sector count */ +#define UNIPHIER_SD_STOP_STP BIT(0) /* issue CMD12 */ +#define UNIPHIER_SD_SECCNT 0x014 /* sector counter */ +#define UNIPHIER_SD_RSP10 0x018 /* response[39:8] */ +#define UNIPHIER_SD_RSP32 0x020 /* response[71:40] */ +#define UNIPHIER_SD_RSP54 0x028 /* response[103:72] */ +#define UNIPHIER_SD_RSP76 0x030 /* response[127:104] */ +#define UNIPHIER_SD_INFO1 0x038 /* IRQ status 1 */ +#define UNIPHIER_SD_INFO1_CD BIT(5) /* state of card detect */ +#define UNIPHIER_SD_INFO1_INSERT BIT(4) /* card inserted */ +#define UNIPHIER_SD_INFO1_REMOVE BIT(3) /* card removed */ +#define UNIPHIER_SD_INFO1_CMP BIT(2) /* data complete */ +#define UNIPHIER_SD_INFO1_RSP BIT(0) /* response complete */ +#define UNIPHIER_SD_INFO2 0x03c /* IRQ status 2 */ +#define UNIPHIER_SD_INFO2_ERR_ILA BIT(15) /* illegal access err */ +#define UNIPHIER_SD_INFO2_CBSY BIT(14) /* command busy */ +#define UNIPHIER_SD_INFO2_BWE BIT(9) /* write buffer ready */ +#define UNIPHIER_SD_INFO2_BRE BIT(8) /* read buffer ready */ +#define UNIPHIER_SD_INFO2_DAT0 BIT(7) /* SDDAT0 */ +#define UNIPHIER_SD_INFO2_ERR_RTO BIT(6) /* response time out */ +#define UNIPHIER_SD_INFO2_ERR_ILR BIT(5) /* illegal read err */ +#define UNIPHIER_SD_INFO2_ERR_ILW BIT(4) /* illegal write err */ +#define UNIPHIER_SD_INFO2_ERR_TO BIT(3) /* time out error */ +#define UNIPHIER_SD_INFO2_ERR_END BIT(2) /* END bit error */ +#define UNIPHIER_SD_INFO2_ERR_CRC BIT(1) /* CRC error */ +#define UNIPHIER_SD_INFO2_ERR_IDX BIT(0) /* cmd index error */ +#define UNIPHIER_SD_INFO1_MASK 0x040 +#define UNIPHIER_SD_INFO2_MASK 0x044 +#define UNIPHIER_SD_CLKCTL 0x048 /* clock divisor */ +#define UNIPHIER_SD_CLKCTL_DIV_MASK 0x104ff +#define UNIPHIER_SD_CLKCTL_DIV1024 BIT(16) /* SDCLK = CLK / 1024 */ +#define UNIPHIER_SD_CLKCTL_DIV512 BIT(7) /* SDCLK = CLK / 512 */ +#define UNIPHIER_SD_CLKCTL_DIV256 BIT(6) /* SDCLK = CLK / 256 */ +#define UNIPHIER_SD_CLKCTL_DIV128 BIT(5) /* SDCLK = CLK / 128 */ +#define UNIPHIER_SD_CLKCTL_DIV64 BIT(4) /* SDCLK = CLK / 64 */ +#define UNIPHIER_SD_CLKCTL_DIV32 BIT(3) /* SDCLK = CLK / 32 */ +#define UNIPHIER_SD_CLKCTL_DIV16 BIT(2) /* SDCLK = CLK / 16 */ +#define UNIPHIER_SD_CLKCTL_DIV8 BIT(1) /* SDCLK = CLK / 8 */ +#define UNIPHIER_SD_CLKCTL_DIV4 BIT(0) /* SDCLK = CLK / 4 */ +#define UNIPHIER_SD_CLKCTL_DIV2 0 /* SDCLK = CLK / 2 */ +#define UNIPHIER_SD_CLKCTL_DIV1 BIT(10) /* SDCLK = CLK */ +#define UNIPHIER_SD_CLKCTL_OFFEN BIT(9) /* stop SDCLK when unused */ +#define UNIPHIER_SD_CLKCTL_SCLKEN BIT(8) /* SDCLK output enable */ +#define UNIPHIER_SD_SIZE 0x04c /* block size */ +#define UNIPHIER_SD_OPTION 0x050 +#define UNIPHIER_SD_OPTION_WIDTH_MASK (5 << 13) +#define UNIPHIER_SD_OPTION_WIDTH_1 (4 << 13) +#define UNIPHIER_SD_OPTION_WIDTH_4 (0 << 13) +#define UNIPHIER_SD_OPTION_WIDTH_8 (1 << 13) +#define UNIPHIER_SD_BUF 0x060 /* read/write buffer */ +#define UNIPHIER_SD_EXTMODE 0x1b0 +#define UNIPHIER_SD_EXTMODE_DMA_EN BIT(1) /* transfer 1: DMA, 0: pio */ +#define UNIPHIER_SD_SOFT_RST 0x1c0 +#define UNIPHIER_SD_SOFT_RST_RSTX BIT(0) /* reset deassert */ +#define UNIPHIER_SD_VERSION 0x1c4 /* version register */ +#define UNIPHIER_SD_VERSION_IP 0xff /* IP version */ +#define UNIPHIER_SD_HOST_MODE 0x1c8 +#define UNIPHIER_SD_IF_MODE 0x1cc +#define UNIPHIER_SD_IF_MODE_DDR BIT(0) /* DDR mode */ +#define UNIPHIER_SD_VOLT 0x1e4 /* voltage switch */ +#define UNIPHIER_SD_VOLT_MASK (3 << 0) +#define UNIPHIER_SD_VOLT_OFF (0 << 0) +#define UNIPHIER_SD_VOLT_330 (1 << 0)/* 3.3V signal */ +#define UNIPHIER_SD_VOLT_180 (2 << 0)/* 1.8V signal */ +#define UNIPHIER_SD_DMA_MODE 0x410 +#define UNIPHIER_SD_DMA_MODE_DIR_RD BIT(16) /* 1: from device, 0: to dev */ +#define UNIPHIER_SD_DMA_MODE_ADDR_INC BIT(0) /* 1: address inc, 0: fixed */ +#define UNIPHIER_SD_DMA_CTL 0x414 +#define UNIPHIER_SD_DMA_CTL_START BIT(0) /* start DMA (auto cleared) */ +#define UNIPHIER_SD_DMA_RST 0x418 +#define UNIPHIER_SD_DMA_RST_RD BIT(9) +#define UNIPHIER_SD_DMA_RST_WR BIT(8) +#define UNIPHIER_SD_DMA_INFO1 0x420 +#define UNIPHIER_SD_DMA_INFO1_END_RD2 BIT(20) /* DMA from device is complete*/ +#define UNIPHIER_SD_DMA_INFO1_END_RD BIT(17) /* Don't use! Hardware bug */ +#define UNIPHIER_SD_DMA_INFO1_END_WR BIT(16) /* DMA to device is complete */ +#define UNIPHIER_SD_DMA_INFO1_MASK 0x424 +#define UNIPHIER_SD_DMA_INFO2 0x428 +#define UNIPHIER_SD_DMA_INFO2_ERR_RD BIT(17) +#define UNIPHIER_SD_DMA_INFO2_ERR_WR BIT(16) +#define UNIPHIER_SD_DMA_INFO2_MASK 0x42c +#define UNIPHIER_SD_DMA_ADDR_L 0x440 +#define UNIPHIER_SD_DMA_ADDR_H 0x444 + +/* alignment required by the DMA engine of this controller */ +#define UNIPHIER_SD_DMA_MINALIGN 0x10 + +struct uniphier_sd_priv { + struct mmc_config cfg; + struct mmc *mmc; + void __iomem *regbase; + unsigned long mclk; + unsigned int version; + u32 caps; +#define UNIPHIER_SD_CAP_NONREMOVABLE BIT(0) /* Nonremovable e.g. eMMC */ +#define UNIPHIER_SD_CAP_DMA_INTERNAL BIT(1) /* have internal DMA engine */ +#define UNIPHIER_SD_CAP_DIV1024 BIT(2) /* divisor 1024 is available */ +}; + +static dma_addr_t __dma_map_single(void *ptr, size_t size, + enum dma_data_direction dir) +{ + unsigned long addr = (unsigned long)ptr; + + if (dir == DMA_FROM_DEVICE) + invalidate_dcache_range(addr, addr + size); + else + flush_dcache_range(addr, addr + size); + + return addr; +} + +static void __dma_unmap_single(dma_addr_t addr, size_t size, + enum dma_data_direction dir) +{ + if (dir != DMA_TO_DEVICE) + invalidate_dcache_range(addr, addr + size); +} + +static int uniphier_sd_check_error(struct uniphier_sd_priv *priv) +{ + u32 info2 = readl(priv->regbase + UNIPHIER_SD_INFO2); + + if (info2 & UNIPHIER_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 TIMEOUT; + } + + if (info2 & UNIPHIER_SD_INFO2_ERR_TO) { + pr_err("timeout error\n"); + return -ETIMEDOUT; + } + + if (info2 & (UNIPHIER_SD_INFO2_ERR_END | UNIPHIER_SD_INFO2_ERR_CRC | + UNIPHIER_SD_INFO2_ERR_IDX)) { + pr_err("communication out of sync\n"); + return -EILSEQ; + } + + if (info2 & (UNIPHIER_SD_INFO2_ERR_ILA | UNIPHIER_SD_INFO2_ERR_ILR | + UNIPHIER_SD_INFO2_ERR_ILW)) { + pr_err("illegal access\n"); + return -EIO; + } + + return 0; +} + +static int uniphier_sd_wait_irq(struct uniphier_sd_priv *priv, + unsigned int reg, u32 flag) +{ + long wait = 1000000; + int ret; + + while (!(readl(priv->regbase + reg) & flag)) { + if (wait-- < 0) { + pr_err("timeout\n"); + return -ETIMEDOUT; + } + + ret = uniphier_sd_check_error(priv); + if (ret) + return ret; + + udelay(1); + } + + return 0; +} + +static int uniphier_sd_pio_read_one_block(struct mmc *mmc, u32 **pbuf, + uint blocksize) +{ + struct uniphier_sd_priv *priv = mmc->priv; + int i, ret; + + /* wait until the buffer is filled with data */ + ret = uniphier_sd_wait_irq(priv, UNIPHIER_SD_INFO2, + UNIPHIER_SD_INFO2_BRE); + if (ret) + return ret; + + /* + * Clear the status flag _before_ read the buffer out because + * UNIPHIER_SD_INFO2_BRE is edge-triggered, not level-triggered. + */ + writel(0, priv->regbase + UNIPHIER_SD_INFO2); + + if (likely(IS_ALIGNED((unsigned long)*pbuf, 4))) { + for (i = 0; i < blocksize / 4; i++) + *(*pbuf)++ = readl(priv->regbase + UNIPHIER_SD_BUF); + } else { + for (i = 0; i < blocksize / 4; i++) + put_unaligned(readl(priv->regbase + UNIPHIER_SD_BUF), + (*pbuf)++); + } + + return 0; +} + +static int uniphier_sd_pio_write_one_block(struct mmc *mmc, const u32 **pbuf, + uint blocksize) +{ + struct uniphier_sd_priv *priv = mmc->priv; + int i, ret; + + /* wait until the buffer becomes empty */ + ret = uniphier_sd_wait_irq(priv, UNIPHIER_SD_INFO2, + UNIPHIER_SD_INFO2_BWE); + if (ret) + return ret; + + writel(0, priv->regbase + UNIPHIER_SD_INFO2); + + if (likely(IS_ALIGNED((unsigned long)*pbuf, 4))) { + for (i = 0; i < blocksize / 4; i++) + writel(*(*pbuf)++, priv->regbase + UNIPHIER_SD_BUF); + } else { + for (i = 0; i < blocksize / 4; i++) + writel(get_unaligned((*pbuf)++), + priv->regbase + UNIPHIER_SD_BUF); + } + + return 0; +} + +static int uniphier_sd_pio_xfer(struct mmc *mmc, struct mmc_data *data) +{ + u32 *dest = (u32 *)data->dest; + const u32 *src = (const u32 *)data->src; + int i, ret; + + for (i = 0; i < data->blocks; i++) { + if (data->flags & MMC_DATA_READ) + ret = uniphier_sd_pio_read_one_block(mmc, &dest, + data->blocksize); + else + ret = uniphier_sd_pio_write_one_block(mmc, &src, + data->blocksize); + if (ret) + return ret; + } + + return 0; +} + +static void uniphier_sd_dma_start(struct uniphier_sd_priv *priv, + dma_addr_t dma_addr) +{ + u32 tmp; + + writel(0, priv->regbase + UNIPHIER_SD_DMA_INFO1); + writel(0, priv->regbase + UNIPHIER_SD_DMA_INFO2); + + /* enable DMA */ + tmp = readl(priv->regbase + UNIPHIER_SD_EXTMODE); + tmp |= UNIPHIER_SD_EXTMODE_DMA_EN; + writel(tmp, priv->regbase + UNIPHIER_SD_EXTMODE); + + writel(dma_addr & U32_MAX, priv->regbase + UNIPHIER_SD_DMA_ADDR_L); + + /* suppress the warning "right shift count >= width of type" */ + dma_addr >>= min_t(int, 32, 8 * sizeof(dma_addr)); + + writel(dma_addr & U32_MAX, priv->regbase + UNIPHIER_SD_DMA_ADDR_H); + + writel(UNIPHIER_SD_DMA_CTL_START, priv->regbase + UNIPHIER_SD_DMA_CTL); +} + +static int uniphier_sd_dma_wait_irq(struct uniphier_sd_priv *priv, u32 flag, + unsigned int blocks) +{ + long wait = 1000000 + 10 * blocks; + + while (!(readl(priv->regbase + UNIPHIER_SD_DMA_INFO1) & flag)) { + if (wait-- < 0) { + pr_err("timeout during DMA\n"); + return -ETIMEDOUT; + } + + udelay(10); + } + + if (readl(priv->regbase + UNIPHIER_SD_DMA_INFO2)) { + pr_err("error during DMA\n"); + return -EIO; + } + + return 0; +} + +static int uniphier_sd_dma_xfer(struct mmc *mmc, struct mmc_data *data) +{ + struct uniphier_sd_priv *priv = mmc->priv; + 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 = readl(priv->regbase + UNIPHIER_SD_DMA_MODE); + + if (data->flags & MMC_DATA_READ) { + buf = data->dest; + dir = DMA_FROM_DEVICE; + poll_flag = UNIPHIER_SD_DMA_INFO1_END_RD2; + tmp |= UNIPHIER_SD_DMA_MODE_DIR_RD; + } else { + buf = (void *)data->src; + dir = DMA_TO_DEVICE; + poll_flag = UNIPHIER_SD_DMA_INFO1_END_WR; + tmp &= ~UNIPHIER_SD_DMA_MODE_DIR_RD; + } + + writel(tmp, priv->regbase + UNIPHIER_SD_DMA_MODE); + + dma_addr = __dma_map_single(buf, len, dir); + + uniphier_sd_dma_start(priv, dma_addr); + + ret = uniphier_sd_dma_wait_irq(priv, poll_flag, data->blocks); + + __dma_unmap_single(dma_addr, len, dir); + + return ret; +} + +static int uniphier_sd_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, + struct mmc_data *data) +{ + struct uniphier_sd_priv *priv = mmc->priv; + int ret; + u32 tmp; + + if (readl(priv->regbase + UNIPHIER_SD_INFO2) & UNIPHIER_SD_INFO2_CBSY) { + pr_err("command busy\n"); + return -EBUSY; + } + + /* clear all status flags */ + writel(0, priv->regbase + UNIPHIER_SD_INFO1); + writel(0, priv->regbase + UNIPHIER_SD_INFO2); + + /* disable DMA once */ + tmp = readl(priv->regbase + UNIPHIER_SD_EXTMODE); + tmp &= ~UNIPHIER_SD_EXTMODE_DMA_EN; + writel(tmp, priv->regbase + UNIPHIER_SD_EXTMODE); + + writel(cmd->cmdarg, priv->regbase + UNIPHIER_SD_ARG); + + tmp = cmd->cmdidx; + + if (data) { + writel(data->blocksize, priv->regbase + UNIPHIER_SD_SIZE); + writel(data->blocks, priv->regbase + UNIPHIER_SD_SECCNT); + + /* Do not send CMD12 automatically */ + tmp |= UNIPHIER_SD_CMD_NOSTOP | UNIPHIER_SD_CMD_DATA; + + if (data->blocks > 1) + tmp |= UNIPHIER_SD_CMD_MULTI; + + if (data->flags & MMC_DATA_READ) + tmp |= UNIPHIER_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 |= UNIPHIER_SD_CMD_RSP_NONE; + break; + case MMC_RSP_R1: + tmp |= UNIPHIER_SD_CMD_RSP_R1; + break; + case MMC_RSP_R1b: + tmp |= UNIPHIER_SD_CMD_RSP_R1B; + break; + case MMC_RSP_R2: + tmp |= UNIPHIER_SD_CMD_RSP_R2; + break; + case MMC_RSP_R3: + tmp |= UNIPHIER_SD_CMD_RSP_R3; + break; + default: + pr_err("unknown response type\n"); + return -EINVAL; + } + + pr_debug("sending CMD%d (SD_CMD=%08x, SD_ARG=%08x)\n", + cmd->cmdidx, tmp, cmd->cmdarg); + writel(tmp, priv->regbase + UNIPHIER_SD_CMD); + + ret = uniphier_sd_wait_irq(priv, UNIPHIER_SD_INFO1, + UNIPHIER_SD_INFO1_RSP); + if (ret) + return ret; + + if (cmd->resp_type & MMC_RSP_136) { + u32 rsp_127_104 = readl(priv->regbase + UNIPHIER_SD_RSP76); + u32 rsp_103_72 = readl(priv->regbase + UNIPHIER_SD_RSP54); + u32 rsp_71_40 = readl(priv->regbase + UNIPHIER_SD_RSP32); + u32 rsp_39_8 = readl(priv->regbase + UNIPHIER_SD_RSP10); + + cmd->response[0] = (rsp_127_104 & 0xffffff) << 8 | + (rsp_103_72 & 0xff); + cmd->response[1] = (rsp_103_72 & 0xffffff) << 8 | + (rsp_71_40 & 0xff); + cmd->response[2] = (rsp_71_40 & 0xffffff) << 8 | + (rsp_39_8 & 0xff); + cmd->response[3] = (rsp_39_8 & 0xffffff) << 8; + } else { + /* bit 39-8 */ + cmd->response[0] = readl(priv->regbase + UNIPHIER_SD_RSP10); + } + + if (data) { + /* use DMA if the HW supports it and the buffer is aligned */ + if ((priv->caps & UNIPHIER_SD_CAP_DMA_INTERNAL) && + IS_ALIGNED((long)data->src, UNIPHIER_SD_DMA_MINALIGN)) + ret = uniphier_sd_dma_xfer(mmc, data); + else + ret = uniphier_sd_pio_xfer(mmc, data); + + ret = uniphier_sd_wait_irq(priv, UNIPHIER_SD_INFO1, + UNIPHIER_SD_INFO1_CMP); + if (ret) + return ret; + } + + return ret; +} + +static void uniphier_sd_set_bus_width(struct mmc *mmc) +{ + struct uniphier_sd_priv *priv = mmc->priv; + u32 val, tmp; + + pr_debug("uniphier_sd: setting bus to %u bit\n", mmc->bus_width); + + switch (mmc->bus_width) { + case 1: + val = UNIPHIER_SD_OPTION_WIDTH_1; + break; + case 4: + val = UNIPHIER_SD_OPTION_WIDTH_4; + break; + case 8: + val = UNIPHIER_SD_OPTION_WIDTH_8; + break; + default: + BUG(); + break; + } + + tmp = readl(priv->regbase + UNIPHIER_SD_OPTION); + tmp &= ~UNIPHIER_SD_OPTION_WIDTH_MASK; + tmp |= val; + writel(tmp, priv->regbase + UNIPHIER_SD_OPTION); +} + +static void uniphier_sd_set_clk(struct mmc *mmc) +{ + struct uniphier_sd_priv *priv = mmc->priv; + unsigned int divisor; + u32 val, tmp; + + if (!mmc->clock) + return; + + pr_debug("uniphier_sd: setting clock to %u, DDR=%s\n", + mmc->clock, mmc->ddr_mode ? "on" : "off"); + + divisor = DIV_ROUND_UP(priv->mclk, mmc->clock); + + if (divisor <= 1) + val = UNIPHIER_SD_CLKCTL_DIV1; + else if (divisor <= 2) + val = UNIPHIER_SD_CLKCTL_DIV2; + else if (divisor <= 4) + val = UNIPHIER_SD_CLKCTL_DIV4; + else if (divisor <= 8) + val = UNIPHIER_SD_CLKCTL_DIV8; + else if (divisor <= 16) + val = UNIPHIER_SD_CLKCTL_DIV16; + else if (divisor <= 32) + val = UNIPHIER_SD_CLKCTL_DIV32; + else if (divisor <= 64) + val = UNIPHIER_SD_CLKCTL_DIV64; + else if (divisor <= 128) + val = UNIPHIER_SD_CLKCTL_DIV128; + else if (divisor <= 256) + val = UNIPHIER_SD_CLKCTL_DIV256; + else if (divisor <= 512 || !(priv->caps & UNIPHIER_SD_CAP_DIV1024)) + val = UNIPHIER_SD_CLKCTL_DIV512; + else + val = UNIPHIER_SD_CLKCTL_DIV1024; + + tmp = readl(priv->regbase + UNIPHIER_SD_CLKCTL); + tmp &= ~UNIPHIER_SD_CLKCTL_DIV_MASK; + tmp |= val | UNIPHIER_SD_CLKCTL_OFFEN | UNIPHIER_SD_CLKCTL_SCLKEN; + writel(tmp, priv->regbase + UNIPHIER_SD_CLKCTL); + + tmp = readl(priv->regbase + UNIPHIER_SD_IF_MODE); + if (mmc->ddr_mode) + tmp |= UNIPHIER_SD_IF_MODE_DDR; + else + tmp &= ~UNIPHIER_SD_IF_MODE_DDR; + writel(tmp, priv->regbase + UNIPHIER_SD_IF_MODE); + + udelay(1000); +} + +static void uniphier_sd_set_ios(struct mmc *mmc) +{ + uniphier_sd_set_clk(mmc); + uniphier_sd_set_bus_width(mmc); +} + +static int uniphier_sd_init(struct mmc *mmc) +{ + struct uniphier_sd_priv *priv = mmc->priv; + u32 tmp; + + /* soft reset of the host */ + tmp = readl(priv->regbase + UNIPHIER_SD_SOFT_RST); + tmp &= ~UNIPHIER_SD_SOFT_RST_RSTX; + writel(tmp, priv->regbase + UNIPHIER_SD_SOFT_RST); + tmp |= UNIPHIER_SD_SOFT_RST_RSTX; + writel(tmp, priv->regbase + UNIPHIER_SD_SOFT_RST); + + /* FIXME: implement eMMC hw_reset */ + + writel(UNIPHIER_SD_STOP_SEC, priv->regbase + UNIPHIER_SD_STOP); + + writel(priv->version >= 0x10 ? 0x00000101 : 0x00000000, + priv->regbase + UNIPHIER_SD_HOST_MODE); + + if (priv->caps & UNIPHIER_SD_CAP_DMA_INTERNAL) { + tmp = readl(priv->regbase + UNIPHIER_SD_DMA_MODE); + tmp |= UNIPHIER_SD_DMA_MODE_ADDR_INC; + writel(tmp, priv->regbase + UNIPHIER_SD_DMA_MODE); + } + + return 0; +} + +static int uniphier_sd_getcd(struct mmc *mmc) +{ + struct uniphier_sd_priv *priv = mmc->priv; + + if (priv->caps & UNIPHIER_SD_CAP_NONREMOVABLE) + return 1; + + return !!(readl(priv->regbase + UNIPHIER_SD_INFO1) & + UNIPHIER_SD_INFO1_CD); +} + +static const struct mmc_ops uniphier_sd_ops = { + .send_cmd = uniphier_sd_send_cmd, + .set_ios = uniphier_sd_set_ios, + .init = uniphier_sd_init, + .getcd = uniphier_sd_getcd, +}; + +int uniphier_sd_probe(struct udevice *dev) +{ + struct uniphier_sd_priv *priv = dev_get_priv(dev); + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); + fdt_addr_t base; + fdt_size_t size; + struct udevice *clk_dev; + int clk_id; + int ret; + + base = fdtdec_get_addr_size(gd->fdt_blob, dev->of_offset, "reg", &size); + priv->regbase = map_sysmem(base, size); + if (!priv->regbase) + return -ENOMEM; + + clk_id = clk_get_by_index(dev, 0, &clk_dev); + if (clk_id < 0) { + pr_err("failed to get host clock\n"); + return clk_id; + } + + /* set to max rate */ + priv->mclk = clk_set_periph_rate(clk_dev, clk_id, ULONG_MAX); + if (IS_ERR_VALUE(priv->mclk)) { + pr_err("failed to set rate for host clock\n"); + return priv->mclk; + } + + ret = clk_enable(clk_dev, clk_id); + if (ret) { + pr_err("failed to enable host clock\n"); + return ret; + } + + priv->cfg.name = dev->name; + priv->cfg.ops = &uniphier_sd_ops; + priv->cfg.host_caps = MMC_MODE_HS_52MHz | MMC_MODE_HS; + + switch (fdtdec_get_int(gd->fdt_blob, dev->of_offset, "bus-width", 1)) { + case 8: + priv->cfg.host_caps |= MMC_MODE_8BIT; + break; + case 4: + priv->cfg.host_caps |= MMC_MODE_4BIT; + break; + case 1: + break; + default: + pr_err("Invalid "bus-width" value\n"); + return -EINVAL; + } + + if (fdt_get_property(gd->fdt_blob, dev->of_offset, "non-removable", + NULL)) + priv->caps |= UNIPHIER_SD_CAP_NONREMOVABLE; + + priv->version = readl(priv->regbase + UNIPHIER_SD_VERSION) & + UNIPHIER_SD_VERSION_IP; + pr_debug("version %x\n", priv->version); + if (priv->version >= 0x10) { + /* + * For UniPhier ARMv7 SoCs, RAM is not available in SPL, + * so DMA is not available either. + */ + if (!IS_ENABLED(CONFIG_SPL_BUILD)) + priv->caps |= UNIPHIER_SD_CAP_DMA_INTERNAL; + priv->caps |= UNIPHIER_SD_CAP_DIV1024; + } + + priv->cfg.voltages = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34; + priv->cfg.f_min = priv->mclk / + (priv->caps & UNIPHIER_SD_CAP_DIV1024 ? 1024 : 512); + priv->cfg.f_max = priv->mclk; + priv->cfg.b_max = U32_MAX; /* max value of UNIPHIER_SD_SECCNT */ + + priv->mmc = mmc_create(&priv->cfg, priv); + if (!priv->mmc) + return -EIO; + + upriv->mmc = priv->mmc; + + return 0; +} + +int uniphier_sd_remove(struct udevice *dev) +{ + struct uniphier_sd_priv *priv = dev_get_priv(dev); + + unmap_sysmem(priv->regbase); + mmc_destroy(priv->mmc); + + return 0; +} + +static const struct udevice_id uniphier_sd_match[] = { + { .compatible = "socionext,uniphier-sdhc" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(uniphier_mmc) = { + .name = "uniphier-mmc", + .id = UCLASS_MMC, + .of_match = uniphier_sd_match, + .probe = uniphier_sd_probe, + .remove = uniphier_sd_remove, + .priv_auto_alloc_size = sizeof(struct uniphier_sd_priv), +};

On 02/10/2016 02:28 PM, Masahiro Yamada wrote:
Add a driver for the on-chip SD/eMMC host controller used by UniPhier SoC family.
Signed-off-by: Masahiro Yamada yamada.masahiro@socionext.com
前略 山田さん,
[...]
+#include <common.h> +#include <clk.h> +#include <fdtdec.h> +#include <mapmem.h> +#include <mmc.h> +#include <dm/device.h> +#include <linux/compat.h> +#include <linux/io.h> +#include <asm/unaligned.h> +#include <asm/dma-mapping.h>
+#define pr_err printf +#define pr_warn printf +#ifdef DEBUG +#define pr_debug printf +#else +#define pr_debug(...) +#endif
This should go into include/ somewhere, your driver shouldn't be a platform abstraction library.
+DECLARE_GLOBAL_DATA_PTR;
+#define UNIPHIER_SD_CMD 0x000 /* command */
[...]
+static int uniphier_sd_wait_irq(struct uniphier_sd_priv *priv,
unsigned int reg, u32 flag)
+{
- long wait = 1000000;
- int ret;
Replace this with wait_for_bit() please .
- while (!(readl(priv->regbase + reg) & flag)) {
if (wait-- < 0) {
pr_err("timeout\n");
return -ETIMEDOUT;
}
ret = uniphier_sd_check_error(priv);
if (ret)
return ret;
udelay(1);
- }
- return 0;
+}
[...]
+static void uniphier_sd_dma_start(struct uniphier_sd_priv *priv,
dma_addr_t dma_addr)
+{
- u32 tmp;
- writel(0, priv->regbase + UNIPHIER_SD_DMA_INFO1);
- writel(0, priv->regbase + UNIPHIER_SD_DMA_INFO2);
- /* enable DMA */
- tmp = readl(priv->regbase + UNIPHIER_SD_EXTMODE);
- tmp |= UNIPHIER_SD_EXTMODE_DMA_EN;
- writel(tmp, priv->regbase + UNIPHIER_SD_EXTMODE);
I'd say, use setbits_le32(), but could it be that this driver is kept in sync with Linux ?
- writel(dma_addr & U32_MAX, priv->regbase + UNIPHIER_SD_DMA_ADDR_L);
- /* suppress the warning "right shift count >= width of type" */
- dma_addr >>= min_t(int, 32, 8 * sizeof(dma_addr));
- writel(dma_addr & U32_MAX, priv->regbase + UNIPHIER_SD_DMA_ADDR_H);
- writel(UNIPHIER_SD_DMA_CTL_START, priv->regbase + UNIPHIER_SD_DMA_CTL);
+}
+static int uniphier_sd_dma_wait_irq(struct uniphier_sd_priv *priv, u32 flag,
unsigned int blocks)
+{
- long wait = 1000000 + 10 * blocks;
wait_for_bit() again.
- while (!(readl(priv->regbase + UNIPHIER_SD_DMA_INFO1) & flag)) {
if (wait-- < 0) {
pr_err("timeout during DMA\n");
return -ETIMEDOUT;
}
udelay(10);
- }
- if (readl(priv->regbase + UNIPHIER_SD_DMA_INFO2)) {
pr_err("error during DMA\n");
return -EIO;
- }
- return 0;
+}
草々

Hi Marek,
2016-02-10 22:45 GMT+09:00 Marek Vasut marex@denx.de:
On 02/10/2016 02:28 PM, Masahiro Yamada wrote:
Add a driver for the on-chip SD/eMMC host controller used by UniPhier SoC family.
Signed-off-by: Masahiro Yamada yamada.masahiro@socionext.com
前略 山田さん,
[...]
+#include <common.h> +#include <clk.h> +#include <fdtdec.h> +#include <mapmem.h> +#include <mmc.h> +#include <dm/device.h> +#include <linux/compat.h> +#include <linux/io.h> +#include <asm/unaligned.h> +#include <asm/dma-mapping.h>
+#define pr_err printf +#define pr_warn printf +#ifdef DEBUG +#define pr_debug printf +#else +#define pr_debug(...) +#endif
This should go into include/ somewhere, your driver shouldn't be a platform abstraction library.
Fixed in v3.
+static int uniphier_sd_wait_irq(struct uniphier_sd_priv *priv,
unsigned int reg, u32 flag)
+{
long wait = 1000000;
int ret;
Replace this with wait_for_bit() please .
It cannot check error during the loop.
I want to check the error flags in the loop because no reason to wait for the time-out if some error happens.
while (!(readl(priv->regbase + reg) & flag)) {
if (wait-- < 0) {
pr_err("timeout\n");
return -ETIMEDOUT;
}
ret = uniphier_sd_check_error(priv);
if (ret)
return ret;
udelay(1);
}
return 0;
+}
[...]
+static void uniphier_sd_dma_start(struct uniphier_sd_priv *priv,
dma_addr_t dma_addr)
+{
u32 tmp;
writel(0, priv->regbase + UNIPHIER_SD_DMA_INFO1);
writel(0, priv->regbase + UNIPHIER_SD_DMA_INFO2);
/* enable DMA */
tmp = readl(priv->regbase + UNIPHIER_SD_EXTMODE);
tmp |= UNIPHIER_SD_EXTMODE_DMA_EN;
writel(tmp, priv->regbase + UNIPHIER_SD_EXTMODE);
I'd say, use setbits_le32(), but could it be that this driver is kept in sync with Linux ?
Yes, I am developing the MMC driver for Linux as well as U-Boot at the same time.
This is the U-Boot counter-part, although the Linux one has not been upstreamed yet.
It can save my time to copy-paste code snippets between the two.
I want to sync as much code as possible.

On 02/16/2016 09:18 AM, Masahiro Yamada wrote:
Hi Marek,
Hi!
[...]
+static int uniphier_sd_wait_irq(struct uniphier_sd_priv *priv,
unsigned int reg, u32 flag)
+{
long wait = 1000000;
int ret;
Replace this with wait_for_bit() please .
It cannot check error during the loop.
I want to check the error flags in the loop because no reason to wait for the time-out if some error happens.
You have a point there.
I wonder if it'd make sense to extend the wait_for_bit with some callback maybe ?
while (!(readl(priv->regbase + reg) & flag)) {
if (wait-- < 0) {
pr_err("timeout\n");
return -ETIMEDOUT;
}
ret = uniphier_sd_check_error(priv);
if (ret)
return ret;
udelay(1);
}
return 0;
+}
[...]
+static void uniphier_sd_dma_start(struct uniphier_sd_priv *priv,
dma_addr_t dma_addr)
+{
u32 tmp;
writel(0, priv->regbase + UNIPHIER_SD_DMA_INFO1);
writel(0, priv->regbase + UNIPHIER_SD_DMA_INFO2);
/* enable DMA */
tmp = readl(priv->regbase + UNIPHIER_SD_EXTMODE);
tmp |= UNIPHIER_SD_EXTMODE_DMA_EN;
writel(tmp, priv->regbase + UNIPHIER_SD_EXTMODE);
I'd say, use setbits_le32(), but could it be that this driver is kept in sync with Linux ?
Yes, I am developing the MMC driver for Linux as well as U-Boot at the same time.
This is the U-Boot counter-part, although the Linux one has not been upstreamed yet.
It can save my time to copy-paste code snippets between the two.
I want to sync as much code as possible.
Understood, thanks!

Enable the driver in all UniPhier defconfig files and add some needed defines to the common files.
Signed-off-by: Masahiro Yamada yamada.masahiro@socionext.com ---
Changes in v2: None
arch/arm/Kconfig | 1 + configs/uniphier_ld4_sld8_defconfig | 1 + configs/uniphier_pro4_defconfig | 1 + configs/uniphier_pro5_defconfig | 1 + configs/uniphier_pxs2_ld6b_defconfig | 1 + configs/uniphier_sld3_defconfig | 1 + include/configs/uniphier.h | 4 ++++ 7 files changed, 10 insertions(+)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index d8b63e9..6a8c9ae 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -699,6 +699,7 @@ config ARCH_UNIPHIER select SPL_DM select DM_SERIAL select DM_I2C + select DM_MMC help Support for UniPhier SoC family developed by Socionext Inc. (formerly, System LSI Business Division of Panasonic Corporation) diff --git a/configs/uniphier_ld4_sld8_defconfig b/configs/uniphier_ld4_sld8_defconfig index 535f96f..9bae445 100644 --- a/configs/uniphier_ld4_sld8_defconfig +++ b/configs/uniphier_ld4_sld8_defconfig @@ -19,6 +19,7 @@ CONFIG_CMD_TIME=y # CONFIG_CMD_MISC is not set CONFIG_NET_RANDOM_ETHADDR=y CONFIG_SPL_SIMPLE_BUS=y +CONFIG_MMC_UNIPHIER=y CONFIG_NAND_DENALI=y CONFIG_SYS_NAND_DENALI_64BIT=y CONFIG_NAND_DENALI_SPARE_AREA_SKIP_BYTES=8 diff --git a/configs/uniphier_pro4_defconfig b/configs/uniphier_pro4_defconfig index 2361db6..b6e6ebf 100644 --- a/configs/uniphier_pro4_defconfig +++ b/configs/uniphier_pro4_defconfig @@ -18,6 +18,7 @@ CONFIG_CMD_TIME=y # CONFIG_CMD_MISC is not set CONFIG_NET_RANDOM_ETHADDR=y CONFIG_SPL_SIMPLE_BUS=y +CONFIG_MMC_UNIPHIER=y CONFIG_NAND_DENALI=y CONFIG_SYS_NAND_DENALI_64BIT=y CONFIG_NAND_DENALI_SPARE_AREA_SKIP_BYTES=8 diff --git a/configs/uniphier_pro5_defconfig b/configs/uniphier_pro5_defconfig index be0d7b5..5981c87 100644 --- a/configs/uniphier_pro5_defconfig +++ b/configs/uniphier_pro5_defconfig @@ -18,6 +18,7 @@ CONFIG_CMD_TIME=y # CONFIG_CMD_MISC is not set CONFIG_NET_RANDOM_ETHADDR=y CONFIG_SPL_SIMPLE_BUS=y +CONFIG_MMC_UNIPHIER=y CONFIG_NAND_DENALI=y CONFIG_SYS_NAND_DENALI_64BIT=y CONFIG_NAND_DENALI_SPARE_AREA_SKIP_BYTES=8 diff --git a/configs/uniphier_pxs2_ld6b_defconfig b/configs/uniphier_pxs2_ld6b_defconfig index f8cb794..dae5a6e 100644 --- a/configs/uniphier_pxs2_ld6b_defconfig +++ b/configs/uniphier_pxs2_ld6b_defconfig @@ -19,6 +19,7 @@ CONFIG_CMD_TIME=y # CONFIG_CMD_MISC is not set CONFIG_NET_RANDOM_ETHADDR=y CONFIG_SPL_SIMPLE_BUS=y +CONFIG_MMC_UNIPHIER=y CONFIG_NAND_DENALI=y CONFIG_SYS_NAND_DENALI_64BIT=y CONFIG_NAND_DENALI_SPARE_AREA_SKIP_BYTES=8 diff --git a/configs/uniphier_sld3_defconfig b/configs/uniphier_sld3_defconfig index e369c45..0a4550e 100644 --- a/configs/uniphier_sld3_defconfig +++ b/configs/uniphier_sld3_defconfig @@ -16,6 +16,7 @@ CONFIG_CMD_PING=y CONFIG_CMD_TIME=y # CONFIG_CMD_MISC is not set CONFIG_NET_RANDOM_ETHADDR=y +CONFIG_MMC_UNIPHIER=y CONFIG_NAND_DENALI=y CONFIG_SYS_NAND_DENALI_64BIT=y CONFIG_NAND_DENALI_SPARE_AREA_SKIP_BYTES=8 diff --git a/include/configs/uniphier.h b/include/configs/uniphier.h index 43fe946..bef92a1 100644 --- a/include/configs/uniphier.h +++ b/include/configs/uniphier.h @@ -146,6 +146,10 @@ #define CONFIG_FAT_WRITE #define CONFIG_DOS_PARTITION
+/* SD/MMC */ +#define CONFIG_CMD_MMC +#define CONFIG_GENERIC_MMC + /* memtest works on */ #define CONFIG_SYS_MEMTEST_START CONFIG_SYS_SDRAM_BASE #define CONFIG_SYS_MEMTEST_END (CONFIG_SYS_SDRAM_BASE + 0x01000000)

This host controller is available for all UniPhier SoCs.
Signed-off-by: Masahiro Yamada yamada.masahiro@socionext.com ---
Changes in v2: None
arch/arm/dts/uniphier-ph1-ld4-ref.dts | 4 +++ arch/arm/dts/uniphier-ph1-ld4.dtsi | 25 +++++++++++++++++++ arch/arm/dts/uniphier-ph1-ld6b-ref.dts | 4 +++ arch/arm/dts/uniphier-ph1-pro4-ref.dts | 8 ++++++ arch/arm/dts/uniphier-ph1-pro4.dtsi | 37 ++++++++++++++++++++++++++++ arch/arm/dts/uniphier-ph1-pro5-4kbox.dts | 8 ++++++ arch/arm/dts/uniphier-ph1-pro5.dtsi | 24 ++++++++++++++++++ arch/arm/dts/uniphier-ph1-sld3-ref.dts | 4 +++ arch/arm/dts/uniphier-ph1-sld3.dtsi | 19 ++++++++++++++ arch/arm/dts/uniphier-ph1-sld8-ref.dts | 4 +++ arch/arm/dts/uniphier-ph1-sld8.dtsi | 25 +++++++++++++++++++ arch/arm/dts/uniphier-pinctrl.dtsi | 15 +++++++++++ arch/arm/dts/uniphier-proxstream2-gentil.dts | 4 +++ arch/arm/dts/uniphier-proxstream2-vodka.dts | 4 +++ arch/arm/dts/uniphier-proxstream2.dtsi | 24 ++++++++++++++++++ 15 files changed, 209 insertions(+)
diff --git a/arch/arm/dts/uniphier-ph1-ld4-ref.dts b/arch/arm/dts/uniphier-ph1-ld4-ref.dts index f62916d..d7b0007 100644 --- a/arch/arm/dts/uniphier-ph1-ld4-ref.dts +++ b/arch/arm/dts/uniphier-ph1-ld4-ref.dts @@ -51,6 +51,10 @@ status = "okay"; };
+&sd { + status = "okay"; +}; + &usb0 { status = "okay"; }; diff --git a/arch/arm/dts/uniphier-ph1-ld4.dtsi b/arch/arm/dts/uniphier-ph1-ld4.dtsi index 7c8759f..b93a34f 100644 --- a/arch/arm/dts/uniphier-ph1-ld4.dtsi +++ b/arch/arm/dts/uniphier-ph1-ld4.dtsi @@ -108,6 +108,31 @@ clock-frequency = <100000>; };
+ sd: sdhc@5a400000 { + compatible = "socionext,uniphier-sdhc"; + status = "disabled"; + reg = <0x5a400000 0x200>; + interrupts = <0 76 4>; + pinctrl-names = "default", "1.8v"; + pinctrl-0 = <&pinctrl_sd>; + pinctrl-1 = <&pinctrl_sd_1v8>; + clocks = <&mio 0>; + bus-width = <4>; + }; + + emmc: sdhc@5a500000 { + compatible = "socionext,uniphier-sdhc"; + status = "disabled"; + reg = <0x5a500000 0x200>; + interrupts = <0 78 4>; + pinctrl-names = "default", "1.8v"; + pinctrl-0 = <&pinctrl_emmc>; + pinctrl-1 = <&pinctrl_emmc_1v8>; + clocks = <&mio 1>; + bus-width = <8>; + non-removable; + }; + usb0: usb@5a800100 { compatible = "socionext,uniphier-ehci", "generic-ehci"; status = "disabled"; diff --git a/arch/arm/dts/uniphier-ph1-ld6b-ref.dts b/arch/arm/dts/uniphier-ph1-ld6b-ref.dts index dca408b..13a29fd 100644 --- a/arch/arm/dts/uniphier-ph1-ld6b-ref.dts +++ b/arch/arm/dts/uniphier-ph1-ld6b-ref.dts @@ -53,6 +53,10 @@ status = "okay"; };
+&sd { + status = "okay"; +}; + &usb0 { status = "okay"; }; diff --git a/arch/arm/dts/uniphier-ph1-pro4-ref.dts b/arch/arm/dts/uniphier-ph1-pro4-ref.dts index 202a642..07a9783 100644 --- a/arch/arm/dts/uniphier-ph1-pro4-ref.dts +++ b/arch/arm/dts/uniphier-ph1-pro4-ref.dts @@ -54,6 +54,14 @@ status = "okay"; };
+&sd { + status = "okay"; +}; + +&sd1 { + status = "okay"; +}; + &usb0 { status = "okay"; }; diff --git a/arch/arm/dts/uniphier-ph1-pro4.dtsi b/arch/arm/dts/uniphier-ph1-pro4.dtsi index cb5b8f1..f413549 100644 --- a/arch/arm/dts/uniphier-ph1-pro4.dtsi +++ b/arch/arm/dts/uniphier-ph1-pro4.dtsi @@ -140,6 +140,43 @@ clock-frequency = <400000>; };
+ sd: sdhc@5a400000 { + compatible = "socionext,uniphier-sdhc"; + status = "disabled"; + reg = <0x5a400000 0x200>; + interrupts = <0 76 4>; + pinctrl-names = "default", "1.8v"; + pinctrl-0 = <&pinctrl_sd>; + pinctrl-1 = <&pinctrl_sd_1v8>; + clocks = <&mio 0>; + bus-width = <4>; + }; + + emmc: sdhc@5a500000 { + compatible = "socionext,uniphier-sdhc"; + status = "disabled"; + reg = <0x5a500000 0x200>; + interrupts = <0 78 4>; + pinctrl-names = "default", "1.8v"; + pinctrl-0 = <&pinctrl_emmc>; + pinctrl-1 = <&pinctrl_emmc_1v8>; + clocks = <&mio 1>; + bus-width = <8>; + non-removable; + }; + + sd1: sdhc@5a600000 { + compatible = "socionext,uniphier-sdhc"; + status = "disabled"; + reg = <0x5a600000 0x200>; + interrupts = <0 85 4>; + pinctrl-names = "default", "1.8v"; + pinctrl-0 = <&pinctrl_sd1>; + pinctrl-1 = <&pinctrl_sd1_1v8>; + clocks = <&mio 2>; + bus-width = <4>; + }; + usb2: usb@5a800100 { compatible = "socionext,uniphier-ehci", "generic-ehci"; status = "disabled"; diff --git a/arch/arm/dts/uniphier-ph1-pro5-4kbox.dts b/arch/arm/dts/uniphier-ph1-pro5-4kbox.dts index 02a3362..cbdc3eb 100644 --- a/arch/arm/dts/uniphier-ph1-pro5-4kbox.dts +++ b/arch/arm/dts/uniphier-ph1-pro5-4kbox.dts @@ -47,6 +47,14 @@ status = "okay"; };
+&emmc { + status = "okay"; +}; + +&sd { + status = "okay"; +}; + /* for U-Boot only */ / { soc { diff --git a/arch/arm/dts/uniphier-ph1-pro5.dtsi b/arch/arm/dts/uniphier-ph1-pro5.dtsi index 087b25a..56b5f3d 100644 --- a/arch/arm/dts/uniphier-ph1-pro5.dtsi +++ b/arch/arm/dts/uniphier-ph1-pro5.dtsi @@ -152,6 +152,30 @@ clock-frequency = <400000>; };
+ emmc: sdhc@68400000 { + compatible = "socionext,uniphier-sdhc"; + status = "disabled"; + reg = <0x68400000 0x800>; + interrupts = <0 78 4>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_emmc>; + clocks = <&mio 1>; + bus-width = <8>; + non-removable; + }; + + sd: sdhc@68800000 { + compatible = "socionext,uniphier-sdhc"; + status = "disabled"; + reg = <0x68800000 0x800>; + interrupts = <0 76 4>; + pinctrl-names = "default", "1.8v"; + pinctrl-0 = <&pinctrl_sd>; + pinctrl-1 = <&pinctrl_sd_1v8>; + clocks = <&mio 0>; + bus-width = <4>; + }; + usb0: usb@65a00000 { compatible = "socionext,uniphier-xhci", "generic-xhci"; status = "disabled"; diff --git a/arch/arm/dts/uniphier-ph1-sld3-ref.dts b/arch/arm/dts/uniphier-ph1-sld3-ref.dts index ff17945..c7213c9 100644 --- a/arch/arm/dts/uniphier-ph1-sld3-ref.dts +++ b/arch/arm/dts/uniphier-ph1-sld3-ref.dts @@ -52,6 +52,10 @@ status = "okay"; };
+&sd { + status = "okay"; +}; + &usb0 { status = "okay"; }; diff --git a/arch/arm/dts/uniphier-ph1-sld3.dtsi b/arch/arm/dts/uniphier-ph1-sld3.dtsi index 85dde66..d118e17 100644 --- a/arch/arm/dts/uniphier-ph1-sld3.dtsi +++ b/arch/arm/dts/uniphier-ph1-sld3.dtsi @@ -186,6 +186,25 @@ clocks = <&sysctrl 10>, <&sysctrl 18>; };
+ emmc: sdhc@5a400000 { + compatible = "socionext,uniphier-sdhc"; + status = "disabled"; + reg = <0x5a400000 0x200>; + interrupts = <0 78 4>; + clocks = <&mio 1>; + bus-width = <8>; + non-removable; + }; + + sd: sdhc@5a500000 { + compatible = "socionext,uniphier-sdhc"; + status = "disabled"; + reg = <0x5a500000 0x200>; + interrupts = <0 76 4>; + clocks = <&mio 0>; + bus-width = <4>; + }; + usb0: usb@5a800100 { compatible = "socionext,uniphier-ehci", "generic-ehci"; status = "disabled"; diff --git a/arch/arm/dts/uniphier-ph1-sld8-ref.dts b/arch/arm/dts/uniphier-ph1-sld8-ref.dts index b5b6f65..ec5c5bd 100644 --- a/arch/arm/dts/uniphier-ph1-sld8-ref.dts +++ b/arch/arm/dts/uniphier-ph1-sld8-ref.dts @@ -51,6 +51,10 @@ status = "okay"; };
+&sd { + status = "okay"; +}; + &usb0 { status = "okay"; }; diff --git a/arch/arm/dts/uniphier-ph1-sld8.dtsi b/arch/arm/dts/uniphier-ph1-sld8.dtsi index f93db83..159354f 100644 --- a/arch/arm/dts/uniphier-ph1-sld8.dtsi +++ b/arch/arm/dts/uniphier-ph1-sld8.dtsi @@ -108,6 +108,31 @@ clock-frequency = <100000>; };
+ sd: sdhc@5a400000 { + compatible = "socionext,uniphier-sdhc"; + status = "disabled"; + reg = <0x5a400000 0x200>; + interrupts = <0 76 4>; + pinctrl-names = "default", "1.8v"; + pinctrl-0 = <&pinctrl_sd>; + pinctrl-1 = <&pinctrl_sd_1v8>; + clocks = <&mio 0>; + bus-width = <4>; + }; + + emmc: sdhc@5a500000 { + compatible = "socionext,uniphier-sdhc"; + status = "disabled"; + interrupts = <0 78 4>; + reg = <0x5a500000 0x200>; + pinctrl-names = "default", "1.8v"; + pinctrl-0 = <&pinctrl_emmc>; + pinctrl-1 = <&pinctrl_emmc_1v8>; + clocks = <&mio 1>; + bus-width = <8>; + non-removable; + }; + usb0: usb@5a800100 { compatible = "socionext,uniphier-ehci", "generic-ehci"; status = "disabled"; diff --git a/arch/arm/dts/uniphier-pinctrl.dtsi b/arch/arm/dts/uniphier-pinctrl.dtsi index b1691d0..494139a 100644 --- a/arch/arm/dts/uniphier-pinctrl.dtsi +++ b/arch/arm/dts/uniphier-pinctrl.dtsi @@ -12,6 +12,11 @@ function = "emmc"; };
+ pinctrl_emmc_1v8: emmc_grp_1v8 { + groups = "emmc", "emmc_dat8"; + function = "emmc"; + }; + pinctrl_i2c0: i2c0_grp { groups = "i2c0"; function = "i2c0"; @@ -37,11 +42,21 @@ function = "sd"; };
+ pinctrl_sd_1v8: sd_grp_1v8 { + groups = "sd"; + function = "sd"; + }; + pinctrl_sd1: sd1_grp { groups = "sd1"; function = "sd1"; };
+ pinctrl_sd1_1v8: sd1_grp_1v8 { + groups = "sd1"; + function = "sd1"; + }; + pinctrl_uart0: uart0_grp { groups = "uart0"; function = "uart0"; diff --git a/arch/arm/dts/uniphier-proxstream2-gentil.dts b/arch/arm/dts/uniphier-proxstream2-gentil.dts index c6c133a..b198d8e 100644 --- a/arch/arm/dts/uniphier-proxstream2-gentil.dts +++ b/arch/arm/dts/uniphier-proxstream2-gentil.dts @@ -41,6 +41,10 @@ status = "okay"; };
+&emmc { + status = "okay"; +}; + &usb0 { status = "okay"; }; diff --git a/arch/arm/dts/uniphier-proxstream2-vodka.dts b/arch/arm/dts/uniphier-proxstream2-vodka.dts index 3703ad3..d61e0b6 100644 --- a/arch/arm/dts/uniphier-proxstream2-vodka.dts +++ b/arch/arm/dts/uniphier-proxstream2-vodka.dts @@ -41,6 +41,10 @@ status = "okay"; };
+&emmc { + status = "okay"; +}; + &usb0 { status = "okay"; }; diff --git a/arch/arm/dts/uniphier-proxstream2.dtsi b/arch/arm/dts/uniphier-proxstream2.dtsi index a70b135..a01725f 100644 --- a/arch/arm/dts/uniphier-proxstream2.dtsi +++ b/arch/arm/dts/uniphier-proxstream2.dtsi @@ -163,6 +163,30 @@ clock-frequency = <400000>; };
+ emmc: sdhc@5a000000 { + compatible = "socionext,uniphier-sdhc"; + status = "disabled"; + reg = <0x5a000000 0x800>; + interrupts = <0 78 4>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_emmc>; + clocks = <&mio 1>; + bus-width = <8>; + non-removable; + }; + + sd: sdhc@5a400000 { + compatible = "socionext,uniphier-sdhc"; + status = "disabled"; + reg = <0x5a400000 0x800>; + interrupts = <0 76 4>; + pinctrl-names = "default", "1.8v"; + pinctrl-0 = <&pinctrl_sd>; + pinctrl-1 = <&pinctrl_sd_1v8>; + clocks = <&mio 0>; + bus-width = <4>; + }; + usb0: usb@65a00000 { compatible = "socionext,uniphier-xhci", "generic-xhci"; status = "disabled";
participants (2)
-
Marek Vasut
-
Masahiro Yamada