mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-09 02:00:43 -04:00
Merge tag 'samsung-drivers-5.12' of git://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux into arm/soc
Samsung SoC drivers changes for v5.12 1. Adjust deferred probe and handle regmap_read() errors in Exynos ASV driver. 2. Convert the ChipID code into a driver (from a early initcall) and merge it into the Exynos ASV. 3. Convert the PM domains code into a driver. This is necessary for upcoming code enabling fw_devlinks. * tag 'samsung-drivers-5.12' of git://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux: soc: samsung: pm_domains: Convert to regular platform driver soc: samsung: exynos-chipid: correct helpers __init annotation soc: samsung: exynos-chipid: convert to driver and merge exynos-asv soc: samsung: exynos-asv: handle reading revision register error soc: samsung: exynos-asv: don't defer early on not-supported SoCs Link: https://lore.kernel.org/r/20210125191240.11278-2-krzk@kernel.org Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com/
|
||||
* Copyright (c) 2020 Krzysztof Kozlowski <krzk@kernel.org>
|
||||
* Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
|
||||
* Author: Krzysztof Kozlowski <krzk@kernel.org>
|
||||
*
|
||||
* Samsung Exynos SoC Adaptive Supply Voltage support
|
||||
*/
|
||||
@@ -10,12 +12,7 @@
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_opp.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/soc/samsung/exynos-chipid.h>
|
||||
@@ -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,39 +116,39 @@ 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);
|
||||
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(dev, "Cannot read revision from ChipID: %d\n", ret);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
regmap_read(asv->chipid_regmap, EXYNOS_CHIPID_REG_PRO_ID, &product_id);
|
||||
|
||||
switch (product_id & EXYNOS_MASK) {
|
||||
case 0xE5422000:
|
||||
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;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(pdev->dev.of_node, "samsung,asv-bin",
|
||||
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(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;
|
||||
|
||||
@@ -161,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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -2,20 +2,28 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com/
|
||||
* Copyright (c) 2020 Krzysztof Kozlowski <krzk@kernel.org>
|
||||
*
|
||||
* Exynos - CHIP ID support
|
||||
* Author: Pankaj Dubey <pankaj.dubey@samsung.com>
|
||||
* Author: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
|
||||
* Author: Krzysztof Kozlowski <krzk@kernel.org>
|
||||
*
|
||||
* Samsung Exynos SoC Adaptive Supply Voltage and Chip ID support
|
||||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/soc/samsung/exynos-chipid.h>
|
||||
#include <linux/sys_soc.h>
|
||||
|
||||
#include "exynos-asv.h"
|
||||
|
||||
static const struct exynos_soc_id {
|
||||
const char *name;
|
||||
unsigned int id;
|
||||
@@ -36,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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
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;
|
||||
pm_domain_cfg = of_device_get_match_data(dev);
|
||||
pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
|
||||
if (!pd)
|
||||
return -ENOMEM;
|
||||
|
||||
pm_domain_cfg = match->data;
|
||||
pd->pd.name = exynos_get_domain_name(np);
|
||||
if (!pd->pd.name)
|
||||
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->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;
|
||||
|
||||
on = readl_relaxed(pd->base + 0x4) & pd->local_pwr_cfg;
|
||||
|
||||
pm_genpd_init(&pd->pd, NULL, !on);
|
||||
of_genpd_add_provider_simple(np, &pd->pd);
|
||||
pd->base = of_iomap(np, 0);
|
||||
if (!pd->base) {
|
||||
kfree_const(pd->pd.name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Assign the child power domains to their parents */
|
||||
for_each_matching_node(np, exynos_pm_domain_of_match) {
|
||||
struct of_phandle_args child, parent;
|
||||
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;
|
||||
|
||||
on = readl_relaxed(pd->base + 0x4) & pd->local_pwr_cfg;
|
||||
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user