From 0458b88267c637fb872b0359da9ff0b243081e9e Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 7 Dec 2020 20:05:14 +0100 Subject: soc: samsung: exynos-asv: don't defer early on not-supported SoCs Check if the SoC is really supported before gathering the needed resources. This fixes endless deferred probe on some SoCs other than Exynos5422 (like Exynos5410). Fixes: 5ea428595cc5 ("soc: samsung: Add Exynos Adaptive Supply Voltage driver") Cc: Signed-off-by: Marek Szyprowski Reviewed-by: Pankaj Dubey Link: https://lore.kernel.org/r/20201207190517.262051-2-krzk@kernel.org Signed-off-by: Krzysztof Kozlowski --- drivers/soc/samsung/exynos-asv.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/samsung/exynos-asv.c b/drivers/soc/samsung/exynos-asv.c index 8abf4dfaa5c5..f653e3533f0f 100644 --- a/drivers/soc/samsung/exynos-asv.c +++ b/drivers/soc/samsung/exynos-asv.c @@ -119,11 +119,6 @@ static int exynos_asv_probe(struct platform_device *pdev) u32 product_id = 0; int ret, i; - cpu_dev = get_cpu_device(0); - ret = dev_pm_opp_get_opp_count(cpu_dev); - if (ret < 0) - return -EPROBE_DEFER; - asv = devm_kzalloc(&pdev->dev, sizeof(*asv), GFP_KERNEL); if (!asv) return -ENOMEM; @@ -144,6 +139,11 @@ static int exynos_asv_probe(struct platform_device *pdev) return -ENODEV; } + cpu_dev = get_cpu_device(0); + ret = dev_pm_opp_get_opp_count(cpu_dev); + if (ret < 0) + return -EPROBE_DEFER; + ret = of_property_read_u32(pdev->dev.of_node, "samsung,asv-bin", &asv->of_bin); if (ret < 0) -- cgit v1.2.3 From 4561560dfb4f847a0b327d48bdd1f45bf1b6261f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 7 Dec 2020 20:05:15 +0100 Subject: soc: samsung: exynos-asv: handle reading revision register error If regmap_read() fails, the product_id local variable will contain random value from the stack. Do not try to parse such value and fail the ASV driver probe. Fixes: 5ea428595cc5 ("soc: samsung: Add Exynos Adaptive Supply Voltage driver") Cc: Signed-off-by: Krzysztof Kozlowski Reviewed-by: Pankaj Dubey Link: https://lore.kernel.org/r/20201207190517.262051-3-krzk@kernel.org --- drivers/soc/samsung/exynos-asv.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/soc') diff --git a/drivers/soc/samsung/exynos-asv.c b/drivers/soc/samsung/exynos-asv.c index f653e3533f0f..5daeadc36382 100644 --- a/drivers/soc/samsung/exynos-asv.c +++ b/drivers/soc/samsung/exynos-asv.c @@ -129,7 +129,13 @@ static int exynos_asv_probe(struct platform_device *pdev) return PTR_ERR(asv->chipid_regmap); } - regmap_read(asv->chipid_regmap, EXYNOS_CHIPID_REG_PRO_ID, &product_id); + ret = regmap_read(asv->chipid_regmap, EXYNOS_CHIPID_REG_PRO_ID, + &product_id); + if (ret < 0) { + dev_err(&pdev->dev, "Cannot read revision from ChipID: %d\n", + ret); + return -ENODEV; + } switch (product_id & EXYNOS_MASK) { case 0xE5422000: -- cgit v1.2.3 From 352bfbb3e0230c96b2bce00d2ac3f0de303cc7b6 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 7 Dec 2020 19:54:57 +0100 Subject: soc: samsung: exynos-chipid: convert to driver and merge exynos-asv The Exynos Chip ID driver on Exynos SoCs has so far only informational purpose - to expose the SoC device in sysfs. No other drivers depend on it so there is really no benefit of initializing it early. The code would be the most flexible if converted to a regular driver. However there is already another driver - Exynos ASV (Adaptive Supply Voltage) - which binds to the device node of Chip ID. The solution is to convert the Exynos Chip ID to a built in driver and merge the Exynos ASV into it. This has several benefits: 1. Although the Exynos ASV driver binds to a device node present in all Exynos DTS (generic compatible), it fails to probe except on the supported ones (only Exynos5422). This means that the regular boot process has a planned/normal device probe failure. Merging the ASV into Chip ID will remove this probe failure because the final driver will always bind, just with disabled ASV features. 2. Allows to use dev_info() as the SoC bus is present (since core_initcall). 3. Could speed things up because of execution of Chip ID code in a SMP environment (after bringing up secondary CPUs, unlike early_initcall), This reduces the amount of work to be done early, when the kernel has to bring up critical devices. 5. Makes the Chip ID code defer-probe friendly, Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201207190517.262051-5-krzk@kernel.org Reviewed-by: Pankaj Dubey --- arch/arm/mach-exynos/Kconfig | 1 - drivers/soc/samsung/Kconfig | 12 +++---- drivers/soc/samsung/Makefile | 3 +- drivers/soc/samsung/exynos-asv.c | 45 ++++++------------------ drivers/soc/samsung/exynos-asv.h | 2 ++ drivers/soc/samsung/exynos-chipid.c | 69 ++++++++++++++++++++++++++----------- 6 files changed, 67 insertions(+), 65 deletions(-) (limited to 'drivers/soc') diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index 56d272967fc0..5a48abac6af4 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig @@ -13,7 +13,6 @@ menuconfig ARCH_EXYNOS select ARM_GIC select EXYNOS_IRQ_COMBINER select COMMON_CLK_SAMSUNG - select EXYNOS_ASV select EXYNOS_CHIPID select EXYNOS_THERMAL select EXYNOS_PMU diff --git a/drivers/soc/samsung/Kconfig b/drivers/soc/samsung/Kconfig index fc7f48a92288..5745d7e5908e 100644 --- a/drivers/soc/samsung/Kconfig +++ b/drivers/soc/samsung/Kconfig @@ -7,21 +7,19 @@ menuconfig SOC_SAMSUNG if SOC_SAMSUNG -config EXYNOS_ASV - bool "Exynos Adaptive Supply Voltage support" if COMPILE_TEST - depends on (ARCH_EXYNOS && EXYNOS_CHIPID) || COMPILE_TEST - select EXYNOS_ASV_ARM if ARM && ARCH_EXYNOS - # There is no need to enable these drivers for ARMv8 config EXYNOS_ASV_ARM bool "Exynos ASV ARMv7-specific driver extensions" if COMPILE_TEST - depends on EXYNOS_ASV + depends on EXYNOS_CHIPID config EXYNOS_CHIPID - bool "Exynos Chipid controller driver" if COMPILE_TEST + bool "Exynos ChipID controller and ASV driver" if COMPILE_TEST depends on ARCH_EXYNOS || COMPILE_TEST + select EXYNOS_ASV_ARM if ARM && ARCH_EXYNOS select MFD_SYSCON select SOC_BUS + help + Support for Samsung Exynos SoC ChipID and Adaptive Supply Voltage. config EXYNOS_PMU bool "Exynos PMU controller driver" if COMPILE_TEST diff --git a/drivers/soc/samsung/Makefile b/drivers/soc/samsung/Makefile index 59e8e9453f27..0c523a8de4eb 100644 --- a/drivers/soc/samsung/Makefile +++ b/drivers/soc/samsung/Makefile @@ -1,9 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_EXYNOS_ASV) += exynos-asv.o obj-$(CONFIG_EXYNOS_ASV_ARM) += exynos5422-asv.o -obj-$(CONFIG_EXYNOS_CHIPID) += exynos-chipid.o +obj-$(CONFIG_EXYNOS_CHIPID) += exynos-chipid.o exynos-asv.o obj-$(CONFIG_EXYNOS_PMU) += exynos-pmu.o obj-$(CONFIG_EXYNOS_PMU_ARM_DRIVERS) += exynos3250-pmu.o exynos4-pmu.o \ diff --git a/drivers/soc/samsung/exynos-asv.c b/drivers/soc/samsung/exynos-asv.c index 5daeadc36382..d60af8acc391 100644 --- a/drivers/soc/samsung/exynos-asv.c +++ b/drivers/soc/samsung/exynos-asv.c @@ -2,7 +2,9 @@ /* * Copyright (c) 2019 Samsung Electronics Co., Ltd. * http://www.samsung.com/ + * Copyright (c) 2020 Krzysztof Kozlowski * Author: Sylwester Nawrocki + * Author: Krzysztof Kozlowski * * Samsung Exynos SoC Adaptive Supply Voltage support */ @@ -10,12 +12,7 @@ #include #include #include -#include -#include -#include #include -#include -#include #include #include #include @@ -111,7 +108,7 @@ static int exynos_asv_update_opps(struct exynos_asv *asv) return 0; } -static int exynos_asv_probe(struct platform_device *pdev) +int exynos_asv_init(struct device *dev, struct regmap *regmap) { int (*probe_func)(struct exynos_asv *asv); struct exynos_asv *asv; @@ -119,21 +116,16 @@ static int exynos_asv_probe(struct platform_device *pdev) u32 product_id = 0; int ret, i; - asv = devm_kzalloc(&pdev->dev, sizeof(*asv), GFP_KERNEL); + asv = devm_kzalloc(dev, sizeof(*asv), GFP_KERNEL); if (!asv) return -ENOMEM; - asv->chipid_regmap = device_node_to_regmap(pdev->dev.of_node); - if (IS_ERR(asv->chipid_regmap)) { - dev_err(&pdev->dev, "Could not find syscon regmap\n"); - return PTR_ERR(asv->chipid_regmap); - } - + asv->chipid_regmap = regmap; + asv->dev = dev; ret = regmap_read(asv->chipid_regmap, EXYNOS_CHIPID_REG_PRO_ID, &product_id); if (ret < 0) { - dev_err(&pdev->dev, "Cannot read revision from ChipID: %d\n", - ret); + dev_err(dev, "Cannot read revision from ChipID: %d\n", ret); return -ENODEV; } @@ -142,7 +134,9 @@ static int exynos_asv_probe(struct platform_device *pdev) probe_func = exynos5422_asv_init; break; default: - return -ENODEV; + dev_dbg(dev, "No ASV support for this SoC\n"); + devm_kfree(dev, asv); + return 0; } cpu_dev = get_cpu_device(0); @@ -150,14 +144,11 @@ static int exynos_asv_probe(struct platform_device *pdev) if (ret < 0) return -EPROBE_DEFER; - ret = of_property_read_u32(pdev->dev.of_node, "samsung,asv-bin", + ret = of_property_read_u32(dev->of_node, "samsung,asv-bin", &asv->of_bin); if (ret < 0) asv->of_bin = -EINVAL; - asv->dev = &pdev->dev; - dev_set_drvdata(&pdev->dev, asv); - for (i = 0; i < ARRAY_SIZE(asv->subsys); i++) asv->subsys[i].asv = asv; @@ -167,17 +158,3 @@ static int exynos_asv_probe(struct platform_device *pdev) return exynos_asv_update_opps(asv); } - -static const struct of_device_id exynos_asv_of_device_ids[] = { - { .compatible = "samsung,exynos4210-chipid" }, - {} -}; - -static struct platform_driver exynos_asv_driver = { - .driver = { - .name = "exynos-asv", - .of_match_table = exynos_asv_of_device_ids, - }, - .probe = exynos_asv_probe, -}; -module_platform_driver(exynos_asv_driver); diff --git a/drivers/soc/samsung/exynos-asv.h b/drivers/soc/samsung/exynos-asv.h index 3fd1f2acd999..dcbe154db31e 100644 --- a/drivers/soc/samsung/exynos-asv.h +++ b/drivers/soc/samsung/exynos-asv.h @@ -68,4 +68,6 @@ static inline u32 exynos_asv_opp_get_frequency(const struct exynos_asv_subsys *s return __asv_get_table_entry(&subsys->table, level, 0); } +int exynos_asv_init(struct device *dev, struct regmap *regmap); + #endif /* __LINUX_SOC_EXYNOS_ASV_H */ diff --git a/drivers/soc/samsung/exynos-chipid.c b/drivers/soc/samsung/exynos-chipid.c index 1a76eade2ed6..fa6a9b9f6d70 100644 --- a/drivers/soc/samsung/exynos-chipid.c +++ b/drivers/soc/samsung/exynos-chipid.c @@ -2,20 +2,28 @@ /* * Copyright (c) 2019 Samsung Electronics Co., Ltd. * http://www.samsung.com/ + * Copyright (c) 2020 Krzysztof Kozlowski * * Exynos - CHIP ID support * Author: Pankaj Dubey * Author: Bartlomiej Zolnierkiewicz + * Author: Krzysztof Kozlowski + * + * Samsung Exynos SoC Adaptive Supply Voltage and Chip ID support */ -#include +#include +#include #include #include +#include #include #include #include #include +#include "exynos-asv.h" + static const struct exynos_soc_id { const char *name; unsigned int id; @@ -46,25 +54,17 @@ static const char * __init product_id_to_soc_id(unsigned int product_id) return NULL; } -static int __init exynos_chipid_early_init(void) +static int exynos_chipid_probe(struct platform_device *pdev) { struct soc_device_attribute *soc_dev_attr; struct soc_device *soc_dev; struct device_node *root; - struct device_node *syscon; struct regmap *regmap; u32 product_id; u32 revision; int ret; - syscon = of_find_compatible_node(NULL, NULL, - "samsung,exynos4210-chipid"); - if (!syscon) - return -ENODEV; - - regmap = device_node_to_regmap(syscon); - of_node_put(syscon); - + regmap = device_node_to_regmap(pdev->dev.of_node); if (IS_ERR(regmap)) return PTR_ERR(regmap); @@ -74,7 +74,8 @@ static int __init exynos_chipid_early_init(void) revision = product_id & EXYNOS_REV_MASK; - soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); + soc_dev_attr = devm_kzalloc(&pdev->dev, sizeof(*soc_dev_attr), + GFP_KERNEL); if (!soc_dev_attr) return -ENOMEM; @@ -84,20 +85,24 @@ static int __init exynos_chipid_early_init(void) of_property_read_string(root, "model", &soc_dev_attr->machine); of_node_put(root); - soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%x", revision); + soc_dev_attr->revision = devm_kasprintf(&pdev->dev, GFP_KERNEL, + "%x", revision); soc_dev_attr->soc_id = product_id_to_soc_id(product_id); if (!soc_dev_attr->soc_id) { pr_err("Unknown SoC\n"); - ret = -ENODEV; - goto err; + return -ENODEV; } /* please note that the actual registration will be deferred */ soc_dev = soc_device_register(soc_dev_attr); - if (IS_ERR(soc_dev)) { - ret = PTR_ERR(soc_dev); + if (IS_ERR(soc_dev)) + return PTR_ERR(soc_dev); + + ret = exynos_asv_init(&pdev->dev, regmap); + if (ret) goto err; - } + + platform_set_drvdata(pdev, soc_dev); dev_info(soc_device_to_device(soc_dev), "Exynos: CPU[%s] PRO_ID[0x%x] REV[0x%x] Detected\n", @@ -106,9 +111,31 @@ static int __init exynos_chipid_early_init(void) return 0; err: - kfree(soc_dev_attr->revision); - kfree(soc_dev_attr); + soc_device_unregister(soc_dev); + return ret; } -arch_initcall(exynos_chipid_early_init); +static int exynos_chipid_remove(struct platform_device *pdev) +{ + struct soc_device *soc_dev = platform_get_drvdata(pdev); + + soc_device_unregister(soc_dev); + + return 0; +} + +static const struct of_device_id exynos_chipid_of_device_ids[] = { + { .compatible = "samsung,exynos4210-chipid" }, + {} +}; + +static struct platform_driver exynos_chipid_driver = { + .driver = { + .name = "exynos-chipid", + .of_match_table = exynos_chipid_of_device_ids, + }, + .probe = exynos_chipid_probe, + .remove = exynos_chipid_remove, +}; +builtin_platform_driver(exynos_chipid_driver); -- cgit v1.2.3 From 6166174afc2bc74ca550af388508384b57d5163d Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 5 Jan 2021 18:44:40 +0100 Subject: soc: samsung: exynos-chipid: correct helpers __init annotation After converting to builtin driver, the probe function should not call __init functions anymore: >> WARNING: modpost: vmlinux.o(.text+0x8884d4): Section mismatch in reference from the function exynos_chipid_probe() to the function .init.text:product_id_to_soc_id() Reported-by: kernel test robot Fixes: 352bfbb3e023 ("soc: samsung: exynos-chipid: convert to driver and merge exynos-asv") Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20210105174440.120041-1-krzk@kernel.org --- drivers/soc/samsung/exynos-chipid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/soc') diff --git a/drivers/soc/samsung/exynos-chipid.c b/drivers/soc/samsung/exynos-chipid.c index fa6a9b9f6d70..5c1d0f97f766 100644 --- a/drivers/soc/samsung/exynos-chipid.c +++ b/drivers/soc/samsung/exynos-chipid.c @@ -44,7 +44,7 @@ static const struct exynos_soc_id { { "EXYNOS7420", 0xE7420000 }, }; -static const char * __init product_id_to_soc_id(unsigned int product_id) +static const char *product_id_to_soc_id(unsigned int product_id) { int i; -- cgit v1.2.3 From c09a3e6c97f00a525e23854d63f003aba9adfa41 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 13 Jan 2021 12:03:20 +0100 Subject: soc: samsung: pm_domains: Convert to regular platform driver When Exynos power domain driver was introduced, the only way to ensure that power domains will be instantiated before the devices which belongs to them was to initialize them early enough, before the devices are instantiated in the system. This in turn required not to use any platform device infrastructure at all, as there have been no way to ensure proper probe order between devices. This has been finally changed and upcomming patch "driver core: Set fw_devlink=on by default" ensures that each device will be probbed only when its resource providers are ready. This allows to convert Exynos power domain driver to regular platform driver. This is also required by the mentioned commit to enable probing any device which belongs to the Exynos power domains, as otherwise the core won't notice that the power domains are in fact available. Signed-off-by: Marek Szyprowski Link: https://lore.kernel.org/r/20210113110320.13149-1-m.szyprowski@samsung.com Signed-off-by: Krzysztof Kozlowski --- drivers/soc/samsung/pm_domains.c | 97 ++++++++++++++++++++-------------------- 1 file changed, 48 insertions(+), 49 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/samsung/pm_domains.c b/drivers/soc/samsung/pm_domains.c index ab8582971bfc..5ec0c13f0aaf 100644 --- a/drivers/soc/samsung/pm_domains.c +++ b/drivers/soc/samsung/pm_domains.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include struct exynos_pm_domain_config { /* Value for LOCAL_PWR_CFG and STATUS fields for each domain */ @@ -73,15 +73,15 @@ static int exynos_pd_power_off(struct generic_pm_domain *domain) return exynos_pd_power(domain, false); } -static const struct exynos_pm_domain_config exynos4210_cfg __initconst = { +static const struct exynos_pm_domain_config exynos4210_cfg = { .local_pwr_cfg = 0x7, }; -static const struct exynos_pm_domain_config exynos5433_cfg __initconst = { +static const struct exynos_pm_domain_config exynos5433_cfg = { .local_pwr_cfg = 0xf, }; -static const struct of_device_id exynos_pm_domain_of_match[] __initconst = { +static const struct of_device_id exynos_pm_domain_of_match[] = { { .compatible = "samsung,exynos4210-pd", .data = &exynos4210_cfg, @@ -92,7 +92,7 @@ static const struct of_device_id exynos_pm_domain_of_match[] __initconst = { { }, }; -static __init const char *exynos_get_domain_name(struct device_node *node) +static const char *exynos_get_domain_name(struct device_node *node) { const char *name; @@ -101,60 +101,44 @@ static __init const char *exynos_get_domain_name(struct device_node *node) return kstrdup_const(name, GFP_KERNEL); } -static __init int exynos4_pm_init_power_domain(void) +static int exynos_pd_probe(struct platform_device *pdev) { - struct device_node *np; - const struct of_device_id *match; - - for_each_matching_node_and_match(np, exynos_pm_domain_of_match, &match) { - const struct exynos_pm_domain_config *pm_domain_cfg; - struct exynos_pm_domain *pd; - int on; + const struct exynos_pm_domain_config *pm_domain_cfg; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct of_phandle_args child, parent; + struct exynos_pm_domain *pd; + int on, ret; - pm_domain_cfg = match->data; + pm_domain_cfg = of_device_get_match_data(dev); + pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); + if (!pd) + return -ENOMEM; - pd = kzalloc(sizeof(*pd), GFP_KERNEL); - if (!pd) { - of_node_put(np); - return -ENOMEM; - } - pd->pd.name = exynos_get_domain_name(np); - if (!pd->pd.name) { - kfree(pd); - of_node_put(np); - return -ENOMEM; - } + pd->pd.name = exynos_get_domain_name(np); + if (!pd->pd.name) + return -ENOMEM; - pd->base = of_iomap(np, 0); - if (!pd->base) { - pr_warn("%s: failed to map memory\n", __func__); - kfree_const(pd->pd.name); - kfree(pd); - continue; - } - - pd->pd.power_off = exynos_pd_power_off; - pd->pd.power_on = exynos_pd_power_on; - pd->local_pwr_cfg = pm_domain_cfg->local_pwr_cfg; + pd->base = of_iomap(np, 0); + if (!pd->base) { + kfree_const(pd->pd.name); + return -ENODEV; + } - on = readl_relaxed(pd->base + 0x4) & pd->local_pwr_cfg; + pd->pd.power_off = exynos_pd_power_off; + pd->pd.power_on = exynos_pd_power_on; + pd->local_pwr_cfg = pm_domain_cfg->local_pwr_cfg; - pm_genpd_init(&pd->pd, NULL, !on); - of_genpd_add_provider_simple(np, &pd->pd); - } + on = readl_relaxed(pd->base + 0x4) & pd->local_pwr_cfg; - /* Assign the child power domains to their parents */ - for_each_matching_node(np, exynos_pm_domain_of_match) { - struct of_phandle_args child, parent; + pm_genpd_init(&pd->pd, NULL, !on); + ret = of_genpd_add_provider_simple(np, &pd->pd); + if (ret == 0 && of_parse_phandle_with_args(np, "power-domains", + "#power-domain-cells", 0, &parent) == 0) { child.np = np; child.args_count = 0; - if (of_parse_phandle_with_args(np, "power-domains", - "#power-domain-cells", 0, - &parent) != 0) - continue; - if (of_genpd_add_subdomain(&parent, &child)) pr_warn("%pOF failed to add subdomain: %pOF\n", parent.np, child.np); @@ -163,6 +147,21 @@ static __init int exynos4_pm_init_power_domain(void) parent.np, child.np); } - return 0; + pm_runtime_enable(dev); + return ret; +} + +static struct platform_driver exynos_pd_driver = { + .probe = exynos_pd_probe, + .driver = { + .name = "exynos-pd", + .of_match_table = exynos_pm_domain_of_match, + .suppress_bind_attrs = true, + } +}; + +static __init int exynos4_pm_init_power_domain(void) +{ + return platform_driver_register(&exynos_pd_driver); } core_initcall(exynos4_pm_init_power_domain); -- cgit v1.2.3 From 56d6fb12e64be09924a7140c43279583d49c4625 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 25 Jan 2021 15:26:06 +0100 Subject: soc: renesas: rcar-sysc: Use readl_poll_timeout_atomic() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the open-coded polling loops by calls to the readl_poll_timeout_atomic() helper macro. Signed-off-by: Geert Uytterhoeven Reviewed-by: Niklas Söderlund Link: https://lore.kernel.org/r/20210125142606.1050130-1-geert+renesas@glider.be --- drivers/soc/renesas/rcar-sysc.c | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/renesas/rcar-sysc.c b/drivers/soc/renesas/rcar-sysc.c index 9b235fc90027..d51ddc7d5232 100644 --- a/drivers/soc/renesas/rcar-sysc.c +++ b/drivers/soc/renesas/rcar-sysc.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include "rcar-sysc.h" @@ -44,13 +45,13 @@ #define PWRER_OFFS 0x14 /* Power Shutoff/Resume Error */ -#define SYSCSR_RETRIES 100 +#define SYSCSR_TIMEOUT 100 #define SYSCSR_DELAY_US 1 #define PWRER_RETRIES 100 #define PWRER_DELAY_US 1 -#define SYSCISR_RETRIES 1000 +#define SYSCISR_TIMEOUT 1000 #define SYSCISR_DELAY_US 1 #define RCAR_PD_ALWAYS_ON 32 /* Always-on power area */ @@ -68,7 +69,8 @@ static u32 rcar_sysc_extmask_offs, rcar_sysc_extmask_val; static int rcar_sysc_pwr_on_off(const struct rcar_sysc_ch *sysc_ch, bool on) { unsigned int sr_bit, reg_offs; - int k; + u32 val; + int ret; if (on) { sr_bit = SYSCSR_PONENB; @@ -79,13 +81,10 @@ static int rcar_sysc_pwr_on_off(const struct rcar_sysc_ch *sysc_ch, bool on) } /* Wait until SYSC is ready to accept a power request */ - for (k = 0; k < SYSCSR_RETRIES; k++) { - if (ioread32(rcar_sysc_base + SYSCSR) & BIT(sr_bit)) - break; - udelay(SYSCSR_DELAY_US); - } - - if (k == SYSCSR_RETRIES) + ret = readl_poll_timeout_atomic(rcar_sysc_base + SYSCSR, val, + val & BIT(sr_bit), SYSCSR_DELAY_US, + SYSCSR_TIMEOUT); + if (ret) return -EAGAIN; /* Submit power shutoff or power resume request */ @@ -99,10 +98,9 @@ static int rcar_sysc_power(const struct rcar_sysc_ch *sysc_ch, bool on) { unsigned int isr_mask = BIT(sysc_ch->isr_bit); unsigned int chan_mask = BIT(sysc_ch->chan_bit); - unsigned int status; + unsigned int status, k; unsigned long flags; - int ret = 0; - int k; + int ret; spin_lock_irqsave(&rcar_sysc_lock, flags); @@ -145,13 +143,10 @@ static int rcar_sysc_power(const struct rcar_sysc_ch *sysc_ch, bool on) } /* Wait until the power shutoff or resume request has completed * */ - for (k = 0; k < SYSCISR_RETRIES; k++) { - if (ioread32(rcar_sysc_base + SYSCISR) & isr_mask) - break; - udelay(SYSCISR_DELAY_US); - } - - if (k == SYSCISR_RETRIES) + ret = readl_poll_timeout_atomic(rcar_sysc_base + SYSCISR, status, + status & isr_mask, SYSCISR_DELAY_US, + SYSCISR_TIMEOUT); + if (ret) ret = -EIO; iowrite32(isr_mask, rcar_sysc_base + SYSCISCR); -- cgit v1.2.3 From 2dfc564bda4a31bc4439315448bd4da5182cb397 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 28 Jan 2021 09:28:47 +0100 Subject: soc: renesas: rcar-sysc: Mark device node OF_POPULATED after init The R-Car System Controller (SYSC) driver registers PM domains from an early_initcall(). It does not use a platform driver, as secondary CPU startup on R-Car H1 needs to control the CPU power domains, before initialization of the driver framework. As fw_devlink only considers devices, it does not know that the System Controller is ready. Hence probing of on-chip devices that are part of the SYSC PM domain fails if fw_devlink is enabled: probe deferral - supplier e6180000.system-controller not ready Fix this by setting the OF_POPULATED flag for the SYSC device node after successful initialization. This will make of_link_to_phandle() ignore the SYSC device node as a dependency, and consumer devices will be probed again. Signed-off-by: Geert Uytterhoeven Reviewed-by: Saravana Kannan Link: https://lore.kernel.org/r/20210128082847.2205950-1-geert+renesas@glider.be --- drivers/soc/renesas/rcar-sysc.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/soc') diff --git a/drivers/soc/renesas/rcar-sysc.c b/drivers/soc/renesas/rcar-sysc.c index d51ddc7d5232..53387a72ca00 100644 --- a/drivers/soc/renesas/rcar-sysc.c +++ b/drivers/soc/renesas/rcar-sysc.c @@ -434,6 +434,8 @@ static int __init rcar_sysc_pd_init(void) } error = of_genpd_add_provider_onecell(np, &domains->onecell_data); + if (!error) + of_node_set_flag(np, OF_POPULATED); out_put: of_node_put(np); -- cgit v1.2.3