Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

Pull pmdomain updates from Ulf Hansson:
"pmdomain core:
- Add support for naming idlestates through DT

pmdomain providers:
- arm: Explicitly request the current state at init for the SCMI PM
domain
- mediatek: Add Airoha CPU PM Domain support for CPU frequency
scaling
- ti: Add per-device latency constraint management to the ti_sci PM
domain

cpuidle-psci:
- Enable system-wakeup through GENPD_FLAG_ACTIVE_WAKEUP"

* tag 'pmdomain-v6.14' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/linux-pm:
pmdomain: airoha: Fix compilation error with Clang-20 and Thumb2 mode
pmdomain: arm: scmi_pm_domain: Send an explicit request to set the current state
pmdomain: airoha: Add Airoha CPU PM Domain support
pmdomain: ti_sci: handle wake IRQs for IO daisy chain wakeups
pmdomain: ti_sci: add wakeup constraint management
pmdomain: ti_sci: add per-device latency constraint management
pmdomain: imx-gpcv2: Suppress bind attrs
pmdomain: imx8m[p]-blk-ctrl: Suppress bind attrs
pmdomain: core: Support naming idle states
dt-bindings: power: domain-idle-state: Allow idle-state-name
cpuidle: psci: Activate GENPD_FLAG_ACTIVE_WAKEUP with OSI

