Skip to content

Commit 777cf27

Browse files
committed
Merge tag 'tegra-for-5.14-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux into arm/soc
soc/tegra: Changes for v5.14-rc1 These changes implement the core power domain for the PMC, and fix a couple of minor issues as well as add stubs to help some drivers be compile tested more easily. * tag 'tegra-for-5.14-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux: soc/tegra: fuse: Fix Tegra234-only builds soc/tegra: fuse: Don't return -ENOMEM when allocate lookups failed soc/tegra: regulators: Support core domain state syncing soc/tegra: pmc: Add driver state syncing soc/tegra: pmc: Add core power domain soc/tegra: fuse: Add stubs needed for compile-testing soc/tegra: Add devm_tegra_core_dev_init_opp_table() soc/tegra: Add stub for soc_is_tegra() soc/tegra: regulators: Bump voltages on system reboot regulator: core: Add regulator_sync_voltage_rdev() Link: https://lore.kernel.org/r/20210611164437.3568059-2-thierry.reding@gmail.com Signed-off-by: Olof Johansson <olof@lixom.net>
2 parents 805be5c + e2d0ee2 commit 777cf27

12 files changed

Lines changed: 509 additions & 12 deletions

File tree

drivers/regulator/core.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4105,6 +4105,29 @@ int regulator_set_voltage_time_sel(struct regulator_dev *rdev,
41054105
}
41064106
EXPORT_SYMBOL_GPL(regulator_set_voltage_time_sel);
41074107

4108+
int regulator_sync_voltage_rdev(struct regulator_dev *rdev)
4109+
{
4110+
int ret;
4111+
4112+
regulator_lock(rdev);
4113+
4114+
if (!rdev->desc->ops->set_voltage &&
4115+
!rdev->desc->ops->set_voltage_sel) {
4116+
ret = -EINVAL;
4117+
goto out;
4118+
}
4119+
4120+
/* balance only, if regulator is coupled */
4121+
if (rdev->coupling_desc.n_coupled > 1)
4122+
ret = regulator_balance_voltage(rdev, PM_SUSPEND_ON);
4123+
else
4124+
ret = -EOPNOTSUPP;
4125+
4126+
out:
4127+
regulator_unlock(rdev);
4128+
return ret;
4129+
}
4130+
41084131
/**
41094132
* regulator_sync_voltage - re-apply last regulator output voltage
41104133
* @regulator: regulator source

drivers/soc/tegra/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,8 @@ config SOC_TEGRA_FLOWCTRL
144144
config SOC_TEGRA_PMC
145145
bool
146146
select GENERIC_PINCONF
147+
select PM_OPP
148+
select PM_GENERIC_DOMAINS
147149

148150
config SOC_TEGRA_POWERGATE_BPMP
149151
def_bool y

drivers/soc/tegra/common.c

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,16 @@
33
* Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved.
44
*/
55

6+
#define dev_fmt(fmt) "tegra-soc: " fmt
7+
8+
#include <linux/clk.h>
9+
#include <linux/device.h>
10+
#include <linux/export.h>
611
#include <linux/of.h>
12+
#include <linux/pm_opp.h>
713

814
#include <soc/tegra/common.h>
15+
#include <soc/tegra/fuse.h>
916

1017
static const struct of_device_id tegra_machine_match[] = {
1118
{ .compatible = "nvidia,tegra20", },
@@ -31,3 +38,93 @@ bool soc_is_tegra(void)
3138

3239
return match != NULL;
3340
}
41+
42+
static int tegra_core_dev_init_opp_state(struct device *dev)
43+
{
44+
unsigned long rate;
45+
struct clk *clk;
46+
int err;
47+
48+
clk = devm_clk_get(dev, NULL);
49+
if (IS_ERR(clk)) {
50+
dev_err(dev, "failed to get clk: %pe\n", clk);
51+
return PTR_ERR(clk);
52+
}
53+
54+
rate = clk_get_rate(clk);
55+
if (!rate) {
56+
dev_err(dev, "failed to get clk rate\n");
57+
return -EINVAL;
58+
}
59+
60+
/* first dummy rate-setting initializes voltage vote */
61+
err = dev_pm_opp_set_rate(dev, rate);
62+
if (err) {
63+
dev_err(dev, "failed to initialize OPP clock: %d\n", err);
64+
return err;
65+
}
66+
67+
return 0;
68+
}
69+
70+
/**
71+
* devm_tegra_core_dev_init_opp_table() - initialize OPP table
72+
* @dev: device for which OPP table is initialized
73+
* @params: pointer to the OPP table configuration
74+
*
75+
* This function will initialize OPP table and sync OPP state of a Tegra SoC
76+
* core device.
77+
*
78+
* Return: 0 on success or errorno.
79+
*/
80+
int devm_tegra_core_dev_init_opp_table(struct device *dev,
81+
struct tegra_core_opp_params *params)
82+
{
83+
u32 hw_version;
84+
int err;
85+
86+
err = devm_pm_opp_set_clkname(dev, NULL);
87+
if (err) {
88+
dev_err(dev, "failed to set OPP clk: %d\n", err);
89+
return err;
90+
}
91+
92+
/* Tegra114+ doesn't support OPP yet */
93+
if (!of_machine_is_compatible("nvidia,tegra20") &&
94+
!of_machine_is_compatible("nvidia,tegra30"))
95+
return -ENODEV;
96+
97+
if (of_machine_is_compatible("nvidia,tegra20"))
98+
hw_version = BIT(tegra_sku_info.soc_process_id);
99+
else
100+
hw_version = BIT(tegra_sku_info.soc_speedo_id);
101+
102+
err = devm_pm_opp_set_supported_hw(dev, &hw_version, 1);
103+
if (err) {
104+
dev_err(dev, "failed to set OPP supported HW: %d\n", err);
105+
return err;
106+
}
107+
108+
/*
109+
* Older device-trees have an empty OPP table, we will get
110+
* -ENODEV from devm_pm_opp_of_add_table() in this case.
111+
*/
112+
err = devm_pm_opp_of_add_table(dev);
113+
if (err) {
114+
if (err == -ENODEV)
115+
dev_err_once(dev, "OPP table not found, please update device-tree\n");
116+
else
117+
dev_err(dev, "failed to add OPP table: %d\n", err);
118+
119+
return err;
120+
}
121+
122+
if (params->init_state) {
123+
err = tegra_core_dev_init_opp_state(dev);
124+
if (err)
125+
return err;
126+
}
127+
128+
return 0;
129+
}
130+
EXPORT_SYMBOL_GPL(devm_tegra_core_dev_init_opp_table);

