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 -----BEGIN PGP SIGNATURE----- iQJLBAABCgA1FiEEugLDXPmKSktSkQsV/iaEJXNYjCkFAmXvJJIXHHVsZi5oYW5z c29uQGxpbmFyby5vcmcACgkQ/iaEJXNYjClQDQ/+JNgDl9Kq0hTid2wWyL498flc bB7kuaIdjkConPUNZ5gP0usirOGoGomHuCP4X5Ms2tWf/ZODkFDoyRhDK2sYUhlY wN7msCaQdMbaXXu+uglsxOKttu7N4lbJ1TwgMNgDiwt5CYirJa7GpRH96/3sIW2B vf8hADeWKZsuJ/2ikLPB4WFOHio5/HxqDp6zq2yCnw4rwG4zF209V3JAx/mMcUhd hXxxhBNVcqngqP8oJUvg6eKY6pWlRnPLvQOOMUFEgxtoCEUda3pw+SXO2JVUgI1x x81FneC2kPSu7/kg9G9hjWfRHs3j3eXz4fXn9C8yPvla0DFDT0jbgnJOqSZBQMd8 4vOLaaeEcVArYg60VC13ez+vldUGAtSfcclzEPOmqQH+cihkbPeRvpve4c0YJkGy kEv2/fIFIJdDBxlg9vrTCczQnaYxou5jYiMkSBec1HBPnntwqQ2ji1hx3n1C+LwQ 0AAQMldz+57oJlhso0iWDwidPairn6NprscaEINiOHdRKyrOJGr7s5vQaXy23bIc U7XHJLZ5cho4YECymLd7oyh30HyPz0Ya4E+NE0pf/Dj8ZZOpiUYnvs4sQuxhX9Fi i/3/cbyZrdSy4bQ2ld1sQV4BM+eYVAOT9l4zNFXbdhMpAjpAbSiStaEHrczhrnGI Fc9BvaDowjufngzhgd8= =KslH -----END PGP SIGNATURE----- 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 ...
This commit is contained in:
commit
a070a08d00
|
@ -24,6 +24,8 @@ properties:
|
|||
- qcom,msm8917-rpmpd
|
||||
- qcom,msm8939-rpmpd
|
||||
- qcom,msm8953-rpmpd
|
||||
- qcom,msm8974-rpmpd
|
||||
- qcom,msm8974pro-pma8084-rpmpd
|
||||
- qcom,msm8976-rpmpd
|
||||
- qcom,msm8994-rpmpd
|
||||
- qcom,msm8996-rpmpd
|
||||
|
|
|
@ -27,8 +27,8 @@ properties:
|
|||
const: 1
|
||||
|
||||
power-domains:
|
||||
minItems: 8
|
||||
maxItems: 8
|
||||
minItems: 10
|
||||
maxItems: 10
|
||||
|
||||
power-domain-names:
|
||||
items:
|
||||
|
@ -40,10 +40,12 @@ properties:
|
|||
- const: trng
|
||||
- const: hdmi-tx
|
||||
- const: hdmi-tx-phy
|
||||
- const: hdcp
|
||||
- const: hrv
|
||||
|
||||
clocks:
|
||||
minItems: 4
|
||||
maxItems: 4
|
||||
minItems: 5
|
||||
maxItems: 5
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
|
@ -51,6 +53,7 @@ properties:
|
|||
- const: axi
|
||||
- const: ref_266m
|
||||
- const: ref_24m
|
||||
- const: fdcc
|
||||
|
||||
interconnects:
|
||||
maxItems: 3
|
||||
|
@ -82,12 +85,15 @@ examples:
|
|||
clocks = <&clk IMX8MP_CLK_HDMI_APB>,
|
||||
<&clk IMX8MP_CLK_HDMI_ROOT>,
|
||||
<&clk IMX8MP_CLK_HDMI_REF_266M>,
|
||||
<&clk IMX8MP_CLK_HDMI_24M>;
|
||||
clock-names = "apb", "axi", "ref_266m", "ref_24m";
|
||||
<&clk IMX8MP_CLK_HDMI_24M>,
|
||||
<&clk IMX8MP_CLK_HDMI_FDCC_TST>;
|
||||
clock-names = "apb", "axi", "ref_266m", "ref_24m", "fdcc";
|
||||
power-domains = <&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",
|
||||
"hdmi-tx", "hdmi-tx-phy";
|
||||
"hdmi-tx", "hdmi-tx-phy",
|
||||
"hdcp", "hrv";
|
||||
#power-domain-cells = <1>;
|
||||
};
|
||||
|
|
|
@ -167,6 +167,115 @@ struct device *dev_pm_domain_attach_by_name(struct device *dev,
|
|||
}
|
||||
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: Device to detach.
|
||||
|
@ -187,6 +296,31 @@ void dev_pm_domain_detach(struct device *dev, bool power_off)
|
|||
}
|
||||
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: Device to start.
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <media/videobuf2-v4l2.h>
|
||||
#include <media/v4l2-mem2mem.h>
|
||||
|
@ -114,7 +115,8 @@ static void venus_sys_error_handler(struct work_struct *work)
|
|||
pm_runtime_put_sync(core->dev);
|
||||
|
||||
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;
|
||||
usleep_range(1000, 1500);
|
||||
}
|
||||
|
@ -705,7 +707,7 @@ static const struct venus_resources sdm845_res_v2 = {
|
|||
.vcodec0_clks = { "vcodec0_core", "vcodec0_bus" },
|
||||
.vcodec1_clks = { "vcodec1_core", "vcodec1_bus" },
|
||||
.vcodec_clks_num = 2,
|
||||
.vcodec_pmdomains = { "venus", "vcodec0", "vcodec1" },
|
||||
.vcodec_pmdomains = (const char *[]) { "venus", "vcodec0", "vcodec1" },
|
||||
.vcodec_pmdomains_num = 3,
|
||||
.opp_pmdomain = (const char *[]) { "cx", NULL },
|
||||
.vcodec_num = 2,
|
||||
|
@ -754,7 +756,7 @@ static const struct venus_resources sc7180_res = {
|
|||
.clks_num = 3,
|
||||
.vcodec0_clks = { "vcodec0_core", "vcodec0_bus" },
|
||||
.vcodec_clks_num = 2,
|
||||
.vcodec_pmdomains = { "venus", "vcodec0" },
|
||||
.vcodec_pmdomains = (const char *[]) { "venus", "vcodec0" },
|
||||
.vcodec_pmdomains_num = 2,
|
||||
.opp_pmdomain = (const char *[]) { "cx", NULL },
|
||||
.vcodec_num = 1,
|
||||
|
@ -811,7 +813,7 @@ static const struct venus_resources sm8250_res = {
|
|||
.resets_num = 2,
|
||||
.vcodec0_clks = { "vcodec0_core" },
|
||||
.vcodec_clks_num = 1,
|
||||
.vcodec_pmdomains = { "venus", "vcodec0" },
|
||||
.vcodec_pmdomains = (const char *[]) { "venus", "vcodec0" },
|
||||
.vcodec_pmdomains_num = 2,
|
||||
.opp_pmdomain = (const char *[]) { "mx", NULL },
|
||||
.vcodec_num = 1,
|
||||
|
@ -870,7 +872,7 @@ static const struct venus_resources sc7280_res = {
|
|||
.clks_num = 3,
|
||||
.vcodec0_clks = {"vcodec_core", "vcodec_bus"},
|
||||
.vcodec_clks_num = 2,
|
||||
.vcodec_pmdomains = { "venus", "vcodec0" },
|
||||
.vcodec_pmdomains = (const char *[]) { "venus", "vcodec0" },
|
||||
.vcodec_pmdomains_num = 2,
|
||||
.opp_pmdomain = (const char *[]) { "cx", NULL },
|
||||
.vcodec_num = 1,
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
|
||||
#define VIDC_CLKS_NUM_MAX 4
|
||||
#define VIDC_VCODEC_CLKS_NUM_MAX 2
|
||||
#define VIDC_PMDOMAINS_NUM_MAX 3
|
||||
#define VIDC_RESETS_NUM_MAX 2
|
||||
|
||||
extern int venus_fw_debug;
|
||||
|
@ -72,7 +71,7 @@ struct venus_resources {
|
|||
const char * const vcodec0_clks[VIDC_VCODEC_CLKS_NUM_MAX];
|
||||
const char * const vcodec1_clks[VIDC_VCODEC_CLKS_NUM_MAX];
|
||||
unsigned int vcodec_clks_num;
|
||||
const char * const vcodec_pmdomains[VIDC_PMDOMAINS_NUM_MAX];
|
||||
const char **vcodec_pmdomains;
|
||||
unsigned int vcodec_pmdomains_num;
|
||||
const char **opp_pmdomain;
|
||||
unsigned int vcodec_num;
|
||||
|
@ -134,7 +133,7 @@ struct venus_format {
|
|||
* @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: 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_pmdomain: an OPP power-domain
|
||||
* @resets: an array of reset signals
|
||||
|
@ -187,7 +186,7 @@ struct venus_core {
|
|||
struct icc_path *video_path;
|
||||
struct icc_path *cpucfg_path;
|
||||
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 *opp_pmdomain;
|
||||
struct reset_control *resets[VIDC_RESETS_NUM_MAX];
|
||||
|
|
|
@ -455,7 +455,7 @@ static int poweroff_coreid(struct venus_core *core, unsigned int coreid_mask)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pm_runtime_put_sync(core->pmdomains[1]);
|
||||
ret = pm_runtime_put_sync(core->pmdomains->pd_devs[1]);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
@ -471,7 +471,7 @@ static int poweroff_coreid(struct venus_core *core, unsigned int coreid_mask)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pm_runtime_put_sync(core->pmdomains[2]);
|
||||
ret = pm_runtime_put_sync(core->pmdomains->pd_devs[2]);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
@ -484,7 +484,7 @@ static int poweron_coreid(struct venus_core *core, unsigned int coreid_mask)
|
|||
int ret;
|
||||
|
||||
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)
|
||||
return ret;
|
||||
|
||||
|
@ -502,7 +502,7 @@ static int poweron_coreid(struct venus_core *core, unsigned int coreid_mask)
|
|||
}
|
||||
|
||||
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)
|
||||
return ret;
|
||||
|
||||
|
@ -860,19 +860,18 @@ static int vcodec_domains_get(struct venus_core *core)
|
|||
struct device **opp_virt_dev;
|
||||
struct device *dev = core->dev;
|
||||
const struct venus_resources *res = core->res;
|
||||
struct device *pd;
|
||||
unsigned int i;
|
||||
struct dev_pm_domain_attach_data vcodec_data = {
|
||||
.pd_names = res->vcodec_pmdomains,
|
||||
.num_pd_names = res->vcodec_pmdomains_num,
|
||||
.pd_flags = PD_FLAG_NO_DEV_LINK,
|
||||
};
|
||||
|
||||
if (!res->vcodec_pmdomains_num)
|
||||
goto skip_pmdomains;
|
||||
|
||||
for (i = 0; i < res->vcodec_pmdomains_num; i++) {
|
||||
pd = dev_pm_domain_attach_by_name(dev,
|
||||
res->vcodec_pmdomains[i]);
|
||||
if (IS_ERR_OR_NULL(pd))
|
||||
return pd ? PTR_ERR(pd) : -ENODATA;
|
||||
core->pmdomains[i] = pd;
|
||||
}
|
||||
ret = dev_pm_domain_attach_list(dev, &vcodec_data, &core->pmdomains);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
skip_pmdomains:
|
||||
if (!core->res->opp_pmdomain)
|
||||
|
@ -896,30 +895,14 @@ skip_pmdomains:
|
|||
return 0;
|
||||
|
||||
opp_attach_err:
|
||||
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);
|
||||
}
|
||||
|
||||
dev_pm_domain_detach_list(core->pmdomains);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void vcodec_domains_put(struct venus_core *core)
|
||||
{
|
||||
const struct venus_resources *res = core->res;
|
||||
unsigned int i;
|
||||
dev_pm_domain_detach_list(core->pmdomains);
|
||||
|
||||
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)
|
||||
return;
|
||||
|
||||
|
@ -1035,7 +1018,8 @@ static void core_put_v4(struct venus_core *core)
|
|||
static int core_power_v4(struct venus_core *core, int on)
|
||||
{
|
||||
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;
|
||||
|
||||
if (on == POWER_ON) {
|
||||
|
|
|
@ -310,73 +310,103 @@ static int genpd_xlate_performance_state(struct generic_pm_domain *genpd,
|
|||
pstate);
|
||||
}
|
||||
|
||||
static int _genpd_set_performance_state(struct generic_pm_domain *genpd,
|
||||
unsigned int state, int depth);
|
||||
|
||||
static void _genpd_rollback_parent_state(struct gpd_link *link, int depth)
|
||||
{
|
||||
struct generic_pm_domain *parent = link->parent;
|
||||
int parent_state;
|
||||
|
||||
genpd_lock_nested(parent, depth + 1);
|
||||
|
||||
parent_state = link->prev_performance_state;
|
||||
link->performance_state = parent_state;
|
||||
|
||||
parent_state = _genpd_reeval_performance_state(parent, parent_state);
|
||||
if (_genpd_set_performance_state(parent, parent_state, depth + 1)) {
|
||||
pr_err("%s: Failed to roll back to %d performance state\n",
|
||||
parent->name, parent_state);
|
||||
}
|
||||
|
||||
genpd_unlock(parent);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
/* Find parent's performance state */
|
||||
ret = genpd_xlate_performance_state(genpd, parent, state);
|
||||
if (unlikely(ret < 0))
|
||||
return ret;
|
||||
|
||||
parent_state = ret;
|
||||
|
||||
genpd_lock_nested(parent, depth + 1);
|
||||
|
||||
link->prev_performance_state = link->performance_state;
|
||||
link->performance_state = parent_state;
|
||||
|
||||
parent_state = _genpd_reeval_performance_state(parent, parent_state);
|
||||
ret = _genpd_set_performance_state(parent, parent_state, depth + 1);
|
||||
if (ret)
|
||||
link->performance_state = link->prev_performance_state;
|
||||
|
||||
genpd_unlock(parent);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _genpd_set_performance_state(struct generic_pm_domain *genpd,
|
||||
unsigned int state, int depth)
|
||||
{
|
||||
struct generic_pm_domain *parent;
|
||||
struct gpd_link *link;
|
||||
int parent_state, ret;
|
||||
struct gpd_link *link = NULL;
|
||||
int ret;
|
||||
|
||||
if (state == genpd->performance_state)
|
||||
return 0;
|
||||
|
||||
/* Propagate to parents of genpd */
|
||||
list_for_each_entry(link, &genpd->child_links, child_node) {
|
||||
parent = link->parent;
|
||||
|
||||
/* Find parent's performance state */
|
||||
ret = genpd_xlate_performance_state(genpd, parent, state);
|
||||
if (unlikely(ret < 0))
|
||||
goto err;
|
||||
|
||||
parent_state = ret;
|
||||
|
||||
genpd_lock_nested(parent, depth + 1);
|
||||
|
||||
link->prev_performance_state = link->performance_state;
|
||||
link->performance_state = parent_state;
|
||||
parent_state = _genpd_reeval_performance_state(parent,
|
||||
parent_state);
|
||||
ret = _genpd_set_performance_state(parent, parent_state, depth + 1);
|
||||
if (ret)
|
||||
link->performance_state = link->prev_performance_state;
|
||||
|
||||
genpd_unlock(parent);
|
||||
|
||||
if (ret)
|
||||
goto err;
|
||||
/* When scaling up, propagate to parents first in normal order */
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (genpd->set_performance_state) {
|
||||
ret = genpd->set_performance_state(genpd, state);
|
||||
if (ret)
|
||||
goto err;
|
||||
if (ret) {
|
||||
if (link)
|
||||
goto rollback_parents_up;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
err:
|
||||
/* 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);
|
||||
|
||||
parent_state = link->prev_performance_state;
|
||||
link->performance_state = parent_state;
|
||||
|
||||
parent_state = _genpd_reeval_performance_state(parent,
|
||||
parent_state);
|
||||
if (_genpd_set_performance_state(parent, parent_state, depth + 1)) {
|
||||
pr_err("%s: Failed to roll back to %d performance state\n",
|
||||
parent->name, parent_state);
|
||||
}
|
||||
|
||||
genpd_unlock(parent);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1100,6 +1130,7 @@ static int __init genpd_power_off_unused(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
pr_info("genpd: Disabling unused power domains\n");
|
||||
mutex_lock(&gpd_list_lock);
|
||||
|
||||
list_for_each_entry(genpd, &gpd_list, gpd_list_node)
|
||||
|
@ -2235,7 +2266,7 @@ static DEFINE_MUTEX(of_genpd_mutex);
|
|||
* to be a valid pointer to struct generic_pm_domain.
|
||||
*/
|
||||
static struct generic_pm_domain *genpd_xlate_simple(
|
||||
struct of_phandle_args *genpdspec,
|
||||
const struct of_phandle_args *genpdspec,
|
||||
void *data)
|
||||
{
|
||||
return data;
|
||||
|
@ -2252,7 +2283,7 @@ static struct generic_pm_domain *genpd_xlate_simple(
|
|||
* the genpd_onecell_data struct when registering the provider.
|
||||
*/
|
||||
static struct generic_pm_domain *genpd_xlate_onecell(
|
||||
struct of_phandle_args *genpdspec,
|
||||
const struct of_phandle_args *genpdspec,
|
||||
void *data)
|
||||
{
|
||||
struct genpd_onecell_data *genpd_data = data;
|
||||
|
@ -2495,7 +2526,7 @@ EXPORT_SYMBOL_GPL(of_genpd_del_provider);
|
|||
* on failure.
|
||||
*/
|
||||
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 of_genpd_provider *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
|
||||
* 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;
|
||||
int ret;
|
||||
|
@ -2560,8 +2591,8 @@ EXPORT_SYMBOL_GPL(of_genpd_add_device);
|
|||
* provided and adds the subdomain to the parent PM domain. Returns a
|
||||
* negative error code on failure.
|
||||
*/
|
||||
int of_genpd_add_subdomain(struct of_phandle_args *parent_spec,
|
||||
struct of_phandle_args *subdomain_spec)
|
||||
int of_genpd_add_subdomain(const struct of_phandle_args *parent_spec,
|
||||
const struct of_phandle_args *subdomain_spec)
|
||||
{
|
||||
struct generic_pm_domain *parent, *subdomain;
|
||||
int ret;
|
||||
|
@ -2598,8 +2629,8 @@ EXPORT_SYMBOL_GPL(of_genpd_add_subdomain);
|
|||
* provided and removes the subdomain from the parent PM domain. Returns a
|
||||
* negative error code on failure.
|
||||
*/
|
||||
int of_genpd_remove_subdomain(struct of_phandle_args *parent_spec,
|
||||
struct of_phandle_args *subdomain_spec)
|
||||
int of_genpd_remove_subdomain(const struct of_phandle_args *parent_spec,
|
||||
const struct of_phandle_args *subdomain_spec)
|
||||
{
|
||||
struct generic_pm_domain *parent, *subdomain;
|
||||
int ret;
|
||||
|
|
|
@ -258,11 +258,14 @@ static int imx8m_blk_ctrl_probe(struct platform_device *pdev)
|
|||
|
||||
domain->power_dev =
|
||||
dev_pm_domain_attach_by_name(dev, data->gpc_name);
|
||||
if (IS_ERR(domain->power_dev)) {
|
||||
dev_err_probe(dev, PTR_ERR(domain->power_dev),
|
||||
if (IS_ERR_OR_NULL(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",
|
||||
data->gpc_name);
|
||||
ret = PTR_ERR(domain->power_dev);
|
||||
goto cleanup_pds;
|
||||
}
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ struct imx8mp_blk_ctrl_domain_data {
|
|||
const char *gpc_name;
|
||||
};
|
||||
|
||||
#define DOMAIN_MAX_CLKS 2
|
||||
#define DOMAIN_MAX_CLKS 3
|
||||
#define DOMAIN_MAX_PATHS 3
|
||||
|
||||
struct imx8mp_blk_ctrl_domain {
|
||||
|
@ -457,8 +457,8 @@ static const struct imx8mp_blk_ctrl_domain_data imx8mp_hdmi_domain_data[] = {
|
|||
},
|
||||
[IMX8MP_HDMIBLK_PD_LCDIF] = {
|
||||
.name = "hdmiblk-lcdif",
|
||||
.clk_names = (const char *[]){ "axi", "apb" },
|
||||
.num_clks = 2,
|
||||
.clk_names = (const char *[]){ "axi", "apb", "fdcc" },
|
||||
.num_clks = 3,
|
||||
.gpc_name = "lcdif",
|
||||
.path_names = (const char *[]){"lcdif-hdmi"},
|
||||
.num_paths = 1,
|
||||
|
@ -483,8 +483,8 @@ static const struct imx8mp_blk_ctrl_domain_data imx8mp_hdmi_domain_data[] = {
|
|||
},
|
||||
[IMX8MP_HDMIBLK_PD_HDMI_TX] = {
|
||||
.name = "hdmiblk-hdmi-tx",
|
||||
.clk_names = (const char *[]){ "apb", "ref_266m" },
|
||||
.num_clks = 2,
|
||||
.clk_names = (const char *[]){ "apb", "ref_266m", "fdcc" },
|
||||
.num_clks = 3,
|
||||
.gpc_name = "hdmi-tx",
|
||||
},
|
||||
[IMX8MP_HDMIBLK_PD_HDMI_TX_PHY] = {
|
||||
|
@ -687,11 +687,14 @@ static int imx8mp_blk_ctrl_probe(struct platform_device *pdev)
|
|||
|
||||
domain->power_dev =
|
||||
dev_pm_domain_attach_by_name(dev, data->gpc_name);
|
||||
if (IS_ERR(domain->power_dev)) {
|
||||
dev_err_probe(dev, PTR_ERR(domain->power_dev),
|
||||
if (IS_ERR_OR_NULL(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",
|
||||
data->gpc_name);
|
||||
ret = PTR_ERR(domain->power_dev);
|
||||
goto cleanup_pds;
|
||||
}
|
||||
|
||||
|
|
|
@ -393,7 +393,7 @@ static int imx_sc_pd_power_off(struct generic_pm_domain *domain)
|
|||
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)
|
||||
{
|
||||
struct generic_pm_domain *domain = ERR_PTR(-ENOENT);
|
||||
|
|
|
@ -425,7 +425,6 @@ static struct scp *init_scp(struct platform_device *pdev,
|
|||
bool bus_prot_reg_update)
|
||||
{
|
||||
struct genpd_onecell_data *pd_data;
|
||||
struct resource *res;
|
||||
int i, j;
|
||||
struct scp *scp;
|
||||
struct clk *clk[CLK_MAX];
|
||||
|
@ -441,8 +440,7 @@ static struct scp *init_scp(struct platform_device *pdev,
|
|||
|
||||
scp->dev = &pdev->dev;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
scp->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
scp->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(scp->base))
|
||||
return ERR_CAST(scp->base);
|
||||
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
#define domain_to_rpmpd(domain) container_of(domain, struct rpmpd, pd)
|
||||
|
||||
static struct qcom_smd_rpm *rpmpd_smd_rpm;
|
||||
|
||||
/* Resource types:
|
||||
* RPMPD_X is X encoded as a little-endian, lower-case, ASCII string */
|
||||
#define RPMPD_SMPA 0x61706d73
|
||||
|
@ -54,7 +56,6 @@ struct rpmpd {
|
|||
bool enabled;
|
||||
const int res_type;
|
||||
const int res_id;
|
||||
struct qcom_smd_rpm *rpm;
|
||||
unsigned int max_state;
|
||||
__le32 key;
|
||||
bool state_synced;
|
||||
|
@ -226,7 +227,46 @@ static struct rpmpd cx_s3a_vfl = {
|
|||
.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 */
|
||||
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 = {
|
||||
.pd = { .name = "gfx", },
|
||||
.res_type = RPMPD_SMPB,
|
||||
|
@ -241,6 +281,20 @@ static struct rpmpd gfx_s2b_vfc = {
|
|||
.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 gx_rwgx0_lvl_ao;
|
||||
static struct rpmpd gx_rwgx0_lvl = {
|
||||
|
@ -663,6 +717,34 @@ static const struct rpmpd_desc msm8953_desc = {
|
|||
.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[] = {
|
||||
[MSM8976_VDDCX] = &cx_s2a_lvl,
|
||||
[MSM8976_VDDCX_AO] = &cx_s2a_lvl_ao,
|
||||
|
@ -856,6 +938,8 @@ static const struct of_device_id rpmpd_match_table[] = {
|
|||
{ .compatible = "qcom,msm8917-rpmpd", .data = &msm8917_desc },
|
||||
{ .compatible = "qcom,msm8939-rpmpd", .data = &msm8939_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,msm8994-rpmpd", .data = &msm8994_desc },
|
||||
{ .compatible = "qcom,msm8996-rpmpd", .data = &msm8996_desc },
|
||||
|
@ -879,7 +963,7 @@ static int rpmpd_send_enable(struct rpmpd *pd, bool 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));
|
||||
}
|
||||
|
||||
|
@ -891,7 +975,7 @@ static int rpmpd_send_corner(struct rpmpd *pd, int state, unsigned int 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));
|
||||
};
|
||||
|
||||
|
@ -1004,12 +1088,11 @@ static int rpmpd_probe(struct platform_device *pdev)
|
|||
int i;
|
||||
size_t num;
|
||||
struct genpd_onecell_data *data;
|
||||
struct qcom_smd_rpm *rpm;
|
||||
struct rpmpd **rpmpds;
|
||||
const struct rpmpd_desc *desc;
|
||||
|
||||
rpm = dev_get_drvdata(pdev->dev.parent);
|
||||
if (!rpm) {
|
||||
rpmpd_smd_rpm = dev_get_drvdata(pdev->dev.parent);
|
||||
if (!rpmpd_smd_rpm) {
|
||||
dev_err(&pdev->dev, "Unable to retrieve handle to RPM\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
@ -1039,7 +1122,6 @@ static int rpmpd_probe(struct platform_device *pdev)
|
|||
continue;
|
||||
}
|
||||
|
||||
rpmpds[i]->rpm = rpm;
|
||||
rpmpds[i]->max_state = desc->max_state;
|
||||
rpmpds[i]->pd.power_off = rpmpd_power_off;
|
||||
rpmpds[i]->pd.power_on = rpmpd_power_on;
|
||||
|
|
|
@ -71,6 +71,10 @@ config SYSC_R8A779G0
|
|||
bool "System Controller support for R-Car V4H" if COMPILE_TEST
|
||||
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
|
||||
bool "System Controller support for R-Mobile" if COMPILE_TEST
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ obj-$(CONFIG_SYSC_R8A77995) += r8a77995-sysc.o
|
|||
obj-$(CONFIG_SYSC_R8A779A0) += r8a779a0-sysc.o
|
||||
obj-$(CONFIG_SYSC_R8A779F0) += r8a779f0-sysc.o
|
||||
obj-$(CONFIG_SYSC_R8A779G0) += r8a779g0-sysc.o
|
||||
obj-$(CONFIG_SYSC_R8A779H0) += r8a779h0-sysc.o
|
||||
# Family
|
||||
obj-$(CONFIG_SYSC_RCAR) += rcar-sysc.o
|
||||
obj-$(CONFIG_SYSC_RCAR_GEN4) += rcar-gen4-sysc.o
|
||||
|
|
|
@ -5,19 +5,7 @@
|
|||
* 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/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>
|
||||
|
||||
|
|
|
@ -5,19 +5,7 @@
|
|||
* 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/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>
|
||||
|
||||
|
|
|
@ -5,19 +5,7 @@
|
|||
* 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/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>
|
||||
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
// 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 @@
|
|||
#define SYSCSR_BUSY GENMASK(1, 0) /* All bit sets is not busy */
|
||||
|
||||
#define SYSCSR_TIMEOUT 10000
|
||||
#define SYSCSR_DELAY_US 10
|
||||
#define SYSCSR_DELAY_US 1
|
||||
|
||||
#define PDRESR_RETRIES 1000
|
||||
#define PDRESR_DELAY_US 10
|
||||
#define PDRESR_RETRIES 10000
|
||||
#define PDRESR_DELAY_US 1
|
||||
|
||||
#define SYSCISR_TIMEOUT 10000
|
||||
#define SYSCISR_DELAY_US 10
|
||||
#define SYSCISCR_TIMEOUT 10000
|
||||
#define SYSCISCR_DELAY_US 1
|
||||
|
||||
#define RCAR_GEN4_PD_ALWAYS_ON 64
|
||||
#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)
|
|||
|
||||
ret = readl_poll_timeout_atomic(rcar_gen4_sysc_base + SYSCISCR(reg_idx),
|
||||
val, !(val & isr_mask),
|
||||
SYSCISR_DELAY_US, SYSCISR_TIMEOUT);
|
||||
SYSCISCR_DELAY_US, SYSCISCR_TIMEOUT);
|
||||
if (ret < 0) {
|
||||
pr_err("\n %s : Can not clear IRQ flags in SYSCISCR", __func__);
|
||||
return -EIO;
|
||||
|
@ -157,7 +157,7 @@ static int rcar_gen4_sysc_power(u8 pdr, bool on)
|
|||
/* Wait until the power shutoff or resume request has completed * */
|
||||
ret = readl_poll_timeout_atomic(rcar_gen4_sysc_base + SYSCISCR(reg_idx),
|
||||
val, (val & isr_mask),
|
||||
SYSCISR_DELAY_US, SYSCISR_TIMEOUT);
|
||||
SYSCISCR_DELAY_US, SYSCISCR_TIMEOUT);
|
||||
if (ret < 0) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
|
@ -284,6 +284,9 @@ static const struct of_device_id rcar_gen4_sysc_matches[] __initconst = {
|
|||
#endif
|
||||
#ifdef CONFIG_SYSC_R8A779G0
|
||||
{ .compatible = "renesas,r8a779g0-sysc", .data = &r8a779g0_sysc_info },
|
||||
#endif
|
||||
#ifdef CONFIG_SYSC_R8A779H0
|
||||
{ .compatible = "renesas,r8a779h0-sysc", .data = &r8a779h0_sysc_info },
|
||||
#endif
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
|
|
@ -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 r8a779f0_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__ */
|
||||
|
|
|
@ -45,10 +45,10 @@
|
|||
#define PWRER_OFFS 0x14 /* Power Shutoff/Resume Error */
|
||||
|
||||
|
||||
#define SYSCSR_TIMEOUT 100
|
||||
#define SYSCSR_TIMEOUT 1000
|
||||
#define SYSCSR_DELAY_US 1
|
||||
|
||||
#define PWRER_RETRIES 100
|
||||
#define PWRER_RETRIES 1000
|
||||
#define PWRER_DELAY_US 1
|
||||
|
||||
#define SYSCISR_TIMEOUT 1000
|
||||
|
|
|
@ -305,7 +305,7 @@ static void tegra_bpmp_remove_powergates(struct tegra_bpmp *bpmp)
|
|||
}
|
||||
|
||||
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 genpd_onecell_data *genpd = data;
|
||||
|
|
|
@ -695,6 +695,8 @@ static int omap_prm_domain_init(struct device *dev, struct omap_prm *prm)
|
|||
data = prm->data;
|
||||
name = devm_kasprintf(dev, GFP_KERNEL, "prm_%s",
|
||||
data->name);
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
|
||||
prmd->dev = dev;
|
||||
prmd->prm = prm;
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
static struct generic_pm_domain *ti_sci_pd_xlate(
|
||||
struct of_phandle_args *genpdspec,
|
||||
const struct of_phandle_args *genpdspec,
|
||||
void *data)
|
||||
{
|
||||
struct genpd_onecell_data *genpd_data = data;
|
||||
|
|
|
@ -210,7 +210,7 @@ static void zynqmp_gpd_detach_dev(struct generic_pm_domain *domain,
|
|||
}
|
||||
|
||||
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;
|
||||
unsigned int i, idx = genpdspec->args[0];
|
||||
|
|
|
@ -103,12 +103,10 @@ enum imx_dsp_rp_mbox_messages {
|
|||
* @tx_ch: mailbox tx channel handle
|
||||
* @rx_ch: mailbox rx channel handle
|
||||
* @rxdb_ch: mailbox rx doorbell channel handle
|
||||
* @pd_dev: power domain device
|
||||
* @pd_dev_link: power domain device link
|
||||
* @pd_list: power domain list
|
||||
* @ipc_handle: System Control Unit ipc handle
|
||||
* @rproc_work: work for processing virtio interrupts
|
||||
* @pm_comp: completion primitive to sync for suspend response
|
||||
* @num_domains: power domain number
|
||||
* @flags: control flags
|
||||
*/
|
||||
struct imx_dsp_rproc {
|
||||
|
@ -121,12 +119,10 @@ struct imx_dsp_rproc {
|
|||
struct mbox_chan *tx_ch;
|
||||
struct mbox_chan *rx_ch;
|
||||
struct mbox_chan *rxdb_ch;
|
||||
struct device **pd_dev;
|
||||
struct device_link **pd_dev_link;
|
||||
struct dev_pm_domain_list *pd_list;
|
||||
struct imx_sc_ipc *ipc_handle;
|
||||
struct work_struct rproc_work;
|
||||
struct completion pm_comp;
|
||||
int num_domains;
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
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)
|
||||
/* A single PM domain is already attached. */
|
||||
if (dev->pm_domain)
|
||||
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)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < priv->num_domains; i++) {
|
||||
device_link_del(priv->pd_dev_link[i]);
|
||||
dev_pm_domain_detach(priv->pd_dev[i], false);
|
||||
}
|
||||
|
||||
return 0;
|
||||
ret = dev_pm_domain_attach_list(dev, NULL, &priv->pd_list);
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1154,7 +1090,7 @@ static int imx_dsp_rproc_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
|
||||
err_detach_domains:
|
||||
imx_dsp_detach_pm_domains(priv);
|
||||
dev_pm_domain_detach_list(priv->pd_list);
|
||||
err_put_rproc:
|
||||
rproc_free(rproc);
|
||||
|
||||
|
@ -1168,7 +1104,7 @@ static void imx_dsp_rproc_remove(struct platform_device *pdev)
|
|||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
rproc_del(rproc);
|
||||
imx_dsp_detach_pm_domains(priv);
|
||||
dev_pm_domain_detach_list(priv->pd_list);
|
||||
rproc_free(rproc);
|
||||
}
|
||||
|
||||
|
|
|
@ -92,7 +92,6 @@ struct imx_rproc_mem {
|
|||
|
||||
static int imx_rproc_xtr_mbox_init(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 device *dev;
|
||||
|
@ -113,10 +112,8 @@ struct imx_rproc {
|
|||
u32 rproc_pt; /* partition id */
|
||||
u32 rsrc_id; /* resource id */
|
||||
u32 entry; /* cpu start address */
|
||||
int num_pd;
|
||||
u32 core_index;
|
||||
struct device **pd_dev;
|
||||
struct device_link **pd_dev_link;
|
||||
struct dev_pm_domain_list *pd_list;
|
||||
};
|
||||
|
||||
static const struct imx_rproc_att imx_rproc_att_imx93[] = {
|
||||
|
@ -853,7 +850,7 @@ static void imx_rproc_put_scu(struct rproc *rproc)
|
|||
return;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -880,72 +877,20 @@ static int imx_rproc_partition_notify(struct notifier_block *nb,
|
|||
static int imx_rproc_attach_pd(struct imx_rproc *priv)
|
||||
{
|
||||
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)
|
||||
if (dev->pm_domain)
|
||||
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
|
||||
* will handle it, no need handle it in this driver.
|
||||
*/
|
||||
if (priv->num_pd <= 1)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < priv->num_pd; i++) {
|
||||
device_link_del(priv->pd_dev_link[i]);
|
||||
dev_pm_domain_detach(priv->pd_dev[i], false);
|
||||
}
|
||||
|
||||
return 0;
|
||||
ret = dev_pm_domain_attach_list(dev, &pd_data, &priv->pd_list);
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
|
||||
static int imx_rproc_detect_mode(struct imx_rproc *priv)
|
||||
|
|
|
@ -55,8 +55,6 @@
|
|||
#define QDSP6SS_CORE_CBCR 0x20
|
||||
#define QDSP6SS_SLEEP_CBCR 0x3c
|
||||
|
||||
#define QCOM_Q6V5_RPROC_PROXY_PD_MAX 3
|
||||
|
||||
#define LPASS_BOOT_CORE_START BIT(0)
|
||||
#define LPASS_BOOT_CMD_START BIT(0)
|
||||
#define LPASS_EFUSE_Q6SS_EVB_SEL 0x0
|
||||
|
@ -74,7 +72,8 @@ struct adsp_pil_data {
|
|||
|
||||
const char **clk_ids;
|
||||
int num_clks;
|
||||
const char **proxy_pd_names;
|
||||
const char **pd_names;
|
||||
unsigned int num_pds;
|
||||
const char *load_state;
|
||||
};
|
||||
|
||||
|
@ -110,8 +109,7 @@ struct qcom_adsp {
|
|||
size_t mem_size;
|
||||
bool has_iommu;
|
||||
|
||||
struct device *proxy_pds[QCOM_Q6V5_RPROC_PROXY_PD_MAX];
|
||||
size_t proxy_pd_count;
|
||||
struct dev_pm_domain_list *pd_list;
|
||||
|
||||
struct qcom_rproc_glink glink_subdev;
|
||||
struct qcom_rproc_ssr ssr_subdev;
|
||||
|
@ -120,98 +118,92 @@ struct qcom_adsp {
|
|||
int (*shutdown)(struct qcom_adsp *adsp);
|
||||
};
|
||||
|
||||
static int qcom_rproc_pds_attach(struct device *dev, struct qcom_adsp *adsp,
|
||||
const char **pd_names)
|
||||
static int qcom_rproc_pds_attach(struct qcom_adsp *adsp, const char **pd_names,
|
||||
unsigned int num_pds)
|
||||
{
|
||||
struct device **devs = adsp->proxy_pds;
|
||||
size_t num_pds = 0;
|
||||
struct device *dev = adsp->dev;
|
||||
struct dev_pm_domain_attach_data pd_data = {
|
||||
.pd_names = pd_names,
|
||||
.num_pd_names = num_pds,
|
||||
};
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
/* Handle single power domain */
|
||||
if (dev->pm_domain)
|
||||
goto out;
|
||||
|
||||
if (!pd_names)
|
||||
return 0;
|
||||
|
||||
/* Handle single power domain */
|
||||
if (dev->pm_domain) {
|
||||
devs[0] = dev;
|
||||
pm_runtime_enable(dev);
|
||||
return 1;
|
||||
}
|
||||
ret = dev_pm_domain_attach_list(dev, &pd_data, &adsp->pd_list);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
while (pd_names[num_pds])
|
||||
num_pds++;
|
||||
|
||||
if (num_pds > ARRAY_SIZE(adsp->proxy_pds))
|
||||
return -E2BIG;
|
||||
|
||||
for (i = 0; i < num_pds; i++) {
|
||||
devs[i] = dev_pm_domain_attach_by_name(dev, pd_names[i]);
|
||||
if (IS_ERR_OR_NULL(devs[i])) {
|
||||
ret = PTR_ERR(devs[i]) ? : -ENODATA;
|
||||
goto unroll_attach;
|
||||
}
|
||||
}
|
||||
|
||||
return num_pds;
|
||||
|
||||
unroll_attach:
|
||||
for (i--; i >= 0; i--)
|
||||
dev_pm_domain_detach(devs[i], false);
|
||||
|
||||
return ret;
|
||||
out:
|
||||
pm_runtime_enable(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qcom_rproc_pds_detach(struct qcom_adsp *adsp, struct device **pds,
|
||||
size_t pd_count)
|
||||
static void qcom_rproc_pds_detach(struct qcom_adsp *adsp)
|
||||
{
|
||||
struct device *dev = adsp->dev;
|
||||
int i;
|
||||
struct dev_pm_domain_list *pds = adsp->pd_list;
|
||||
|
||||
/* Handle single power domain */
|
||||
if (dev->pm_domain && pd_count) {
|
||||
pm_runtime_disable(dev);
|
||||
return;
|
||||
}
|
||||
dev_pm_domain_detach_list(pds);
|
||||
|
||||
for (i = 0; i < pd_count; i++)
|
||||
dev_pm_domain_detach(pds[i], false);
|
||||
if (dev->pm_domain || pds)
|
||||
pm_runtime_disable(adsp->dev);
|
||||
}
|
||||
|
||||
static int qcom_rproc_pds_enable(struct qcom_adsp *adsp, struct device **pds,
|
||||
size_t pd_count)
|
||||
static int qcom_rproc_pds_enable(struct qcom_adsp *adsp)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
struct device *dev = adsp->dev;
|
||||
struct dev_pm_domain_list *pds = adsp->pd_list;
|
||||
int ret, i = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
if (!dev->pm_domain && !pds)
|
||||
return 0;
|
||||
|
||||
if (dev->pm_domain)
|
||||
dev_pm_genpd_set_performance_state(dev, INT_MAX);
|
||||
|
||||
while (pds && i < pds->num_pds) {
|
||||
dev_pm_genpd_set_performance_state(pds->pd_devs[i], INT_MAX);
|
||||
i++;
|
||||
}
|
||||
|
||||
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:
|
||||
for (i--; i >= 0; i--) {
|
||||
dev_pm_genpd_set_performance_state(pds[i], 0);
|
||||
pm_runtime_put(pds[i]);
|
||||
if (dev->pm_domain)
|
||||
dev_pm_genpd_set_performance_state(dev, 0);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void qcom_rproc_pds_disable(struct qcom_adsp *adsp, struct device **pds,
|
||||
size_t pd_count)
|
||||
static void qcom_rproc_pds_disable(struct qcom_adsp *adsp)
|
||||
{
|
||||
int i;
|
||||
struct device *dev = adsp->dev;
|
||||
struct dev_pm_domain_list *pds = adsp->pd_list;
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < pd_count; i++) {
|
||||
dev_pm_genpd_set_performance_state(pds[i], 0);
|
||||
pm_runtime_put(pds[i]);
|
||||
if (!dev->pm_domain && !pds)
|
||||
return;
|
||||
|
||||
if (dev->pm_domain)
|
||||
dev_pm_genpd_set_performance_state(dev, 0);
|
||||
|
||||
while (pds && i < pds->num_pds) {
|
||||
dev_pm_genpd_set_performance_state(pds->pd_devs[i], 0);
|
||||
i++;
|
||||
}
|
||||
|
||||
pm_runtime_put(dev);
|
||||
}
|
||||
|
||||
static int qcom_wpss_shutdown(struct qcom_adsp *adsp)
|
||||
|
@ -397,8 +389,7 @@ static int adsp_start(struct rproc *rproc)
|
|||
if (ret)
|
||||
goto adsp_smmu_unmap;
|
||||
|
||||
ret = qcom_rproc_pds_enable(adsp, adsp->proxy_pds,
|
||||
adsp->proxy_pd_count);
|
||||
ret = qcom_rproc_pds_enable(adsp);
|
||||
if (ret < 0)
|
||||
goto disable_xo_clk;
|
||||
|
||||
|
@ -448,7 +439,7 @@ static int adsp_start(struct rproc *rproc)
|
|||
disable_adsp_clks:
|
||||
clk_bulk_disable_unprepare(adsp->num_clks, adsp->clks);
|
||||
disable_power_domain:
|
||||
qcom_rproc_pds_disable(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
|
||||
qcom_rproc_pds_disable(adsp);
|
||||
disable_xo_clk:
|
||||
clk_disable_unprepare(adsp->xo);
|
||||
adsp_smmu_unmap:
|
||||
|
@ -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);
|
||||
|
||||
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)
|
||||
|
@ -715,13 +706,11 @@ static int adsp_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
goto free_rproc;
|
||||
|
||||
ret = qcom_rproc_pds_attach(adsp->dev, adsp,
|
||||
desc->proxy_pd_names);
|
||||
ret = qcom_rproc_pds_attach(adsp, desc->pd_names, desc->num_pds);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to attach proxy power domains\n");
|
||||
goto free_rproc;
|
||||
}
|
||||
adsp->proxy_pd_count = ret;
|
||||
|
||||
ret = adsp_init_reset(adsp);
|
||||
if (ret)
|
||||
|
@ -753,7 +742,7 @@ static int adsp_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
|
||||
disable_pm:
|
||||
qcom_rproc_pds_detach(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
|
||||
qcom_rproc_pds_detach(adsp);
|
||||
|
||||
free_rproc:
|
||||
rproc_free(rproc);
|
||||
|
@ -771,7 +760,7 @@ static void adsp_remove(struct platform_device *pdev)
|
|||
qcom_remove_glink_subdev(adsp->rproc, &adsp->glink_subdev);
|
||||
qcom_remove_sysmon_subdev(adsp->sysmon);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -788,9 +777,8 @@ static const struct adsp_pil_data adsp_resource_init = {
|
|||
"qdsp6ss_xo", "qdsp6ss_sleep", "qdsp6ss_core", NULL
|
||||
},
|
||||
.num_clks = 7,
|
||||
.proxy_pd_names = (const char*[]) {
|
||||
"cx", NULL
|
||||
},
|
||||
.pd_names = (const char*[]) { "cx" },
|
||||
.num_pds = 1,
|
||||
};
|
||||
|
||||
static const struct adsp_pil_data adsp_sc7280_resource_init = {
|
||||
|
@ -821,9 +809,8 @@ static const struct adsp_pil_data cdsp_resource_init = {
|
|||
"q6_axim", NULL
|
||||
},
|
||||
.num_clks = 7,
|
||||
.proxy_pd_names = (const char*[]) {
|
||||
"cx", NULL
|
||||
},
|
||||
.pd_names = (const char*[]) { "cx" },
|
||||
.num_pds = 1,
|
||||
};
|
||||
|
||||
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
|
||||
},
|
||||
.num_clks = 3,
|
||||
.proxy_pd_names = (const char*[]) {
|
||||
"cx", "mx", NULL
|
||||
},
|
||||
.pd_names = (const char*[]) { "cx", "mx" },
|
||||
.num_pds = 2,
|
||||
};
|
||||
|
||||
static const struct of_device_id adsp_of_match[] = {
|
||||
|
|
|
@ -308,6 +308,13 @@
|
|||
#define MSM8953_VDDMX 5
|
||||
#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 */
|
||||
#define MSM8976_VDDCX 0
|
||||
#define MSM8976_VDDCX_AO 1
|
||||
|
|
|
@ -19,6 +19,33 @@
|
|||
#include <linux/cpumask.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.
|
||||
*
|
||||
|
@ -322,7 +349,7 @@ static inline void dev_pm_genpd_resume(struct device *dev) {}
|
|||
/* OF PM domain providers */
|
||||
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);
|
||||
|
||||
struct genpd_onecell_data {
|
||||
|
@ -337,11 +364,11 @@ int of_genpd_add_provider_simple(struct device_node *np,
|
|||
int of_genpd_add_provider_onecell(struct device_node *np,
|
||||
struct genpd_onecell_data *data);
|
||||
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_subdomain(struct of_phandle_args *parent_spec,
|
||||
struct of_phandle_args *subdomain_spec);
|
||||
int of_genpd_remove_subdomain(struct of_phandle_args *parent_spec,
|
||||
struct of_phandle_args *subdomain_spec);
|
||||
int of_genpd_add_device(const struct of_phandle_args *args, struct device *dev);
|
||||
int of_genpd_add_subdomain(const struct of_phandle_args *parent_spec,
|
||||
const struct of_phandle_args *subdomain_spec);
|
||||
int of_genpd_remove_subdomain(const struct of_phandle_args *parent_spec,
|
||||
const struct of_phandle_args *subdomain_spec);
|
||||
struct generic_pm_domain *of_genpd_remove_last(struct device_node *np);
|
||||
int of_genpd_parse_idle_states(struct device_node *dn,
|
||||
struct genpd_power_state **states, int *n);
|
||||
|
@ -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 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)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline int of_genpd_add_subdomain(struct of_phandle_args *parent_spec,
|
||||
struct of_phandle_args *subdomain_spec)
|
||||
static inline int of_genpd_add_subdomain(const struct of_phandle_args *parent_spec,
|
||||
const struct of_phandle_args *subdomain_spec)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline int of_genpd_remove_subdomain(struct of_phandle_args *parent_spec,
|
||||
struct of_phandle_args *subdomain_spec)
|
||||
static inline int of_genpd_remove_subdomain(const struct of_phandle_args *parent_spec,
|
||||
const struct of_phandle_args *subdomain_spec)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
@ -420,7 +447,11 @@ struct device *dev_pm_domain_attach_by_id(struct device *dev,
|
|||
unsigned int index);
|
||||
struct device *dev_pm_domain_attach_by_name(struct device *dev,
|
||||
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_list(struct dev_pm_domain_list *list);
|
||||
int dev_pm_domain_start(struct device *dev);
|
||||
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);
|
||||
|
@ -439,7 +470,14 @@ static inline struct device *dev_pm_domain_attach_by_name(struct device *dev,
|
|||
{
|
||||
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_list(struct dev_pm_domain_list *list) {}
|
||||
static inline int dev_pm_domain_start(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
|
|
Loading…
Reference in New Issue