+276 -3
+5
Documentation/devicetree/bindings/power/domain-idle-state.yaml
··· 54 54 (i.e. idle states node with entry-method property is set to "psci") 55 55 must specify this property. 56 56 57 + idle-state-name: 58 + $ref: /schemas/types.yaml#/definitions/string 59 + description: 60 + A string used as a descriptive name for the idle state. 61 + 57 62 required: 58 63 - compatible 59 64 - entry-latency-us
+1
drivers/cpuidle/cpuidle-psci-domain.c
··· 72 72 */ 73 73 if (use_osi) { 74 74 pd->power_off = psci_pd_power_off; 75 + pd->flags |= GENPD_FLAG_ACTIVE_WAKEUP; 75 76 if (IS_ENABLED(CONFIG_PREEMPT_RT)) 76 77 pd->flags |= GENPD_FLAG_RPM_ALWAYS_ON; 77 78 } else {
+8
drivers/pmdomain/arm/scmi_pm_domain.c
··· 96 96 continue; 97 97 } 98 98 99 + /* 100 + * Register the explicit power on request to the firmware so 101 + * that it is tracked as used by OSPM agent and not 102 + * accidentally turned off with OSPM's knowledge 103 + */ 104 + if (state == SCMI_POWER_STATE_GENERIC_ON) 105 + power_ops->state_set(ph, i, state); 106 + 99 107 scmi_pd->domain = i; 100 108 scmi_pd->ph = ph; 101 109 scmi_pd->name = power_ops->name_get(ph, i);
+12 -3
drivers/pmdomain/core.c
··· 3180 3180 if (!err) 3181 3181 genpd_state->residency_ns = 1000LL * residency; 3182 3182 3183 + of_property_read_string(state_node, "idle-state-name", &genpd_state->name); 3184 + 3183 3185 genpd_state->power_on_latency_ns = 1000LL * exit_latency; 3184 3186 genpd_state->power_off_latency_ns = 1000LL * entry_latency; 3185 3187 genpd_state->fwnode = &state_node->fwnode; ··· 3460 3458 seq_puts(s, "State Time Spent(ms) Usage Rejected\n"); 3461 3459 3462 3460 for (i = 0; i < genpd->state_count; i++) { 3463 - idle_time += genpd->states[i].idle_time; 3461 + struct genpd_power_state *state = &genpd->states[i]; 3462 + char state_name[15]; 3463 + 3464 + idle_time += state->idle_time; 3464 3465 3465 3466 if (genpd->status == GENPD_STATE_OFF && genpd->state_idx == i) { 3466 3467 now = ktime_get_mono_fast_ns(); ··· 3473 3468 } 3474 3469 } 3475 3470 3471 + if (!state->name) 3472 + snprintf(state_name, ARRAY_SIZE(state_name), "S%-13d", i); 3473 + 3476 3474 do_div(idle_time, NSEC_PER_MSEC); 3477 - seq_printf(s, "S%-13i %-14llu %-14llu %llu\n", i, idle_time, 3478 - genpd->states[i].usage, genpd->states[i].rejected); 3475 + seq_printf(s, "%-14s %-14llu %-14llu %llu\n", 3476 + state->name ?: state_name, idle_time, 3477 + state->usage, state->rejected); 3479 3478 } 3480 3479 3481 3480 genpd_unlock(genpd);
+2
drivers/pmdomain/imx/gpcv2.c
··· 1437 1437 .driver = { 1438 1438 .name = "imx-pgc", 1439 1439 .pm = &imx_pgc_domain_pm_ops, 1440 + .suppress_bind_attrs = true, 1440 1441 }, 1441 1442 .probe = imx_pgc_domain_probe, 1442 1443 .remove = imx_pgc_domain_remove, ··· 1550 1549 .driver = { 1551 1550 .name = "imx-gpcv2", 1552 1551 .of_match_table = imx_gpcv2_dt_ids, 1552 + .suppress_bind_attrs = true, 1553 1553 }, 1554 1554 .probe = imx_gpcv2_probe, 1555 1555 };
+1
drivers/pmdomain/imx/imx8m-blk-ctrl.c
··· 894 894 .name = "imx8m-blk-ctrl", 895 895 .pm = &imx8m_blk_ctrl_pm_ops, 896 896 .of_match_table = imx8m_blk_ctrl_of_match, 897 + .suppress_bind_attrs = true, 897 898 }, 898 899 }; 899 900 module_platform_driver(imx8m_blk_ctrl_driver);
+1
drivers/pmdomain/imx/imx8mp-blk-ctrl.c
··· 862 862 .name = "imx8mp-blk-ctrl", 863 863 .pm = &imx8mp_blk_ctrl_pm_ops, 864 864 .of_match_table = imx8mp_blk_ctrl_of_match, 865 + .suppress_bind_attrs = true, 865 866 }, 866 867 }; 867 868 module_platform_driver(imx8mp_blk_ctrl_driver);
+12
drivers/pmdomain/mediatek/Kconfig
··· 26 26 Control Processor System (SCPSYS) has several power management related 27 27 tasks in the system. 28 28 29 + config AIROHA_CPU_PM_DOMAIN 30 + tristate "Airoha CPU power domain" 31 + default ARCH_AIROHA 32 + depends on HAVE_ARM_SMCCC 33 + depends on PM 34 + select PM_GENERIC_DOMAINS 35 + help 36 + Say y here to enable CPU power domain support for Airoha SoC. 37 + 38 + CPU frequency and power is controlled by ATF with SMC command to 39 + set performance states. 40 + 29 41 endmenu
+8
drivers/pmdomain/mediatek/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 2 obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o 3 3 obj-$(CONFIG_MTK_SCPSYS_PM_DOMAINS) += mtk-pm-domains.o 4 + obj-$(CONFIG_AIROHA_CPU_PM_DOMAIN) += airoha-cpu-pmdomain.o 5 + 6 + ifeq ($(CONFIG_THUMB2_KERNEL)$(CONFIG_CC_IS_CLANG),yy) 7 + # The use of R7 in the SMCCC conflicts with the compiler's use of R7 as a frame 8 + # pointer in Thumb2 mode, which is forcibly enabled by Clang when profiling 9 + # hooks are inserted via the -pg switch. 10 + CFLAGS_REMOVE_airoha-cpu-pmdomain.o += $(CC_FLAGS_FTRACE) 11 + endif
+144
drivers/pmdomain/mediatek/airoha-cpu-pmdomain.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <linux/arm-smccc.h> 4 + #include <linux/bitfield.h> 5 + #include <linux/clk-provider.h> 6 + #include <linux/module.h> 7 + #include <linux/platform_device.h> 8 + #include <linux/pm_domain.h> 9 + #include <linux/slab.h> 10 + 11 + #define AIROHA_SIP_AVS_HANDLE 0x82000301 12 + #define AIROHA_AVS_OP_BASE 0xddddddd0 13 + #define AIROHA_AVS_OP_MASK GENMASK(1, 0) 14 + #define AIROHA_AVS_OP_FREQ_DYN_ADJ (AIROHA_AVS_OP_BASE | \ 15 + FIELD_PREP(AIROHA_AVS_OP_MASK, 0x1)) 16 + #define AIROHA_AVS_OP_GET_FREQ (AIROHA_AVS_OP_BASE | \ 17 + FIELD_PREP(AIROHA_AVS_OP_MASK, 0x2)) 18 + 19 + struct airoha_cpu_pmdomain_priv { 20 + struct clk_hw hw; 21 + struct generic_pm_domain pd; 22 + }; 23 + 24 + static long airoha_cpu_pmdomain_clk_round(struct clk_hw *hw, unsigned long rate, 25 + unsigned long *parent_rate) 26 + { 27 + return rate; 28 + } 29 + 30 + static unsigned long airoha_cpu_pmdomain_clk_get(struct clk_hw *hw, 31 + unsigned long parent_rate) 32 + { 33 + struct arm_smccc_res res; 34 + 35 + arm_smccc_1_1_invoke(AIROHA_SIP_AVS_HANDLE, AIROHA_AVS_OP_GET_FREQ, 36 + 0, 0, 0, 0, 0, 0, &res); 37 + 38 + /* SMCCC returns freq in MHz */ 39 + return (int)(res.a0 * 1000 * 1000); 40 + } 41 + 42 + /* Airoha CPU clk SMCC is always enabled */ 43 + static int airoha_cpu_pmdomain_clk_is_enabled(struct clk_hw *hw) 44 + { 45 + return true; 46 + } 47 + 48 + static const struct clk_ops airoha_cpu_pmdomain_clk_ops = { 49 + .recalc_rate = airoha_cpu_pmdomain_clk_get, 50 + .is_enabled = airoha_cpu_pmdomain_clk_is_enabled, 51 + .round_rate = airoha_cpu_pmdomain_clk_round, 52 + }; 53 + 54 + static int airoha_cpu_pmdomain_set_performance_state(struct generic_pm_domain *domain, 55 + unsigned int state) 56 + { 57 + struct arm_smccc_res res; 58 + 59 + arm_smccc_1_1_invoke(AIROHA_SIP_AVS_HANDLE, AIROHA_AVS_OP_FREQ_DYN_ADJ, 60 + 0, state, 0, 0, 0, 0, &res); 61 + 62 + /* SMC signal correct apply by unsetting BIT 0 */ 63 + return res.a0 & BIT(0) ? -EINVAL : 0; 64 + } 65 + 66 + static int airoha_cpu_pmdomain_probe(struct platform_device *pdev) 67 + { 68 + struct airoha_cpu_pmdomain_priv *priv; 69 + struct device *dev = &pdev->dev; 70 + const struct clk_init_data init = { 71 + .name = "cpu", 72 + .ops = &airoha_cpu_pmdomain_clk_ops, 73 + /* Clock with no set_rate, can't cache */ 74 + .flags = CLK_GET_RATE_NOCACHE, 75 + }; 76 + struct generic_pm_domain *pd; 77 + int ret; 78 + 79 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 80 + if (!priv) 81 + return -ENOMEM; 82 + 83 + /* Init and register a get-only clk for Cpufreq */ 84 + priv->hw.init = &init; 85 + ret = devm_clk_hw_register(dev, &priv->hw); 86 + if (ret) 87 + return ret; 88 + 89 + ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, 90 + &priv->hw); 91 + if (ret) 92 + return ret; 93 + 94 + /* Init and register a PD for CPU */ 95 + pd = &priv->pd; 96 + pd->name = "cpu_pd"; 97 + pd->flags = GENPD_FLAG_ALWAYS_ON; 98 + pd->set_performance_state = airoha_cpu_pmdomain_set_performance_state; 99 + 100 + ret = pm_genpd_init(pd, NULL, false); 101 + if (ret) 102 + return ret; 103 + 104 + ret = of_genpd_add_provider_simple(dev->of_node, pd); 105 + if (ret) 106 + goto err_add_provider; 107 + 108 + platform_set_drvdata(pdev, priv); 109 + 110 + return 0; 111 + 112 + err_add_provider: 113 + pm_genpd_remove(pd); 114 + 115 + return ret; 116 + } 117 + 118 + static void airoha_cpu_pmdomain_remove(struct platform_device *pdev) 119 + { 120 + struct airoha_cpu_pmdomain_priv *priv = platform_get_drvdata(pdev); 121 + 122 + of_genpd_del_provider(pdev->dev.of_node); 123 + pm_genpd_remove(&priv->pd); 124 + } 125 + 126 + static const struct of_device_id airoha_cpu_pmdomain_of_match[] = { 127 + { .compatible = "airoha,en7581-cpufreq" }, 128 + { }, 129 + }; 130 + MODULE_DEVICE_TABLE(of, airoha_cpu_pmdomain_of_match); 131 + 132 + static struct platform_driver airoha_cpu_pmdomain_driver = { 133 + .probe = airoha_cpu_pmdomain_probe, 134 + .remove = airoha_cpu_pmdomain_remove, 135 + .driver = { 136 + .name = "airoha-cpu-pmdomain", 137 + .of_match_table = airoha_cpu_pmdomain_of_match, 138 + }, 139 + }; 140 + module_platform_driver(airoha_cpu_pmdomain_driver); 141 + 142 + MODULE_AUTHOR("Christian Marangi <ansuelsmth@gmail.com>"); 143 + MODULE_DESCRIPTION("CPU PM domain driver for Airoha SoCs"); 144 + MODULE_LICENSE("GPL");
+81
drivers/pmdomain/ti/ti_sci_pm_domains.c
··· 12 12 #include <linux/of.h> 13 13 #include <linux/platform_device.h> 14 14 #include <linux/pm_domain.h> 15 + #include <linux/pm_qos.h> 16 + #include <linux/pm_runtime.h> 15 17 #include <linux/slab.h> 16 18 #include <linux/soc/ti/ti_sci_protocol.h> 17 19 #include <dt-bindings/soc/ti,sci_pm_domain.h> ··· 53 51 54 52 #define genpd_to_ti_sci_pd(gpd) container_of(gpd, struct ti_sci_pm_domain, pd) 55 53 54 + static inline bool ti_sci_pd_is_valid_constraint(s32 val) 55 + { 56 + return val != PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; 57 + } 58 + 59 + #ifdef CONFIG_PM_SLEEP 60 + static void ti_sci_pd_set_lat_constraint(struct device *dev, s32 val) 61 + { 62 + struct generic_pm_domain *genpd = pd_to_genpd(dev->pm_domain); 63 + struct ti_sci_pm_domain *pd = genpd_to_ti_sci_pd(genpd); 64 + const struct ti_sci_handle *ti_sci = pd->parent->ti_sci; 65 + u16 val_ms; 66 + int ret; 67 + 68 + /* PM QoS latency unit is usecs, TI SCI uses msecs */ 69 + val_ms = val / USEC_PER_MSEC; 70 + ret = ti_sci->ops.pm_ops.set_latency_constraint(ti_sci, val_ms, TISCI_MSG_CONSTRAINT_SET); 71 + if (ret) 72 + dev_err(dev, "ti_sci_pd: set latency constraint failed: ret=%d\n", 73 + ret); 74 + else 75 + dev_dbg(dev, "ti_sci_pd: ID:%d set latency constraint %d\n", 76 + pd->idx, val); 77 + } 78 + #endif 79 + 80 + static inline void ti_sci_pd_set_wkup_constraint(struct device *dev) 81 + { 82 + struct generic_pm_domain *genpd = pd_to_genpd(dev->pm_domain); 83 + struct ti_sci_pm_domain *pd = genpd_to_ti_sci_pd(genpd); 84 + const struct ti_sci_handle *ti_sci = pd->parent->ti_sci; 85 + int ret; 86 + 87 + if (device_may_wakeup(dev)) { 88 + /* 89 + * If device can wakeup using IO daisy chain wakeups, 90 + * we do not want to set a constraint. 91 + */ 92 + if (dev->power.wakeirq) { 93 + dev_dbg(dev, "%s: has wake IRQ, not setting constraints\n", __func__); 94 + return; 95 + } 96 + 97 + ret = ti_sci->ops.pm_ops.set_device_constraint(ti_sci, pd->idx, 98 + TISCI_MSG_CONSTRAINT_SET); 99 + if (!ret) 100 + dev_dbg(dev, "ti_sci_pd: ID:%d set device constraint.\n", pd->idx); 101 + } 102 + } 103 + 56 104 /* 57 105 * ti_sci_pd_power_off(): genpd power down hook 58 106 * @domain: pointer to the powerdomain to power off ··· 130 78 else 131 79 return ti_sci->ops.dev_ops.get_device(ti_sci, pd->idx); 132 80 } 81 + 82 + #ifdef CONFIG_PM_SLEEP 83 + static int ti_sci_pd_suspend(struct device *dev) 84 + { 85 + int ret; 86 + s32 val; 87 + 88 + ret = pm_generic_suspend(dev); 89 + if (ret) 90 + return ret; 91 + 92 + val = dev_pm_qos_read_value(dev, DEV_PM_QOS_RESUME_LATENCY); 93 + if (ti_sci_pd_is_valid_constraint(val)) 94 + ti_sci_pd_set_lat_constraint(dev, val); 95 + 96 + ti_sci_pd_set_wkup_constraint(dev); 97 + 98 + return 0; 99 + } 100 + #else 101 + #define ti_sci_pd_suspend NULL 102 + #endif 133 103 134 104 /* 135 105 * ti_sci_pd_xlate(): translation service for TI SCI genpds ··· 256 182 pd->pd.flags |= GENPD_FLAG_ACTIVE_WAKEUP; 257 183 pd->idx = args.args[0]; 258 184 pd->parent = pd_provider; 185 + /* 186 + * If SCI constraint functions are present, then firmware 187 + * supports the constraints API. 188 + */ 189 + if (pd_provider->ti_sci->ops.pm_ops.set_device_constraint && 190 + pd_provider->ti_sci->ops.pm_ops.set_latency_constraint) 191 + pd->pd.domain.ops.suspend = ti_sci_pd_suspend; 259 192 260 193 pm_genpd_init(&pd->pd, NULL, true); 261 194
+1
include/linux/pm_domain.h
··· 147 147 }; 148 148 149 149 struct genpd_power_state { 150 + const char *name; 150 151 s64 power_off_latency_ns; 151 152 s64 power_on_latency_ns; 152 153 s64 residency_ns;