drivers/soc/tegra/fuse/fuse-tegra.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -489,10 +489,8 @@ static int __init tegra_init_fuse(void)
489489
size_t size = sizeof(*fuse->lookups) * fuse->soc->num_lookups;
490490

491491
fuse->lookups = kmemdup(fuse->soc->lookups, size, GFP_KERNEL);
492-
if (!fuse->lookups)
493-
return -ENOMEM;
494-
495-
nvmem_add_cell_lookups(fuse->lookups, fuse->soc->num_lookups);
492+
if (fuse->lookups)
493+
nvmem_add_cell_lookups(fuse->lookups, fuse->soc->num_lookups);
496494
}
497495

498496
return 0;

drivers/soc/tegra/fuse/fuse-tegra30.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@
3737
defined(CONFIG_ARCH_TEGRA_132_SOC) || \
3838
defined(CONFIG_ARCH_TEGRA_210_SOC) || \
3939
defined(CONFIG_ARCH_TEGRA_186_SOC) || \
40-
defined(CONFIG_ARCH_TEGRA_194_SOC)
40+
defined(CONFIG_ARCH_TEGRA_194_SOC) || \
41+
defined(CONFIG_ARCH_TEGRA_234_SOC)
4142
static u32 tegra30_fuse_read_early(struct tegra_fuse *fuse, unsigned int offset)
4243
{
4344
if (WARN_ON(!fuse->base))

drivers/soc/tegra/pmc.c

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include <linux/pinctrl/pinctrl.h>
3939
#include <linux/platform_device.h>
4040
#include <linux/pm_domain.h>
41+
#include <linux/pm_opp.h>
4142
#include <linux/reboot.h>
4243
#include <linux/regmap.h>
4344
#include <linux/reset.h>
@@ -428,6 +429,9 @@ struct tegra_pmc {
428429
struct irq_chip irq;
429430

430431
struct notifier_block clk_nb;
432+
433+
bool core_domain_state_synced;
434+
bool core_domain_registered;
431435
};
432436

433437
static struct tegra_pmc *pmc = &(struct tegra_pmc) {
@@ -1302,12 +1306,107 @@ static int tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
13021306
return err;
13031307
}
13041308

1309+
bool tegra_pmc_core_domain_state_synced(void)
1310+
{
1311+
return pmc->core_domain_state_synced;
1312+
}
1313+
1314+
static int
1315+
tegra_pmc_core_pd_set_performance_state(struct generic_pm_domain *genpd,
1316+
unsigned int level)
1317+
{
1318+
struct dev_pm_opp *opp;
1319+
int err;
1320+
1321+
opp = dev_pm_opp_find_level_ceil(&genpd->dev, &level);
1322+
if (IS_ERR(opp)) {
1323+
dev_err(&genpd->dev, "failed to find OPP for level %u: %pe\n",
1324+
level, opp);
1325+
return PTR_ERR(opp);
1326+
}
1327+
1328+
mutex_lock(&pmc->powergates_lock);
1329+
err = dev_pm_opp_set_opp(pmc->dev, opp);
1330+
mutex_unlock(&pmc->powergates_lock);
1331+
1332+
dev_pm_opp_put(opp);
1333+
1334+
if (err) {
1335+
dev_err(&genpd->dev, "failed to set voltage to %duV: %d\n",
1336+
level, err);
1337+
return err;
1338+
}
1339+
1340+
return 0;
1341+
}
1342+
1343+
static unsigned int
1344+
tegra_pmc_core_pd_opp_to_performance_state(struct generic_pm_domain *genpd,
1345+
struct dev_pm_opp *opp)
1346+
{
1347+
return dev_pm_opp_get_level(opp);
1348+
}
1349+
1350+
static int tegra_pmc_core_pd_add(struct tegra_pmc *pmc, struct device_node *np)
1351+
{
1352+
struct generic_pm_domain *genpd;
1353+
const char *rname = "core";
1354+
int err;
1355+
1356+
genpd = devm_kzalloc(pmc->dev, sizeof(*genpd), GFP_KERNEL);
1357+
if (!genpd)
1358+
return -ENOMEM;
1359+
1360+
genpd->name = np->name;
1361+
genpd->set_performance_state = tegra_pmc_core_pd_set_performance_state;
1362+
genpd->opp_to_performance_state = tegra_pmc_core_pd_opp_to_performance_state;
1363+
1364+
err = devm_pm_opp_set_regulators(pmc->dev, &rname, 1);
1365+
if (err)
1366+
return dev_err_probe(pmc->dev, err,
1367+
"failed to set core OPP regulator\n");
1368+
1369+
err = pm_genpd_init(genpd, NULL, false);
1370+
if (err) {
1371+
dev_err(pmc->dev, "failed to init core genpd: %d\n", err);
1372+
return err;
1373+
}
1374+
1375+
err = of_genpd_add_provider_simple(np, genpd);
1376+
if (err) {
1377+
dev_err(pmc->dev, "failed to add core genpd: %d\n", err);
1378+
goto remove_genpd;
1379+
}
1380+
1381+
pmc->core_domain_registered = true;
1382+
1383+
return 0;
1384+
1385+
remove_genpd:
1386+
pm_genpd_remove(genpd);
1387+
1388+
return err;
1389+
}
1390+
13051391
static int tegra_powergate_init(struct tegra_pmc *pmc,
13061392
struct device_node *parent)
13071393
{
1394+
struct of_phandle_args child_args, parent_args;
13081395
struct device_node *np, *child;
13091396
int err = 0;
13101397

1398+
/*
1399+
* Core power domain is the parent of powergate domains, hence it
1400+
* should be registered first.
1401+
*/
1402+
np = of_get_child_by_name(parent, "core-domain");
1403+
if (np) {
1404+
err = tegra_pmc_core_pd_add(pmc, np);
1405+
of_node_put(np);
1406+
if (err)
1407+
return err;
1408+
}
1409+
13111410
np = of_get_child_by_name(parent, "powergates");
13121411
if (!np)
13131412
return 0;
@@ -1318,6 +1417,21 @@ static int tegra_powergate_init(struct tegra_pmc *pmc,
13181417
of_node_put(child);
13191418
break;
13201419
}
1420+
1421+
if (of_parse_phandle_with_args(child, "power-domains",
1422+
"#power-domain-cells",
1423+
0, &parent_args))
1424+
continue;
1425+
1426+
child_args.np = child;
1427+
child_args.args_count = 0;
1428+
1429+
err = of_genpd_add_subdomain(&parent_args, &child_args);
1430+
of_node_put(parent_args.np);
1431+
if (err) {
1432+
of_node_put(child);
1433+
break;
1434+
}
13211435
}
13221436

13231437
of_node_put(np);
@@ -1361,6 +1475,12 @@ static void tegra_powergate_remove_all(struct device_node *parent)
13611475
}
13621476

