[1/3] mmc: dw_mmc: add support for hi3798mv200
Commit Message
From: Yang Xiwen <forbidden405@outlook.com>
Add support for Hi3798MV200 specific extension.
Signed-off-by: Yang Xiwen <forbidden405@outlook.com>
---
drivers/mmc/host/Kconfig | 9 ++
drivers/mmc/host/Makefile | 1 +
drivers/mmc/host/dw_mmc-hi3798mv200.c | 238 ++++++++++++++++++++++++++++++++++
3 files changed, 248 insertions(+)
Comments
Hi Yang,
kernel test robot noticed the following build errors:
[auto build test ERROR on 8d3dea210042f54b952b481838c1e7dfc4ec751d]
url: https://github.com/intel-lab-lkp/linux/commits/Yang-Xiwen-via-B4-Relay/mmc-dw_mmc-add-support-for-hi3798mv200/20240216-014744
base: 8d3dea210042f54b952b481838c1e7dfc4ec751d
patch link: https://lore.kernel.org/r/20240216-b4-mmc-hi3798mv200-v1-1-7d46db845ae6%40outlook.com
patch subject: [PATCH 1/3] mmc: dw_mmc: add support for hi3798mv200
config: parisc-allyesconfig (https://download.01.org/0day-ci/archive/20240218/202402181540.H4Ose96P-lkp@intel.com/config)
compiler: hppa-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240218/202402181540.H4Ose96P-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202402181540.H4Ose96P-lkp@intel.com/
All errors (new ones prefixed by >>):
drivers/mmc/host/dw_mmc-hi3798mv200.c: In function 'dw_mci_hi3798mv200_init':
>> drivers/mmc/host/dw_mmc-hi3798mv200.c:178:36: error: passing argument 1 of 'mmc_of_parse_clk_phase' from incompatible pointer type [-Werror=incompatible-pointer-types]
178 | mmc_of_parse_clk_phase(host->dev, &priv->phase_map);
| ~~~~^~~~~
| |
| struct device *
In file included from drivers/mmc/host/dw_mmc-hi3798mv200.c:11:
include/linux/mmc/host.h:542:46: note: expected 'struct mmc_host *' but argument is of type 'struct device *'
542 | void mmc_of_parse_clk_phase(struct mmc_host *host,
| ~~~~~~~~~~~~~~~~~^~~~
cc1: some warnings being treated as errors
vim +/mmc_of_parse_clk_phase +178 drivers/mmc/host/dw_mmc-hi3798mv200.c
168
169 static int dw_mci_hi3798mv200_init(struct dw_mci *host)
170 {
171 struct dw_mci_hi3798mv200_priv *priv;
172 struct device_node *np = host->dev->of_node;
173
174 priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
175 if (!priv)
176 return -ENOMEM;
177
> 178 mmc_of_parse_clk_phase(host->dev, &priv->phase_map);
179
180 priv->sample_clk = devm_clk_get_enabled(host->dev, "ciu-sample");
181 if (IS_ERR(priv->sample_clk)) {
182 dev_err(host->dev, "failed to get enabled ciu-sample clock\n");
183 return PTR_ERR(priv->sample_clk);
184 }
185
186 priv->drive_clk = devm_clk_get_enabled(host->dev, "ciu-drive");
187 if (IS_ERR(priv->drive_clk)) {
188 dev_err(host->dev, "failed to get enabled ciu-drive clock\n");
189 return PTR_ERR(priv->drive_clk);
190 }
191
192 priv->sap_dll_reg = syscon_regmap_lookup_by_phandle(np, "hisilicon,sap-dll-reg");
193 if (IS_ERR(priv->sap_dll_reg)) {
194 dev_err(host->dev, "failed to get sap-dll-reg\n");
195 return PTR_ERR(priv->sap_dll_reg);
196 }
197
198 host->priv = priv;
199 return 0;
200 }
201
Hi Yang,
kernel test robot noticed the following build errors:
[auto build test ERROR on 8d3dea210042f54b952b481838c1e7dfc4ec751d]
url: https://github.com/intel-lab-lkp/linux/commits/Yang-Xiwen-via-B4-Relay/mmc-dw_mmc-add-support-for-hi3798mv200/20240216-014744
base: 8d3dea210042f54b952b481838c1e7dfc4ec751d
patch link: https://lore.kernel.org/r/20240216-b4-mmc-hi3798mv200-v1-1-7d46db845ae6%40outlook.com
patch subject: [PATCH 1/3] mmc: dw_mmc: add support for hi3798mv200
config: powerpc-allyesconfig (https://download.01.org/0day-ci/archive/20240219/202402190531.qUVUPNDD-lkp@intel.com/config)
compiler: clang version 19.0.0git (https://github.com/llvm/llvm-project 36adfec155de366d722f2bac8ff9162289dcf06c)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240219/202402190531.qUVUPNDD-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202402190531.qUVUPNDD-lkp@intel.com/
All errors (new ones prefixed by >>):
>> drivers/mmc/host/dw_mmc-hi3798mv200.c:178:25: error: incompatible pointer types passing 'struct device *' to parameter of type 'struct mmc_host *' [-Werror,-Wincompatible-pointer-types]
178 | mmc_of_parse_clk_phase(host->dev, &priv->phase_map);
| ^~~~~~~~~
include/linux/mmc/host.h:542:46: note: passing argument to parameter 'host' here
542 | void mmc_of_parse_clk_phase(struct mmc_host *host,
| ^
1 error generated.
vim +178 drivers/mmc/host/dw_mmc-hi3798mv200.c
168
169 static int dw_mci_hi3798mv200_init(struct dw_mci *host)
170 {
171 struct dw_mci_hi3798mv200_priv *priv;
172 struct device_node *np = host->dev->of_node;
173
174 priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
175 if (!priv)
176 return -ENOMEM;
177
> 178 mmc_of_parse_clk_phase(host->dev, &priv->phase_map);
179
180 priv->sample_clk = devm_clk_get_enabled(host->dev, "ciu-sample");
181 if (IS_ERR(priv->sample_clk)) {
182 dev_err(host->dev, "failed to get enabled ciu-sample clock\n");
183 return PTR_ERR(priv->sample_clk);
184 }
185
186 priv->drive_clk = devm_clk_get_enabled(host->dev, "ciu-drive");
187 if (IS_ERR(priv->drive_clk)) {
188 dev_err(host->dev, "failed to get enabled ciu-drive clock\n");
189 return PTR_ERR(priv->drive_clk);
190 }
191
192 priv->sap_dll_reg = syscon_regmap_lookup_by_phandle(np, "hisilicon,sap-dll-reg");
193 if (IS_ERR(priv->sap_dll_reg)) {
194 dev_err(host->dev, "failed to get sap-dll-reg\n");
195 return PTR_ERR(priv->sap_dll_reg);
196 }
197
198 host->priv = priv;
199 return 0;
200 }
201
On 18/02/2024 09:21, Yang Xiwen wrote:
> On 2/18/2024 4:03 PM, kernel test robot wrote:
>> Hi Yang,
>>
>> kernel test robot noticed the following build errors:
>>
>> [auto build test ERROR on 8d3dea210042f54b952b481838c1e7dfc4ec751d]
>>
>> url: https://github.com/intel-lab-lkp/linux/commits/Yang-Xiwen-via-B4-Relay/mmc-dw_mmc-add-support-for-hi3798mv200/20240216-014744
>> base: 8d3dea210042f54b952b481838c1e7dfc4ec751d
>> patch link: https://lore.kernel.org/r/20240216-b4-mmc-hi3798mv200-v1-1-7d46db845ae6%40outlook.com
>> patch subject: [PATCH 1/3] mmc: dw_mmc: add support for hi3798mv200
>> config: parisc-allyesconfig (https://download.01.org/0day-ci/archive/20240218/202402181540.H4Ose96P-lkp@intel.com/config)
>> compiler: hppa-linux-gcc (GCC) 13.2.0
>> reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240218/202402181540.H4Ose96P-lkp@intel.com/reproduce)
>>
>> If you fix the issue in a separate patch/commit (i.e. not just a new version of
>> the same patch/commit), kindly add following tags
>> | Reported-by: kernel test robot <lkp@intel.com>
>> | Closes: https://lore.kernel.org/oe-kbuild-all/202402181540.H4Ose96P-lkp@intel.com/
>>
>> All errors (new ones prefixed by >>):
>>
>> drivers/mmc/host/dw_mmc-hi3798mv200.c: In function 'dw_mci_hi3798mv200_init':
>>>> drivers/mmc/host/dw_mmc-hi3798mv200.c:178:36: error: passing argument 1 of 'mmc_of_parse_clk_phase' from incompatible pointer type [-Werror=incompatible-pointer-types]
>> 178 | mmc_of_parse_clk_phase(host->dev, &priv->phase_map);
>> | ~~~~^~~~~
>> | |
>> | struct device *
>> In file included from drivers/mmc/host/dw_mmc-hi3798mv200.c:11:
>> include/linux/mmc/host.h:542:46: note: expected 'struct mmc_host *' but argument is of type 'struct device *'
>> 542 | void mmc_of_parse_clk_phase(struct mmc_host *host,
>> | ~~~~~~~~~~~~~~~~~^~~~
>> cc1: some warnings being treated as errors
>>
>>
>> vim +/mmc_of_parse_clk_phase +178 drivers/mmc/host/dw_mmc-hi3798mv200.c
>>
>> 168
>> 169 static int dw_mci_hi3798mv200_init(struct dw_mci *host)
>> 170 {
>> 171 struct dw_mci_hi3798mv200_priv *priv;
>> 172 struct device_node *np = host->dev->of_node;
>> 173
>> 174 priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
>> 175 if (!priv)
>> 176 return -ENOMEM;
>> 177
>> > 178 mmc_of_parse_clk_phase(host->dev, &priv->phase_map);
>
> Please note that this patch is depending on another patch[1].
>
> [1]:
> https://lore.kernel.org/linux-mmc/ae876e697ba16ba2925ec217c6b4e3d8ffea4ab3.camel@codeconstruct.com.au/T/#t
>
You did not provide any links to dependencies in cover letter nor in
patch changelog. You included on purpose, which is nice and correct, the
base commit:
base-commit: 8d3dea210042f54b952b481838c1e7dfc4ec751d
which does not include above commit apparently.
How anyone can guess it and test your patches?
Please send with proper dependencies marked.
Best regards,
Krzysztof
@@ -798,6 +798,15 @@ config MMC_DW_HI3798CV200
Synopsys DesignWare Memory Card Interface driver. Select this option
for platforms based on HiSilicon Hi3798CV200 SoC.
+config MMC_DW_HI3798MV200
+ tristate "Hi3798MV200 specific extensions for Synopsys DW Memory Card Interface"
+ depends on MMC_DW
+ select MMC_DW_PLTFM
+ help
+ This selects support for HiSilicon Hi3798MV200 SoC specific extensions to the
+ Synopsys DesignWare Memory Card Interface driver. Select this option
+ for platforms based on HiSilicon Hi3798MV200 SoC.
+
config MMC_DW_K3
tristate "K3 specific extensions for Synopsys DW Memory Card Interface"
depends on MMC_DW
@@ -51,6 +51,7 @@ obj-$(CONFIG_MMC_DW_PLTFM) += dw_mmc-pltfm.o
obj-$(CONFIG_MMC_DW_BLUEFIELD) += dw_mmc-bluefield.o
obj-$(CONFIG_MMC_DW_EXYNOS) += dw_mmc-exynos.o
obj-$(CONFIG_MMC_DW_HI3798CV200) += dw_mmc-hi3798cv200.o
+obj-$(CONFIG_MMC_DW_HI3798MV200) += dw_mmc-hi3798mv200.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
new file mode 100644
@@ -0,0 +1,238 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Modified from dw_mmc-hi3798cv200.c
+ *
+ * Copyright (c) 2024 Yang Xiwen <forbidden405@outlook.com>
+ * Copyright (c) 2018 HiSilicon Technologies Co., Ltd.
+ */
+
+#include <linux/clk.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mmc/host.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include "dw_mmc.h"
+#include "dw_mmc-pltfm.h"
+
+#define SDMMC_TUNING_CTRL 0x118
+#define SDMMC_TUNING_FIND_EDGE BIT(5)
+
+#define ALL_INT_CLR 0x1ffff
+
+/* DLL ctrl reg */
+#define SAP_DLL_CTRL_DLLMODE BIT(16)
+
+struct dw_mci_hi3798mv200_priv {
+ struct clk *sample_clk;
+ struct clk *drive_clk;
+ struct regmap *sap_dll_reg;
+ struct mmc_clk_phase_map phase_map;
+};
+
+static void dw_mci_hi3798mv200_set_ios(struct dw_mci *host, struct mmc_ios *ios)
+{
+ struct dw_mci_hi3798mv200_priv *priv = host->priv;
+ struct mmc_clk_phase phase = priv->phase_map.phase[ios->timing];
+ u32 val;
+
+ val = mci_readl(host, ENABLE_SHIFT);
+ if (ios->timing == MMC_TIMING_MMC_DDR52
+ || ios->timing == MMC_TIMING_UHS_DDR50)
+ val |= SDMMC_ENABLE_PHASE;
+ else
+ val &= ~SDMMC_ENABLE_PHASE;
+ mci_writel(host, ENABLE_SHIFT, val);
+
+ val = mci_readl(host, DDR_REG);
+ if (ios->timing == MMC_TIMING_MMC_HS400)
+ val |= SDMMC_DDR_HS400;
+ else
+ val &= ~SDMMC_DDR_HS400;
+ mci_writel(host, DDR_REG, val);
+
+ if (clk_set_rate(host->ciu_clk, ios->clock))
+ dev_warn(host->dev, "Failed to set rate to %u\n", ios->clock);
+ else
+ // CLK_MUX_ROUND_NEAREST is enabled for this clock
+ // The actual clock rate is not what we setted, but a rounded value
+ // so we should get the rate once again
+ host->bus_hz = clk_get_rate(host->ciu_clk);
+
+ if (phase.valid) {
+ clk_set_phase(priv->drive_clk, phase.out_deg);
+ clk_set_phase(priv->sample_clk, phase.in_deg);
+ } else {
+ dev_warn(host->dev,
+ "The phase entry for timing mode %d is missing in device tree.\n",
+ ios->timing);
+ }
+}
+
+static inline int dw_mci_hi3798mv200_enable_tuning(struct dw_mci_slot *slot)
+{
+ struct dw_mci_hi3798mv200_priv *priv = slot->host->priv;
+ struct regmap *dll_reg = priv->sap_dll_reg;
+
+ return regmap_clear_bits(dll_reg, 0, SAP_DLL_CTRL_DLLMODE);
+}
+
+static inline int dw_mci_hi3798mv200_disable_tuning(struct dw_mci_slot *slot)
+{
+ struct dw_mci_hi3798mv200_priv *priv = slot->host->priv;
+ struct regmap *dll_reg = priv->sap_dll_reg;
+
+ return regmap_set_bits(dll_reg, 0, SAP_DLL_CTRL_DLLMODE);
+}
+
+static int dw_mci_hi3798mv200_execute_tuning_mix_mode(struct dw_mci_slot *slot,
+ u32 opcode)
+{
+ static const int degrees[] = { 0, 45, 90, 135, 180, 225, 270, 315 };
+ struct dw_mci *host = slot->host;
+ struct dw_mci_hi3798mv200_priv *priv = host->priv;
+ int raise_point = -1, fall_point = -1;
+ int err, prev_err = -1;
+ int found = 0;
+ int regval;
+ int i;
+ int ret;
+
+ // enable tuning
+ ret = dw_mci_hi3798mv200_enable_tuning(slot);
+ if (ret < 0)
+ return ret;
+ for (i = 0; i < ARRAY_SIZE(degrees); i++) {
+ clk_set_phase(priv->sample_clk, degrees[i]);
+ mci_writel(host, RINTSTS, ALL_INT_CLR);
+
+ err = mmc_send_tuning(slot->mmc, opcode, NULL);
+ if (!err) {
+ regval = mci_readl(host, TUNING_CTRL);
+ if (regval & SDMMC_TUNING_FIND_EDGE)
+ err = 1;
+ else
+ found = 1;
+ };
+
+ if (i > 0) {
+ if (err && !prev_err)
+ fall_point = i - 1;
+ if (!err && prev_err)
+ raise_point = i;
+ }
+
+ if (raise_point != -1 && fall_point != -1)
+ goto tuning_out;
+
+ prev_err = err;
+ err = 0;
+ }
+
+tuning_out:
+ ret = dw_mci_hi3798mv200_disable_tuning(slot);
+ if (ret < 0)
+ return ret;
+ if (found) {
+ if (raise_point == -1)
+ raise_point = 0;
+ if (fall_point == -1)
+ fall_point = ARRAY_SIZE(degrees) - 1;
+ if (fall_point < raise_point) {
+ if ((raise_point + fall_point) >
+ (ARRAY_SIZE(degrees) - 1))
+ i = fall_point / 2;
+ else
+ i = (raise_point + ARRAY_SIZE(degrees) - 1) / 2;
+ } else {
+ i = (raise_point + fall_point) / 2;
+ }
+
+ // use the same phase table for both HS200 and HS400
+ priv->phase_map.phase[MMC_TIMING_MMC_HS200].in_deg = degrees[i];
+ priv->phase_map.phase[MMC_TIMING_MMC_HS400].in_deg = degrees[i];
+
+ clk_set_phase(priv->sample_clk, degrees[i]);
+ dev_dbg(host->dev, "Tuning clk_sample[%d, %d], set[%d]\n",
+ raise_point, fall_point, degrees[i]);
+ } else {
+ dev_err(host->dev, "No valid clk_sample shift! use default\n");
+ err = -EINVAL;
+ }
+
+ mci_writel(host, RINTSTS, ALL_INT_CLR);
+ return err;
+}
+
+static int dw_mci_hi3798mv200_init(struct dw_mci *host)
+{
+ struct dw_mci_hi3798mv200_priv *priv;
+ struct device_node *np = host->dev->of_node;
+
+ priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ mmc_of_parse_clk_phase(host->dev, &priv->phase_map);
+
+ priv->sample_clk = devm_clk_get_enabled(host->dev, "ciu-sample");
+ if (IS_ERR(priv->sample_clk)) {
+ dev_err(host->dev, "failed to get enabled ciu-sample clock\n");
+ return PTR_ERR(priv->sample_clk);
+ }
+
+ priv->drive_clk = devm_clk_get_enabled(host->dev, "ciu-drive");
+ if (IS_ERR(priv->drive_clk)) {
+ dev_err(host->dev, "failed to get enabled ciu-drive clock\n");
+ return PTR_ERR(priv->drive_clk);
+ }
+
+ priv->sap_dll_reg = syscon_regmap_lookup_by_phandle(np, "hisilicon,sap-dll-reg");
+ if (IS_ERR(priv->sap_dll_reg)) {
+ dev_err(host->dev, "failed to get sap-dll-reg\n");
+ return PTR_ERR(priv->sap_dll_reg);
+ }
+
+ host->priv = priv;
+ return 0;
+}
+
+static const struct dw_mci_drv_data hi3798mv200_data = {
+ .common_caps = MMC_CAP_CMD23,
+ .init = dw_mci_hi3798mv200_init,
+ .set_ios = dw_mci_hi3798mv200_set_ios,
+ .execute_tuning = dw_mci_hi3798mv200_execute_tuning_mix_mode,
+};
+
+static const struct of_device_id dw_mci_hi3798mv200_match[] = {
+ { .compatible = "hisilicon,hi3798mv200-dw-mshc" },
+ {},
+};
+
+static int dw_mci_hi3798mv200_probe(struct platform_device *pdev)
+{
+ return dw_mci_pltfm_register(pdev, &hi3798mv200_data);
+}
+
+static void dw_mci_hi3798mv200_remove(struct platform_device *pdev)
+{
+ dw_mci_pltfm_remove(pdev);
+}
+
+MODULE_DEVICE_TABLE(of, dw_mci_hi3798mv200_match);
+static struct platform_driver dw_mci_hi3798mv200_driver = {
+ .probe = dw_mci_hi3798mv200_probe,
+ .remove_new = dw_mci_hi3798mv200_remove,
+ .driver = {
+ .name = "dwmmc_hi3798mv200",
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ .of_match_table = dw_mci_hi3798mv200_match,
+ },
+};
+module_platform_driver(dw_mci_hi3798mv200_driver);
+
+MODULE_DESCRIPTION("HiSilicon Hi3798MV200 Specific DW-MSHC Driver Extension");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:dwmmc_hi3798mv200");