pmdomain core:
- Leave powered-on genpds on until ->sync_state() or late_initcall_sync
- Export a common ->sync_state() helper for genpd providers
- Add generic ->sync_state() support
- Add a bus/driver for genpd provider-devices
- Introduce dev_pm_genpd_is_on() for consumers
pmdomain providers:
- cpuidle-psci: Drop redundant ->sync_state() support
- cpuidle-riscv-sbi: Drop redundant ->sync_state() support
- imx: Set ISI panic write for imx8m-blk-ctrl
- qcom: Add support for Glymur and Milos RPMh power-domains
- qcom: Use of_genpd_sync_state() for power-domains
- rockchip: Add support for the RK3528 variant
- samsung: Fix splash-screen handover by enforcing a ->sync_state()
- sunxi: Add support for Allwinner A523's PCK600 power-controller
- tegra: Opt-out from genpd's common ->sync_state() support for pmc
- thead: Instantiate a GPU power sequencer via the auxiliary bus
- renesas: Move init to postcore_initcalls
- xilinx: Move ->sync_state() support to firmware driver
- xilinx: Use of_genpd_sync_state() for power-domains
pmdomain consumers:
- remoteproc: imx_rproc: Fixup the detect/attach procedure for pre-booted cores
-----BEGIN PGP SIGNATURE-----
iQJLBAABCgA1FiEEugLDXPmKSktSkQsV/iaEJXNYjCkFAmiIqskXHHVsZi5oYW5z
c29uQGxpbmFyby5vcmcACgkQ/iaEJXNYjClOLBAAxsd5QP7QyeCePR4hADGePY4d
Ab4fX01EVsu+g5cjg7L1V8gZMbNC/O+bxVhF5s1CiDbXbEcDliuW9yKCTFq4Yqx+
7PtR+U538FADJGbbETzp8AFbcD8hmd/Wt/o7JyqC2wmmRwlgDEKPTR+M7FirrU3J
fLsE+wyJSxn8ywJ1XwQOxBOZUtq11a8UueMXb8L1DhilyjT88zqCNiMvkcLtBlh+
tRT5TWBEGr7qPCDAW6w3RL/8Y22g8xIjJxcDI8LycI/ed7qB5gtIs3ORiTl2w4qE
k78wp2Ltv1Q2AmrYiLoaciFMTXckeBycVhobf0c4zVn2HGS15Fip0YNhPQmOz3aI
JY+h5aUTMTUICVTG1D9uTW9gEbzqJOnqwU75R6zyV6xUk9pS4pGHaxaqKasNdDPy
zIVgaURMZZxq37x7TNmnQZSZ3pAisFTm8Rv4oDTOJshblhuzG0TsXTlgMuy+EONB
qh0obkHZFETrucGwaGBFVenzpnwZiEZ3EAKMGDcjBAO54waWdo+SmmJCc0KCQLih
UheFi4v0IAUm8KqzwM4CKGg5NhGo2E1FcG8YbX6t2phycQLfVHDSw3rXHJRfXOzu
s6njs7DhPKvUdlQxm1Fjq+eeMw2wsUFj8x1+usQYiD3UfuC26GU3cPsrU99+pcak
eTcWfSnpDiXpVE3pEOk=
=9SL+
-----END PGP SIGNATURE-----
Merge tag 'pmdomain-v6.17' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/linux-pm
Pull pmdomain updates from Ulf Hansson:
"pmdomain core:
- Leave powered-on genpds on until ->sync_state() or late_initcall_sync
- Export a common ->sync_state() helper for genpd providers
- Add generic ->sync_state() support
- Add a bus/driver for genpd provider-devices
- Introduce dev_pm_genpd_is_on() for consumers
pmdomain providers:
- cpuidle-psci: Drop redundant ->sync_state() support
- cpuidle-riscv-sbi: Drop redundant ->sync_state() support
- imx: Set ISI panic write for imx8m-blk-ctrl
- qcom: Add support for Glymur and Milos RPMh power-domains
- qcom: Use of_genpd_sync_state() for power-domains
- rockchip: Add support for the RK3528 variant
- samsung: Fix splash-screen handover by enforcing a ->sync_state()
- sunxi: Add support for Allwinner A523's PCK600 power-controller
- tegra: Opt-out from genpd's common ->sync_state() support for pmc
- thead: Instantiate a GPU power sequencer via the auxiliary bus
- renesas: Move init to postcore_initcalls
- xilinx: Move ->sync_state() support to firmware driver
- xilinx: Use of_genpd_sync_state() for power-domains
pmdomain consumers:
- remoteproc: imx_rproc: Fixup the detect/attach procedure for
pre-booted cores"
* tag 'pmdomain-v6.17' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/linux-pm: (44 commits)
pmdomain: qcom: rpmhpd: Add Glymur RPMh Power Domains
dt-bindings: power: rpmpd: Add Glymur power domains
remoteproc: imx_rproc: detect and attach to pre-booted remote cores
remoteproc: imx_rproc: skip clock enable when M-core is managed by the SCU
pmdomain: core: introduce dev_pm_genpd_is_on()
pmdomain: ti: Select PM_GENERIC_DOMAINS
pmdomain: sunxi: sun20i-ppu: change to tristate and enable for ARCH_SUNXI
pmdomain: sunxi: add driver for Allwinner A523's PCK-600 power controller
pmdomain: sunxi: sun20i-ppu: add A523 support
pmdomain: samsung: Fix splash-screen handover by enforcing a sync_state
cpuidle: riscv-sbi: Drop redundant sync_state support
cpuidle: psci: Drop redundant sync_state support
pmdomain: core: Leave powered-on genpds on until sync_state
pmdomain: core: Leave powered-on genpds on until late_initcall_sync
pmdomain: core: Default to use of_genpd_sync_state() for genpd providers
driver core: Add dev_set_drv_sync_state()
pmdomain: core: Add common ->sync_state() support for genpd providers
driver core: Export get_dev_from_fwnode()
firmware: xilinx: Use of_genpd_sync_state()
firmware: xilinx: Don't share zynqmp_pm_init_finalize()
...
pull/1309/head
commit
fc8f5028eb
|
|
@ -17,6 +17,7 @@ properties:
|
||||||
compatible:
|
compatible:
|
||||||
oneOf:
|
oneOf:
|
||||||
- enum:
|
- enum:
|
||||||
|
- qcom,glymur-rpmhpd
|
||||||
- qcom,mdm9607-rpmpd
|
- qcom,mdm9607-rpmpd
|
||||||
- qcom,milos-rpmhpd
|
- qcom,milos-rpmhpd
|
||||||
- qcom,msm8226-rpmpd
|
- qcom,msm8226-rpmpd
|
||||||
|
|
|
||||||
|
|
@ -1881,8 +1881,6 @@ static void fw_devlink_unblock_consumers(struct device *dev)
|
||||||
device_links_write_unlock();
|
device_links_write_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
#define get_dev_from_fwnode(fwnode) get_device((fwnode)->dev)
|
|
||||||
|
|
||||||
static bool fwnode_init_without_drv(struct fwnode_handle *fwnode)
|
static bool fwnode_init_without_drv(struct fwnode_handle *fwnode)
|
||||||
{
|
{
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
|
|
@ -5281,6 +5279,12 @@ void device_set_node(struct device *dev, struct fwnode_handle *fwnode)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(device_set_node);
|
EXPORT_SYMBOL_GPL(device_set_node);
|
||||||
|
|
||||||
|
struct device *get_dev_from_fwnode(struct fwnode_handle *fwnode)
|
||||||
|
{
|
||||||
|
return get_device((fwnode)->dev);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(get_dev_from_fwnode);
|
||||||
|
|
||||||
int device_match_name(struct device *dev, const void *name)
|
int device_match_name(struct device *dev, const void *name)
|
||||||
{
|
{
|
||||||
return sysfs_streq(dev_name(dev), name);
|
return sysfs_streq(dev_name(dev), name);
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,6 @@ struct psci_pd_provider {
|
||||||
};
|
};
|
||||||
|
|
||||||
static LIST_HEAD(psci_pd_providers);
|
static LIST_HEAD(psci_pd_providers);
|
||||||
static bool psci_pd_allow_domain_state;
|
|
||||||
|
|
||||||
static int psci_pd_power_off(struct generic_pm_domain *pd)
|
static int psci_pd_power_off(struct generic_pm_domain *pd)
|
||||||
{
|
{
|
||||||
|
|
@ -38,9 +37,6 @@ static int psci_pd_power_off(struct generic_pm_domain *pd)
|
||||||
if (!state->data)
|
if (!state->data)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!psci_pd_allow_domain_state)
|
|
||||||
return -EBUSY;
|
|
||||||
|
|
||||||
/* OSI mode is enabled, set the corresponding domain state. */
|
/* OSI mode is enabled, set the corresponding domain state. */
|
||||||
pd_state = state->data;
|
pd_state = state->data;
|
||||||
psci_set_domain_state(pd, pd->state_idx, *pd_state);
|
psci_set_domain_state(pd, pd->state_idx, *pd_state);
|
||||||
|
|
@ -126,15 +122,6 @@ static void psci_pd_remove(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void psci_cpuidle_domain_sync_state(struct device *dev)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* All devices have now been attached/probed to the PM domain topology,
|
|
||||||
* hence it's fine to allow domain states to be picked.
|
|
||||||
*/
|
|
||||||
psci_pd_allow_domain_state = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct of_device_id psci_of_match[] = {
|
static const struct of_device_id psci_of_match[] = {
|
||||||
{ .compatible = "arm,psci-1.0" },
|
{ .compatible = "arm,psci-1.0" },
|
||||||
{}
|
{}
|
||||||
|
|
@ -195,7 +182,6 @@ static struct platform_driver psci_cpuidle_domain_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "psci-cpuidle-domain",
|
.name = "psci-cpuidle-domain",
|
||||||
.of_match_table = psci_of_match,
|
.of_match_table = psci_of_match,
|
||||||
.sync_state = psci_cpuidle_domain_sync_state,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,6 @@ static DEFINE_PER_CPU_READ_MOSTLY(struct sbi_cpuidle_data, sbi_cpuidle_data);
|
||||||
static DEFINE_PER_CPU(struct sbi_domain_state, domain_state);
|
static DEFINE_PER_CPU(struct sbi_domain_state, domain_state);
|
||||||
static bool sbi_cpuidle_use_osi;
|
static bool sbi_cpuidle_use_osi;
|
||||||
static bool sbi_cpuidle_use_cpuhp;
|
static bool sbi_cpuidle_use_cpuhp;
|
||||||
static bool sbi_cpuidle_pd_allow_domain_state;
|
|
||||||
|
|
||||||
static inline void sbi_set_domain_state(u32 state)
|
static inline void sbi_set_domain_state(u32 state)
|
||||||
{
|
{
|
||||||
|
|
@ -345,15 +344,6 @@ deinit:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sbi_cpuidle_domain_sync_state(struct device *dev)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* All devices have now been attached/probed to the PM domain
|
|
||||||
* topology, hence it's fine to allow domain states to be picked.
|
|
||||||
*/
|
|
||||||
sbi_cpuidle_pd_allow_domain_state = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_DT_IDLE_GENPD
|
#ifdef CONFIG_DT_IDLE_GENPD
|
||||||
|
|
||||||
static int sbi_cpuidle_pd_power_off(struct generic_pm_domain *pd)
|
static int sbi_cpuidle_pd_power_off(struct generic_pm_domain *pd)
|
||||||
|
|
@ -364,9 +354,6 @@ static int sbi_cpuidle_pd_power_off(struct generic_pm_domain *pd)
|
||||||
if (!state->data)
|
if (!state->data)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!sbi_cpuidle_pd_allow_domain_state)
|
|
||||||
return -EBUSY;
|
|
||||||
|
|
||||||
/* OSI mode is enabled, set the corresponding domain state. */
|
/* OSI mode is enabled, set the corresponding domain state. */
|
||||||
pd_state = state->data;
|
pd_state = state->data;
|
||||||
sbi_set_domain_state(*pd_state);
|
sbi_set_domain_state(*pd_state);
|
||||||
|
|
@ -564,7 +551,6 @@ static struct platform_driver sbi_cpuidle_driver = {
|
||||||
.probe = sbi_cpuidle_probe,
|
.probe = sbi_cpuidle_probe,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "sbi-cpuidle",
|
.name = "sbi-cpuidle",
|
||||||
.sync_state = sbi_cpuidle_domain_sync_state,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_platform.h>
|
#include <linux/of_platform.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/pm_domain.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
#include <linux/hashtable.h>
|
#include <linux/hashtable.h>
|
||||||
|
|
@ -1299,11 +1300,10 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_bootmode_write);
|
||||||
* This API function is to be used for notify the power management controller
|
* This API function is to be used for notify the power management controller
|
||||||
* about the completed power management initialization.
|
* about the completed power management initialization.
|
||||||
*/
|
*/
|
||||||
int zynqmp_pm_init_finalize(void)
|
static int zynqmp_pm_init_finalize(void)
|
||||||
{
|
{
|
||||||
return zynqmp_pm_invoke_fn(PM_PM_INIT_FINALIZE, NULL, 0);
|
return zynqmp_pm_invoke_fn(PM_PM_INIT_FINALIZE, NULL, 0);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(zynqmp_pm_init_finalize);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* zynqmp_pm_set_suspend_mode() - Set system suspend mode
|
* zynqmp_pm_set_suspend_mode() - Set system suspend mode
|
||||||
|
|
@ -2100,6 +2100,19 @@ static void zynqmp_firmware_remove(struct platform_device *pdev)
|
||||||
platform_device_unregister(em_dev);
|
platform_device_unregister(em_dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void zynqmp_firmware_sync_state(struct device *dev)
|
||||||
|
{
|
||||||
|
struct device_node *np = dev->of_node;
|
||||||
|
|
||||||
|
if (!of_device_is_compatible(np, "xlnx,zynqmp-firmware"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
of_genpd_sync_state(np);
|
||||||
|
|
||||||
|
if (zynqmp_pm_init_finalize())
|
||||||
|
dev_warn(dev, "failed to release power management to firmware\n");
|
||||||
|
}
|
||||||
|
|
||||||
static const struct of_device_id zynqmp_firmware_of_match[] = {
|
static const struct of_device_id zynqmp_firmware_of_match[] = {
|
||||||
{.compatible = "xlnx,zynqmp-firmware"},
|
{.compatible = "xlnx,zynqmp-firmware"},
|
||||||
{.compatible = "xlnx,versal-firmware"},
|
{.compatible = "xlnx,versal-firmware"},
|
||||||
|
|
@ -2112,6 +2125,7 @@ static struct platform_driver zynqmp_firmware_driver = {
|
||||||
.name = "zynqmp_firmware",
|
.name = "zynqmp_firmware",
|
||||||
.of_match_table = zynqmp_firmware_of_match,
|
.of_match_table = zynqmp_firmware_of_match,
|
||||||
.dev_groups = zynqmp_firmware_groups,
|
.dev_groups = zynqmp_firmware_groups,
|
||||||
|
.sync_state = zynqmp_firmware_sync_state,
|
||||||
},
|
},
|
||||||
.probe = zynqmp_firmware_probe,
|
.probe = zynqmp_firmware_probe,
|
||||||
.remove = zynqmp_firmware_remove,
|
.remove = zynqmp_firmware_remove,
|
||||||
|
|
|
||||||
|
|
@ -342,32 +342,32 @@ static int meson_secure_pwrc_probe(struct platform_device *pdev)
|
||||||
return of_genpd_add_provider_onecell(pdev->dev.of_node, &pwrc->xlate);
|
return of_genpd_add_provider_onecell(pdev->dev.of_node, &pwrc->xlate);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct meson_secure_pwrc_domain_data meson_secure_a1_pwrc_data = {
|
static const struct meson_secure_pwrc_domain_data meson_secure_a1_pwrc_data = {
|
||||||
.domains = a1_pwrc_domains,
|
.domains = a1_pwrc_domains,
|
||||||
.count = ARRAY_SIZE(a1_pwrc_domains),
|
.count = ARRAY_SIZE(a1_pwrc_domains),
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct meson_secure_pwrc_domain_data amlogic_secure_a4_pwrc_data = {
|
static const struct meson_secure_pwrc_domain_data amlogic_secure_a4_pwrc_data = {
|
||||||
.domains = a4_pwrc_domains,
|
.domains = a4_pwrc_domains,
|
||||||
.count = ARRAY_SIZE(a4_pwrc_domains),
|
.count = ARRAY_SIZE(a4_pwrc_domains),
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct meson_secure_pwrc_domain_data amlogic_secure_a5_pwrc_data = {
|
static const struct meson_secure_pwrc_domain_data amlogic_secure_a5_pwrc_data = {
|
||||||
.domains = a5_pwrc_domains,
|
.domains = a5_pwrc_domains,
|
||||||
.count = ARRAY_SIZE(a5_pwrc_domains),
|
.count = ARRAY_SIZE(a5_pwrc_domains),
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct meson_secure_pwrc_domain_data amlogic_secure_c3_pwrc_data = {
|
static const struct meson_secure_pwrc_domain_data amlogic_secure_c3_pwrc_data = {
|
||||||
.domains = c3_pwrc_domains,
|
.domains = c3_pwrc_domains,
|
||||||
.count = ARRAY_SIZE(c3_pwrc_domains),
|
.count = ARRAY_SIZE(c3_pwrc_domains),
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct meson_secure_pwrc_domain_data meson_secure_s4_pwrc_data = {
|
static const struct meson_secure_pwrc_domain_data meson_secure_s4_pwrc_data = {
|
||||||
.domains = s4_pwrc_domains,
|
.domains = s4_pwrc_domains,
|
||||||
.count = ARRAY_SIZE(s4_pwrc_domains),
|
.count = ARRAY_SIZE(s4_pwrc_domains),
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct meson_secure_pwrc_domain_data amlogic_secure_t7_pwrc_data = {
|
static const struct meson_secure_pwrc_domain_data amlogic_secure_t7_pwrc_data = {
|
||||||
.domains = t7_pwrc_domains,
|
.domains = t7_pwrc_domains,
|
||||||
.count = ARRAY_SIZE(t7_pwrc_domains),
|
.count = ARRAY_SIZE(t7_pwrc_domains),
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ config APPLE_PMGR_PWRSTATE
|
||||||
select MFD_SYSCON
|
select MFD_SYSCON
|
||||||
select PM_GENERIC_DOMAINS
|
select PM_GENERIC_DOMAINS
|
||||||
select RESET_CONTROLLER
|
select RESET_CONTROLLER
|
||||||
default ARCH_APPLE
|
|
||||||
help
|
help
|
||||||
The PMGR block in Apple SoCs provides high-level power state
|
The PMGR block in Apple SoCs provides high-level power state
|
||||||
controls for SoC devices. This driver manages them through the
|
controls for SoC devices. This driver manages them through the
|
||||||
|
|
|
||||||
|
|
@ -22,27 +22,21 @@ struct scmi_pm_domain {
|
||||||
|
|
||||||
#define to_scmi_pd(gpd) container_of(gpd, struct scmi_pm_domain, genpd)
|
#define to_scmi_pd(gpd) container_of(gpd, struct scmi_pm_domain, genpd)
|
||||||
|
|
||||||
static int scmi_pd_power(struct generic_pm_domain *domain, bool power_on)
|
static int scmi_pd_power(struct generic_pm_domain *domain, u32 state)
|
||||||
{
|
{
|
||||||
u32 state;
|
|
||||||
struct scmi_pm_domain *pd = to_scmi_pd(domain);
|
struct scmi_pm_domain *pd = to_scmi_pd(domain);
|
||||||
|
|
||||||
if (power_on)
|
|
||||||
state = SCMI_POWER_STATE_GENERIC_ON;
|
|
||||||
else
|
|
||||||
state = SCMI_POWER_STATE_GENERIC_OFF;
|
|
||||||
|
|
||||||
return power_ops->state_set(pd->ph, pd->domain, state);
|
return power_ops->state_set(pd->ph, pd->domain, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int scmi_pd_power_on(struct generic_pm_domain *domain)
|
static int scmi_pd_power_on(struct generic_pm_domain *domain)
|
||||||
{
|
{
|
||||||
return scmi_pd_power(domain, true);
|
return scmi_pd_power(domain, SCMI_POWER_STATE_GENERIC_ON);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int scmi_pd_power_off(struct generic_pm_domain *domain)
|
static int scmi_pd_power_off(struct generic_pm_domain *domain)
|
||||||
{
|
{
|
||||||
return scmi_pd_power(domain, false);
|
return scmi_pd_power(domain, SCMI_POWER_STATE_GENERIC_OFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int scmi_pm_domain_probe(struct scmi_device *sdev)
|
static int scmi_pm_domain_probe(struct scmi_device *sdev)
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,16 @@
|
||||||
/* Provides a unique ID for each genpd device */
|
/* Provides a unique ID for each genpd device */
|
||||||
static DEFINE_IDA(genpd_ida);
|
static DEFINE_IDA(genpd_ida);
|
||||||
|
|
||||||
|
/* The bus for genpd_providers. */
|
||||||
|
static const struct bus_type genpd_provider_bus_type = {
|
||||||
|
.name = "genpd_provider",
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The parent for genpd_provider devices. */
|
||||||
|
static struct device genpd_provider_bus = {
|
||||||
|
.init_name = "genpd_provider",
|
||||||
|
};
|
||||||
|
|
||||||
#define GENPD_RETRY_MAX_MS 250 /* Approximate */
|
#define GENPD_RETRY_MAX_MS 250 /* Approximate */
|
||||||
|
|
||||||
#define GENPD_DEV_CALLBACK(genpd, type, callback, dev) \
|
#define GENPD_DEV_CALLBACK(genpd, type, callback, dev) \
|
||||||
|
|
@ -176,6 +186,7 @@ static const struct genpd_lock_ops genpd_raw_spin_ops = {
|
||||||
#define genpd_is_rpm_always_on(genpd) (genpd->flags & GENPD_FLAG_RPM_ALWAYS_ON)
|
#define genpd_is_rpm_always_on(genpd) (genpd->flags & GENPD_FLAG_RPM_ALWAYS_ON)
|
||||||
#define genpd_is_opp_table_fw(genpd) (genpd->flags & GENPD_FLAG_OPP_TABLE_FW)
|
#define genpd_is_opp_table_fw(genpd) (genpd->flags & GENPD_FLAG_OPP_TABLE_FW)
|
||||||
#define genpd_is_dev_name_fw(genpd) (genpd->flags & GENPD_FLAG_DEV_NAME_FW)
|
#define genpd_is_dev_name_fw(genpd) (genpd->flags & GENPD_FLAG_DEV_NAME_FW)
|
||||||
|
#define genpd_is_no_sync_state(genpd) (genpd->flags & GENPD_FLAG_NO_SYNC_STATE)
|
||||||
|
|
||||||
static inline bool irq_safe_dev_in_sleep_domain(struct device *dev,
|
static inline bool irq_safe_dev_in_sleep_domain(struct device *dev,
|
||||||
const struct generic_pm_domain *genpd)
|
const struct generic_pm_domain *genpd)
|
||||||
|
|
@ -758,6 +769,39 @@ int dev_pm_genpd_rpm_always_on(struct device *dev, bool on)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(dev_pm_genpd_rpm_always_on);
|
EXPORT_SYMBOL_GPL(dev_pm_genpd_rpm_always_on);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dev_pm_genpd_is_on() - Get device's current power domain status
|
||||||
|
*
|
||||||
|
* @dev: Device to get the current power status
|
||||||
|
*
|
||||||
|
* This function checks whether the generic power domain associated with the
|
||||||
|
* given device is on or not by verifying if genpd_status_on equals
|
||||||
|
* GENPD_STATE_ON.
|
||||||
|
*
|
||||||
|
* Note: this function returns the power status of the genpd at the time of the
|
||||||
|
* call. The power status may change after due to activity from other devices
|
||||||
|
* sharing the same genpd. Therefore, this information should not be relied for
|
||||||
|
* long-term decisions about the device power state.
|
||||||
|
*
|
||||||
|
* Return: 'true' if the device's power domain is on, 'false' otherwise.
|
||||||
|
*/
|
||||||
|
bool dev_pm_genpd_is_on(struct device *dev)
|
||||||
|
{
|
||||||
|
struct generic_pm_domain *genpd;
|
||||||
|
bool is_on;
|
||||||
|
|
||||||
|
genpd = dev_to_genpd_safe(dev);
|
||||||
|
if (!genpd)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
genpd_lock(genpd);
|
||||||
|
is_on = genpd_status_on(genpd);
|
||||||
|
genpd_unlock(genpd);
|
||||||
|
|
||||||
|
return is_on;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(dev_pm_genpd_is_on);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pm_genpd_inc_rejected() - Adjust the rejected/usage counts for an idle-state.
|
* pm_genpd_inc_rejected() - Adjust the rejected/usage counts for an idle-state.
|
||||||
*
|
*
|
||||||
|
|
@ -920,11 +964,12 @@ static void genpd_power_off(struct generic_pm_domain *genpd, bool one_dev_on,
|
||||||
* The domain is already in the "power off" state.
|
* The domain is already in the "power off" state.
|
||||||
* System suspend is in progress.
|
* System suspend is in progress.
|
||||||
* The domain is configured as always on.
|
* The domain is configured as always on.
|
||||||
|
* The domain was on at boot and still need to stay on.
|
||||||
* The domain has a subdomain being powered on.
|
* The domain has a subdomain being powered on.
|
||||||
*/
|
*/
|
||||||
if (!genpd_status_on(genpd) || genpd->prepared_count > 0 ||
|
if (!genpd_status_on(genpd) || genpd->prepared_count > 0 ||
|
||||||
genpd_is_always_on(genpd) || genpd_is_rpm_always_on(genpd) ||
|
genpd_is_always_on(genpd) || genpd_is_rpm_always_on(genpd) ||
|
||||||
atomic_read(&genpd->sd_count) > 0)
|
genpd->stay_on || atomic_read(&genpd->sd_count) > 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -1312,6 +1357,7 @@ err_poweroff:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef CONFIG_PM_GENERIC_DOMAINS_OF
|
||||||
static bool pd_ignore_unused;
|
static bool pd_ignore_unused;
|
||||||
static int __init pd_ignore_unused_setup(char *__unused)
|
static int __init pd_ignore_unused_setup(char *__unused)
|
||||||
{
|
{
|
||||||
|
|
@ -1335,14 +1381,19 @@ static int __init genpd_power_off_unused(void)
|
||||||
pr_info("genpd: Disabling unused power domains\n");
|
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) {
|
||||||
|
genpd_lock(genpd);
|
||||||
|
genpd->stay_on = false;
|
||||||
|
genpd_unlock(genpd);
|
||||||
genpd_queue_power_off_work(genpd);
|
genpd_queue_power_off_work(genpd);
|
||||||
|
}
|
||||||
|
|
||||||
mutex_unlock(&gpd_list_lock);
|
mutex_unlock(&gpd_list_lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
late_initcall_sync(genpd_power_off_unused);
|
late_initcall_sync(genpd_power_off_unused);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_PM_SLEEP
|
#ifdef CONFIG_PM_SLEEP
|
||||||
|
|
||||||
|
|
@ -2262,6 +2313,8 @@ static int genpd_alloc_data(struct generic_pm_domain *genpd)
|
||||||
genpd->gd = gd;
|
genpd->gd = gd;
|
||||||
device_initialize(&genpd->dev);
|
device_initialize(&genpd->dev);
|
||||||
genpd->dev.release = genpd_provider_release;
|
genpd->dev.release = genpd_provider_release;
|
||||||
|
genpd->dev.bus = &genpd_provider_bus_type;
|
||||||
|
genpd->dev.parent = &genpd_provider_bus;
|
||||||
|
|
||||||
if (!genpd_is_dev_name_fw(genpd)) {
|
if (!genpd_is_dev_name_fw(genpd)) {
|
||||||
dev_set_name(&genpd->dev, "%s", genpd->name);
|
dev_set_name(&genpd->dev, "%s", genpd->name);
|
||||||
|
|
@ -2339,6 +2392,8 @@ int pm_genpd_init(struct generic_pm_domain *genpd,
|
||||||
INIT_WORK(&genpd->power_off_work, genpd_power_off_work_fn);
|
INIT_WORK(&genpd->power_off_work, genpd_power_off_work_fn);
|
||||||
atomic_set(&genpd->sd_count, 0);
|
atomic_set(&genpd->sd_count, 0);
|
||||||
genpd->status = is_off ? GENPD_STATE_OFF : GENPD_STATE_ON;
|
genpd->status = is_off ? GENPD_STATE_OFF : GENPD_STATE_ON;
|
||||||
|
genpd->stay_on = !is_off;
|
||||||
|
genpd->sync_state = GENPD_SYNC_STATE_OFF;
|
||||||
genpd->device_count = 0;
|
genpd->device_count = 0;
|
||||||
genpd->provider = NULL;
|
genpd->provider = NULL;
|
||||||
genpd->device_id = -ENXIO;
|
genpd->device_id = -ENXIO;
|
||||||
|
|
@ -2491,6 +2546,8 @@ struct of_genpd_provider {
|
||||||
static LIST_HEAD(of_genpd_providers);
|
static LIST_HEAD(of_genpd_providers);
|
||||||
/* Mutex to protect the list above. */
|
/* Mutex to protect the list above. */
|
||||||
static DEFINE_MUTEX(of_genpd_mutex);
|
static DEFINE_MUTEX(of_genpd_mutex);
|
||||||
|
/* Used to prevent registering devices before the bus. */
|
||||||
|
static bool genpd_bus_registered;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* genpd_xlate_simple() - Xlate function for direct node-domain mapping
|
* genpd_xlate_simple() - Xlate function for direct node-domain mapping
|
||||||
|
|
@ -2557,7 +2614,7 @@ static int genpd_add_provider(struct device_node *np, genpd_xlate_t xlate,
|
||||||
cp->node = of_node_get(np);
|
cp->node = of_node_get(np);
|
||||||
cp->data = data;
|
cp->data = data;
|
||||||
cp->xlate = xlate;
|
cp->xlate = xlate;
|
||||||
fwnode_dev_initialized(&np->fwnode, true);
|
fwnode_dev_initialized(of_fwnode_handle(np), true);
|
||||||
|
|
||||||
mutex_lock(&of_genpd_mutex);
|
mutex_lock(&of_genpd_mutex);
|
||||||
list_add(&cp->link, &of_genpd_providers);
|
list_add(&cp->link, &of_genpd_providers);
|
||||||
|
|
@ -2584,6 +2641,11 @@ static bool genpd_present(const struct generic_pm_domain *genpd)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void genpd_sync_state(struct device *dev)
|
||||||
|
{
|
||||||
|
return of_genpd_sync_state(dev->of_node);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* of_genpd_add_provider_simple() - Register a simple PM domain provider
|
* of_genpd_add_provider_simple() - Register a simple PM domain provider
|
||||||
* @np: Device node pointer associated with the PM domain provider.
|
* @np: Device node pointer associated with the PM domain provider.
|
||||||
|
|
@ -2592,21 +2654,43 @@ static bool genpd_present(const struct generic_pm_domain *genpd)
|
||||||
int of_genpd_add_provider_simple(struct device_node *np,
|
int of_genpd_add_provider_simple(struct device_node *np,
|
||||||
struct generic_pm_domain *genpd)
|
struct generic_pm_domain *genpd)
|
||||||
{
|
{
|
||||||
|
struct fwnode_handle *fwnode;
|
||||||
|
struct device *dev;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!np || !genpd)
|
if (!np || !genpd)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!genpd_bus_registered)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
if (!genpd_present(genpd))
|
if (!genpd_present(genpd))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
genpd->dev.of_node = np;
|
genpd->dev.of_node = np;
|
||||||
|
|
||||||
|
fwnode = of_fwnode_handle(np);
|
||||||
|
dev = get_dev_from_fwnode(fwnode);
|
||||||
|
if (!dev && !genpd_is_no_sync_state(genpd)) {
|
||||||
|
genpd->sync_state = GENPD_SYNC_STATE_SIMPLE;
|
||||||
|
device_set_node(&genpd->dev, fwnode);
|
||||||
|
} else {
|
||||||
|
dev_set_drv_sync_state(dev, genpd_sync_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
put_device(dev);
|
||||||
|
|
||||||
|
ret = device_add(&genpd->dev);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
/* Parse genpd OPP table */
|
/* Parse genpd OPP table */
|
||||||
if (!genpd_is_opp_table_fw(genpd) && genpd->set_performance_state) {
|
if (!genpd_is_opp_table_fw(genpd) && genpd->set_performance_state) {
|
||||||
ret = dev_pm_opp_of_add_table(&genpd->dev);
|
ret = dev_pm_opp_of_add_table(&genpd->dev);
|
||||||
if (ret)
|
if (ret) {
|
||||||
return dev_err_probe(&genpd->dev, ret, "Failed to add OPP table\n");
|
dev_err_probe(&genpd->dev, ret, "Failed to add OPP table\n");
|
||||||
|
goto err_del;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Save table for faster processing while setting performance
|
* Save table for faster processing while setting performance
|
||||||
|
|
@ -2617,19 +2701,22 @@ int of_genpd_add_provider_simple(struct device_node *np,
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = genpd_add_provider(np, genpd_xlate_simple, genpd);
|
ret = genpd_add_provider(np, genpd_xlate_simple, genpd);
|
||||||
if (ret) {
|
if (ret)
|
||||||
if (genpd->opp_table) {
|
goto err_opp;
|
||||||
dev_pm_opp_put_opp_table(genpd->opp_table);
|
|
||||||
dev_pm_opp_of_remove_table(&genpd->dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
genpd->provider = fwnode;
|
||||||
}
|
|
||||||
|
|
||||||
genpd->provider = &np->fwnode;
|
|
||||||
genpd->has_provider = true;
|
genpd->has_provider = true;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
err_opp:
|
||||||
|
if (genpd->opp_table) {
|
||||||
|
dev_pm_opp_put_opp_table(genpd->opp_table);
|
||||||
|
dev_pm_opp_of_remove_table(&genpd->dev);
|
||||||
|
}
|
||||||
|
err_del:
|
||||||
|
device_del(&genpd->dev);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(of_genpd_add_provider_simple);
|
EXPORT_SYMBOL_GPL(of_genpd_add_provider_simple);
|
||||||
|
|
||||||
|
|
@ -2642,15 +2729,30 @@ int of_genpd_add_provider_onecell(struct device_node *np,
|
||||||
struct genpd_onecell_data *data)
|
struct genpd_onecell_data *data)
|
||||||
{
|
{
|
||||||
struct generic_pm_domain *genpd;
|
struct generic_pm_domain *genpd;
|
||||||
|
struct fwnode_handle *fwnode;
|
||||||
|
struct device *dev;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
int ret = -EINVAL;
|
int ret = -EINVAL;
|
||||||
|
bool sync_state = false;
|
||||||
|
|
||||||
if (!np || !data)
|
if (!np || !data)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!genpd_bus_registered)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
if (!data->xlate)
|
if (!data->xlate)
|
||||||
data->xlate = genpd_xlate_onecell;
|
data->xlate = genpd_xlate_onecell;
|
||||||
|
|
||||||
|
fwnode = of_fwnode_handle(np);
|
||||||
|
dev = get_dev_from_fwnode(fwnode);
|
||||||
|
if (!dev)
|
||||||
|
sync_state = true;
|
||||||
|
else
|
||||||
|
dev_set_drv_sync_state(dev, genpd_sync_state);
|
||||||
|
|
||||||
|
put_device(dev);
|
||||||
|
|
||||||
for (i = 0; i < data->num_domains; i++) {
|
for (i = 0; i < data->num_domains; i++) {
|
||||||
genpd = data->domains[i];
|
genpd = data->domains[i];
|
||||||
|
|
||||||
|
|
@ -2661,12 +2763,23 @@ int of_genpd_add_provider_onecell(struct device_node *np,
|
||||||
|
|
||||||
genpd->dev.of_node = np;
|
genpd->dev.of_node = np;
|
||||||
|
|
||||||
|
if (sync_state && !genpd_is_no_sync_state(genpd)) {
|
||||||
|
genpd->sync_state = GENPD_SYNC_STATE_ONECELL;
|
||||||
|
device_set_node(&genpd->dev, fwnode);
|
||||||
|
sync_state = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = device_add(&genpd->dev);
|
||||||
|
if (ret)
|
||||||
|
goto error;
|
||||||
|
|
||||||
/* Parse genpd OPP table */
|
/* Parse genpd OPP table */
|
||||||
if (!genpd_is_opp_table_fw(genpd) && genpd->set_performance_state) {
|
if (!genpd_is_opp_table_fw(genpd) && genpd->set_performance_state) {
|
||||||
ret = dev_pm_opp_of_add_table_indexed(&genpd->dev, i);
|
ret = dev_pm_opp_of_add_table_indexed(&genpd->dev, i);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err_probe(&genpd->dev, ret,
|
dev_err_probe(&genpd->dev, ret,
|
||||||
"Failed to add OPP table for index %d\n", i);
|
"Failed to add OPP table for index %d\n", i);
|
||||||
|
device_del(&genpd->dev);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2678,7 +2791,7 @@ int of_genpd_add_provider_onecell(struct device_node *np,
|
||||||
WARN_ON(IS_ERR(genpd->opp_table));
|
WARN_ON(IS_ERR(genpd->opp_table));
|
||||||
}
|
}
|
||||||
|
|
||||||
genpd->provider = &np->fwnode;
|
genpd->provider = fwnode;
|
||||||
genpd->has_provider = true;
|
genpd->has_provider = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2702,6 +2815,8 @@ error:
|
||||||
dev_pm_opp_put_opp_table(genpd->opp_table);
|
dev_pm_opp_put_opp_table(genpd->opp_table);
|
||||||
dev_pm_opp_of_remove_table(&genpd->dev);
|
dev_pm_opp_of_remove_table(&genpd->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
device_del(&genpd->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
@ -2727,17 +2842,19 @@ void of_genpd_del_provider(struct device_node *np)
|
||||||
* so that the PM domain can be safely removed.
|
* so that the PM domain can be safely removed.
|
||||||
*/
|
*/
|
||||||
list_for_each_entry(gpd, &gpd_list, gpd_list_node) {
|
list_for_each_entry(gpd, &gpd_list, gpd_list_node) {
|
||||||
if (gpd->provider == &np->fwnode) {
|
if (gpd->provider == of_fwnode_handle(np)) {
|
||||||
gpd->has_provider = false;
|
gpd->has_provider = false;
|
||||||
|
|
||||||
if (gpd->opp_table) {
|
if (gpd->opp_table) {
|
||||||
dev_pm_opp_put_opp_table(gpd->opp_table);
|
dev_pm_opp_put_opp_table(gpd->opp_table);
|
||||||
dev_pm_opp_of_remove_table(&gpd->dev);
|
dev_pm_opp_of_remove_table(&gpd->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
device_del(&gpd->dev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fwnode_dev_initialized(&cp->node->fwnode, false);
|
fwnode_dev_initialized(of_fwnode_handle(cp->node), false);
|
||||||
list_del(&cp->link);
|
list_del(&cp->link);
|
||||||
of_node_put(cp->node);
|
of_node_put(cp->node);
|
||||||
kfree(cp);
|
kfree(cp);
|
||||||
|
|
@ -2916,7 +3033,7 @@ struct generic_pm_domain *of_genpd_remove_last(struct device_node *np)
|
||||||
|
|
||||||
mutex_lock(&gpd_list_lock);
|
mutex_lock(&gpd_list_lock);
|
||||||
list_for_each_entry_safe(gpd, tmp, &gpd_list, gpd_list_node) {
|
list_for_each_entry_safe(gpd, tmp, &gpd_list, gpd_list_node) {
|
||||||
if (gpd->provider == &np->fwnode) {
|
if (gpd->provider == of_fwnode_handle(np)) {
|
||||||
ret = genpd_remove(gpd);
|
ret = genpd_remove(gpd);
|
||||||
genpd = ret ? ERR_PTR(ret) : gpd;
|
genpd = ret ? ERR_PTR(ret) : gpd;
|
||||||
break;
|
break;
|
||||||
|
|
@ -3179,6 +3296,9 @@ struct device *genpd_dev_pm_attach_by_id(struct device *dev,
|
||||||
if (num_domains < 0 || index >= num_domains)
|
if (num_domains < 0 || index >= num_domains)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
if (!genpd_bus_registered)
|
||||||
|
return ERR_PTR(-ENODEV);
|
||||||
|
|
||||||
/* Allocate and register device on the genpd bus. */
|
/* Allocate and register device on the genpd bus. */
|
||||||
virt_dev = kzalloc(sizeof(*virt_dev), GFP_KERNEL);
|
virt_dev = kzalloc(sizeof(*virt_dev), GFP_KERNEL);
|
||||||
if (!virt_dev)
|
if (!virt_dev)
|
||||||
|
|
@ -3269,7 +3389,7 @@ static int genpd_parse_state(struct genpd_power_state *genpd_state,
|
||||||
|
|
||||||
genpd_state->power_on_latency_ns = 1000LL * exit_latency;
|
genpd_state->power_on_latency_ns = 1000LL * exit_latency;
|
||||||
genpd_state->power_off_latency_ns = 1000LL * entry_latency;
|
genpd_state->power_off_latency_ns = 1000LL * entry_latency;
|
||||||
genpd_state->fwnode = &state_node->fwnode;
|
genpd_state->fwnode = of_fwnode_handle(state_node);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -3355,9 +3475,103 @@ int of_genpd_parse_idle_states(struct device_node *dn,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(of_genpd_parse_idle_states);
|
EXPORT_SYMBOL_GPL(of_genpd_parse_idle_states);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* of_genpd_sync_state() - A common sync_state function for genpd providers
|
||||||
|
* @np: The device node the genpd provider is associated with.
|
||||||
|
*
|
||||||
|
* The @np that corresponds to a genpd provider may provide one or multiple
|
||||||
|
* genpds. This function makes use @np to find the genpds that belongs to the
|
||||||
|
* provider. For each genpd we try a power-off.
|
||||||
|
*/
|
||||||
|
void of_genpd_sync_state(struct device_node *np)
|
||||||
|
{
|
||||||
|
struct generic_pm_domain *genpd;
|
||||||
|
|
||||||
|
if (!np)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mutex_lock(&gpd_list_lock);
|
||||||
|
list_for_each_entry(genpd, &gpd_list, gpd_list_node) {
|
||||||
|
if (genpd->provider == of_fwnode_handle(np)) {
|
||||||
|
genpd_lock(genpd);
|
||||||
|
genpd->stay_on = false;
|
||||||
|
genpd_power_off(genpd, false, 0);
|
||||||
|
genpd_unlock(genpd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mutex_unlock(&gpd_list_lock);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(of_genpd_sync_state);
|
||||||
|
|
||||||
|
static int genpd_provider_probe(struct device *dev)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void genpd_provider_sync_state(struct device *dev)
|
||||||
|
{
|
||||||
|
struct generic_pm_domain *genpd = container_of(dev, struct generic_pm_domain, dev);
|
||||||
|
|
||||||
|
switch (genpd->sync_state) {
|
||||||
|
case GENPD_SYNC_STATE_OFF:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GENPD_SYNC_STATE_ONECELL:
|
||||||
|
of_genpd_sync_state(dev->of_node);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GENPD_SYNC_STATE_SIMPLE:
|
||||||
|
genpd_lock(genpd);
|
||||||
|
genpd->stay_on = false;
|
||||||
|
genpd_power_off(genpd, false, 0);
|
||||||
|
genpd_unlock(genpd);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct device_driver genpd_provider_drv = {
|
||||||
|
.name = "genpd_provider",
|
||||||
|
.bus = &genpd_provider_bus_type,
|
||||||
|
.probe = genpd_provider_probe,
|
||||||
|
.sync_state = genpd_provider_sync_state,
|
||||||
|
.suppress_bind_attrs = true,
|
||||||
|
};
|
||||||
|
|
||||||
static int __init genpd_bus_init(void)
|
static int __init genpd_bus_init(void)
|
||||||
{
|
{
|
||||||
return bus_register(&genpd_bus_type);
|
int ret;
|
||||||
|
|
||||||
|
ret = device_register(&genpd_provider_bus);
|
||||||
|
if (ret) {
|
||||||
|
put_device(&genpd_provider_bus);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = bus_register(&genpd_provider_bus_type);
|
||||||
|
if (ret)
|
||||||
|
goto err_dev;
|
||||||
|
|
||||||
|
ret = bus_register(&genpd_bus_type);
|
||||||
|
if (ret)
|
||||||
|
goto err_prov_bus;
|
||||||
|
|
||||||
|
ret = driver_register(&genpd_provider_drv);
|
||||||
|
if (ret)
|
||||||
|
goto err_bus;
|
||||||
|
|
||||||
|
genpd_bus_registered = true;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_bus:
|
||||||
|
bus_unregister(&genpd_bus_type);
|
||||||
|
err_prov_bus:
|
||||||
|
bus_unregister(&genpd_provider_bus_type);
|
||||||
|
err_dev:
|
||||||
|
device_unregister(&genpd_provider_bus);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
core_initcall(genpd_bus_init);
|
core_initcall(genpd_bus_init);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -665,6 +665,11 @@ static const struct imx8m_blk_ctrl_data imx8mn_disp_blk_ctl_dev_data = {
|
||||||
#define LCDIF_1_RD_HURRY GENMASK(15, 13)
|
#define LCDIF_1_RD_HURRY GENMASK(15, 13)
|
||||||
#define LCDIF_0_RD_HURRY GENMASK(12, 10)
|
#define LCDIF_0_RD_HURRY GENMASK(12, 10)
|
||||||
|
|
||||||
|
#define ISI_CACHE_CTRL 0x50
|
||||||
|
#define ISI_V_WR_HURRY GENMASK(28, 26)
|
||||||
|
#define ISI_U_WR_HURRY GENMASK(25, 23)
|
||||||
|
#define ISI_Y_WR_HURRY GENMASK(22, 20)
|
||||||
|
|
||||||
static int imx8mp_media_power_notifier(struct notifier_block *nb,
|
static int imx8mp_media_power_notifier(struct notifier_block *nb,
|
||||||
unsigned long action, void *data)
|
unsigned long action, void *data)
|
||||||
{
|
{
|
||||||
|
|
@ -694,6 +699,11 @@ static int imx8mp_media_power_notifier(struct notifier_block *nb,
|
||||||
regmap_set_bits(bc->regmap, LCDIF_ARCACHE_CTRL,
|
regmap_set_bits(bc->regmap, LCDIF_ARCACHE_CTRL,
|
||||||
FIELD_PREP(LCDIF_1_RD_HURRY, 7) |
|
FIELD_PREP(LCDIF_1_RD_HURRY, 7) |
|
||||||
FIELD_PREP(LCDIF_0_RD_HURRY, 7));
|
FIELD_PREP(LCDIF_0_RD_HURRY, 7));
|
||||||
|
/* Same here for ISI */
|
||||||
|
regmap_set_bits(bc->regmap, ISI_CACHE_CTRL,
|
||||||
|
FIELD_PREP(ISI_V_WR_HURRY, 7) |
|
||||||
|
FIELD_PREP(ISI_U_WR_HURRY, 7) |
|
||||||
|
FIELD_PREP(ISI_Y_WR_HURRY, 7));
|
||||||
}
|
}
|
||||||
|
|
||||||
return NOTIFY_OK;
|
return NOTIFY_OK;
|
||||||
|
|
|
||||||
|
|
@ -217,6 +217,24 @@ static struct rpmhpd gmxc = {
|
||||||
.res_name = "gmxc.lvl",
|
.res_name = "gmxc.lvl",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Milos RPMH powerdomains */
|
||||||
|
static struct rpmhpd *milos_rpmhpds[] = {
|
||||||
|
[RPMHPD_CX] = &cx,
|
||||||
|
[RPMHPD_CX_AO] = &cx_ao,
|
||||||
|
[RPMHPD_EBI] = &ebi,
|
||||||
|
[RPMHPD_GFX] = &gfx,
|
||||||
|
[RPMHPD_LCX] = &lcx,
|
||||||
|
[RPMHPD_LMX] = &lmx,
|
||||||
|
[RPMHPD_MSS] = &mss,
|
||||||
|
[RPMHPD_MX] = &mx,
|
||||||
|
[RPMHPD_MX_AO] = &mx_ao,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct rpmhpd_desc milos_desc = {
|
||||||
|
.rpmhpds = milos_rpmhpds,
|
||||||
|
.num_pds = ARRAY_SIZE(milos_rpmhpds),
|
||||||
|
};
|
||||||
|
|
||||||
/* SA8540P RPMH powerdomains */
|
/* SA8540P RPMH powerdomains */
|
||||||
static struct rpmhpd *sa8540p_rpmhpds[] = {
|
static struct rpmhpd *sa8540p_rpmhpds[] = {
|
||||||
[SC8280XP_CX] = &cx,
|
[SC8280XP_CX] = &cx,
|
||||||
|
|
@ -666,6 +684,31 @@ static const struct rpmhpd_desc sc8280xp_desc = {
|
||||||
.num_pds = ARRAY_SIZE(sc8280xp_rpmhpds),
|
.num_pds = ARRAY_SIZE(sc8280xp_rpmhpds),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Glymur RPMH powerdomains */
|
||||||
|
static struct rpmhpd *glymur_rpmhpds[] = {
|
||||||
|
[RPMHPD_CX] = &cx,
|
||||||
|
[RPMHPD_CX_AO] = &cx_ao,
|
||||||
|
[RPMHPD_EBI] = &ebi,
|
||||||
|
[RPMHPD_GFX] = &gfx,
|
||||||
|
[RPMHPD_LCX] = &lcx,
|
||||||
|
[RPMHPD_LMX] = &lmx,
|
||||||
|
[RPMHPD_MMCX] = &mmcx,
|
||||||
|
[RPMHPD_MMCX_AO] = &mmcx_ao,
|
||||||
|
[RPMHPD_MX] = &mx,
|
||||||
|
[RPMHPD_MX_AO] = &mx_ao,
|
||||||
|
[RPMHPD_MXC] = &mxc,
|
||||||
|
[RPMHPD_MXC_AO] = &mxc_ao,
|
||||||
|
[RPMHPD_MSS] = &mss,
|
||||||
|
[RPMHPD_NSP] = &nsp,
|
||||||
|
[RPMHPD_NSP2] = &nsp2,
|
||||||
|
[RPMHPD_GMXC] = &gmxc,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct rpmhpd_desc glymur_desc = {
|
||||||
|
.rpmhpds = glymur_rpmhpds,
|
||||||
|
.num_pds = ARRAY_SIZE(glymur_rpmhpds),
|
||||||
|
};
|
||||||
|
|
||||||
/* X1E80100 RPMH powerdomains */
|
/* X1E80100 RPMH powerdomains */
|
||||||
static struct rpmhpd *x1e80100_rpmhpds[] = {
|
static struct rpmhpd *x1e80100_rpmhpds[] = {
|
||||||
[RPMHPD_CX] = &cx,
|
[RPMHPD_CX] = &cx,
|
||||||
|
|
@ -723,6 +766,8 @@ static const struct rpmhpd_desc qcs615_desc = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct of_device_id rpmhpd_match_table[] = {
|
static const struct of_device_id rpmhpd_match_table[] = {
|
||||||
|
{ .compatible = "qcom,glymur-rpmhpd", .data = &glymur_desc },
|
||||||
|
{ .compatible = "qcom,milos-rpmhpd", .data = &milos_desc },
|
||||||
{ .compatible = "qcom,qcs615-rpmhpd", .data = &qcs615_desc },
|
{ .compatible = "qcom,qcs615-rpmhpd", .data = &qcs615_desc },
|
||||||
{ .compatible = "qcom,qcs8300-rpmhpd", .data = &qcs8300_desc },
|
{ .compatible = "qcom,qcs8300-rpmhpd", .data = &qcs8300_desc },
|
||||||
{ .compatible = "qcom,qdu1000-rpmhpd", .data = &qdu1000_desc },
|
{ .compatible = "qcom,qdu1000-rpmhpd", .data = &qdu1000_desc },
|
||||||
|
|
@ -1027,6 +1072,8 @@ static void rpmhpd_sync_state(struct device *dev)
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
of_genpd_sync_state(dev->of_node);
|
||||||
|
|
||||||
mutex_lock(&rpmhpd_lock);
|
mutex_lock(&rpmhpd_lock);
|
||||||
for (i = 0; i < desc->num_pds; i++) {
|
for (i = 0; i < desc->num_pds; i++) {
|
||||||
pd = rpmhpds[i];
|
pd = rpmhpds[i];
|
||||||
|
|
|
||||||
|
|
@ -1144,6 +1144,8 @@ static void rpmpd_sync_state(struct device *dev)
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
of_genpd_sync_state(dev->of_node);
|
||||||
|
|
||||||
mutex_lock(&rpmpd_lock);
|
mutex_lock(&rpmpd_lock);
|
||||||
for (i = 0; i < desc->num_pds; i++) {
|
for (i = 0; i < desc->num_pds; i++) {
|
||||||
pd = rpmpds[i];
|
pd = rpmpds[i];
|
||||||
|
|
|
||||||
|
|
@ -1,113 +1,117 @@
|
||||||
# SPDX-License-Identifier: GPL-2.0
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
if SOC_RENESAS
|
if SOC_RENESAS
|
||||||
|
menu "Renesas PM Domains"
|
||||||
|
|
||||||
|
# SoC Family
|
||||||
config SYSC_RCAR
|
config SYSC_RCAR
|
||||||
bool "System Controller support for R-Car" if COMPILE_TEST
|
bool "System Controller support for R-Car" if COMPILE_TEST
|
||||||
|
|
||||||
config SYSC_RCAR_GEN4
|
config SYSC_RCAR_GEN4
|
||||||
bool "System Controller support for R-Car Gen4" if COMPILE_TEST
|
bool "System Controller support for R-Car Gen4" if COMPILE_TEST
|
||||||
|
|
||||||
config SYSC_R8A77995
|
|
||||||
bool "System Controller support for R-Car D3" if COMPILE_TEST
|
|
||||||
select SYSC_RCAR
|
|
||||||
|
|
||||||
config SYSC_R8A7794
|
|
||||||
bool "System Controller support for R-Car E2" if COMPILE_TEST
|
|
||||||
select SYSC_RCAR
|
|
||||||
|
|
||||||
config SYSC_R8A77990
|
|
||||||
bool "System Controller support for R-Car E3" if COMPILE_TEST
|
|
||||||
select SYSC_RCAR
|
|
||||||
|
|
||||||
config SYSC_R8A7779
|
|
||||||
bool "System Controller support for R-Car H1" if COMPILE_TEST
|
|
||||||
select SYSC_RCAR
|
|
||||||
|
|
||||||
config SYSC_R8A7790
|
|
||||||
bool "System Controller support for R-Car H2" if COMPILE_TEST
|
|
||||||
select SYSC_RCAR
|
|
||||||
|
|
||||||
config SYSC_R8A7795
|
|
||||||
bool "System Controller support for R-Car H3" if COMPILE_TEST
|
|
||||||
select SYSC_RCAR
|
|
||||||
|
|
||||||
config SYSC_R8A7791
|
|
||||||
bool "System Controller support for R-Car M2-W/N" if COMPILE_TEST
|
|
||||||
select SYSC_RCAR
|
|
||||||
|
|
||||||
config SYSC_R8A77965
|
|
||||||
bool "System Controller support for R-Car M3-N" if COMPILE_TEST
|
|
||||||
select SYSC_RCAR
|
|
||||||
|
|
||||||
config SYSC_R8A77960
|
|
||||||
bool "System Controller support for R-Car M3-W" if COMPILE_TEST
|
|
||||||
select SYSC_RCAR
|
|
||||||
|
|
||||||
config SYSC_R8A77961
|
|
||||||
bool "System Controller support for R-Car M3-W+" if COMPILE_TEST
|
|
||||||
select SYSC_RCAR
|
|
||||||
|
|
||||||
config SYSC_R8A779F0
|
|
||||||
bool "System Controller support for R-Car S4-8" if COMPILE_TEST
|
|
||||||
select SYSC_RCAR_GEN4
|
|
||||||
|
|
||||||
config SYSC_R8A7792
|
|
||||||
bool "System Controller support for R-Car V2H" if COMPILE_TEST
|
|
||||||
select SYSC_RCAR
|
|
||||||
|
|
||||||
config SYSC_R8A77980
|
|
||||||
bool "System Controller support for R-Car V3H" if COMPILE_TEST
|
|
||||||
select SYSC_RCAR
|
|
||||||
|
|
||||||
config SYSC_R8A77970
|
|
||||||
bool "System Controller support for R-Car V3M" if COMPILE_TEST
|
|
||||||
select SYSC_RCAR
|
|
||||||
|
|
||||||
config SYSC_R8A779A0
|
|
||||||
bool "System Controller support for R-Car V3U" if COMPILE_TEST
|
|
||||||
select SYSC_RCAR_GEN4
|
|
||||||
|
|
||||||
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
|
config SYSC_RMOBILE
|
||||||
bool "System Controller support for R-Mobile" if COMPILE_TEST
|
bool "System Controller support for R-Mobile" if COMPILE_TEST
|
||||||
|
|
||||||
config SYSC_R8A77470
|
# SoC
|
||||||
bool "System Controller support for RZ/G1C" if COMPILE_TEST
|
|
||||||
select SYSC_RCAR
|
|
||||||
|
|
||||||
config SYSC_R8A7745
|
|
||||||
bool "System Controller support for RZ/G1E" if COMPILE_TEST
|
|
||||||
select SYSC_RCAR
|
|
||||||
|
|
||||||
config SYSC_R8A7742
|
config SYSC_R8A7742
|
||||||
bool "System Controller support for RZ/G1H" if COMPILE_TEST
|
bool "System Controller support for R8A7742 (RZ/G1H)" if COMPILE_TEST
|
||||||
select SYSC_RCAR
|
select SYSC_RCAR
|
||||||
|
|
||||||
config SYSC_R8A7743
|
config SYSC_R8A7743
|
||||||
bool "System Controller support for RZ/G1M" if COMPILE_TEST
|
bool "System Controller support for R8A7743 (RZ/G1M)" if COMPILE_TEST
|
||||||
select SYSC_RCAR
|
select SYSC_RCAR
|
||||||
|
|
||||||
config SYSC_R8A774C0
|
config SYSC_R8A7745
|
||||||
bool "System Controller support for RZ/G2E" if COMPILE_TEST
|
bool "System Controller support for R8A7745 (RZ/G1E)" if COMPILE_TEST
|
||||||
select SYSC_RCAR
|
select SYSC_RCAR
|
||||||
|
|
||||||
config SYSC_R8A774E1
|
config SYSC_R8A77470
|
||||||
bool "System Controller support for RZ/G2H" if COMPILE_TEST
|
bool "System Controller support for R8A77470 (RZ/G1C)" if COMPILE_TEST
|
||||||
select SYSC_RCAR
|
select SYSC_RCAR
|
||||||
|
|
||||||
config SYSC_R8A774A1
|
config SYSC_R8A774A1
|
||||||
bool "System Controller support for RZ/G2M" if COMPILE_TEST
|
bool "System Controller support for R8A774A1 (RZ/G2M)" if COMPILE_TEST
|
||||||
select SYSC_RCAR
|
select SYSC_RCAR
|
||||||
|
|
||||||
config SYSC_R8A774B1
|
config SYSC_R8A774B1
|
||||||
bool "System Controller support for RZ/G2N" if COMPILE_TEST
|
bool "System Controller support for R8A774B1 (RZ/G2N)" if COMPILE_TEST
|
||||||
select SYSC_RCAR
|
select SYSC_RCAR
|
||||||
|
|
||||||
|
config SYSC_R8A774C0
|
||||||
|
bool "System Controller support for R8A774C0 (RZ/G2E)" if COMPILE_TEST
|
||||||
|
select SYSC_RCAR
|
||||||
|
|
||||||
|
config SYSC_R8A774E1
|
||||||
|
bool "System Controller support for R8A774E1 (RZ/G2H)" if COMPILE_TEST
|
||||||
|
select SYSC_RCAR
|
||||||
|
|
||||||
|
config SYSC_R8A7779
|
||||||
|
bool "System Controller support for R8A7779 (R-Car H1)" if COMPILE_TEST
|
||||||
|
select SYSC_RCAR
|
||||||
|
|
||||||
|
config SYSC_R8A7790
|
||||||
|
bool "System Controller support for R8A7790 (R-Car H2)" if COMPILE_TEST
|
||||||
|
select SYSC_RCAR
|
||||||
|
|
||||||
|
config SYSC_R8A7791
|
||||||
|
bool "System Controller support for R8A7791/R8A7793 (R-Car M2-W/N)" if COMPILE_TEST
|
||||||
|
select SYSC_RCAR
|
||||||
|
|
||||||
|
config SYSC_R8A7792
|
||||||
|
bool "System Controller support for R8A7792 (R-Car V2H)" if COMPILE_TEST
|
||||||
|
select SYSC_RCAR
|
||||||
|
|
||||||
|
config SYSC_R8A7794
|
||||||
|
bool "System Controller support for R8A7794 (R-Car E2)" if COMPILE_TEST
|
||||||
|
select SYSC_RCAR
|
||||||
|
|
||||||
|
config SYSC_R8A7795
|
||||||
|
bool "System Controller support for R8A7795 (R-Car H3)" if COMPILE_TEST
|
||||||
|
select SYSC_RCAR
|
||||||
|
|
||||||
|
config SYSC_R8A77960
|
||||||
|
bool "System Controller support for R8A77960 (R-Car M3-W)" if COMPILE_TEST
|
||||||
|
select SYSC_RCAR
|
||||||
|
|
||||||
|
config SYSC_R8A77961
|
||||||
|
bool "System Controller support for R8A77961 (R-Car M3-W+)" if COMPILE_TEST
|
||||||
|
select SYSC_RCAR
|
||||||
|
|
||||||
|
config SYSC_R8A77965
|
||||||
|
bool "System Controller support for R8A77965 (R-Car M3-N)" if COMPILE_TEST
|
||||||
|
select SYSC_RCAR
|
||||||
|
|
||||||
|
config SYSC_R8A77970
|
||||||
|
bool "System Controller support for R8A77970 (R-Car V3M)" if COMPILE_TEST
|
||||||
|
select SYSC_RCAR
|
||||||
|
|
||||||
|
config SYSC_R8A77980
|
||||||
|
bool "System Controller support for R8A77980 (R-Car V3H)" if COMPILE_TEST
|
||||||
|
select SYSC_RCAR
|
||||||
|
|
||||||
|
config SYSC_R8A77990
|
||||||
|
bool "System Controller support for R8A77990 (R-Car E3)" if COMPILE_TEST
|
||||||
|
select SYSC_RCAR
|
||||||
|
|
||||||
|
config SYSC_R8A77995
|
||||||
|
bool "System Controller support for R8A77995 (R-Car D3)" if COMPILE_TEST
|
||||||
|
select SYSC_RCAR
|
||||||
|
|
||||||
|
config SYSC_R8A779A0
|
||||||
|
bool "System Controller support for R8A779A0 (R-Car V3U)" if COMPILE_TEST
|
||||||
|
select SYSC_RCAR_GEN4
|
||||||
|
|
||||||
|
config SYSC_R8A779F0
|
||||||
|
bool "System Controller support for R8A779F0 (R-Car S4-8)" if COMPILE_TEST
|
||||||
|
select SYSC_RCAR_GEN4
|
||||||
|
|
||||||
|
config SYSC_R8A779G0
|
||||||
|
bool "System Controller support for R8A779G0 (R-Car V4H)" if COMPILE_TEST
|
||||||
|
select SYSC_RCAR_GEN4
|
||||||
|
|
||||||
|
config SYSC_R8A779H0
|
||||||
|
bool "System Controller support for R8A779H0 (R-Car V4M)" if COMPILE_TEST
|
||||||
|
select SYSC_RCAR_GEN4
|
||||||
|
|
||||||
|
endmenu
|
||||||
endif
|
endif
|
||||||
|
|
|
||||||
|
|
@ -374,4 +374,4 @@ out_put:
|
||||||
of_node_put(np);
|
of_node_put(np);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
early_initcall(rcar_gen4_sysc_pd_init);
|
postcore_initcall(rcar_gen4_sysc_pd_init);
|
||||||
|
|
|
||||||
|
|
@ -342,6 +342,7 @@ struct rcar_pm_domains {
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct genpd_onecell_data *rcar_sysc_onecell_data;
|
static struct genpd_onecell_data *rcar_sysc_onecell_data;
|
||||||
|
static struct device_node *rcar_sysc_onecell_np;
|
||||||
|
|
||||||
static int __init rcar_sysc_pd_init(void)
|
static int __init rcar_sysc_pd_init(void)
|
||||||
{
|
{
|
||||||
|
|
@ -428,7 +429,8 @@ static int __init rcar_sysc_pd_init(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
error = of_genpd_add_provider_onecell(np, &domains->onecell_data);
|
rcar_sysc_onecell_np = np;
|
||||||
|
return 0;
|
||||||
|
|
||||||
out_put:
|
out_put:
|
||||||
of_node_put(np);
|
of_node_put(np);
|
||||||
|
|
@ -436,6 +438,21 @@ out_put:
|
||||||
}
|
}
|
||||||
early_initcall(rcar_sysc_pd_init);
|
early_initcall(rcar_sysc_pd_init);
|
||||||
|
|
||||||
|
static int __init rcar_sysc_pd_init_provider(void)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
|
||||||
|
if (!rcar_sysc_onecell_np)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
error = of_genpd_add_provider_onecell(rcar_sysc_onecell_np,
|
||||||
|
rcar_sysc_onecell_data);
|
||||||
|
|
||||||
|
of_node_put(rcar_sysc_onecell_np);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
postcore_initcall(rcar_sysc_pd_init_provider);
|
||||||
|
|
||||||
#ifdef CONFIG_ARCH_R8A7779
|
#ifdef CONFIG_ARCH_R8A7779
|
||||||
static int rcar_sysc_power_cpu(unsigned int idx, bool on)
|
static int rcar_sysc_power_cpu(unsigned int idx, bool on)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -335,5 +335,4 @@ static int __init rmobile_init_pm_domains(void)
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
postcore_initcall(rmobile_init_pm_domains);
|
||||||
core_initcall(rmobile_init_pm_domains);
|
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@
|
||||||
#include <dt-bindings/power/rk3366-power.h>
|
#include <dt-bindings/power/rk3366-power.h>
|
||||||
#include <dt-bindings/power/rk3368-power.h>
|
#include <dt-bindings/power/rk3368-power.h>
|
||||||
#include <dt-bindings/power/rk3399-power.h>
|
#include <dt-bindings/power/rk3399-power.h>
|
||||||
|
#include <dt-bindings/power/rockchip,rk3528-power.h>
|
||||||
#include <dt-bindings/power/rockchip,rk3562-power.h>
|
#include <dt-bindings/power/rockchip,rk3562-power.h>
|
||||||
#include <dt-bindings/power/rk3568-power.h>
|
#include <dt-bindings/power/rk3568-power.h>
|
||||||
#include <dt-bindings/power/rockchip,rk3576-power.h>
|
#include <dt-bindings/power/rockchip,rk3576-power.h>
|
||||||
|
|
@ -216,6 +217,9 @@ struct rockchip_pmu {
|
||||||
#define DOMAIN_RK3399(name, pwr, status, req, wakeup) \
|
#define DOMAIN_RK3399(name, pwr, status, req, wakeup) \
|
||||||
DOMAIN(name, pwr, status, req, req, req, wakeup)
|
DOMAIN(name, pwr, status, req, req, req, wakeup)
|
||||||
|
|
||||||
|
#define DOMAIN_RK3528(name, pwr, req) \
|
||||||
|
DOMAIN_M(name, pwr, pwr, req, req, req, false)
|
||||||
|
|
||||||
#define DOMAIN_RK3562(name, pwr, req, g_mask, mem, wakeup) \
|
#define DOMAIN_RK3562(name, pwr, req, g_mask, mem, wakeup) \
|
||||||
DOMAIN_M_G_SD(name, pwr, pwr, req, req, req, g_mask, mem, wakeup, false)
|
DOMAIN_M_G_SD(name, pwr, pwr, req, req, req, g_mask, mem, wakeup, false)
|
||||||
|
|
||||||
|
|
@ -1215,6 +1219,14 @@ static const struct rockchip_domain_info rk3399_pm_domains[] = {
|
||||||
[RK3399_PD_SDIOAUDIO] = DOMAIN_RK3399("sdioaudio", BIT(31), BIT(31), BIT(29), true),
|
[RK3399_PD_SDIOAUDIO] = DOMAIN_RK3399("sdioaudio", BIT(31), BIT(31), BIT(29), true),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct rockchip_domain_info rk3528_pm_domains[] = {
|
||||||
|
[RK3528_PD_GPU] = DOMAIN_RK3528("gpu", BIT(0), BIT(4)),
|
||||||
|
[RK3528_PD_RKVDEC] = DOMAIN_RK3528("vdec", 0, BIT(5)),
|
||||||
|
[RK3528_PD_RKVENC] = DOMAIN_RK3528("venc", 0, BIT(6)),
|
||||||
|
[RK3528_PD_VO] = DOMAIN_RK3528("vo", 0, BIT(7)),
|
||||||
|
[RK3528_PD_VPU] = DOMAIN_RK3528("vpu", 0, BIT(8)),
|
||||||
|
};
|
||||||
|
|
||||||
static const struct rockchip_domain_info rk3562_pm_domains[] = {
|
static const struct rockchip_domain_info rk3562_pm_domains[] = {
|
||||||
/* name pwr req g_mask mem wakeup */
|
/* name pwr req g_mask mem wakeup */
|
||||||
[RK3562_PD_GPU] = DOMAIN_RK3562("gpu", BIT(0), BIT(1), BIT(1), 0, false),
|
[RK3562_PD_GPU] = DOMAIN_RK3562("gpu", BIT(0), BIT(1), BIT(1), 0, false),
|
||||||
|
|
@ -1428,6 +1440,17 @@ static const struct rockchip_pmu_info rk3399_pmu = {
|
||||||
.domain_info = rk3399_pm_domains,
|
.domain_info = rk3399_pm_domains,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct rockchip_pmu_info rk3528_pmu = {
|
||||||
|
.pwr_offset = 0x1210,
|
||||||
|
.status_offset = 0x1230,
|
||||||
|
.req_offset = 0x1110,
|
||||||
|
.idle_offset = 0x1128,
|
||||||
|
.ack_offset = 0x1120,
|
||||||
|
|
||||||
|
.num_domains = ARRAY_SIZE(rk3528_pm_domains),
|
||||||
|
.domain_info = rk3528_pm_domains,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct rockchip_pmu_info rk3562_pmu = {
|
static const struct rockchip_pmu_info rk3562_pmu = {
|
||||||
.pwr_offset = 0x210,
|
.pwr_offset = 0x210,
|
||||||
.status_offset = 0x230,
|
.status_offset = 0x230,
|
||||||
|
|
@ -1538,6 +1561,10 @@ static const struct of_device_id rockchip_pm_domain_dt_match[] = {
|
||||||
.compatible = "rockchip,rk3399-power-controller",
|
.compatible = "rockchip,rk3399-power-controller",
|
||||||
.data = (void *)&rk3399_pmu,
|
.data = (void *)&rk3399_pmu,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.compatible = "rockchip,rk3528-power-controller",
|
||||||
|
.data = (void *)&rk3528_pmu,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.compatible = "rockchip,rk3562-power-controller",
|
.compatible = "rockchip,rk3562-power-controller",
|
||||||
.data = (void *)&rk3562_pmu,
|
.data = (void *)&rk3562_pmu,
|
||||||
|
|
|
||||||
|
|
@ -147,6 +147,15 @@ static int exynos_pd_probe(struct platform_device *pdev)
|
||||||
parent.np, child.np);
|
parent.np, child.np);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some Samsung platforms with bootloaders turning on the splash-screen
|
||||||
|
* and handing it over to the kernel, requires the power-domains to be
|
||||||
|
* reset during boot. As a temporary hack to manage this, let's enforce
|
||||||
|
* a sync_state.
|
||||||
|
*/
|
||||||
|
if (!ret)
|
||||||
|
of_genpd_sync_state(np);
|
||||||
|
|
||||||
pm_runtime_enable(dev);
|
pm_runtime_enable(dev);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,15 @@
|
||||||
# SPDX-License-Identifier: GPL-2.0-only
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
config SUN20I_PPU
|
config SUN20I_PPU
|
||||||
bool "Allwinner D1 PPU power domain driver"
|
tristate "Allwinner D1 PPU power domain driver"
|
||||||
depends on ARCH_SUNXI || COMPILE_TEST
|
depends on ARCH_SUNXI || COMPILE_TEST
|
||||||
depends on PM
|
depends on PM
|
||||||
|
default ARCH_SUNXI
|
||||||
select PM_GENERIC_DOMAINS
|
select PM_GENERIC_DOMAINS
|
||||||
help
|
help
|
||||||
Say y to enable the PPU power domain driver. This saves power
|
Say y to enable the PPU power domain driver. This is required
|
||||||
when certain peripherals, such as the video engine, are idle.
|
to enable power to certain peripherals, such as the display
|
||||||
|
engine.
|
||||||
|
|
||||||
config SUN50I_H6_PRCM_PPU
|
config SUN50I_H6_PRCM_PPU
|
||||||
tristate "Allwinner H6 PRCM power domain driver"
|
tristate "Allwinner H6 PRCM power domain driver"
|
||||||
|
|
@ -18,3 +20,14 @@ config SUN50I_H6_PRCM_PPU
|
||||||
Say y to enable the Allwinner H6/H616 PRCM power domain driver.
|
Say y to enable the Allwinner H6/H616 PRCM power domain driver.
|
||||||
This is required to enable the Mali GPU in the H616 SoC, it is
|
This is required to enable the Mali GPU in the H616 SoC, it is
|
||||||
optional for the H6.
|
optional for the H6.
|
||||||
|
|
||||||
|
config SUN55I_PCK600
|
||||||
|
tristate "Allwinner A523 PCK-600 power domain driver"
|
||||||
|
depends on ARCH_SUNXI || COMPILE_TEST
|
||||||
|
depends on PM
|
||||||
|
default ARCH_SUNXI
|
||||||
|
select PM_GENERIC_DOMAINS
|
||||||
|
help
|
||||||
|
Say y to enable the PCK-600 power domain driver. This is required
|
||||||
|
to enable power to certain peripherals, such as the display and
|
||||||
|
video engines.
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
# SPDX-License-Identifier: GPL-2.0-only
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
obj-$(CONFIG_SUN20I_PPU) += sun20i-ppu.o
|
obj-$(CONFIG_SUN20I_PPU) += sun20i-ppu.o
|
||||||
obj-$(CONFIG_SUN50I_H6_PRCM_PPU) += sun50i-h6-prcm-ppu.o
|
obj-$(CONFIG_SUN50I_H6_PRCM_PPU) += sun50i-h6-prcm-ppu.o
|
||||||
|
obj-$(CONFIG_SUN55I_PCK600) += sun55i-pck600.o
|
||||||
|
|
|
||||||
|
|
@ -193,6 +193,19 @@ static const struct sun20i_ppu_desc sun8i_v853_ppu_desc = {
|
||||||
.num_domains = ARRAY_SIZE(sun8i_v853_ppu_pd_names),
|
.num_domains = ARRAY_SIZE(sun8i_v853_ppu_pd_names),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const char *const sun55i_a523_ppu_pd_names[] = {
|
||||||
|
"DSP",
|
||||||
|
"NPU",
|
||||||
|
"AUDIO",
|
||||||
|
"SRAM",
|
||||||
|
"RISCV",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct sun20i_ppu_desc sun55i_a523_ppu_desc = {
|
||||||
|
.names = sun55i_a523_ppu_pd_names,
|
||||||
|
.num_domains = ARRAY_SIZE(sun55i_a523_ppu_pd_names),
|
||||||
|
};
|
||||||
|
|
||||||
static const struct of_device_id sun20i_ppu_of_match[] = {
|
static const struct of_device_id sun20i_ppu_of_match[] = {
|
||||||
{
|
{
|
||||||
.compatible = "allwinner,sun20i-d1-ppu",
|
.compatible = "allwinner,sun20i-d1-ppu",
|
||||||
|
|
@ -202,6 +215,10 @@ static const struct of_device_id sun20i_ppu_of_match[] = {
|
||||||
.compatible = "allwinner,sun8i-v853-ppu",
|
.compatible = "allwinner,sun8i-v853-ppu",
|
||||||
.data = &sun8i_v853_ppu_desc,
|
.data = &sun8i_v853_ppu_desc,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.compatible = "allwinner,sun55i-a523-ppu",
|
||||||
|
.data = &sun55i_a523_ppu_desc,
|
||||||
|
},
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, sun20i_ppu_of_match);
|
MODULE_DEVICE_TABLE(of, sun20i_ppu_of_match);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,234 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
/*
|
||||||
|
* Allwinner PCK-600 power domain support
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025 Chen-Yu Tsai <wens@csie.org>
|
||||||
|
*
|
||||||
|
* The hardware is likely based on the Arm PCK-600 IP, since some of
|
||||||
|
* the registers match Arm's documents, with additional delay controls
|
||||||
|
* that are in registers listed as reserved.
|
||||||
|
*
|
||||||
|
* Documents include:
|
||||||
|
* - "Arm CoreLink PCK-600 Power Control Kit" TRM
|
||||||
|
* - "Arm Power Policy Unit" architecture specification (DEN0051E)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/bitfield.h>
|
||||||
|
#include <linux/clk.h>
|
||||||
|
#include <linux/container_of.h>
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/dev_printk.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/iopoll.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/pm_domain.h>
|
||||||
|
#include <linux/reset.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/string_choices.h>
|
||||||
|
|
||||||
|
#define PPU_PWPR 0x0
|
||||||
|
#define PPU_PWSR 0x8
|
||||||
|
#define PPU_DCDR0 0x170
|
||||||
|
#define PPU_DCDR1 0x174
|
||||||
|
|
||||||
|
/* shared definition for PPU_PWPR and PPU_PWSR */
|
||||||
|
#define PPU_PWR_STATUS GENMASK(3, 0)
|
||||||
|
#define PPU_POWER_MODE_ON 0x8
|
||||||
|
#define PPU_POWER_MODE_OFF 0x0
|
||||||
|
|
||||||
|
#define PPU_REG_SIZE 0x1000
|
||||||
|
|
||||||
|
struct sunxi_pck600_desc {
|
||||||
|
const char * const *pd_names;
|
||||||
|
unsigned int num_domains;
|
||||||
|
u32 logic_power_switch0_delay_offset;
|
||||||
|
u32 logic_power_switch1_delay_offset;
|
||||||
|
u32 off2on_delay_offset;
|
||||||
|
u32 device_ctrl0_delay;
|
||||||
|
u32 device_ctrl1_delay;
|
||||||
|
u32 logic_power_switch0_delay;
|
||||||
|
u32 logic_power_switch1_delay;
|
||||||
|
u32 off2on_delay;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sunxi_pck600_pd {
|
||||||
|
struct generic_pm_domain genpd;
|
||||||
|
struct sunxi_pck600 *pck;
|
||||||
|
void __iomem *base;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sunxi_pck600 {
|
||||||
|
struct device *dev;
|
||||||
|
struct genpd_onecell_data genpd_data;
|
||||||
|
struct sunxi_pck600_pd pds[];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define to_sunxi_pd(gpd) container_of(gpd, struct sunxi_pck600_pd, genpd)
|
||||||
|
|
||||||
|
static int sunxi_pck600_pd_set_power(struct sunxi_pck600_pd *pd, bool on)
|
||||||
|
{
|
||||||
|
struct sunxi_pck600 *pck = pd->pck;
|
||||||
|
struct generic_pm_domain *genpd = &pd->genpd;
|
||||||
|
int ret;
|
||||||
|
u32 val, reg;
|
||||||
|
|
||||||
|
val = on ? PPU_POWER_MODE_ON : PPU_POWER_MODE_OFF;
|
||||||
|
|
||||||
|
reg = readl(pd->base + PPU_PWPR);
|
||||||
|
FIELD_MODIFY(PPU_PWR_STATUS, ®, val);
|
||||||
|
writel(reg, pd->base + PPU_PWPR);
|
||||||
|
|
||||||
|
/* push write out to hardware */
|
||||||
|
reg = readl(pd->base + PPU_PWPR);
|
||||||
|
|
||||||
|
ret = readl_poll_timeout_atomic(pd->base + PPU_PWSR, reg,
|
||||||
|
FIELD_GET(PPU_PWR_STATUS, reg) == val,
|
||||||
|
0, 10000);
|
||||||
|
if (ret)
|
||||||
|
dev_err(pck->dev, "failed to turn domain \"%s\" %s: %d\n",
|
||||||
|
genpd->name, str_on_off(on), ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sunxi_pck600_power_on(struct generic_pm_domain *domain)
|
||||||
|
{
|
||||||
|
struct sunxi_pck600_pd *pd = to_sunxi_pd(domain);
|
||||||
|
|
||||||
|
return sunxi_pck600_pd_set_power(pd, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sunxi_pck600_power_off(struct generic_pm_domain *domain)
|
||||||
|
{
|
||||||
|
struct sunxi_pck600_pd *pd = to_sunxi_pd(domain);
|
||||||
|
|
||||||
|
return sunxi_pck600_pd_set_power(pd, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sunxi_pck600_pd_setup(struct sunxi_pck600_pd *pd,
|
||||||
|
const struct sunxi_pck600_desc *desc)
|
||||||
|
{
|
||||||
|
writel(desc->device_ctrl0_delay, pd->base + PPU_DCDR0);
|
||||||
|
writel(desc->device_ctrl1_delay, pd->base + PPU_DCDR1);
|
||||||
|
writel(desc->logic_power_switch0_delay,
|
||||||
|
pd->base + desc->logic_power_switch0_delay_offset);
|
||||||
|
writel(desc->logic_power_switch1_delay,
|
||||||
|
pd->base + desc->logic_power_switch1_delay_offset);
|
||||||
|
writel(desc->off2on_delay, pd->base + desc->off2on_delay_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sunxi_pck600_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
const struct sunxi_pck600_desc *desc;
|
||||||
|
struct genpd_onecell_data *genpds;
|
||||||
|
struct sunxi_pck600 *pck;
|
||||||
|
struct reset_control *rst;
|
||||||
|
struct clk *clk;
|
||||||
|
void __iomem *base;
|
||||||
|
int i, ret;
|
||||||
|
|
||||||
|
desc = of_device_get_match_data(dev);
|
||||||
|
|
||||||
|
pck = devm_kzalloc(dev, struct_size(pck, pds, desc->num_domains), GFP_KERNEL);
|
||||||
|
if (!pck)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
pck->dev = &pdev->dev;
|
||||||
|
platform_set_drvdata(pdev, pck);
|
||||||
|
|
||||||
|
genpds = &pck->genpd_data;
|
||||||
|
genpds->num_domains = desc->num_domains;
|
||||||
|
genpds->domains = devm_kcalloc(dev, desc->num_domains,
|
||||||
|
sizeof(*genpds->domains), GFP_KERNEL);
|
||||||
|
if (!genpds->domains)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
base = devm_platform_ioremap_resource(pdev, 0);
|
||||||
|
if (IS_ERR(base))
|
||||||
|
return PTR_ERR(base);
|
||||||
|
|
||||||
|
rst = devm_reset_control_get_exclusive_released(dev, NULL);
|
||||||
|
if (IS_ERR(rst))
|
||||||
|
return dev_err_probe(dev, PTR_ERR(rst), "failed to get reset control\n");
|
||||||
|
|
||||||
|
clk = devm_clk_get_enabled(dev, NULL);
|
||||||
|
if (IS_ERR(clk))
|
||||||
|
return dev_err_probe(dev, PTR_ERR(clk), "failed to get clock\n");
|
||||||
|
|
||||||
|
for (i = 0; i < desc->num_domains; i++) {
|
||||||
|
struct sunxi_pck600_pd *pd = &pck->pds[i];
|
||||||
|
|
||||||
|
pd->genpd.name = desc->pd_names[i];
|
||||||
|
pd->genpd.power_off = sunxi_pck600_power_off;
|
||||||
|
pd->genpd.power_on = sunxi_pck600_power_on;
|
||||||
|
pd->base = base + PPU_REG_SIZE * i;
|
||||||
|
|
||||||
|
sunxi_pck600_pd_setup(pd, desc);
|
||||||
|
ret = pm_genpd_init(&pd->genpd, NULL, false);
|
||||||
|
if (ret) {
|
||||||
|
dev_err_probe(dev, ret, "failed to initialize power domain\n");
|
||||||
|
goto err_remove_pds;
|
||||||
|
}
|
||||||
|
|
||||||
|
genpds->domains[i] = &pd->genpd;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = of_genpd_add_provider_onecell(dev_of_node(dev), genpds);
|
||||||
|
if (ret) {
|
||||||
|
dev_err_probe(dev, ret, "failed to add PD provider\n");
|
||||||
|
goto err_remove_pds;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_remove_pds:
|
||||||
|
for (i--; i >= 0; i--)
|
||||||
|
pm_genpd_remove(genpds->domains[i]);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char * const sun55i_a523_pck600_pd_names[] = {
|
||||||
|
"VE", "GPU", "VI", "VO0", "VO1", "DE", "NAND", "PCIE"
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct sunxi_pck600_desc sun55i_a523_pck600_desc = {
|
||||||
|
.pd_names = sun55i_a523_pck600_pd_names,
|
||||||
|
.num_domains = ARRAY_SIZE(sun55i_a523_pck600_pd_names),
|
||||||
|
.logic_power_switch0_delay_offset = 0xc00,
|
||||||
|
.logic_power_switch1_delay_offset = 0xc04,
|
||||||
|
.off2on_delay_offset = 0xc10,
|
||||||
|
.device_ctrl0_delay = 0xffffff,
|
||||||
|
.device_ctrl1_delay = 0xffff,
|
||||||
|
.logic_power_switch0_delay = 0x8080808,
|
||||||
|
.logic_power_switch1_delay = 0x808,
|
||||||
|
.off2on_delay = 0x8
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct of_device_id sunxi_pck600_of_match[] = {
|
||||||
|
{
|
||||||
|
.compatible = "allwinner,sun55i-a523-pck-600",
|
||||||
|
.data = &sun55i_a523_pck600_desc,
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, sunxi_pck600_of_match);
|
||||||
|
|
||||||
|
static struct platform_driver sunxi_pck600_driver = {
|
||||||
|
.probe = sunxi_pck600_probe,
|
||||||
|
.driver = {
|
||||||
|
.name = "sunxi-pck-600",
|
||||||
|
.of_match_table = sunxi_pck600_of_match,
|
||||||
|
/* Power domains cannot be removed if in use. */
|
||||||
|
.suppress_bind_attrs = true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
module_platform_driver(sunxi_pck600_driver);
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION("Allwinner PCK-600 power domain driver");
|
||||||
|
MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
|
@ -4,6 +4,7 @@ config TH1520_PM_DOMAINS
|
||||||
tristate "Support TH1520 Power Domains"
|
tristate "Support TH1520 Power Domains"
|
||||||
depends on TH1520_AON_PROTOCOL
|
depends on TH1520_AON_PROTOCOL
|
||||||
select REGMAP_MMIO
|
select REGMAP_MMIO
|
||||||
|
select AUXILIARY_BUS
|
||||||
help
|
help
|
||||||
This driver enables power domain management for the T-HEAD
|
This driver enables power domain management for the T-HEAD
|
||||||
TH-1520 SoC. On this SoC there are number of power domains,
|
TH-1520 SoC. On this SoC there are number of power domains,
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
* Author: Michal Wilczynski <m.wilczynski@samsung.com>
|
* Author: Michal Wilczynski <m.wilczynski@samsung.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/auxiliary_bus.h>
|
||||||
#include <linux/firmware/thead/thead,th1520-aon.h>
|
#include <linux/firmware/thead/thead,th1520-aon.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
|
@ -128,6 +129,50 @@ static void th1520_pd_init_all_off(struct generic_pm_domain **domains,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void th1520_pd_pwrseq_unregister_adev(void *adev)
|
||||||
|
{
|
||||||
|
auxiliary_device_delete(adev);
|
||||||
|
auxiliary_device_uninit(adev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int th1520_pd_pwrseq_gpu_init(struct device *dev)
|
||||||
|
{
|
||||||
|
struct auxiliary_device *adev;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Correctly check only for the property's existence in the DT node.
|
||||||
|
* We don't need to get/claim the reset here; that is the job of
|
||||||
|
* the auxiliary driver that we are about to spawn.
|
||||||
|
*/
|
||||||
|
if (device_property_match_string(dev, "reset-names", "gpu-clkgen") < 0)
|
||||||
|
/*
|
||||||
|
* This is not an error. It simply means the optional sequencer
|
||||||
|
* is not described in the device tree.
|
||||||
|
*/
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
adev = devm_kzalloc(dev, sizeof(*adev), GFP_KERNEL);
|
||||||
|
if (!adev)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
adev->name = "pwrseq-gpu";
|
||||||
|
adev->dev.parent = dev;
|
||||||
|
|
||||||
|
ret = auxiliary_device_init(adev);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = auxiliary_device_add(adev);
|
||||||
|
if (ret) {
|
||||||
|
auxiliary_device_uninit(adev);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return devm_add_action_or_reset(dev, th1520_pd_pwrseq_unregister_adev,
|
||||||
|
adev);
|
||||||
|
}
|
||||||
|
|
||||||
static int th1520_pd_probe(struct platform_device *pdev)
|
static int th1520_pd_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct generic_pm_domain **domains;
|
struct generic_pm_domain **domains;
|
||||||
|
|
@ -186,8 +231,14 @@ static int th1520_pd_probe(struct platform_device *pdev)
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_clean_genpd;
|
goto err_clean_genpd;
|
||||||
|
|
||||||
|
ret = th1520_pd_pwrseq_gpu_init(dev);
|
||||||
|
if (ret)
|
||||||
|
goto err_clean_provider;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
err_clean_provider:
|
||||||
|
of_genpd_del_provider(dev->of_node);
|
||||||
err_clean_genpd:
|
err_clean_genpd:
|
||||||
for (i--; i >= 0; i--)
|
for (i--; i >= 0; i--)
|
||||||
pm_genpd_remove(domains[i]);
|
pm_genpd_remove(domains[i]);
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ if SOC_TI
|
||||||
config TI_SCI_PM_DOMAINS
|
config TI_SCI_PM_DOMAINS
|
||||||
tristate "TI SCI PM Domains Driver"
|
tristate "TI SCI PM Domains Driver"
|
||||||
depends on TI_SCI_PROTOCOL
|
depends on TI_SCI_PROTOCOL
|
||||||
depends on PM_GENERIC_DOMAINS
|
select PM_GENERIC_DOMAINS if PM
|
||||||
help
|
help
|
||||||
Generic power domain implementation for TI device implementing
|
Generic power domain implementation for TI device implementing
|
||||||
the TI SCI protocol.
|
the TI SCI protocol.
|
||||||
|
|
|
||||||
|
|
@ -153,14 +153,8 @@ static int zynqmp_gpd_attach_dev(struct generic_pm_domain *domain,
|
||||||
struct device *dev)
|
struct device *dev)
|
||||||
{
|
{
|
||||||
struct zynqmp_pm_domain *pd = to_zynqmp_pm_domain(domain);
|
struct zynqmp_pm_domain *pd = to_zynqmp_pm_domain(domain);
|
||||||
struct device_link *link;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
link = device_link_add(dev, &domain->dev, DL_FLAG_SYNC_STATE_ONLY);
|
|
||||||
if (!link)
|
|
||||||
dev_dbg(&domain->dev, "failed to create device link for %s\n",
|
|
||||||
dev_name(dev));
|
|
||||||
|
|
||||||
/* If this is not the first device to attach there is nothing to do */
|
/* If this is not the first device to attach there is nothing to do */
|
||||||
if (domain->device_count)
|
if (domain->device_count)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -298,19 +292,9 @@ static void zynqmp_gpd_remove(struct platform_device *pdev)
|
||||||
of_genpd_del_provider(pdev->dev.parent->of_node);
|
of_genpd_del_provider(pdev->dev.parent->of_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void zynqmp_gpd_sync_state(struct device *dev)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = zynqmp_pm_init_finalize();
|
|
||||||
if (ret)
|
|
||||||
dev_warn(dev, "failed to release power management to firmware\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct platform_driver zynqmp_power_domain_driver = {
|
static struct platform_driver zynqmp_power_domain_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "zynqmp_power_controller",
|
.name = "zynqmp_power_controller",
|
||||||
.sync_state = zynqmp_gpd_sync_state,
|
|
||||||
},
|
},
|
||||||
.probe = zynqmp_gpd_probe,
|
.probe = zynqmp_gpd_probe,
|
||||||
.remove = zynqmp_gpd_remove,
|
.remove = zynqmp_gpd_remove,
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
#include <linux/of_reserved_mem.h>
|
#include <linux/of_reserved_mem.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/pm_domain.h>
|
#include <linux/pm_domain.h>
|
||||||
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/reboot.h>
|
#include <linux/reboot.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
#include <linux/remoteproc.h>
|
#include <linux/remoteproc.h>
|
||||||
|
|
@ -890,10 +891,8 @@ 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;
|
int ret, i;
|
||||||
struct dev_pm_domain_attach_data pd_data = {
|
bool detached = true;
|
||||||
.pd_flags = PD_FLAG_DEV_LINK_ON,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there is only one power-domain entry, the platform driver framework
|
* If there is only one power-domain entry, the platform driver framework
|
||||||
|
|
@ -902,8 +901,25 @@ static int imx_rproc_attach_pd(struct imx_rproc *priv)
|
||||||
if (dev->pm_domain)
|
if (dev->pm_domain)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ret = dev_pm_domain_attach_list(dev, &pd_data, &priv->pd_list);
|
ret = dev_pm_domain_attach_list(dev, NULL, &priv->pd_list);
|
||||||
return ret < 0 ? ret : 0;
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
/*
|
||||||
|
* If all the power domain devices are already turned on, the remote
|
||||||
|
* core is already powered up and running when the kernel booted (e.g.,
|
||||||
|
* started by U-Boot's bootaux command). In this case attach to it.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < ret; i++) {
|
||||||
|
if (!dev_pm_genpd_is_on(priv->pd_list->pd_devs[i])) {
|
||||||
|
detached = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (detached)
|
||||||
|
priv->rproc->state = RPROC_DETACHED;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int imx_rproc_detect_mode(struct imx_rproc *priv)
|
static int imx_rproc_detect_mode(struct imx_rproc *priv)
|
||||||
|
|
@ -1029,8 +1045,8 @@ static int imx_rproc_clk_enable(struct imx_rproc *priv)
|
||||||
struct device *dev = priv->dev;
|
struct device *dev = priv->dev;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Remote core is not under control of Linux */
|
/* Remote core is not under control of Linux or it is managed by SCU API */
|
||||||
if (dcfg->method == IMX_RPROC_NONE)
|
if (dcfg->method == IMX_RPROC_NONE || dcfg->method == IMX_RPROC_SCU_API)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
priv->clk = devm_clk_get(dev, NULL);
|
priv->clk = devm_clk_get(dev, NULL);
|
||||||
|
|
@ -1146,6 +1162,15 @@ static int imx_rproc_probe(struct platform_device *pdev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dcfg->method == IMX_RPROC_SCU_API) {
|
||||||
|
pm_runtime_enable(dev);
|
||||||
|
ret = pm_runtime_resume_and_get(dev);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "pm_runtime get failed: %d\n", ret);
|
||||||
|
goto err_put_clk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ret = rproc_add(rproc);
|
ret = rproc_add(rproc);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "rproc_add failed\n");
|
dev_err(dev, "rproc_add failed\n");
|
||||||
|
|
@ -1171,6 +1196,10 @@ static void imx_rproc_remove(struct platform_device *pdev)
|
||||||
struct rproc *rproc = platform_get_drvdata(pdev);
|
struct rproc *rproc = platform_get_drvdata(pdev);
|
||||||
struct imx_rproc *priv = rproc->priv;
|
struct imx_rproc *priv = rproc->priv;
|
||||||
|
|
||||||
|
if (priv->dcfg->method == IMX_RPROC_SCU_API) {
|
||||||
|
pm_runtime_disable(priv->dev);
|
||||||
|
pm_runtime_put(priv->dev);
|
||||||
|
}
|
||||||
clk_disable_unprepare(priv->clk);
|
clk_disable_unprepare(priv->clk);
|
||||||
rproc_del(rproc);
|
rproc_del(rproc);
|
||||||
imx_rproc_put_scu(rproc);
|
imx_rproc_put_scu(rproc);
|
||||||
|
|
|
||||||
|
|
@ -418,7 +418,6 @@ struct tegra_pmc_soc {
|
||||||
* @irq: chip implementation for the IRQ domain
|
* @irq: chip implementation for the IRQ domain
|
||||||
* @clk_nb: pclk clock changes handler
|
* @clk_nb: pclk clock changes handler
|
||||||
* @core_domain_state_synced: flag marking the core domain's state as synced
|
* @core_domain_state_synced: flag marking the core domain's state as synced
|
||||||
* @core_domain_registered: flag marking the core domain as registered
|
|
||||||
* @wake_type_level_map: Bitmap indicating level type for non-dual edge wakes
|
* @wake_type_level_map: Bitmap indicating level type for non-dual edge wakes
|
||||||
* @wake_type_dual_edge_map: Bitmap indicating if a wake is dual-edge or not
|
* @wake_type_dual_edge_map: Bitmap indicating if a wake is dual-edge or not
|
||||||
* @wake_sw_status_map: Bitmap to hold raw status of wakes without mask
|
* @wake_sw_status_map: Bitmap to hold raw status of wakes without mask
|
||||||
|
|
@ -462,7 +461,6 @@ struct tegra_pmc {
|
||||||
struct notifier_block clk_nb;
|
struct notifier_block clk_nb;
|
||||||
|
|
||||||
bool core_domain_state_synced;
|
bool core_domain_state_synced;
|
||||||
bool core_domain_registered;
|
|
||||||
|
|
||||||
unsigned long *wake_type_level_map;
|
unsigned long *wake_type_level_map;
|
||||||
unsigned long *wake_type_dual_edge_map;
|
unsigned long *wake_type_dual_edge_map;
|
||||||
|
|
@ -1297,6 +1295,7 @@ static int tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
|
||||||
|
|
||||||
pg->id = id;
|
pg->id = id;
|
||||||
pg->genpd.name = np->name;
|
pg->genpd.name = np->name;
|
||||||
|
pg->genpd.flags = GENPD_FLAG_NO_SYNC_STATE;
|
||||||
pg->genpd.power_off = tegra_genpd_power_off;
|
pg->genpd.power_off = tegra_genpd_power_off;
|
||||||
pg->genpd.power_on = tegra_genpd_power_on;
|
pg->genpd.power_on = tegra_genpd_power_on;
|
||||||
pg->pmc = pmc;
|
pg->pmc = pmc;
|
||||||
|
|
@ -1406,6 +1405,7 @@ static int tegra_pmc_core_pd_add(struct tegra_pmc *pmc, struct device_node *np)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
genpd->name = "core";
|
genpd->name = "core";
|
||||||
|
genpd->flags = GENPD_FLAG_NO_SYNC_STATE;
|
||||||
genpd->set_performance_state = tegra_pmc_core_pd_set_performance_state;
|
genpd->set_performance_state = tegra_pmc_core_pd_set_performance_state;
|
||||||
|
|
||||||
err = devm_pm_opp_set_regulators(pmc->dev, rname);
|
err = devm_pm_opp_set_regulators(pmc->dev, rname);
|
||||||
|
|
@ -1425,8 +1425,6 @@ static int tegra_pmc_core_pd_add(struct tegra_pmc *pmc, struct device_node *np)
|
||||||
goto remove_genpd;
|
goto remove_genpd;
|
||||||
}
|
}
|
||||||
|
|
||||||
pmc->core_domain_registered = true;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
remove_genpd:
|
remove_genpd:
|
||||||
|
|
@ -4383,8 +4381,25 @@ static const struct of_device_id tegra_pmc_match[] = {
|
||||||
|
|
||||||
static void tegra_pmc_sync_state(struct device *dev)
|
static void tegra_pmc_sync_state(struct device *dev)
|
||||||
{
|
{
|
||||||
|
struct device_node *np, *child;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
np = of_get_child_by_name(dev->of_node, "powergates");
|
||||||
|
if (!np)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for_each_child_of_node(np, child)
|
||||||
|
of_genpd_sync_state(child);
|
||||||
|
|
||||||
|
of_node_put(np);
|
||||||
|
|
||||||
|
np = of_get_child_by_name(dev->of_node, "core-domain");
|
||||||
|
if (!np)
|
||||||
|
return;
|
||||||
|
|
||||||
|
of_genpd_sync_state(np);
|
||||||
|
of_node_put(np);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Newer device-trees have power domains, but we need to prepare all
|
* Newer device-trees have power domains, but we need to prepare all
|
||||||
* device drivers with runtime PM and OPP support first, otherwise
|
* device drivers with runtime PM and OPP support first, otherwise
|
||||||
|
|
@ -4398,9 +4413,6 @@ static void tegra_pmc_sync_state(struct device *dev)
|
||||||
* no dependencies that will block the state syncing. We shouldn't
|
* no dependencies that will block the state syncing. We shouldn't
|
||||||
* mark the domain as synced in this case.
|
* mark the domain as synced in this case.
|
||||||
*/
|
*/
|
||||||
if (!pmc->core_domain_registered)
|
|
||||||
return;
|
|
||||||
|
|
||||||
pmc->core_domain_state_synced = true;
|
pmc->core_domain_state_synced = true;
|
||||||
|
|
||||||
/* this is a no-op if core regulator isn't used */
|
/* this is a no-op if core regulator isn't used */
|
||||||
|
|
|
||||||
|
|
@ -944,6 +944,18 @@ static inline bool dev_has_sync_state(struct device *dev)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int dev_set_drv_sync_state(struct device *dev,
|
||||||
|
void (*fn)(struct device *dev))
|
||||||
|
{
|
||||||
|
if (!dev || !dev->driver)
|
||||||
|
return 0;
|
||||||
|
if (dev->driver->sync_state && dev->driver->sync_state != fn)
|
||||||
|
return -EBUSY;
|
||||||
|
if (!dev->driver->sync_state)
|
||||||
|
dev->driver->sync_state = fn;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void dev_set_removable(struct device *dev,
|
static inline void dev_set_removable(struct device *dev,
|
||||||
enum device_removable removable)
|
enum device_removable removable)
|
||||||
{
|
{
|
||||||
|
|
@ -1075,6 +1087,7 @@ void device_set_node(struct device *dev, struct fwnode_handle *fwnode);
|
||||||
int device_add_of_node(struct device *dev, struct device_node *of_node);
|
int device_add_of_node(struct device *dev, struct device_node *of_node);
|
||||||
void device_remove_of_node(struct device *dev);
|
void device_remove_of_node(struct device *dev);
|
||||||
void device_set_of_node_from_dev(struct device *dev, const struct device *dev2);
|
void device_set_of_node_from_dev(struct device *dev, const struct device *dev2);
|
||||||
|
struct device *get_dev_from_fwnode(struct fwnode_handle *fwnode);
|
||||||
|
|
||||||
static inline struct device_node *dev_of_node(struct device *dev)
|
static inline struct device_node *dev_of_node(struct device *dev)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -585,7 +585,6 @@ int zynqmp_pm_reset_assert(const u32 reset,
|
||||||
int zynqmp_pm_reset_get_status(const u32 reset, u32 *status);
|
int zynqmp_pm_reset_get_status(const u32 reset, u32 *status);
|
||||||
unsigned int zynqmp_pm_bootmode_read(u32 *ps_mode);
|
unsigned int zynqmp_pm_bootmode_read(u32 *ps_mode);
|
||||||
int zynqmp_pm_bootmode_write(u32 ps_mode);
|
int zynqmp_pm_bootmode_write(u32 ps_mode);
|
||||||
int zynqmp_pm_init_finalize(void);
|
|
||||||
int zynqmp_pm_set_suspend_mode(u32 mode);
|
int zynqmp_pm_set_suspend_mode(u32 mode);
|
||||||
int zynqmp_pm_request_node(const u32 node, const u32 capabilities,
|
int zynqmp_pm_request_node(const u32 node, const u32 capabilities,
|
||||||
const u32 qos, const enum zynqmp_pm_request_ack ack);
|
const u32 qos, const enum zynqmp_pm_request_ack ack);
|
||||||
|
|
@ -746,11 +745,6 @@ static inline int zynqmp_pm_bootmode_write(u32 ps_mode)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int zynqmp_pm_init_finalize(void)
|
|
||||||
{
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int zynqmp_pm_set_suspend_mode(u32 mode)
|
static inline int zynqmp_pm_set_suspend_mode(u32 mode)
|
||||||
{
|
{
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,11 @@ struct dev_pm_domain_list {
|
||||||
* GENPD_FLAG_DEV_NAME_FW: Instructs genpd to generate an unique device name
|
* GENPD_FLAG_DEV_NAME_FW: Instructs genpd to generate an unique device name
|
||||||
* using ida. It is used by genpd providers which
|
* using ida. It is used by genpd providers which
|
||||||
* get their genpd-names directly from FW.
|
* get their genpd-names directly from FW.
|
||||||
|
*
|
||||||
|
* GENPD_FLAG_NO_SYNC_STATE: The ->sync_state() support is implemented in a
|
||||||
|
* genpd provider specific way, likely through a
|
||||||
|
* parent device node. This flag makes genpd to
|
||||||
|
* skip its internal support for this.
|
||||||
*/
|
*/
|
||||||
#define GENPD_FLAG_PM_CLK (1U << 0)
|
#define GENPD_FLAG_PM_CLK (1U << 0)
|
||||||
#define GENPD_FLAG_IRQ_SAFE (1U << 1)
|
#define GENPD_FLAG_IRQ_SAFE (1U << 1)
|
||||||
|
|
@ -120,6 +125,7 @@ struct dev_pm_domain_list {
|
||||||
#define GENPD_FLAG_MIN_RESIDENCY (1U << 6)
|
#define GENPD_FLAG_MIN_RESIDENCY (1U << 6)
|
||||||
#define GENPD_FLAG_OPP_TABLE_FW (1U << 7)
|
#define GENPD_FLAG_OPP_TABLE_FW (1U << 7)
|
||||||
#define GENPD_FLAG_DEV_NAME_FW (1U << 8)
|
#define GENPD_FLAG_DEV_NAME_FW (1U << 8)
|
||||||
|
#define GENPD_FLAG_NO_SYNC_STATE (1U << 9)
|
||||||
|
|
||||||
enum gpd_status {
|
enum gpd_status {
|
||||||
GENPD_STATE_ON = 0, /* PM domain is on */
|
GENPD_STATE_ON = 0, /* PM domain is on */
|
||||||
|
|
@ -133,6 +139,12 @@ enum genpd_notication {
|
||||||
GENPD_NOTIFY_ON,
|
GENPD_NOTIFY_ON,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum genpd_sync_state {
|
||||||
|
GENPD_SYNC_STATE_OFF = 0,
|
||||||
|
GENPD_SYNC_STATE_SIMPLE,
|
||||||
|
GENPD_SYNC_STATE_ONECELL,
|
||||||
|
};
|
||||||
|
|
||||||
struct dev_power_governor {
|
struct dev_power_governor {
|
||||||
bool (*power_down_ok)(struct dev_pm_domain *domain);
|
bool (*power_down_ok)(struct dev_pm_domain *domain);
|
||||||
bool (*suspend_ok)(struct device *dev);
|
bool (*suspend_ok)(struct device *dev);
|
||||||
|
|
@ -193,6 +205,8 @@ struct generic_pm_domain {
|
||||||
unsigned int performance_state; /* Aggregated max performance state */
|
unsigned int performance_state; /* Aggregated max performance state */
|
||||||
cpumask_var_t cpus; /* A cpumask of the attached CPUs */
|
cpumask_var_t cpus; /* A cpumask of the attached CPUs */
|
||||||
bool synced_poweroff; /* A consumer needs a synced poweroff */
|
bool synced_poweroff; /* A consumer needs a synced poweroff */
|
||||||
|
bool stay_on; /* Stay powered-on during boot. */
|
||||||
|
enum genpd_sync_state sync_state; /* How sync_state is managed. */
|
||||||
int (*power_off)(struct generic_pm_domain *domain);
|
int (*power_off)(struct generic_pm_domain *domain);
|
||||||
int (*power_on)(struct generic_pm_domain *domain);
|
int (*power_on)(struct generic_pm_domain *domain);
|
||||||
struct raw_notifier_head power_notifiers; /* Power on/off notifiers */
|
struct raw_notifier_head power_notifiers; /* Power on/off notifiers */
|
||||||
|
|
@ -307,6 +321,7 @@ void dev_pm_genpd_synced_poweroff(struct device *dev);
|
||||||
int dev_pm_genpd_set_hwmode(struct device *dev, bool enable);
|
int dev_pm_genpd_set_hwmode(struct device *dev, bool enable);
|
||||||
bool dev_pm_genpd_get_hwmode(struct device *dev);
|
bool dev_pm_genpd_get_hwmode(struct device *dev);
|
||||||
int dev_pm_genpd_rpm_always_on(struct device *dev, bool on);
|
int dev_pm_genpd_rpm_always_on(struct device *dev, bool on);
|
||||||
|
bool dev_pm_genpd_is_on(struct device *dev);
|
||||||
|
|
||||||
extern struct dev_power_governor simple_qos_governor;
|
extern struct dev_power_governor simple_qos_governor;
|
||||||
extern struct dev_power_governor pm_domain_always_on_gov;
|
extern struct dev_power_governor pm_domain_always_on_gov;
|
||||||
|
|
@ -399,6 +414,11 @@ static inline int dev_pm_genpd_rpm_always_on(struct device *dev, bool on)
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool dev_pm_genpd_is_on(struct device *dev)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
#define simple_qos_governor (*(struct dev_power_governor *)(NULL))
|
#define simple_qos_governor (*(struct dev_power_governor *)(NULL))
|
||||||
#define pm_domain_always_on_gov (*(struct dev_power_governor *)(NULL))
|
#define pm_domain_always_on_gov (*(struct dev_power_governor *)(NULL))
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -437,6 +457,7 @@ int of_genpd_remove_subdomain(const struct of_phandle_args *parent_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);
|
||||||
|
void of_genpd_sync_state(struct device_node *np);
|
||||||
|
|
||||||
int genpd_dev_pm_attach(struct device *dev);
|
int genpd_dev_pm_attach(struct device *dev);
|
||||||
struct device *genpd_dev_pm_attach_by_id(struct device *dev,
|
struct device *genpd_dev_pm_attach_by_id(struct device *dev,
|
||||||
|
|
@ -482,6 +503,8 @@ static inline int of_genpd_parse_idle_states(struct device_node *dn,
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void of_genpd_sync_state(struct device_node *np) {}
|
||||||
|
|
||||||
static inline int genpd_dev_pm_attach(struct device *dev)
|
static inline int genpd_dev_pm_attach(struct device *dev)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue