Commit a070a08d authored by Linus Torvalds's avatar Linus Torvalds

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

Pull pmdomain updates from Ulf Hansson:
 "Core:
   - Log a message when unused PM domains gets disabled
   - Scale down parent/child performance states in the reverse order

  Providers:
   - qcom: rpmpd: Add power domains support for MSM8974, MSM8974PRO,
     PMA8084 and PM8841
   - renesas: rcar-gen4-sysc: Reduce atomic delays
   - renesas: rcar-sysc: Adjust the waiting time to cover the worst case
   - renesas: r8a779h0-sysc: Add support for the r8a779h0 PM domains
   - imx: imx8mp-blk-ctrl: Add the fdcc clock to the hdmimix domains
   - imx: imx8mp-blk-ctrl: Error out if domains are missing in DT

  Improve support for multiple PM domains:
   - Add two helper functions to attach/detach multiple PM domains
   - Convert a couple of drivers to use the new helper functions"

* tag 'pmdomain-v6.9' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/linux-pm: (22 commits)
  pmdomain: renesas: rcar-gen4-sysc: Reduce atomic delays
  pmdomain: renesas: Adjust the waiting time to cover the worst case
  pmdomain: qcom: rpmpd: Add MSM8974PRO+PMA8084 power domains
  pmdomain: qcom: rpmpd: Add MSM8974+PM8841 power domains
  pmdomain: core: constify of_phandle_args in add device and subdomain
  pmdomain: core: constify of_phandle_args in xlate
  media: venus: Convert to dev_pm_domain_attach|detach_list() for vcodec
  remoteproc: qcom_q6v5_adsp: Convert to dev_pm_domain_attach|detach_list()
  remoteproc: imx_rproc: Convert to dev_pm_domain_attach|detach_list()
  remoteproc: imx_dsp_rproc: Convert to dev_pm_domain_attach|detach_list()
  PM: domains: Add helper functions to attach/detach multiple PM domains
  pmdomain: imx8mp-blk-ctrl: imx8mp_blk: Add fdcc clock to hdmimix domain
  pmdomain: mediatek: Use devm_platform_ioremap_resource() in init_scp()
  pmdomain: renesas: r8a779h0-sysc: Add r8a779h0 support
  pmdomain: imx8mp-blk-ctrl: Error out if domains are missing in DT
  pmdomain: ti: Add a null pointer check to the omap_prm_domain_init
  pmdomain: renesas: rcar-gen4-sysc: Remove unneeded includes
  pmdomain: core: Print a message when unused power domains are disabled
  pmdomain: qcom: rpmpd: Keep one RPM handle for all RPMPDs
  pmdomain: core: Scale down parent/child performance states in reverse order
  ...