13631477
of_node_put(np);
1478+
1479+
np = of_get_child_by_name(parent, "core-domain");
1480+
if (np) {
1481+
of_genpd_del_provider(np);
1482+
of_genpd_remove_last(np);
1483+
}
13641484
}
13651485

13661486
static const struct tegra_io_pad_soc *
@@ -3672,6 +3792,29 @@ static const struct of_device_id tegra_pmc_match[] = {
36723792
{ }
36733793
};
36743794

3795+
static void tegra_pmc_sync_state(struct device *dev)
3796+
{
3797+
int err;
3798+
3799+
/*
3800+
* Older device-trees don't have core PD, and thus, there are
3801+
* no dependencies that will block the state syncing. We shouldn't
3802+
* mark the domain as synced in this case.
3803+
*/
3804+
if (!pmc->core_domain_registered)
3805+
return;
3806+
3807+
pmc->core_domain_state_synced = true;
3808+
3809+
/* this is a no-op if core regulator isn't used */
3810+
mutex_lock(&pmc->powergates_lock);
3811+
err = dev_pm_opp_sync_regulators(dev);
3812+
mutex_unlock(&pmc->powergates_lock);
3813+
3814+
if (err)
3815+
dev_err(dev, "failed to sync regulators: %d\n", err);
3816+
}
3817+
36753818
static struct platform_driver tegra_pmc_driver = {
36763819
.driver = {
36773820
.name = "tegra-pmc",
@@ -3680,6 +3823,7 @@ static struct platform_driver tegra_pmc_driver = {
36803823
#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM)
36813824
.pm = &tegra_pmc_pm_ops,
36823825
#endif
3826+
.sync_state = tegra_pmc_sync_state,
36833827
},
36843828
.probe = tegra_pmc_probe,
36853829
};

0 commit comments

Comments
 (0)