pmdomain core:

- Set the required dev for a required OPP during genpd attach
  - Add support for required OPPs to dev_pm_domain_attach_list()
 
 pmdomain providers:
  - ti: Enable GENPD_FLAG_ACTIVE_WAKEUP flag for ti_sci PM domains
  - mediatek: Add support for MT6735 PM domains
  - mediatek: Use OF-specific regulator API to get power domain supply
  - qcom: Add support for the SM8750/SAR2130P/qcs615/qcs8300 rpmhpds
 
 pmdomain consumers:
  - Convert a couple of consumer drivers to *_pm_domain_attach|detach_list()
 
 opp core:
  - Rework and cleanup some code that manages required OPPs
  - Remove *_opp_attach|detach_genpd()
 -----BEGIN PGP SIGNATURE-----
 
 iQJLBAABCgA1FiEEugLDXPmKSktSkQsV/iaEJXNYjCkFAmc7Y+QXHHVsZi5oYW5z
 c29uQGxpbmFyby5vcmcACgkQ/iaEJXNYjCmbrw/9FVdo3+mo6EZne+Zsxc0+3N9G
 bRwkgyCB8WSFy6MHD1TRyP9u8bFgFDitSxcUGuBW0l9t1le3IcsYwfbTEEZpUkU4
 iasPoZoFKA3Akfr7tvQpIpSNh8MIBMFy7CfxWpsfiHlmwrIH6oT6HmlwWwFsbVxh
 Fv8xA5SOE1KRHq0Aos23h7MizPsav/PYSh/4Ga5l6ZBlm40c16cE0i0M4RRUnoNY
 FmUBe57HoumDd05ToFR9wrqMEVWbAJHV4xZpZwnfYUhwGrgbxUWI/1FIfwxtob12
 OExPr9kiV8/f8Kfp3E3ul0R8q8XYaYZaT3R7nF5QOngLZCCpD5H9aWEcAihUryBh
 Ol9Wao0Ku1JqLc776bjwf92ozFDtx0yUN/8LXmQgUu+e+MC3eAOrsls+U4731p+Y
 V80mvBpqn8AbX7LOjJvmbOhK6Qnm0cHo2cs0afBSS5c9RBcCWuEy9d7n8dks6JX2
 7H6ySDaKoEEK06V6VzEKdHQoRFkmw95w4n7Ei3OL0cxNLcT1ILGA1+O7PPw+6h4T
 3UnSik6szZCBXFFaDsw4J53HZACVZWbkyrk5Dbsigte8lh6e2VI+qd9whd46nuCY
 Sn4vJ399FJvXBuEIu+8yymGwn/NSpgd6ybpkwdDNJ+fItbes7DQhtxM6k74ANAhf
 0irf1o4Yv0S5W+pXBAM=
 =SpyF
 -----END PGP SIGNATURE-----

Merge tag 'pmdomain-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/linux-pm

Pull pmdomain updates from Ulf Hansson:
"pmdomain core:
   - Set the required dev for a required OPP during genpd attach
   - Add support for required OPPs to dev_pm_domain_attach_list()

  pmdomain providers:
   - ti: Enable GENPD_FLAG_ACTIVE_WAKEUP flag for ti_sci PM domains
   - mediatek: Add support for MT6735 PM domains
   - mediatek: Use OF-specific regulator API to get power domain supply
   - qcom: Add support for the SM8750/SAR2130P/qcs615/qcs8300 rpmhpds

  pmdomain consumers:
   - Convert a couple of consumer drivers to
     *_pm_domain_attach|detach_list()

  opp core:
   - Rework and cleanup some code that manages required OPPs
   - Remove *_opp_attach|detach_genpd()"

* tag 'pmdomain-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/linux-pm: (25 commits)
  pmdomain: qcom: rpmhpd: Add rpmhpd support for SM8750
  dt-bindings: power: qcom,rpmpd: document the SM8750 RPMh Power Domains
  pmdomain: imx: Use of_property_present() for non-boolean properties
  pmdomain: imx: gpcv2: replace dev_err() with dev_err_probe()
  pmdomain: ti-sci: Use scope based of_node_put() to simplify code.
  pmdomain: ti-sci: Add missing of_node_put() for args.np
  pmdomain: ti-sci: set the GENPD_FLAG_ACTIVE_WAKEUP flag for all PM domains
  pmdomain: mediatek: Add support for MT6735
  pmdomain: qcom: rpmhpd: add support for SAR2130P
  dt-bindings: power: Add binding for MediaTek MT6735 power controller
  dt-bindings: power: rpmpd: Add SAR2130P compatible
  OPP: Drop redundant *_opp_attach|detach_genpd()
  cpufreq: qcom-nvmem: Convert to dev_pm_domain_attach|detach_list()
  media: venus: Convert into devm_pm_domain_attach_list() for OPP PM domain
  drm/tegra: gr3d: Convert into devm_pm_domain_attach_list()
  OPP: Drop redundant code in _link_required_opps()
  pmdomain: core: Set the required dev for a required OPP during genpd attach
  pmdomain: core: Manage the default required OPP from a separate function
  PM: domains: Support required OPPs in dev_pm_domain_attach_list()
  OPP: Rework _set_required_devs() to manage a single device per call
  ...
This commit is contained in:
Linus Torvalds 2024-11-20 12:44:59 -08:00
commit 75f2b37dd0
25 changed files with 435 additions and 399 deletions

View File

@ -23,6 +23,7 @@ properties:
compatible:
enum:
- mediatek,mt6735-power-controller
- mediatek,mt6795-power-controller
- mediatek,mt8167-power-controller
- mediatek,mt8173-power-controller

View File

@ -32,11 +32,14 @@ properties:
- qcom,msm8998-rpmpd
- qcom,qcm2290-rpmpd
- qcom,qcs404-rpmpd
- qcom,qcs615-rpmhpd
- qcom,qcs8300-rpmhpd
- qcom,qdu1000-rpmhpd
- qcom,qm215-rpmpd
- qcom,sa8155p-rpmhpd
- qcom,sa8540p-rpmhpd
- qcom,sa8775p-rpmhpd
- qcom,sar2130p-rpmhpd
- qcom,sc7180-rpmhpd
- qcom,sc7280-rpmhpd
- qcom,sc8180x-rpmhpd
@ -58,6 +61,7 @@ properties:
- qcom,sm8450-rpmhpd
- qcom,sm8550-rpmhpd
- qcom,sm8650-rpmhpd
- qcom,sm8750-rpmhpd
- qcom,x1e80100-rpmhpd
- items:
- enum:

View File

@ -20,6 +20,7 @@ Required properties:
- compatible: Should be one of:
- "mediatek,mt2701-scpsys"
- "mediatek,mt2712-scpsys"
- "mediatek,mt6735-scpsys"
- "mediatek,mt6765-scpsys"
- "mediatek,mt6797-scpsys"
- "mediatek,mt7622-scpsys"

View File

@ -11,6 +11,7 @@
#include <linux/pm_clock.h>
#include <linux/acpi.h>
#include <linux/pm_domain.h>
#include <linux/pm_opp.h>
#include "power.h"
@ -222,13 +223,15 @@ int dev_pm_domain_attach_list(struct device *dev,
if (!pds)
return -ENOMEM;
size = sizeof(*pds->pd_devs) + sizeof(*pds->pd_links);
size = sizeof(*pds->pd_devs) + sizeof(*pds->pd_links) +
sizeof(*pds->opp_tokens);
pds->pd_devs = kcalloc(num_pds, size, GFP_KERNEL);
if (!pds->pd_devs) {
ret = -ENOMEM;
goto free_pds;
}
pds->pd_links = (void *)(pds->pd_devs + num_pds);
pds->opp_tokens = (void *)(pds->pd_links + num_pds);
if (link_flags && pd_flags & PD_FLAG_DEV_LINK_ON)
link_flags |= DL_FLAG_RPM_ACTIVE;
@ -244,6 +247,19 @@ int dev_pm_domain_attach_list(struct device *dev,
goto err_attach;
}
if (pd_flags & PD_FLAG_REQUIRED_OPP) {
struct dev_pm_opp_config config = {
.required_dev = pd_dev,
.required_dev_index = i,
};
ret = dev_pm_opp_set_config(dev, &config);
if (ret < 0)
goto err_link;
pds->opp_tokens[i] = ret;
}
if (link_flags) {
struct device_link *link;
@ -264,9 +280,11 @@ int dev_pm_domain_attach_list(struct device *dev,
return num_pds;
err_link:
dev_pm_opp_clear_config(pds->opp_tokens[i]);
dev_pm_domain_detach(pd_dev, true);
err_attach:
while (--i >= 0) {
dev_pm_opp_clear_config(pds->opp_tokens[i]);
if (pds->pd_links[i])
device_link_del(pds->pd_links[i]);
dev_pm_domain_detach(pds->pd_devs[i], true);
@ -361,6 +379,7 @@ void dev_pm_domain_detach_list(struct dev_pm_domain_list *list)
return;
for (i = 0; i < list->num_pds; i++) {
dev_pm_opp_clear_config(list->opp_tokens[i]);
if (list->pd_links[i])
device_link_del(list->pd_links[i]);
dev_pm_domain_detach(list->pd_devs[i], true);

View File

@ -52,12 +52,13 @@ struct qcom_cpufreq_match_data {
struct nvmem_cell *speedbin_nvmem,
char **pvs_name,
struct qcom_cpufreq_drv *drv);
const char **genpd_names;
const char **pd_names;
unsigned int num_pd_names;
};
struct qcom_cpufreq_drv_cpu {
int opp_token;
struct device **virt_devs;
struct dev_pm_domain_list *pd_list;
};
struct qcom_cpufreq_drv {
@ -395,8 +396,6 @@ static int qcom_cpufreq_ipq8074_name_version(struct device *cpu_dev,
return 0;
}
static const char *generic_genpd_names[] = { "perf", NULL };
static const struct qcom_cpufreq_match_data match_data_kryo = {
.get_version = qcom_cpufreq_kryo_name_version,
};
@ -407,13 +406,13 @@ static const struct qcom_cpufreq_match_data match_data_krait = {
static const struct qcom_cpufreq_match_data match_data_msm8909 = {
.get_version = qcom_cpufreq_simple_get_version,
.genpd_names = generic_genpd_names,
.pd_names = (const char *[]) { "perf" },
.num_pd_names = 1,
};
static const char *qcs404_genpd_names[] = { "cpr", NULL };
static const struct qcom_cpufreq_match_data match_data_qcs404 = {
.genpd_names = qcs404_genpd_names,
.pd_names = (const char *[]) { "cpr" },
.num_pd_names = 1,
};
static const struct qcom_cpufreq_match_data match_data_ipq6018 = {
@ -428,28 +427,16 @@ static const struct qcom_cpufreq_match_data match_data_ipq8074 = {
.get_version = qcom_cpufreq_ipq8074_name_version,
};
static void qcom_cpufreq_suspend_virt_devs(struct qcom_cpufreq_drv *drv, unsigned int cpu)
static void qcom_cpufreq_suspend_pd_devs(struct qcom_cpufreq_drv *drv, unsigned int cpu)
{
const char * const *name = drv->data->genpd_names;
struct dev_pm_domain_list *pd_list = drv->cpus[cpu].pd_list;
int i;
if (!drv->cpus[cpu].virt_devs)
if (!pd_list)
return;
for (i = 0; *name; i++, name++)
device_set_awake_path(drv->cpus[cpu].virt_devs[i]);
}
static void qcom_cpufreq_put_virt_devs(struct qcom_cpufreq_drv *drv, unsigned int cpu)
{
const char * const *name = drv->data->genpd_names;
int i;
if (!drv->cpus[cpu].virt_devs)
return;
for (i = 0; *name; i++, name++)
pm_runtime_put(drv->cpus[cpu].virt_devs[i]);
for (i = 0; i < pd_list->num_pds; i++)
device_set_awake_path(pd_list->pd_devs[i]);
}
static int qcom_cpufreq_probe(struct platform_device *pdev)
@ -503,7 +490,6 @@ static int qcom_cpufreq_probe(struct platform_device *pdev)
}
for_each_possible_cpu(cpu) {
struct device **virt_devs = NULL;
struct dev_pm_opp_config config = {
.supported_hw = NULL,
};
@ -522,12 +508,7 @@ static int qcom_cpufreq_probe(struct platform_device *pdev)
config.prop_name = pvs_name;
}
if (drv->data->genpd_names) {
config.genpd_names = drv->data->genpd_names;
config.virt_devs = &virt_devs;
}
if (config.supported_hw || config.genpd_names) {
if (config.supported_hw) {
drv->cpus[cpu].opp_token = dev_pm_opp_set_config(cpu_dev, &config);
if (drv->cpus[cpu].opp_token < 0) {
ret = drv->cpus[cpu].opp_token;
@ -536,27 +517,20 @@ static int qcom_cpufreq_probe(struct platform_device *pdev)
}
}
if (virt_devs) {
const char * const *name = config.genpd_names;
int i, j;
for (i = 0; *name; i++, name++) {
ret = pm_runtime_resume_and_get(virt_devs[i]);
if (ret) {
dev_err(cpu_dev, "failed to resume %s: %d\n",
*name, ret);
/* Rollback previous PM runtime calls */
name = config.genpd_names;
for (j = 0; *name && j < i; j++, name++)
pm_runtime_put(virt_devs[j]);
if (drv->data->pd_names) {
struct dev_pm_domain_attach_data attach_data = {
.pd_names = drv->data->pd_names,
.num_pd_names = drv->data->num_pd_names,
.pd_flags = PD_FLAG_DEV_LINK_ON |
PD_FLAG_REQUIRED_OPP,
};
ret = dev_pm_domain_attach_list(cpu_dev, &attach_data,
&drv->cpus[cpu].pd_list);
if (ret < 0)
goto free_opp;
}
}
drv->cpus[cpu].virt_devs = virt_devs;
}
}
cpufreq_dt_pdev = platform_device_register_simple("cpufreq-dt", -1,
NULL, 0);
@ -570,7 +544,7 @@ static int qcom_cpufreq_probe(struct platform_device *pdev)
free_opp:
for_each_possible_cpu(cpu) {
qcom_cpufreq_put_virt_devs(drv, cpu);
dev_pm_domain_detach_list(drv->cpus[cpu].pd_list);
dev_pm_opp_clear_config(drv->cpus[cpu].opp_token);
}
return ret;
@ -584,7 +558,7 @@ static void qcom_cpufreq_remove(struct platform_device *pdev)
platform_device_unregister(cpufreq_dt_pdev);
for_each_possible_cpu(cpu) {
qcom_cpufreq_put_virt_devs(drv, cpu);
dev_pm_domain_detach_list(drv->cpus[cpu].pd_list);
dev_pm_opp_clear_config(drv->cpus[cpu].opp_token);
}
}
@ -595,7 +569,7 @@ static int qcom_cpufreq_suspend(struct device *dev)
unsigned int cpu;
for_each_possible_cpu(cpu)
qcom_cpufreq_suspend_virt_devs(drv, cpu);
qcom_cpufreq_suspend_pd_devs(drv, cpu);
return 0;
}

View File

@ -46,6 +46,7 @@ struct gr3d {
unsigned int nclocks;
struct reset_control_bulk_data resets[RST_GR3D_MAX];
unsigned int nresets;
struct dev_pm_domain_list *pd_list;
DECLARE_BITMAP(addr_regs, GR3D_NUM_REGS);
};
@ -369,18 +370,13 @@ static int gr3d_power_up_legacy_domain(struct device *dev, const char *name,
return 0;
}
static void gr3d_del_link(void *link)
{
device_link_del(link);
}
static int gr3d_init_power(struct device *dev, struct gr3d *gr3d)
{
static const char * const opp_genpd_names[] = { "3d0", "3d1", NULL };
const u32 link_flags = DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME;
struct device **opp_virt_devs, *pd_dev;
struct device_link *link;
unsigned int i;
struct dev_pm_domain_attach_data pd_data = {
.pd_names = (const char *[]) { "3d0", "3d1" },
.num_pd_names = 2,
.pd_flags = PD_FLAG_REQUIRED_OPP,
};
int err;
err = of_count_phandle_with_args(dev->of_node, "power-domains",
@ -414,29 +410,10 @@ static int gr3d_init_power(struct device *dev, struct gr3d *gr3d)
if (dev->pm_domain)
return 0;
err = devm_pm_opp_attach_genpd(dev, opp_genpd_names, &opp_virt_devs);
if (err)
err = devm_pm_domain_attach_list(dev, &pd_data, &gr3d->pd_list);
if (err < 0)
return err;
for (i = 0; opp_genpd_names[i]; i++) {
pd_dev = opp_virt_devs[i];
if (!pd_dev) {
dev_err(dev, "failed to get %s power domain\n",
opp_genpd_names[i]);
return -EINVAL;
}
link = device_link_add(dev, pd_dev, link_flags);
if (!link) {
dev_err(dev, "failed to link to %s\n", dev_name(pd_dev));
return -EINVAL;
}
err = devm_add_action_or_reset(dev, gr3d_del_link, link);
if (err)
return err;
}
return 0;
}

View File

@ -752,7 +752,7 @@ static const struct venus_resources sdm845_res_v2 = {
.vcodec_clks_num = 2,
.vcodec_pmdomains = (const char *[]) { "venus", "vcodec0", "vcodec1" },
.vcodec_pmdomains_num = 3,
.opp_pmdomain = (const char *[]) { "cx", NULL },
.opp_pmdomain = (const char *[]) { "cx" },
.vcodec_num = 2,
.max_load = 3110400, /* 4096x2160@90 */
.hfi_version = HFI_VERSION_4XX,
@ -801,7 +801,7 @@ static const struct venus_resources sc7180_res = {
.vcodec_clks_num = 2,
.vcodec_pmdomains = (const char *[]) { "venus", "vcodec0" },
.vcodec_pmdomains_num = 2,
.opp_pmdomain = (const char *[]) { "cx", NULL },
.opp_pmdomain = (const char *[]) { "cx" },
.vcodec_num = 1,
.hfi_version = HFI_VERSION_4XX,
.vpu_version = VPU_VERSION_AR50,
@ -858,7 +858,7 @@ static const struct venus_resources sm8250_res = {
.vcodec_clks_num = 1,
.vcodec_pmdomains = (const char *[]) { "venus", "vcodec0" },
.vcodec_pmdomains_num = 2,
.opp_pmdomain = (const char *[]) { "mx", NULL },
.opp_pmdomain = (const char *[]) { "mx" },
.vcodec_num = 1,
.max_load = 7833600,
.hfi_version = HFI_VERSION_6XX,
@ -917,7 +917,7 @@ static const struct venus_resources sc7280_res = {
.vcodec_clks_num = 2,
.vcodec_pmdomains = (const char *[]) { "venus", "vcodec0" },
.vcodec_pmdomains_num = 2,
.opp_pmdomain = (const char *[]) { "cx", NULL },
.opp_pmdomain = (const char *[]) { "cx" },
.vcodec_num = 1,
.hfi_version = HFI_VERSION_6XX,
.vpu_version = VPU_VERSION_IRIS2_1,

View File

@ -132,9 +132,7 @@ struct venus_format {
* @vcodec1_clks: an array of vcodec1 struct clk pointers
* @video_path: an interconnect handle to video to/from memory path
* @cpucfg_path: an interconnect handle to cpu configuration path
* @has_opp_table: does OPP table exist
* @pmdomains: a pointer to a list of pmdomains
* @opp_dl_venus: an device-link for device OPP
* @opp_pmdomain: an OPP power-domain
* @resets: an array of reset signals
* @vdev_dec: a reference to video device structure for decoder instances
@ -186,10 +184,8 @@ struct venus_core {
struct clk *vcodec1_clks[VIDC_VCODEC_CLKS_NUM_MAX];
struct icc_path *video_path;
struct icc_path *cpucfg_path;
bool has_opp_table;
struct dev_pm_domain_list *pmdomains;
struct device_link *opp_dl_venus;
struct device *opp_pmdomain;
struct dev_pm_domain_list *opp_pmdomain;
struct reset_control *resets[VIDC_RESETS_NUM_MAX];
struct video_device *vdev_dec;
struct video_device *vdev_enc;

View File

@ -864,7 +864,6 @@ static int venc_power_v4(struct device *dev, int on)
static int vcodec_domains_get(struct venus_core *core)
{
int ret;
struct device **opp_virt_dev;
struct device *dev = core->dev;
const struct venus_resources *res = core->res;
struct dev_pm_domain_attach_data vcodec_data = {
@ -872,6 +871,11 @@ static int vcodec_domains_get(struct venus_core *core)
.num_pd_names = res->vcodec_pmdomains_num,
.pd_flags = PD_FLAG_NO_DEV_LINK,
};
struct dev_pm_domain_attach_data opp_pd_data = {
.pd_names = res->opp_pmdomain,
.num_pd_names = 1,
.pd_flags = PD_FLAG_DEV_LINK_ON | PD_FLAG_REQUIRED_OPP,
};
if (!res->vcodec_pmdomains_num)
goto skip_pmdomains;
@ -881,37 +885,15 @@ static int vcodec_domains_get(struct venus_core *core)
return ret;
skip_pmdomains:
if (!core->res->opp_pmdomain)
if (!res->opp_pmdomain)
return 0;
/* Attach the power domain for setting performance state */
ret = devm_pm_opp_attach_genpd(dev, res->opp_pmdomain, &opp_virt_dev);
if (ret)
goto opp_attach_err;
core->opp_pmdomain = *opp_virt_dev;
core->opp_dl_venus = device_link_add(dev, core->opp_pmdomain,
DL_FLAG_RPM_ACTIVE |
DL_FLAG_PM_RUNTIME |
DL_FLAG_STATELESS);
if (!core->opp_dl_venus) {
ret = -ENODEV;
goto opp_attach_err;
}
ret = devm_pm_domain_attach_list(dev, &opp_pd_data, &core->opp_pmdomain);
if (ret < 0)
return ret;
return 0;
opp_attach_err:
return ret;
}
static void vcodec_domains_put(struct venus_core *core)
{
if (!core->has_opp_table)
return;
if (core->opp_dl_venus)
device_link_del(core->opp_dl_venus);
}
static int core_resets_reset(struct venus_core *core)
@ -1000,9 +982,7 @@ static int core_get_v4(struct venus_core *core)
if (core->res->opp_pmdomain) {
ret = devm_pm_opp_of_add_table(dev);
if (!ret) {
core->has_opp_table = true;
} else if (ret != -ENODEV) {
if (ret && ret != -ENODEV) {
dev_err(dev, "invalid OPP table in device tree\n");
return ret;
}
@ -1013,10 +993,6 @@ static int core_get_v4(struct venus_core *core)
static void core_put_v4(struct venus_core *core)
{
if (legacy_binding)
return;
vcodec_domains_put(core);
}
static int core_power_v4(struct venus_core *core, int on)

View File

@ -2360,48 +2360,13 @@ static void _opp_put_config_regulators_helper(struct opp_table *opp_table)
opp_table->config_regulators = NULL;
}
static void _opp_detach_genpd(struct opp_table *opp_table)
static int _opp_set_required_dev(struct opp_table *opp_table,
struct device *dev,
struct device *required_dev,
unsigned int index)
{
int index;
for (index = 0; index < opp_table->required_opp_count; index++) {
if (!opp_table->required_devs[index])
continue;
dev_pm_domain_detach(opp_table->required_devs[index], false);
opp_table->required_devs[index] = NULL;
}
}
/*
* Multiple generic power domains for a device are supported with the help of
* virtual genpd devices, which are created for each consumer device - genpd
* pair. These are the device structures which are attached to the power domain
* and are required by the OPP core to set the performance state of the genpd.
* The same API also works for the case where single genpd is available and so
* we don't need to support that separately.
*
* This helper will normally be called by the consumer driver of the device
* "dev", as only that has details of the genpd names.
*
* This helper needs to be called once with a list of all genpd to attach.
* Otherwise the original device structure will be used instead by the OPP core.
*
* The order of entries in the names array must match the order in which
* "required-opps" are added in DT.
*/
static int _opp_attach_genpd(struct opp_table *opp_table, struct device *dev,
const char * const *names, struct device ***virt_devs)
{
struct device *virt_dev, *gdev;
struct opp_table *genpd_table;
int index = 0, ret = -EINVAL;
const char * const *name = names;
if (!opp_table->required_devs) {
dev_err(dev, "Required OPPs not available, can't attach genpd\n");
return -EINVAL;
}
struct opp_table *required_table, *pd_table;
struct device *gdev;
/* Genpd core takes care of propagation to parent genpd */
if (opp_table->is_genpd) {
@ -2409,114 +2374,59 @@ static int _opp_attach_genpd(struct opp_table *opp_table, struct device *dev,
return -EOPNOTSUPP;
}
/* Checking only the first one is enough ? */
if (opp_table->required_devs[0])
return 0;
while (*name) {
if (index >= opp_table->required_opp_count) {
dev_err(dev, "Index can't be greater than required-opp-count - 1, %s (%d : %d)\n",
*name, opp_table->required_opp_count, index);
goto err;
}
virt_dev = dev_pm_domain_attach_by_name(dev, *name);
if (IS_ERR_OR_NULL(virt_dev)) {
ret = virt_dev ? PTR_ERR(virt_dev) : -ENODEV;
dev_err(dev, "Couldn't attach to pm_domain: %d\n", ret);
goto err;
}
/*
* The required_opp_tables parsing is not perfect, as the OPP
* core does the parsing solely based on the DT node pointers.
* The core sets the required_opp_tables entry to the first OPP
* table in the "opp_tables" list, that matches with the node
* pointer.
*
* If the target DT OPP table is used by multiple devices and
* they all create separate instances of 'struct opp_table' from
* it, then it is possible that the required_opp_tables entry
* may be set to the incorrect sibling device.
*
* Cross check it again and fix if required.
*/
gdev = dev_to_genpd_dev(virt_dev);
if (IS_ERR(gdev)) {
ret = PTR_ERR(gdev);
goto err;
}
genpd_table = _find_opp_table(gdev);
if (!IS_ERR(genpd_table)) {
if (genpd_table != opp_table->required_opp_tables[index]) {
dev_pm_opp_put_opp_table(opp_table->required_opp_tables[index]);
opp_table->required_opp_tables[index] = genpd_table;
} else {
dev_pm_opp_put_opp_table(genpd_table);
}
}
opp_table->required_devs[index] = virt_dev;
index++;
name++;
}
if (virt_devs)
*virt_devs = opp_table->required_devs;
return 0;
err:
_opp_detach_genpd(opp_table);
return ret;
}
static int _opp_set_required_devs(struct opp_table *opp_table,
struct device *dev,
struct device **required_devs)
{
int i;
if (!opp_table->required_devs) {
dev_err(dev, "Required OPPs not available, can't set required devs\n");
return -EINVAL;
}
/* Another device that shares the OPP table has set the required devs ? */
if (opp_table->required_devs[0])
return 0;
for (i = 0; i < opp_table->required_opp_count; i++) {
/* Genpd core takes care of propagation to parent genpd */
if (required_devs[i] && opp_table->is_genpd &&
opp_table->required_opp_tables[i]->is_genpd) {
dev_err(dev, "%s: Operation not supported for genpds\n", __func__);
return -EOPNOTSUPP;
required_table = opp_table->required_opp_tables[index];
if (IS_ERR(required_table)) {
dev_err(dev, "Missing OPP table, unable to set the required devs\n");
return -ENODEV;
}
opp_table->required_devs[i] = required_devs[i];
/*
* The required_opp_tables parsing is not perfect, as the OPP core does
* the parsing solely based on the DT node pointers. The core sets the
* required_opp_tables entry to the first OPP table in the "opp_tables"
* list, that matches with the node pointer.
*
* If the target DT OPP table is used by multiple devices and they all
* create separate instances of 'struct opp_table' from it, then it is
* possible that the required_opp_tables entry may be set to the
* incorrect sibling device.
*
* Cross check it again and fix if required.
*/
gdev = dev_to_genpd_dev(required_dev);
if (IS_ERR(gdev))
return PTR_ERR(gdev);
pd_table = _find_opp_table(gdev);
if (!IS_ERR(pd_table)) {
if (pd_table != required_table) {
dev_pm_opp_put_opp_table(required_table);
opp_table->required_opp_tables[index] = pd_table;
} else {
dev_pm_opp_put_opp_table(pd_table);
}
}
opp_table->required_devs[index] = required_dev;
return 0;
}
static void _opp_put_required_devs(struct opp_table *opp_table)
static void _opp_put_required_dev(struct opp_table *opp_table,
unsigned int index)
{
int i;
for (i = 0; i < opp_table->required_opp_count; i++)
opp_table->required_devs[i] = NULL;
opp_table->required_devs[index] = NULL;
}
static void _opp_clear_config(struct opp_config_data *data)
{
if (data->flags & OPP_CONFIG_REQUIRED_DEVS)
_opp_put_required_devs(data->opp_table);
else if (data->flags & OPP_CONFIG_GENPD)
_opp_detach_genpd(data->opp_table);
if (data->flags & OPP_CONFIG_REQUIRED_DEV)
_opp_put_required_dev(data->opp_table,
data->required_dev_index);
if (data->flags & OPP_CONFIG_REGULATOR)
_opp_put_regulators(data->opp_table);
if (data->flags & OPP_CONFIG_SUPPORTED_HW)
@ -2628,26 +2538,15 @@ int dev_pm_opp_set_config(struct device *dev, struct dev_pm_opp_config *config)
data->flags |= OPP_CONFIG_REGULATOR;
}
/* Attach genpds */
if (config->genpd_names) {
if (config->required_devs) {
ret = -EINVAL;
goto err;
}
ret = _opp_attach_genpd(opp_table, dev, config->genpd_names,
config->virt_devs);
if (config->required_dev) {
ret = _opp_set_required_dev(opp_table, dev,
config->required_dev,
config->required_dev_index);
if (ret)
goto err;
data->flags |= OPP_CONFIG_GENPD;
} else if (config->required_devs) {
ret = _opp_set_required_devs(opp_table, dev,
config->required_devs);
if (ret)
goto err;
data->flags |= OPP_CONFIG_REQUIRED_DEVS;
data->required_dev_index = config->required_dev_index;
data->flags |= OPP_CONFIG_REQUIRED_DEV;
}
ret = xa_alloc(&opp_configs, &id, data, XA_LIMIT(1, INT_MAX),

View File

@ -295,7 +295,7 @@ void _of_clear_opp(struct opp_table *opp_table, struct dev_pm_opp *opp)
of_node_put(opp->np);
}
static int _link_required_opps(struct dev_pm_opp *opp, struct opp_table *opp_table,
static int _link_required_opps(struct dev_pm_opp *opp,
struct opp_table *required_table, int index)
{
struct device_node *np;
@ -313,39 +313,6 @@ static int _link_required_opps(struct dev_pm_opp *opp, struct opp_table *opp_tab
return -ENODEV;
}
/*
* There are two genpd (as required-opp) cases that we need to handle,
* devices with a single genpd and ones with multiple genpds.
*
* The single genpd case requires special handling as we need to use the
* same `dev` structure (instead of a virtual one provided by genpd
* core) for setting the performance state.
*
* It doesn't make sense for a device's DT entry to have both
* "opp-level" and single "required-opps" entry pointing to a genpd's
* OPP, as that would make the OPP core call
* dev_pm_domain_set_performance_state() for two different values for
* the same device structure. Lets treat single genpd configuration as a
* case where the OPP's level is directly available without required-opp
* link in the DT.
*
* Just update the `level` with the right value, which
* dev_pm_opp_set_opp() will take care of in the normal path itself.
*
* There is another case though, where a genpd's OPP table has
* required-opps set to a parent genpd. The OPP core expects the user to
* set the respective required `struct device` pointer via
* dev_pm_opp_set_config().
*/
if (required_table->is_genpd && opp_table->required_opp_count == 1 &&
!opp_table->required_devs[0]) {
/* Genpd core takes care of propagation to parent genpd */
if (!opp_table->is_genpd) {
if (!WARN_ON(opp->level != OPP_LEVEL_UNSET))
opp->level = opp->required_opps[0]->level;
}
}
return 0;
}
@ -370,7 +337,7 @@ static int _of_opp_alloc_required_opps(struct opp_table *opp_table,
if (IS_ERR_OR_NULL(required_table))
continue;
ret = _link_required_opps(opp, opp_table, required_table, i);
ret = _link_required_opps(opp, required_table, i);
if (ret)
goto free_required_opps;
}
@ -391,7 +358,7 @@ static int lazy_link_required_opps(struct opp_table *opp_table,
int ret;
list_for_each_entry(opp, &opp_table->opp_list, node) {
ret = _link_required_opps(opp, opp_table, new_table, index);
ret = _link_required_opps(opp, new_table, index);
if (ret)
return ret;
}

View File

@ -34,13 +34,13 @@ extern struct list_head opp_tables;
#define OPP_CONFIG_REGULATOR_HELPER BIT(2)
#define OPP_CONFIG_PROP_NAME BIT(3)
#define OPP_CONFIG_SUPPORTED_HW BIT(4)
#define OPP_CONFIG_GENPD BIT(5)
#define OPP_CONFIG_REQUIRED_DEVS BIT(6)
#define OPP_CONFIG_REQUIRED_DEV BIT(5)
/**
* struct opp_config_data - data for set config operations
* @opp_table: OPP table
* @flags: OPP config flags
* @required_dev_index: The position in the array of required_devs
*
* This structure stores the OPP config information for each OPP table
* configuration by the callers.
@ -48,6 +48,7 @@ extern struct list_head opp_tables;
struct opp_config_data {
struct opp_table *opp_table;
unsigned int flags;
unsigned int required_dev_index;
};
/**

View File

@ -1727,6 +1727,7 @@ static void genpd_free_dev_data(struct device *dev,
spin_unlock_irq(&dev->power.lock);
dev_pm_opp_clear_config(gpd_data->opp_token);
kfree(gpd_data->td);
kfree(gpd_data);
dev_pm_put_subsys_data(dev);
@ -2903,12 +2904,58 @@ static void genpd_dev_pm_sync(struct device *dev)
genpd_queue_power_off_work(pd);
}
static int genpd_set_required_opp_dev(struct device *dev,
struct device *base_dev)
{
struct dev_pm_opp_config config = {
.required_dev = dev,
};
int ret;
/* Limit support to non-providers for now. */
if (of_property_present(base_dev->of_node, "#power-domain-cells"))
return 0;
if (!dev_pm_opp_of_has_required_opp(base_dev))
return 0;
ret = dev_pm_opp_set_config(base_dev, &config);
if (ret < 0)
return ret;
dev_gpd_data(dev)->opp_token = ret;
return 0;
}
static int genpd_set_required_opp(struct device *dev, unsigned int index)
{
int ret, pstate;
/* Set the default performance state */
pstate = of_get_required_opp_performance_state(dev->of_node, index);
if (pstate < 0 && pstate != -ENODEV && pstate != -EOPNOTSUPP) {
ret = pstate;
goto err;
} else if (pstate > 0) {
ret = dev_pm_genpd_set_performance_state(dev, pstate);
if (ret)
goto err;
dev_gpd_data(dev)->default_pstate = pstate;
}
return 0;
err:
dev_err(dev, "failed to set required performance state for power-domain %s: %d\n",
dev_to_genpd(dev)->name, ret);
return ret;
}
static int __genpd_dev_pm_attach(struct device *dev, struct device *base_dev,
unsigned int index, bool power_on)
unsigned int index, unsigned int num_domains,
bool power_on)
{
struct of_phandle_args pd_args;
struct generic_pm_domain *pd;
int pstate;
int ret;
ret = of_parse_phandle_with_args(dev->of_node, "power-domains",
@ -2937,18 +2984,21 @@ static int __genpd_dev_pm_attach(struct device *dev, struct device *base_dev,
dev->pm_domain->detach = genpd_dev_pm_detach;
dev->pm_domain->sync = genpd_dev_pm_sync;
/* Set the default performance state */
pstate = of_get_required_opp_performance_state(dev->of_node, index);
if (pstate < 0 && pstate != -ENODEV && pstate != -EOPNOTSUPP) {
ret = pstate;
goto err;
} else if (pstate > 0) {
ret = dev_pm_genpd_set_performance_state(dev, pstate);
/*
* For a single PM domain the index of the required OPP must be zero, so
* let's try to assign a required dev in that case. In the multiple PM
* domains case, we need platform code to specify the index.
*/
if (num_domains == 1) {
ret = genpd_set_required_opp_dev(dev, base_dev);
if (ret)
goto err;
dev_gpd_data(dev)->default_pstate = pstate;
}
ret = genpd_set_required_opp(dev, index);
if (ret)
goto err;
if (power_on) {
genpd_lock(pd);
ret = genpd_power_on(pd, 0);
@ -2969,8 +3019,6 @@ static int __genpd_dev_pm_attach(struct device *dev, struct device *base_dev,
return 1;
err:
dev_err(dev, "failed to set required performance state for power-domain %s: %d\n",
pd->name, ret);
genpd_remove_device(pd, dev);
return ret;
}
@ -3001,7 +3049,7 @@ int genpd_dev_pm_attach(struct device *dev)
"#power-domain-cells") != 1)
return 0;
return __genpd_dev_pm_attach(dev, dev, 0, true);
return __genpd_dev_pm_attach(dev, dev, 0, 1, true);
}
EXPORT_SYMBOL_GPL(genpd_dev_pm_attach);
@ -3054,7 +3102,7 @@ struct device *genpd_dev_pm_attach_by_id(struct device *dev,
}
/* Try to attach the device to the PM domain at the specified index. */
ret = __genpd_dev_pm_attach(virt_dev, dev, index, false);
ret = __genpd_dev_pm_attach(virt_dev, dev, index, num_domains, false);
if (ret < 1) {
device_unregister(virt_dev);
return ret ? ERR_PTR(ret) : NULL;

View File

@ -411,7 +411,7 @@ static int imx_gpc_probe(struct platform_device *pdev)
pgc_node = of_get_child_by_name(pdev->dev.of_node, "pgc");
/* bail out if DT too old and doesn't provide the necessary info */
if (!of_property_read_bool(pdev->dev.of_node, "#power-domain-cells") &&
if (!of_property_present(pdev->dev.of_node, "#power-domain-cells") &&
!pgc_node)
return 0;
@ -511,7 +511,7 @@ static void imx_gpc_remove(struct platform_device *pdev)
pgc_node = of_get_child_by_name(pdev->dev.of_node, "pgc");
/* bail out if DT too old and doesn't provide the necessary info */
if (!of_property_read_bool(pdev->dev.of_node, "#power-domain-cells") &&
if (!of_property_present(pdev->dev.of_node, "#power-domain-cells") &&
!pgc_node)
return;

View File

@ -1356,7 +1356,7 @@ static int imx_pgc_domain_probe(struct platform_device *pdev)
ret = pm_genpd_init(&domain->genpd, NULL, true);
if (ret) {
dev_err(domain->dev, "Failed to init power domain\n");
dev_err_probe(domain->dev, ret, "Failed to init power domain\n");
goto out_domain_unmap;
}
@ -1367,7 +1367,7 @@ static int imx_pgc_domain_probe(struct platform_device *pdev)
ret = of_genpd_add_provider_simple(domain->dev->of_node,
&domain->genpd);
if (ret) {
dev_err(domain->dev, "Failed to add genpd provider\n");
dev_err_probe(domain->dev, ret, "Failed to add genpd provider\n");
goto out_genpd_remove;
}

View File

@ -0,0 +1,96 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef __SOC_MEDIATEK_MT6735_PM_DOMAINS_H
#define __SOC_MEDIATEK_MT6735_PM_DOMAINS_H
#include "mtk-pm-domains.h"
#include <dt-bindings/power/mediatek,mt6735-power-controller.h>
/*
* MT6735 power domain support
*/
static const struct scpsys_domain_data scpsys_domain_data_mt6735[] = {
[MT6735_POWER_DOMAIN_MD1] = {
.name = "md1",
.sta_mask = PWR_STATUS_MD1,
.ctl_offs = SPM_MD1_PWR_CON,
.pwr_sta_offs = SPM_PWR_STATUS,
.pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
.sram_pdn_bits = GENMASK(8, 8),
.sram_pdn_ack_bits = 0,
.bp_cfg = {
BUS_PROT_INFRA_UPDATE_TOPAXI(MT6735_TOP_AXI_PROT_EN_MD1),
},
},
[MT6735_POWER_DOMAIN_CONN] = {
.name = "conn",
.sta_mask = PWR_STATUS_CONN,
.ctl_offs = SPM_CONN_PWR_CON,
.pwr_sta_offs = SPM_PWR_STATUS,
.pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
.sram_pdn_bits = GENMASK(8, 8),
.sram_pdn_ack_bits = 0,
.bp_cfg = {
BUS_PROT_INFRA_UPDATE_TOPAXI(MT6735_TOP_AXI_PROT_EN_CONN),
},
},
[MT6735_POWER_DOMAIN_DIS] = {
.name = "dis",
.sta_mask = PWR_STATUS_DISP,
.ctl_offs = SPM_DIS_PWR_CON,
.pwr_sta_offs = SPM_PWR_STATUS,
.pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
.sram_pdn_bits = GENMASK(11, 8),
.sram_pdn_ack_bits = GENMASK(12, 12),
.bp_cfg = {
BUS_PROT_INFRA_UPDATE_TOPAXI(MT8173_TOP_AXI_PROT_EN_MM_M0),
},
},
[MT6735_POWER_DOMAIN_MFG] = {
.name = "mfg",
.sta_mask = PWR_STATUS_MFG,
.ctl_offs = SPM_MFG_PWR_CON,
.pwr_sta_offs = SPM_PWR_STATUS,
.pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
.sram_pdn_bits = GENMASK(11, 8),
.sram_pdn_ack_bits = GENMASK(12, 12),
.bp_cfg = {
BUS_PROT_INFRA_UPDATE_TOPAXI(MT8173_TOP_AXI_PROT_EN_MFG_S),
},
},
[MT6735_POWER_DOMAIN_ISP] = {
.name = "isp",
.sta_mask = PWR_STATUS_ISP,
.ctl_offs = SPM_ISP_PWR_CON,
.pwr_sta_offs = SPM_PWR_STATUS,
.pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
.sram_pdn_bits = GENMASK(11, 8),
.sram_pdn_ack_bits = GENMASK(13, 12),
},
[MT6735_POWER_DOMAIN_VDE] = {
.name = "vde",
.sta_mask = PWR_STATUS_VDEC,
.ctl_offs = SPM_VDE_PWR_CON,
.pwr_sta_offs = SPM_PWR_STATUS,
.pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
.sram_pdn_bits = GENMASK(11, 8),
.sram_pdn_ack_bits = GENMASK(12, 12),
},
[MT6735_POWER_DOMAIN_VEN] = {
.name = "ven",
.sta_mask = BIT(8),
.ctl_offs = SPM_VEN_PWR_CON,
.pwr_sta_offs = SPM_PWR_STATUS,
.pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
.sram_pdn_bits = GENMASK(11, 8),
.sram_pdn_ack_bits = GENMASK(15, 12),
},
};
static const struct scpsys_soc_data mt6735_scpsys_data = {
.domains_data = scpsys_domain_data_mt6735,
.num_domains = ARRAY_SIZE(scpsys_domain_data_mt6735),
};
#endif /* __SOC_MEDIATEK_MT6735_PM_DOMAINS_H */

View File

@ -16,6 +16,7 @@
#include <linux/regulator/consumer.h>
#include <linux/soc/mediatek/infracfg.h>
#include "mt6735-pm-domains.h"
#include "mt6795-pm-domains.h"
#include "mt8167-pm-domains.h"
#include "mt8173-pm-domains.h"
@ -353,7 +354,6 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no
{
const struct scpsys_domain_data *domain_data;
struct scpsys_domain *pd;
struct device_node *root_node = scpsys->dev->of_node;
struct device_node *smi_node;
struct property *prop;
const char *clk_name;
@ -388,16 +388,7 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no
pd->scpsys = scpsys;
if (MTK_SCPD_CAPS(pd, MTK_SCPD_DOMAIN_SUPPLY)) {
/*
* Find regulator in current power domain node.
* devm_regulator_get() finds regulator in a node and its child
* node, so set of_node to current power domain node then change
* back to original node after regulator is found for current
* power domain node.
*/
scpsys->dev->of_node = node;
pd->supply = devm_regulator_get(scpsys->dev, "domain");
scpsys->dev->of_node = root_node;
pd->supply = devm_of_regulator_get_optional(scpsys->dev, node, "domain");
if (IS_ERR(pd->supply))
return dev_err_cast_probe(scpsys->dev, pd->supply,
"%pOF: failed to get power supply.\n",
@ -618,6 +609,10 @@ static void scpsys_domain_cleanup(struct scpsys *scpsys)
}
static const struct of_device_id scpsys_of_match[] = {
{
.compatible = "mediatek,mt6735-power-controller",
.data = &mt6735_scpsys_data,
},
{
.compatible = "mediatek,mt6795-power-controller",
.data = &mt6795_scpsys_data,

View File

@ -21,6 +21,7 @@
#define SPM_ISP_PWR_CON 0x0238
#define SPM_DIS_PWR_CON 0x023c
#define SPM_CONN_PWR_CON 0x0280
#define SPM_MD1_PWR_CON 0x0284
#define SPM_VEN2_PWR_CON 0x0298
#define SPM_AUDIO_PWR_CON 0x029c
#define SPM_MFG_2D_PWR_CON 0x02c0
@ -30,6 +31,7 @@
#define SPM_PWR_STATUS 0x060c
#define SPM_PWR_STATUS_2ND 0x0610
#define PWR_STATUS_MD1 BIT(0)
#define PWR_STATUS_CONN BIT(1)
#define PWR_STATUS_DISP BIT(3)
#define PWR_STATUS_MFG BIT(4)

View File

@ -259,6 +259,30 @@ static const struct rpmhpd_desc sa8775p_desc = {
.num_pds = ARRAY_SIZE(sa8775p_rpmhpds),
};
/* SAR2130P RPMH powerdomains */
static struct rpmhpd *sar2130p_rpmhpds[] = {
[RPMHPD_CX] = &cx,
[RPMHPD_CX_AO] = &cx_ao,
[RPMHPD_EBI] = &ebi,
[RPMHPD_GFX] = &gfx,
[RPMHPD_LCX] = &lcx,
[RPMHPD_LMX] = &lmx,
[RPMHPD_MMCX] = &mmcx_w_cx_parent,
[RPMHPD_MMCX_AO] = &mmcx_ao_w_cx_parent,
[RPMHPD_MSS] = &mss,
[RPMHPD_MX] = &mx,
[RPMHPD_MX_AO] = &mx_ao,
[RPMHPD_MXC] = &mxc,
[RPMHPD_MXC_AO] = &mxc_ao,
[RPMHPD_NSP] = &nsp,
[RPMHPD_QPHY] = &qphy,
};
static const struct rpmhpd_desc sar2130p_desc = {
.rpmhpds = sar2130p_rpmhpds,
.num_pds = ARRAY_SIZE(sar2130p_rpmhpds),
};
/* SDM670 RPMH powerdomains */
static struct rpmhpd *sdm670_rpmhpds[] = {
[SDM670_CX] = &cx_w_mx_parent,
@ -513,6 +537,31 @@ static const struct rpmhpd_desc sm8650_desc = {
.num_pds = ARRAY_SIZE(sm8650_rpmhpds),
};
/* SM8750 RPMH powerdomains */
static struct rpmhpd *sm8750_rpmhpds[] = {
[RPMHPD_CX] = &cx,
[RPMHPD_CX_AO] = &cx_ao,
[RPMHPD_EBI] = &ebi,
[RPMHPD_GFX] = &gfx,
[RPMHPD_GMXC] = &gmxc,
[RPMHPD_LCX] = &lcx,
[RPMHPD_LMX] = &lmx,
[RPMHPD_MX] = &mx,
[RPMHPD_MX_AO] = &mx_ao,
[RPMHPD_MMCX] = &mmcx_w_cx_parent,
[RPMHPD_MMCX_AO] = &mmcx_ao_w_cx_parent,
[RPMHPD_MSS] = &mss,
[RPMHPD_MXC] = &mxc,
[RPMHPD_MXC_AO] = &mxc_ao,
[RPMHPD_NSP] = &nsp,
[RPMHPD_NSP2] = &nsp2,
};
static const struct rpmhpd_desc sm8750_desc = {
.rpmhpds = sm8750_rpmhpds,
.num_pds = ARRAY_SIZE(sm8750_rpmhpds),
};
/* QDU1000/QRU1000 RPMH powerdomains */
static struct rpmhpd *qdu1000_rpmhpds[] = {
[QDU1000_CX] = &cx,
@ -624,11 +673,48 @@ static const struct rpmhpd_desc x1e80100_desc = {
.num_pds = ARRAY_SIZE(x1e80100_rpmhpds),
};
/* QCS8300 RPMH power domains */
static struct rpmhpd *qcs8300_rpmhpds[] = {
[RPMHPD_CX] = &cx,
[RPMHPD_CX_AO] = &cx_ao,
[RPMHPD_EBI] = &ebi,
[RPMHPD_GFX] = &gfx,
[RPMHPD_LCX] = &lcx,
[RPMHPD_LMX] = &lmx,
[RPMHPD_MMCX] = &mmcx_w_cx_parent,
[RPMHPD_MMCX_AO] = &mmcx_ao_w_cx_parent,
[RPMHPD_MXC] = &mxc,
[RPMHPD_MXC_AO] = &mxc_ao,
[RPMHPD_MX] = &mx,
[RPMHPD_MX_AO] = &mx_ao,
[RPMHPD_NSP0] = &nsp0,
[RPMHPD_NSP1] = &nsp1,
};
static const struct rpmhpd_desc qcs8300_desc = {
.rpmhpds = qcs8300_rpmhpds,
.num_pds = ARRAY_SIZE(qcs8300_rpmhpds),
};
/* QCS615 RPMH powerdomains */
static struct rpmhpd *qcs615_rpmhpds[] = {
[RPMHPD_CX] = &cx,
[RPMHPD_CX_AO] = &cx_ao,
};
static const struct rpmhpd_desc qcs615_desc = {
.rpmhpds = qcs615_rpmhpds,
.num_pds = ARRAY_SIZE(qcs615_rpmhpds),
};
static const struct of_device_id rpmhpd_match_table[] = {
{ .compatible = "qcom,qcs615-rpmhpd", .data = &qcs615_desc },
{ .compatible = "qcom,qcs8300-rpmhpd", .data = &qcs8300_desc },
{ .compatible = "qcom,qdu1000-rpmhpd", .data = &qdu1000_desc },
{ .compatible = "qcom,sa8155p-rpmhpd", .data = &sa8155p_desc },
{ .compatible = "qcom,sa8540p-rpmhpd", .data = &sa8540p_desc },
{ .compatible = "qcom,sa8775p-rpmhpd", .data = &sa8775p_desc },
{ .compatible = "qcom,sar2130p-rpmhpd", .data = &sar2130p_desc},
{ .compatible = "qcom,sc7180-rpmhpd", .data = &sc7180_desc },
{ .compatible = "qcom,sc7280-rpmhpd", .data = &sc7280_desc },
{ .compatible = "qcom,sc8180x-rpmhpd", .data = &sc8180x_desc },
@ -646,6 +732,7 @@ static const struct of_device_id rpmhpd_match_table[] = {
{ .compatible = "qcom,sm8450-rpmhpd", .data = &sm8450_desc },
{ .compatible = "qcom,sm8550-rpmhpd", .data = &sm8550_desc },
{ .compatible = "qcom,sm8650-rpmhpd", .data = &sm8650_desc },
{ .compatible = "qcom,sm8750-rpmhpd", .data = &sm8750_desc },
{ .compatible = "qcom,x1e80100-rpmhpd", .data = &x1e80100_desc },
{ }
};

View File

@ -131,9 +131,8 @@ static int ti_sci_pm_domain_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct ti_sci_genpd_provider *pd_provider;
struct ti_sci_pm_domain *pd;
struct device_node *np;
struct device_node *np __free(device_node) = NULL;
struct of_phandle_args args;
int ret;
u32 max_id = 0;
int index;
@ -153,14 +152,12 @@ static int ti_sci_pm_domain_probe(struct platform_device *pdev)
for_each_node_with_property(np, "power-domains") {
index = 0;
while (1) {
ret = of_parse_phandle_with_args(np, "power-domains",
while (!of_parse_phandle_with_args(np, "power-domains",
"#power-domain-cells",
index, &args);
if (ret)
break;
index, &args)) {
if (args.args_count >= 1 && args.np == dev->of_node) {
of_node_put(args.np);
if (args.args[0] > max_id) {
max_id = args.args[0];
} else {
@ -171,28 +168,28 @@ static int ti_sci_pm_domain_probe(struct platform_device *pdev)
}
pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
if (!pd) {
of_node_put(np);
if (!pd)
return -ENOMEM;
}
pd->pd.name = devm_kasprintf(dev, GFP_KERNEL,
"pd:%d",
args.args[0]);
if (!pd->pd.name) {
of_node_put(np);
if (!pd->pd.name)
return -ENOMEM;
}
pd->pd.power_off = ti_sci_pd_power_off;
pd->pd.power_on = ti_sci_pd_power_on;
pd->pd.flags |= GENPD_FLAG_ACTIVE_WAKEUP;
pd->idx = args.args[0];
pd->parent = pd_provider;
pm_genpd_init(&pd->pd, NULL, true);
list_add(&pd->node, &pd_provider->pd_list);
} else {
of_node_put(args.np);
}
index++;
}
}

View File

@ -0,0 +1,14 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
#ifndef _DT_BINDINGS_POWER_MT6735_POWER_CONTROLLER_H
#define _DT_BINDINGS_POWER_MT6735_POWER_CONTROLLER_H
#define MT6735_POWER_DOMAIN_MD1 0
#define MT6735_POWER_DOMAIN_CONN 1
#define MT6735_POWER_DOMAIN_DIS 2
#define MT6735_POWER_DOMAIN_MFG 3
#define MT6735_POWER_DOMAIN_ISP 4
#define MT6735_POWER_DOMAIN_VDE 5
#define MT6735_POWER_DOMAIN_VEN 6
#endif

View File

@ -218,6 +218,7 @@
/* SDM845 Power Domain performance levels */
#define RPMH_REGULATOR_LEVEL_RETENTION 16
#define RPMH_REGULATOR_LEVEL_MIN_SVS 48
#define RPMH_REGULATOR_LEVEL_LOW_SVS_D3 50
#define RPMH_REGULATOR_LEVEL_LOW_SVS_D2 52
#define RPMH_REGULATOR_LEVEL_LOW_SVS_D1 56
#define RPMH_REGULATOR_LEVEL_LOW_SVS_D0 60
@ -238,6 +239,7 @@
#define RPMH_REGULATOR_LEVEL_TURBO_L1 416
#define RPMH_REGULATOR_LEVEL_TURBO_L2 432
#define RPMH_REGULATOR_LEVEL_TURBO_L3 448
#define RPMH_REGULATOR_LEVEL_TURBO_L4 452
#define RPMH_REGULATOR_LEVEL_SUPER_TURBO 464
#define RPMH_REGULATOR_LEVEL_SUPER_TURBO_NO_CPR 480

View File

@ -30,9 +30,16 @@
* supplier and its PM domain when creating the
* device-links.
*
* PD_FLAG_REQUIRED_OPP: Assign required_devs for the required OPPs. The
* index of the required OPP must correspond to the
* index in the array of the pd_names. If pd_names
* isn't specified, the index just follows the
* index for the attached PM domain.
*
*/
#define PD_FLAG_NO_DEV_LINK BIT(0)
#define PD_FLAG_DEV_LINK_ON BIT(1)
#define PD_FLAG_REQUIRED_OPP BIT(2)
struct dev_pm_domain_attach_data {
const char * const *pd_names;
@ -43,6 +50,7 @@ struct dev_pm_domain_attach_data {
struct dev_pm_domain_list {
struct device **pd_devs;
struct device_link **pd_links;
u32 *opp_tokens;
u32 num_pds;
};
@ -250,6 +258,7 @@ struct generic_pm_domain_data {
unsigned int performance_state;
unsigned int default_pstate;
unsigned int rpm_pstate;
unsigned int opp_token;
bool hw_mode;
void *data;
};

View File

@ -62,11 +62,8 @@ typedef int (*config_clks_t)(struct device *dev, struct opp_table *opp_table,
* @supported_hw: Array of hierarchy of versions to match.
* @supported_hw_count: Number of elements in the array.
* @regulator_names: Array of pointers to the names of the regulator, NULL terminated.
* @genpd_names: Null terminated array of pointers containing names of genpd to
* attach. Mutually exclusive with required_devs.
* @virt_devs: Pointer to return the array of genpd virtual devices. Mutually
* exclusive with required_devs.
* @required_devs: Required OPP devices. Mutually exclusive with genpd_names/virt_devs.
* @required_dev: The required OPP device.
* @required_dev_index: The index of the required OPP for the @required_dev.
*
* This structure contains platform specific OPP configurations for the device.
*/
@ -79,9 +76,8 @@ struct dev_pm_opp_config {
const unsigned int *supported_hw;
unsigned int supported_hw_count;
const char * const *regulator_names;
const char * const *genpd_names;
struct device ***virt_devs;
struct device **required_devs;
struct device *required_dev;
unsigned int required_dev_index;
};
#define OPP_LEVEL_UNSET U32_MAX
@ -675,36 +671,6 @@ static inline void dev_pm_opp_put_config_regulators(int token)
dev_pm_opp_clear_config(token);
}
/* genpd helpers */
static inline int dev_pm_opp_attach_genpd(struct device *dev,
const char * const *names,
struct device ***virt_devs)
{
struct dev_pm_opp_config config = {
.genpd_names = names,
.virt_devs = virt_devs,
};
return dev_pm_opp_set_config(dev, &config);
}
static inline void dev_pm_opp_detach_genpd(int token)
{
dev_pm_opp_clear_config(token);
}
static inline int devm_pm_opp_attach_genpd(struct device *dev,
const char * const *names,
struct device ***virt_devs)
{
struct dev_pm_opp_config config = {
.genpd_names = names,
.virt_devs = virt_devs,
};
return devm_pm_opp_set_config(dev, &config);
}
/* prop-name helpers */
static inline int dev_pm_opp_set_prop_name(struct device *dev, const char *name)
{

View File

@ -434,6 +434,11 @@
#define MT7622_TOP_AXI_PROT_EN_WB (BIT(2) | BIT(6) | \
BIT(7) | BIT(8))
#define MT6735_TOP_AXI_PROT_EN_CONN (BIT(2) | BIT(8))
#define MT6735_TOP_AXI_PROT_EN_MD1 (BIT(24) | BIT(25) | \
BIT(26) | BIT(27) | \
BIT(28))
#define INFRA_TOPAXI_PROTECTEN 0x0220
#define INFRA_TOPAXI_PROTECTSTA1 0x0228
#define INFRA_TOPAXI_PROTECTEN_SET 0x0260