Merge tag 'arc-for-2019.07' of git://git.denx.de/u-boot-arc

In this small series we migrate ARC boards to DM_MMC
so we're hopefully are good now and our boards will be kept
in U-Boot for some more time :)
This commit is contained in:
Tom Rini 2019-04-18 12:12:16 -04:00
commit 1f4ae66eaa
11 changed files with 314 additions and 64 deletions

View file

@ -74,6 +74,13 @@ L: uboot-snps-arc@synopsys.com
F: doc/device-tree-bindings/gpio/snps,creg-gpio.txt F: doc/device-tree-bindings/gpio/snps,creg-gpio.txt
F: drivers/gpio/hsdk-creg-gpio.c F: drivers/gpio/hsdk-creg-gpio.c
ARC SYNOPSYS DW MMC EXTENSIONS
M: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
S: Maintained
L: uboot-snps-arc@synopsys.com
F: doc/device-tree-bindings/mmc/snps,dw-mmc.txt
F: drivers/mmc/snps_dw_mmc.c
ARM ARM
M: Albert Aribaud <albert.u.boot@aribaud.net> M: Albert Aribaud <albert.u.boot@aribaud.net>
S: Maintained S: Maintained

View file

@ -31,6 +31,25 @@
#clock-cells = <0>; #clock-cells = <0>;
u-boot,dm-pre-reloc; u-boot,dm-pre-reloc;
}; };
mmcclk_ciu: mmcclk-ciu {
compatible = "fixed-clock";
/*
* DW sdio controller has external ciu clock divider
* controlled via register in SDIO IP. It divides
* sdio_ref_clk (which comes from CGU) by 16 for
* default. So default mmcclk clock (which comes
* to sdk_in) is 25000000 Hz.
*/
clock-frequency = <25000000>;
#clock-cells = <0>;
};
mmcclk_biu: mmcclk-biu {
compatible = "fixed-clock";
clock-frequency = <50000000>;
#clock-cells = <0>;
};
}; };
ethernet@18000 { ethernet@18000 {
@ -53,6 +72,15 @@
reg = < 0x60000 0x100 >; reg = < 0x60000 0x100 >;
}; };
mmc: mmc@15000 {
compatible = "snps,dw-mshc";
reg = <0x15000 0x400>;
bus-width = <4>;
clocks = <&mmcclk_biu>, <&mmcclk_ciu>;
clock-names = "biu", "ciu";
max-frequency = <25000000>;
};
uart0: serial0@22000 { uart0: serial0@22000 {
compatible = "snps,dw-apb-uart"; compatible = "snps,dw-apb-uart";
reg = <0x22000 0x100>; reg = <0x22000 0x100>;

View file

@ -86,6 +86,32 @@
reg = <0xf0060000 0x100>; reg = <0xf0060000 0x100>;
}; };
mmcclk_ciu: mmcclk-ciu {
compatible = "fixed-clock";
/*
* DW sdio controller has external ciu clock divider
* controlled via register in SDIO IP. Due to its
* unexpected default value (it should divide by 1
* but it divides by 8) SDIO IP uses wrong clock and
* works unstable (see STAR 9001204800)
* We switched to the minimum possible value of the
* divisor (div-by-2) in HSDK platform code.
* So default mmcclk ciu clock is 50000000 Hz.
*/
clock-frequency = <50000000>;
#clock-cells = <0>;
};
mmc: mmc0@f000a000 {
compatible = "snps,dw-mshc";
reg = <0xf000a000 0x400>;
bus-width = <4>;
fifo-depth = <256>;
clocks = <&cgu_clk CLK_SYS_SDIO>, <&mmcclk_ciu>;
clock-names = "biu", "ciu";
max-frequency = <25000000>;
};
spi0: spi@f0020000 { spi0: spi@f0020000 {
compatible = "snps,dw-apb-ssi"; compatible = "snps,dw-apb-ssi";
reg = <0xf0020000 0x1000>; reg = <0xf0020000 0x1000>;

View file

@ -11,35 +11,6 @@
DECLARE_GLOBAL_DATA_PTR; DECLARE_GLOBAL_DATA_PTR;
int board_mmc_init(bd_t *bis)
{
struct dwmci_host *host = NULL;
host = malloc(sizeof(struct dwmci_host));
if (!host) {
printf("dwmci_host malloc fail!\n");
return 1;
}
memset(host, 0, sizeof(struct dwmci_host));
host->name = "Synopsys Mobile storage";
host->ioaddr = (void *)ARC_DWMMC_BASE;
host->buswidth = 4;
host->dev_index = 0;
host->bus_hz = 50000000;
add_dwmci(host, host->bus_hz / 2, 400000);
return 0;
}
int board_mmc_getcd(struct mmc *mmc)
{
struct dwmci_host *host = mmc->priv;
return !(dwmci_readl(host, DWMCI_CDETECT) & 1);
}
#define AXS_MB_CREG 0xE0011000 #define AXS_MB_CREG 0xE0011000
int board_early_init_f(void) int board_early_init_f(void)

View file

@ -982,6 +982,12 @@ int board_early_init_f(void)
*/ */
init_memory_bridge(); init_memory_bridge();
/*
* Switch SDIO external ciu clock divider from default div-by-8 to
* minimum possible div-by-2.
*/
writel(SDIO_UHS_REG_EXT_DIV_2, (void __iomem *)SDIO_UHS_REG_EXT);
return 0; return 0;
} }
@ -1019,41 +1025,6 @@ int board_late_init(void)
return 0; return 0;
} }
int board_mmc_getcd(struct mmc *mmc)
{
struct dwmci_host *host = mmc->priv;
return !(dwmci_readl(host, DWMCI_CDETECT) & 1);
}
int board_mmc_init(bd_t *bis)
{
struct dwmci_host *host = NULL;
host = malloc(sizeof(struct dwmci_host));
if (!host) {
printf("dwmci_host malloc fail!\n");
return 1;
}
/*
* Switch SDIO external ciu clock divider from default div-by-8 to
* minimum possible div-by-2.
*/
writel(SDIO_UHS_REG_EXT_DIV_2, (void __iomem *)SDIO_UHS_REG_EXT);
memset(host, 0, sizeof(struct dwmci_host));
host->name = "Synopsys Mobile storage";
host->ioaddr = (void *)ARC_DWMMC_BASE;
host->buswidth = 4;
host->dev_index = 0;
host->bus_hz = 50000000;
add_dwmci(host, host->bus_hz / 2, 400000);
return 0;
}
int checkboard(void) int checkboard(void)
{ {
puts("Board: Synopsys ARC HS Development Kit\n"); puts("Board: Synopsys ARC HS Development Kit\n");

View file

@ -35,7 +35,9 @@ CONFIG_DM=y
CONFIG_DM_GPIO=y CONFIG_DM_GPIO=y
CONFIG_HSDK_CREG_GPIO=y CONFIG_HSDK_CREG_GPIO=y
CONFIG_MMC=y CONFIG_MMC=y
CONFIG_DM_MMC=y
CONFIG_MMC_DW=y CONFIG_MMC_DW=y
CONFIG_MMC_DW_SNPS=y
CONFIG_DM_SPI_FLASH=y CONFIG_DM_SPI_FLASH=y
CONFIG_SPI_FLASH=y CONFIG_SPI_FLASH=y
CONFIG_SPI_FLASH_STMICRO=y CONFIG_SPI_FLASH_STMICRO=y

View file

@ -38,7 +38,9 @@ CONFIG_CLK_HSDK=y
CONFIG_DM_GPIO=y CONFIG_DM_GPIO=y
CONFIG_HSDK_CREG_GPIO=y CONFIG_HSDK_CREG_GPIO=y
CONFIG_MMC=y CONFIG_MMC=y
CONFIG_DM_MMC=y
CONFIG_MMC_DW=y CONFIG_MMC_DW=y
CONFIG_MMC_DW_SNPS=y
CONFIG_DM_SPI_FLASH=y CONFIG_DM_SPI_FLASH=y
CONFIG_SPI_FLASH=y CONFIG_SPI_FLASH=y
CONFIG_SPI_FLASH_SST=y CONFIG_SPI_FLASH_SST=y

View file

@ -0,0 +1,33 @@
Synopsys Designware Mobile Storage Host Controller extensions
used in Synopsys ARC devboards
Required Properties:
* compatible: should be - "snps,dw-mshc".
* bus-width: number of data lines connected to the controller.
* clocks: from common clock binding: handle to biu and ciu clocks for the
bus interface unit clock and the card interface unit clock.
* clock-names: from common clock binding: Shall be "biu" and "ciu".
Optional properties:
* fifo-depth: The maximum size of the tx/rx fifo's. If this property is not
specified, the default value of the fifo size is determined from the
controller registers.
* fifo-mode: Don't use DMA.
* max-frequency: Maximum operating clock frequency, driver uses 'ciu' clock
frequency if it is not set.
Example:
mmc0@f000a000 {
compatible = "snps,dw-mshc";
reg = <0xf000a000 0x400>;
bus-width = <4>;
fifo-depth = <256>;
clocks = <&mmcclk_biu>, <&mmcclk_ciu>;
clock-names = "biu", "ciu";
max-frequency = <25000000>;
};

View file

@ -222,6 +222,16 @@ config MMC_DW_SOCFPGA
Synopsys DesignWare Memory Card Interface driver. Select this option Synopsys DesignWare Memory Card Interface driver. Select this option
for platforms based on Altera SOCFPGA. for platforms based on Altera SOCFPGA.
config MMC_DW_SNPS
bool "Extensions for DW Memory Card Interface used in Synopsys ARC devboards"
depends on MMC_DW
depends on DM_MMC
depends on OF_CONTROL
depends on CLK
help
This selects support for Synopsys DesignWare Memory Card Interface driver
extensions used in various Synopsys ARC devboards.
config MMC_MESON_GX config MMC_MESON_GX
bool "Meson GX EMMC controller support" bool "Meson GX EMMC controller support"
depends on DM_MMC && BLK && ARCH_MESON depends on DM_MMC && BLK && ARCH_MESON

View file

@ -24,6 +24,7 @@ obj-$(CONFIG_MMC_DW_EXYNOS) += exynos_dw_mmc.o
obj-$(CONFIG_MMC_DW_K3) += hi6220_dw_mmc.o obj-$(CONFIG_MMC_DW_K3) += hi6220_dw_mmc.o
obj-$(CONFIG_MMC_DW_ROCKCHIP) += rockchip_dw_mmc.o obj-$(CONFIG_MMC_DW_ROCKCHIP) += rockchip_dw_mmc.o
obj-$(CONFIG_MMC_DW_SOCFPGA) += socfpga_dw_mmc.o obj-$(CONFIG_MMC_DW_SOCFPGA) += socfpga_dw_mmc.o
obj-$(CONFIG_MMC_DW_SNPS) += snps_dw_mmc.o
obj-$(CONFIG_FSL_ESDHC) += fsl_esdhc.o obj-$(CONFIG_FSL_ESDHC) += fsl_esdhc.o
obj-$(CONFIG_FTSDC010) += ftsdc010_mci.o obj-$(CONFIG_FTSDC010) += ftsdc010_mci.o
obj-$(CONFIG_GENERIC_ATMEL_MCI) += gen_atmel_mci.o obj-$(CONFIG_GENERIC_ATMEL_MCI) += gen_atmel_mci.o

199
drivers/mmc/snps_dw_mmc.c Normal file
View file

@ -0,0 +1,199 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Synopsys DesignWare Multimedia Card Interface driver
* extensions used in various Synopsys ARC devboards.
*
* Copyright (C) 2019 Synopsys
* Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
*/
#include <common.h>
#include <clk.h>
#include <dm.h>
#include <dwmmc.h>
#include <errno.h>
#include <fdtdec.h>
#include <linux/libfdt.h>
#include <linux/err.h>
#include <malloc.h>
#define CLOCK_MIN 400000 /* 400 kHz */
#define FIFO_MIN 8
#define FIFO_MAX 4096
struct snps_dwmci_plat {
struct mmc_config cfg;
struct mmc mmc;
};
struct snps_dwmci_priv_data {
struct dwmci_host host;
u32 f_max;
};
static int snps_dwmmc_clk_setup(struct udevice *dev)
{
struct snps_dwmci_priv_data *priv = dev_get_priv(dev);
struct dwmci_host *host = &priv->host;
struct clk clk_ciu, clk_biu;
int ret;
ret = clk_get_by_name(dev, "ciu", &clk_ciu);
if (ret)
goto clk_err;
ret = clk_enable(&clk_ciu);
if (ret && ret != -ENOSYS && ret != -ENOTSUPP)
goto clk_err_ciu;
host->bus_hz = clk_get_rate(&clk_ciu);
if (host->bus_hz < CLOCK_MIN) {
ret = -EINVAL;
goto clk_err_ciu_dis;
}
ret = clk_get_by_name(dev, "biu", &clk_biu);
if (ret)
goto clk_err_ciu_dis;
ret = clk_enable(&clk_biu);
if (ret && ret != -ENOSYS && ret != -ENOTSUPP)
goto clk_err_biu;
return 0;
clk_err_biu:
clk_free(&clk_biu);
clk_err_ciu_dis:
clk_disable(&clk_ciu);
clk_err_ciu:
clk_free(&clk_ciu);
clk_err:
dev_err(dev, "failed to setup clocks, ret %d\n", ret);
return ret;
}
static int snps_dwmmc_ofdata_to_platdata(struct udevice *dev)
{
struct snps_dwmci_priv_data *priv = dev_get_priv(dev);
struct dwmci_host *host = &priv->host;
u32 fifo_depth;
int ret;
host->ioaddr = devfdt_get_addr_ptr(dev);
/*
* If fifo-depth is unset don't set fifoth_val - we will try to
* auto detect it.
*/
ret = dev_read_u32(dev, "fifo-depth", &fifo_depth);
if (!ret) {
if (fifo_depth < FIFO_MIN || fifo_depth > FIFO_MAX)
return -EINVAL;
host->fifoth_val = MSIZE(0x2) |
RX_WMARK(fifo_depth / 2 - 1) |
TX_WMARK(fifo_depth / 2);
}
host->buswidth = dev_read_u32_default(dev, "bus-width", 4);
if (host->buswidth != 1 && host->buswidth != 4 && host->buswidth != 8)
return -EINVAL;
/*
* If max-frequency is unset don't set priv->f_max - we will use
* host->bus_hz in probe() instead.
*/
ret = dev_read_u32(dev, "max-frequency", &priv->f_max);
if (!ret && priv->f_max < CLOCK_MIN)
return -EINVAL;
host->fifo_mode = dev_read_bool(dev, "fifo-mode");
host->name = dev->name;
host->dev_index = 0;
host->priv = priv;
return 0;
}
int snps_dwmmc_getcd(struct udevice *dev)
{
struct snps_dwmci_priv_data *priv = dev_get_priv(dev);
struct dwmci_host *host = &priv->host;
return !(dwmci_readl(host, DWMCI_CDETECT) & 1);
}
struct dm_mmc_ops snps_dwmci_dm_ops;
static int snps_dwmmc_probe(struct udevice *dev)
{
#ifdef CONFIG_BLK
struct snps_dwmci_plat *plat = dev_get_platdata(dev);
#endif
struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
struct snps_dwmci_priv_data *priv = dev_get_priv(dev);
struct dwmci_host *host = &priv->host;
unsigned int clock_max;
int ret;
/* Extend generic 'dm_dwmci_ops' with our 'getcd' implementation */
memcpy(&snps_dwmci_dm_ops, &dm_dwmci_ops, sizeof(struct dm_mmc_ops));
snps_dwmci_dm_ops.get_cd = snps_dwmmc_getcd;
ret = snps_dwmmc_clk_setup(dev);
if (ret)
return ret;
if (!priv->f_max)
clock_max = host->bus_hz;
else
clock_max = min_t(unsigned int, host->bus_hz, priv->f_max);
#ifdef CONFIG_BLK
dwmci_setup_cfg(&plat->cfg, host, clock_max, CLOCK_MIN);
host->mmc = &plat->mmc;
#else
ret = add_dwmci(host, clock_max, CLOCK_MIN);
if (ret)
return ret;
#endif
host->mmc->priv = &priv->host;
upriv->mmc = host->mmc;
host->mmc->dev = dev;
return dwmci_probe(dev);
}
static int snps_dwmmc_bind(struct udevice *dev)
{
#ifdef CONFIG_BLK
struct snps_dwmci_plat *plat = dev_get_platdata(dev);
int ret;
ret = dwmci_bind(dev, &plat->mmc, &plat->cfg);
if (ret)
return ret;
#endif
return 0;
}
static const struct udevice_id snps_dwmmc_ids[] = {
{ .compatible = "snps,dw-mshc" },
{ }
};
U_BOOT_DRIVER(snps_dwmmc_drv) = {
.name = "snps_dw_mmc",
.id = UCLASS_MMC,
.of_match = snps_dwmmc_ids,
.ofdata_to_platdata = snps_dwmmc_ofdata_to_platdata,
.ops = &snps_dwmci_dm_ops,
.bind = snps_dwmmc_bind,
.probe = snps_dwmmc_probe,
.priv_auto_alloc_size = sizeof(struct snps_dwmci_priv_data),
.platdata_auto_alloc_size = sizeof(struct snps_dwmci_plat),
};