From patchwork Thu Dec 1 02:06:07 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andes X-Patchwork-Id: 701318 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 3tTh916S6Pz9t14 for ; Thu, 1 Dec 2016 13:30:45 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 0C8CCA75B4; Thu, 1 Dec 2016 03:30:44 +0100 (CET) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id Y1ZADYAluloP; Thu, 1 Dec 2016 03:30:43 +0100 (CET) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 93139A7593; Thu, 1 Dec 2016 03:30:43 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 4BD1AA7593 for ; Thu, 1 Dec 2016 03:30:39 +0100 (CET) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id hLqsbADUKyfW for ; Thu, 1 Dec 2016 03:30:39 +0100 (CET) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail.andestech.com (exmail.andestech.com [59.124.169.137]) by theia.denx.de (Postfix) with ESMTPS id D5FF8A7576 for ; Thu, 1 Dec 2016 03:30:37 +0100 (CET) Received: from app09.andestech.com (10.0.4.97) by ATCPCS16.andestech.com (10.0.1.222) with Microsoft SMTP Server id 14.3.123.3; Thu, 1 Dec 2016 10:30:26 +0800 From: Andes To: , , Date: Thu, 1 Dec 2016 10:06:07 +0800 Message-ID: <1480557967-6628-1-git-send-email-uboot@andestech.com> X-Mailer: git-send-email 1.7.9.5 MIME-Version: 1.0 X-Originating-IP: [10.0.4.97] Subject: [U-Boot] [PATCH] nds32: Support mmc DM. X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.15 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" From: rick Add Andestech mmc DM driver for ag101p board. Do not use get_timer() to check mmc state can improve throughput performance. Signed-off-by: rick Cc: Andes --- arch/nds32/dts/ag101p.dts | 8 ++ board/AndesTech/adp-ag101p/adp-ag101p.c | 2 + configs/adp-ag101p_defconfig | 4 + drivers/mmc/Kconfig | 7 ++ drivers/mmc/Makefile | 1 + drivers/mmc/ftsdc010_mci.c | 104 +++++++++++++++++------ drivers/mmc/nds32_mmc.c | 138 +++++++++++++++++++++++++++++++ include/faraday/ftsdc010.h | 40 +++++++++ 8 files changed, 277 insertions(+), 27 deletions(-) create mode 100644 drivers/mmc/nds32_mmc.c diff --git a/arch/nds32/dts/ag101p.dts b/arch/nds32/dts/ag101p.dts index 8099665..c87d0bd 100644 --- a/arch/nds32/dts/ag101p.dts +++ b/arch/nds32/dts/ag101p.dts @@ -59,4 +59,12 @@ reg = <0x90900000 0x1000>; interrupts = <25 4>; }; + + mmc0: mmc@98e00000 { + compatible = "andestech,atsdc010"; + clock-freq-min-max = <400000 30000000>; + fifo-depth = <0x10>; + reg = <0x98e00000 0x1000>; + interrupts = <5 4>; + }; }; diff --git a/board/AndesTech/adp-ag101p/adp-ag101p.c b/board/AndesTech/adp-ag101p/adp-ag101p.c index 84c77f7..dbeb662 100644 --- a/board/AndesTech/adp-ag101p/adp-ag101p.c +++ b/board/AndesTech/adp-ag101p/adp-ag101p.c @@ -76,6 +76,8 @@ ulong board_flash_get_legacy(ulong base, int banknum, flash_info_t *info) int board_mmc_init(bd_t *bis) { +#ifndef CONFIG_DM_MMC ftsdc010_mmc_init(0); +#endif return 0; } diff --git a/configs/adp-ag101p_defconfig b/configs/adp-ag101p_defconfig index 8c2fc0b..f22a85b 100644 --- a/configs/adp-ag101p_defconfig +++ b/configs/adp-ag101p_defconfig @@ -12,6 +12,10 @@ CONFIG_CMD_EXT2=y CONFIG_CMD_FAT=y CONFIG_OF_CONTROL=y CONFIG_DM=y +CONFIG_BLK=y +CONFIG_DM_MMC=y +CONFIG_DM_MMC_OPS=y +CONFIG_NDS32_MMC=y CONFIG_DM_SERIAL=y CONFIG_SYS_NS16550=y CONFIG_TIMER=y diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index ba9a723..e50109d 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -53,6 +53,13 @@ config ROCKCHIP_DWMMC SD 3.0, SDIO 3.0 and MMC 4.5 and supports common eMMC chips as well as removeable SD and micro-SD cards. +config NDS32_MMC + bool "Andestech SD/MMC controller support" + depends on DM_MMC && OF_CONTROL + help + This enables support for the Andestech SD/MMM controller, which is + based on Faraday IP. + config SH_SDHI bool "SuperH/Renesas ARM SoCs on-chip SDHI host controller support" depends on RMOBILE diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 18351fb..e81fe58 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -40,6 +40,7 @@ obj-$(CONFIG_OMAP_HSMMC) += omap_hsmmc.o obj-$(CONFIG_X86) += pci_mmc.o obj-$(CONFIG_PXA_MMC_GENERIC) += pxa_mmc_gen.o obj-$(CONFIG_ROCKCHIP_DWMMC) += rockchip_dw_mmc.o +obj-$(CONFIG_NDS32_MMC) += nds32_mmc.o obj-$(CONFIG_SUPPORT_EMMC_RPMB) += rpmb.o obj-$(CONFIG_S3C_SDI) += s3c_sdi.o obj-$(CONFIG_S5P_SDHCI) += s5p_sdhci.o diff --git a/drivers/mmc/ftsdc010_mci.c b/drivers/mmc/ftsdc010_mci.c index e88c632..7ba4f39 100644 --- a/drivers/mmc/ftsdc010_mci.c +++ b/drivers/mmc/ftsdc010_mci.c @@ -11,7 +11,6 @@ #include #include #include - #include #include #include @@ -20,16 +19,6 @@ #define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 4) /* 250 ms */ #define CFG_RST_TIMEOUT CONFIG_SYS_HZ /* 1 sec reset timeout */ -struct ftsdc010_chip { - void __iomem *regs; - uint32_t wprot; /* write protected (locked) */ - uint32_t rate; /* actual SD clock in Hz */ - uint32_t sclk; /* FTSDC010 source clock in Hz */ - uint32_t fifo; /* fifo depth in bytes */ - uint32_t acmd; - struct mmc_config cfg; /* mmc configuration */ -}; - static inline int ftsdc010_send_cmd(struct mmc *mmc, struct mmc_cmd *mmc_cmd) { struct ftsdc010_chip *chip = mmc->priv; @@ -127,9 +116,8 @@ static void ftsdc010_clkset(struct mmc *mmc, uint32_t rate) static int ftsdc010_wait(struct ftsdc010_mmc __iomem *regs, uint32_t mask) { int ret = -ETIMEDOUT; - uint32_t st, ts; - - for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) { + uint32_t st, timeout = 10000000; + while (timeout--) { st = readl(®s->status); if (!(st & mask)) continue; @@ -137,7 +125,6 @@ static int ftsdc010_wait(struct ftsdc010_mmc __iomem *regs, uint32_t mask) ret = 0; break; } - if (ret) debug("ftsdc010: wait st(0x%x) timeout\n", mask); @@ -147,10 +134,16 @@ static int ftsdc010_wait(struct ftsdc010_mmc __iomem *regs, uint32_t mask) /* * u-boot mmc api */ - +#ifdef CONFIG_DM_MMC_OPS +static int ftsdc010_request(struct udevice *dev, struct mmc_cmd *cmd, + struct mmc_data *data) +{ + struct mmc *mmc = mmc_get_mmc_dev(dev); +#else static int ftsdc010_request(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) { +#endif int ret = -EOPNOTSUPP; uint32_t len = 0; struct ftsdc010_chip *chip = mmc->priv; @@ -251,8 +244,14 @@ static int ftsdc010_request(struct mmc *mmc, struct mmc_cmd *cmd, return ret; } +#ifdef CONFIG_DM_MMC_OPS +static int ftsdc010_set_ios(struct udevice *dev) +{ + struct mmc *mmc = mmc_get_mmc_dev(dev); +#else static void ftsdc010_set_ios(struct mmc *mmc) { +#endif struct ftsdc010_chip *chip = mmc->priv; struct ftsdc010_mmc __iomem *regs = chip->regs; @@ -270,6 +269,9 @@ static void ftsdc010_set_ios(struct mmc *mmc) setbits_le32(®s->bwr, FTSDC010_BWR_MODE_1BIT); break; } +#ifdef CONFIG_DM_MMC_OPS + return 0; +#endif } static int ftsdc010_init(struct mmc *mmc) @@ -309,11 +311,66 @@ static int ftsdc010_init(struct mmc *mmc) return 0; } +#ifdef CONFIG_DM_MMC_OPS +int ftsdc010_probe(struct udevice *dev) +{ + struct mmc *mmc = mmc_get_mmc_dev(dev); + return ftsdc010_init(mmc); +} + +const struct dm_mmc_ops dm_ftsdc010_ops = { + .send_cmd = ftsdc010_request, + .set_ios = ftsdc010_set_ios, +}; + +#else static const struct mmc_ops ftsdc010_ops = { .send_cmd = ftsdc010_request, .set_ios = ftsdc010_set_ios, .init = ftsdc010_init, }; +#endif + +void ftsdc_setup_cfg(struct mmc_config *cfg, const char *name, int buswidth, + uint caps, u32 max_clk, u32 min_clk) +{ + cfg->name = name; + cfg->f_min = min_clk; + cfg->f_max = max_clk; + cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; + cfg->host_caps = caps; + if (buswidth == 8) { + cfg->host_caps |= MMC_MODE_8BIT; + cfg->host_caps &= ~MMC_MODE_4BIT; + } else { + cfg->host_caps |= MMC_MODE_4BIT; + cfg->host_caps &= ~MMC_MODE_8BIT; + } + cfg->host_caps |= MMC_MODE_HS | MMC_MODE_HS_52MHz; + cfg->part_type = PART_TYPE_DOS; + cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; +} + +void set_bus_width(struct ftsdc010_mmc __iomem *regs, struct mmc_config *cfg) +{ + switch (readl(®s->bwr) & FTSDC010_BWR_CAPS_MASK) { + case FTSDC010_BWR_CAPS_4BIT: + cfg->host_caps |= MMC_MODE_4BIT; + break; + case FTSDC010_BWR_CAPS_8BIT: + cfg->host_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT; + break; + default: + break; + } +} + +#ifdef CONFIG_BLK +int ftsdc010_bind(struct udevice *dev, struct mmc *mmc, struct mmc_config *cfg) +{ + return mmc_bind(dev, mmc, cfg); +} +#else int ftsdc010_mmc_init(int devid) { @@ -343,19 +400,11 @@ int ftsdc010_mmc_init(int devid) #endif chip->cfg.name = "ftsdc010"; +#ifndef CONFIG_DM_MMC_OPS chip->cfg.ops = &ftsdc010_ops; +#endif chip->cfg.host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz; - switch (readl(®s->bwr) & FTSDC010_BWR_CAPS_MASK) { - case FTSDC010_BWR_CAPS_4BIT: - chip->cfg.host_caps |= MMC_MODE_4BIT; - break; - case FTSDC010_BWR_CAPS_8BIT: - chip->cfg.host_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT; - break; - default: - break; - } - + set_bus_width(regs , &chip->cfg); chip->cfg.voltages = MMC_VDD_32_33 | MMC_VDD_33_34; chip->cfg.f_max = chip->sclk / 2; chip->cfg.f_min = chip->sclk / 0x100; @@ -371,3 +420,4 @@ int ftsdc010_mmc_init(int devid) return 0; } +#endif diff --git a/drivers/mmc/nds32_mmc.c b/drivers/mmc/nds32_mmc.c new file mode 100644 index 0000000..635d32b --- /dev/null +++ b/drivers/mmc/nds32_mmc.c @@ -0,0 +1,138 @@ +/* + * Andestech ATFSDC010 SD/MMC driver + * + * (C) Copyright 2016 + * Rick Chen, NDS32 Software Engineering, rick@andestech.com + + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +#if CONFIG_IS_ENABLED(OF_PLATDATA) +struct nds_mmc { + fdt32_t bus_width; + bool cap_mmc_highspeed; + bool cap_sd_highspeed; + fdt32_t card_detect_delay; + fdt32_t clock_freq_min_max[2]; + struct phandle_2_cell clocks[4]; + bool disable_wp; + fdt32_t fifo_depth; + fdt32_t interrupts[3]; + fdt32_t num_slots; + fdt32_t reg[2]; + fdt32_t vmmc_supply; +}; +#endif + +struct nds_mmc_plat { +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct nds_mmc dtplat; +#endif + struct mmc_config cfg; + struct mmc mmc; +}; + +struct ftsdc_priv { + struct clk clk; + struct ftsdc010_chip chip; + int fifo_depth; + bool fifo_mode; + u32 minmax[2]; +}; + +static int nds32_mmc_ofdata_to_platdata(struct udevice *dev) +{ +#if !CONFIG_IS_ENABLED(OF_PLATDATA) + struct ftsdc_priv *priv = dev_get_priv(dev); + struct ftsdc010_chip *chip = &priv->chip; + chip->name = dev->name; + chip->ioaddr = (void *)dev_get_addr(dev); + chip->buswidth = fdtdec_get_int(gd->fdt_blob, dev->of_offset, + "bus-width", 4); + chip->priv = dev; + /* use non-removeable as sdcard and emmc as judgement */ + if (fdtdec_get_bool(gd->fdt_blob, dev->of_offset, "non-removable")) + chip->dev_index = 0; + else + chip->dev_index = 1; + + priv->fifo_depth = fdtdec_get_int(gd->fdt_blob, dev->of_offset, + "fifo-depth", 0); + priv->fifo_mode = fdtdec_get_bool(gd->fdt_blob, dev->of_offset, + "fifo-mode"); + if (fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, + "clock-freq-min-max", priv->minmax, 2)) + return -EINVAL; +#endif + chip->sclk = priv->minmax[1]; + chip->regs = chip->ioaddr; + return 0; +} + +static int nds32_mmc_probe(struct udevice *dev) +{ + struct nds_mmc_plat *plat = dev_get_platdata(dev); + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); + struct ftsdc_priv *priv = dev_get_priv(dev); + struct ftsdc010_chip *chip = &priv->chip; + struct udevice *pwr_dev __maybe_unused; +#if CONFIG_IS_ENABLED(OF_PLATDATA) + int ret; + struct nds_mmc *dtplat = &plat->dtplat; + chip->name = dev->name; + chip->ioaddr = map_sysmem(dtplat->reg[0], dtplat->reg[1]); + chip->buswidth = dtplat->bus_width; + chip->priv = dev; + chip->dev_index = 0; + priv->fifo_depth = dtplat->fifo_depth; + priv->fifo_mode = 0; + memcpy(priv->minmax, dtplat->clock_freq_min_max, sizeof(priv->minmax)); + ret = clk_get_by_index_platdata(dev, 0, dtplat->clocks, &priv->clk); + if (ret < 0) + return ret; +#endif + ftsdc_setup_cfg(&plat->cfg, dev->name, chip->buswidth, chip->caps, + priv->minmax[1], priv->minmax[0]); + chip->mmc = &plat->mmc; + chip->mmc->priv = &priv->chip; + chip->mmc->dev = dev; + upriv->mmc = chip->mmc; + return ftsdc010_probe(dev); +} + +static int nds32_mmc_bind(struct udevice *dev) +{ + struct nds_mmc_plat *plat = dev_get_platdata(dev); + return ftsdc010_bind(dev, &plat->mmc, &plat->cfg); +} + +static const struct udevice_id nds32_mmc_ids[] = { + { .compatible = "andestech,atsdc010" }, + { } +}; + +U_BOOT_DRIVER(rockchip_dwmmc_drv) = { + .name = "nds32_mmc", + .id = UCLASS_MMC, + .of_match = nds32_mmc_ids, + .ofdata_to_platdata = nds32_mmc_ofdata_to_platdata, + .ops = &dm_ftsdc010_ops, + .bind = nds32_mmc_bind, + .probe = nds32_mmc_probe, + .priv_auto_alloc_size = sizeof(struct ftsdc_priv), + .platdata_auto_alloc_size = sizeof(struct nds_mmc_plat), +}; diff --git a/include/faraday/ftsdc010.h b/include/faraday/ftsdc010.h index 9bfdef9..4d2b1b6 100644 --- a/include/faraday/ftsdc010.h +++ b/include/faraday/ftsdc010.h @@ -6,6 +6,7 @@ * * SPDX-License-Identifier: GPL-2.0+ */ +#include #ifndef __FTSDC010_H #define __FTSDC010_H @@ -243,4 +244,43 @@ int ftsdc010_mmc_init(int dev_index); #endif /* CONFIG_FTSDC010_SDIO */ +struct ftsdc010_chip { + void __iomem *regs; + uint32_t wprot; /* write protected (locked) */ + uint32_t rate; /* actual SD clock in Hz */ + uint32_t sclk; /* FTSDC010 source clock in Hz */ + uint32_t fifo; /* fifo depth in bytes */ + uint32_t acmd; + struct mmc_config cfg; /* mmc configuration */ + const char *name; + void *ioaddr; + unsigned int quirks; + unsigned int caps; + unsigned int version; + unsigned int clock; + unsigned int bus_hz; + unsigned int div; + int dev_index; + int dev_id; + int buswidth; + u32 fifoth_val; + struct mmc *mmc; + void *priv; + bool fifo_mode; +}; + + +#ifdef CONFIG_DM_MMC_OPS +/* Export the operations to drivers */ +int ftsdc010_probe(struct udevice *dev); +extern const struct dm_mmc_ops dm_ftsdc010_ops; +#endif +void ftsdc_setup_cfg(struct mmc_config *cfg, const char *name, int buswidth, + uint caps, u32 max_clk, u32 min_clk); + +#ifdef CONFIG_BLK +int ftsdc010_bind(struct udevice *dev, struct mmc *mmc, struct mmc_config *cfg); +#endif + + #endif /* __FTSDC010_H */