* Re: [v15, 3/7] powerpc/fsl: move mpc85xx.h to include/linux/fsl
From: Arnd Bergmann @ 2016-11-07 21:20 UTC (permalink / raw)
To: Y.B. Lu
Cc: linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org,
linux-mmc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
ulf.hansson-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org, Scott Wood,
Mark Rutland, Greg Kroah-Hartman, X.B. Xie, M.H. Lian,
linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-clk-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Qiang Zhao,
Russell King, Bhupesh Sharma, Joerg Roedel, Claudiu Manoil,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Rob Herring
In-Reply-To: <DB6PR0401MB2536B1B2E6AC36BDC8FC540DF8AE0-2mNvjAGDOPkZcyyZo0JLBI3W/0Ik+aLCnBOFsp37pqbUKgpGm//BTAC/G2K4zDHf@public.gmane.org>
On Monday, October 31, 2016 9:35:33 AM CET Y.B. Lu wrote:
> >
> > I don't see any of the contents of this header referenced by the soc
> > driver any more. I think you can just drop this patch.
> >
>
> [Lu Yangbo-B47093] This header file was included by guts.c.
> The guts driver used macro SVR_MAJ/SVR_MIN for calculation.
>
> This header file was for powerpc arch before. And this patch is to made it as
> common header file for both ARM and PPC.
> Sooner or later this is needed.
Let's discuss it once we actually need the header then, ok?
Arnd
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v7 09/11] scsi: ufs: connect to RPMB subsystem
From: Christoph Hellwig @ 2016-11-07 21:37 UTC (permalink / raw)
To: Winkler, Tomas
Cc: Christoph Hellwig, Greg Kroah-Hartman, Ulf Hansson,
Hunter, Adrian, James Bottomley, Martin K . Petersen,
Vinayak Holikatti, Andy Lutomirski, Arve Hj?nnev?g,
Michael Ryleev, Joao Pinto, Yaniv Gardi, Avri Altman,
linux-kernel@vger.kernel.org, linux-mmc@vger.kernel.org,
linux-scsi@vger.kernel.org, linux-doc@vger.kernel.org
In-Reply-To: <5B8DA87D05A7694D9FA63FD143655C1B5431750E@hasmsx108.ger.corp.intel.com>
On Mon, Nov 07, 2016 at 07:27:38PM +0000, Winkler, Tomas wrote:
> I value your opinion but I'm not responsible for inventing RPMB
> and/or its implementation storage devices (eMMC, UFC, NVMe), it's pretty much done deal out there in the wild.
> I'm just trying to provide common API above it.
And the common API must go through the SCSI midlayer. If it can't we
won't support it, so please drop the UFS patches from the series.
^ permalink raw reply
* Re: [PATCH v4 2/5] mmc: zx: Initial support for ZX mmc controller
From: Jun Nie @ 2016-11-08 1:24 UTC (permalink / raw)
To: Shawn Guo, xie.baoyou
Cc: Ulf Hansson, Jaehoon Chung, Jason Liu, linux-mmc, Jun Nie
In-Reply-To: <1478523888-4524-3-git-send-email-jun.nie@linaro.org>
2016-11-07 21:04 GMT+08:00 Jun Nie <jun.nie@linaro.org>:
> This platform driver adds initial support for the DW host controller
> found on ZTE SoCs.
>
> It has been tested on ZX296718 EVB board currently. More support on
> timing tuning will be added when hardware is available.
>
> Signed-off-by: Jun Nie <jun.nie@linaro.org>
> ---
> drivers/mmc/host/Kconfig | 9 ++
> drivers/mmc/host/Makefile | 1 +
> drivers/mmc/host/dw_mmc-zx.c | 242 +++++++++++++++++++++++++++++++++++++++++++
> drivers/mmc/host/dw_mmc-zx.h | 31 ++++++
> 4 files changed, 283 insertions(+)
> create mode 100644 drivers/mmc/host/dw_mmc-zx.c
> create mode 100644 drivers/mmc/host/dw_mmc-zx.h
>
> diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
> index 5274f50..4dafbc2 100644
> --- a/drivers/mmc/host/Kconfig
> +++ b/drivers/mmc/host/Kconfig
> @@ -662,6 +662,15 @@ config MMC_DW_ROCKCHIP
> Synopsys DesignWare Memory Card Interface driver. Select this option
> for platforms based on RK3066, RK3188 and RK3288 SoC's.
>
> +config MMC_DW_ZX
> + tristate "ZTE specific extensions for Synopsys DW Memory Card Interface"
> + depends on MMC_DW && ARCH_ZX
> + select MMC_DW_PLTFM
> + help
> + This selects support for ZTE SoC specific extensions to the
> + Synopsys DesignWare Memory Card Interface driver. Select this option
> + for platforms based on ZX296718 SoC's.
> +
> config MMC_SH_MMCIF
> tristate "SuperH Internal MMCIF support"
> depends on HAS_DMA
> diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
> index e2bdaaf..9766143 100644
> --- a/drivers/mmc/host/Makefile
> +++ b/drivers/mmc/host/Makefile
> @@ -48,6 +48,7 @@ obj-$(CONFIG_MMC_DW_EXYNOS) += dw_mmc-exynos.o
> obj-$(CONFIG_MMC_DW_K3) += dw_mmc-k3.o
> obj-$(CONFIG_MMC_DW_PCI) += dw_mmc-pci.o
> obj-$(CONFIG_MMC_DW_ROCKCHIP) += dw_mmc-rockchip.o
> +obj-$(CONFIG_MMC_DW_ZX) += dw_mmc-zx.o
> obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o
> obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o
> obj-$(CONFIG_MMC_VUB300) += vub300.o
> diff --git a/drivers/mmc/host/dw_mmc-zx.c b/drivers/mmc/host/dw_mmc-zx.c
> new file mode 100644
> index 0000000..de77408
> --- /dev/null
> +++ b/drivers/mmc/host/dw_mmc-zx.c
> @@ -0,0 +1,242 @@
> +/*
> + * ZX Specific Extensions for Synopsys DW Multimedia Card Interface driver
> + *
> + * Copyright (C) 2016, Linaro Ltd.
> + * Copyright (C) 2016, ZTE Corp.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/mmc/dw_mmc.h>
> +#include <linux/mmc/host.h>
> +#include <linux/mmc/mmc.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/regmap.h>
> +#include <linux/slab.h>
> +
> +#include "dw_mmc.h"
> +#include "dw_mmc-pltfm.h"
> +#include "dw_mmc-zx.h"
> +
> +struct dw_mci_zx_priv_data {
> + struct regmap *sysc_base;
> +};
> +
> +enum delay_type {
> + DELAY_TYPE_READ, /* read dqs delay */
> + DELAY_TYPE_CLK, /* clk sample delay */
> +};
> +
> +static int dw_mci_zx_emmc_set_delay(struct dw_mci *host, unsigned int delay,
> + enum delay_type dflag)
> +{
> + struct dw_mci_zx_priv_data *priv = host->priv;
> + struct regmap *sysc_base = priv->sysc_base;
> + unsigned int clksel;
> + unsigned int loop = 1000;
> + int ret;
> +
> + if (!sysc_base)
> + return -EINVAL;
> +
> + ret = regmap_update_bits(sysc_base, LB_AON_EMMC_CFG_REG0,
> + PARA_HALF_CLK_MODE | PARA_DLL_BYPASS_MODE |
> + PARA_PHASE_DET_SEL_MASK |
> + PARA_DLL_LOCK_NUM_MASK |
> + DLL_REG_SET | PARA_DLL_START_MASK,
> + PARA_DLL_START(4) | PARA_DLL_LOCK_NUM(4));
> + if (ret)
> + return ret;
> +
> + ret = regmap_read(sysc_base, LB_AON_EMMC_CFG_REG1, &clksel);
> + if (ret)
> + return ret;
> +
> + if (dflag == DELAY_TYPE_CLK) {
> + clksel &= ~CLK_SAMP_DELAY_MASK;
> + clksel |= CLK_SAMP_DELAY(delay);
> + } else {
> + clksel &= ~READ_DQS_DELAY_MASK;
> + clksel |= READ_DQS_DELAY(delay);
> + }
> +
> + regmap_write(sysc_base, LB_AON_EMMC_CFG_REG1, clksel);
> + regmap_update_bits(sysc_base, LB_AON_EMMC_CFG_REG0,
> + PARA_DLL_START_MASK | PARA_DLL_LOCK_NUM_MASK |
> + DLL_REG_SET,
> + PARA_DLL_START(4) | PARA_DLL_LOCK_NUM(4) |
> + DLL_REG_SET);
> +
> + do {
> + ret = regmap_read(sysc_base, LB_AON_EMMC_CFG_REG2, &clksel);
> + if (ret)
> + return ret;
> +
> + } while (--loop && !(clksel & ZX_DLL_LOCKED));
> +
> + if (!loop) {
> + dev_err(host->dev, "Error: %s dll lock fail\n", __func__);
> + return -EIO;
> + }
> +
> + return 0;
> +}
> +
> +static int dw_mci_zx_emmc_execute_tuning(struct dw_mci_slot *slot, u32 opcode)
> +{
> + struct dw_mci *host = slot->host;
> + struct mmc_host *mmc = slot->mmc;
> + int len, start = 0, end = 0, delay, best = 0;
> +
> + for (delay = 1 ; delay < 128; delay++) {
> + dw_mci_zx_emmc_set_delay(host, delay, DELAY_TYPE_CLK);
> + if (mmc_send_tuning(mmc, opcode, NULL)) {
> + if (start >= 0) {
> + end = delay - 1;
> + /* check and update longest good range */
> + if ((end - start) > len) {
> + best = (start + end) >> 1;
> + len = end - start;
> + }
> + }
> + start = -1;
> + end = 0;
> + continue;
> + }
> + if (start < 0)
> + start = delay;
> + }
> +
> + if (start >= 0) {
> + end = delay - 1;
> + if ((end - start) > len) {
> + best = (start + end) >> 1;
> + len = end - start;
> + }
> + }
> + if (best < 0)
> + return -EIO;
> +
> + dev_info(host->dev, "%s best range: start %d end %d\n", __func__,
> + start, end);
> + dw_mci_zx_emmc_set_delay(host, best, DELAY_TYPE_CLK);
> + return 0;
> +}
> +
> +static int dw_mci_zx_prepare_hs400_tuning(struct dw_mci *host,
> + struct mmc_ios *ios)
> +{
> + int ret;
> +
> + /* config phase shift as 90 degree */
> + ret = dw_mci_zx_emmc_set_delay(host, 32, DELAY_TYPE_READ);
> + if (ret < 0)
> + return -EIO;
> +
> + return 0;
> +}
> +
> +static int dw_mci_zx_execute_tuning(struct dw_mci_slot *slot, u32 opcode)
> +{
> + struct dw_mci *host = slot->host;
> +
> + if (host->verid == 0x290a) /* only for emmc */
> + return dw_mci_zx_emmc_execute_tuning(slot, opcode);
> + /* TODO: Add 0x210a dedicated tuning for sd/sdio */
> +
> + return 0;
> +}
> +
> +static int dw_mci_zx_parse_dt(struct dw_mci *host)
> +{
> + struct device_node *np = host->dev->of_node;
> + struct device_node *node;
> + struct dw_mci_zx_priv_data *priv;
> + struct regmap *sysc_base;
> + int ret;
> +
> + /* syscon is needed only by emmc */
> + node = of_parse_phandle(np, "zte,aon-syscon", 0);
> + if (node) {
> + sysc_base = syscon_node_to_regmap(node);
> + of_node_put(node);
> +
> + if (IS_ERR(sysc_base)) {
> + ret = PTR_ERR(sysc_base);
> + if (ret != -EPROBE_DEFER)
> + dev_err(host->dev, "Can't get syscon: %d\n",
> + ret);
> + return ret;
> + }
> + } else {
> + return 0;
> + }
> +
> + priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
> + if (!priv)
> + return -ENOMEM;
> + priv->sysc_base = sysc_base;
> + host->priv = priv;
> +
> + return 0;
> +}
> +
> +static unsigned long zx_dwmmc_caps[3] = {
> + MMC_CAP_CMD23,
> + MMC_CAP_CMD23,
> + MMC_CAP_CMD23,
> +};
> +
> +static const struct dw_mci_drv_data zx_drv_data = {
> + .caps = zx_dwmmc_caps,
> + .execute_tuning = dw_mci_zx_execute_tuning,
> + .prepare_hs400_tuning = dw_mci_zx_prepare_hs400_tuning,
> + .parse_dt = dw_mci_zx_parse_dt,
> +};
> +
> +static const struct of_device_id dw_mci_zx_match[] = {
> + { .compatible = "zte,zx296718-dw-mshc", .data = &zx_drv_data},
{},
Forget to fix this stupid bug. Will add the fix in version 5.
> +};
> +MODULE_DEVICE_TABLE(of, dw_mci_zx_match);
> +
> +static int dw_mci_zx_probe(struct platform_device *pdev)
> +{
> + const struct dw_mci_drv_data *drv_data;
> + const struct of_device_id *match;
> +
> + match = of_match_node(dw_mci_zx_match, pdev->dev.of_node);
> + drv_data = match->data;
> +
> + return dw_mci_pltfm_register(pdev, drv_data);
> +}
> +
> +static const struct dev_pm_ops dw_mci_zx_dev_pm_ops = {
> + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
> + pm_runtime_force_resume)
> + SET_RUNTIME_PM_OPS(dw_mci_runtime_suspend,
> + dw_mci_runtime_resume,
> + NULL)
> +};
> +
> +static struct platform_driver dw_mci_zx_pltfm_driver = {
> + .probe = dw_mci_zx_probe,
> + .remove = dw_mci_pltfm_remove,
> + .driver = {
> + .name = "dwmmc_zx",
> + .of_match_table = dw_mci_zx_match,
> + .pm = &dw_mci_zx_dev_pm_ops,
> + },
> +};
> +
> +module_platform_driver(dw_mci_zx_pltfm_driver);
> +
> +MODULE_DESCRIPTION("ZTE emmc/sd driver");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/mmc/host/dw_mmc-zx.h b/drivers/mmc/host/dw_mmc-zx.h
> new file mode 100644
> index 0000000..f369997
> --- /dev/null
> +++ b/drivers/mmc/host/dw_mmc-zx.h
> @@ -0,0 +1,31 @@
> +#ifndef _DW_MMC_ZX_H_
> +#define _DW_MMC_ZX_H_
> +
> +/* ZX296718 SoC specific DLL register offset. */
> +#define LB_AON_EMMC_CFG_REG0 0x1B0
> +#define LB_AON_EMMC_CFG_REG1 0x1B4
> +#define LB_AON_EMMC_CFG_REG2 0x1B8
> +
> +/* LB_AON_EMMC_CFG_REG0 register defines */
> +#define PARA_DLL_START(x) ((x) & 0xFF)
> +#define PARA_DLL_START_MASK 0xFF
> +#define DLL_REG_SET BIT(8)
> +#define PARA_DLL_LOCK_NUM(x) (((x) & 7) << 16)
> +#define PARA_DLL_LOCK_NUM_MASK (7 << 16)
> +#define PARA_PHASE_DET_SEL(x) (((x) & 7) << 20)
> +#define PARA_PHASE_DET_SEL_MASK (7 << 20)
> +#define PARA_DLL_BYPASS_MODE BIT(23)
> +#define PARA_HALF_CLK_MODE BIT(24)
> +
> +/* LB_AON_EMMC_CFG_REG1 register defines */
> +#define READ_DQS_DELAY(x) ((x) & 0x7F)
> +#define READ_DQS_DELAY_MASK (0x7F)
> +#define READ_DQS_BYPASS_MODE BIT(7)
> +#define CLK_SAMP_DELAY(x) (((x) & 0x7F) << 8)
> +#define CLK_SAMP_DELAY_MASK (0x7F << 8)
> +#define CLK_SAMP_BYPASS_MODE BIT(15)
> +
> +/* LB_AON_EMMC_CFG_REG2 register defines */
> +#define ZX_DLL_LOCKED BIT(2)
> +
> +#endif /* _DW_MMC_ZX_H_ */
> --
> 1.9.1
>
^ permalink raw reply
* [PATCH v5 0/5] Add intial support to DW MMC host on ZTE SoC
From: Jun Nie @ 2016-11-08 1:24 UTC (permalink / raw)
To: shawn.guo, xie.baoyou
Cc: ulf.hansson, jh80.chung, jason.liu, linux-mmc, Jun Nie
Add intial support to DW MMC host on ZTE SoC. It include platform
specific wrapper driver and workarounds for fifo quirk.
Patches are prepared based on latest dw mmc runtime change:
https://github.com/jh80chung/dw-mmc.git for-ulf
Changes vs version 4:
- Fix missing empty dts compatible element in the end of compatible array.
Changes vs version 3:
- Fix brace error in document.
Changes vs version 2:
- Change dt property fifo-addr to data-addr and fifo-watermark-quirk to
fifo-watermark-aligned.
- Polish ZX MMC driver on minor coding style issues.
Changes vs version 1:
- Change fifo-addr-override to fifo-addr and remove its workaround tag in comments.
- Remove ZX DW MMC driver reset cap in driver, which can be added in dt nodes.
Jun Nie (5):
mmc: dt-bindings: add ZTE ZX296718 MMC bindings
mmc: zx: Initial support for ZX mmc controller
Documentation: synopsys-dw-mshc: add binding for fifo quirks
mmc: dw: Add fifo address property
mmc: dw: Add fifo watermark alignment property
.../devicetree/bindings/mmc/synopsys-dw-mshc.txt | 13 ++
.../devicetree/bindings/mmc/zx-dw-mshc.txt | 34 +++
drivers/mmc/host/Kconfig | 9 +
drivers/mmc/host/Makefile | 1 +
drivers/mmc/host/dw_mmc-zx.c | 242 +++++++++++++++++++++
drivers/mmc/host/dw_mmc-zx.h | 31 +++
drivers/mmc/host/dw_mmc.c | 17 +-
include/linux/mmc/dw_mmc.h | 5 +
8 files changed, 349 insertions(+), 3 deletions(-)
create mode 100644 Documentation/devicetree/bindings/mmc/zx-dw-mshc.txt
create mode 100644 drivers/mmc/host/dw_mmc-zx.c
create mode 100644 drivers/mmc/host/dw_mmc-zx.h
--
1.9.1
^ permalink raw reply
* [PATCH v5 1/5] mmc: dt-bindings: add ZTE ZX296718 MMC bindings
From: Jun Nie @ 2016-11-08 1:24 UTC (permalink / raw)
To: shawn.guo, xie.baoyou
Cc: ulf.hansson, jh80.chung, jason.liu, linux-mmc, Jun Nie
In-Reply-To: <1478568298-18380-1-git-send-email-jun.nie@linaro.org>
Document the device-tree binding of ZTE MMC host on
ZX296718 SoC.
Signed-off-by: Jun Nie <jun.nie@linaro.org>
---
.../devicetree/bindings/mmc/zx-dw-mshc.txt | 35 ++++++++++++++++++++++
1 file changed, 35 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mmc/zx-dw-mshc.txt
diff --git a/Documentation/devicetree/bindings/mmc/zx-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/zx-dw-mshc.txt
new file mode 100644
index 0000000..c175c4b
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/zx-dw-mshc.txt
@@ -0,0 +1,35 @@
+* ZTE specific extensions to the Synopsys Designware Mobile Storage
+ Host Controller
+
+The Synopsys designware mobile storage host controller is used to interface
+a SoC with storage medium such as eMMC or SD/MMC cards. This file documents
+differences between the core Synopsys dw mshc controller properties described
+by synopsys-dw-mshc.txt and the properties used by the ZTE specific
+extensions to the Synopsys Designware Mobile Storage Host Controller.
+
+Required Properties:
+
+* compatible: should be
+ - "zte,zx296718-dw-mshc": for ZX SoCs
+
+Example:
+
+ mmc1: mmc@1110000 {
+ compatible = "zte,zx296718-dw-mshc";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x01110000 0x1000>;
+ interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
+ fifo-depth = <32>;
+ data-addr = <0x200>;
+ fifo-watermark-aligned;
+ bus-width = <4>;
+ clock-frequency = <50000000>;
+ clocks = <&topcrm SD0_AHB>, <&topcrm SD0_WCLK>;
+ clock-names = "biu", "ciu";
+ num-slots = <1>;
+ max-frequency = <50000000>;
+ cap-sdio-irq;
+ cap-sd-highspeed;
+ status = "disabled";
+ };
--
1.9.1
^ permalink raw reply related
* [PATCH v5 2/5] mmc: zx: Initial support for ZX mmc controller
From: Jun Nie @ 2016-11-08 1:24 UTC (permalink / raw)
To: shawn.guo, xie.baoyou
Cc: ulf.hansson, jh80.chung, jason.liu, linux-mmc, Jun Nie
In-Reply-To: <1478568298-18380-1-git-send-email-jun.nie@linaro.org>
This platform driver adds initial support for the DW host controller
found on ZTE SoCs.
It has been tested on ZX296718 EVB board currently. More support on
timing tuning will be added when hardware is available.
Signed-off-by: Jun Nie <jun.nie@linaro.org>
---
drivers/mmc/host/Kconfig | 9 ++
drivers/mmc/host/Makefile | 1 +
drivers/mmc/host/dw_mmc-zx.c | 243 +++++++++++++++++++++++++++++++++++++++++++
drivers/mmc/host/dw_mmc-zx.h | 31 ++++++
4 files changed, 284 insertions(+)
create mode 100644 drivers/mmc/host/dw_mmc-zx.c
create mode 100644 drivers/mmc/host/dw_mmc-zx.h
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 5274f50..4dafbc2 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -662,6 +662,15 @@ config MMC_DW_ROCKCHIP
Synopsys DesignWare Memory Card Interface driver. Select this option
for platforms based on RK3066, RK3188 and RK3288 SoC's.
+config MMC_DW_ZX
+ tristate "ZTE specific extensions for Synopsys DW Memory Card Interface"
+ depends on MMC_DW && ARCH_ZX
+ select MMC_DW_PLTFM
+ help
+ This selects support for ZTE SoC specific extensions to the
+ Synopsys DesignWare Memory Card Interface driver. Select this option
+ for platforms based on ZX296718 SoC's.
+
config MMC_SH_MMCIF
tristate "SuperH Internal MMCIF support"
depends on HAS_DMA
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index e2bdaaf..9766143 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -48,6 +48,7 @@ obj-$(CONFIG_MMC_DW_EXYNOS) += dw_mmc-exynos.o
obj-$(CONFIG_MMC_DW_K3) += dw_mmc-k3.o
obj-$(CONFIG_MMC_DW_PCI) += dw_mmc-pci.o
obj-$(CONFIG_MMC_DW_ROCKCHIP) += dw_mmc-rockchip.o
+obj-$(CONFIG_MMC_DW_ZX) += dw_mmc-zx.o
obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o
obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o
obj-$(CONFIG_MMC_VUB300) += vub300.o
diff --git a/drivers/mmc/host/dw_mmc-zx.c b/drivers/mmc/host/dw_mmc-zx.c
new file mode 100644
index 0000000..c48d851
--- /dev/null
+++ b/drivers/mmc/host/dw_mmc-zx.c
@@ -0,0 +1,243 @@
+/*
+ * ZX Specific Extensions for Synopsys DW Multimedia Card Interface driver
+ *
+ * Copyright (C) 2016, Linaro Ltd.
+ * Copyright (C) 2016, ZTE Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mmc/dw_mmc.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include "dw_mmc.h"
+#include "dw_mmc-pltfm.h"
+#include "dw_mmc-zx.h"
+
+struct dw_mci_zx_priv_data {
+ struct regmap *sysc_base;
+};
+
+enum delay_type {
+ DELAY_TYPE_READ, /* read dqs delay */
+ DELAY_TYPE_CLK, /* clk sample delay */
+};
+
+static int dw_mci_zx_emmc_set_delay(struct dw_mci *host, unsigned int delay,
+ enum delay_type dflag)
+{
+ struct dw_mci_zx_priv_data *priv = host->priv;
+ struct regmap *sysc_base = priv->sysc_base;
+ unsigned int clksel;
+ unsigned int loop = 1000;
+ int ret;
+
+ if (!sysc_base)
+ return -EINVAL;
+
+ ret = regmap_update_bits(sysc_base, LB_AON_EMMC_CFG_REG0,
+ PARA_HALF_CLK_MODE | PARA_DLL_BYPASS_MODE |
+ PARA_PHASE_DET_SEL_MASK |
+ PARA_DLL_LOCK_NUM_MASK |
+ DLL_REG_SET | PARA_DLL_START_MASK,
+ PARA_DLL_START(4) | PARA_DLL_LOCK_NUM(4));
+ if (ret)
+ return ret;
+
+ ret = regmap_read(sysc_base, LB_AON_EMMC_CFG_REG1, &clksel);
+ if (ret)
+ return ret;
+
+ if (dflag == DELAY_TYPE_CLK) {
+ clksel &= ~CLK_SAMP_DELAY_MASK;
+ clksel |= CLK_SAMP_DELAY(delay);
+ } else {
+ clksel &= ~READ_DQS_DELAY_MASK;
+ clksel |= READ_DQS_DELAY(delay);
+ }
+
+ regmap_write(sysc_base, LB_AON_EMMC_CFG_REG1, clksel);
+ regmap_update_bits(sysc_base, LB_AON_EMMC_CFG_REG0,
+ PARA_DLL_START_MASK | PARA_DLL_LOCK_NUM_MASK |
+ DLL_REG_SET,
+ PARA_DLL_START(4) | PARA_DLL_LOCK_NUM(4) |
+ DLL_REG_SET);
+
+ do {
+ ret = regmap_read(sysc_base, LB_AON_EMMC_CFG_REG2, &clksel);
+ if (ret)
+ return ret;
+
+ } while (--loop && !(clksel & ZX_DLL_LOCKED));
+
+ if (!loop) {
+ dev_err(host->dev, "Error: %s dll lock fail\n", __func__);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int dw_mci_zx_emmc_execute_tuning(struct dw_mci_slot *slot, u32 opcode)
+{
+ struct dw_mci *host = slot->host;
+ struct mmc_host *mmc = slot->mmc;
+ int len, start = 0, end = 0, delay, best = 0;
+
+ for (delay = 1 ; delay < 128; delay++) {
+ dw_mci_zx_emmc_set_delay(host, delay, DELAY_TYPE_CLK);
+ if (mmc_send_tuning(mmc, opcode, NULL)) {
+ if (start >= 0) {
+ end = delay - 1;
+ /* check and update longest good range */
+ if ((end - start) > len) {
+ best = (start + end) >> 1;
+ len = end - start;
+ }
+ }
+ start = -1;
+ end = 0;
+ continue;
+ }
+ if (start < 0)
+ start = delay;
+ }
+
+ if (start >= 0) {
+ end = delay - 1;
+ if ((end - start) > len) {
+ best = (start + end) >> 1;
+ len = end - start;
+ }
+ }
+ if (best < 0)
+ return -EIO;
+
+ dev_info(host->dev, "%s best range: start %d end %d\n", __func__,
+ start, end);
+ dw_mci_zx_emmc_set_delay(host, best, DELAY_TYPE_CLK);
+ return 0;
+}
+
+static int dw_mci_zx_prepare_hs400_tuning(struct dw_mci *host,
+ struct mmc_ios *ios)
+{
+ int ret;
+
+ /* config phase shift as 90 degree */
+ ret = dw_mci_zx_emmc_set_delay(host, 32, DELAY_TYPE_READ);
+ if (ret < 0)
+ return -EIO;
+
+ return 0;
+}
+
+static int dw_mci_zx_execute_tuning(struct dw_mci_slot *slot, u32 opcode)
+{
+ struct dw_mci *host = slot->host;
+
+ if (host->verid == 0x290a) /* only for emmc */
+ return dw_mci_zx_emmc_execute_tuning(slot, opcode);
+ /* TODO: Add 0x210a dedicated tuning for sd/sdio */
+
+ return 0;
+}
+
+static int dw_mci_zx_parse_dt(struct dw_mci *host)
+{
+ struct device_node *np = host->dev->of_node;
+ struct device_node *node;
+ struct dw_mci_zx_priv_data *priv;
+ struct regmap *sysc_base;
+ int ret;
+
+ /* syscon is needed only by emmc */
+ node = of_parse_phandle(np, "zte,aon-syscon", 0);
+ if (node) {
+ sysc_base = syscon_node_to_regmap(node);
+ of_node_put(node);
+
+ if (IS_ERR(sysc_base)) {
+ ret = PTR_ERR(sysc_base);
+ if (ret != -EPROBE_DEFER)
+ dev_err(host->dev, "Can't get syscon: %d\n",
+ ret);
+ return ret;
+ }
+ } else {
+ return 0;
+ }
+
+ priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+ priv->sysc_base = sysc_base;
+ host->priv = priv;
+
+ return 0;
+}
+
+static unsigned long zx_dwmmc_caps[3] = {
+ MMC_CAP_CMD23,
+ MMC_CAP_CMD23,
+ MMC_CAP_CMD23,
+};
+
+static const struct dw_mci_drv_data zx_drv_data = {
+ .caps = zx_dwmmc_caps,
+ .execute_tuning = dw_mci_zx_execute_tuning,
+ .prepare_hs400_tuning = dw_mci_zx_prepare_hs400_tuning,
+ .parse_dt = dw_mci_zx_parse_dt,
+};
+
+static const struct of_device_id dw_mci_zx_match[] = {
+ { .compatible = "zte,zx296718-dw-mshc", .data = &zx_drv_data},
+ {},
+};
+MODULE_DEVICE_TABLE(of, dw_mci_zx_match);
+
+static int dw_mci_zx_probe(struct platform_device *pdev)
+{
+ const struct dw_mci_drv_data *drv_data;
+ const struct of_device_id *match;
+
+ match = of_match_node(dw_mci_zx_match, pdev->dev.of_node);
+ drv_data = match->data;
+
+ return dw_mci_pltfm_register(pdev, drv_data);
+}
+
+static const struct dev_pm_ops dw_mci_zx_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+ SET_RUNTIME_PM_OPS(dw_mci_runtime_suspend,
+ dw_mci_runtime_resume,
+ NULL)
+};
+
+static struct platform_driver dw_mci_zx_pltfm_driver = {
+ .probe = dw_mci_zx_probe,
+ .remove = dw_mci_pltfm_remove,
+ .driver = {
+ .name = "dwmmc_zx",
+ .of_match_table = dw_mci_zx_match,
+ .pm = &dw_mci_zx_dev_pm_ops,
+ },
+};
+
+module_platform_driver(dw_mci_zx_pltfm_driver);
+
+MODULE_DESCRIPTION("ZTE emmc/sd driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/dw_mmc-zx.h b/drivers/mmc/host/dw_mmc-zx.h
new file mode 100644
index 0000000..f369997
--- /dev/null
+++ b/drivers/mmc/host/dw_mmc-zx.h
@@ -0,0 +1,31 @@
+#ifndef _DW_MMC_ZX_H_
+#define _DW_MMC_ZX_H_
+
+/* ZX296718 SoC specific DLL register offset. */
+#define LB_AON_EMMC_CFG_REG0 0x1B0
+#define LB_AON_EMMC_CFG_REG1 0x1B4
+#define LB_AON_EMMC_CFG_REG2 0x1B8
+
+/* LB_AON_EMMC_CFG_REG0 register defines */
+#define PARA_DLL_START(x) ((x) & 0xFF)
+#define PARA_DLL_START_MASK 0xFF
+#define DLL_REG_SET BIT(8)
+#define PARA_DLL_LOCK_NUM(x) (((x) & 7) << 16)
+#define PARA_DLL_LOCK_NUM_MASK (7 << 16)
+#define PARA_PHASE_DET_SEL(x) (((x) & 7) << 20)
+#define PARA_PHASE_DET_SEL_MASK (7 << 20)
+#define PARA_DLL_BYPASS_MODE BIT(23)
+#define PARA_HALF_CLK_MODE BIT(24)
+
+/* LB_AON_EMMC_CFG_REG1 register defines */
+#define READ_DQS_DELAY(x) ((x) & 0x7F)
+#define READ_DQS_DELAY_MASK (0x7F)
+#define READ_DQS_BYPASS_MODE BIT(7)
+#define CLK_SAMP_DELAY(x) (((x) & 0x7F) << 8)
+#define CLK_SAMP_DELAY_MASK (0x7F << 8)
+#define CLK_SAMP_BYPASS_MODE BIT(15)
+
+/* LB_AON_EMMC_CFG_REG2 register defines */
+#define ZX_DLL_LOCKED BIT(2)
+
+#endif /* _DW_MMC_ZX_H_ */
--
1.9.1
^ permalink raw reply related
* [PATCH v5 3/5] Documentation: synopsys-dw-mshc: add binding for fifo quirks
From: Jun Nie @ 2016-11-08 1:24 UTC (permalink / raw)
To: shawn.guo, xie.baoyou
Cc: ulf.hansson, jh80.chung, jason.liu, linux-mmc, Jun Nie
In-Reply-To: <1478568298-18380-1-git-send-email-jun.nie@linaro.org>
Add fifo-addr property and fifo-watermark-quirk property to
synopsys-dw-mshc bindings. It is intended to provide more
dt interface to support SoCs specific configuration.
Signed-off-by: Jun Nie <jun.nie@linaro.org>
---
Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt
index 4e00e85..8bf2e41 100644
--- a/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt
+++ b/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt
@@ -76,6 +76,17 @@ Optional properties:
* broken-cd: as documented in mmc core bindings.
+* data-addr: Override fifo address with value provided by DT. The default FIFO reg
+ offset is assumed as 0x100 (version < 0x240A) and 0x200(version >= 0x240A) by
+ driver. If the controller does not follow this rule, please use this property
+ to set fifo address in device tree.
+
+* fifo-watermark-aligned: Data done irq is expected if data length is less than
+ watermark in PIO mode. But fifo watermark is requested to be aligned with data
+ length in some SoC so that TX/RX irq can be generated with data done irq. Add this
+ watermark quirk to mark this requirement and force fifo watermark setting
+ accordingly.
+
* vmmc-supply: The phandle to the regulator to use for vmmc. If this is
specified we'll defer probe until we can find this regulator.
@@ -103,6 +114,8 @@ board specific portions as listed below.
interrupts = <0 75 0>;
#address-cells = <1>;
#size-cells = <0>;
+ data-addr = <0x200>;
+ fifo-watermark-aligned;
};
[board specific internal DMA resources]
--
1.9.1
^ permalink raw reply related
* [PATCH v5 4/5] mmc: dw: Add fifo address property
From: Jun Nie @ 2016-11-08 1:24 UTC (permalink / raw)
To: shawn.guo, xie.baoyou
Cc: ulf.hansson, jh80.chung, jason.liu, linux-mmc, Jun Nie
In-Reply-To: <1478568298-18380-1-git-send-email-jun.nie@linaro.org>
The FIFO address may break default address assumption of 0x100
(version < 0x240A) and 0x200(version >= 0x240A) in current driver.
The new property is introduced to override fifo address via DT
node information.
Signed-off-by: Jun Nie <jun.nie@linaro.org>
---
drivers/mmc/host/dw_mmc.c | 6 +++++-
include/linux/mmc/dw_mmc.h | 2 ++
2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 1c9ee36..696b5e6 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -2955,6 +2955,8 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms);
+ of_property_read_u32(np, "data-addr", &host->data_addr_override);
+
if (!of_property_read_u32(np, "clock-frequency", &clock_frequency))
pdata->bus_hz = clock_frequency;
@@ -3158,7 +3160,9 @@ int dw_mci_probe(struct dw_mci *host)
host->verid = SDMMC_GET_VERID(mci_readl(host, VERID));
dev_info(host->dev, "Version ID is %04x\n", host->verid);
- if (host->verid < DW_MMC_240A)
+ if (host->data_addr_override)
+ host->fifo_reg = host->regs + host->data_addr_override;
+ else if (host->verid < DW_MMC_240A)
host->fifo_reg = host->regs + DATA_OFFSET;
else
host->fifo_reg = host->regs + DATA_240A_OFFSET;
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
index f5af2bd..17cb95a 100644
--- a/include/linux/mmc/dw_mmc.h
+++ b/include/linux/mmc/dw_mmc.h
@@ -107,6 +107,7 @@ struct dw_mci_dma_slave {
* @ciu_clk: Pointer to card interface unit clock instance.
* @slot: Slots sharing this MMC controller.
* @fifo_depth: depth of FIFO.
+ * @data_addr_override: override fifo reg offset with this value.
* @data_shift: log2 of FIFO item size.
* @part_buf_start: Start index in part_buf.
* @part_buf_count: Bytes of partial data in part_buf.
@@ -154,6 +155,7 @@ struct dw_mci {
spinlock_t irq_lock;
void __iomem *regs;
void __iomem *fifo_reg;
+ u32 data_addr_override;
struct scatterlist *sg;
struct sg_mapping_iter sg_miter;
--
1.9.1
^ permalink raw reply related
* [PATCH v5 5/5] mmc: dw: Add fifo watermark alignment property
From: Jun Nie @ 2016-11-08 1:24 UTC (permalink / raw)
To: shawn.guo, xie.baoyou
Cc: ulf.hansson, jh80.chung, jason.liu, linux-mmc, Jun Nie
In-Reply-To: <1478568298-18380-1-git-send-email-jun.nie@linaro.org>
Data done irq is expected if data length is less than
watermark in PIO mode. But fifo watermark is requested
to be aligned with data length in some SoC so that TX/RX
irq can be generated with data done irq. Add the
watermark alignment to mark this requirement and force
fifo watermark setting accordingly.
Signed-off-by: Jun Nie <jun.nie@linaro.org>
---
drivers/mmc/host/dw_mmc.c | 11 +++++++++--
include/linux/mmc/dw_mmc.h | 3 +++
2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 696b5e6..6d85ca6 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1111,11 +1111,15 @@ static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data)
mci_writel(host, CTRL, temp);
/*
- * Use the initial fifoth_val for PIO mode.
+ * Use the initial fifoth_val for PIO mode. If wm_algined
+ * is set, we set watermark same as data size.
* If next issued data may be transfered by DMA mode,
* prev_blksz should be invalidated.
*/
- mci_writel(host, FIFOTH, host->fifoth_val);
+ if (host->wm_aligned)
+ dw_mci_adjust_fifoth(host, data);
+ else
+ mci_writel(host, FIFOTH, host->fifoth_val);
host->prev_blksz = 0;
} else {
/*
@@ -2957,6 +2961,9 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
of_property_read_u32(np, "data-addr", &host->data_addr_override);
+ if (of_get_property(np, "fifo-watermark-aligned", NULL))
+ host->wm_aligned = true;
+
if (!of_property_read_u32(np, "clock-frequency", &clock_frequency))
pdata->bus_hz = clock_frequency;
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
index 17cb95a..ee4bb30 100644
--- a/include/linux/mmc/dw_mmc.h
+++ b/include/linux/mmc/dw_mmc.h
@@ -108,6 +108,8 @@ struct dw_mci_dma_slave {
* @slot: Slots sharing this MMC controller.
* @fifo_depth: depth of FIFO.
* @data_addr_override: override fifo reg offset with this value.
+ * @wm_aligned: force fifo watermark equal with data length in PIO mode.
+ * Set as true if alignment is needed.
* @data_shift: log2 of FIFO item size.
* @part_buf_start: Start index in part_buf.
* @part_buf_count: Bytes of partial data in part_buf.
@@ -156,6 +158,7 @@ struct dw_mci {
void __iomem *regs;
void __iomem *fifo_reg;
u32 data_addr_override;
+ bool wm_aligned;
struct scatterlist *sg;
struct sg_mapping_iter sg_miter;
--
1.9.1
^ permalink raw reply related
* Re: [PATCH v6 01/14] clk: Add clk_hw_get_clk() helper API to be used by clk providers
From: Rajendra Nayak @ 2016-11-08 3:37 UTC (permalink / raw)
To: Ritesh Harjani, ulf.hansson-QSEj5FYQhm4dnm+yROfE0A,
linux-mmc-u79uwXL29TY76Z2rM5mHXA,
adrian.hunter-ral2JQCrhuEAvxtiuMwx3w,
shawn.lin-TNX95d0MmH7DzftRWevZcw, sboyd-sgV2jX0FEOL9JmXXK+q4OQ
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-clk-u79uwXL29TY76Z2rM5mHXA,
david.brown-QSEj5FYQhm4dnm+yROfE0A,
andy.gross-QSEj5FYQhm4dnm+yROfE0A,
linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
georgi.djakov-QSEj5FYQhm4dnm+yROfE0A,
alex.lemberg-XdAiOPVOjttBDgjK7y7TUQ,
mateusz.nowak-ral2JQCrhuEAvxtiuMwx3w,
Yuliy.Izrailov-XdAiOPVOjttBDgjK7y7TUQ,
asutoshd-sgV2jX0FEOL9JmXXK+q4OQ, kdorfman-sgV2jX0FEOL9JmXXK+q4OQ,
david.griego-QSEj5FYQhm4dnm+yROfE0A,
stummala-sgV2jX0FEOL9JmXXK+q4OQ, venkatg-sgV2jX0FEOL9JmXXK+q4OQ,
pramod.gurav-QSEj5FYQhm4dnm+yROfE0A
In-Reply-To: <1478517877-23733-2-git-send-email-riteshh-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
On 11/07/2016 04:54 PM, Ritesh Harjani wrote:
> From: Rajendra Nayak <rnayak-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
>
> Add a helper API that will allow clk providers to turn their clk_hw
> structures into struct clk pointer.
>
> Signed-off-by: Rajendra Nayak <rnayak-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
Please drop this patch, it isn't needed here anyway, besides
it needs to be reworked as already discussed.
> ---
> drivers/clk/clk.c | 6 ++++++
> include/linux/clk-provider.h | 1 +
> 2 files changed, 7 insertions(+)
>
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> index 0fb39fe..52ef035 100644
> --- a/drivers/clk/clk.c
> +++ b/drivers/clk/clk.c
> @@ -186,6 +186,12 @@ const char *clk_hw_get_name(const struct clk_hw *hw)
> }
> EXPORT_SYMBOL_GPL(clk_hw_get_name);
>
> +struct clk *clk_hw_get_clk(const struct clk_hw *hw)
> +{
> + return hw->clk;
> +}
> +EXPORT_SYMBOL_GPL(clk_hw_get_clk);
> +
> struct clk_hw *__clk_get_hw(struct clk *clk)
> {
> return !clk ? NULL : clk->core->hw;
> diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
> index af59638..37022a9 100644
> --- a/include/linux/clk-provider.h
> +++ b/include/linux/clk-provider.h
> @@ -729,6 +729,7 @@ struct clk_hw *clk_hw_register_gpio_mux(struct device *dev, const char *name,
> /* helper functions */
> const char *__clk_get_name(const struct clk *clk);
> const char *clk_hw_get_name(const struct clk_hw *hw);
> +struct clk *clk_hw_get_clk(const struct clk_hw *hw);
> struct clk_hw *__clk_get_hw(struct clk *clk);
> unsigned int clk_hw_get_num_parents(const struct clk_hw *hw);
> struct clk_hw *clk_hw_get_parent(const struct clk_hw *hw);
>
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v6 01/14] clk: Add clk_hw_get_clk() helper API to be used by clk providers
From: Ritesh Harjani @ 2016-11-08 4:08 UTC (permalink / raw)
To: Rajendra Nayak, ulf.hansson-QSEj5FYQhm4dnm+yROfE0A,
linux-mmc-u79uwXL29TY76Z2rM5mHXA,
adrian.hunter-ral2JQCrhuEAvxtiuMwx3w,
shawn.lin-TNX95d0MmH7DzftRWevZcw, sboyd-sgV2jX0FEOL9JmXXK+q4OQ
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-clk-u79uwXL29TY76Z2rM5mHXA,
david.brown-QSEj5FYQhm4dnm+yROfE0A,
andy.gross-QSEj5FYQhm4dnm+yROfE0A,
linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
georgi.djakov-QSEj5FYQhm4dnm+yROfE0A,
alex.lemberg-XdAiOPVOjttBDgjK7y7TUQ,
mateusz.nowak-ral2JQCrhuEAvxtiuMwx3w,
Yuliy.Izrailov-XdAiOPVOjttBDgjK7y7TUQ,
asutoshd-sgV2jX0FEOL9JmXXK+q4OQ, kdorfman-sgV2jX0FEOL9JmXXK+q4OQ,
david.griego-QSEj5FYQhm4dnm+yROfE0A,
stummala-sgV2jX0FEOL9JmXXK+q4OQ, venkatg-sgV2jX0FEOL9JmXXK+q4OQ,
pramod.gurav-QSEj5FYQhm4dnm+yROfE0A
In-Reply-To: <58214862.8080604-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
Hi,
On 11/8/2016 9:07 AM, Rajendra Nayak wrote:
>
>
> On 11/07/2016 04:54 PM, Ritesh Harjani wrote:
>> From: Rajendra Nayak <rnayak-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
>>
>> Add a helper API that will allow clk providers to turn their clk_hw
>> structures into struct clk pointer.
>>
>> Signed-off-by: Rajendra Nayak <rnayak-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
>
> Please drop this patch, it isn't needed here anyway, besides
> it needs to be reworked as already discussed.
Ok, sure.
>
>> ---
>> drivers/clk/clk.c | 6 ++++++
>> include/linux/clk-provider.h | 1 +
>> 2 files changed, 7 insertions(+)
>>
>> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
>> index 0fb39fe..52ef035 100644
>> --- a/drivers/clk/clk.c
>> +++ b/drivers/clk/clk.c
>> @@ -186,6 +186,12 @@ const char *clk_hw_get_name(const struct clk_hw *hw)
>> }
>> EXPORT_SYMBOL_GPL(clk_hw_get_name);
>>
>> +struct clk *clk_hw_get_clk(const struct clk_hw *hw)
>> +{
>> + return hw->clk;
>> +}
>> +EXPORT_SYMBOL_GPL(clk_hw_get_clk);
>> +
>> struct clk_hw *__clk_get_hw(struct clk *clk)
>> {
>> return !clk ? NULL : clk->core->hw;
>> diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
>> index af59638..37022a9 100644
>> --- a/include/linux/clk-provider.h
>> +++ b/include/linux/clk-provider.h
>> @@ -729,6 +729,7 @@ struct clk_hw *clk_hw_register_gpio_mux(struct device *dev, const char *name,
>> /* helper functions */
>> const char *__clk_get_name(const struct clk *clk);
>> const char *clk_hw_get_name(const struct clk_hw *hw);
>> +struct clk *clk_hw_get_clk(const struct clk_hw *hw);
>> struct clk_hw *__clk_get_hw(struct clk *clk);
>> unsigned int clk_hw_get_num_parents(const struct clk_hw *hw);
>> struct clk_hw *clk_hw_get_parent(const struct clk_hw *hw);
>>
>
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH 0/4] Support sdio feature
From: Yong Mao @ 2016-11-08 6:08 UTC (permalink / raw)
To: Ulf Hansson
Cc: Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA, YH Huang,
Nicolas Boichat, Mathias Nyman,
srv_heupstream-NuS5LvNUpcJWk0Htik3J/w, Catalin Marinas,
linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Will Deacon,
Douglas Anderson, yong mao, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
Chunfeng Yun, Rob Herring, Geert Uytterhoeven,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Philipp Zabel,
Matthias Brugger, linux-mmc-u79uwXL29TY76Z2rM5mHXA, Eddie Huang,
Chaotian Jing
Fix CMD6 timeout issue
Add irqlock to protect accessing the shared register
Modify the implementation of msdc_card_busy
Add msdc_recheck_sdio_irq mechanism
Support sdr104_clk_delay in sdio
Add description of mmc3 for supporting sdio feature
yong mao (4):
mmc: mediatek: Fix CMD6 timeout issue
sdio: mediatek: Support sdio feature
sdio: mediatek: support sdr104_clk_delay in sdio
dts: arm64: enable mmc3 for supporting sdio feature
arch/arm64/boot/dts/mediatek/mt8173-evb.dts | 82 +++++++++
drivers/mmc/host/mtk-sd.c | 254 +++++++++++++++++++++-------
2 files changed, 271 insertions(+), 65 deletions(-)
--
1.8.1.1.dirty
^ permalink raw reply
* [PATCH 1/4] mmc: mediatek: Fix CMD6 timeout issue
From: Yong Mao @ 2016-11-08 6:08 UTC (permalink / raw)
To: Ulf Hansson
Cc: Rob Herring, Mark Rutland, Catalin Marinas, Will Deacon,
Matthias Brugger, YH Huang, Mathias Nyman, Chunfeng Yun,
Eddie Huang, Philipp Zabel, yong mao, Chaotian Jing,
Nicolas Boichat, Douglas Anderson, Geert Uytterhoeven,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-mmc-u79uwXL29TY76Z2rM5mHXA, linux-mediatek
In-Reply-To: <1478585341-6749-1-git-send-email-yong.mao-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
From: yong mao <yong.mao-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
When initializing EMMC, after switch to HS400,
it will issue CMD6 to change ext_csd, if first CMD6 got CRC
error, the repeat CMD6 may get timeout, that's
because SDCBSY was cleared by msdc_reset_hw()
Signed-off-by: Yong Mao <yong.mao-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
Signed-off-by: Chaotian Jing <chaotian.jing-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
---
drivers/mmc/host/mtk-sd.c | 77 ++++++++++++++++++++++++++++++---------------
1 file changed, 51 insertions(+), 26 deletions(-)
diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
index 84e9afc..b29683b 100644
--- a/drivers/mmc/host/mtk-sd.c
+++ b/drivers/mmc/host/mtk-sd.c
@@ -826,6 +826,15 @@ static bool msdc_cmd_done(struct msdc_host *host, int events,
return true;
}
+static int msdc_card_busy(struct mmc_host *mmc)
+{
+ struct msdc_host *host = mmc_priv(mmc);
+ u32 status = readl(host->base + MSDC_PS);
+
+ /* check if data0 is low */
+ return !(status & BIT(16));
+}
+
/* It is the core layer's responsibility to ensure card status
* is correct before issue a request. but host design do below
* checks recommended.
@@ -835,10 +844,20 @@ static inline bool msdc_cmd_is_ready(struct msdc_host *host,
{
/* The max busy time we can endure is 20ms */
unsigned long tmo = jiffies + msecs_to_jiffies(20);
+ u32 count = 0;
+
+ if (in_interrupt()) {
+ while ((readl(host->base + SDC_STS) & SDC_STS_CMDBUSY) &&
+ (count < 1000)) {
+ udelay(1);
+ count++;
+ }
+ } else {
+ while ((readl(host->base + SDC_STS) & SDC_STS_CMDBUSY) &&
+ time_before(jiffies, tmo))
+ cpu_relax();
+ }
- while ((readl(host->base + SDC_STS) & SDC_STS_CMDBUSY) &&
- time_before(jiffies, tmo))
- cpu_relax();
if (readl(host->base + SDC_STS) & SDC_STS_CMDBUSY) {
dev_err(host->dev, "CMD bus busy detected\n");
host->error |= REQ_CMD_BUSY;
@@ -846,17 +865,35 @@ static inline bool msdc_cmd_is_ready(struct msdc_host *host,
return false;
}
- if (mmc_resp_type(cmd) == MMC_RSP_R1B || cmd->data) {
- tmo = jiffies + msecs_to_jiffies(20);
- /* R1B or with data, should check SDCBUSY */
- while ((readl(host->base + SDC_STS) & SDC_STS_SDCBUSY) &&
- time_before(jiffies, tmo))
- cpu_relax();
- if (readl(host->base + SDC_STS) & SDC_STS_SDCBUSY) {
- dev_err(host->dev, "Controller busy detected\n");
- host->error |= REQ_CMD_BUSY;
- msdc_cmd_done(host, MSDC_INT_CMDTMO, mrq, cmd);
- return false;
+ if (cmd->opcode != MMC_SEND_STATUS) {
+ count = 0;
+ /* Consider that CMD6 crc error before card was init done,
+ * mmc_retune() will return directly as host->card is null.
+ * and CMD6 will retry 3 times, must ensure card is in transfer
+ * state when retry.
+ */
+ tmo = jiffies + msecs_to_jiffies(60 * 1000);
+ while (1) {
+ if (msdc_card_busy(host->mmc)) {
+ if (in_interrupt()) {
+ udelay(1);
+ count++;
+ } else {
+ msleep_interruptible(10);
+ }
+ } else {
+ break;
+ }
+ /* Timeout if the device never
+ * leaves the program state.
+ */
+ if (count > 1000 || time_after(jiffies, tmo)) {
+ pr_err("%s: Card stuck in programming state! %s\n",
+ mmc_hostname(host->mmc), __func__);
+ host->error |= REQ_CMD_BUSY;
+ msdc_cmd_done(host, MSDC_INT_CMDTMO, mrq, cmd);
+ return false;
+ }
}
}
return true;
@@ -1070,18 +1107,6 @@ static int msdc_ops_switch_volt(struct mmc_host *mmc, struct mmc_ios *ios)
return ret;
}
-static int msdc_card_busy(struct mmc_host *mmc)
-{
- struct msdc_host *host = mmc_priv(mmc);
- u32 status = readl(host->base + MSDC_PS);
-
- /* check if any pin between dat[0:3] is low */
- if (((status >> 16) & 0xf) != 0xf)
- return 1;
-
- return 0;
-}
-
static void msdc_request_timeout(struct work_struct *work)
{
struct msdc_host *host = container_of(work, struct msdc_host,
--
1.7.9.5
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH 2/4] sdio: mediatek: Support sdio feature
From: Yong Mao @ 2016-11-08 6:08 UTC (permalink / raw)
To: Ulf Hansson
Cc: Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA, YH Huang,
Nicolas Boichat, Mathias Nyman,
srv_heupstream-NuS5LvNUpcJWk0Htik3J/w, Catalin Marinas,
linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Will Deacon,
Douglas Anderson, yong mao, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
Chunfeng Yun, Rob Herring, Geert Uytterhoeven,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Philipp Zabel,
Matthias Brugger, linux-mmc-u79uwXL29TY76Z2rM5mHXA, Eddie Huang,
Chaotian Jing
In-Reply-To: <1478585341-6749-1-git-send-email-yong.mao-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
From: yong mao <yong.mao-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
1. Add irqlock to protect accessing the shared register
2. Modify the implementation of msdc_card_busy due to SDIO
3. Implement enable_sdio_irq
4. Add msdc_recheck_sdio_irq mechanism to make sure all
interrupts can be processed immediately
Signed-off-by: Yong Mao <yong.mao-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
Signed-off-by: Chaotian Jing <chaotian.jing-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
---
drivers/mmc/host/mtk-sd.c | 167 ++++++++++++++++++++++++++++++++++-----------
1 file changed, 129 insertions(+), 38 deletions(-)
diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
index b29683b..37edf30 100644
--- a/drivers/mmc/host/mtk-sd.c
+++ b/drivers/mmc/host/mtk-sd.c
@@ -117,6 +117,7 @@
#define MSDC_PS_CDSTS (0x1 << 1) /* R */
#define MSDC_PS_CDDEBOUNCE (0xf << 12) /* RW */
#define MSDC_PS_DAT (0xff << 16) /* R */
+#define MSDC_PS_DATA1 (0x1 << 17) /* R */
#define MSDC_PS_CMD (0x1 << 24) /* R */
#define MSDC_PS_WP (0x1 << 31) /* R */
@@ -304,6 +305,7 @@ struct msdc_host {
int cmd_rsp;
spinlock_t lock;
+ spinlock_t irqlock; /* sdio irq lock */
struct mmc_request *mrq;
struct mmc_command *cmd;
struct mmc_data *data;
@@ -322,12 +324,14 @@ struct msdc_host {
struct pinctrl_state *pins_uhs;
struct delayed_work req_timeout;
int irq; /* host interrupt */
+ bool irq_thread_alive;
struct clk *src_clk; /* msdc source clock */
struct clk *h_clk; /* msdc h_clk */
u32 mclk; /* mmc subsystem clock frequency */
u32 src_clk_freq; /* source clock frequency */
u32 sclk; /* SD/MS bus clock frequency */
+ bool clock_on;
unsigned char timing;
bool vqmmc_enabled;
u32 hs400_ds_delay;
@@ -387,6 +391,7 @@ static void msdc_reset_hw(struct msdc_host *host)
static void msdc_cmd_next(struct msdc_host *host,
struct mmc_request *mrq, struct mmc_command *cmd);
+static void msdc_recheck_sdio_irq(struct msdc_host *host);
static const u32 cmd_ints_mask = MSDC_INTEN_CMDRDY | MSDC_INTEN_RSPCRCERR |
MSDC_INTEN_CMDTMO | MSDC_INTEN_ACMDRDY |
@@ -513,6 +518,7 @@ static void msdc_gate_clock(struct msdc_host *host)
{
clk_disable_unprepare(host->src_clk);
clk_disable_unprepare(host->h_clk);
+ host->clock_on = false;
}
static void msdc_ungate_clock(struct msdc_host *host)
@@ -521,6 +527,7 @@ static void msdc_ungate_clock(struct msdc_host *host)
clk_prepare_enable(host->src_clk);
while (!(readl(host->base + MSDC_CFG) & MSDC_CFG_CKSTB))
cpu_relax();
+ host->clock_on = true;
}
static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
@@ -529,6 +536,7 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
u32 flags;
u32 div;
u32 sclk;
+ unsigned long irq_flags;
if (!hz) {
dev_dbg(host->dev, "set mclk to 0\n");
@@ -537,8 +545,11 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
return;
}
+ spin_lock_irqsave(&host->irqlock, irq_flags);
flags = readl(host->base + MSDC_INTEN);
sdr_clr_bits(host->base + MSDC_INTEN, flags);
+ spin_unlock_irqrestore(&host->irqlock, irq_flags);
+
sdr_clr_bits(host->base + MSDC_CFG, MSDC_CFG_HS400_CK_MODE);
if (timing == MMC_TIMING_UHS_DDR50 ||
timing == MMC_TIMING_MMC_DDR52 ||
@@ -588,7 +599,10 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
host->timing = timing;
/* need because clk changed. */
msdc_set_timeout(host, host->timeout_ns, host->timeout_clks);
+
+ spin_lock_irqsave(&host->irqlock, irq_flags);
sdr_set_bits(host->base + MSDC_INTEN, flags);
+ spin_unlock_irqrestore(&host->irqlock, irq_flags);
/*
* mmc_select_hs400() will drop to 50Mhz and High speed mode,
@@ -690,6 +704,7 @@ static inline u32 msdc_cmd_prepare_raw_cmd(struct msdc_host *host,
static void msdc_start_data(struct msdc_host *host, struct mmc_request *mrq,
struct mmc_command *cmd, struct mmc_data *data)
{
+ unsigned long flags;
bool read;
WARN_ON(host->data);
@@ -698,8 +713,12 @@ static void msdc_start_data(struct msdc_host *host, struct mmc_request *mrq,
mod_delayed_work(system_wq, &host->req_timeout, DAT_TIMEOUT);
msdc_dma_setup(host, &host->dma, data);
+
+ spin_lock_irqsave(&host->irqlock, flags);
sdr_set_bits(host->base + MSDC_INTEN, data_ints_mask);
sdr_set_field(host->base + MSDC_DMA_CTRL, MSDC_DMA_CTRL_START, 1);
+ spin_unlock_irqrestore(&host->irqlock, flags);
+
dev_dbg(host->dev, "DMA start\n");
dev_dbg(host->dev, "%s: cmd=%d DMA data: %d blocks; read=%d\n",
__func__, cmd->opcode, data->blocks, read);
@@ -756,6 +775,7 @@ static void msdc_request_done(struct msdc_host *host, struct mmc_request *mrq)
if (mrq->data)
msdc_unprepare_data(host, mrq);
mmc_request_done(host->mmc, mrq);
+ msdc_recheck_sdio_irq(host);
}
/* returns true if command is fully handled; returns false otherwise */
@@ -779,15 +799,17 @@ static bool msdc_cmd_done(struct msdc_host *host, int events,
| MSDC_INT_CMDTMO)))
return done;
- spin_lock_irqsave(&host->lock, flags);
done = !host->cmd;
+ spin_lock_irqsave(&host->lock, flags);
host->cmd = NULL;
spin_unlock_irqrestore(&host->lock, flags);
if (done)
return true;
+ spin_lock_irqsave(&host->irqlock, flags);
sdr_clr_bits(host->base + MSDC_INTEN, cmd_ints_mask);
+ spin_unlock_irqrestore(&host->irqlock, flags);
if (cmd->flags & MMC_RSP_PRESENT) {
if (cmd->flags & MMC_RSP_136) {
@@ -902,6 +924,7 @@ static inline bool msdc_cmd_is_ready(struct msdc_host *host,
static void msdc_start_command(struct msdc_host *host,
struct mmc_request *mrq, struct mmc_command *cmd)
{
+ unsigned long flags;
u32 rawcmd;
WARN_ON(host->cmd);
@@ -920,7 +943,10 @@ static void msdc_start_command(struct msdc_host *host,
rawcmd = msdc_cmd_prepare_raw_cmd(host, mrq, cmd);
mod_delayed_work(system_wq, &host->req_timeout, DAT_TIMEOUT);
+ spin_lock_irqsave(&host->irqlock, flags);
sdr_set_bits(host->base + MSDC_INTEN, cmd_ints_mask);
+ spin_unlock_irqrestore(&host->irqlock, flags);
+
writel(cmd->arg, host->base + SDC_ARG);
writel(rawcmd, host->base + SDC_CMD);
}
@@ -1013,8 +1039,8 @@ static bool msdc_data_xfer_done(struct msdc_host *host, u32 events,
| MSDC_INT_DMA_BDCSERR | MSDC_INT_DMA_GPDCSERR
| MSDC_INT_DMA_PROTECT);
- spin_lock_irqsave(&host->lock, flags);
done = !host->data;
+ spin_lock_irqsave(&host->lock, flags);
if (check_data)
host->data = NULL;
spin_unlock_irqrestore(&host->lock, flags);
@@ -1029,7 +1055,11 @@ static bool msdc_data_xfer_done(struct msdc_host *host, u32 events,
1);
while (readl(host->base + MSDC_DMA_CFG) & MSDC_DMA_CFG_STS)
cpu_relax();
+
+ spin_lock_irqsave(&host->irqlock, flags);
sdr_clr_bits(host->base + MSDC_INTEN, data_ints_mask);
+ spin_unlock_irqrestore(&host->irqlock, flags);
+
dev_dbg(host->dev, "DMA stop\n");
if ((events & MSDC_INT_XFER_COMPL) && (!stop || !stop->error)) {
@@ -1134,44 +1164,47 @@ static void msdc_request_timeout(struct work_struct *work)
static irqreturn_t msdc_irq(int irq, void *dev_id)
{
+ unsigned long flags;
struct msdc_host *host = (struct msdc_host *) dev_id;
+ struct mmc_request *mrq;
+ struct mmc_command *cmd;
+ struct mmc_data *data;
+ u32 events, event_mask;
+
+ spin_lock_irqsave(&host->irqlock, flags);
+ events = readl(host->base + MSDC_INT);
+ event_mask = readl(host->base + MSDC_INTEN);
+ /* clear interrupts */
+ writel(events & event_mask, host->base + MSDC_INT);
+
+ mrq = host->mrq;
+ cmd = host->cmd;
+ data = host->data;
+ spin_unlock_irqrestore(&host->irqlock, flags);
+
+ if ((events & event_mask) & MSDC_INT_SDIOIRQ) {
+ mmc_signal_sdio_irq(host->mmc);
+ if (!mrq)
+ return IRQ_HANDLED;
+ }
- while (true) {
- unsigned long flags;
- struct mmc_request *mrq;
- struct mmc_command *cmd;
- struct mmc_data *data;
- u32 events, event_mask;
-
- spin_lock_irqsave(&host->lock, flags);
- events = readl(host->base + MSDC_INT);
- event_mask = readl(host->base + MSDC_INTEN);
- /* clear interrupts */
- writel(events & event_mask, host->base + MSDC_INT);
-
- mrq = host->mrq;
- cmd = host->cmd;
- data = host->data;
- spin_unlock_irqrestore(&host->lock, flags);
-
- if (!(events & event_mask))
- break;
+ if (!(events & (event_mask & ~MSDC_INT_SDIOIRQ)))
+ return IRQ_HANDLED;
- if (!mrq) {
- dev_err(host->dev,
- "%s: MRQ=NULL; events=%08X; event_mask=%08X\n",
- __func__, events, event_mask);
- WARN_ON(1);
- break;
- }
+ if (!mrq) {
+ dev_err(host->dev,
+ "%s: MRQ=NULL; events=%08X; event_mask=%08X\n",
+ __func__, events, event_mask);
+ WARN_ON(1);
+ return IRQ_HANDLED;
+ }
- dev_dbg(host->dev, "%s: events=%08X\n", __func__, events);
+ dev_dbg(host->dev, "%s: events=%08X\n", __func__, events);
- if (cmd)
- msdc_cmd_done(host, events, mrq, cmd);
- else if (data)
- msdc_data_xfer_done(host, events, mrq, data);
- }
+ if (cmd)
+ msdc_cmd_done(host, events, mrq, cmd);
+ else if (data)
+ msdc_data_xfer_done(host, events, mrq, data);
return IRQ_HANDLED;
}
@@ -1179,6 +1212,7 @@ static irqreturn_t msdc_irq(int irq, void *dev_id)
static void msdc_init_hw(struct msdc_host *host)
{
u32 val;
+ unsigned long flags;
/* Configure to MMC/SD mode, clock free running */
sdr_set_bits(host->base + MSDC_CFG, MSDC_CFG_MODE | MSDC_CFG_CKPDN);
@@ -1190,9 +1224,11 @@ static void msdc_init_hw(struct msdc_host *host)
sdr_clr_bits(host->base + MSDC_PS, MSDC_PS_CDEN);
/* Disable and clear all interrupts */
+ spin_lock_irqsave(&host->irqlock, flags);
writel(0, host->base + MSDC_INTEN);
val = readl(host->base + MSDC_INT);
writel(val, host->base + MSDC_INT);
+ spin_unlock_irqrestore(&host->irqlock, flags);
writel(0, host->base + MSDC_PAD_TUNE);
writel(0, host->base + MSDC_IOCON);
@@ -1207,9 +1243,11 @@ static void msdc_init_hw(struct msdc_host *host)
*/
sdr_set_bits(host->base + SDC_CFG, SDC_CFG_SDIO);
- /* disable detect SDIO device interrupt function */
- sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE);
-
+ if (host->mmc->caps & MMC_CAP_SDIO_IRQ)
+ sdr_set_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE);
+ else
+ /* disable detect SDIO device interrupt function */
+ sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE);
/* Configure to default data timeout */
sdr_set_field(host->base + SDC_CFG, SDC_CFG_DTOC, 3);
@@ -1221,11 +1259,15 @@ static void msdc_init_hw(struct msdc_host *host)
static void msdc_deinit_hw(struct msdc_host *host)
{
u32 val;
+ unsigned long flags;
+
/* Disable and clear all interrupts */
+ spin_lock_irqsave(&host->irqlock, flags);
writel(0, host->base + MSDC_INTEN);
val = readl(host->base + MSDC_INT);
writel(val, host->base + MSDC_INT);
+ spin_unlock_irqrestore(&host->irqlock, flags);
}
/* init gpd and bd list in msdc_drv_probe */
@@ -1493,6 +1535,52 @@ static void msdc_hw_reset(struct mmc_host *mmc)
sdr_clr_bits(host->base + EMMC_IOCON, 1);
}
+/**
+ * msdc_recheck_sdio_irq - recheck whether the SDIO IRQ is lost
+ * @host: The host to check.
+ *
+ * Host controller may lost interrupt in some special case.
+ * Add sdio IRQ recheck mechanism to make sure all interrupts
+ * can be processed immediately
+ *
+ */
+static void msdc_recheck_sdio_irq(struct msdc_host *host)
+{
+ u32 reg_int, reg_ps;
+
+ if (host->clock_on &&
+ (host->mmc->caps & MMC_CAP_SDIO_IRQ) &&
+ host->irq_thread_alive) {
+ reg_int = readl(host->base + MSDC_INT);
+ reg_ps = readl(host->base + MSDC_PS);
+ if (!((reg_int & MSDC_INT_SDIOIRQ) ||
+ (reg_ps & MSDC_PS_DATA1))) {
+ mmc_signal_sdio_irq(host->mmc);
+ }
+ }
+}
+
+static void msdc_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+ unsigned long flags;
+ struct msdc_host *host = mmc_priv(mmc);
+
+ host->irq_thread_alive = true;
+ if (enable) {
+ pm_runtime_get_sync(host->dev);
+ msdc_recheck_sdio_irq(host);
+
+ spin_lock_irqsave(&host->irqlock, flags);
+ sdr_set_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE);
+ sdr_set_bits(host->base + MSDC_INTEN, MSDC_INTEN_SDIOIRQ);
+ spin_unlock_irqrestore(&host->irqlock, flags);
+ } else {
+ spin_lock_irqsave(&host->irqlock, flags);
+ sdr_clr_bits(host->base + MSDC_INTEN, MSDC_INTEN_SDIOIRQ);
+ spin_unlock_irqrestore(&host->irqlock, flags);
+ }
+}
+
static struct mmc_host_ops mt_msdc_ops = {
.post_req = msdc_post_req,
.pre_req = msdc_pre_req,
@@ -1504,6 +1592,7 @@ static void msdc_hw_reset(struct mmc_host *mmc)
.execute_tuning = msdc_execute_tuning,
.prepare_hs400_tuning = msdc_prepare_hs400_tuning,
.hw_reset = msdc_hw_reset,
+ .enable_sdio_irq = msdc_enable_sdio_irq,
};
static int msdc_drv_probe(struct platform_device *pdev)
@@ -1600,6 +1689,7 @@ static int msdc_drv_probe(struct platform_device *pdev)
mmc_dev(mmc)->dma_mask = &host->dma_mask;
host->timeout_clks = 3 * 1048576;
+ host->irq_thread_alive = false;
host->dma.gpd = dma_alloc_coherent(&pdev->dev,
2 * sizeof(struct mt_gpdma_desc),
&host->dma.gpd_addr, GFP_KERNEL);
@@ -1613,6 +1703,7 @@ static int msdc_drv_probe(struct platform_device *pdev)
msdc_init_gpd_bd(host, &host->dma);
INIT_DELAYED_WORK(&host->req_timeout, msdc_request_timeout);
spin_lock_init(&host->lock);
+ spin_lock_init(&host->irqlock);
platform_set_drvdata(pdev, mmc);
msdc_ungate_clock(host);
--
1.7.9.5
^ permalink raw reply related
* [PATCH 3/4] sdio: mediatek: support sdr104_clk_delay in sdio
From: Yong Mao @ 2016-11-08 6:09 UTC (permalink / raw)
To: Ulf Hansson
Cc: Mark Rutland, devicetree, YH Huang, Nicolas Boichat,
Mathias Nyman, srv_heupstream, Catalin Marinas, linux-mediatek,
Will Deacon, Douglas Anderson, yong mao, linux-kernel,
Chunfeng Yun, Rob Herring, Geert Uytterhoeven, linux-arm-kernel,
Philipp Zabel, Matthias Brugger, linux-mmc, Eddie Huang,
Chaotian Jing
In-Reply-To: <1478585341-6749-1-git-send-email-yong.mao@mediatek.com>
From: yong mao <yong.mao@mediatek.com>
In order to let sdio run stable with 200M clock,
we should setup the value of clock delay.
Signed-off-by: Yong Mao <yong.mao@mediatek.com>
Signed-off-by: Chaotian Jing <chaotian.jing@mediatek.com>
---
drivers/mmc/host/mtk-sd.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
index 37edf30..fba28f2 100644
--- a/drivers/mmc/host/mtk-sd.c
+++ b/drivers/mmc/host/mtk-sd.c
@@ -213,6 +213,7 @@
#define MSDC_PAD_TUNE_DATRRDLY (0x1f << 8) /* RW */
#define MSDC_PAD_TUNE_CMDRDLY (0x1f << 16) /* RW */
+#define MSDC_PAD_TUNE_CLKTDLY (0x1f << 27) /* RW */
#define PAD_DS_TUNE_DLY1 (0x1f << 2) /* RW */
#define PAD_DS_TUNE_DLY2 (0x1f << 7) /* RW */
@@ -335,6 +336,7 @@ struct msdc_host {
unsigned char timing;
bool vqmmc_enabled;
u32 hs400_ds_delay;
+ u32 sdr104_clk_delay;
bool hs400_mode; /* current eMMC will run at hs400 mode */
struct msdc_save_para save_para; /* used when gate HCLK */
struct msdc_tune_para def_tune_para; /* default tune setting */
@@ -1230,7 +1232,8 @@ static void msdc_init_hw(struct msdc_host *host)
writel(val, host->base + MSDC_INT);
spin_unlock_irqrestore(&host->irqlock, flags);
- writel(0, host->base + MSDC_PAD_TUNE);
+ sdr_set_field(host->base + MSDC_PAD_TUNE,
+ MSDC_PAD_TUNE_CLKTDLY, host->sdr104_clk_delay);
writel(0, host->base + MSDC_IOCON);
sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_DDLSEL, 0);
writel(0x403c0046, host->base + MSDC_PATCH_BIT);
@@ -1671,6 +1674,11 @@ static int msdc_drv_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "hs400-ds-delay: %x\n",
host->hs400_ds_delay);
+ if (!of_property_read_u32(pdev->dev.of_node, "sdr104-clk-delay",
+ &host->sdr104_clk_delay))
+ dev_dbg(&pdev->dev, "sdr104-clk-delay: %x\n",
+ host->sdr104_clk_delay);
+
host->dev = &pdev->dev;
host->mmc = mmc;
host->src_clk_freq = clk_get_rate(host->src_clk);
--
1.7.9.5
^ permalink raw reply related
* [PATCH 4/4] dts: arm64: enable mmc3 for supporting sdio feature
From: Yong Mao @ 2016-11-08 6:09 UTC (permalink / raw)
To: Ulf Hansson
Cc: Mark Rutland, devicetree, YH Huang, Nicolas Boichat,
Mathias Nyman, srv_heupstream, Catalin Marinas, linux-mediatek,
Will Deacon, Douglas Anderson, yong mao, linux-kernel,
Chunfeng Yun, Rob Herring, Geert Uytterhoeven, linux-arm-kernel,
Philipp Zabel, Matthias Brugger, linux-mmc, Eddie Huang,
Chaotian Jing
In-Reply-To: <1478585341-6749-1-git-send-email-yong.mao@mediatek.com>
From: yong mao <yong.mao@mediatek.com>
Add description of mmc3 for supporting sdio feature
Signed-off-by: Yong Mao <yong.mao@mediatek.com>
Signed-off-by: Chaotian Jing <chaotian.jing@mediatek.com>
---
arch/arm64/boot/dts/mediatek/mt8173-evb.dts | 82 +++++++++++++++++++++++++++
1 file changed, 82 insertions(+)
diff --git a/arch/arm64/boot/dts/mediatek/mt8173-evb.dts b/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
index 2a7f731..4dbd299 100644
--- a/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
+++ b/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
@@ -43,6 +43,14 @@
enable-active-high;
};
+ sdio_fixed_3v3: fixedregulator@0 {
+ compatible = "regulator-fixed";
+ regulator-name = "3V3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ gpio = <&pio 85 GPIO_ACTIVE_HIGH>;
+ };
+
connector {
compatible = "hdmi-connector";
label = "hdmi";
@@ -139,6 +147,25 @@
vqmmc-supply = <&mt6397_vmc_reg>;
};
+&mmc3 {
+ status = "okay";
+ pinctrl-names = "default", "state_uhs";
+ pinctrl-0 = <&mmc3_pins_default>;
+ pinctrl-1 = <&mmc3_pins_uhs>;
+ bus-width = <4>;
+ max-frequency = <200000000>;
+ cap-sd-highspeed;
+ sd-uhs-sdr50;
+ sd-uhs-sdr104;
+ sdr104-clk-delay = <5>;
+ keep-power-in-suspend;
+ enable-sdio-wakeup;
+ cap-sdio-irq;
+ vmmc-supply = <&sdio_fixed_3v3>;
+ vqmmc-supply = <&mt6397_vgp3_reg>;
+ non-removable;
+};
+
&pio {
disp_pwm0_pins: disp_pwm0_pins {
pins1 {
@@ -197,6 +224,36 @@
};
};
+ mmc3_pins_default: mmc3default {
+ pins_dat {
+ pinmux = <MT8173_PIN_22_MSDC3_DAT0__FUNC_MSDC3_DAT0>,
+ <MT8173_PIN_23_MSDC3_DAT1__FUNC_MSDC3_DAT1>,
+ <MT8173_PIN_24_MSDC3_DAT2__FUNC_MSDC3_DAT2>,
+ <MT8173_PIN_25_MSDC3_DAT3__FUNC_MSDC3_DAT3>;
+ input-enable;
+ drive-strength = <MTK_DRIVE_8mA>;
+ bias-pull-up = <MTK_PUPD_SET_R1R0_10>;
+ };
+
+ pins_cmd {
+ pinmux = <MT8173_PIN_27_MSDC3_CMD__FUNC_MSDC3_CMD>;
+ input-enable;
+ drive-strength = <MTK_DRIVE_8mA>;
+ bias-pull-up = <MTK_PUPD_SET_R1R0_10>;
+ };
+
+ pins_clk {
+ pinmux = <MT8173_PIN_26_MSDC3_CLK__FUNC_MSDC3_CLK>;
+ bias-pull-down;
+ drive-strength = <MTK_DRIVE_8mA>;
+ };
+
+ pins_pdn {
+ pinmux = <MT8173_PIN_85_AUD_DAT_MOSI__FUNC_GPIO85>;
+ output-low;
+ };
+ };
+
mmc0_pins_uhs: mmc0 {
pins_cmd_dat {
pinmux = <MT8173_PIN_57_MSDC0_DAT0__FUNC_MSDC0_DAT0>,
@@ -243,6 +300,31 @@
bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
};
};
+
+ mmc3_pins_uhs: mmc3 {
+ pins_dat {
+ pinmux = <MT8173_PIN_22_MSDC3_DAT0__FUNC_MSDC3_DAT0>,
+ <MT8173_PIN_23_MSDC3_DAT1__FUNC_MSDC3_DAT1>,
+ <MT8173_PIN_24_MSDC3_DAT2__FUNC_MSDC3_DAT2>,
+ <MT8173_PIN_25_MSDC3_DAT3__FUNC_MSDC3_DAT3>;
+ input-enable;
+ drive-strength = <MTK_DRIVE_8mA>;
+ bias-pull-up = <MTK_PUPD_SET_R1R0_10>;
+ };
+
+ pins_cmd {
+ pinmux = <MT8173_PIN_27_MSDC3_CMD__FUNC_MSDC3_CMD>;
+ input-enable;
+ drive-strength = <MTK_DRIVE_8mA>;
+ bias-pull-up = <MTK_PUPD_SET_R1R0_10>;
+ };
+
+ pins_clk {
+ pinmux = <MT8173_PIN_26_MSDC3_CLK__FUNC_MSDC3_CLK>;
+ drive-strength = <MTK_DRIVE_8mA>;
+ bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+ };
+ };
};
&pwm0 {
--
1.7.9.5
^ permalink raw reply related
* RE: [v15, 3/7] powerpc/fsl: move mpc85xx.h to include/linux/fsl
From: Y.B. Lu @ 2016-11-08 6:49 UTC (permalink / raw)
To: Arnd Bergmann
Cc: linuxppc-dev@lists.ozlabs.org, linux-mmc@vger.kernel.org,
ulf.hansson@linaro.org, Scott Wood, Mark Rutland,
Greg Kroah-Hartman, X.B. Xie, M.H. Lian,
linux-i2c@vger.kernel.org, linux-clk@vger.kernel.org, Qiang Zhao,
Russell King, Bhupesh Sharma, Joerg Roedel, Claudiu Manoil,
devicetree@vger.kernel.org, Rob Herring
In-Reply-To: <1543282.vWjeo4ynTa@wuerfel>
Hi Arnd,
> -----Original Message-----
> From: Arnd Bergmann [mailto:arnd@arndb.de]
> Sent: Tuesday, November 08, 2016 5:20 AM
> To: Y.B. Lu
> Cc: linuxppc-dev@lists.ozlabs.org; linux-mmc@vger.kernel.org;
> ulf.hansson@linaro.org; Scott Wood; Mark Rutland; Greg Kroah-Hartman; X.B.
> Xie; M.H. Lian; linux-i2c@vger.kernel.org; linux-clk@vger.kernel.org;
> Qiang Zhao; Russell King; Bhupesh Sharma; Joerg Roedel; Claudiu Manoil;
> devicetree@vger.kernel.org; Rob Herring; Santosh Shilimkar; linux-arm-
> kernel@lists.infradead.org; netdev@vger.kernel.org; linux-
> kernel@vger.kernel.org; Leo Li; iommu@lists.linux-foundation.org; Kumar
> Gala
> Subject: Re: [v15, 3/7] powerpc/fsl: move mpc85xx.h to include/linux/fsl
>
> On Monday, October 31, 2016 9:35:33 AM CET Y.B. Lu wrote:
> > >
> > > I don't see any of the contents of this header referenced by the soc
> > > driver any more. I think you can just drop this patch.
> > >
> >
> > [Lu Yangbo-B47093] This header file was included by guts.c.
> > The guts driver used macro SVR_MAJ/SVR_MIN for calculation.
> >
> > This header file was for powerpc arch before. And this patch is to
> > made it as common header file for both ARM and PPC.
> > Sooner or later this is needed.
>
> Let's discuss it once we actually need the header then, ok?
[Lu Yangbo-B47093] As I said, this header file was included by guts.c in patch 4.
The guts driver used macro SVR_MAJ/SVR_MIN for calculation which were defined in this header file.
Did you suggest we dropped this patch and just calculated them in driver?
Thanks :)
>
> Arnd
^ permalink raw reply
* Re: [PATCH] mmc: sdhci-pci-core: Tuning mode support for HS200 on AMD Platforms
From: Adrian Hunter @ 2016-11-08 9:45 UTC (permalink / raw)
To: Shyam Sundar S K
Cc: Ulf Hansson, linux-mmc, Sen, Pankaj, Shah, Nehal-bakulchandra,
Agrawal, Nitesh-kumar
In-Reply-To: <CAPDyKFoghPtP0Yff68k7gc+GxUo6uoqb1ucYPFWpEMReGM7Auw@mail.gmail.com>
On 07/11/16 14:00, Ulf Hansson wrote:
> On 27 October 2016 at 11:52, Shyam Sundar S K <ssundark@amd.com> wrote:
>> Made changes to the earlier submission based on the comments
>> received from Adrian.
>>
>> Reviewed-by: Sen, Pankaj <Pankaj.Sen@amd.com>
>> Reviewed-by: Shah, Nehal-bakulchandra <Nehal-bakulchandra.Shah@amd.com>
>> Signed-off-by: S-k, Shyam-sundar <Shyam-sundar.S-k@amd.com>
>>
>> Also, adding patch from Adrian for handling the device specific
>> private data.
>>
>> From: Adrian Hunter <adrian.hunter@intel.com>
>> Date: Mon, 10 Oct 2016 10:04:45 +0300
>> Subject: [PATCH] mmc: sdhci-pci: Let devices define their own private data
>
> Shyam,
>
> Seems like this should be two separate changes, one made by Adrian and
> one by you. Can you please re-spin.
Yes, 2 separate patches please. I didn't mean mix the patches together -
sorry if there was confusion.
^ permalink raw reply
* Re: [PATCH v2 2/2] mmc: sdhci-iproc: support standard byte register accesses
From: Adrian Hunter @ 2016-11-08 9:55 UTC (permalink / raw)
To: Scott Branden, Ulf Hansson, Rob Herring, Mark Rutland, Ray Jui,
Scott Branden
Cc: BCM Kernel Feedback, linux-mmc-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Srinath Mannam
In-Reply-To: <1478018277-10097-3-git-send-email-scott.branden-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
On 01/11/16 18:37, Scott Branden wrote:
> Add bytewise register accesses support for newer versions of IPROC
> SDHCI controllers.
> Previous sdhci-iproc versions of SDIO controllers
> (such as Raspberry Pi and Cygnus) only allowed for 32-bit register
> accesses.
>
> Signed-off-by: Srinath Mannam <srinath.mannam-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
> Signed-off-by: Scott Branden <scott.branden-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
This is unchanged from V1 which I acked, so:
Acked-by: Adrian Hunter <adrian.hunter-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v6 06/14] mmc: sdhci-msm: Add get_min_clock() and get_max_clock() callback
From: Adrian Hunter @ 2016-11-08 12:15 UTC (permalink / raw)
To: Ritesh Harjani, ulf.hansson-QSEj5FYQhm4dnm+yROfE0A,
linux-mmc-u79uwXL29TY76Z2rM5mHXA,
shawn.lin-TNX95d0MmH7DzftRWevZcw, sboyd-sgV2jX0FEOL9JmXXK+q4OQ
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-clk-u79uwXL29TY76Z2rM5mHXA,
david.brown-QSEj5FYQhm4dnm+yROfE0A,
andy.gross-QSEj5FYQhm4dnm+yROfE0A,
linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
georgi.djakov-QSEj5FYQhm4dnm+yROfE0A,
alex.lemberg-XdAiOPVOjttBDgjK7y7TUQ,
mateusz.nowak-ral2JQCrhuEAvxtiuMwx3w,
Yuliy.Izrailov-XdAiOPVOjttBDgjK7y7TUQ,
asutoshd-sgV2jX0FEOL9JmXXK+q4OQ, kdorfman-sgV2jX0FEOL9JmXXK+q4OQ,
david.griego-QSEj5FYQhm4dnm+yROfE0A,
stummala-sgV2jX0FEOL9JmXXK+q4OQ, venkatg-sgV2jX0FEOL9JmXXK+q4OQ,
rnayak-sgV2jX0FEOL9JmXXK+q4OQ,
pramod.gurav-QSEj5FYQhm4dnm+yROfE0A
In-Reply-To: <1478517877-23733-7-git-send-email-riteshh-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
On 07/11/16 13:24, Ritesh Harjani wrote:
> This add get_min_clock() and get_max_clock() callback
> for sdhci-msm. sdhci-msm min/max clocks may be different
> hence implement these callbacks.
>
> Signed-off-by: Sahitya Tummala <stummala-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
> Signed-off-by: Ritesh Harjani <riteshh-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
Acked-by: Adrian Hunter <adrian.hunter-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
> ---
> drivers/mmc/host/sdhci-msm.c | 16 ++++++++++++++++
> 1 file changed, 16 insertions(+)
>
> diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
> index 32b0b79..66ca444 100644
> --- a/drivers/mmc/host/sdhci-msm.c
> +++ b/drivers/mmc/host/sdhci-msm.c
> @@ -68,6 +68,7 @@
> #define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c
>
> #define TCXO_FREQ 19200000
> +#define SDHCI_MSM_MIN_CLOCK 400000
>
> #define CDR_SELEXT_SHIFT 20
> #define CDR_SELEXT_MASK (0xf << CDR_SELEXT_SHIFT)
> @@ -559,6 +560,19 @@ static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data)
> return IRQ_HANDLED;
> }
>
> +static unsigned int sdhci_msm_get_max_clock(struct sdhci_host *host)
> +{
> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
> + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
> +
> + return clk_round_rate(msm_host->clk, ULONG_MAX);
> +}
> +
> +static unsigned int sdhci_msm_get_min_clock(struct sdhci_host *host)
> +{
> + return SDHCI_MSM_MIN_CLOCK;
> +}
> +
> static const struct of_device_id sdhci_msm_dt_match[] = {
> { .compatible = "qcom,sdhci-msm-v4" },
> {},
> @@ -570,6 +584,8 @@ static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data)
> .platform_execute_tuning = sdhci_msm_execute_tuning,
> .reset = sdhci_reset,
> .set_clock = sdhci_set_clock,
> + .get_min_clock = sdhci_msm_get_min_clock,
> + .get_max_clock = sdhci_msm_get_max_clock,
> .set_bus_width = sdhci_set_bus_width,
> .set_uhs_signaling = sdhci_msm_set_uhs_signaling,
> .voltage_switch = sdhci_msm_voltage_switch,
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v6 08/14] mmc: sdhci-msm: Implement set_clock callback for sdhci-msm
From: Adrian Hunter @ 2016-11-08 12:16 UTC (permalink / raw)
To: Ritesh Harjani, ulf.hansson, linux-mmc, shawn.lin, sboyd
Cc: devicetree, linux-clk, david.brown, andy.gross, linux-arm-msm,
georgi.djakov, alex.lemberg, mateusz.nowak, Yuliy.Izrailov,
asutoshd, kdorfman, david.griego, stummala, venkatg, rnayak,
pramod.gurav
In-Reply-To: <1478517877-23733-9-git-send-email-riteshh@codeaurora.org>
On 07/11/16 13:24, Ritesh Harjani wrote:
> sdhci-msm controller may have different clk-rates for each
> bus speed mode. Thus implement set_clock callback for
> sdhci-msm driver.
>
> Signed-off-by: Sahitya Tummala <stummala@codeaurora.org>
> Signed-off-by: Ritesh Harjani <riteshh@codeaurora.org>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
^ permalink raw reply
* Re: [PATCH v6 09/14] mmc: sdhci-msm: Add clock changes for DDR mode.
From: Adrian Hunter @ 2016-11-08 12:20 UTC (permalink / raw)
To: Ritesh Harjani, ulf.hansson, linux-mmc, shawn.lin, sboyd
Cc: devicetree, linux-clk, david.brown, andy.gross, linux-arm-msm,
georgi.djakov, alex.lemberg, mateusz.nowak, Yuliy.Izrailov,
asutoshd, kdorfman, david.griego, stummala, venkatg, rnayak,
pramod.gurav
In-Reply-To: <1478517877-23733-10-git-send-email-riteshh@codeaurora.org>
On 07/11/16 13:24, Ritesh Harjani wrote:
> SDHC MSM controller need 2x clock for MCLK at GCC.
> Hence make required changes to have 2x clock for
> DDR timing modes.
>
> Signed-off-by: Ritesh Harjani <riteshh@codeaurora.org>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
> ---
> drivers/mmc/host/sdhci-msm.c | 17 +++++++++++++++--
> 1 file changed, 15 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
> index ff0915b..220567c 100644
> --- a/drivers/mmc/host/sdhci-msm.c
> +++ b/drivers/mmc/host/sdhci-msm.c
> @@ -633,6 +633,7 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
> {
> struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
> struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
> + struct mmc_ios curr_ios = host->mmc->ios;
> int rc;
>
> if (!clock) {
> @@ -641,11 +642,23 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
> }
>
> spin_unlock_irq(&host->lock);
> + /*
> + * The SDHC requires internal clock frequency to be double the
> + * actual clock that will be set for DDR mode. The controller
> + * uses the faster clock(100/400MHz) for some of its parts and
> + * send the actual required clock (50/200MHz) to the card.
> + */
> + if ((curr_ios.timing == MMC_TIMING_UHS_DDR50) ||
> + (curr_ios.timing == MMC_TIMING_MMC_DDR52) ||
> + (curr_ios.timing == MMC_TIMING_MMC_HS400))
> + clock *= 2;
> +
> if (clock != msm_host->clk_rate) {
> rc = clk_set_rate(msm_host->clk, clock);
> if (rc) {
> - pr_err("%s: Failed to set clock at rate %u\n",
> - mmc_hostname(host->mmc), clock);
> + pr_err("%s: Failed to set clock at rate %u at timing %d\n",
> + mmc_hostname(host->mmc), clock,
> + curr_ios.timing);
> spin_lock_irq(&host->lock);
> goto out;
> }
>
^ permalink raw reply
* Re: [PATCH v6 11/14] mmc: sdhci-msm: Add HS400 platform support
From: Adrian Hunter @ 2016-11-08 12:37 UTC (permalink / raw)
To: Ritesh Harjani, ulf.hansson, linux-mmc, shawn.lin, sboyd
Cc: devicetree, linux-clk, david.brown, andy.gross, linux-arm-msm,
georgi.djakov, alex.lemberg, mateusz.nowak, Yuliy.Izrailov,
asutoshd, kdorfman, david.griego, stummala, venkatg, rnayak,
pramod.gurav
In-Reply-To: <1478517877-23733-12-git-send-email-riteshh@codeaurora.org>
On 07/11/16 13:24, Ritesh Harjani wrote:
> From: Venkat Gopalakrishnan <venkatg@codeaurora.org>
>
> The following msm platform specific changes are added to support HS400.
> - Allow tuning for HS400 mode.
> - Configure HS400 timing mode using the VENDOR_SPECIFIC_FUNC register.
>
> Signed-off-by: Venkat Gopalakrishnan <venkatg@codeaurora.org>
> Signed-off-by: Ritesh Harjani <riteshh@codeaurora.org>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
> ---
> drivers/mmc/host/sdhci-msm.c | 127 +++++++++++++++++++++++++++++++++++++++----
> 1 file changed, 117 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
> index 220567c..2561c41 100644
> --- a/drivers/mmc/host/sdhci-msm.c
> +++ b/drivers/mmc/host/sdhci-msm.c
> @@ -31,6 +31,7 @@
> #define HC_MODE_EN 0x1
> #define CORE_POWER 0x0
> #define CORE_SW_RST BIT(7)
> +#define FF_CLK_SW_RST_DIS BIT(13)
>
> #define CORE_PWRCTL_STATUS 0xdc
> #define CORE_PWRCTL_MASK 0xe0
> @@ -64,11 +65,18 @@
>
> #define CORE_VENDOR_SPEC 0x10c
> #define CORE_CLK_PWRSAVE BIT(1)
> +#define CORE_HC_MCLK_SEL_DFLT (2 << 8)
> +#define CORE_HC_MCLK_SEL_HS400 (3 << 8)
> +#define CORE_HC_MCLK_SEL_MASK (3 << 8)
> +#define CORE_HC_SELECT_IN_EN BIT(18)
> +#define CORE_HC_SELECT_IN_HS400 (6 << 19)
> +#define CORE_HC_SELECT_IN_MASK (7 << 19)
>
> #define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c
>
> #define TCXO_FREQ 19200000
> #define SDHCI_MSM_MIN_CLOCK 400000
> +#define CORE_FREQ_100MHZ (100 * 1000 * 1000)
>
> #define CDR_SELEXT_SHIFT 20
> #define CDR_SELEXT_MASK (0xf << CDR_SELEXT_SHIFT)
> @@ -85,6 +93,8 @@ struct sdhci_msm_host {
> unsigned long clk_rate;
> struct mmc_host *mmc;
> bool use_14lpp_dll_reset;
> + bool tuning_done;
> + bool calibration_done;
> };
>
> /* Platform specific tuning */
> @@ -173,8 +183,8 @@ static int msm_config_cm_dll_phase(struct sdhci_host *host, u8 phase)
> * Find out the greatest range of consecuitive selected
> * DLL clock output phases that can be used as sampling
> * setting for SD3.0 UHS-I card read operation (in SDR104
> - * timing mode) or for eMMC4.5 card read operation (in HS200
> - * timing mode).
> + * timing mode) or for eMMC4.5 card read operation (in
> + * HS400/HS200 timing mode).
> * Select the 3/4 of the range and configure the DLL with the
> * selected DLL clock output phase.
> */
> @@ -426,9 +436,10 @@ static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)
> * Tuning is required for SDR104, HS200 and HS400 cards and
> * if clock frequency is greater than 100MHz in these modes.
> */
> - if (host->clock <= 100 * 1000 * 1000 ||
> - !((ios.timing == MMC_TIMING_MMC_HS200) ||
> - (ios.timing == MMC_TIMING_UHS_SDR104)))
> + if (host->clock <= CORE_FREQ_100MHZ ||
> + !(ios.timing == MMC_TIMING_MMC_HS400 ||
> + ios.timing == MMC_TIMING_MMC_HS200 ||
> + ios.timing == MMC_TIMING_UHS_SDR104))
> return 0;
>
> retry:
> @@ -479,6 +490,8 @@ static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)
> rc = -EIO;
> }
>
> + if (!rc)
> + msm_host->tuning_done = true;
> return rc;
> }
>
> @@ -486,7 +499,10 @@ static void sdhci_msm_set_uhs_signaling(struct sdhci_host *host,
> unsigned int uhs)
> {
> struct mmc_host *mmc = host->mmc;
> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
> + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
> u16 ctrl_2;
> + u32 config;
>
> ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
> /* Select Bus Speed Mode for host */
> @@ -501,6 +517,7 @@ static void sdhci_msm_set_uhs_signaling(struct sdhci_host *host,
> case MMC_TIMING_UHS_SDR50:
> ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
> break;
> + case MMC_TIMING_MMC_HS400:
> case MMC_TIMING_MMC_HS200:
> case MMC_TIMING_UHS_SDR104:
> ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
> @@ -517,11 +534,31 @@ static void sdhci_msm_set_uhs_signaling(struct sdhci_host *host,
> * provide feedback clock, the mode selection can be any value less
> * than 3'b011 in bits [2:0] of HOST CONTROL2 register.
> */
> - if (host->clock <= 100000000 &&
> - (uhs == MMC_TIMING_MMC_HS400 ||
> - uhs == MMC_TIMING_MMC_HS200 ||
> - uhs == MMC_TIMING_UHS_SDR104))
> - ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
> + if (host->clock <= CORE_FREQ_100MHZ) {
> + if ((uhs == MMC_TIMING_MMC_HS400) ||
> + (uhs == MMC_TIMING_MMC_HS200) ||
> + (uhs == MMC_TIMING_UHS_SDR104))
> + ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
> + /*
> + * Make sure DLL is disabled when not required
> + *
> + * Write 1 to DLL_RST bit of DLL_CONFIG register
> + */
> + config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
> + config |= CORE_DLL_RST;
> + writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
> +
> + /* Write 1 to DLL_PDN bit of DLL_CONFIG register */
> + config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
> + config |= CORE_DLL_PDN;
> + writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
> +
> + /*
> + * The DLL needs to be restored and CDCLP533 recalibrated
> + * when the clock frequency is set back to 400MHz.
> + */
> + msm_host->calibration_done = false;
> + }
>
> dev_dbg(mmc_dev(mmc), "%s: clock=%u uhs=%u ctrl_2=0x%x\n",
> mmc_hostname(host->mmc), host->clock, uhs, ctrl_2);
> @@ -634,6 +671,7 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
> struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
> struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
> struct mmc_ios curr_ios = host->mmc->ios;
> + u32 config;
> int rc;
>
> if (!clock) {
> @@ -652,6 +690,70 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
> (curr_ios.timing == MMC_TIMING_MMC_DDR52) ||
> (curr_ios.timing == MMC_TIMING_MMC_HS400))
> clock *= 2;
> + /*
> + * In general all timing modes are controlled via UHS mode select in
> + * Host Control2 register. eMMC specific HS200/HS400 doesn't have
> + * their respective modes defined here, hence we use these values.
> + *
> + * HS200 - SDR104 (Since they both are equivalent in functionality)
> + * HS400 - This involves multiple configurations
> + * Initially SDR104 - when tuning is required as HS200
> + * Then when switching to DDR @ 400MHz (HS400) we use
> + * the vendor specific HC_SELECT_IN to control the mode.
> + *
> + * In addition to controlling the modes we also need to select the
> + * correct input clock for DLL depending on the mode.
> + *
> + * HS400 - divided clock (free running MCLK/2)
> + * All other modes - default (free running MCLK)
> + */
> + if (curr_ios.timing == MMC_TIMING_MMC_HS400) {
> + /* Select the divided clock (free running MCLK/2) */
> + config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC);
> + config &= ~CORE_HC_MCLK_SEL_MASK;
> + config |= CORE_HC_MCLK_SEL_HS400;
> +
> + writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC);
> + /*
> + * Select HS400 mode using the HC_SELECT_IN from VENDOR SPEC
> + * register
> + */
> + if (msm_host->tuning_done && !msm_host->calibration_done) {
> + /*
> + * Write 0x6 to HC_SELECT_IN and 1 to HC_SELECT_IN_EN
> + * field in VENDOR_SPEC_FUNC
> + */
> + config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC);
> + config |= CORE_HC_SELECT_IN_HS400;
> + config |= CORE_HC_SELECT_IN_EN;
> + writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC);
> + }
> + } else {
> + /* Select the default clock (free running MCLK) */
> + config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC);
> + config &= ~CORE_HC_MCLK_SEL_MASK;
> + config |= CORE_HC_MCLK_SEL_DFLT;
> + writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC);
> +
> + /*
> + * Disable HC_SELECT_IN to be able to use the UHS mode select
> + * configuration from Host Control2 register for all other
> + * modes.
> + *
> + * Write 0 to HC_SELECT_IN and HC_SELECT_IN_EN field
> + * in VENDOR_SPEC_FUNC
> + */
> + config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC);
> + config &= ~CORE_HC_SELECT_IN_EN;
> + config &= ~CORE_HC_SELECT_IN_MASK;
> + writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC);
> + }
> +
> + /*
> + * Make sure above writes impacting free running MCLK are completed
> + * before changing the clk_rate at GCC.
> + */
> + wmb();
>
> if (clock != msm_host->clk_rate) {
> rc = clk_set_rate(msm_host->clk, clock);
> @@ -790,6 +892,11 @@ static int sdhci_msm_probe(struct platform_device *pdev)
> /* Set HC_MODE_EN bit in HC_MODE register */
> writel_relaxed(HC_MODE_EN, (msm_host->core_mem + CORE_HC_MODE));
>
> + /* Set FF_CLK_SW_RST_DIS bit in HC_MODE register */
> + config = readl_relaxed(msm_host->core_mem + CORE_HC_MODE);
> + config |= FF_CLK_SW_RST_DIS;
> + writel_relaxed(config, msm_host->core_mem + CORE_HC_MODE);
> +
> host_version = readw_relaxed((host->ioaddr + SDHCI_HOST_VERSION));
> dev_dbg(&pdev->dev, "Host Version: 0x%x Vendor Version 0x%x\n",
> host_version, ((host_version & SDHCI_VENDOR_VER_MASK) >>
>
^ permalink raw reply
* Re: [PATCH v6 12/14] mmc: sdhci-msm: Save the calculated tuning phase
From: Adrian Hunter @ 2016-11-08 12:41 UTC (permalink / raw)
To: Ritesh Harjani, ulf.hansson, linux-mmc, shawn.lin, sboyd
Cc: devicetree, linux-clk, david.brown, andy.gross, linux-arm-msm,
georgi.djakov, alex.lemberg, mateusz.nowak, Yuliy.Izrailov,
asutoshd, kdorfman, david.griego, stummala, venkatg, rnayak,
pramod.gurav
In-Reply-To: <1478517877-23733-13-git-send-email-riteshh@codeaurora.org>
On 07/11/16 13:24, Ritesh Harjani wrote:
> Save the tuning phase once the tuning is performed.
> This phase value will be used while calibrating DLL
> for HS400 mode.
>
> Signed-off-by: Ritesh Harjani <riteshh@codeaurora.org>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
> ---
> drivers/mmc/host/sdhci-msm.c | 10 ++++++++++
> 1 file changed, 10 insertions(+)
>
> diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
> index 2561c41..6431bb8 100644
> --- a/drivers/mmc/host/sdhci-msm.c
> +++ b/drivers/mmc/host/sdhci-msm.c
> @@ -74,6 +74,7 @@
>
> #define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c
>
> +#define INVALID_TUNING_PHASE -1
> #define TCXO_FREQ 19200000
> #define SDHCI_MSM_MIN_CLOCK 400000
> #define CORE_FREQ_100MHZ (100 * 1000 * 1000)
> @@ -95,6 +96,7 @@ struct sdhci_msm_host {
> bool use_14lpp_dll_reset;
> bool tuning_done;
> bool calibration_done;
> + u8 saved_tuning_phase;
> };
>
> /* Platform specific tuning */
> @@ -134,6 +136,9 @@ static int msm_config_cm_dll_phase(struct sdhci_host *host, u8 phase)
> u32 config;
> struct mmc_host *mmc = host->mmc;
>
> + if (phase > 0xf)
> + return -EINVAL;
> +
> spin_lock_irqsave(&host->lock, flags);
>
> config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
> @@ -431,6 +436,8 @@ static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)
> int rc;
> struct mmc_host *mmc = host->mmc;
> struct mmc_ios ios = host->mmc->ios;
> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
> + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
>
> /*
> * Tuning is required for SDR104, HS200 and HS400 cards and
> @@ -455,6 +462,7 @@ static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)
> if (rc)
> return rc;
>
> + msm_host->saved_tuning_phase = phase;
> rc = mmc_send_tuning(mmc, opcode, NULL);
> if (!rc) {
> /* Tuning is successful at this tuning point */
> @@ -826,6 +834,8 @@ static int sdhci_msm_probe(struct platform_device *pdev)
>
> sdhci_get_of_property(pdev);
>
> + msm_host->saved_tuning_phase = INVALID_TUNING_PHASE;
> +
> /* Setup SDCC bus voter clock. */
> msm_host->bus_clk = devm_clk_get(&pdev->dev, "bus");
> if (!IS_ERR(msm_host->bus_clk)) {
>
^ permalink raw reply
* Re: [PATCH v6 13/14] mmc: sdhci-msm: Add calibration tuning for CDCLP533 circuit
From: Adrian Hunter @ 2016-11-08 12:50 UTC (permalink / raw)
To: Ritesh Harjani, ulf.hansson, linux-mmc, shawn.lin, sboyd
Cc: devicetree, linux-clk, david.brown, andy.gross, linux-arm-msm,
georgi.djakov, alex.lemberg, mateusz.nowak, Yuliy.Izrailov,
asutoshd, kdorfman, david.griego, stummala, venkatg, rnayak,
pramod.gurav
In-Reply-To: <1478517877-23733-14-git-send-email-riteshh@codeaurora.org>
On 07/11/16 13:24, Ritesh Harjani wrote:
> In HS400 mode a new RCLK is introduced on the interface for read data
> transfers. The eMMC5.0 device transmits the read data to the host with
> respect to rising and falling edges of RCLK. In order to ensure correct
> operation of read data transfers in HS400 mode, the incoming RX data
> needs to be sampled by delayed version of RCLK.
>
> The CDCLP533 delay circuit shifts the RCLK by T/4. It needs to be
> initialized, configured and enabled once during HS400 mode switch and
> when operational voltage/clock is changed.
>
> Signed-off-by: Venkat Gopalakrishnan <venkatg@codeaurora.org>
> Signed-off-by: Ritesh Harjani <riteshh@codeaurora.org>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
> ---
> drivers/mmc/host/sdhci-msm.c | 163 +++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 163 insertions(+)
>
> diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
> index 6431bb8..ae19d1a 100644
> --- a/drivers/mmc/host/sdhci-msm.c
> +++ b/drivers/mmc/host/sdhci-msm.c
> @@ -19,6 +19,7 @@
> #include <linux/delay.h>
> #include <linux/mmc/mmc.h>
> #include <linux/slab.h>
> +#include <linux/iopoll.h>
>
> #include "sdhci-pltfm.h"
>
> @@ -57,6 +58,7 @@
> #define CORE_DLL_PDN BIT(29)
> #define CORE_DLL_RST BIT(30)
> #define CORE_DLL_CONFIG 0x100
> +#define CORE_CMD_DAT_TRACK_SEL BIT(0)
> #define CORE_DLL_STATUS 0x108
>
> #define CORE_DLL_CONFIG_2 0x1b4
> @@ -72,6 +74,33 @@
> #define CORE_HC_SELECT_IN_HS400 (6 << 19)
> #define CORE_HC_SELECT_IN_MASK (7 << 19)
>
> +#define CORE_CSR_CDC_CTLR_CFG0 0x130
> +#define CORE_SW_TRIG_FULL_CALIB BIT(16)
> +#define CORE_HW_AUTOCAL_ENA BIT(17)
> +
> +#define CORE_CSR_CDC_CTLR_CFG1 0x134
> +#define CORE_CSR_CDC_CAL_TIMER_CFG0 0x138
> +#define CORE_TIMER_ENA BIT(16)
> +
> +#define CORE_CSR_CDC_CAL_TIMER_CFG1 0x13C
> +#define CORE_CSR_CDC_REFCOUNT_CFG 0x140
> +#define CORE_CSR_CDC_COARSE_CAL_CFG 0x144
> +#define CORE_CDC_OFFSET_CFG 0x14C
> +#define CORE_CSR_CDC_DELAY_CFG 0x150
> +#define CORE_CDC_SLAVE_DDA_CFG 0x160
> +#define CORE_CSR_CDC_STATUS0 0x164
> +#define CORE_CALIBRATION_DONE BIT(0)
> +
> +#define CORE_CDC_ERROR_CODE_MASK 0x7000000
> +
> +#define CORE_CSR_CDC_GEN_CFG 0x178
> +#define CORE_CDC_SWITCH_BYPASS_OFF BIT(0)
> +#define CORE_CDC_SWITCH_RC_EN BIT(1)
> +
> +#define CORE_DDR_200_CFG 0x184
> +#define CORE_CDC_T4_DLY_SEL BIT(0)
> +#define CORE_START_CDC_TRAFFIC BIT(6)
> +
> #define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c
>
> #define INVALID_TUNING_PHASE -1
> @@ -429,6 +458,131 @@ static int msm_init_cm_dll(struct sdhci_host *host)
> return 0;
> }
>
> +static int sdhci_msm_cdclp533_calibration(struct sdhci_host *host)
> +{
> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
> + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
> + u32 config, calib_done;
> + int ret;
> +
> + pr_debug("%s: %s: Enter\n", mmc_hostname(host->mmc), __func__);
> +
> + /*
> + * Retuning in HS400 (DDR mode) will fail, just reset the
> + * tuning block and restore the saved tuning phase.
> + */
> + ret = msm_init_cm_dll(host);
> + if (ret)
> + goto out;
> +
> + /* Set the selected phase in delay line hw block */
> + ret = msm_config_cm_dll_phase(host, msm_host->saved_tuning_phase);
> + if (ret)
> + goto out;
> +
> + /* Write 1 to CMD_DAT_TRACK_SEL field in DLL_CONFIG */
> + config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
> + config |= CORE_CMD_DAT_TRACK_SEL;
> + writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
> +
> + /* Write 0 to CDC_T4_DLY_SEL field in VENDOR_SPEC_DDR200_CFG */
> + config = readl_relaxed(host->ioaddr + CORE_DDR_200_CFG);
> + config &= ~CORE_CDC_T4_DLY_SEL;
> + writel_relaxed(config, host->ioaddr + CORE_DDR_200_CFG);
> +
> + /* Write 0 to CDC_SWITCH_BYPASS_OFF field in CORE_CSR_CDC_GEN_CFG */
> + config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_GEN_CFG);
> + config &= ~CORE_CDC_SWITCH_BYPASS_OFF;
> + writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_GEN_CFG);
> +
> + /* Write 1 to CDC_SWITCH_RC_EN field in CORE_CSR_CDC_GEN_CFG */
> + config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_GEN_CFG);
> + config |= CORE_CDC_SWITCH_RC_EN;
> + writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_GEN_CFG);
> +
> + /* Write 0 to START_CDC_TRAFFIC field in CORE_DDR200_CFG */
> + config = readl_relaxed(host->ioaddr + CORE_DDR_200_CFG);
> + config &= ~CORE_START_CDC_TRAFFIC;
> + writel_relaxed(config, host->ioaddr + CORE_DDR_200_CFG);
> +
> + /*
> + * Perform CDC Register Initialization Sequence
> + *
> + * CORE_CSR_CDC_CTLR_CFG0 0x11800EC
> + * CORE_CSR_CDC_CTLR_CFG1 0x3011111
> + * CORE_CSR_CDC_CAL_TIMER_CFG0 0x1201000
> + * CORE_CSR_CDC_CAL_TIMER_CFG1 0x4
> + * CORE_CSR_CDC_REFCOUNT_CFG 0xCB732020
> + * CORE_CSR_CDC_COARSE_CAL_CFG 0xB19
> + * CORE_CSR_CDC_DELAY_CFG 0x3AC
> + * CORE_CDC_OFFSET_CFG 0x0
> + * CORE_CDC_SLAVE_DDA_CFG 0x16334
> + */
> +
> + writel_relaxed(0x11800EC, host->ioaddr + CORE_CSR_CDC_CTLR_CFG0);
> + writel_relaxed(0x3011111, host->ioaddr + CORE_CSR_CDC_CTLR_CFG1);
> + writel_relaxed(0x1201000, host->ioaddr + CORE_CSR_CDC_CAL_TIMER_CFG0);
> + writel_relaxed(0x4, host->ioaddr + CORE_CSR_CDC_CAL_TIMER_CFG1);
> + writel_relaxed(0xCB732020, host->ioaddr + CORE_CSR_CDC_REFCOUNT_CFG);
> + writel_relaxed(0xB19, host->ioaddr + CORE_CSR_CDC_COARSE_CAL_CFG);
> + writel_relaxed(0x3AC, host->ioaddr + CORE_CSR_CDC_DELAY_CFG);
> + writel_relaxed(0x0, host->ioaddr + CORE_CDC_OFFSET_CFG);
> + writel_relaxed(0x16334, host->ioaddr + CORE_CDC_SLAVE_DDA_CFG);
> +
> + /* CDC HW Calibration */
> +
> + /* Write 1 to SW_TRIG_FULL_CALIB field in CORE_CSR_CDC_CTLR_CFG0 */
> + config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_CTLR_CFG0);
> + config |= CORE_SW_TRIG_FULL_CALIB;
> + writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_CTLR_CFG0);
> +
> + /* Write 0 to SW_TRIG_FULL_CALIB field in CORE_CSR_CDC_CTLR_CFG0 */
> + config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_CTLR_CFG0);
> + config &= ~CORE_SW_TRIG_FULL_CALIB;
> + writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_CTLR_CFG0);
> +
> + /* Write 1 to HW_AUTOCAL_ENA field in CORE_CSR_CDC_CTLR_CFG0 */
> + config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_CTLR_CFG0);
> + config |= CORE_HW_AUTOCAL_ENA;
> + writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_CTLR_CFG0);
> +
> + /* Write 1 to TIMER_ENA field in CORE_CSR_CDC_CAL_TIMER_CFG0 */
> + config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_CAL_TIMER_CFG0);
> + config |= CORE_TIMER_ENA;
> + writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_CAL_TIMER_CFG0);
> +
> + /* Poll on CALIBRATION_DONE field in CORE_CSR_CDC_STATUS0 to be 1 */
> + ret = readl_relaxed_poll_timeout(host->ioaddr + CORE_CSR_CDC_STATUS0,
> + calib_done,
> + (calib_done & CORE_CALIBRATION_DONE),
> + 1, 50);
> +
> + if (ret == -ETIMEDOUT) {
> + pr_err("%s: %s: CDC calibration was not completed\n",
> + mmc_hostname(host->mmc), __func__);
> + goto out;
> + }
> +
> + /* Verify CDC_ERROR_CODE field in CORE_CSR_CDC_STATUS0 is 0 */
> + ret = readl_relaxed(host->ioaddr + CORE_CSR_CDC_STATUS0)
> + & CORE_CDC_ERROR_CODE_MASK;
> + if (ret) {
> + pr_err("%s: %s: CDC error code %d\n",
> + mmc_hostname(host->mmc), __func__, ret);
> + ret = -EINVAL;
> + goto out;
> + }
> +
> + /* Write 1 to START_CDC_TRAFFIC field in CORE_DDR200_CFG */
> + config = readl_relaxed(host->ioaddr + CORE_DDR_200_CFG);
> + config |= CORE_START_CDC_TRAFFIC;
> + writel_relaxed(config, host->ioaddr + CORE_DDR_200_CFG);
> +out:
> + pr_debug("%s: %s: Exit, ret %d\n", mmc_hostname(host->mmc),
> + __func__, ret);
> + return ret;
> +}
> +
> static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)
> {
> int tuning_seq_cnt = 3;
> @@ -571,6 +725,15 @@ static void sdhci_msm_set_uhs_signaling(struct sdhci_host *host,
> dev_dbg(mmc_dev(mmc), "%s: clock=%u uhs=%u ctrl_2=0x%x\n",
> mmc_hostname(host->mmc), host->clock, uhs, ctrl_2);
> sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
> +
> + spin_unlock_irq(&host->lock);
> + /* CDCLP533 HW calibration is only required for HS400 mode*/
> + if (host->clock > CORE_FREQ_100MHZ &&
> + msm_host->tuning_done && !msm_host->calibration_done &&
> + (mmc->ios.timing == MMC_TIMING_MMC_HS400))
> + if (!sdhci_msm_cdclp533_calibration(host))
> + msm_host->calibration_done = true;
> + spin_lock_irq(&host->lock);
> }
>
> static void sdhci_msm_voltage_switch(struct sdhci_host *host)
>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox