pmdomain core:

- Add residency reflection for domain-idlestates to debugfs
  - Add genpd helper to correct the usage/rejected counters
 
 pmdomain providers:
  - mediatek: Add support for Dimensity 1200 MT6893
  - qcom: Add support for SM4450 power domains
  - rockchip: Add support for RK3562 SoC
  - sunxi: Add support for Allwinner H6/H616 PRCM PPU
  - ti: Fix STANDBY handling of OMAP2+ PER power domain
 
 cpuidle-psci:
  - Correct the domain-idlestate statistics in debugfs
 -----BEGIN PGP SIGNATURE-----
 
 iQJLBAABCgA1FiEEugLDXPmKSktSkQsV/iaEJXNYjCkFAmg1l1MXHHVsZi5oYW5z
 c29uQGxpbmFyby5vcmcACgkQ/iaEJXNYjCmnYg/+JtlqFbusU070t9luv1B6SjHr
 KQ5T5WfLykyoV1tT8lkbPxXnayQO9F+B5ueRW8e8e/Ha5omBfUF+jCF/SCjGQ6Uu
 sJg3wYCtgPII29BmkDvWfkUPeXo+DpiXwqroAtjm5w1G1owIRa2/uPMzJYcxqfE5
 7Cj/vJTJ5HWF7TLiuEBqe9qXyWdjKHfvZLzqQqv6I6ZUW0HIlcQQ2k8aza0kh/Pm
 1CQBexCwZknP9d3J5Ys+42K7ElrLPfaw4KGtF4336iQ/HFoHhhCkUupnS88T8Kbb
 7IeBXPmK/Pq4KD6mwzD5SX/sGvNLJ8awsx3R5blJ7OvKBIOa1kD9+YrfTRc8SZ8/
 2MakIRs980w1WUGYSEUHHKMBXVxi1TbD2fS/svK6wOof9tm9h0YKvpu+E6khUlIF
 QPU+96WNpRvjY+nJuCMhGeQcuAXEXy//SS0w9av+1Qy7bidDHAra2Zq5w3KqXXhh
 X9y+PEQaebePBU4R16Un7F1UPX3zz84rtPlsCl3MVahBdIm6UShIBDFzti+gdLy7
 spImRWPSwaWPp/6PrrPaMA733hVuVNxUB2GH7eq+N9a8a8e3Hvbp4qc9H/Yv4Rxi
 EK79iKaxQQBH+HC4pElpDbSSU6pJl7UQsSmitJmQQr8vh0/a47HUW1+qHwONyjUG
 Ulsli2bkAtHJJsZE+H4=
 =0pAF
 -----END PGP SIGNATURE-----

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

Pull pmdomain updates from Ulf Hansson:
 "pmdomain core:
   - Add residency reflection for domain-idlestates to debugfs
   - Add genpd helper to correct the usage/rejected counters

  pmdomain providers:
   - mediatek: Add support for Dimensity 1200 MT6893
   - qcom: Add support for SM4450 power domains
   - rockchip: Add support for RK3562 SoC
   - sunxi: Add support for Allwinner H6/H616 PRCM PPU
   - ti: Fix STANDBY handling of OMAP2+ PER power domain

  cpuidle-psci:
   - Correct the domain-idlestate statistics in debugfs"

* tag 'pmdomain-v6.16' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/linux-pm: (23 commits)
  pmdomain: ti: Fix STANDBY handling of PER power domain
  pmdomain: amlogic: Constify some structures
  pmdomain: core: Use genpd->opp_table to simplify error/remove path
  pmdomain: core: Simplify return statement in genpd_power_off()
  pmdomain: core: Convert genpd_power_off() to void
  pmdomain: core: Convert to device_awake_path()
  pmdomain: mediatek: Add error messages for missing regmaps
  pmdomain: arm: Do not enable by default during compile testing
  pmdomain: qcom: rpmhpd: Add SM4450 power domains
  dt-bindings: power: qcom,rpmpd: Add SM4450 compatible
  pmdomain: sunxi: add H6 PRCM PPU driver
  dt-bindings: power: Add Allwinner H6/H616 PRCM PPU
  pmdomain: bcm: bcm2835-power: Use devm_clk_get_optional
  pmdomain: rockchip: Add support for RK3562 SoC
  dt-bindings: power: rockchip: Add support for RK3562 SoC
  pmdomain: mediatek: Add support for Dimensity 1200 MT6893
  pmdomain: mediatek: Bump maximum bus protect data array elements
  dt-bindings: power: mediatek: Support Dimensity 1200 MT6893 MTCMOS
  pmdomain: core: Reset genpd->states to avoid freeing invalid data
  pmdomain: core: Add residency reflection for domain-idlestates to debugfs
  ...
This commit is contained in:
Linus Torvalds 2025-05-27 16:19:30 -07:00
commit 418da6ee1e
24 changed files with 1185 additions and 115 deletions

View File

@ -0,0 +1,42 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/power/allwinner,sun50i-h6-prcm-ppu.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Allwinner SoCs PRCM power domain controller
maintainers:
- Andre Przywara <andre.przywara@arm.com>
description:
The Allwinner Power Reset Clock Management (PRCM) unit contains bits to
control a few power domains.
properties:
compatible:
enum:
- allwinner,sun50i-h6-prcm-ppu
- allwinner,sun50i-h616-prcm-ppu
- allwinner,sun55i-a523-prcm-ppu
reg:
maxItems: 1
'#power-domain-cells':
const: 1
required:
- compatible
- reg
- '#power-domain-cells'
additionalProperties: false
examples:
- |
prcm_ppu: power-controller@7010210 {
compatible = "allwinner,sun50i-h616-prcm-ppu";
reg = <0x7010210 0x10>;
#power-domain-cells = <1>;
};

View File

@ -25,6 +25,7 @@ properties:
enum:
- mediatek,mt6735-power-controller
- mediatek,mt6795-power-controller
- mediatek,mt6893-power-controller
- mediatek,mt8167-power-controller
- mediatek,mt8173-power-controller
- mediatek,mt8183-power-controller
@ -88,6 +89,7 @@ $defs:
description: |
Power domain index. Valid values are defined in:
"include/dt-bindings/power/mt6795-power.h" - for MT8167 type power domain.
"include/dt-bindings/power/mediatek,mt6893-power.h" - for MT6893 type power domain.
"include/dt-bindings/power/mt8167-power.h" - for MT8167 type power domain.
"include/dt-bindings/power/mt8173-power.h" - for MT8173 type power domain.
"include/dt-bindings/power/mt8183-power.h" - for MT8183 type power domain.

View File

@ -50,6 +50,7 @@ properties:
- qcom,sdx55-rpmhpd
- qcom,sdx65-rpmhpd
- qcom,sdx75-rpmhpd
- qcom,sm4450-rpmhpd
- qcom,sm6115-rpmpd
- qcom,sm6125-rpmpd
- qcom,sm6350-rpmhpd

View File

@ -40,6 +40,7 @@ properties:
- rockchip,rk3366-power-controller
- rockchip,rk3368-power-controller
- rockchip,rk3399-power-controller
- rockchip,rk3562-power-controller
- rockchip,rk3568-power-controller
- rockchip,rk3576-power-controller
- rockchip,rk3588-power-controller

View File

@ -43,7 +43,7 @@ static int psci_pd_power_off(struct generic_pm_domain *pd)
/* OSI mode is enabled, set the corresponding domain state. */
pd_state = state->data;
psci_set_domain_state(*pd_state);
psci_set_domain_state(pd, pd->state_idx, *pd_state);
return 0;
}

View File

@ -36,19 +36,30 @@ struct psci_cpuidle_data {
struct device *dev;
};
struct psci_cpuidle_domain_state {
struct generic_pm_domain *pd;
unsigned int state_idx;
u32 state;
};
static DEFINE_PER_CPU_READ_MOSTLY(struct psci_cpuidle_data, psci_cpuidle_data);
static DEFINE_PER_CPU(u32, domain_state);
static DEFINE_PER_CPU(struct psci_cpuidle_domain_state, psci_domain_state);
static bool psci_cpuidle_use_syscore;
static bool psci_cpuidle_use_cpuhp;
void psci_set_domain_state(u32 state)
void psci_set_domain_state(struct generic_pm_domain *pd, unsigned int state_idx,
u32 state)
{
__this_cpu_write(domain_state, state);
struct psci_cpuidle_domain_state *ds = this_cpu_ptr(&psci_domain_state);
ds->pd = pd;
ds->state_idx = state_idx;
ds->state = state;
}
static inline u32 psci_get_domain_state(void)
static inline void psci_clear_domain_state(void)
{
return __this_cpu_read(domain_state);
__this_cpu_write(psci_domain_state.state, 0);
}
static __cpuidle int __psci_enter_domain_idle_state(struct cpuidle_device *dev,
@ -58,7 +69,8 @@ static __cpuidle int __psci_enter_domain_idle_state(struct cpuidle_device *dev,
struct psci_cpuidle_data *data = this_cpu_ptr(&psci_cpuidle_data);
u32 *states = data->psci_states;
struct device *pd_dev = data->dev;
u32 state;
struct psci_cpuidle_domain_state *ds;
u32 state = states[idx];
int ret;
ret = cpu_pm_enter();
@ -71,9 +83,9 @@ static __cpuidle int __psci_enter_domain_idle_state(struct cpuidle_device *dev,
else
pm_runtime_put_sync_suspend(pd_dev);
state = psci_get_domain_state();
if (!state)
state = states[idx];
ds = this_cpu_ptr(&psci_domain_state);
if (ds->state)
state = ds->state;
trace_psci_domain_idle_enter(dev->cpu, state, s2idle);
ret = psci_cpu_suspend_enter(state) ? -1 : idx;
@ -86,8 +98,12 @@ static __cpuidle int __psci_enter_domain_idle_state(struct cpuidle_device *dev,
cpu_pm_exit();
/* Correct domain-idlestate statistics if we failed to enter. */
if (ret == -1 && ds->state)
pm_genpd_inc_rejected(ds->pd, ds->state_idx);
/* Clear the domain state to start fresh when back from idle. */
psci_set_domain_state(0);
psci_clear_domain_state();
return ret;
}
@ -121,7 +137,7 @@ static int psci_idle_cpuhp_down(unsigned int cpu)
if (pd_dev) {
pm_runtime_put_sync(pd_dev);
/* Clear domain state to start fresh at next online. */
psci_set_domain_state(0);
psci_clear_domain_state();
}
return 0;
@ -147,7 +163,7 @@ static void psci_idle_syscore_switch(bool suspend)
/* Clear domain state to re-start fresh. */
if (!cleared) {
psci_set_domain_state(0);
psci_clear_domain_state();
cleared = true;
}
}

View File

@ -4,8 +4,10 @@
#define __CPUIDLE_PSCI_H
struct device_node;
struct generic_pm_domain;
void psci_set_domain_state(u32 state);
void psci_set_domain_state(struct generic_pm_domain *pd, unsigned int state_idx,
u32 state);
int psci_dt_parse_state_node(struct device_node *np, u32 *state);
#endif /* __CPUIDLE_PSCI_H */

View File

@ -69,27 +69,27 @@ struct meson_ee_pwrc_domain_desc {
char *name;
unsigned int reset_names_count;
unsigned int clk_names_count;
struct meson_ee_pwrc_top_domain *top_pd;
const struct meson_ee_pwrc_top_domain *top_pd;
unsigned int mem_pd_count;
struct meson_ee_pwrc_mem_domain *mem_pd;
const struct meson_ee_pwrc_mem_domain *mem_pd;
bool (*is_powered_off)(struct meson_ee_pwrc_domain *pwrc_domain);
};
struct meson_ee_pwrc_domain_data {
unsigned int count;
struct meson_ee_pwrc_domain_desc *domains;
const struct meson_ee_pwrc_domain_desc *domains;
};
/* TOP Power Domains */
static struct meson_ee_pwrc_top_domain gx_pwrc_vpu = {
static const struct meson_ee_pwrc_top_domain gx_pwrc_vpu = {
.sleep_reg = GX_AO_RTI_GEN_PWR_SLEEP0,
.sleep_mask = BIT(8),
.iso_reg = GX_AO_RTI_GEN_PWR_SLEEP0,
.iso_mask = BIT(9),
};
static struct meson_ee_pwrc_top_domain meson8_pwrc_vpu = {
static const struct meson_ee_pwrc_top_domain meson8_pwrc_vpu = {
.sleep_reg = MESON8_AO_RTI_GEN_PWR_SLEEP0,
.sleep_mask = BIT(8),
.iso_reg = MESON8_AO_RTI_GEN_PWR_SLEEP0,
@ -104,20 +104,20 @@ static struct meson_ee_pwrc_top_domain meson8_pwrc_vpu = {
.iso_mask = BIT(__bit), \
}
static struct meson_ee_pwrc_top_domain sm1_pwrc_vpu = SM1_EE_PD(8);
static struct meson_ee_pwrc_top_domain sm1_pwrc_nna = SM1_EE_PD(16);
static struct meson_ee_pwrc_top_domain sm1_pwrc_usb = SM1_EE_PD(17);
static struct meson_ee_pwrc_top_domain sm1_pwrc_pci = SM1_EE_PD(18);
static struct meson_ee_pwrc_top_domain sm1_pwrc_ge2d = SM1_EE_PD(19);
static const struct meson_ee_pwrc_top_domain sm1_pwrc_vpu = SM1_EE_PD(8);
static const struct meson_ee_pwrc_top_domain sm1_pwrc_nna = SM1_EE_PD(16);
static const struct meson_ee_pwrc_top_domain sm1_pwrc_usb = SM1_EE_PD(17);
static const struct meson_ee_pwrc_top_domain sm1_pwrc_pci = SM1_EE_PD(18);
static const struct meson_ee_pwrc_top_domain sm1_pwrc_ge2d = SM1_EE_PD(19);
static struct meson_ee_pwrc_top_domain g12a_pwrc_nna = {
static const struct meson_ee_pwrc_top_domain g12a_pwrc_nna = {
.sleep_reg = GX_AO_RTI_GEN_PWR_SLEEP0,
.sleep_mask = BIT(16) | BIT(17),
.iso_reg = GX_AO_RTI_GEN_PWR_ISO0,
.iso_mask = BIT(16) | BIT(17),
};
static struct meson_ee_pwrc_top_domain g12a_pwrc_isp = {
static const struct meson_ee_pwrc_top_domain g12a_pwrc_isp = {
.sleep_reg = GX_AO_RTI_GEN_PWR_SLEEP0,
.sleep_mask = BIT(18) | BIT(19),
.iso_reg = GX_AO_RTI_GEN_PWR_ISO0,
@ -154,39 +154,39 @@ static struct meson_ee_pwrc_top_domain g12a_pwrc_isp = {
{ __reg, BIT(14) }, \
{ __reg, BIT(15) }
static struct meson_ee_pwrc_mem_domain axg_pwrc_mem_vpu[] = {
static const struct meson_ee_pwrc_mem_domain axg_pwrc_mem_vpu[] = {
VPU_MEMPD(HHI_VPU_MEM_PD_REG0),
VPU_HHI_MEMPD(HHI_MEM_PD_REG0),
};
static struct meson_ee_pwrc_mem_domain g12a_pwrc_mem_vpu[] = {
static const struct meson_ee_pwrc_mem_domain g12a_pwrc_mem_vpu[] = {
VPU_MEMPD(HHI_VPU_MEM_PD_REG0),
VPU_MEMPD(HHI_VPU_MEM_PD_REG1),
VPU_MEMPD(HHI_VPU_MEM_PD_REG2),
VPU_HHI_MEMPD(HHI_MEM_PD_REG0),
};
static struct meson_ee_pwrc_mem_domain gxbb_pwrc_mem_vpu[] = {
static const struct meson_ee_pwrc_mem_domain gxbb_pwrc_mem_vpu[] = {
VPU_MEMPD(HHI_VPU_MEM_PD_REG0),
VPU_MEMPD(HHI_VPU_MEM_PD_REG1),
VPU_HHI_MEMPD(HHI_MEM_PD_REG0),
};
static struct meson_ee_pwrc_mem_domain meson_pwrc_mem_eth[] = {
static const struct meson_ee_pwrc_mem_domain meson_pwrc_mem_eth[] = {
{ HHI_MEM_PD_REG0, GENMASK(3, 2) },
};
static struct meson_ee_pwrc_mem_domain meson8_pwrc_audio_dsp_mem[] = {
static const struct meson_ee_pwrc_mem_domain meson8_pwrc_audio_dsp_mem[] = {
{ HHI_MEM_PD_REG0, GENMASK(1, 0) },
};
static struct meson_ee_pwrc_mem_domain meson8_pwrc_mem_vpu[] = {
static const struct meson_ee_pwrc_mem_domain meson8_pwrc_mem_vpu[] = {
VPU_MEMPD(HHI_VPU_MEM_PD_REG0),
VPU_MEMPD(HHI_VPU_MEM_PD_REG1),
VPU_HHI_MEMPD(HHI_MEM_PD_REG0),
};
static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_vpu[] = {
static const struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_vpu[] = {
VPU_MEMPD(HHI_VPU_MEM_PD_REG0),
VPU_MEMPD(HHI_VPU_MEM_PD_REG1),
VPU_MEMPD(HHI_VPU_MEM_PD_REG2),
@ -198,28 +198,28 @@ static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_vpu[] = {
VPU_HHI_MEMPD(HHI_MEM_PD_REG0),
};
static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_nna[] = {
static const struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_nna[] = {
{ HHI_NANOQ_MEM_PD_REG0, 0xff },
{ HHI_NANOQ_MEM_PD_REG1, 0xff },
};
static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_usb[] = {
static const struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_usb[] = {
{ HHI_MEM_PD_REG0, GENMASK(31, 30) },
};
static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_pcie[] = {
static const struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_pcie[] = {
{ HHI_MEM_PD_REG0, GENMASK(29, 26) },
};
static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_ge2d[] = {
static const struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_ge2d[] = {
{ HHI_MEM_PD_REG0, GENMASK(25, 18) },
};
static struct meson_ee_pwrc_mem_domain axg_pwrc_mem_audio[] = {
static const struct meson_ee_pwrc_mem_domain axg_pwrc_mem_audio[] = {
{ HHI_MEM_PD_REG0, GENMASK(5, 4) },
};
static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_audio[] = {
static const struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_audio[] = {
{ HHI_MEM_PD_REG0, GENMASK(5, 4) },
{ HHI_AUDIO_MEM_PD_REG0, GENMASK(1, 0) },
{ HHI_AUDIO_MEM_PD_REG0, GENMASK(3, 2) },
@ -235,12 +235,12 @@ static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_audio[] = {
{ HHI_AUDIO_MEM_PD_REG0, GENMASK(27, 26) },
};
static struct meson_ee_pwrc_mem_domain g12a_pwrc_mem_nna[] = {
static const struct meson_ee_pwrc_mem_domain g12a_pwrc_mem_nna[] = {
{ G12A_HHI_NANOQ_MEM_PD_REG0, GENMASK(31, 0) },
{ G12A_HHI_NANOQ_MEM_PD_REG1, GENMASK(31, 0) },
};
static struct meson_ee_pwrc_mem_domain g12a_pwrc_mem_isp[] = {
static const struct meson_ee_pwrc_mem_domain g12a_pwrc_mem_isp[] = {
{ G12A_HHI_ISP_MEM_PD_REG0, GENMASK(31, 0) },
{ G12A_HHI_ISP_MEM_PD_REG1, GENMASK(31, 0) },
};
@ -270,14 +270,14 @@ static struct meson_ee_pwrc_mem_domain g12a_pwrc_mem_isp[] = {
static bool pwrc_ee_is_powered_off(struct meson_ee_pwrc_domain *pwrc_domain);
static struct meson_ee_pwrc_domain_desc axg_pwrc_domains[] = {
static const struct meson_ee_pwrc_domain_desc axg_pwrc_domains[] = {
[PWRC_AXG_VPU_ID] = VPU_PD("VPU", &gx_pwrc_vpu, axg_pwrc_mem_vpu,
pwrc_ee_is_powered_off, 5, 2),
[PWRC_AXG_ETHERNET_MEM_ID] = MEM_PD("ETH", meson_pwrc_mem_eth),
[PWRC_AXG_AUDIO_ID] = MEM_PD("AUDIO", axg_pwrc_mem_audio),
};
static struct meson_ee_pwrc_domain_desc g12a_pwrc_domains[] = {
static const struct meson_ee_pwrc_domain_desc g12a_pwrc_domains[] = {
[PWRC_G12A_VPU_ID] = VPU_PD("VPU", &gx_pwrc_vpu, g12a_pwrc_mem_vpu,
pwrc_ee_is_powered_off, 11, 2),
[PWRC_G12A_ETH_ID] = MEM_PD("ETH", meson_pwrc_mem_eth),
@ -287,13 +287,13 @@ static struct meson_ee_pwrc_domain_desc g12a_pwrc_domains[] = {
pwrc_ee_is_powered_off),
};
static struct meson_ee_pwrc_domain_desc gxbb_pwrc_domains[] = {
static const struct meson_ee_pwrc_domain_desc gxbb_pwrc_domains[] = {
[PWRC_GXBB_VPU_ID] = VPU_PD("VPU", &gx_pwrc_vpu, gxbb_pwrc_mem_vpu,
pwrc_ee_is_powered_off, 12, 2),
[PWRC_GXBB_ETHERNET_MEM_ID] = MEM_PD("ETH", meson_pwrc_mem_eth),
};
static struct meson_ee_pwrc_domain_desc meson8_pwrc_domains[] = {
static const struct meson_ee_pwrc_domain_desc meson8_pwrc_domains[] = {
[PWRC_MESON8_VPU_ID] = VPU_PD("VPU", &meson8_pwrc_vpu,
meson8_pwrc_mem_vpu,
pwrc_ee_is_powered_off, 0, 1),
@ -303,7 +303,7 @@ static struct meson_ee_pwrc_domain_desc meson8_pwrc_domains[] = {
meson8_pwrc_audio_dsp_mem),
};
static struct meson_ee_pwrc_domain_desc meson8b_pwrc_domains[] = {
static const struct meson_ee_pwrc_domain_desc meson8b_pwrc_domains[] = {
[PWRC_MESON8_VPU_ID] = VPU_PD("VPU", &meson8_pwrc_vpu,
meson8_pwrc_mem_vpu,
pwrc_ee_is_powered_off, 11, 1),
@ -313,7 +313,7 @@ static struct meson_ee_pwrc_domain_desc meson8b_pwrc_domains[] = {
meson8_pwrc_audio_dsp_mem),
};
static struct meson_ee_pwrc_domain_desc sm1_pwrc_domains[] = {
static const struct meson_ee_pwrc_domain_desc sm1_pwrc_domains[] = {
[PWRC_SM1_VPU_ID] = VPU_PD("VPU", &sm1_pwrc_vpu, sm1_pwrc_mem_vpu,
pwrc_ee_is_powered_off, 11, 2),
[PWRC_SM1_NNA_ID] = TOP_PD("NNA", &sm1_pwrc_nna, sm1_pwrc_mem_nna,
@ -576,32 +576,32 @@ static void meson_ee_pwrc_shutdown(struct platform_device *pdev)
}
}
static struct meson_ee_pwrc_domain_data meson_ee_g12a_pwrc_data = {
static const struct meson_ee_pwrc_domain_data meson_ee_g12a_pwrc_data = {
.count = ARRAY_SIZE(g12a_pwrc_domains),
.domains = g12a_pwrc_domains,
};
static struct meson_ee_pwrc_domain_data meson_ee_axg_pwrc_data = {
static const struct meson_ee_pwrc_domain_data meson_ee_axg_pwrc_data = {
.count = ARRAY_SIZE(axg_pwrc_domains),
.domains = axg_pwrc_domains,
};
static struct meson_ee_pwrc_domain_data meson_ee_gxbb_pwrc_data = {
static const struct meson_ee_pwrc_domain_data meson_ee_gxbb_pwrc_data = {
.count = ARRAY_SIZE(gxbb_pwrc_domains),
.domains = gxbb_pwrc_domains,
};
static struct meson_ee_pwrc_domain_data meson_ee_m8_pwrc_data = {
static const struct meson_ee_pwrc_domain_data meson_ee_m8_pwrc_data = {
.count = ARRAY_SIZE(meson8_pwrc_domains),
.domains = meson8_pwrc_domains,
};
static struct meson_ee_pwrc_domain_data meson_ee_m8b_pwrc_data = {
static const struct meson_ee_pwrc_domain_data meson_ee_m8b_pwrc_data = {
.count = ARRAY_SIZE(meson8b_pwrc_domains),
.domains = meson8b_pwrc_domains,
};
static struct meson_ee_pwrc_domain_data meson_ee_sm1_pwrc_data = {
static const struct meson_ee_pwrc_domain_data meson_ee_sm1_pwrc_data = {
.count = ARRAY_SIZE(sm1_pwrc_domains),
.domains = sm1_pwrc_domains,
};

View File

@ -2,7 +2,7 @@
config ARM_SCMI_PERF_DOMAIN
tristate "SCMI performance domain driver"
depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF)
default y
default ARM_SCMI_PROTOCOL
select PM_GENERIC_DOMAINS if PM
help
This enables support for the SCMI performance domains which can be
@ -14,7 +14,7 @@ config ARM_SCMI_PERF_DOMAIN
config ARM_SCMI_POWER_DOMAIN
tristate "SCMI power domain driver"
depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF)
default y
default ARM_SCMI_PROTOCOL
select PM_GENERIC_DOMAINS if PM
help
This enables support for the SCMI power domains which can be
@ -27,7 +27,7 @@ config ARM_SCMI_POWER_DOMAIN
config ARM_SCPI_POWER_DOMAIN
tristate "SCPI power domain driver"
depends on ARM_SCPI_PROTOCOL || (COMPILE_TEST && OF)
default y
default ARM_SCPI_PROTOCOL
select PM_GENERIC_DOMAINS if PM
help
This enables support for the SCPI power domains which can be

View File

@ -506,18 +506,10 @@ bcm2835_init_power_domain(struct bcm2835_power *power,
struct device *dev = power->dev;
struct bcm2835_power_domain *dom = &power->domains[pd_xlate_index];
dom->clk = devm_clk_get(dev->parent, name);
if (IS_ERR(dom->clk)) {
int ret = PTR_ERR(dom->clk);
if (ret == -EPROBE_DEFER)
return ret;
/* Some domains don't have a clk, so make sure that we
* don't deref an error pointer later.
*/
dom->clk = NULL;
}
dom->clk = devm_clk_get_optional(dev->parent, name);
if (IS_ERR(dom->clk))
return dev_err_probe(dev, PTR_ERR(dom->clk), "Failed to get clock %s\n",
name);
dom->base.name = name;
dom->base.flags = GENPD_FLAG_ACTIVE_WAKEUP;

View File

@ -304,10 +304,40 @@ static void genpd_update_accounting(struct generic_pm_domain *genpd)
genpd->accounting_time = now;
}
static void genpd_reflect_residency(struct generic_pm_domain *genpd)
{
struct genpd_governor_data *gd = genpd->gd;
struct genpd_power_state *state, *next_state;
unsigned int state_idx;
s64 sleep_ns, target_ns;
if (!gd || !gd->reflect_residency)
return;
sleep_ns = ktime_to_ns(ktime_sub(ktime_get(), gd->last_enter));
state_idx = genpd->state_idx;
state = &genpd->states[state_idx];
target_ns = state->power_off_latency_ns + state->residency_ns;
if (sleep_ns < target_ns) {
state->above++;
} else if (state_idx < (genpd->state_count -1)) {
next_state = &genpd->states[state_idx + 1];
target_ns = next_state->power_off_latency_ns +
next_state->residency_ns;
if (sleep_ns >= target_ns)
state->below++;
}
gd->reflect_residency = false;
}
#else
static inline void genpd_debug_add(struct generic_pm_domain *genpd) {}
static inline void genpd_debug_remove(struct generic_pm_domain *genpd) {}
static inline void genpd_update_accounting(struct generic_pm_domain *genpd) {}
static inline void genpd_reflect_residency(struct generic_pm_domain *genpd) {}
#endif
static int _genpd_reeval_performance_state(struct generic_pm_domain *genpd,
@ -728,6 +758,31 @@ int dev_pm_genpd_rpm_always_on(struct device *dev, bool on)
}
EXPORT_SYMBOL_GPL(dev_pm_genpd_rpm_always_on);
/**
* pm_genpd_inc_rejected() - Adjust the rejected/usage counts for an idle-state.
*
* @genpd: The PM domain the idle-state belongs to.
* @state_idx: The index of the idle-state that failed.
*
* In some special cases the ->power_off() callback is asynchronously powering
* off the PM domain, leading to that it may return zero to indicate success,
* even though the actual power-off could fail. To account for this correctly in
* the rejected/usage counts for the idle-state statistics, users can call this
* function to adjust the values.
*
* It is assumed that the users guarantee that the genpd doesn't get removed
* while this routine is getting called.
*/
void pm_genpd_inc_rejected(struct generic_pm_domain *genpd,
unsigned int state_idx)
{
genpd_lock(genpd);
genpd->states[genpd->state_idx].rejected++;
genpd->states[genpd->state_idx].usage--;
genpd_unlock(genpd);
}
EXPORT_SYMBOL_GPL(pm_genpd_inc_rejected);
static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed)
{
unsigned int state_idx = genpd->state_idx;
@ -853,31 +908,24 @@ static void genpd_queue_power_off_work(struct generic_pm_domain *genpd)
* If all of the @genpd's devices have been suspended and all of its subdomains
* have been powered down, remove power from @genpd.
*/
static int genpd_power_off(struct generic_pm_domain *genpd, bool one_dev_on,
unsigned int depth)
static void genpd_power_off(struct generic_pm_domain *genpd, bool one_dev_on,
unsigned int depth)
{
struct pm_domain_data *pdd;
struct gpd_link *link;
unsigned int not_suspended = 0;
int ret;
/*
* Do not try to power off the domain in the following situations:
* (1) The domain is already in the "power off" state.
* (2) System suspend is in progress.
* The domain is already in the "power off" state.
* System suspend is in progress.
* The domain is configured as always on.
* The domain has a subdomain being powered on.
*/
if (!genpd_status_on(genpd) || genpd->prepared_count > 0)
return 0;
/*
* Abort power off for the PM domain in the following situations:
* (1) The domain is configured as always on.
* (2) When the domain has a subdomain being powered on.
*/
if (genpd_is_always_on(genpd) ||
genpd_is_rpm_always_on(genpd) ||
atomic_read(&genpd->sd_count) > 0)
return -EBUSY;
if (!genpd_status_on(genpd) || genpd->prepared_count > 0 ||
genpd_is_always_on(genpd) || genpd_is_rpm_always_on(genpd) ||
atomic_read(&genpd->sd_count) > 0)
return;
/*
* The children must be in their deepest (powered-off) states to allow
@ -888,7 +936,7 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool one_dev_on,
list_for_each_entry(link, &genpd->parent_links, parent_node) {
struct generic_pm_domain *child = link->child;
if (child->state_idx < child->state_count - 1)
return -EBUSY;
return;
}
list_for_each_entry(pdd, &genpd->dev_list, list_node) {
@ -902,15 +950,15 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool one_dev_on,
/* The device may need its PM domain to stay powered on. */
if (to_gpd_data(pdd)->rpm_always_on)
return -EBUSY;
return;
}
if (not_suspended > 1 || (not_suspended == 1 && !one_dev_on))
return -EBUSY;
return;
if (genpd->gov && genpd->gov->power_down_ok) {
if (!genpd->gov->power_down_ok(&genpd->domain))
return -EAGAIN;
return;
}
/* Default to shallowest state. */
@ -919,12 +967,11 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool one_dev_on,
/* Don't power off, if a child domain is waiting to power on. */
if (atomic_read(&genpd->sd_count) > 0)
return -EBUSY;
return;
ret = _genpd_power_off(genpd, true);
if (ret) {
if (_genpd_power_off(genpd, true)) {
genpd->states[genpd->state_idx].rejected++;
return ret;
return;
}
genpd->status = GENPD_STATE_OFF;
@ -937,8 +984,6 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool one_dev_on,
genpd_power_off(link->parent, false, depth + 1);
genpd_unlock(link->parent);
}
return 0;
}
/**
@ -957,6 +1002,9 @@ static int genpd_power_on(struct generic_pm_domain *genpd, unsigned int depth)
if (genpd_status_on(genpd))
return 0;
/* Reflect over the entered idle-states residency for debugfs. */
genpd_reflect_residency(genpd);
/*
* The list is guaranteed not to change while the loop below is being
* executed, unless one of the parents' .power_on() callbacks fiddles
@ -1450,7 +1498,7 @@ static int genpd_finish_suspend(struct device *dev,
if (ret)
return ret;
if (device_wakeup_path(dev) && genpd_is_active_wakeup(genpd))
if (device_awake_path(dev) && genpd_is_active_wakeup(genpd))
return 0;
if (genpd->dev_ops.stop && genpd->dev_ops.start &&
@ -1505,7 +1553,7 @@ static int genpd_finish_resume(struct device *dev,
if (IS_ERR(genpd))
return -EINVAL;
if (device_wakeup_path(dev) && genpd_is_active_wakeup(genpd))
if (device_awake_path(dev) && genpd_is_active_wakeup(genpd))
return resume_noirq(dev);
genpd_lock(genpd);
@ -2229,8 +2277,10 @@ static int genpd_alloc_data(struct generic_pm_domain *genpd)
return 0;
put:
put_device(&genpd->dev);
if (genpd->free_states == genpd_free_default_power_state)
if (genpd->free_states == genpd_free_default_power_state) {
kfree(genpd->states);
genpd->states = NULL;
}
free:
if (genpd_is_cpu_domain(genpd))
free_cpumask_var(genpd->cpus);
@ -2293,6 +2343,7 @@ int pm_genpd_init(struct generic_pm_domain *genpd,
genpd->provider = NULL;
genpd->device_id = -ENXIO;
genpd->has_provider = false;
genpd->opp_table = NULL;
genpd->accounting_time = ktime_get_mono_fast_ns();
genpd->domain.ops.runtime_suspend = genpd_runtime_suspend;
genpd->domain.ops.runtime_resume = genpd_runtime_resume;
@ -2567,7 +2618,7 @@ int of_genpd_add_provider_simple(struct device_node *np,
ret = genpd_add_provider(np, genpd_xlate_simple, genpd);
if (ret) {
if (!genpd_is_opp_table_fw(genpd) && genpd->set_performance_state) {
if (genpd->opp_table) {
dev_pm_opp_put_opp_table(genpd->opp_table);
dev_pm_opp_of_remove_table(&genpd->dev);
}
@ -2647,7 +2698,7 @@ int of_genpd_add_provider_onecell(struct device_node *np,
genpd->provider = NULL;
genpd->has_provider = false;
if (!genpd_is_opp_table_fw(genpd) && genpd->set_performance_state) {
if (genpd->opp_table) {
dev_pm_opp_put_opp_table(genpd->opp_table);
dev_pm_opp_of_remove_table(&genpd->dev);
}
@ -2679,11 +2730,10 @@ void of_genpd_del_provider(struct device_node *np)
if (gpd->provider == &np->fwnode) {
gpd->has_provider = false;
if (genpd_is_opp_table_fw(gpd) || !gpd->set_performance_state)
continue;
dev_pm_opp_put_opp_table(gpd->opp_table);
dev_pm_opp_of_remove_table(&gpd->dev);
if (gpd->opp_table) {
dev_pm_opp_put_opp_table(gpd->opp_table);
dev_pm_opp_of_remove_table(&gpd->dev);
}
}
}
@ -3492,7 +3542,7 @@ static int idle_states_show(struct seq_file *s, void *data)
if (ret)
return -ERESTARTSYS;
seq_puts(s, "State Time Spent(ms) Usage Rejected\n");
seq_puts(s, "State Time Spent(ms) Usage Rejected Above Below\n");
for (i = 0; i < genpd->state_count; i++) {
struct genpd_power_state *state = &genpd->states[i];
@ -3512,9 +3562,10 @@ static int idle_states_show(struct seq_file *s, void *data)
snprintf(state_name, ARRAY_SIZE(state_name), "S%-13d", i);
do_div(idle_time, NSEC_PER_MSEC);
seq_printf(s, "%-14s %-14llu %-14llu %llu\n",
seq_printf(s, "%-14s %-14llu %-10llu %-10llu %-10llu %llu\n",
state->name ?: state_name, idle_time,
state->usage, state->rejected);
state->usage, state->rejected, state->above,
state->below);
}
genpd_unlock(genpd);

View File

@ -392,6 +392,8 @@ static bool cpu_power_down_ok(struct dev_pm_domain *pd)
if (idle_duration_ns >= (genpd->states[i].residency_ns +
genpd->states[i].power_off_latency_ns)) {
genpd->state_idx = i;
genpd->gd->last_enter = now;
genpd->gd->reflect_residency = true;
return true;
}
} while (--i >= 0);

View File

@ -0,0 +1,585 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2025 Collabora Ltd
* AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
*/
#ifndef __PMDOMAIN_MEDIATEK_MT6893_PM_DOMAINS_H
#define __PMDOMAIN_MEDIATEK_MT6893_PM_DOMAINS_H
#include <linux/soc/mediatek/infracfg.h>
#include <dt-bindings/power/mediatek,mt6893-power.h>
#include "mtk-pm-domains.h"
#define MT6893_TOP_AXI_PROT_EN_MCU_STA1 0x2e4
#define MT6893_TOP_AXI_PROT_EN_MCU_SET 0x2c4
#define MT6893_TOP_AXI_PROT_EN_MCU_CLR 0x2c8
#define MT6893_TOP_AXI_PROT_EN_VDNR_1_SET 0xba4
#define MT6893_TOP_AXI_PROT_EN_VDNR_1_CLR 0xba8
#define MT6893_TOP_AXI_PROT_EN_VDNR_1_STA1 0xbb0
#define MT6893_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_SET 0xbb8
#define MT6893_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_CLR 0xbbc
#define MT6893_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_STA1 0xbc4
#define MT6893_TOP_AXI_PROT_EN_1_MFG1_STEP1 GENMASK(21, 19)
#define MT6893_TOP_AXI_PROT_EN_2_MFG1_STEP2 GENMASK(6, 5)
#define MT6893_TOP_AXI_PROT_EN_MFG1_STEP3 GENMASK(22, 21)
#define MT6893_TOP_AXI_PROT_EN_2_MFG1_STEP4 BIT(7)
#define MT6893_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_MFG1_STEP5 GENMASK(19, 17)
#define MT6893_TOP_AXI_PROT_EN_MM_VDEC0_STEP1 BIT(24)
#define MT6893_TOP_AXI_PROT_EN_MM_2_VDEC0_STEP2 BIT(25)
#define MT6893_TOP_AXI_PROT_EN_MM_VDEC1_STEP1 BIT(6)
#define MT6893_TOP_AXI_PROT_EN_MM_VDEC1_STEP2 BIT(7)
#define MT6893_TOP_AXI_PROT_EN_MM_VENC0_STEP1 BIT(26)
#define MT6893_TOP_AXI_PROT_EN_MM_2_VENC0_STEP2 BIT(0)
#define MT6893_TOP_AXI_PROT_EN_MM_VENC0_STEP3 BIT(27)
#define MT6893_TOP_AXI_PROT_EN_MM_2_VENC0_STEP4 BIT(1)
#define MT6893_TOP_AXI_PROT_EN_MM_VENC1_STEP1 GENMASK(30, 28)
#define MT6893_TOP_AXI_PROT_EN_MM_VENC1_STEP2 GENMASK(31, 29)
#define MT6893_TOP_AXI_PROT_EN_MDP_STEP1 BIT(10)
#define MT6893_TOP_AXI_PROT_EN_MM_MDP_STEP2 (BIT(2) | BIT(4) | BIT(6) | \
BIT(8) | BIT(18) | BIT(22) | \
BIT(28) | BIT(30))
#define MT6893_TOP_AXI_PROT_EN_MM_2_MDP_STEP3 (BIT(0) | BIT(2) | BIT(4) | \
BIT(6) | BIT(8))
#define MT6893_TOP_AXI_PROT_EN_MDP_STEP4 BIT(23)
#define MT6893_TOP_AXI_PROT_EN_MM_MDP_STEP5 (BIT(3) | BIT(5) | BIT(7) | \
BIT(9) | BIT(19) | BIT(23) | \
BIT(29) | BIT(31))
#define MT6893_TOP_AXI_PROT_EN_MM_2_MDP_STEP6 (BIT(1) | BIT(7) | BIT(9) | BIT(11))
#define MT6893_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_MDP_STEP7 BIT(20)
#define MT6893_TOP_AXI_PROT_EN_MM_DISP_STEP1 (BIT(0) | BIT(6) | BIT(8) | \
BIT(10) | BIT(12) | BIT(14) | \
BIT(16) | BIT(20) | BIT(24) | \
BIT(26))
#define MT6893_TOP_AXI_PROT_EN_DISP_STEP2 BIT(6)
#define MT6893_TOP_AXI_PROT_EN_MM_DISP_STEP3 (BIT(1) | BIT(7) | BIT(9) | \
BIT(15) | BIT(17) | BIT(21) | \
BIT(25) | BIT(27))
#define MT6893_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_DISP_STEP4 BIT(21)
#define MT6893_TOP_AXI_PROT_EN_2_ADSP BIT(3)
#define MT6893_TOP_AXI_PROT_EN_2_CAM_STEP1 BIT(1)
#define MT6893_TOP_AXI_PROT_EN_MM_CAM_STEP2 (BIT(0) | BIT(2) | BIT(4))
#define MT6893_TOP_AXI_PROT_EN_1_CAM_STEP3 BIT(22)
#define MT6893_TOP_AXI_PROT_EN_MM_CAM_STEP4 (BIT(1) | BIT(3) | BIT(5))
#define MT6893_TOP_AXI_PROT_EN_MM_CAM_RAWA_STEP1 BIT(18)
#define MT6893_TOP_AXI_PROT_EN_MM_CAM_RAWA_STEP2 BIT(19)
#define MT6893_TOP_AXI_PROT_EN_MM_CAM_RAWB_STEP1 BIT(20)
#define MT6893_TOP_AXI_PROT_EN_MM_CAM_RAWB_STEP2 BIT(21)
#define MT6893_TOP_AXI_PROT_EN_MM_CAM_RAWC_STEP1 BIT(22)
#define MT6893_TOP_AXI_PROT_EN_MM_CAM_RAWC_STEP2 BIT(23)
/*
* MT6893 Power Domain (MTCMOS) support
*
* The register layout for this IP is very similar to MT8192 so where possible
* the same definitions are reused to avoid duplication.
* Where the bus protection bits are also the same, the entire set is reused.
*/
static const struct scpsys_domain_data scpsys_domain_data_mt6893[] = {
[MT6893_POWER_DOMAIN_CONN] = {
.name = "conn",
.sta_mask = BIT(1),
.ctl_offs = 0x304,
.pwr_sta_offs = 0x16c,
.pwr_sta2nd_offs = 0x170,
.sram_pdn_bits = 0,
.sram_pdn_ack_bits = 0,
.bp_cfg = {
BUS_PROT_WR(INFRA,
MT8192_TOP_AXI_PROT_EN_CONN,
MT8192_TOP_AXI_PROT_EN_SET,
MT8192_TOP_AXI_PROT_EN_CLR,
MT8192_TOP_AXI_PROT_EN_STA1),
BUS_PROT_WR(INFRA,
MT8192_TOP_AXI_PROT_EN_CONN_2ND,
MT8192_TOP_AXI_PROT_EN_SET,
MT8192_TOP_AXI_PROT_EN_CLR,
MT8192_TOP_AXI_PROT_EN_STA1),
BUS_PROT_WR(INFRA,
MT8192_TOP_AXI_PROT_EN_1_CONN,
MT8192_TOP_AXI_PROT_EN_1_SET,
MT8192_TOP_AXI_PROT_EN_1_CLR,
MT8192_TOP_AXI_PROT_EN_1_STA1),
},
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
},
[MT6893_POWER_DOMAIN_MFG0] = {
.name = "mfg0",
.sta_mask = BIT(2),
.ctl_offs = 0x308,
.pwr_sta_offs = 0x16c,
.pwr_sta2nd_offs = 0x170,
.sram_pdn_bits = BIT(8),
.sram_pdn_ack_bits = BIT(12),
.caps = MTK_SCPD_KEEP_DEFAULT_OFF | MTK_SCPD_DOMAIN_SUPPLY,
},
[MT6893_POWER_DOMAIN_MFG1] = {
.name = "mfg1",
.sta_mask = BIT(3),
.ctl_offs = 0x30c,
.pwr_sta_offs = 0x16c,
.pwr_sta2nd_offs = 0x170,
.sram_pdn_bits = BIT(8),
.sram_pdn_ack_bits = BIT(12),
.bp_cfg = {
BUS_PROT_WR(INFRA,
MT6893_TOP_AXI_PROT_EN_1_MFG1_STEP1,
MT8192_TOP_AXI_PROT_EN_1_SET,
MT8192_TOP_AXI_PROT_EN_1_CLR,
MT8192_TOP_AXI_PROT_EN_1_STA1),
BUS_PROT_WR(INFRA,
MT6893_TOP_AXI_PROT_EN_2_MFG1_STEP2,
MT8192_TOP_AXI_PROT_EN_2_SET,
MT8192_TOP_AXI_PROT_EN_2_CLR,
MT8192_TOP_AXI_PROT_EN_2_STA1),
BUS_PROT_WR(INFRA,
MT6893_TOP_AXI_PROT_EN_MFG1_STEP3,
MT8192_TOP_AXI_PROT_EN_SET,
MT8192_TOP_AXI_PROT_EN_CLR,
MT8192_TOP_AXI_PROT_EN_STA1),
BUS_PROT_WR(INFRA,
MT6893_TOP_AXI_PROT_EN_2_MFG1_STEP4,
MT8192_TOP_AXI_PROT_EN_2_SET,
MT8192_TOP_AXI_PROT_EN_2_CLR,
MT8192_TOP_AXI_PROT_EN_2_STA1),
BUS_PROT_WR(INFRA,
MT6893_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_MFG1_STEP5,
MT6893_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_SET,
MT6893_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_CLR,
MT6893_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_STA1),
},
.caps = MTK_SCPD_KEEP_DEFAULT_OFF | MTK_SCPD_DOMAIN_SUPPLY,
},
[MT6893_POWER_DOMAIN_MFG2] = {
.name = "mfg2",
.sta_mask = BIT(4),
.ctl_offs = 0x310,
.pwr_sta_offs = 0x16c,
.pwr_sta2nd_offs = 0x170,
.sram_pdn_bits = BIT(8),
.sram_pdn_ack_bits = BIT(12),
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
},
[MT6893_POWER_DOMAIN_MFG3] = {
.name = "mfg3",
.sta_mask = BIT(5),
.ctl_offs = 0x314,
.pwr_sta_offs = 0x16c,
.pwr_sta2nd_offs = 0x170,
.sram_pdn_bits = BIT(8),
.sram_pdn_ack_bits = BIT(12),
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
},
[MT6893_POWER_DOMAIN_MFG4] = {
.name = "mfg4",
.sta_mask = BIT(6),
.ctl_offs = 0x318,
.pwr_sta_offs = 0x16c,
.pwr_sta2nd_offs = 0x170,
.sram_pdn_bits = BIT(8),
.sram_pdn_ack_bits = BIT(12),
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
},
[MT6893_POWER_DOMAIN_MFG5] = {
.name = "mfg5",
.sta_mask = BIT(7),
.ctl_offs = 0x31c,
.pwr_sta_offs = 0x16c,
.pwr_sta2nd_offs = 0x170,
.sram_pdn_bits = BIT(8),
.sram_pdn_ack_bits = BIT(12),
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
},
[MT6893_POWER_DOMAIN_MFG6] = {
.name = "mfg6",
.sta_mask = BIT(8),
.ctl_offs = 0x320,
.pwr_sta_offs = 0x16c,
.pwr_sta2nd_offs = 0x170,
.sram_pdn_bits = BIT(8),
.sram_pdn_ack_bits = BIT(12),
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
},
[MT6893_POWER_DOMAIN_ISP] = {
.name = "isp",
.sta_mask = BIT(12),
.ctl_offs = 0x330,
.pwr_sta_offs = 0x16c,
.pwr_sta2nd_offs = 0x170,
.sram_pdn_bits = BIT(8),
.sram_pdn_ack_bits = BIT(12),
.bp_cfg = {
BUS_PROT_WR(INFRA,
MT8192_TOP_AXI_PROT_EN_MM_2_ISP,
MT8192_TOP_AXI_PROT_EN_MM_2_SET,
MT8192_TOP_AXI_PROT_EN_MM_2_CLR,
MT8192_TOP_AXI_PROT_EN_MM_2_STA1),
BUS_PROT_WR(INFRA,
MT8192_TOP_AXI_PROT_EN_MM_2_ISP_2ND,
MT8192_TOP_AXI_PROT_EN_MM_2_SET,
MT8192_TOP_AXI_PROT_EN_MM_2_CLR,
MT8192_TOP_AXI_PROT_EN_MM_2_STA1),
},
},
[MT6893_POWER_DOMAIN_ISP2] = {
.name = "isp2",
.sta_mask = BIT(13),
.ctl_offs = 0x334,
.pwr_sta_offs = 0x16c,
.pwr_sta2nd_offs = 0x170,
.sram_pdn_bits = BIT(8),
.sram_pdn_ack_bits = BIT(12),
.bp_cfg = {
BUS_PROT_WR(INFRA,
MT8192_TOP_AXI_PROT_EN_MM_ISP2,
MT8192_TOP_AXI_PROT_EN_MM_SET,
MT8192_TOP_AXI_PROT_EN_MM_CLR,
MT8192_TOP_AXI_PROT_EN_MM_STA1),
BUS_PROT_WR(INFRA,
MT8192_TOP_AXI_PROT_EN_MM_ISP2_2ND,
MT8192_TOP_AXI_PROT_EN_MM_SET,
MT8192_TOP_AXI_PROT_EN_MM_CLR,
MT8192_TOP_AXI_PROT_EN_MM_STA1),
},
},
[MT6893_POWER_DOMAIN_IPE] = {
.name = "ipe",
.sta_mask = BIT(14),
.ctl_offs = 0x338,
.pwr_sta_offs = 0x16c,
.pwr_sta2nd_offs = 0x170,
.sram_pdn_bits = BIT(8),
.sram_pdn_ack_bits = BIT(12),
.bp_cfg = {
BUS_PROT_WR(INFRA,
MT8192_TOP_AXI_PROT_EN_MM_IPE,
MT8192_TOP_AXI_PROT_EN_MM_SET,
MT8192_TOP_AXI_PROT_EN_MM_CLR,
MT8192_TOP_AXI_PROT_EN_MM_STA1),
BUS_PROT_WR(INFRA,
MT8192_TOP_AXI_PROT_EN_MM_IPE_2ND,
MT8192_TOP_AXI_PROT_EN_MM_SET,
MT8192_TOP_AXI_PROT_EN_MM_CLR,
MT8192_TOP_AXI_PROT_EN_MM_STA1),
},
},
[MT6893_POWER_DOMAIN_VDEC0] = {
.name = "vdec0",
.sta_mask = BIT(15),
.ctl_offs = 0x33c,
.pwr_sta_offs = 0x16c,
.pwr_sta2nd_offs = 0x170,
.sram_pdn_bits = BIT(8),
.sram_pdn_ack_bits = BIT(12),
.bp_cfg = {
BUS_PROT_WR(INFRA,
MT6893_TOP_AXI_PROT_EN_MM_VDEC0_STEP1,
MT8192_TOP_AXI_PROT_EN_MM_SET,
MT8192_TOP_AXI_PROT_EN_MM_CLR,
MT8192_TOP_AXI_PROT_EN_MM_STA1),
BUS_PROT_WR(INFRA,
MT6893_TOP_AXI_PROT_EN_MM_2_VDEC0_STEP2,
MT8192_TOP_AXI_PROT_EN_MM_2_SET,
MT8192_TOP_AXI_PROT_EN_MM_2_CLR,
MT8192_TOP_AXI_PROT_EN_MM_STA1),
},
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
},
[MT6893_POWER_DOMAIN_VDEC1] = {
.name = "vdec1",
.sta_mask = BIT(16),
.ctl_offs = 0x340,
.pwr_sta_offs = 0x16c,
.pwr_sta2nd_offs = 0x170,
.sram_pdn_bits = BIT(8),
.sram_pdn_ack_bits = BIT(12),
.bp_cfg = {
BUS_PROT_WR(INFRA,
MT6893_TOP_AXI_PROT_EN_MM_VDEC1_STEP1,
MT8192_TOP_AXI_PROT_EN_MM_SET,
MT8192_TOP_AXI_PROT_EN_MM_CLR,
MT8192_TOP_AXI_PROT_EN_MM_STA1),
BUS_PROT_WR(INFRA,
MT6893_TOP_AXI_PROT_EN_MM_VDEC1_STEP2,
MT8192_TOP_AXI_PROT_EN_MM_SET,
MT8192_TOP_AXI_PROT_EN_MM_CLR,
MT8192_TOP_AXI_PROT_EN_MM_STA1),
},
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
},
[MT6893_POWER_DOMAIN_VENC0] = {
.name = "venc0",
.sta_mask = BIT(17),
.ctl_offs = 0x344,
.pwr_sta_offs = 0x16c,
.pwr_sta2nd_offs = 0x170,
.sram_pdn_bits = BIT(8),
.sram_pdn_ack_bits = BIT(12),
.bp_cfg = {
BUS_PROT_WR(INFRA,
MT6893_TOP_AXI_PROT_EN_MM_VENC0_STEP1,
MT8192_TOP_AXI_PROT_EN_MM_SET,
MT8192_TOP_AXI_PROT_EN_MM_CLR,
MT8192_TOP_AXI_PROT_EN_MM_STA1),
BUS_PROT_WR(INFRA,
MT6893_TOP_AXI_PROT_EN_MM_2_VENC0_STEP2,
MT8192_TOP_AXI_PROT_EN_MM_2_SET,
MT8192_TOP_AXI_PROT_EN_MM_2_CLR,
MT8192_TOP_AXI_PROT_EN_MM_2_STA1),
BUS_PROT_WR(INFRA,
MT6893_TOP_AXI_PROT_EN_MM_VENC0_STEP3,
MT8192_TOP_AXI_PROT_EN_MM_SET,
MT8192_TOP_AXI_PROT_EN_MM_CLR,
MT8192_TOP_AXI_PROT_EN_MM_STA1),
BUS_PROT_WR(INFRA,
MT6893_TOP_AXI_PROT_EN_MM_2_VENC0_STEP4,
MT8192_TOP_AXI_PROT_EN_MM_2_SET,
MT8192_TOP_AXI_PROT_EN_MM_2_CLR,
MT8192_TOP_AXI_PROT_EN_MM_2_STA1),
},
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
},
[MT6893_POWER_DOMAIN_VENC1] = {
.name = "venc1",
.sta_mask = BIT(18),
.ctl_offs = 0x348,
.pwr_sta_offs = 0x16c,
.pwr_sta2nd_offs = 0x170,
.sram_pdn_bits = BIT(8),
.sram_pdn_ack_bits = BIT(12),
.bp_cfg = {
BUS_PROT_WR(INFRA,
MT6893_TOP_AXI_PROT_EN_MM_VENC1_STEP1,
MT8192_TOP_AXI_PROT_EN_MM_SET,
MT8192_TOP_AXI_PROT_EN_MM_CLR,
MT8192_TOP_AXI_PROT_EN_MM_STA1),
BUS_PROT_WR(INFRA,
MT6893_TOP_AXI_PROT_EN_MM_VENC1_STEP2,
MT8192_TOP_AXI_PROT_EN_MM_SET,
MT8192_TOP_AXI_PROT_EN_MM_CLR,
MT8192_TOP_AXI_PROT_EN_MM_STA1),
},
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
},
[MT6893_POWER_DOMAIN_MDP] = {
.name = "mdp",
.sta_mask = BIT(19),
.ctl_offs = 0x34c,
.pwr_sta_offs = 0x16c,
.pwr_sta2nd_offs = 0x170,
.sram_pdn_bits = BIT(8),
.sram_pdn_ack_bits = BIT(12),
.bp_cfg = {
BUS_PROT_WR(INFRA,
MT6893_TOP_AXI_PROT_EN_MDP_STEP1,
MT8192_TOP_AXI_PROT_EN_SET,
MT8192_TOP_AXI_PROT_EN_CLR,
MT8192_TOP_AXI_PROT_EN_STA1),
BUS_PROT_WR(INFRA,
MT6893_TOP_AXI_PROT_EN_MM_MDP_STEP2,
MT8192_TOP_AXI_PROT_EN_MM_SET,
MT8192_TOP_AXI_PROT_EN_MM_CLR,
MT8192_TOP_AXI_PROT_EN_MM_STA1),
BUS_PROT_WR(INFRA,
MT6893_TOP_AXI_PROT_EN_MM_2_MDP_STEP3,
MT8192_TOP_AXI_PROT_EN_MM_2_SET,
MT8192_TOP_AXI_PROT_EN_MM_2_CLR,
MT8192_TOP_AXI_PROT_EN_MM_2_STA1),
BUS_PROT_WR(INFRA,
MT6893_TOP_AXI_PROT_EN_MDP_STEP4,
MT8192_TOP_AXI_PROT_EN_SET,
MT8192_TOP_AXI_PROT_EN_CLR,
MT8192_TOP_AXI_PROT_EN_STA1),
BUS_PROT_WR(INFRA,
MT6893_TOP_AXI_PROT_EN_MM_MDP_STEP5,
MT8192_TOP_AXI_PROT_EN_MM_SET,
MT8192_TOP_AXI_PROT_EN_MM_CLR,
MT8192_TOP_AXI_PROT_EN_MM_STA1),
BUS_PROT_WR(INFRA,
MT6893_TOP_AXI_PROT_EN_MM_2_MDP_STEP6,
MT8192_TOP_AXI_PROT_EN_MM_2_SET,
MT8192_TOP_AXI_PROT_EN_MM_2_CLR,
MT8192_TOP_AXI_PROT_EN_MM_2_STA1),
BUS_PROT_WR(INFRA,
MT6893_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_MDP_STEP7,
MT6893_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_SET,
MT6893_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_CLR,
MT6893_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_STA1),
},
},
[MT6893_POWER_DOMAIN_DISP] = {
.name = "disp",
.sta_mask = BIT(20),
.ctl_offs = 0x350,
.pwr_sta_offs = 0x16c,
.pwr_sta2nd_offs = 0x170,
.sram_pdn_bits = BIT(8),
.sram_pdn_ack_bits = BIT(12),
.bp_cfg = {
BUS_PROT_WR(INFRA,
MT6893_TOP_AXI_PROT_EN_MM_DISP_STEP1,
MT8192_TOP_AXI_PROT_EN_MM_SET,
MT8192_TOP_AXI_PROT_EN_MM_CLR,
MT8192_TOP_AXI_PROT_EN_MM_STA1),
BUS_PROT_WR(INFRA,
MT6893_TOP_AXI_PROT_EN_DISP_STEP2,
MT8192_TOP_AXI_PROT_EN_SET,
MT8192_TOP_AXI_PROT_EN_CLR,
MT8192_TOP_AXI_PROT_EN_STA1),
BUS_PROT_WR(INFRA,
MT6893_TOP_AXI_PROT_EN_MM_DISP_STEP3,
MT8192_TOP_AXI_PROT_EN_MM_SET,
MT8192_TOP_AXI_PROT_EN_MM_CLR,
MT8192_TOP_AXI_PROT_EN_MM_STA1),
BUS_PROT_WR(INFRA,
MT6893_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_DISP_STEP4,
MT6893_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_SET,
MT6893_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_CLR,
MT6893_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_STA1),
},
},
[MT6893_POWER_DOMAIN_AUDIO] = {
.name = "audio",
.sta_mask = BIT(21),
.ctl_offs = 0x354,
.pwr_sta_offs = 0x16c,
.pwr_sta2nd_offs = 0x170,
.sram_pdn_bits = BIT(8),
.sram_pdn_ack_bits = BIT(12),
.bp_cfg = {
BUS_PROT_WR(INFRA,
MT8192_TOP_AXI_PROT_EN_2_AUDIO,
MT8192_TOP_AXI_PROT_EN_2_SET,
MT8192_TOP_AXI_PROT_EN_2_CLR,
MT8192_TOP_AXI_PROT_EN_2_STA1),
},
},
[MT6893_POWER_DOMAIN_ADSP] = {
.name = "audio",
.sta_mask = BIT(22),
.ctl_offs = 0x358,
.pwr_sta_offs = 0x16c,
.pwr_sta2nd_offs = 0x170,
.sram_pdn_bits = BIT(9),
.sram_pdn_ack_bits = BIT(12),
.bp_cfg = {
BUS_PROT_WR(INFRA,
MT6893_TOP_AXI_PROT_EN_2_ADSP,
MT8192_TOP_AXI_PROT_EN_2_SET,
MT8192_TOP_AXI_PROT_EN_2_CLR,
MT8192_TOP_AXI_PROT_EN_2_STA1),
},
},
[MT6893_POWER_DOMAIN_CAM] = {
.name = "cam",
.sta_mask = BIT(23),
.ctl_offs = 0x35c,
.pwr_sta_offs = 0x16c,
.pwr_sta2nd_offs = 0x170,
.sram_pdn_bits = BIT(8),
.sram_pdn_ack_bits = BIT(12),
.bp_cfg = {
BUS_PROT_WR(INFRA,
MT6893_TOP_AXI_PROT_EN_2_CAM_STEP1,
MT8192_TOP_AXI_PROT_EN_2_SET,
MT8192_TOP_AXI_PROT_EN_2_CLR,
MT8192_TOP_AXI_PROT_EN_2_STA1),
BUS_PROT_WR(INFRA,
MT6893_TOP_AXI_PROT_EN_MM_CAM_STEP2,
MT8192_TOP_AXI_PROT_EN_MM_SET,
MT8192_TOP_AXI_PROT_EN_MM_CLR,
MT8192_TOP_AXI_PROT_EN_MM_STA1),
BUS_PROT_WR(INFRA,
MT6893_TOP_AXI_PROT_EN_1_CAM_STEP3,
MT8192_TOP_AXI_PROT_EN_1_SET,
MT8192_TOP_AXI_PROT_EN_1_CLR,
MT8192_TOP_AXI_PROT_EN_1_STA1),
BUS_PROT_WR(INFRA,
MT6893_TOP_AXI_PROT_EN_MM_CAM_STEP4,
MT8192_TOP_AXI_PROT_EN_MM_SET,
MT8192_TOP_AXI_PROT_EN_MM_CLR,
MT8192_TOP_AXI_PROT_EN_MM_STA1),
},
},
[MT6893_POWER_DOMAIN_CAM_RAWA] = {
.name = "cam_rawa",
.sta_mask = BIT(24),
.ctl_offs = 0x360,
.pwr_sta_offs = 0x16c,
.pwr_sta2nd_offs = 0x170,
.sram_pdn_bits = BIT(8),
.sram_pdn_ack_bits = BIT(12),
.bp_cfg = {
BUS_PROT_WR(INFRA,
MT6893_TOP_AXI_PROT_EN_MM_CAM_RAWA_STEP1,
MT8192_TOP_AXI_PROT_EN_MM_SET,
MT8192_TOP_AXI_PROT_EN_MM_CLR,
MT8192_TOP_AXI_PROT_EN_MM_STA1),
BUS_PROT_WR(INFRA,
MT6893_TOP_AXI_PROT_EN_MM_CAM_RAWA_STEP2,
MT8192_TOP_AXI_PROT_EN_MM_SET,
MT8192_TOP_AXI_PROT_EN_MM_CLR,
MT8192_TOP_AXI_PROT_EN_MM_STA1),
},
},
[MT6893_POWER_DOMAIN_CAM_RAWB] = {
.name = "cam_rawb",
.sta_mask = BIT(25),
.ctl_offs = 0x364,
.pwr_sta_offs = 0x16c,
.pwr_sta2nd_offs = 0x170,
.sram_pdn_bits = BIT(8),
.sram_pdn_ack_bits = BIT(12),
.bp_cfg = {
BUS_PROT_WR(INFRA,
MT6893_TOP_AXI_PROT_EN_MM_CAM_RAWB_STEP1,
MT8192_TOP_AXI_PROT_EN_MM_SET,
MT8192_TOP_AXI_PROT_EN_MM_CLR,
MT8192_TOP_AXI_PROT_EN_MM_STA1),
BUS_PROT_WR(INFRA,
MT6893_TOP_AXI_PROT_EN_MM_CAM_RAWB_STEP2,
MT8192_TOP_AXI_PROT_EN_MM_SET,
MT8192_TOP_AXI_PROT_EN_MM_CLR,
MT8192_TOP_AXI_PROT_EN_MM_STA1),
},
},
[MT6893_POWER_DOMAIN_CAM_RAWC] = {
.name = "cam_rawc",
.sta_mask = BIT(26),
.ctl_offs = 0x368,
.pwr_sta_offs = 0x16c,
.pwr_sta2nd_offs = 0x170,
.sram_pdn_bits = BIT(8),
.sram_pdn_ack_bits = BIT(12),
.bp_cfg = {
BUS_PROT_WR(INFRA,
MT6893_TOP_AXI_PROT_EN_MM_CAM_RAWC_STEP1,
MT8192_TOP_AXI_PROT_EN_MM_SET,
MT8192_TOP_AXI_PROT_EN_MM_CLR,
MT8192_TOP_AXI_PROT_EN_MM_STA1),
BUS_PROT_WR(INFRA,
MT6893_TOP_AXI_PROT_EN_MM_CAM_RAWC_STEP2,
MT8192_TOP_AXI_PROT_EN_MM_SET,
MT8192_TOP_AXI_PROT_EN_MM_CLR,
MT8192_TOP_AXI_PROT_EN_MM_STA1),
},
},
[MT6893_POWER_DOMAIN_DP_TX] = {
.name = "dp_tx",
.sta_mask = BIT(27),
.ctl_offs = 0x3ac,
.pwr_sta_offs = 0x16c,
.pwr_sta2nd_offs = 0x170,
.sram_pdn_bits = BIT(8),
.sram_pdn_ack_bits = BIT(12),
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
},
};
static const struct scpsys_soc_data mt6893_scpsys_data = {
.domains_data = scpsys_domain_data_mt6893,
.num_domains = ARRAY_SIZE(scpsys_domain_data_mt6893),
};
#endif /* __PMDOMAIN_MEDIATEK_MT6893_PM_DOMAINS_H */

View File

@ -18,6 +18,7 @@
#include "mt6735-pm-domains.h"
#include "mt6795-pm-domains.h"
#include "mt6893-pm-domains.h"
#include "mt8167-pm-domains.h"
#include "mt8173-pm-domains.h"
#include "mt8183-pm-domains.h"
@ -397,20 +398,26 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no
pd->infracfg = syscon_regmap_lookup_by_phandle_optional(node, "mediatek,infracfg");
if (IS_ERR(pd->infracfg))
return ERR_CAST(pd->infracfg);
return dev_err_cast_probe(scpsys->dev, pd->infracfg,
"%pOF: failed to get infracfg regmap\n",
node);
smi_node = of_parse_phandle(node, "mediatek,smi", 0);
if (smi_node) {
pd->smi = device_node_to_regmap(smi_node);
of_node_put(smi_node);
if (IS_ERR(pd->smi))
return ERR_CAST(pd->smi);
return dev_err_cast_probe(scpsys->dev, pd->smi,
"%pOF: failed to get SMI regmap\n",
node);
}
if (MTK_SCPD_CAPS(pd, MTK_SCPD_HAS_INFRA_NAO)) {
pd->infracfg_nao = syscon_regmap_lookup_by_phandle(node, "mediatek,infracfg-nao");
if (IS_ERR(pd->infracfg_nao))
return ERR_CAST(pd->infracfg_nao);
return dev_err_cast_probe(scpsys->dev, pd->infracfg_nao,
"%pOF: failed to get infracfg-nao regmap\n",
node);
} else {
pd->infracfg_nao = NULL;
}
@ -617,6 +624,10 @@ static const struct of_device_id scpsys_of_match[] = {
.compatible = "mediatek,mt6795-power-controller",
.data = &mt6795_scpsys_data,
},
{
.compatible = "mediatek,mt6893-power-controller",
.data = &mt6893_scpsys_data,
},
{
.compatible = "mediatek,mt8167-power-controller",
.data = &mt8167_scpsys_data,

View File

@ -44,7 +44,7 @@
#define PWR_STATUS_AUDIO BIT(24)
#define PWR_STATUS_USB BIT(25)
#define SPM_MAX_BUS_PROT_DATA 6
#define SPM_MAX_BUS_PROT_DATA 7
enum scpsys_bus_prot_flags {
BUS_PROT_REG_UPDATE = BIT(1),

View File

@ -360,6 +360,21 @@ static const struct rpmhpd_desc sdx75_desc = {
.num_pds = ARRAY_SIZE(sdx75_rpmhpds),
};
/* SM4450 RPMH powerdomains */
static struct rpmhpd *sm4450_rpmhpds[] = {
[RPMHPD_CX] = &cx,
[RPMHPD_CX_AO] = &cx_ao,
[RPMHPD_EBI] = &ebi,
[RPMHPD_LMX] = &lmx,
[RPMHPD_MSS] = &mss,
[RPMHPD_MX] = &mx,
};
static const struct rpmhpd_desc sm4450_desc = {
.rpmhpds = sm4450_rpmhpds,
.num_pds = ARRAY_SIZE(sm4450_rpmhpds),
};
/* SM6350 RPMH powerdomains */
static struct rpmhpd *sm6350_rpmhpds[] = {
[SM6350_CX] = &cx_w_mx_parent,
@ -724,6 +739,7 @@ static const struct of_device_id rpmhpd_match_table[] = {
{ .compatible = "qcom,sdx55-rpmhpd", .data = &sdx55_desc},
{ .compatible = "qcom,sdx65-rpmhpd", .data = &sdx65_desc},
{ .compatible = "qcom,sdx75-rpmhpd", .data = &sdx75_desc},
{ .compatible = "qcom,sm4450-rpmhpd", .data = &sm4450_desc },
{ .compatible = "qcom,sm6350-rpmhpd", .data = &sm6350_desc },
{ .compatible = "qcom,sm7150-rpmhpd", .data = &sm7150_desc },
{ .compatible = "qcom,sm8150-rpmhpd", .data = &sm8150_desc },

View File

@ -2,7 +2,7 @@
/*
* Rockchip Generic power domain support.
*
* Copyright (c) 2015 ROCKCHIP, Co. Ltd.
* Copyright (c) 2015 Rockchip Electronics Co., Ltd.
*/
#include <linux/arm-smccc.h>
@ -35,6 +35,7 @@
#include <dt-bindings/power/rk3366-power.h>
#include <dt-bindings/power/rk3368-power.h>
#include <dt-bindings/power/rk3399-power.h>
#include <dt-bindings/power/rockchip,rk3562-power.h>
#include <dt-bindings/power/rk3568-power.h>
#include <dt-bindings/power/rockchip,rk3576-power.h>
#include <dt-bindings/power/rk3588-power.h>
@ -135,6 +136,20 @@ struct rockchip_pmu {
.active_wakeup = wakeup, \
}
#define DOMAIN_M_G_SD(_name, pwr, status, req, idle, ack, g_mask, mem, wakeup, keepon) \
{ \
.name = _name, \
.pwr_w_mask = (pwr) << 16, \
.pwr_mask = (pwr), \
.status_mask = (status), \
.req_w_mask = (req) << 16, \
.req_mask = (req), \
.idle_mask = (idle), \
.ack_mask = (ack), \
.clk_ungate_mask = (g_mask), \
.active_wakeup = wakeup, \
}
#define DOMAIN_M_O_R(_name, p_offset, pwr, status, m_offset, m_status, r_status, r_offset, req, idle, ack, wakeup, regulator) \
{ \
.name = _name, \
@ -201,6 +216,9 @@ struct rockchip_pmu {
#define DOMAIN_RK3399(name, pwr, status, req, wakeup) \
DOMAIN(name, pwr, status, req, req, req, 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)
#define DOMAIN_RK3568(name, pwr, req, wakeup) \
DOMAIN_M(name, pwr, pwr, req, req, req, wakeup)
@ -1197,6 +1215,18 @@ static const struct rockchip_domain_info rk3399_pm_domains[] = {
[RK3399_PD_SDIOAUDIO] = DOMAIN_RK3399("sdioaudio", BIT(31), BIT(31), BIT(29), true),
};
static const struct rockchip_domain_info rk3562_pm_domains[] = {
/* name pwr req g_mask mem wakeup */
[RK3562_PD_GPU] = DOMAIN_RK3562("gpu", BIT(0), BIT(1), BIT(1), 0, false),
[RK3562_PD_NPU] = DOMAIN_RK3562("npu", BIT(1), BIT(2), BIT(2), 0, false),
[RK3562_PD_VDPU] = DOMAIN_RK3562("vdpu", BIT(2), BIT(6), BIT(6), 0, false),
[RK3562_PD_VEPU] = DOMAIN_RK3562("vepu", BIT(3), BIT(7), BIT(7) | BIT(3), 0, false),
[RK3562_PD_RGA] = DOMAIN_RK3562("rga", BIT(4), BIT(5), BIT(5) | BIT(4), 0, false),
[RK3562_PD_VI] = DOMAIN_RK3562("vi", BIT(5), BIT(3), BIT(3), 0, false),
[RK3562_PD_VO] = DOMAIN_RK3562("vo", BIT(6), BIT(4), BIT(4), 16, false),
[RK3562_PD_PHP] = DOMAIN_RK3562("php", BIT(7), BIT(8), BIT(8), 0, false),
};
static const struct rockchip_domain_info rk3568_pm_domains[] = {
[RK3568_PD_NPU] = DOMAIN_RK3568("npu", BIT(1), BIT(2), false),
[RK3568_PD_GPU] = DOMAIN_RK3568("gpu", BIT(0), BIT(1), false),
@ -1398,6 +1428,18 @@ static const struct rockchip_pmu_info rk3399_pmu = {
.domain_info = rk3399_pm_domains,
};
static const struct rockchip_pmu_info rk3562_pmu = {
.pwr_offset = 0x210,
.status_offset = 0x230,
.req_offset = 0x110,
.idle_offset = 0x128,
.ack_offset = 0x120,
.clk_ungate_offset = 0x140,
.num_domains = ARRAY_SIZE(rk3562_pm_domains),
.domain_info = rk3562_pm_domains,
};
static const struct rockchip_pmu_info rk3568_pmu = {
.pwr_offset = 0xa0,
.status_offset = 0x98,
@ -1496,6 +1538,10 @@ static const struct of_device_id rockchip_pm_domain_dt_match[] = {
.compatible = "rockchip,rk3399-power-controller",
.data = (void *)&rk3399_pmu,
},
{
.compatible = "rockchip,rk3562-power-controller",
.data = (void *)&rk3562_pmu,
},
{
.compatible = "rockchip,rk3568-power-controller",
.data = (void *)&rk3568_pmu,

View File

@ -8,3 +8,13 @@ config SUN20I_PPU
help
Say y to enable the PPU power domain driver. This saves power
when certain peripherals, such as the video engine, are idle.
config SUN50I_H6_PRCM_PPU
tristate "Allwinner H6 PRCM power domain driver"
depends on ARCH_SUNXI || COMPILE_TEST
depends on PM
select PM_GENERIC_DOMAINS
help
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
optional for the H6.

View File

@ -1,2 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_SUN20I_PPU) += sun20i-ppu.o
obj-$(CONFIG_SUN50I_H6_PRCM_PPU) += sun50i-h6-prcm-ppu.o

View File

@ -0,0 +1,208 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) Arm Ltd. 2024
*
* Allwinner H6/H616 PRCM power domain driver.
* This covers a few registers inside the PRCM (Power Reset Clock Management)
* block that control some power rails, most prominently for the Mali GPU.
*/
#include <linux/bitfield.h>
#include <linux/clk.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>
/*
* The PRCM block covers multiple devices, starting with some clocks,
* then followed by the power rails.
* The clocks are covered by a different driver, so this driver's MMIO range
* starts later in the PRCM MMIO frame, not at the beginning of it.
* To keep the register offsets consistent with other PRCM documentation,
* express the registers relative to the beginning of the whole PRCM, and
* subtract the PPU offset this driver is bound to.
*/
#define PD_H6_PPU_OFFSET 0x250
#define PD_H6_VDD_SYS_REG 0x250
#define PD_H616_ANA_VDD_GATE BIT(4)
#define PD_H6_CPUS_VDD_GATE BIT(3)
#define PD_H6_AVCC_VDD_GATE BIT(2)
#define PD_H6_GPU_REG 0x254
#define PD_H6_GPU_GATE BIT(0)
struct sun50i_h6_ppu_pd {
struct generic_pm_domain genpd;
void __iomem *reg;
u32 gate_mask;
bool negated;
};
#define FLAG_PPU_ALWAYS_ON BIT(0)
#define FLAG_PPU_NEGATED BIT(1)
struct sun50i_h6_ppu_desc {
const char *name;
u32 offset;
u32 mask;
unsigned int flags;
};
static const struct sun50i_h6_ppu_desc sun50i_h6_ppus[] = {
{ "AVCC", PD_H6_VDD_SYS_REG, PD_H6_AVCC_VDD_GATE },
{ "CPUS", PD_H6_VDD_SYS_REG, PD_H6_CPUS_VDD_GATE },
{ "GPU", PD_H6_GPU_REG, PD_H6_GPU_GATE },
};
static const struct sun50i_h6_ppu_desc sun50i_h616_ppus[] = {
{ "PLL", PD_H6_VDD_SYS_REG, PD_H6_AVCC_VDD_GATE,
FLAG_PPU_ALWAYS_ON | FLAG_PPU_NEGATED },
{ "ANA", PD_H6_VDD_SYS_REG, PD_H616_ANA_VDD_GATE, FLAG_PPU_ALWAYS_ON },
{ "GPU", PD_H6_GPU_REG, PD_H6_GPU_GATE, FLAG_PPU_NEGATED },
};
struct sun50i_h6_ppu_data {
const struct sun50i_h6_ppu_desc *descs;
int nr_domains;
};
static const struct sun50i_h6_ppu_data sun50i_h6_ppu_data = {
.descs = sun50i_h6_ppus,
.nr_domains = ARRAY_SIZE(sun50i_h6_ppus),
};
static const struct sun50i_h6_ppu_data sun50i_h616_ppu_data = {
.descs = sun50i_h616_ppus,
.nr_domains = ARRAY_SIZE(sun50i_h616_ppus),
};
#define to_sun50i_h6_ppu_pd(_genpd) \
container_of(_genpd, struct sun50i_h6_ppu_pd, genpd)
static bool sun50i_h6_ppu_power_status(const struct sun50i_h6_ppu_pd *pd)
{
bool bit = readl(pd->reg) & pd->gate_mask;
return bit ^ pd->negated;
}
static int sun50i_h6_ppu_pd_set_power(const struct sun50i_h6_ppu_pd *pd,
bool set_bit)
{
u32 reg = readl(pd->reg);
if (set_bit)
writel(reg | pd->gate_mask, pd->reg);
else
writel(reg & ~pd->gate_mask, pd->reg);
return 0;
}
static int sun50i_h6_ppu_pd_power_on(struct generic_pm_domain *genpd)
{
const struct sun50i_h6_ppu_pd *pd = to_sun50i_h6_ppu_pd(genpd);
return sun50i_h6_ppu_pd_set_power(pd, !pd->negated);
}
static int sun50i_h6_ppu_pd_power_off(struct generic_pm_domain *genpd)
{
const struct sun50i_h6_ppu_pd *pd = to_sun50i_h6_ppu_pd(genpd);
return sun50i_h6_ppu_pd_set_power(pd, pd->negated);
}
static int sun50i_h6_ppu_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct genpd_onecell_data *ppu;
struct sun50i_h6_ppu_pd *pds;
const struct sun50i_h6_ppu_data *data;
void __iomem *base;
int ret, i;
data = of_device_get_match_data(dev);
if (!data)
return -EINVAL;
pds = devm_kcalloc(dev, data->nr_domains, sizeof(*pds), GFP_KERNEL);
if (!pds)
return -ENOMEM;
ppu = devm_kzalloc(dev, sizeof(*ppu), GFP_KERNEL);
if (!ppu)
return -ENOMEM;
ppu->num_domains = data->nr_domains;
ppu->domains = devm_kcalloc(dev, data->nr_domains,
sizeof(*ppu->domains), GFP_KERNEL);
if (!ppu->domains)
return -ENOMEM;
platform_set_drvdata(pdev, ppu);
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);
for (i = 0; i < data->nr_domains; i++) {
struct sun50i_h6_ppu_pd *pd = &pds[i];
const struct sun50i_h6_ppu_desc *desc = &data->descs[i];
pd->genpd.name = desc->name;
pd->genpd.power_off = sun50i_h6_ppu_pd_power_off;
pd->genpd.power_on = sun50i_h6_ppu_pd_power_on;
if (desc->flags & FLAG_PPU_ALWAYS_ON)
pd->genpd.flags = GENPD_FLAG_ALWAYS_ON;
pd->negated = !!(desc->flags & FLAG_PPU_NEGATED);
pd->reg = base + desc->offset - PD_H6_PPU_OFFSET;
pd->gate_mask = desc->mask;
ret = pm_genpd_init(&pd->genpd, NULL,
!sun50i_h6_ppu_power_status(pd));
if (ret) {
dev_warn(dev, "Failed to add %s power domain: %d\n",
desc->name, ret);
goto out_remove_pds;
}
ppu->domains[i] = &pd->genpd;
}
ret = of_genpd_add_provider_onecell(dev->of_node, ppu);
if (!ret)
return 0;
dev_warn(dev, "Failed to add provider: %d\n", ret);
out_remove_pds:
for (i--; i >= 0; i--)
pm_genpd_remove(&pds[i].genpd);
return ret;
}
static const struct of_device_id sun50i_h6_ppu_of_match[] = {
{ .compatible = "allwinner,sun50i-h6-prcm-ppu",
.data = &sun50i_h6_ppu_data },
{ .compatible = "allwinner,sun50i-h616-prcm-ppu",
.data = &sun50i_h616_ppu_data },
{ }
};
MODULE_DEVICE_TABLE(of, sun50i_h6_ppu_of_match);
static struct platform_driver sun50i_h6_ppu_driver = {
.probe = sun50i_h6_ppu_probe,
.driver = {
.name = "sun50i-h6-prcm-ppu",
.of_match_table = sun50i_h6_ppu_of_match,
/* Power domains cannot be removed while they are in use. */
.suppress_bind_attrs = true,
},
};
module_platform_driver(sun50i_h6_ppu_driver);
MODULE_AUTHOR("Andre Przywara <andre.przywara@arm.com>");
MODULE_DESCRIPTION("Allwinner H6 PRCM power domain driver");
MODULE_LICENSE("GPL");

View File

@ -18,7 +18,9 @@
#include <linux/pm_domain.h>
#include <linux/reset-controller.h>
#include <linux/delay.h>
#if IS_ENABLED(CONFIG_SUSPEND)
#include <linux/suspend.h>
#endif
#include <linux/platform_data/ti-prm.h>
enum omap_prm_domain_mode {
@ -88,6 +90,7 @@ struct omap_reset_data {
#define OMAP_PRM_HAS_RSTST BIT(1)
#define OMAP_PRM_HAS_NO_CLKDM BIT(2)
#define OMAP_PRM_RET_WHEN_IDLE BIT(3)
#define OMAP_PRM_ON_WHEN_STANDBY BIT(4)
#define OMAP_PRM_HAS_RESETS (OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_RSTST)
@ -404,7 +407,8 @@ static const struct omap_prm_data am3_prm_data[] = {
.name = "per", .base = 0x44e00c00,
.pwrstctrl = 0xc, .pwrstst = 0x8, .dmap = &omap_prm_noinact,
.rstctrl = 0x0, .rstmap = am3_per_rst_map,
.flags = OMAP_PRM_HAS_RSTCTRL, .clkdm_name = "pruss_ocp"
.flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_ON_WHEN_STANDBY,
.clkdm_name = "pruss_ocp",
},
{
.name = "wkup", .base = 0x44e00d00,

View File

@ -0,0 +1,35 @@
/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
/*
* Copyright (c) 2025 Collabora Ltd
* AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
*/
#ifndef _DT_BINDINGS_POWER_MT6893_POWER_H
#define _DT_BINDINGS_POWER_MT6893_POWER_H
#define MT6893_POWER_DOMAIN_CONN 0
#define MT6893_POWER_DOMAIN_MFG0 1
#define MT6893_POWER_DOMAIN_MFG1 2
#define MT6893_POWER_DOMAIN_MFG2 3
#define MT6893_POWER_DOMAIN_MFG3 4
#define MT6893_POWER_DOMAIN_MFG4 5
#define MT6893_POWER_DOMAIN_MFG5 6
#define MT6893_POWER_DOMAIN_MFG6 7
#define MT6893_POWER_DOMAIN_ISP 8
#define MT6893_POWER_DOMAIN_ISP2 9
#define MT6893_POWER_DOMAIN_IPE 10
#define MT6893_POWER_DOMAIN_VDEC0 11
#define MT6893_POWER_DOMAIN_VDEC1 12
#define MT6893_POWER_DOMAIN_VENC0 13
#define MT6893_POWER_DOMAIN_VENC1 14
#define MT6893_POWER_DOMAIN_MDP 15
#define MT6893_POWER_DOMAIN_DISP 16
#define MT6893_POWER_DOMAIN_AUDIO 17
#define MT6893_POWER_DOMAIN_ADSP 18
#define MT6893_POWER_DOMAIN_CAM 19
#define MT6893_POWER_DOMAIN_CAM_RAWA 20
#define MT6893_POWER_DOMAIN_CAM_RAWB 21
#define MT6893_POWER_DOMAIN_CAM_RAWC 22
#define MT6893_POWER_DOMAIN_DP_TX 23
#endif /* _DT_BINDINGS_POWER_MT6893_POWER_H */

View File

@ -0,0 +1,35 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
/*
* Copyright (c) 2022-2024 Rockchip Electronics Co., Ltd.
*/
#ifndef __DT_BINDINGS_POWER_RK3562_POWER_H__
#define __DT_BINDINGS_POWER_RK3562_POWER_H__
/* VD_CORE */
#define RK3562_PD_CPU_0 0
#define RK3562_PD_CPU_1 1
#define RK3562_PD_CPU_2 2
#define RK3562_PD_CPU_3 3
#define RK3562_PD_CORE_ALIVE 4
/* VD_PMU */
#define RK3562_PD_PMU 5
#define RK3562_PD_PMU_ALIVE 6
/* VD_NPU */
#define RK3562_PD_NPU 7
/* VD_GPU */
#define RK3562_PD_GPU 8
/* VD_LOGIC */
#define RK3562_PD_DDR 9
#define RK3562_PD_VEPU 10
#define RK3562_PD_VDPU 11
#define RK3562_PD_VI 12
#define RK3562_PD_VO 13
#define RK3562_PD_RGA 14
#define RK3562_PD_PHP 15
#define RK3562_PD_LOGIC_ALIVE 16
#endif

View File

@ -142,6 +142,8 @@ struct genpd_governor_data {
bool max_off_time_changed;
ktime_t next_wakeup;
ktime_t next_hrtimer;
ktime_t last_enter;
bool reflect_residency;
bool cached_power_down_ok;
bool cached_power_down_state_idx;
};
@ -153,6 +155,8 @@ struct genpd_power_state {
s64 residency_ns;
u64 usage;
u64 rejected;
u64 above;
u64 below;
struct fwnode_handle *fwnode;
u64 idle_time;
void *data;
@ -285,6 +289,8 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
int pm_genpd_init(struct generic_pm_domain *genpd,
struct dev_power_governor *gov, bool is_off);
int pm_genpd_remove(struct generic_pm_domain *genpd);
void pm_genpd_inc_rejected(struct generic_pm_domain *genpd,
unsigned int state_idx);
struct device *dev_to_genpd_dev(struct device *dev);
int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state);
int dev_pm_genpd_add_notifier(struct device *dev, struct notifier_block *nb);
@ -336,6 +342,10 @@ static inline int pm_genpd_remove(struct generic_pm_domain *genpd)
return -EOPNOTSUPP;
}
static inline void pm_genpd_inc_rejected(struct generic_pm_domain *genpd,
unsigned int state_idx)
{ }
static inline struct device *dev_to_genpd_dev(struct device *dev)
{
return ERR_PTR(-EOPNOTSUPP);