parents 15223fdb ccabbb67
...@@ -24,6 +24,8 @@ properties: ...@@ -24,6 +24,8 @@ properties:
- qcom,msm8917-rpmpd - qcom,msm8917-rpmpd
- qcom,msm8939-rpmpd - qcom,msm8939-rpmpd
- qcom,msm8953-rpmpd - qcom,msm8953-rpmpd
- qcom,msm8974-rpmpd
- qcom,msm8974pro-pma8084-rpmpd
- qcom,msm8976-rpmpd - qcom,msm8976-rpmpd
- qcom,msm8994-rpmpd - qcom,msm8994-rpmpd
- qcom,msm8996-rpmpd - qcom,msm8996-rpmpd
......
...@@ -27,8 +27,8 @@ properties: ...@@ -27,8 +27,8 @@ properties:
const: 1 const: 1
power-domains: power-domains:
minItems: 8 minItems: 10
maxItems: 8 maxItems: 10
power-domain-names: power-domain-names:
items: items:
...@@ -40,10 +40,12 @@ properties: ...@@ -40,10 +40,12 @@ properties:
- const: trng - const: trng
- const: hdmi-tx - const: hdmi-tx
- const: hdmi-tx-phy - const: hdmi-tx-phy
- const: hdcp
- const: hrv
clocks: clocks:
minItems: 4 minItems: 5
maxItems: 4 maxItems: 5
clock-names: clock-names:
items: items:
...@@ -51,6 +53,7 @@ properties: ...@@ -51,6 +53,7 @@ properties:
- const: axi - const: axi
- const: ref_266m - const: ref_266m
- const: ref_24m - const: ref_24m
- const: fdcc
interconnects: interconnects:
maxItems: 3 maxItems: 3
...@@ -82,12 +85,15 @@ examples: ...@@ -82,12 +85,15 @@ examples:
clocks = <&clk IMX8MP_CLK_HDMI_APB>, clocks = <&clk IMX8MP_CLK_HDMI_APB>,
<&clk IMX8MP_CLK_HDMI_ROOT>, <&clk IMX8MP_CLK_HDMI_ROOT>,
<&clk IMX8MP_CLK_HDMI_REF_266M>, <&clk IMX8MP_CLK_HDMI_REF_266M>,
<&clk IMX8MP_CLK_HDMI_24M>; <&clk IMX8MP_CLK_HDMI_24M>,
clock-names = "apb", "axi", "ref_266m", "ref_24m"; <&clk IMX8MP_CLK_HDMI_FDCC_TST>;
clock-names = "apb", "axi", "ref_266m", "ref_24m", "fdcc";
power-domains = <&pgc_hdmimix>, <&pgc_hdmimix>, <&pgc_hdmimix>, power-domains = <&pgc_hdmimix>, <&pgc_hdmimix>, <&pgc_hdmimix>,
<&pgc_hdmimix>, <&pgc_hdmimix>, <&pgc_hdmimix>, <&pgc_hdmimix>, <&pgc_hdmimix>, <&pgc_hdmimix>,
<&pgc_hdmimix>, <&pgc_hdmi_phy>; <&pgc_hdmimix>, <&pgc_hdmi_phy>,
<&pgc_hdmimix>, <&pgc_hdmimix>;
power-domain-names = "bus", "irqsteer", "lcdif", "pai", "pvi", "trng", power-domain-names = "bus", "irqsteer", "lcdif", "pai", "pvi", "trng",
"hdmi-tx", "hdmi-tx-phy"; "hdmi-tx", "hdmi-tx-phy",
"hdcp", "hrv";
#power-domain-cells = <1>; #power-domain-cells = <1>;
}; };
...@@ -167,6 +167,115 @@ struct device *dev_pm_domain_attach_by_name(struct device *dev, ...@@ -167,6 +167,115 @@ struct device *dev_pm_domain_attach_by_name(struct device *dev,
} }
EXPORT_SYMBOL_GPL(dev_pm_domain_attach_by_name); EXPORT_SYMBOL_GPL(dev_pm_domain_attach_by_name);
/**
* dev_pm_domain_attach_list - Associate a device with its PM domains.
* @dev: The device used to lookup the PM domains for.
* @data: The data used for attaching to the PM domains.
* @list: An out-parameter with an allocated list of attached PM domains.
*
* This function helps to attach a device to its multiple PM domains. The
* caller, which is typically a driver's probe function, may provide a list of
* names for the PM domains that we should try to attach the device to, but it
* may also provide an empty list, in case the attach should be done for all of
* the available PM domains.
*
* Callers must ensure proper synchronization of this function with power
* management callbacks.
*
* Returns the number of attached PM domains or a negative error code in case of
* a failure. Note that, to detach the list of PM domains, the driver shall call
* dev_pm_domain_detach_list(), typically during the remove phase.
*/
int dev_pm_domain_attach_list(struct device *dev,
const struct dev_pm_domain_attach_data *data,
struct dev_pm_domain_list **list)
{
struct device_node *np = dev->of_node;
struct dev_pm_domain_list *pds;
struct device *pd_dev = NULL;
int ret, i, num_pds = 0;
bool by_id = true;
u32 pd_flags = data ? data->pd_flags : 0;
u32 link_flags = pd_flags & PD_FLAG_NO_DEV_LINK ? 0 :
DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME;
if (dev->pm_domain)
return -EEXIST;
/* For now this is limited to OF based platforms. */
if (!np)
return 0;
if (data && data->pd_names) {
num_pds = data->num_pd_names;
by_id = false;
} else {
num_pds = of_count_phandle_with_args(np, "power-domains",
"#power-domain-cells");
}
if (num_pds <= 0)
return 0;
pds = devm_kzalloc(dev, sizeof(*pds), GFP_KERNEL);
if (!pds)
return -ENOMEM;
pds->pd_devs = devm_kcalloc(dev, num_pds, sizeof(*pds->pd_devs),
GFP_KERNEL);
if (!pds->pd_devs)
return -ENOMEM;
pds->pd_links = devm_kcalloc(dev, num_pds, sizeof(*pds->pd_links),
GFP_KERNEL);
if (!pds->pd_links)
return -ENOMEM;
if (link_flags && pd_flags & PD_FLAG_DEV_LINK_ON)
link_flags |= DL_FLAG_RPM_ACTIVE;
for (i = 0; i < num_pds; i++) {
if (by_id)
pd_dev = dev_pm_domain_attach_by_id(dev, i);
else
pd_dev = dev_pm_domain_attach_by_name(dev,
data->pd_names[i]);
if (IS_ERR_OR_NULL(pd_dev)) {
ret = pd_dev ? PTR_ERR(pd_dev) : -ENODEV;
goto err_attach;
}
if (link_flags) {
struct device_link *link;
link = device_link_add(dev, pd_dev, link_flags);
if (!link) {
ret = -ENODEV;
goto err_link;
}
pds->pd_links[i] = link;
}
pds->pd_devs[i] = pd_dev;
}
pds->num_pds = num_pds;
*list = pds;
return num_pds;
err_link:
dev_pm_domain_detach(pd_dev, true);
err_attach:
while (--i >= 0) {
if (pds->pd_links[i])
device_link_del(pds->pd_links[i]);
dev_pm_domain_detach(pds->pd_devs[i], true);
}
return ret;
}
EXPORT_SYMBOL_GPL(dev_pm_domain_attach_list);
/** /**
* dev_pm_domain_detach - Detach a device from its PM domain. * dev_pm_domain_detach - Detach a device from its PM domain.
* @dev: Device to detach. * @dev: Device to detach.
...@@ -187,6 +296,31 @@ void dev_pm_domain_detach(struct device *dev, bool power_off) ...@@ -187,6 +296,31 @@ void dev_pm_domain_detach(struct device *dev, bool power_off)
} }
EXPORT_SYMBOL_GPL(dev_pm_domain_detach); EXPORT_SYMBOL_GPL(dev_pm_domain_detach);
/**
* dev_pm_domain_detach_list - Detach a list of PM domains.
* @list: The list of PM domains to detach.
*
* This function reverse the actions from dev_pm_domain_attach_list().
* Typically it should be invoked during the remove phase from drivers.
*
* Callers must ensure proper synchronization of this function with power
* management callbacks.
*/
void dev_pm_domain_detach_list(struct dev_pm_domain_list *list)
{
int i;
if (!list)
return;
for (i = 0; i < list->num_pds; i++) {
if (list->pd_links[i])
device_link_del(list->pd_links[i]);
dev_pm_domain_detach(list->pd_devs[i], true);
}
}
EXPORT_SYMBOL_GPL(dev_pm_domain_detach_list);
/** /**
* dev_pm_domain_start - Start the device through its PM domain. * dev_pm_domain_start - Start the device through its PM domain.
* @dev: Device to start. * @dev: Device to start.
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <media/videobuf2-v4l2.h> #include <media/videobuf2-v4l2.h>
#include <media/v4l2-mem2mem.h> #include <media/v4l2-mem2mem.h>
...@@ -114,7 +115,8 @@ static void venus_sys_error_handler(struct work_struct *work) ...@@ -114,7 +115,8 @@ static void venus_sys_error_handler(struct work_struct *work)
pm_runtime_put_sync(core->dev); pm_runtime_put_sync(core->dev);
for (i = 0; i < max_attempts; i++) { for (i = 0; i < max_attempts; i++) {
if (!core->pmdomains[0] || !pm_runtime_active(core->pmdomains[0])) if (!core->pmdomains ||
!pm_runtime_active(core->pmdomains->pd_devs[0]))
break; break;
usleep_range(1000, 1500); usleep_range(1000, 1500);
} }
...@@ -705,7 +707,7 @@ static const struct venus_resources sdm845_res_v2 = { ...@@ -705,7 +707,7 @@ static const struct venus_resources sdm845_res_v2 = {
.vcodec0_clks = { "vcodec0_core", "vcodec0_bus" }, .vcodec0_clks = { "vcodec0_core", "vcodec0_bus" },
.vcodec1_clks = { "vcodec1_core", "vcodec1_bus" }, .vcodec1_clks = { "vcodec1_core", "vcodec1_bus" },
.vcodec_clks_num = 2, .vcodec_clks_num = 2,
.vcodec_pmdomains = { "venus", "vcodec0", "vcodec1" }, .vcodec_pmdomains = (const char *[]) { "venus", "vcodec0", "vcodec1" },
.vcodec_pmdomains_num = 3, .vcodec_pmdomains_num = 3,
.opp_pmdomain = (const char *[]) { "cx", NULL }, .opp_pmdomain = (const char *[]) { "cx", NULL },
.vcodec_num = 2, .vcodec_num = 2,
...@@ -754,7 +756,7 @@ static const struct venus_resources sc7180_res = { ...@@ -754,7 +756,7 @@ static const struct venus_resources sc7180_res = {
.clks_num = 3, .clks_num = 3,
.vcodec0_clks = { "vcodec0_core", "vcodec0_bus" }, .vcodec0_clks = { "vcodec0_core", "vcodec0_bus" },
.vcodec_clks_num = 2, .vcodec_clks_num = 2,
.vcodec_pmdomains = { "venus", "vcodec0" }, .vcodec_pmdomains = (const char *[]) { "venus", "vcodec0" },
.vcodec_pmdomains_num = 2, .vcodec_pmdomains_num = 2,
.opp_pmdomain = (const char *[]) { "cx", NULL }, .opp_pmdomain = (const char *[]) { "cx", NULL },
.vcodec_num = 1, .vcodec_num = 1,
...@@ -811,7 +813,7 @@ static const struct venus_resources sm8250_res = { ...@@ -811,7 +813,7 @@ static const struct venus_resources sm8250_res = {
.resets_num = 2, .resets_num = 2,
.vcodec0_clks = { "vcodec0_core" }, .vcodec0_clks = { "vcodec0_core" },
.vcodec_clks_num = 1, .vcodec_clks_num = 1,
.vcodec_pmdomains = { "venus", "vcodec0" }, .vcodec_pmdomains = (const char *[]) { "venus", "vcodec0" },
.vcodec_pmdomains_num = 2, .vcodec_pmdomains_num = 2,
.opp_pmdomain = (const char *[]) { "mx", NULL }, .opp_pmdomain = (const char *[]) { "mx", NULL },
.vcodec_num = 1, .vcodec_num = 1,
...@@ -870,7 +872,7 @@ static const struct venus_resources sc7280_res = { ...@@ -870,7 +872,7 @@ static const struct venus_resources sc7280_res = {
.clks_num = 3, .clks_num = 3,
.vcodec0_clks = {"vcodec_core", "vcodec_bus"}, .vcodec0_clks = {"vcodec_core", "vcodec_bus"},
.vcodec_clks_num = 2, .vcodec_clks_num = 2,
.vcodec_pmdomains = { "venus", "vcodec0" }, .vcodec_pmdomains = (const char *[]) { "venus", "vcodec0" },
.vcodec_pmdomains_num = 2, .vcodec_pmdomains_num = 2,
.opp_pmdomain = (const char *[]) { "cx", NULL }, .opp_pmdomain = (const char *[]) { "cx", NULL },
.vcodec_num = 1, .vcodec_num = 1,
......
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
#define VIDC_CLKS_NUM_MAX 4 #define VIDC_CLKS_NUM_MAX 4
#define VIDC_VCODEC_CLKS_NUM_MAX 2 #define VIDC_VCODEC_CLKS_NUM_MAX 2
#define VIDC_PMDOMAINS_NUM_MAX 3
#define VIDC_RESETS_NUM_MAX 2 #define VIDC_RESETS_NUM_MAX 2
extern int venus_fw_debug; extern int venus_fw_debug;
...@@ -72,7 +71,7 @@ struct venus_resources { ...@@ -72,7 +71,7 @@ struct venus_resources {
const char * const vcodec0_clks[VIDC_VCODEC_CLKS_NUM_MAX]; const char * const vcodec0_clks[VIDC_VCODEC_CLKS_NUM_MAX];
const char * const vcodec1_clks[VIDC_VCODEC_CLKS_NUM_MAX]; const char * const vcodec1_clks[VIDC_VCODEC_CLKS_NUM_MAX];
unsigned int vcodec_clks_num; unsigned int vcodec_clks_num;
const char * const vcodec_pmdomains[VIDC_PMDOMAINS_NUM_MAX]; const char **vcodec_pmdomains;
unsigned int vcodec_pmdomains_num; unsigned int vcodec_pmdomains_num;
const char **opp_pmdomain; const char **opp_pmdomain;
unsigned int vcodec_num; unsigned int vcodec_num;
...@@ -134,7 +133,7 @@ struct venus_format { ...@@ -134,7 +133,7 @@ struct venus_format {
* @video_path: an interconnect handle to video to/from memory path * @video_path: an interconnect handle to video to/from memory path
* @cpucfg_path: an interconnect handle to cpu configuration path * @cpucfg_path: an interconnect handle to cpu configuration path
* @has_opp_table: does OPP table exist * @has_opp_table: does OPP table exist
* @pmdomains: an array of pmdomains struct device pointers * @pmdomains: a pointer to a list of pmdomains
* @opp_dl_venus: an device-link for device OPP * @opp_dl_venus: an device-link for device OPP
* @opp_pmdomain: an OPP power-domain * @opp_pmdomain: an OPP power-domain
* @resets: an array of reset signals * @resets: an array of reset signals
...@@ -187,7 +186,7 @@ struct venus_core { ...@@ -187,7 +186,7 @@ struct venus_core {
struct icc_path *video_path; struct icc_path *video_path;
struct icc_path *cpucfg_path; struct icc_path *cpucfg_path;
bool has_opp_table; bool has_opp_table;
struct device *pmdomains[VIDC_PMDOMAINS_NUM_MAX]; struct dev_pm_domain_list *pmdomains;
struct device_link *opp_dl_venus; struct device_link *opp_dl_venus;
struct device *opp_pmdomain; struct device *opp_pmdomain;
struct reset_control *resets[VIDC_RESETS_NUM_MAX]; struct reset_control *resets[VIDC_RESETS_NUM_MAX];
......
...@@ -455,7 +455,7 @@ static int poweroff_coreid(struct venus_core *core, unsigned int coreid_mask) ...@@ -455,7 +455,7 @@ static int poweroff_coreid(struct venus_core *core, unsigned int coreid_mask)
if (ret) if (ret)
return ret; return ret;
ret = pm_runtime_put_sync(core->pmdomains[1]); ret = pm_runtime_put_sync(core->pmdomains->pd_devs[1]);
if (ret < 0) if (ret < 0)
return ret; return ret;
} }
...@@ -471,7 +471,7 @@ static int poweroff_coreid(struct venus_core *core, unsigned int coreid_mask) ...@@ -471,7 +471,7 @@ static int poweroff_coreid(struct venus_core *core, unsigned int coreid_mask)
if (ret) if (ret)
return ret; return ret;
ret = pm_runtime_put_sync(core->pmdomains[2]); ret = pm_runtime_put_sync(core->pmdomains->pd_devs[2]);
if (ret < 0) if (ret < 0)
return ret; return ret;
} }
...@@ -484,7 +484,7 @@ static int poweron_coreid(struct venus_core *core, unsigned int coreid_mask) ...@@ -484,7 +484,7 @@ static int poweron_coreid(struct venus_core *core, unsigned int coreid_mask)
int ret; int ret;
if (coreid_mask & VIDC_CORE_ID_1) { if (coreid_mask & VIDC_CORE_ID_1) {
ret = pm_runtime_get_sync(core->pmdomains[1]); ret = pm_runtime_get_sync(core->pmdomains->pd_devs[1]);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -502,7 +502,7 @@ static int poweron_coreid(struct venus_core *core, unsigned int coreid_mask) ...@@ -502,7 +502,7 @@ static int poweron_coreid(struct venus_core *core, unsigned int coreid_mask)
} }
if (coreid_mask & VIDC_CORE_ID_2) { if (coreid_mask & VIDC_CORE_ID_2) {
ret = pm_runtime_get_sync(core->pmdomains[2]); ret = pm_runtime_get_sync(core->pmdomains->pd_devs[2]);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -860,19 +860,18 @@ static int vcodec_domains_get(struct venus_core *core) ...@@ -860,19 +860,18 @@ static int vcodec_domains_get(struct venus_core *core)
struct device **opp_virt_dev; struct device **opp_virt_dev;
struct device *dev = core->dev; struct device *dev = core->dev;
const struct venus_resources *res = core->res; const struct venus_resources *res = core->res;
struct device *pd; struct dev_pm_domain_attach_data vcodec_data = {
unsigned int i; .pd_names = res->vcodec_pmdomains,
.num_pd_names = res->vcodec_pmdomains_num,
.pd_flags = PD_FLAG_NO_DEV_LINK,
};
if (!res->vcodec_pmdomains_num) if (!res->vcodec_pmdomains_num)
goto skip_pmdomains; goto skip_pmdomains;
for (i = 0; i < res->vcodec_pmdomains_num; i++) { ret = dev_pm_domain_attach_list(dev, &vcodec_data, &core->pmdomains);
pd = dev_pm_domain_attach_by_name(dev, if (ret < 0)
res->vcodec_pmdomains[i]); return ret;
if (IS_ERR_OR_NULL(pd))
return pd ? PTR_ERR(pd) : -ENODATA;
core->pmdomains[i] = pd;
}
skip_pmdomains: skip_pmdomains:
if (!core->res->opp_pmdomain) if (!core->res->opp_pmdomain)
...@@ -896,30 +895,14 @@ static int vcodec_domains_get(struct venus_core *core) ...@@ -896,30 +895,14 @@ static int vcodec_domains_get(struct venus_core *core)
return 0; return 0;
opp_attach_err: opp_attach_err:
for (i = 0; i < res->vcodec_pmdomains_num; i++) { dev_pm_domain_detach_list(core->pmdomains);
if (IS_ERR_OR_NULL(core->pmdomains[i]))
continue;
dev_pm_domain_detach(core->pmdomains[i], true);
}
return ret; return ret;
} }
static void vcodec_domains_put(struct venus_core *core) static void vcodec_domains_put(struct venus_core *core)
{ {
const struct venus_resources *res = core->res; dev_pm_domain_detach_list(core->pmdomains);
unsigned int i;
if (!res->vcodec_pmdomains_num)
goto skip_pmdomains;
for (i = 0; i < res->vcodec_pmdomains_num; i++) {
if (IS_ERR_OR_NULL(core->pmdomains[i]))
continue;
dev_pm_domain_detach(core->pmdomains[i], true);
}
skip_pmdomains:
if (!core->has_opp_table) if (!core->has_opp_table)
return; return;
...@@ -1035,7 +1018,8 @@ static void core_put_v4(struct venus_core *core) ...@@ -1035,7 +1018,8 @@ static void core_put_v4(struct venus_core *core)
static int core_power_v4(struct venus_core *core, int on) static int core_power_v4(struct venus_core *core, int on)
{ {
struct device *dev = core->dev; struct device *dev = core->dev;
struct device *pmctrl = core->pmdomains[0]; struct device *pmctrl = core->pmdomains ?
core->pmdomains->pd_devs[0] : NULL;
int ret = 0; int ret = 0;
if (on == POWER_ON) { if (on == POWER_ON) {
......
...@@ -311,72 +311,102 @@ static int genpd_xlate_performance_state(struct generic_pm_domain *genpd, ...@@ -311,72 +311,102 @@ static int genpd_xlate_performance_state(struct generic_pm_domain *genpd,
} }
static int _genpd_set_performance_state(struct generic_pm_domain *genpd, static int _genpd_set_performance_state(struct generic_pm_domain *genpd,
unsigned int state, int depth) unsigned int state, int depth);
static void _genpd_rollback_parent_state(struct gpd_link *link, int depth)
{ {
struct generic_pm_domain *parent; struct generic_pm_domain *parent = link->parent;
struct gpd_link *link; int parent_state;
int parent_state, ret;
if (state == genpd->performance_state) genpd_lock_nested(parent, depth + 1);
return 0;
/* Propagate to parents of genpd */ parent_state = link->prev_performance_state;
list_for_each_entry(link, &genpd->child_links, child_node) { link->performance_state = parent_state;
parent = link->parent;
/* Find parent's performance state */ parent_state = _genpd_reeval_performance_state(parent, parent_state);
ret = genpd_xlate_performance_state(genpd, parent, state); if (_genpd_set_performance_state(parent, parent_state, depth + 1)) {
if (unlikely(ret < 0)) pr_err("%s: Failed to roll back to %d performance state\n",
goto err; parent->name, parent_state);
}
parent_state = ret; genpd_unlock(parent);
}
genpd_lock_nested(parent, depth + 1); static int _genpd_set_parent_state(struct generic_pm_domain *genpd,
struct gpd_link *link,
unsigned int state, int depth)
{
struct generic_pm_domain *parent = link->parent;
int parent_state, ret;
link->prev_performance_state = link->performance_state; /* Find parent's performance state */
link->performance_state = parent_state; ret = genpd_xlate_performance_state(genpd, parent, state);
parent_state = _genpd_reeval_performance_state(parent, if (unlikely(ret < 0))
parent_state); return ret;
ret = _genpd_set_performance_state(parent, parent_state, depth + 1);
if (ret)
link->performance_state = link->prev_performance_state;
genpd_unlock(parent); parent_state = ret;
if (ret) genpd_lock_nested(parent, depth + 1);
goto err;
}
if (genpd->set_performance_state) { link->prev_performance_state = link->performance_state;
ret = genpd->set_performance_state(genpd, state); link->performance_state = parent_state;
if (ret)
goto err;
}
genpd->performance_state = state; parent_state = _genpd_reeval_performance_state(parent, parent_state);
return 0; ret = _genpd_set_performance_state(parent, parent_state, depth + 1);
if (ret)
link->performance_state = link->prev_performance_state;
err: genpd_unlock(parent);
/* Encountered an error, lets rollback */
list_for_each_entry_continue_reverse(link, &genpd->child_links,
child_node) {
parent = link->parent;
genpd_lock_nested(parent, depth + 1); return ret;
}
static int _genpd_set_performance_state(struct generic_pm_domain *genpd,
unsigned int state, int depth)
{
struct gpd_link *link = NULL;
int ret;
if (state == genpd->performance_state)
return 0;
parent_state = link->prev_performance_state; /* When scaling up, propagate to parents first in normal order */
link->performance_state = parent_state; if (state > genpd->performance_state) {
list_for_each_entry(link, &genpd->child_links, child_node) {
ret = _genpd_set_parent_state(genpd, link, state, depth);
if (ret)
goto rollback_parents_up;
}
}
parent_state = _genpd_reeval_performance_state(parent, if (genpd->set_performance_state) {
parent_state); ret = genpd->set_performance_state(genpd, state);
if (_genpd_set_performance_state(parent, parent_state, depth + 1)) { if (ret) {
pr_err("%s: Failed to roll back to %d performance state\n", if (link)
parent->name, parent_state); goto rollback_parents_up;
return ret;
} }
}
genpd_unlock(parent); /* When scaling down, propagate to parents last in reverse order */
if (state < genpd->performance_state) {
list_for_each_entry_reverse(link, &genpd->child_links, child_node) {
ret = _genpd_set_parent_state(genpd, link, state, depth);
if (ret)
goto rollback_parents_down;
}
} }
genpd->performance_state = state;
return 0;
rollback_parents_up:
list_for_each_entry_continue_reverse(link, &genpd->child_links, child_node)
_genpd_rollback_parent_state(link, depth);
return ret;
rollback_parents_down:
list_for_each_entry_continue(link, &genpd->child_links, child_node)
_genpd_rollback_parent_state(link, depth);
return ret; return ret;
} }
...@@ -1100,6 +1130,7 @@ static int __init genpd_power_off_unused(void) ...@@ -1100,6 +1130,7 @@ static int __init genpd_power_off_unused(void)
return 0; return 0;
} }
pr_info("genpd: Disabling unused power domains\n");
mutex_lock(&gpd_list_lock); mutex_lock(&gpd_list_lock);
list_for_each_entry(genpd, &gpd_list, gpd_list_node) list_for_each_entry(genpd, &gpd_list, gpd_list_node)
...@@ -2235,7 +2266,7 @@ static DEFINE_MUTEX(of_genpd_mutex); ...@@ -2235,7 +2266,7 @@ static DEFINE_MUTEX(of_genpd_mutex);
* to be a valid pointer to struct generic_pm_domain. * to be a valid pointer to struct generic_pm_domain.
*/ */
static struct generic_pm_domain *genpd_xlate_simple( static struct generic_pm_domain *genpd_xlate_simple(
struct of_phandle_args *genpdspec, const struct of_phandle_args *genpdspec,
void *data) void *data)
{ {
return data; return data;
...@@ -2252,7 +2283,7 @@ static struct generic_pm_domain *genpd_xlate_simple( ...@@ -2252,7 +2283,7 @@ static struct generic_pm_domain *genpd_xlate_simple(
* the genpd_onecell_data struct when registering the provider. * the genpd_onecell_data struct when registering the provider.
*/ */
static struct generic_pm_domain *genpd_xlate_onecell( static struct generic_pm_domain *genpd_xlate_onecell(
struct of_phandle_args *genpdspec, const struct of_phandle_args *genpdspec,
void *data) void *data)
{ {
struct genpd_onecell_data *genpd_data = data; struct genpd_onecell_data *genpd_data = data;
...@@ -2495,7 +2526,7 @@ EXPORT_SYMBOL_GPL(of_genpd_del_provider); ...@@ -2495,7 +2526,7 @@ EXPORT_SYMBOL_GPL(of_genpd_del_provider);
* on failure. * on failure.
*/ */
static struct generic_pm_domain *genpd_get_from_provider( static struct generic_pm_domain *genpd_get_from_provider(
struct of_phandle_args *genpdspec) const struct of_phandle_args *genpdspec)
{ {
struct generic_pm_domain *genpd = ERR_PTR(-ENOENT); struct generic_pm_domain *genpd = ERR_PTR(-ENOENT);
struct of_genpd_provider *provider; struct of_genpd_provider *provider;
...@@ -2526,7 +2557,7 @@ static struct generic_pm_domain *genpd_get_from_provider( ...@@ -2526,7 +2557,7 @@ static struct generic_pm_domain *genpd_get_from_provider(
* Looks-up an I/O PM domain based upon phandle args provided and adds * Looks-up an I/O PM domain based upon phandle args provided and adds
* the device to the PM domain. Returns a negative error code on failure. * the device to the PM domain. Returns a negative error code on failure.
*/ */
int of_genpd_add_device(struct of_phandle_args *genpdspec, struct device *dev) int of_genpd_add_device(const struct of_phandle_args *genpdspec, struct device *dev)
{ {
struct generic_pm_domain *genpd; struct generic_pm_domain *genpd;
int ret; int ret;
...@@ -2560,8 +2591,8 @@ EXPORT_SYMBOL_GPL(of_genpd_add_device); ...@@ -2560,8 +2591,8 @@ EXPORT_SYMBOL_GPL(of_genpd_add_device);
* provided and adds the subdomain to the parent PM domain. Returns a * provided and adds the subdomain to the parent PM domain. Returns a
* negative error code on failure. * negative error code on failure.
*/ */
int of_genpd_add_subdomain(struct of_phandle_args *parent_spec, int of_genpd_add_subdomain(const struct of_phandle_args *parent_spec,
struct of_phandle_args *subdomain_spec) const struct of_phandle_args *subdomain_spec)
{ {
struct generic_pm_domain *parent, *subdomain; struct generic_pm_domain *parent, *subdomain;
int ret; int ret;
...@@ -2598,8 +2629,8 @@ EXPORT_SYMBOL_GPL(of_genpd_add_subdomain); ...@@ -2598,8 +2629,8 @@ EXPORT_SYMBOL_GPL(of_genpd_add_subdomain);
* provided and removes the subdomain from the parent PM domain. Returns a * provided and removes the subdomain from the parent PM domain. Returns a
* negative error code on failure. * negative error code on failure.
*/ */
int of_genpd_remove_subdomain(struct of_phandle_args *parent_spec, int of_genpd_remove_subdomain(const struct of_phandle_args *parent_spec,
struct of_phandle_args *subdomain_spec) const struct of_phandle_args *subdomain_spec)
{ {
struct generic_pm_domain *parent, *subdomain; struct generic_pm_domain *parent, *subdomain;
int ret; int ret;
......
...@@ -258,11 +258,14 @@ static int imx8m_blk_ctrl_probe(struct platform_device *pdev) ...@@ -258,11 +258,14 @@ static int imx8m_blk_ctrl_probe(struct platform_device *pdev)
domain->power_dev = domain->power_dev =
dev_pm_domain_attach_by_name(dev, data->gpc_name); dev_pm_domain_attach_by_name(dev, data->gpc_name);
if (IS_ERR(domain->power_dev)) { if (IS_ERR_OR_NULL(domain->power_dev)) {
dev_err_probe(dev, PTR_ERR(domain->power_dev), if (!domain->power_dev)
ret = -ENODEV;
else
ret = PTR_ERR(domain->power_dev);
dev_err_probe(dev, ret,
"failed to attach power domain \"%s\"\n", "failed to attach power domain \"%s\"\n",
data->gpc_name); data->gpc_name);
ret = PTR_ERR(domain->power_dev);
goto cleanup_pds; goto cleanup_pds;
} }
......
...@@ -55,7 +55,7 @@ struct imx8mp_blk_ctrl_domain_data { ...@@ -55,7 +55,7 @@ struct imx8mp_blk_ctrl_domain_data {
const char *gpc_name; const char *gpc_name;
}; };
#define DOMAIN_MAX_CLKS 2 #define DOMAIN_MAX_CLKS 3
#define DOMAIN_MAX_PATHS 3 #define DOMAIN_MAX_PATHS 3
struct imx8mp_blk_ctrl_domain { struct imx8mp_blk_ctrl_domain {
...@@ -457,8 +457,8 @@ static const struct imx8mp_blk_ctrl_domain_data imx8mp_hdmi_domain_data[] = { ...@@ -457,8 +457,8 @@ static const struct imx8mp_blk_ctrl_domain_data imx8mp_hdmi_domain_data[] = {
}, },
[IMX8MP_HDMIBLK_PD_LCDIF] = { [IMX8MP_HDMIBLK_PD_LCDIF] = {
.name = "hdmiblk-lcdif", .name = "hdmiblk-lcdif",
.clk_names = (const char *[]){ "axi", "apb" }, .clk_names = (const char *[]){ "axi", "apb", "fdcc" },
.num_clks = 2, .num_clks = 3,
.gpc_name = "lcdif", .gpc_name = "lcdif",
.path_names = (const char *[]){"lcdif-hdmi"}, .path_names = (const char *[]){"lcdif-hdmi"},
.num_paths = 1, .num_paths = 1,
...@@ -483,8 +483,8 @@ static const struct imx8mp_blk_ctrl_domain_data imx8mp_hdmi_domain_data[] = { ...@@ -483,8 +483,8 @@ static const struct imx8mp_blk_ctrl_domain_data imx8mp_hdmi_domain_data[] = {
}, },
[IMX8MP_HDMIBLK_PD_HDMI_TX] = { [IMX8MP_HDMIBLK_PD_HDMI_TX] = {
.name = "hdmiblk-hdmi-tx", .name = "hdmiblk-hdmi-tx",
.clk_names = (const char *[]){ "apb", "ref_266m" }, .clk_names = (const char *[]){ "apb", "ref_266m", "fdcc" },
.num_clks = 2, .num_clks = 3,
.gpc_name = "hdmi-tx", .gpc_name = "hdmi-tx",
}, },
[IMX8MP_HDMIBLK_PD_HDMI_TX_PHY] = { [IMX8MP_HDMIBLK_PD_HDMI_TX_PHY] = {
...@@ -687,11 +687,14 @@ static int imx8mp_blk_ctrl_probe(struct platform_device *pdev) ...@@ -687,11 +687,14 @@ static int imx8mp_blk_ctrl_probe(struct platform_device *pdev)
domain->power_dev = domain->power_dev =
dev_pm_domain_attach_by_name(dev, data->gpc_name); dev_pm_domain_attach_by_name(dev, data->gpc_name);
if (IS_ERR(domain->power_dev)) { if (IS_ERR_OR_NULL(domain->power_dev)) {
dev_err_probe(dev, PTR_ERR(domain->power_dev), if (!domain->power_dev)
ret = -ENODEV;
else
ret = PTR_ERR(domain->power_dev);
dev_err_probe(dev, ret,
"failed to attach power domain %s\n", "failed to attach power domain %s\n",
data->gpc_name); data->gpc_name);
ret = PTR_ERR(domain->power_dev);
goto cleanup_pds; goto cleanup_pds;
} }
......
...@@ -393,7 +393,7 @@ static int imx_sc_pd_power_off(struct generic_pm_domain *domain) ...@@ -393,7 +393,7 @@ static int imx_sc_pd_power_off(struct generic_pm_domain *domain)
return imx_sc_pd_power(domain, false); return imx_sc_pd_power(domain, false);
} }
static struct generic_pm_domain *imx_scu_pd_xlate(struct of_phandle_args *spec, static struct generic_pm_domain *imx_scu_pd_xlate(const struct of_phandle_args *spec,
void *data) void *data)
{ {
struct generic_pm_domain *domain = ERR_PTR(-ENOENT); struct generic_pm_domain *domain = ERR_PTR(-ENOENT);
......
...@@ -425,7 +425,6 @@ static struct scp *init_scp(struct platform_device *pdev, ...@@ -425,7 +425,6 @@ static struct scp *init_scp(struct platform_device *pdev,
bool bus_prot_reg_update) bool bus_prot_reg_update)
{ {
struct genpd_onecell_data *pd_data; struct genpd_onecell_data *pd_data;
struct resource *res;
int i, j; int i, j;
struct scp *scp; struct scp *scp;
struct clk *clk[CLK_MAX]; struct clk *clk[CLK_MAX];
...@@ -441,8 +440,7 @@ static struct scp *init_scp(struct platform_device *pdev, ...@@ -441,8 +440,7 @@ static struct scp *init_scp(struct platform_device *pdev,
scp->dev = &pdev->dev; scp->dev = &pdev->dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); scp->base = devm_platform_ioremap_resource(pdev, 0);
scp->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(scp->base)) if (IS_ERR(scp->base))
return ERR_CAST(scp->base); return ERR_CAST(scp->base);
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
#define domain_to_rpmpd(domain) container_of(domain, struct rpmpd, pd) #define domain_to_rpmpd(domain) container_of(domain, struct rpmpd, pd)
static struct qcom_smd_rpm *rpmpd_smd_rpm;
/* Resource types: /* Resource types:
* RPMPD_X is X encoded as a little-endian, lower-case, ASCII string */ * RPMPD_X is X encoded as a little-endian, lower-case, ASCII string */
#define RPMPD_SMPA 0x61706d73 #define RPMPD_SMPA 0x61706d73
...@@ -54,7 +56,6 @@ struct rpmpd { ...@@ -54,7 +56,6 @@ struct rpmpd {
bool enabled; bool enabled;
const int res_type; const int res_type;
const int res_id; const int res_id;
struct qcom_smd_rpm *rpm;
unsigned int max_state; unsigned int max_state;
__le32 key; __le32 key;
bool state_synced; bool state_synced;
...@@ -226,7 +227,46 @@ static struct rpmpd cx_s3a_vfl = { ...@@ -226,7 +227,46 @@ static struct rpmpd cx_s3a_vfl = {
.key = KEY_FLOOR_LEVEL, .key = KEY_FLOOR_LEVEL,
}; };
static struct rpmpd cx_s2b_corner_ao;
static struct rpmpd cx_s2b_corner = {
.pd = { .name = "cx", },
.peer = &cx_s2b_corner_ao,
.res_type = RPMPD_SMPB,
.res_id = 2,
.key = KEY_CORNER,
};
static struct rpmpd cx_s2b_corner_ao = {
.pd = { .name = "cx_ao", },
.peer = &cx_s2b_corner,
.active_only = true,
.res_type = RPMPD_SMPB,
.res_id = 2,
.key = KEY_CORNER,
};
static struct rpmpd cx_s2b_vfc = {
.pd = { .name = "cx_vfc", },
.res_type = RPMPD_SMPB,
.res_id = 2,
.key = KEY_FLOOR_CORNER,
};
/* G(F)X */ /* G(F)X */
static struct rpmpd gfx_s7a_corner = {
.pd = { .name = "gfx", },
.res_type = RPMPD_SMPA,
.res_id = 7,
.key = KEY_CORNER,
};
static struct rpmpd gfx_s7a_vfc = {
.pd = { .name = "gfx_vfc", },
.res_type = RPMPD_SMPA,
.res_id = 7,
.key = KEY_FLOOR_CORNER,
};
static struct rpmpd gfx_s2b_corner = { static struct rpmpd gfx_s2b_corner = {
.pd = { .name = "gfx", }, .pd = { .name = "gfx", },
.res_type = RPMPD_SMPB, .res_type = RPMPD_SMPB,
...@@ -241,6 +281,20 @@ static struct rpmpd gfx_s2b_vfc = { ...@@ -241,6 +281,20 @@ static struct rpmpd gfx_s2b_vfc = {
.key = KEY_FLOOR_CORNER, .key = KEY_FLOOR_CORNER,
}; };
static struct rpmpd gfx_s4b_corner = {
.pd = { .name = "gfx", },
.res_type = RPMPD_SMPB,
.res_id = 4,
.key = KEY_CORNER,
};
static struct rpmpd gfx_s4b_vfc = {
.pd = { .name = "gfx_vfc", },
.res_type = RPMPD_SMPB,
.res_id = 4,
.key = KEY_FLOOR_CORNER,
};
static struct rpmpd mx_rwmx0_lvl; static struct rpmpd mx_rwmx0_lvl;
static struct rpmpd gx_rwgx0_lvl_ao; static struct rpmpd gx_rwgx0_lvl_ao;
static struct rpmpd gx_rwgx0_lvl = { static struct rpmpd gx_rwgx0_lvl = {
...@@ -663,6 +717,34 @@ static const struct rpmpd_desc msm8953_desc = { ...@@ -663,6 +717,34 @@ static const struct rpmpd_desc msm8953_desc = {
.max_state = RPM_SMD_LEVEL_TURBO, .max_state = RPM_SMD_LEVEL_TURBO,
}; };
static struct rpmpd *msm8974_rpmpds[] = {
[MSM8974_VDDCX] = &cx_s2b_corner,
[MSM8974_VDDCX_AO] = &cx_s2b_corner_ao,
[MSM8974_VDDCX_VFC] = &cx_s2b_vfc,
[MSM8974_VDDGFX] = &gfx_s4b_corner,
[MSM8974_VDDGFX_VFC] = &gfx_s4b_vfc,
};
static const struct rpmpd_desc msm8974_desc = {
.rpmpds = msm8974_rpmpds,
.num_pds = ARRAY_SIZE(msm8974_rpmpds),
.max_state = MAX_CORNER_RPMPD_STATE,
};
static struct rpmpd *msm8974pro_pma8084_rpmpds[] = {
[MSM8974_VDDCX] = &cx_s2a_corner,
[MSM8974_VDDCX_AO] = &cx_s2a_corner_ao,
[MSM8974_VDDCX_VFC] = &cx_s2a_vfc,
[MSM8974_VDDGFX] = &gfx_s7a_corner,
[MSM8974_VDDGFX_VFC] = &gfx_s7a_vfc,
};
static const struct rpmpd_desc msm8974pro_pma8084_desc = {
.rpmpds = msm8974pro_pma8084_rpmpds,
.num_pds = ARRAY_SIZE(msm8974pro_pma8084_rpmpds),
.max_state = MAX_CORNER_RPMPD_STATE,
};
static struct rpmpd *msm8976_rpmpds[] = { static struct rpmpd *msm8976_rpmpds[] = {
[MSM8976_VDDCX] = &cx_s2a_lvl, [MSM8976_VDDCX] = &cx_s2a_lvl,
[MSM8976_VDDCX_AO] = &cx_s2a_lvl_ao, [MSM8976_VDDCX_AO] = &cx_s2a_lvl_ao,
...@@ -856,6 +938,8 @@ static const struct of_device_id rpmpd_match_table[] = { ...@@ -856,6 +938,8 @@ static const struct of_device_id rpmpd_match_table[] = {
{ .compatible = "qcom,msm8917-rpmpd", .data = &msm8917_desc }, { .compatible = "qcom,msm8917-rpmpd", .data = &msm8917_desc },
{ .compatible = "qcom,msm8939-rpmpd", .data = &msm8939_desc }, { .compatible = "qcom,msm8939-rpmpd", .data = &msm8939_desc },
{ .compatible = "qcom,msm8953-rpmpd", .data = &msm8953_desc }, { .compatible = "qcom,msm8953-rpmpd", .data = &msm8953_desc },
{ .compatible = "qcom,msm8974-rpmpd", .data = &msm8974_desc },
{ .compatible = "qcom,msm8974pro-pma8084-rpmpd", .data = &msm8974pro_pma8084_desc },
{ .compatible = "qcom,msm8976-rpmpd", .data = &msm8976_desc }, { .compatible = "qcom,msm8976-rpmpd", .data = &msm8976_desc },
{ .compatible = "qcom,msm8994-rpmpd", .data = &msm8994_desc }, { .compatible = "qcom,msm8994-rpmpd", .data = &msm8994_desc },
{ .compatible = "qcom,msm8996-rpmpd", .data = &msm8996_desc }, { .compatible = "qcom,msm8996-rpmpd", .data = &msm8996_desc },
...@@ -879,7 +963,7 @@ static int rpmpd_send_enable(struct rpmpd *pd, bool enable) ...@@ -879,7 +963,7 @@ static int rpmpd_send_enable(struct rpmpd *pd, bool enable)
.value = cpu_to_le32(enable), .value = cpu_to_le32(enable),
}; };
return qcom_rpm_smd_write(pd->rpm, QCOM_SMD_RPM_ACTIVE_STATE, return qcom_rpm_smd_write(rpmpd_smd_rpm, QCOM_SMD_RPM_ACTIVE_STATE,
pd->res_type, pd->res_id, &req, sizeof(req)); pd->res_type, pd->res_id, &req, sizeof(req));
} }
...@@ -891,7 +975,7 @@ static int rpmpd_send_corner(struct rpmpd *pd, int state, unsigned int corner) ...@@ -891,7 +975,7 @@ static int rpmpd_send_corner(struct rpmpd *pd, int state, unsigned int corner)
.value = cpu_to_le32(corner), .value = cpu_to_le32(corner),
}; };
return qcom_rpm_smd_write(pd->rpm, state, pd->res_type, pd->res_id, return qcom_rpm_smd_write(rpmpd_smd_rpm, state, pd->res_type, pd->res_id,
&req, sizeof(req)); &req, sizeof(req));
}; };
...@@ -1004,12 +1088,11 @@ static int rpmpd_probe(struct platform_device *pdev) ...@@ -1004,12 +1088,11 @@ static int rpmpd_probe(struct platform_device *pdev)
int i; int i;
size_t num; size_t num;
struct genpd_onecell_data *data; struct genpd_onecell_data *data;
struct qcom_smd_rpm *rpm;
struct rpmpd **rpmpds; struct rpmpd **rpmpds;
const struct rpmpd_desc *desc; const struct rpmpd_desc *desc;
rpm = dev_get_drvdata(pdev->dev.parent); rpmpd_smd_rpm = dev_get_drvdata(pdev->dev.parent);
if (!rpm) { if (!rpmpd_smd_rpm) {
dev_err(&pdev->dev, "Unable to retrieve handle to RPM\n"); dev_err(&pdev->dev, "Unable to retrieve handle to RPM\n");
return -ENODEV; return -ENODEV;
} }
...@@ -1039,7 +1122,6 @@ static int rpmpd_probe(struct platform_device *pdev) ...@@ -1039,7 +1122,6 @@ static int rpmpd_probe(struct platform_device *pdev)
continue; continue;
} }
rpmpds[i]->rpm = rpm;
rpmpds[i]->max_state = desc->max_state; rpmpds[i]->max_state = desc->max_state;
rpmpds[i]->pd.power_off = rpmpd_power_off; rpmpds[i]->pd.power_off = rpmpd_power_off;
rpmpds[i]->pd.power_on = rpmpd_power_on; rpmpds[i]->pd.power_on = rpmpd_power_on;
......
...@@ -71,6 +71,10 @@ config SYSC_R8A779G0 ...@@ -71,6 +71,10 @@ config SYSC_R8A779G0
bool "System Controller support for R-Car V4H" if COMPILE_TEST bool "System Controller support for R-Car V4H" if COMPILE_TEST
select SYSC_RCAR_GEN4 select SYSC_RCAR_GEN4
config SYSC_R8A779H0
bool "System Controller support for R-Car V4M" if COMPILE_TEST
select SYSC_RCAR_GEN4
config SYSC_RMOBILE config SYSC_RMOBILE
bool "System Controller support for R-Mobile" if COMPILE_TEST bool "System Controller support for R-Mobile" if COMPILE_TEST
......
...@@ -24,6 +24,7 @@ obj-$(CONFIG_SYSC_R8A77995) += r8a77995-sysc.o ...@@ -24,6 +24,7 @@ obj-$(CONFIG_SYSC_R8A77995) += r8a77995-sysc.o
obj-$(CONFIG_SYSC_R8A779A0) += r8a779a0-sysc.o obj-$(CONFIG_SYSC_R8A779A0) += r8a779a0-sysc.o
obj-$(CONFIG_SYSC_R8A779F0) += r8a779f0-sysc.o obj-$(CONFIG_SYSC_R8A779F0) += r8a779f0-sysc.o
obj-$(CONFIG_SYSC_R8A779G0) += r8a779g0-sysc.o obj-$(CONFIG_SYSC_R8A779G0) += r8a779g0-sysc.o
obj-$(CONFIG_SYSC_R8A779H0) += r8a779h0-sysc.o
# Family # Family
obj-$(CONFIG_SYSC_RCAR) += rcar-sysc.o obj-$(CONFIG_SYSC_RCAR) += rcar-sysc.o
obj-$(CONFIG_SYSC_RCAR_GEN4) += rcar-gen4-sysc.o obj-$(CONFIG_SYSC_RCAR_GEN4) += rcar-gen4-sysc.o
......
...@@ -5,19 +5,7 @@ ...@@ -5,19 +5,7 @@
* Copyright (C) 2020 Renesas Electronics Corp. * Copyright (C) 2020 Renesas Electronics Corp.
*/ */
#include <linux/bits.h>
#include <linux/clk/renesas.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/of_address.h>
#include <linux/pm_domain.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <dt-bindings/power/r8a779a0-sysc.h> #include <dt-bindings/power/r8a779a0-sysc.h>
......
...@@ -5,19 +5,7 @@ ...@@ -5,19 +5,7 @@
* Copyright (C) 2021 Renesas Electronics Corp. * Copyright (C) 2021 Renesas Electronics Corp.
*/ */
#include <linux/bits.h>
#include <linux/clk/renesas.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/of_address.h>
#include <linux/pm_domain.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <dt-bindings/power/r8a779f0-sysc.h> #include <dt-bindings/power/r8a779f0-sysc.h>
......
...@@ -5,19 +5,7 @@ ...@@ -5,19 +5,7 @@
* Copyright (C) 2022 Renesas Electronics Corp. * Copyright (C) 2022 Renesas Electronics Corp.
*/ */
#include <linux/bits.h>
#include <linux/clk/renesas.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/of_address.h>
#include <linux/pm_domain.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <dt-bindings/power/r8a779g0-sysc.h> #include <dt-bindings/power/r8a779g0-sysc.h>
......
// SPDX-License-Identifier: GPL-2.0
/*
* Renesas R-Car V4M System Controller
*
* Copyright (C) 2023 Renesas Electronics Corp
*/
#include <linux/kernel.h>
#include <dt-bindings/power/renesas,r8a779h0-sysc.h>
#include "rcar-gen4-sysc.h"
static struct rcar_gen4_sysc_area r8a779h0_areas[] __initdata = {
{ "always-on", R8A779H0_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
{ "c4", R8A779H0_PD_C4, R8A779H0_PD_ALWAYS_ON },
{ "a2e0d0", R8A779H0_PD_A2E0D0, R8A779H0_PD_C4, PD_SCU },
{ "a1e0d0c0", R8A779H0_PD_A1E0D0C0, R8A779H0_PD_A2E0D0, PD_CPU_NOCR },
{ "a1e0d0c1", R8A779H0_PD_A1E0D0C1, R8A779H0_PD_A2E0D0, PD_CPU_NOCR },
{ "a1e0d0c2", R8A779H0_PD_A1E0D0C2, R8A779H0_PD_A2E0D0, PD_CPU_NOCR },
{ "a1e0d0c3", R8A779H0_PD_A1E0D0C3, R8A779H0_PD_A2E0D0, PD_CPU_NOCR },
{ "a3cr0", R8A779H0_PD_A3CR0, R8A779H0_PD_ALWAYS_ON, PD_CPU_NOCR },
{ "a3cr1", R8A779H0_PD_A3CR1, R8A779H0_PD_ALWAYS_ON, PD_CPU_NOCR },
{ "a3cr2", R8A779H0_PD_A3CR2, R8A779H0_PD_ALWAYS_ON, PD_CPU_NOCR },
{ "a33dga", R8A779H0_PD_A33DGA, R8A779H0_PD_C4 },
{ "a23dgb", R8A779H0_PD_A23DGB, R8A779H0_PD_A33DGA },
{ "a3vip0", R8A779H0_PD_A3VIP0, R8A779H0_PD_C4 },
{ "a3vip2", R8A779H0_PD_A3VIP2, R8A779H0_PD_C4 },
{ "a3dul", R8A779H0_PD_A3DUL, R8A779H0_PD_C4 },
{ "a3isp0", R8A779H0_PD_A3ISP0, R8A779H0_PD_C4 },
{ "a2cn0", R8A779H0_PD_A2CN0, R8A779H0_PD_C4 },
{ "a1cn0", R8A779H0_PD_A1CN0, R8A779H0_PD_A2CN0 },
{ "a1dsp0", R8A779H0_PD_A1DSP0, R8A779H0_PD_A2CN0 },
{ "a1dsp1", R8A779H0_PD_A1DSP1, R8A779H0_PD_A2CN0 },
{ "a2imp01", R8A779H0_PD_A2IMP01, R8A779H0_PD_C4 },
{ "a2psc", R8A779H0_PD_A2PSC, R8A779H0_PD_C4 },
{ "a2dma", R8A779H0_PD_A2DMA, R8A779H0_PD_C4 },
{ "a2cv0", R8A779H0_PD_A2CV0, R8A779H0_PD_C4 },
{ "a2cv1", R8A779H0_PD_A2CV1, R8A779H0_PD_C4 },
{ "a2cv2", R8A779H0_PD_A2CV2, R8A779H0_PD_C4 },
{ "a2cv3", R8A779H0_PD_A2CV3, R8A779H0_PD_C4 },
{ "a3imr0", R8A779H0_PD_A3IMR0, R8A779H0_PD_C4 },
{ "a3imr1", R8A779H0_PD_A3IMR1, R8A779H0_PD_C4 },
{ "a3imr2", R8A779H0_PD_A3IMR2, R8A779H0_PD_C4 },
{ "a3imr3", R8A779H0_PD_A3IMR3, R8A779H0_PD_C4 },
{ "a3vc", R8A779H0_PD_A3VC, R8A779H0_PD_C4 },
{ "a3pci", R8A779H0_PD_A3PCI, R8A779H0_PD_C4 },
{ "a2pciphy", R8A779H0_PD_A2PCIPHY, R8A779H0_PD_A3PCI },
};
const struct rcar_gen4_sysc_info r8a779h0_sysc_info __initconst = {
.areas = r8a779h0_areas,
.num_areas = ARRAY_SIZE(r8a779h0_areas),
};
...@@ -50,13 +50,13 @@ ...@@ -50,13 +50,13 @@
#define SYSCSR_BUSY GENMASK(1, 0) /* All bit sets is not busy */ #define SYSCSR_BUSY GENMASK(1, 0) /* All bit sets is not busy */
#define SYSCSR_TIMEOUT 10000 #define SYSCSR_TIMEOUT 10000
#define SYSCSR_DELAY_US 10 #define SYSCSR_DELAY_US 1
#define PDRESR_RETRIES 1000 #define PDRESR_RETRIES 10000
#define PDRESR_DELAY_US 10 #define PDRESR_DELAY_US 1
#define SYSCISR_TIMEOUT 10000 #define SYSCISCR_TIMEOUT 10000
#define SYSCISR_DELAY_US 10 #define SYSCISCR_DELAY_US 1
#define RCAR_GEN4_PD_ALWAYS_ON 64 #define RCAR_GEN4_PD_ALWAYS_ON 64
#define NUM_DOMAINS_EACH_REG BITS_PER_TYPE(u32) #define NUM_DOMAINS_EACH_REG BITS_PER_TYPE(u32)
...@@ -97,7 +97,7 @@ static int clear_irq_flags(unsigned int reg_idx, unsigned int isr_mask) ...@@ -97,7 +97,7 @@ static int clear_irq_flags(unsigned int reg_idx, unsigned int isr_mask)
ret = readl_poll_timeout_atomic(rcar_gen4_sysc_base + SYSCISCR(reg_idx), ret = readl_poll_timeout_atomic(rcar_gen4_sysc_base + SYSCISCR(reg_idx),
val, !(val & isr_mask), val, !(val & isr_mask),
SYSCISR_DELAY_US, SYSCISR_TIMEOUT); SYSCISCR_DELAY_US, SYSCISCR_TIMEOUT);
if (ret < 0) { if (ret < 0) {
pr_err("\n %s : Can not clear IRQ flags in SYSCISCR", __func__); pr_err("\n %s : Can not clear IRQ flags in SYSCISCR", __func__);
return -EIO; return -EIO;
...@@ -157,7 +157,7 @@ static int rcar_gen4_sysc_power(u8 pdr, bool on) ...@@ -157,7 +157,7 @@ static int rcar_gen4_sysc_power(u8 pdr, bool on)
/* Wait until the power shutoff or resume request has completed * */ /* Wait until the power shutoff or resume request has completed * */
ret = readl_poll_timeout_atomic(rcar_gen4_sysc_base + SYSCISCR(reg_idx), ret = readl_poll_timeout_atomic(rcar_gen4_sysc_base + SYSCISCR(reg_idx),
val, (val & isr_mask), val, (val & isr_mask),
SYSCISR_DELAY_US, SYSCISR_TIMEOUT); SYSCISCR_DELAY_US, SYSCISCR_TIMEOUT);
if (ret < 0) { if (ret < 0) {
ret = -EIO; ret = -EIO;
goto out; goto out;
...@@ -284,6 +284,9 @@ static const struct of_device_id rcar_gen4_sysc_matches[] __initconst = { ...@@ -284,6 +284,9 @@ static const struct of_device_id rcar_gen4_sysc_matches[] __initconst = {
#endif #endif
#ifdef CONFIG_SYSC_R8A779G0 #ifdef CONFIG_SYSC_R8A779G0
{ .compatible = "renesas,r8a779g0-sysc", .data = &r8a779g0_sysc_info }, { .compatible = "renesas,r8a779g0-sysc", .data = &r8a779g0_sysc_info },
#endif
#ifdef CONFIG_SYSC_R8A779H0
{ .compatible = "renesas,r8a779h0-sysc", .data = &r8a779h0_sysc_info },
#endif #endif
{ /* sentinel */ } { /* sentinel */ }
}; };
......
...@@ -40,5 +40,6 @@ struct rcar_gen4_sysc_info { ...@@ -40,5 +40,6 @@ struct rcar_gen4_sysc_info {
extern const struct rcar_gen4_sysc_info r8a779a0_sysc_info; extern const struct rcar_gen4_sysc_info r8a779a0_sysc_info;
extern const struct rcar_gen4_sysc_info r8a779f0_sysc_info; extern const struct rcar_gen4_sysc_info r8a779f0_sysc_info;
extern const struct rcar_gen4_sysc_info r8a779g0_sysc_info; extern const struct rcar_gen4_sysc_info r8a779g0_sysc_info;
extern const struct rcar_gen4_sysc_info r8a779h0_sysc_info;
#endif /* __SOC_RENESAS_RCAR_GEN4_SYSC_H__ */ #endif /* __SOC_RENESAS_RCAR_GEN4_SYSC_H__ */
...@@ -45,10 +45,10 @@ ...@@ -45,10 +45,10 @@
#define PWRER_OFFS 0x14 /* Power Shutoff/Resume Error */ #define PWRER_OFFS 0x14 /* Power Shutoff/Resume Error */
#define SYSCSR_TIMEOUT 100 #define SYSCSR_TIMEOUT 1000
#define SYSCSR_DELAY_US 1 #define SYSCSR_DELAY_US 1
#define PWRER_RETRIES 100 #define PWRER_RETRIES 1000
#define PWRER_DELAY_US 1 #define PWRER_DELAY_US 1
#define SYSCISR_TIMEOUT 1000 #define SYSCISR_TIMEOUT 1000
......
...@@ -305,7 +305,7 @@ static void tegra_bpmp_remove_powergates(struct tegra_bpmp *bpmp) ...@@ -305,7 +305,7 @@ static void tegra_bpmp_remove_powergates(struct tegra_bpmp *bpmp)
} }
static struct generic_pm_domain * static struct generic_pm_domain *
tegra_powergate_xlate(struct of_phandle_args *spec, void *data) tegra_powergate_xlate(const struct of_phandle_args *spec, void *data)
{ {
struct generic_pm_domain *domain = ERR_PTR(-ENOENT); struct generic_pm_domain *domain = ERR_PTR(-ENOENT);
struct genpd_onecell_data *genpd = data; struct genpd_onecell_data *genpd = data;
......
...@@ -695,6 +695,8 @@ static int omap_prm_domain_init(struct device *dev, struct omap_prm *prm) ...@@ -695,6 +695,8 @@ static int omap_prm_domain_init(struct device *dev, struct omap_prm *prm)
data = prm->data; data = prm->data;
name = devm_kasprintf(dev, GFP_KERNEL, "prm_%s", name = devm_kasprintf(dev, GFP_KERNEL, "prm_%s",
data->name); data->name);
if (!name)
return -ENOMEM;
prmd->dev = dev; prmd->dev = dev;
prmd->prm = prm; prmd->prm = prm;
......
...@@ -85,7 +85,7 @@ static int ti_sci_pd_power_on(struct generic_pm_domain *domain) ...@@ -85,7 +85,7 @@ static int ti_sci_pd_power_on(struct generic_pm_domain *domain)
* @data: genpd core data for all the powerdomains on the device * @data: genpd core data for all the powerdomains on the device
*/ */
static struct generic_pm_domain *ti_sci_pd_xlate( static struct generic_pm_domain *ti_sci_pd_xlate(
struct of_phandle_args *genpdspec, const struct of_phandle_args *genpdspec,
void *data) void *data)
{ {
struct genpd_onecell_data *genpd_data = data; struct genpd_onecell_data *genpd_data = data;
......
...@@ -210,7 +210,7 @@ static void zynqmp_gpd_detach_dev(struct generic_pm_domain *domain, ...@@ -210,7 +210,7 @@ static void zynqmp_gpd_detach_dev(struct generic_pm_domain *domain,
} }
static struct generic_pm_domain *zynqmp_gpd_xlate static struct generic_pm_domain *zynqmp_gpd_xlate
(struct of_phandle_args *genpdspec, void *data) (const struct of_phandle_args *genpdspec, void *data)
{ {
struct genpd_onecell_data *genpd_data = data; struct genpd_onecell_data *genpd_data = data;
unsigned int i, idx = genpdspec->args[0]; unsigned int i, idx = genpdspec->args[0];
......
...@@ -103,12 +103,10 @@ enum imx_dsp_rp_mbox_messages { ...@@ -103,12 +103,10 @@ enum imx_dsp_rp_mbox_messages {
* @tx_ch: mailbox tx channel handle * @tx_ch: mailbox tx channel handle
* @rx_ch: mailbox rx channel handle * @rx_ch: mailbox rx channel handle
* @rxdb_ch: mailbox rx doorbell channel handle * @rxdb_ch: mailbox rx doorbell channel handle
* @pd_dev: power domain device * @pd_list: power domain list
* @pd_dev_link: power domain device link
* @ipc_handle: System Control Unit ipc handle * @ipc_handle: System Control Unit ipc handle
* @rproc_work: work for processing virtio interrupts * @rproc_work: work for processing virtio interrupts
* @pm_comp: completion primitive to sync for suspend response * @pm_comp: completion primitive to sync for suspend response
* @num_domains: power domain number
* @flags: control flags * @flags: control flags
*/ */
struct imx_dsp_rproc { struct imx_dsp_rproc {
...@@ -121,12 +119,10 @@ struct imx_dsp_rproc { ...@@ -121,12 +119,10 @@ struct imx_dsp_rproc {
struct mbox_chan *tx_ch; struct mbox_chan *tx_ch;
struct mbox_chan *rx_ch; struct mbox_chan *rx_ch;
struct mbox_chan *rxdb_ch; struct mbox_chan *rxdb_ch;
struct device **pd_dev; struct dev_pm_domain_list *pd_list;
struct device_link **pd_dev_link;
struct imx_sc_ipc *ipc_handle; struct imx_sc_ipc *ipc_handle;
struct work_struct rproc_work; struct work_struct rproc_work;
struct completion pm_comp; struct completion pm_comp;
int num_domains;
u32 flags; u32 flags;
}; };
...@@ -955,74 +951,14 @@ static const struct rproc_ops imx_dsp_rproc_ops = { ...@@ -955,74 +951,14 @@ static const struct rproc_ops imx_dsp_rproc_ops = {
static int imx_dsp_attach_pm_domains(struct imx_dsp_rproc *priv) static int imx_dsp_attach_pm_domains(struct imx_dsp_rproc *priv)
{ {
struct device *dev = priv->rproc->dev.parent; struct device *dev = priv->rproc->dev.parent;
int ret, i; int ret;
priv->num_domains = of_count_phandle_with_args(dev->of_node,
"power-domains",
"#power-domain-cells");
/* If only one domain, then no need to link the device */
if (priv->num_domains <= 1)
return 0;
priv->pd_dev = devm_kmalloc_array(dev, priv->num_domains,
sizeof(*priv->pd_dev),
GFP_KERNEL);
if (!priv->pd_dev)
return -ENOMEM;
priv->pd_dev_link = devm_kmalloc_array(dev, priv->num_domains,
sizeof(*priv->pd_dev_link),
GFP_KERNEL);
if (!priv->pd_dev_link)
return -ENOMEM;
for (i = 0; i < priv->num_domains; i++) {
priv->pd_dev[i] = dev_pm_domain_attach_by_id(dev, i);
if (IS_ERR(priv->pd_dev[i])) {
ret = PTR_ERR(priv->pd_dev[i]);
goto detach_pm;
}
/*
* device_link_add will check priv->pd_dev[i], if it is
* NULL, then will break.
*/
priv->pd_dev_link[i] = device_link_add(dev,
priv->pd_dev[i],
DL_FLAG_STATELESS |
DL_FLAG_PM_RUNTIME);
if (!priv->pd_dev_link[i]) {
dev_pm_domain_detach(priv->pd_dev[i], false);
ret = -EINVAL;
goto detach_pm;
}
}
return 0;
detach_pm:
while (--i >= 0) {
device_link_del(priv->pd_dev_link[i]);
dev_pm_domain_detach(priv->pd_dev[i], false);
}
return ret;
}
static int imx_dsp_detach_pm_domains(struct imx_dsp_rproc *priv)
{
int i;
if (priv->num_domains <= 1) /* A single PM domain is already attached. */
if (dev->pm_domain)
return 0; return 0;
for (i = 0; i < priv->num_domains; i++) { ret = dev_pm_domain_attach_list(dev, NULL, &priv->pd_list);
device_link_del(priv->pd_dev_link[i]); return ret < 0 ? ret : 0;
dev_pm_domain_detach(priv->pd_dev[i], false);
}
return 0;
} }
/** /**
...@@ -1154,7 +1090,7 @@ static int imx_dsp_rproc_probe(struct platform_device *pdev) ...@@ -1154,7 +1090,7 @@ static int imx_dsp_rproc_probe(struct platform_device *pdev)
return 0; return 0;
err_detach_domains: err_detach_domains:
imx_dsp_detach_pm_domains(priv); dev_pm_domain_detach_list(priv->pd_list);
err_put_rproc: err_put_rproc:
rproc_free(rproc); rproc_free(rproc);
...@@ -1168,7 +1104,7 @@ static void imx_dsp_rproc_remove(struct platform_device *pdev) ...@@ -1168,7 +1104,7 @@ static void imx_dsp_rproc_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
rproc_del(rproc); rproc_del(rproc);
imx_dsp_detach_pm_domains(priv); dev_pm_domain_detach_list(priv->pd_list);
rproc_free(rproc); rproc_free(rproc);
} }
......
...@@ -92,7 +92,6 @@ struct imx_rproc_mem { ...@@ -92,7 +92,6 @@ struct imx_rproc_mem {
static int imx_rproc_xtr_mbox_init(struct rproc *rproc); static int imx_rproc_xtr_mbox_init(struct rproc *rproc);
static void imx_rproc_free_mbox(struct rproc *rproc); static void imx_rproc_free_mbox(struct rproc *rproc);
static int imx_rproc_detach_pd(struct rproc *rproc);
struct imx_rproc { struct imx_rproc {
struct device *dev; struct device *dev;
...@@ -113,10 +112,8 @@ struct imx_rproc { ...@@ -113,10 +112,8 @@ struct imx_rproc {
u32 rproc_pt; /* partition id */ u32 rproc_pt; /* partition id */
u32 rsrc_id; /* resource id */ u32 rsrc_id; /* resource id */
u32 entry; /* cpu start address */ u32 entry; /* cpu start address */
int num_pd;
u32 core_index; u32 core_index;
struct device **pd_dev; struct dev_pm_domain_list *pd_list;
struct device_link **pd_dev_link;
}; };
static const struct imx_rproc_att imx_rproc_att_imx93[] = { static const struct imx_rproc_att imx_rproc_att_imx93[] = {
...@@ -853,7 +850,7 @@ static void imx_rproc_put_scu(struct rproc *rproc) ...@@ -853,7 +850,7 @@ static void imx_rproc_put_scu(struct rproc *rproc)
return; return;
if (imx_sc_rm_is_resource_owned(priv->ipc_handle, priv->rsrc_id)) { if (imx_sc_rm_is_resource_owned(priv->ipc_handle, priv->rsrc_id)) {
imx_rproc_detach_pd(rproc); dev_pm_domain_detach_list(priv->pd_list);
return; return;
} }
...@@ -880,72 +877,20 @@ static int imx_rproc_partition_notify(struct notifier_block *nb, ...@@ -880,72 +877,20 @@ static int imx_rproc_partition_notify(struct notifier_block *nb,
static int imx_rproc_attach_pd(struct imx_rproc *priv) static int imx_rproc_attach_pd(struct imx_rproc *priv)
{ {
struct device *dev = priv->dev; struct device *dev = priv->dev;
int ret, i; int ret;
struct dev_pm_domain_attach_data pd_data = {
/* .pd_flags = PD_FLAG_DEV_LINK_ON,
* If there is only one power-domain entry, the platform driver framework };
* will handle it, no need handle it in this driver.
*/
priv->num_pd = of_count_phandle_with_args(dev->of_node, "power-domains",
"#power-domain-cells");
if (priv->num_pd <= 1)
return 0;
priv->pd_dev = devm_kmalloc_array(dev, priv->num_pd, sizeof(*priv->pd_dev), GFP_KERNEL);
if (!priv->pd_dev)
return -ENOMEM;
priv->pd_dev_link = devm_kmalloc_array(dev, priv->num_pd, sizeof(*priv->pd_dev_link),
GFP_KERNEL);
if (!priv->pd_dev_link)
return -ENOMEM;
for (i = 0; i < priv->num_pd; i++) {
priv->pd_dev[i] = dev_pm_domain_attach_by_id(dev, i);
if (IS_ERR(priv->pd_dev[i])) {
ret = PTR_ERR(priv->pd_dev[i]);
goto detach_pd;
}
priv->pd_dev_link[i] = device_link_add(dev, priv->pd_dev[i], DL_FLAG_STATELESS |
DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE);
if (!priv->pd_dev_link[i]) {
dev_pm_domain_detach(priv->pd_dev[i], false);
ret = -EINVAL;
goto detach_pd;
}
}
return 0;
detach_pd:
while (--i >= 0) {
device_link_del(priv->pd_dev_link[i]);
dev_pm_domain_detach(priv->pd_dev[i], false);
}
return ret;
}
static int imx_rproc_detach_pd(struct rproc *rproc)
{
struct imx_rproc *priv = rproc->priv;
int i;
/* /*
* If there is only one power-domain entry, the platform driver framework * If there is only one power-domain entry, the platform driver framework
* will handle it, no need handle it in this driver. * will handle it, no need handle it in this driver.
*/ */
if (priv->num_pd <= 1) if (dev->pm_domain)
return 0; return 0;
for (i = 0; i < priv->num_pd; i++) { ret = dev_pm_domain_attach_list(dev, &pd_data, &priv->pd_list);
device_link_del(priv->pd_dev_link[i]); return ret < 0 ? ret : 0;
dev_pm_domain_detach(priv->pd_dev[i], false);
}
return 0;
} }
static int imx_rproc_detect_mode(struct imx_rproc *priv) static int imx_rproc_detect_mode(struct imx_rproc *priv)
......
...@@ -55,8 +55,6 @@ ...@@ -55,8 +55,6 @@
#define QDSP6SS_CORE_CBCR 0x20 #define QDSP6SS_CORE_CBCR 0x20
#define QDSP6SS_SLEEP_CBCR 0x3c #define QDSP6SS_SLEEP_CBCR 0x3c
#define QCOM_Q6V5_RPROC_PROXY_PD_MAX 3
#define LPASS_BOOT_CORE_START BIT(0) #define LPASS_BOOT_CORE_START BIT(0)
#define LPASS_BOOT_CMD_START BIT(0) #define LPASS_BOOT_CMD_START BIT(0)
#define LPASS_EFUSE_Q6SS_EVB_SEL 0x0 #define LPASS_EFUSE_Q6SS_EVB_SEL 0x0
...@@ -74,7 +72,8 @@ struct adsp_pil_data { ...@@ -74,7 +72,8 @@ struct adsp_pil_data {
const char **clk_ids; const char **clk_ids;
int num_clks; int num_clks;
const char **proxy_pd_names; const char **pd_names;
unsigned int num_pds;
const char *load_state; const char *load_state;
}; };
...@@ -110,8 +109,7 @@ struct qcom_adsp { ...@@ -110,8 +109,7 @@ struct qcom_adsp {
size_t mem_size; size_t mem_size;
bool has_iommu; bool has_iommu;
struct device *proxy_pds[QCOM_Q6V5_RPROC_PROXY_PD_MAX]; struct dev_pm_domain_list *pd_list;
size_t proxy_pd_count;
struct qcom_rproc_glink glink_subdev; struct qcom_rproc_glink glink_subdev;
struct qcom_rproc_ssr ssr_subdev; struct qcom_rproc_ssr ssr_subdev;
...@@ -120,98 +118,92 @@ struct qcom_adsp { ...@@ -120,98 +118,92 @@ struct qcom_adsp {
int (*shutdown)(struct qcom_adsp *adsp); int (*shutdown)(struct qcom_adsp *adsp);
}; };
static int qcom_rproc_pds_attach(struct device *dev, struct qcom_adsp *adsp, static int qcom_rproc_pds_attach(struct qcom_adsp *adsp, const char **pd_names,
const char **pd_names) unsigned int num_pds)
{ {
struct device **devs = adsp->proxy_pds; struct device *dev = adsp->dev;
size_t num_pds = 0; struct dev_pm_domain_attach_data pd_data = {
.pd_names = pd_names,
.num_pd_names = num_pds,
};
int ret; int ret;
int i;
if (!pd_names)
return 0;
/* Handle single power domain */ /* Handle single power domain */
if (dev->pm_domain) { if (dev->pm_domain)
devs[0] = dev; goto out;
pm_runtime_enable(dev);
return 1;
}
while (pd_names[num_pds]) if (!pd_names)
num_pds++; return 0;
if (num_pds > ARRAY_SIZE(adsp->proxy_pds)) ret = dev_pm_domain_attach_list(dev, &pd_data, &adsp->pd_list);
return -E2BIG; if (ret < 0)
return ret;
for (i = 0; i < num_pds; i++) { out:
devs[i] = dev_pm_domain_attach_by_name(dev, pd_names[i]); pm_runtime_enable(dev);
if (IS_ERR_OR_NULL(devs[i])) { return 0;
ret = PTR_ERR(devs[i]) ? : -ENODATA; }
goto unroll_attach;
}
}
return num_pds; static void qcom_rproc_pds_detach(struct qcom_adsp *adsp)
{
struct device *dev = adsp->dev;
struct dev_pm_domain_list *pds = adsp->pd_list;
unroll_attach: dev_pm_domain_detach_list(pds);
for (i--; i >= 0; i--)
dev_pm_domain_detach(devs[i], false);
return ret; if (dev->pm_domain || pds)
pm_runtime_disable(adsp->dev);
} }
static void qcom_rproc_pds_detach(struct qcom_adsp *adsp, struct device **pds, static int qcom_rproc_pds_enable(struct qcom_adsp *adsp)
size_t pd_count)
{ {
struct device *dev = adsp->dev; struct device *dev = adsp->dev;
int i; struct dev_pm_domain_list *pds = adsp->pd_list;
int ret, i = 0;
/* Handle single power domain */ if (!dev->pm_domain && !pds)
if (dev->pm_domain && pd_count) { return 0;
pm_runtime_disable(dev);
return;
}
for (i = 0; i < pd_count; i++) if (dev->pm_domain)
dev_pm_domain_detach(pds[i], false); dev_pm_genpd_set_performance_state(dev, INT_MAX);
}
static int qcom_rproc_pds_enable(struct qcom_adsp *adsp, struct device **pds, while (pds && i < pds->num_pds) {
size_t pd_count) dev_pm_genpd_set_performance_state(pds->pd_devs[i], INT_MAX);
{ i++;
int ret;
int i;
for (i = 0; i < pd_count; i++) {
dev_pm_genpd_set_performance_state(pds[i], INT_MAX);
ret = pm_runtime_resume_and_get(pds[i]);
if (ret < 0) {
dev_pm_genpd_set_performance_state(pds[i], 0);
goto unroll_pd_votes;
}
} }
return 0; ret = pm_runtime_resume_and_get(dev);
if (ret < 0) {
while (pds && i > 0) {
i--;
dev_pm_genpd_set_performance_state(pds->pd_devs[i], 0);
}
unroll_pd_votes: if (dev->pm_domain)
for (i--; i >= 0; i--) { dev_pm_genpd_set_performance_state(dev, 0);
dev_pm_genpd_set_performance_state(pds[i], 0);
pm_runtime_put(pds[i]);
} }
return ret; return ret;
} }
static void qcom_rproc_pds_disable(struct qcom_adsp *adsp, struct device **pds, static void qcom_rproc_pds_disable(struct qcom_adsp *adsp)
size_t pd_count)
{ {
int i; struct device *dev = adsp->dev;
struct dev_pm_domain_list *pds = adsp->pd_list;
int i = 0;
if (!dev->pm_domain && !pds)
return;
if (dev->pm_domain)
dev_pm_genpd_set_performance_state(dev, 0);
for (i = 0; i < pd_count; i++) { while (pds && i < pds->num_pds) {
dev_pm_genpd_set_performance_state(pds[i], 0); dev_pm_genpd_set_performance_state(pds->pd_devs[i], 0);
pm_runtime_put(pds[i]); i++;
} }
pm_runtime_put(dev);
} }
static int qcom_wpss_shutdown(struct qcom_adsp *adsp) static int qcom_wpss_shutdown(struct qcom_adsp *adsp)
...@@ -397,8 +389,7 @@ static int adsp_start(struct rproc *rproc) ...@@ -397,8 +389,7 @@ static int adsp_start(struct rproc *rproc)
if (ret) if (ret)
goto adsp_smmu_unmap; goto adsp_smmu_unmap;
ret = qcom_rproc_pds_enable(adsp, adsp->proxy_pds, ret = qcom_rproc_pds_enable(adsp);
adsp->proxy_pd_count);
if (ret < 0) if (ret < 0)
goto disable_xo_clk; goto disable_xo_clk;
...@@ -448,7 +439,7 @@ static int adsp_start(struct rproc *rproc) ...@@ -448,7 +439,7 @@ static int adsp_start(struct rproc *rproc)
disable_adsp_clks: disable_adsp_clks:
clk_bulk_disable_unprepare(adsp->num_clks, adsp->clks); clk_bulk_disable_unprepare(adsp->num_clks, adsp->clks);
disable_power_domain: disable_power_domain:
qcom_rproc_pds_disable(adsp, adsp->proxy_pds, adsp->proxy_pd_count); qcom_rproc_pds_disable(adsp);
disable_xo_clk: disable_xo_clk:
clk_disable_unprepare(adsp->xo); clk_disable_unprepare(adsp->xo);
adsp_smmu_unmap: adsp_smmu_unmap:
...@@ -464,7 +455,7 @@ static void qcom_adsp_pil_handover(struct qcom_q6v5 *q6v5) ...@@ -464,7 +455,7 @@ static void qcom_adsp_pil_handover(struct qcom_q6v5 *q6v5)
struct qcom_adsp *adsp = container_of(q6v5, struct qcom_adsp, q6v5); struct qcom_adsp *adsp = container_of(q6v5, struct qcom_adsp, q6v5);
clk_disable_unprepare(adsp->xo); clk_disable_unprepare(adsp->xo);
qcom_rproc_pds_disable(adsp, adsp->proxy_pds, adsp->proxy_pd_count); qcom_rproc_pds_disable(adsp);
} }
static int adsp_stop(struct rproc *rproc) static int adsp_stop(struct rproc *rproc)
...@@ -715,13 +706,11 @@ static int adsp_probe(struct platform_device *pdev) ...@@ -715,13 +706,11 @@ static int adsp_probe(struct platform_device *pdev)
if (ret) if (ret)
goto free_rproc; goto free_rproc;
ret = qcom_rproc_pds_attach(adsp->dev, adsp, ret = qcom_rproc_pds_attach(adsp, desc->pd_names, desc->num_pds);
desc->proxy_pd_names);
if (ret < 0) { if (ret < 0) {
dev_err(&pdev->dev, "Failed to attach proxy power domains\n"); dev_err(&pdev->dev, "Failed to attach proxy power domains\n");
goto free_rproc; goto free_rproc;
} }
adsp->proxy_pd_count = ret;
ret = adsp_init_reset(adsp); ret = adsp_init_reset(adsp);
if (ret) if (ret)
...@@ -753,7 +742,7 @@ static int adsp_probe(struct platform_device *pdev) ...@@ -753,7 +742,7 @@ static int adsp_probe(struct platform_device *pdev)
return 0; return 0;
disable_pm: disable_pm:
qcom_rproc_pds_detach(adsp, adsp->proxy_pds, adsp->proxy_pd_count); qcom_rproc_pds_detach(adsp);
free_rproc: free_rproc:
rproc_free(rproc); rproc_free(rproc);
...@@ -771,7 +760,7 @@ static void adsp_remove(struct platform_device *pdev) ...@@ -771,7 +760,7 @@ static void adsp_remove(struct platform_device *pdev)
qcom_remove_glink_subdev(adsp->rproc, &adsp->glink_subdev); qcom_remove_glink_subdev(adsp->rproc, &adsp->glink_subdev);
qcom_remove_sysmon_subdev(adsp->sysmon); qcom_remove_sysmon_subdev(adsp->sysmon);
qcom_remove_ssr_subdev(adsp->rproc, &adsp->ssr_subdev); qcom_remove_ssr_subdev(adsp->rproc, &adsp->ssr_subdev);
qcom_rproc_pds_detach(adsp, adsp->proxy_pds, adsp->proxy_pd_count); qcom_rproc_pds_detach(adsp);
rproc_free(adsp->rproc); rproc_free(adsp->rproc);
} }
...@@ -788,9 +777,8 @@ static const struct adsp_pil_data adsp_resource_init = { ...@@ -788,9 +777,8 @@ static const struct adsp_pil_data adsp_resource_init = {
"qdsp6ss_xo", "qdsp6ss_sleep", "qdsp6ss_core", NULL "qdsp6ss_xo", "qdsp6ss_sleep", "qdsp6ss_core", NULL
}, },
.num_clks = 7, .num_clks = 7,
.proxy_pd_names = (const char*[]) { .pd_names = (const char*[]) { "cx" },
"cx", NULL .num_pds = 1,
},
}; };
static const struct adsp_pil_data adsp_sc7280_resource_init = { static const struct adsp_pil_data adsp_sc7280_resource_init = {
...@@ -821,9 +809,8 @@ static const struct adsp_pil_data cdsp_resource_init = { ...@@ -821,9 +809,8 @@ static const struct adsp_pil_data cdsp_resource_init = {
"q6_axim", NULL "q6_axim", NULL
}, },
.num_clks = 7, .num_clks = 7,
.proxy_pd_names = (const char*[]) { .pd_names = (const char*[]) { "cx" },
"cx", NULL .num_pds = 1,
},
}; };
static const struct adsp_pil_data wpss_resource_init = { static const struct adsp_pil_data wpss_resource_init = {
...@@ -839,9 +826,8 @@ static const struct adsp_pil_data wpss_resource_init = { ...@@ -839,9 +826,8 @@ static const struct adsp_pil_data wpss_resource_init = {
"ahb_bdg", "ahb", "rscp", NULL "ahb_bdg", "ahb", "rscp", NULL
}, },
.num_clks = 3, .num_clks = 3,
.proxy_pd_names = (const char*[]) { .pd_names = (const char*[]) { "cx", "mx" },
"cx", "mx", NULL .num_pds = 2,
},
}; };
static const struct of_device_id adsp_of_match[] = { static const struct of_device_id adsp_of_match[] = {
......
...@@ -308,6 +308,13 @@ ...@@ -308,6 +308,13 @@
#define MSM8953_VDDMX 5 #define MSM8953_VDDMX 5
#define MSM8953_VDDMX_AO 6 #define MSM8953_VDDMX_AO 6
/* MSM8974 Power Domain Indexes */
#define MSM8974_VDDCX 0
#define MSM8974_VDDCX_AO 1
#define MSM8974_VDDCX_VFC 2
#define MSM8974_VDDGFX 3
#define MSM8974_VDDGFX_VFC 4
/* MSM8976 Power Domain Indexes */ /* MSM8976 Power Domain Indexes */
#define MSM8976_VDDCX 0 #define MSM8976_VDDCX 0
#define MSM8976_VDDCX_AO 1 #define MSM8976_VDDCX_AO 1
......
...@@ -19,6 +19,33 @@ ...@@ -19,6 +19,33 @@
#include <linux/cpumask.h> #include <linux/cpumask.h>
#include <linux/time64.h> #include <linux/time64.h>
/*
* Flags to control the behaviour when attaching a device to its PM domains.
*
* PD_FLAG_NO_DEV_LINK: As the default behaviour creates a device-link
* for every PM domain that gets attached, this
* flag can be used to skip that.
*
* PD_FLAG_DEV_LINK_ON: Add the DL_FLAG_RPM_ACTIVE to power-on the
* supplier and its PM domain when creating the
* device-links.
*
*/
#define PD_FLAG_NO_DEV_LINK BIT(0)
#define PD_FLAG_DEV_LINK_ON BIT(1)
struct dev_pm_domain_attach_data {
const char * const *pd_names;
const u32 num_pd_names;
const u32 pd_flags;
};
struct dev_pm_domain_list {
struct device **pd_devs;
struct device_link **pd_links;
u32 num_pds;
};
/* /*
* Flags to control the behaviour of a genpd. * Flags to control the behaviour of a genpd.
* *
...@@ -322,7 +349,7 @@ static inline void dev_pm_genpd_resume(struct device *dev) {} ...@@ -322,7 +349,7 @@ static inline void dev_pm_genpd_resume(struct device *dev) {}
/* OF PM domain providers */ /* OF PM domain providers */
struct of_device_id; struct of_device_id;
typedef struct generic_pm_domain *(*genpd_xlate_t)(struct of_phandle_args *args, typedef struct generic_pm_domain *(*genpd_xlate_t)(const struct of_phandle_args *args,
void *data); void *data);
struct genpd_onecell_data { struct genpd_onecell_data {
...@@ -337,11 +364,11 @@ int of_genpd_add_provider_simple(struct device_node *np, ...@@ -337,11 +364,11 @@ int of_genpd_add_provider_simple(struct device_node *np,
int of_genpd_add_provider_onecell(struct device_node *np, int of_genpd_add_provider_onecell(struct device_node *np,
struct genpd_onecell_data *data); struct genpd_onecell_data *data);
void of_genpd_del_provider(struct device_node *np); void of_genpd_del_provider(struct device_node *np);
int of_genpd_add_device(struct of_phandle_args *args, struct device *dev); int of_genpd_add_device(const struct of_phandle_args *args, struct device *dev);
int of_genpd_add_subdomain(struct of_phandle_args *parent_spec, int of_genpd_add_subdomain(const struct of_phandle_args *parent_spec,
struct of_phandle_args *subdomain_spec); const struct of_phandle_args *subdomain_spec);
int of_genpd_remove_subdomain(struct of_phandle_args *parent_spec, int of_genpd_remove_subdomain(const struct of_phandle_args *parent_spec,
struct of_phandle_args *subdomain_spec); const struct of_phandle_args *subdomain_spec);
struct generic_pm_domain *of_genpd_remove_last(struct device_node *np); struct generic_pm_domain *of_genpd_remove_last(struct device_node *np);
int of_genpd_parse_idle_states(struct device_node *dn, int of_genpd_parse_idle_states(struct device_node *dn,
struct genpd_power_state **states, int *n); struct genpd_power_state **states, int *n);
...@@ -366,20 +393,20 @@ static inline int of_genpd_add_provider_onecell(struct device_node *np, ...@@ -366,20 +393,20 @@ static inline int of_genpd_add_provider_onecell(struct device_node *np,
static inline void of_genpd_del_provider(struct device_node *np) {} static inline void of_genpd_del_provider(struct device_node *np) {}
static inline int of_genpd_add_device(struct of_phandle_args *args, static inline int of_genpd_add_device(const struct of_phandle_args *args,
struct device *dev) struct device *dev)
{ {
return -ENODEV; return -ENODEV;
} }
static inline int of_genpd_add_subdomain(struct of_phandle_args *parent_spec, static inline int of_genpd_add_subdomain(const struct of_phandle_args *parent_spec,
struct of_phandle_args *subdomain_spec) const struct of_phandle_args *subdomain_spec)
{ {
return -ENODEV; return -ENODEV;
} }
static inline int of_genpd_remove_subdomain(struct of_phandle_args *parent_spec, static inline int of_genpd_remove_subdomain(const struct of_phandle_args *parent_spec,
struct of_phandle_args *subdomain_spec) const struct of_phandle_args *subdomain_spec)
{ {
return -ENODEV; return -ENODEV;
} }
...@@ -420,7 +447,11 @@ struct device *dev_pm_domain_attach_by_id(struct device *dev, ...@@ -420,7 +447,11 @@ struct device *dev_pm_domain_attach_by_id(struct device *dev,
unsigned int index); unsigned int index);
struct device *dev_pm_domain_attach_by_name(struct device *dev, struct device *dev_pm_domain_attach_by_name(struct device *dev,
const char *name); const char *name);
int dev_pm_domain_attach_list(struct device *dev,
const struct dev_pm_domain_attach_data *data,
struct dev_pm_domain_list **list);
void dev_pm_domain_detach(struct device *dev, bool power_off); void dev_pm_domain_detach(struct device *dev, bool power_off);
void dev_pm_domain_detach_list(struct dev_pm_domain_list *list);
int dev_pm_domain_start(struct device *dev); int dev_pm_domain_start(struct device *dev);
void dev_pm_domain_set(struct device *dev, struct dev_pm_domain *pd); void dev_pm_domain_set(struct device *dev, struct dev_pm_domain *pd);
int dev_pm_domain_set_performance_state(struct device *dev, unsigned int state); int dev_pm_domain_set_performance_state(struct device *dev, unsigned int state);
...@@ -439,7 +470,14 @@ static inline struct device *dev_pm_domain_attach_by_name(struct device *dev, ...@@ -439,7 +470,14 @@ static inline struct device *dev_pm_domain_attach_by_name(struct device *dev,
{ {
return NULL; return NULL;
} }
static inline int dev_pm_domain_attach_list(struct device *dev,
const struct dev_pm_domain_attach_data *data,
struct dev_pm_domain_list **list)
{
return 0;
}
static inline void dev_pm_domain_detach(struct device *dev, bool power_off) {} static inline void dev_pm_domain_detach(struct device *dev, bool power_off) {}
static inline void dev_pm_domain_detach_list(struct dev_pm_domain_list *list) {}
static inline int dev_pm_domain_start(struct device *dev) static inline int dev_pm_domain_start(struct device *dev)
{ {
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment