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.19' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/linux-pm

Pull pmdomain updates from Ulf Hansson:
"pmdomain core:
- Allow power-off for out-of-band wakeup-capable devices
- Drop the redundant call to dev_pm_domain_detach() for the amba bus
- Extend the genpd governor for CPUs to account for IPIs

pmdomain providers:
- bcm: Add support for BCM2712
- mediatek: Add support for MFlexGraphics power domains
- mediatek: Add support for MT8196 power domains
- qcom: Add RPMh power domain support for Kaanapali
- rockchip: Add support for RV1126B

pmdomain consumers:
- usb: dwc3: Enable out of band wakeup for i.MX95
- usb: chipidea: Enable out of band wakeup for i.MX95"

* tag 'pmdomain-v6.19' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/linux-pm: (26 commits)
pmdomain: Extend the genpd governor for CPUs to account for IPIs
smp: Introduce a helper function to check for pending IPIs
pmdomain: mediatek: convert from clk round_rate() to determine_rate()
amba: bus: Drop dev_pm_domain_detach() call
pmdomain: bcm: bcm2835-power: Prepare to support BCM2712
pmdomain: mediatek: mtk-mfg: select MAILBOX in Kconfig
pmdomain: mediatek: Add support for MFlexGraphics
pmdomain: mediatek: Fix build-errors
cpuidle: psci: Replace deprecated strcpy in psci_idle_init_cpu
pmdomain: rockchip: Add support for RV1126B
pmdomain: mediatek: Add support for MT8196 HFRPSYS power domains
pmdomain: mediatek: Add support for MT8196 SCPSYS power domains
pmdomain: mediatek: Add support for secure HWCCF infra power on
pmdomain: mediatek: Add support for Hardware Voter power domains
pmdomain: qcom: rpmhpd: Add RPMh power domain support for Kaanapali
usb: dwc3: imx8mp: Set out of band wakeup for i.MX95
usb: chipidea: ci_hdrc_imx: Set out of band wakeup for i.MX95
usb: chipidea: core: detach power domain for ci_hdrc platform device
pmdomain: core: Allow power-off for out-of-band wakeup-capable devices
PM: wakeup: Add out-of-band system wakeup support for devices
...

+2417 -60
+117
Documentation/devicetree/bindings/power/mediatek,mt8196-gpufreq.yaml
··· 1 + # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/power/mediatek,mt8196-gpufreq.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: MediaTek MFlexGraphics Power and Frequency Controller 8 + 9 + maintainers: 10 + - Nicolas Frattaroli <nicolas.frattaroli@collabora.com> 11 + 12 + description: 13 + A special-purpose embedded MCU to control power and frequency of GPU devices 14 + using MediaTek Flexible Graphics integration hardware. 15 + 16 + properties: 17 + $nodename: 18 + pattern: '^power-controller@[a-f0-9]+$' 19 + 20 + compatible: 21 + enum: 22 + - mediatek,mt8196-gpufreq 23 + 24 + reg: 25 + items: 26 + - description: GPR memory area 27 + - description: RPC memory area 28 + - description: SoC variant ID register 29 + 30 + reg-names: 31 + items: 32 + - const: gpr 33 + - const: rpc 34 + - const: hw-revision 35 + 36 + clocks: 37 + items: 38 + - description: main clock of the embedded controller (EB) 39 + - description: core PLL 40 + - description: stack 0 PLL 41 + - description: stack 1 PLL 42 + 43 + clock-names: 44 + items: 45 + - const: eb 46 + - const: core 47 + - const: stack0 48 + - const: stack1 49 + 50 + mboxes: 51 + items: 52 + - description: FastDVFS events 53 + - description: frequency control 54 + - description: sleep control 55 + - description: timer control 56 + - description: frequency hopping control 57 + - description: hardware voter control 58 + - description: FastDVFS control 59 + 60 + mbox-names: 61 + items: 62 + - const: fast-dvfs-event 63 + - const: gpufreq 64 + - const: sleep 65 + - const: timer 66 + - const: fhctl 67 + - const: ccf 68 + - const: fast-dvfs 69 + 70 + memory-region: 71 + items: 72 + - description: phandle to the GPUEB shared memory 73 + 74 + "#clock-cells": 75 + const: 1 76 + 77 + "#power-domain-cells": 78 + const: 0 79 + 80 + required: 81 + - compatible 82 + - reg 83 + - reg-names 84 + - clocks 85 + - clock-names 86 + - mboxes 87 + - mbox-names 88 + - memory-region 89 + - "#clock-cells" 90 + - "#power-domain-cells" 91 + 92 + additionalProperties: false 93 + 94 + examples: 95 + - | 96 + #include <dt-bindings/clock/mediatek,mt8196-clock.h> 97 + 98 + power-controller@4b09fd00 { 99 + compatible = "mediatek,mt8196-gpufreq"; 100 + reg = <0x4b09fd00 0x80>, 101 + <0x4b800000 0x1000>, 102 + <0x4b860128 0x4>; 103 + reg-names = "gpr", "rpc", "hw-revision"; 104 + clocks = <&topckgen CLK_TOP_MFG_EB>, 105 + <&mfgpll CLK_MFG_AO_MFGPLL>, 106 + <&mfgpll_sc0 CLK_MFGSC0_AO_MFGPLL_SC0>, 107 + <&mfgpll_sc1 CLK_MFGSC1_AO_MFGPLL_SC1>; 108 + clock-names = "eb", "core", "stack0", "stack1"; 109 + mboxes = <&gpueb_mbox 0>, <&gpueb_mbox 1>, <&gpueb_mbox 2>, 110 + <&gpueb_mbox 3>, <&gpueb_mbox 4>, <&gpueb_mbox 5>, 111 + <&gpueb_mbox 7>; 112 + mbox-names = "fast-dvfs-event", "gpufreq", "sleep", "timer", "fhctl", 113 + "ccf", "fast-dvfs"; 114 + memory-region = <&gpueb_shared_memory>; 115 + #clock-cells = <1>; 116 + #power-domain-cells = <0>; 117 + };
+4
Documentation/devicetree/bindings/power/mediatek,power-controller.yaml
··· 33 33 - mediatek,mt8188-power-controller 34 34 - mediatek,mt8192-power-controller 35 35 - mediatek,mt8195-power-controller 36 + - mediatek,mt8196-hwv-hfrp-power-controller 37 + - mediatek,mt8196-hwv-scp-power-controller 38 + - mediatek,mt8196-power-controller 36 39 - mediatek,mt8365-power-controller 37 40 38 41 '#power-domain-cells': ··· 160 157 contains: 161 158 enum: 162 159 - mediatek,mt8183-power-controller 160 + - mediatek,mt8196-power-controller 163 161 then: 164 162 properties: 165 163 access-controllers:
+1
Documentation/devicetree/bindings/power/qcom,rpmpd.yaml
··· 18 18 oneOf: 19 19 - enum: 20 20 - qcom,glymur-rpmhpd 21 + - qcom,kaanapali-rpmhpd 21 22 - qcom,mdm9607-rpmpd 22 23 - qcom,milos-rpmhpd 23 24 - qcom,msm8226-rpmpd
+2
Documentation/devicetree/bindings/power/rockchip,power-controller.yaml
··· 46 46 - rockchip,rk3576-power-controller 47 47 - rockchip,rk3588-power-controller 48 48 - rockchip,rv1126-power-controller 49 + - rockchip,rv1126b-power-controller 49 50 50 51 "#power-domain-cells": 51 52 const: 1 ··· 127 126 "include/dt-bindings/power/rk3568-power.h" 128 127 "include/dt-bindings/power/rk3588-power.h" 129 128 "include/dt-bindings/power/rockchip,rv1126-power.h" 129 + "include/dt-bindings/power/rockchip,rv1126b-power-controller.h" 130 130 131 131 clocks: 132 132 minItems: 1
+32 -6
Documentation/devicetree/bindings/soc/bcm/brcm,bcm2835-pm.yaml
··· 13 13 maintainers: 14 14 - Nicolas Saenz Julienne <nsaenz@kernel.org> 15 15 16 - allOf: 17 - - $ref: /schemas/watchdog/watchdog.yaml# 18 - 19 16 properties: 20 17 compatible: 21 18 items: 22 19 - enum: 23 20 - brcm,bcm2835-pm 24 21 - brcm,bcm2711-pm 22 + - brcm,bcm2712-pm 25 23 - const: brcm,bcm2835-pm-wdt 26 24 27 25 reg: 28 - minItems: 2 26 + minItems: 1 29 27 maxItems: 3 30 28 31 29 reg-names: 32 - minItems: 2 30 + minItems: 1 33 31 items: 34 32 - const: pm 35 33 - const: asb ··· 60 62 - reg 61 63 - "#power-domain-cells" 62 64 - "#reset-cells" 63 - - clocks 65 + 66 + allOf: 67 + - $ref: /schemas/watchdog/watchdog.yaml# 68 + 69 + - if: 70 + properties: 71 + compatible: 72 + contains: 73 + enum: 74 + - brcm,bcm2835-pm 75 + - brcm,bcm2711-pm 76 + then: 77 + required: 78 + - clocks 79 + 80 + properties: 81 + reg: 82 + minItems: 2 83 + 84 + reg-names: 85 + minItems: 2 86 + 87 + else: 88 + properties: 89 + reg: 90 + maxItems: 1 91 + 92 + reg-names: 93 + maxItems: 1 64 94 65 95 additionalProperties: false 66 96
+3 -6
drivers/amba/bus.c
··· 291 291 if (ret < 0) 292 292 break; 293 293 294 - ret = dev_pm_domain_attach(dev, PD_FLAG_ATTACH_POWER_ON); 294 + ret = dev_pm_domain_attach(dev, PD_FLAG_ATTACH_POWER_ON | 295 + PD_FLAG_DETACH_POWER_OFF); 295 296 if (ret) 296 297 break; 297 298 298 299 ret = amba_get_enable_pclk(pcdev); 299 - if (ret) { 300 - dev_pm_domain_detach(dev, true); 300 + if (ret) 301 301 break; 302 - } 303 302 304 303 pm_runtime_get_noresume(dev); 305 304 pm_runtime_set_active(dev); ··· 313 314 pm_runtime_put_noidle(dev); 314 315 315 316 amba_put_disable_pclk(pcdev); 316 - dev_pm_domain_detach(dev, true); 317 317 } while (0); 318 318 319 319 return ret; ··· 334 336 pm_runtime_put_noidle(dev); 335 337 336 338 amba_put_disable_pclk(pcdev); 337 - dev_pm_domain_detach(dev, true); 338 339 } 339 340 340 341 static void amba_shutdown(struct device *dev)
+1
drivers/base/power/main.c
··· 2148 2148 device_lock(dev); 2149 2149 2150 2150 dev->power.wakeup_path = false; 2151 + dev->power.out_band_wakeup = false; 2151 2152 2152 2153 if (dev->power.no_pm_callbacks) 2153 2154 goto unlock;
+2 -2
drivers/cpuidle/cpuidle-psci.c
··· 382 382 drv->states[0].exit_latency = 1; 383 383 drv->states[0].target_residency = 1; 384 384 drv->states[0].power_usage = UINT_MAX; 385 - strcpy(drv->states[0].name, "WFI"); 386 - strcpy(drv->states[0].desc, "ARM WFI"); 385 + strscpy(drv->states[0].name, "WFI"); 386 + strscpy(drv->states[0].desc, "ARM WFI"); 387 387 388 388 /* 389 389 * If no DT idle states are detected (ret == 0) let the driver
+13 -4
drivers/pmdomain/bcm/bcm2835-power.c
··· 79 79 #define PM_IMAGE 0x108 80 80 #define PM_GRAFX 0x10c 81 81 #define PM_PROC 0x110 82 + #define PM_GRAFX_2712 0x304 82 83 #define PM_ENAB BIT(12) 83 84 #define PM_ISPRSTN BIT(8) 84 85 #define PM_H264RSTN BIT(7) ··· 382 381 return bcm2835_power_power_on(pd, PM_GRAFX); 383 382 384 383 case BCM2835_POWER_DOMAIN_GRAFX_V3D: 384 + if (!power->asb) 385 + return bcm2835_asb_power_on(pd, PM_GRAFX_2712, 386 + 0, 0, PM_V3DRSTN); 385 387 return bcm2835_asb_power_on(pd, PM_GRAFX, 386 388 ASB_V3D_M_CTRL, ASB_V3D_S_CTRL, 387 389 PM_V3DRSTN); ··· 451 447 return bcm2835_power_power_off(pd, PM_GRAFX); 452 448 453 449 case BCM2835_POWER_DOMAIN_GRAFX_V3D: 450 + if (!power->asb) 451 + return bcm2835_asb_power_off(pd, PM_GRAFX_2712, 452 + 0, 0, PM_V3DRSTN); 454 453 return bcm2835_asb_power_off(pd, PM_GRAFX, 455 454 ASB_V3D_M_CTRL, ASB_V3D_S_CTRL, 456 455 PM_V3DRSTN); ··· 642 635 power->asb = pm->asb; 643 636 power->rpivid_asb = pm->rpivid_asb; 644 637 645 - id = readl(power->asb + ASB_AXI_BRDG_ID); 646 - if (id != BCM2835_BRDG_ID /* "BRDG" */) { 647 - dev_err(dev, "ASB register ID returned 0x%08x\n", id); 648 - return -ENODEV; 638 + if (power->asb) { 639 + id = readl(power->asb + ASB_AXI_BRDG_ID); 640 + if (id != BCM2835_BRDG_ID /* "BRDG" */) { 641 + dev_err(dev, "ASB register ID returned 0x%08x\n", id); 642 + return -ENODEV; 643 + } 649 644 } 650 645 651 646 if (power->rpivid_asb) {
+4 -2
drivers/pmdomain/core.c
··· 1551 1551 if (ret) 1552 1552 return ret; 1553 1553 1554 - if (device_awake_path(dev) && genpd_is_active_wakeup(genpd)) 1554 + if (device_awake_path(dev) && genpd_is_active_wakeup(genpd) && 1555 + !device_out_band_wakeup(dev)) 1555 1556 return 0; 1556 1557 1557 1558 if (genpd->dev_ops.stop && genpd->dev_ops.start && ··· 1607 1606 if (IS_ERR(genpd)) 1608 1607 return -EINVAL; 1609 1608 1610 - if (device_awake_path(dev) && genpd_is_active_wakeup(genpd)) 1609 + if (device_awake_path(dev) && genpd_is_active_wakeup(genpd) && 1610 + !device_out_band_wakeup(dev)) 1611 1611 return resume_noirq(dev); 1612 1612 1613 1613 genpd_lock(genpd);
+13 -7
drivers/pmdomain/governor.c
··· 408 408 if ((idle_duration_ns >= (genpd->states[i].residency_ns + 409 409 genpd->states[i].power_off_latency_ns)) && 410 410 (global_constraint >= (genpd->states[i].power_on_latency_ns + 411 - genpd->states[i].power_off_latency_ns))) { 412 - genpd->state_idx = i; 413 - genpd->gd->last_enter = now; 414 - genpd->gd->reflect_residency = true; 415 - return true; 416 - } 411 + genpd->states[i].power_off_latency_ns))) 412 + break; 413 + 417 414 } while (--i >= 0); 418 415 419 - return false; 416 + if (i < 0) 417 + return false; 418 + 419 + if (cpus_peek_for_pending_ipi(genpd->cpus)) 420 + return false; 421 + 422 + genpd->state_idx = i; 423 + genpd->gd->last_enter = now; 424 + genpd->gd->reflect_residency = true; 425 + return true; 420 426 } 421 427 422 428 static bool cpu_system_power_down_ok(struct dev_pm_domain *pd)
+17
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 MTK_MFG_PM_DOMAIN 30 + bool "MediaTek MFlexGraphics power domain" 31 + default ARCH_MEDIATEK 32 + depends on PM 33 + depends on OF 34 + depends on COMMON_CLK 35 + select MAILBOX 36 + select PM_GENERIC_DOMAINS 37 + imply MTK_GPUEB_MBOX 38 + help 39 + Say y or m here to enable the power domains driver for MediaTek 40 + MFlexGraphics. This driver allows for power and frequency control of 41 + GPUs on MediaTek SoCs such as the MT8196 or MT6991. 42 + 43 + This driver is required for the Mali GPU to work at all on MT8196 and 44 + MT6991. 45 + 29 46 config AIROHA_CPU_PM_DOMAIN 30 47 tristate "Airoha CPU power domain" 31 48 default ARCH_AIROHA
+1
drivers/pmdomain/mediatek/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 + obj-$(CONFIG_MTK_MFG_PM_DOMAIN) += mtk-mfg-pmdomain.o 2 3 obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o 3 4 obj-$(CONFIG_MTK_SCPSYS_PM_DOMAINS) += mtk-pm-domains.o 4 5 obj-$(CONFIG_AIROHA_CPU_PM_DOMAIN) += airoha-cpu-pmdomain.o
+625
drivers/pmdomain/mediatek/mt8196-pm-domains.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Copyright (c) 2025 Collabora Ltd 4 + * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> 5 + */ 6 + 7 + #ifndef __SOC_MEDIATEK_MT8196_PM_DOMAINS_H 8 + #define __SOC_MEDIATEK_MT8196_PM_DOMAINS_H 9 + 10 + #include "mtk-pm-domains.h" 11 + #include <dt-bindings/power/mediatek,mt8196-power.h> 12 + 13 + /* 14 + * MT8196 and MT6991 power domain support 15 + */ 16 + 17 + /* INFRA TOP_AXI registers */ 18 + #define MT8196_TOP_AXI_PROT_EN_SET 0x4 19 + #define MT8196_TOP_AXI_PROT_EN_CLR 0x8 20 + #define MT8196_TOP_AXI_PROT_EN_STA 0xc 21 + #define MT8196_TOP_AXI_PROT_EN_SLEEP0_MD BIT(29) 22 + 23 + #define MT8196_TOP_AXI_PROT_EN_1_SET 0x24 24 + #define MT8196_TOP_AXI_PROT_EN_1_CLR 0x28 25 + #define MT8196_TOP_AXI_PROT_EN_1_STA 0x2c 26 + #define MT8196_TOP_AXI_PROT_EN_1_SLEEP1_MD BIT(0) 27 + 28 + /* SPM BUS_PROTECT registers */ 29 + #define MT8196_SPM_BUS_PROTECT_CON_SET 0xdc 30 + #define MT8196_SPM_BUS_PROTECT_CON_CLR 0xe0 31 + #define MT8196_SPM_BUS_PROTECT_RDY 0x208 32 + #define MT8196_SPM_PROT_EN_BUS_CONN BIT(1) 33 + #define MT8196_SPM_PROT_EN_BUS_SSUSB_DP_PHY_P0 BIT(6) 34 + #define MT8196_SPM_PROT_EN_BUS_SSUSB_P0 BIT(7) 35 + #define MT8196_SPM_PROT_EN_BUS_SSUSB_P1 BIT(8) 36 + #define MT8196_SPM_PROT_EN_BUS_SSUSB_P23 BIT(9) 37 + #define MT8196_SPM_PROT_EN_BUS_SSUSB_PHY_P2 BIT(10) 38 + #define MT8196_SPM_PROT_EN_BUS_PEXTP_MAC0 BIT(13) 39 + #define MT8196_SPM_PROT_EN_BUS_PEXTP_MAC1 BIT(14) 40 + #define MT8196_SPM_PROT_EN_BUS_PEXTP_MAC2 BIT(15) 41 + #define MT8196_SPM_PROT_EN_BUS_PEXTP_PHY0 BIT(16) 42 + #define MT8196_SPM_PROT_EN_BUS_PEXTP_PHY1 BIT(17) 43 + #define MT8196_SPM_PROT_EN_BUS_PEXTP_PHY2 BIT(18) 44 + #define MT8196_SPM_PROT_EN_BUS_AUDIO BIT(19) 45 + #define MT8196_SPM_PROT_EN_BUS_ADSP_TOP BIT(21) 46 + #define MT8196_SPM_PROT_EN_BUS_ADSP_INFRA BIT(22) 47 + #define MT8196_SPM_PROT_EN_BUS_ADSP_AO BIT(23) 48 + #define MT8196_SPM_PROT_EN_BUS_MM_PROC BIT(24) 49 + 50 + /* PWR_CON registers */ 51 + #define MT8196_PWR_ACK BIT(30) 52 + #define MT8196_PWR_ACK_2ND BIT(31) 53 + 54 + static enum scpsys_bus_prot_block scpsys_bus_prot_blocks_mt8196[] = { 55 + BUS_PROT_BLOCK_INFRA, BUS_PROT_BLOCK_SPM 56 + }; 57 + 58 + static const struct scpsys_domain_data scpsys_domain_data_mt8196[] = { 59 + [MT8196_POWER_DOMAIN_MD] = { 60 + .name = "md", 61 + .sta_mask = MT8196_PWR_ACK, 62 + .sta2nd_mask = MT8196_PWR_ACK_2ND, 63 + .ctl_offs = 0xe00, 64 + .pwr_sta_offs = 0xe00, 65 + .pwr_sta2nd_offs = 0xe00, 66 + .ext_buck_iso_offs = 0xefc, 67 + .ext_buck_iso_mask = GENMASK(1, 0), 68 + .bp_cfg = { 69 + BUS_PROT_WR_IGN(INFRA, MT8196_TOP_AXI_PROT_EN_SLEEP0_MD, 70 + MT8196_TOP_AXI_PROT_EN_SET, 71 + MT8196_TOP_AXI_PROT_EN_CLR, 72 + MT8196_TOP_AXI_PROT_EN_STA), 73 + BUS_PROT_WR_IGN(INFRA, MT8196_TOP_AXI_PROT_EN_1_SLEEP1_MD, 74 + MT8196_TOP_AXI_PROT_EN_1_SET, 75 + MT8196_TOP_AXI_PROT_EN_1_CLR, 76 + MT8196_TOP_AXI_PROT_EN_1_STA), 77 + }, 78 + .caps = MTK_SCPD_MODEM_PWRSEQ | MTK_SCPD_EXT_BUCK_ISO | 79 + MTK_SCPD_SKIP_RESET_B | MTK_SCPD_KEEP_DEFAULT_OFF, 80 + }, 81 + [MT8196_POWER_DOMAIN_CONN] = { 82 + .name = "conn", 83 + .sta_mask = MT8196_PWR_ACK, 84 + .sta2nd_mask = MT8196_PWR_ACK_2ND, 85 + .ctl_offs = 0xe04, 86 + .pwr_sta_offs = 0xe04, 87 + .pwr_sta2nd_offs = 0xe04, 88 + .bp_cfg = { 89 + BUS_PROT_WR_IGN(SPM, MT8196_SPM_PROT_EN_BUS_CONN, 90 + MT8196_SPM_BUS_PROTECT_CON_SET, 91 + MT8196_SPM_BUS_PROTECT_CON_CLR, 92 + MT8196_SPM_BUS_PROTECT_RDY), 93 + }, 94 + .caps = MTK_SCPD_KEEP_DEFAULT_OFF, 95 + .rtff_type = SCPSYS_RTFF_TYPE_GENERIC, 96 + }, 97 + [MT8196_POWER_DOMAIN_SSUSB_DP_PHY_P0] = { 98 + .name = "ssusb-dp-phy-p0", 99 + .sta_mask = MT8196_PWR_ACK, 100 + .sta2nd_mask = MT8196_PWR_ACK_2ND, 101 + .ctl_offs = 0xe18, 102 + .pwr_sta_offs = 0xe18, 103 + .pwr_sta2nd_offs = 0xe18, 104 + .bp_cfg = { 105 + BUS_PROT_WR_IGN(SPM, MT8196_SPM_PROT_EN_BUS_SSUSB_DP_PHY_P0, 106 + MT8196_SPM_BUS_PROTECT_CON_SET, 107 + MT8196_SPM_BUS_PROTECT_CON_CLR, 108 + MT8196_SPM_BUS_PROTECT_RDY), 109 + }, 110 + .caps = MTK_SCPD_ALWAYS_ON, 111 + .rtff_type = SCPSYS_RTFF_TYPE_GENERIC, 112 + }, 113 + [MT8196_POWER_DOMAIN_SSUSB_P0] = { 114 + .name = "ssusb-p0", 115 + .sta_mask = MT8196_PWR_ACK, 116 + .sta2nd_mask = MT8196_PWR_ACK_2ND, 117 + .ctl_offs = 0xe1c, 118 + .pwr_sta_offs = 0xe1c, 119 + .pwr_sta2nd_offs = 0xe1c, 120 + .sram_pdn_bits = BIT(8), 121 + .sram_pdn_ack_bits = BIT(12), 122 + .bp_cfg = { 123 + BUS_PROT_WR_IGN(SPM, MT8196_SPM_PROT_EN_BUS_SSUSB_P0, 124 + MT8196_SPM_BUS_PROTECT_CON_SET, 125 + MT8196_SPM_BUS_PROTECT_CON_CLR, 126 + MT8196_SPM_BUS_PROTECT_RDY), 127 + }, 128 + .caps = MTK_SCPD_ALWAYS_ON, 129 + .rtff_type = SCPSYS_RTFF_TYPE_GENERIC, 130 + }, 131 + [MT8196_POWER_DOMAIN_SSUSB_P1] = { 132 + .name = "ssusb-p1", 133 + .sta_mask = MT8196_PWR_ACK, 134 + .sta2nd_mask = MT8196_PWR_ACK_2ND, 135 + .ctl_offs = 0xe20, 136 + .pwr_sta_offs = 0xe20, 137 + .pwr_sta2nd_offs = 0xe20, 138 + .sram_pdn_bits = BIT(8), 139 + .sram_pdn_ack_bits = BIT(12), 140 + .bp_cfg = { 141 + BUS_PROT_WR_IGN(SPM, MT8196_SPM_PROT_EN_BUS_SSUSB_P1, 142 + MT8196_SPM_BUS_PROTECT_CON_SET, 143 + MT8196_SPM_BUS_PROTECT_CON_CLR, 144 + MT8196_SPM_BUS_PROTECT_RDY), 145 + }, 146 + .caps = MTK_SCPD_ALWAYS_ON, 147 + .rtff_type = SCPSYS_RTFF_TYPE_GENERIC, 148 + }, 149 + [MT8196_POWER_DOMAIN_SSUSB_P23] = { 150 + .name = "ssusb-p23", 151 + .sta_mask = MT8196_PWR_ACK, 152 + .sta2nd_mask = MT8196_PWR_ACK_2ND, 153 + .ctl_offs = 0xe24, 154 + .pwr_sta_offs = 0xe24, 155 + .pwr_sta2nd_offs = 0xe24, 156 + .bp_cfg = { 157 + BUS_PROT_WR_IGN(SPM, MT8196_SPM_PROT_EN_BUS_SSUSB_P23, 158 + MT8196_SPM_BUS_PROTECT_CON_SET, 159 + MT8196_SPM_BUS_PROTECT_CON_CLR, 160 + MT8196_SPM_BUS_PROTECT_RDY), 161 + }, 162 + .caps = MTK_SCPD_KEEP_DEFAULT_OFF, 163 + .rtff_type = SCPSYS_RTFF_TYPE_GENERIC, 164 + }, 165 + [MT8196_POWER_DOMAIN_SSUSB_PHY_P2] = { 166 + .name = "ssusb-phy-p2", 167 + .sta_mask = MT8196_PWR_ACK, 168 + .sta2nd_mask = MT8196_PWR_ACK_2ND, 169 + .ctl_offs = 0xe28, 170 + .pwr_sta_offs = 0xe28, 171 + .pwr_sta2nd_offs = 0xe28, 172 + .sram_pdn_bits = BIT(8), 173 + .sram_pdn_ack_bits = BIT(12), 174 + .bp_cfg = { 175 + BUS_PROT_WR_IGN(SPM, MT8196_SPM_PROT_EN_BUS_SSUSB_PHY_P2, 176 + MT8196_SPM_BUS_PROTECT_CON_SET, 177 + MT8196_SPM_BUS_PROTECT_CON_CLR, 178 + MT8196_SPM_BUS_PROTECT_RDY), 179 + }, 180 + .caps = MTK_SCPD_KEEP_DEFAULT_OFF, 181 + .rtff_type = SCPSYS_RTFF_TYPE_GENERIC, 182 + }, 183 + [MT8196_POWER_DOMAIN_PEXTP_MAC0] = { 184 + .name = "pextp-mac0", 185 + .sta_mask = MT8196_PWR_ACK, 186 + .sta2nd_mask = MT8196_PWR_ACK_2ND, 187 + .ctl_offs = 0xe34, 188 + .pwr_sta_offs = 0xe34, 189 + .pwr_sta2nd_offs = 0xe34, 190 + .sram_pdn_bits = BIT(8), 191 + .sram_pdn_ack_bits = BIT(12), 192 + .bp_cfg = { 193 + BUS_PROT_WR_IGN(SPM, MT8196_SPM_PROT_EN_BUS_PEXTP_MAC0, 194 + MT8196_SPM_BUS_PROTECT_CON_SET, 195 + MT8196_SPM_BUS_PROTECT_CON_CLR, 196 + MT8196_SPM_BUS_PROTECT_RDY), 197 + }, 198 + .rtff_type = SCPSYS_RTFF_TYPE_PCIE_PHY, 199 + }, 200 + [MT8196_POWER_DOMAIN_PEXTP_MAC1] = { 201 + .name = "pextp-mac1", 202 + .sta_mask = MT8196_PWR_ACK, 203 + .sta2nd_mask = MT8196_PWR_ACK_2ND, 204 + .ctl_offs = 0xe38, 205 + .pwr_sta_offs = 0xe38, 206 + .pwr_sta2nd_offs = 0xe38, 207 + .sram_pdn_bits = BIT(8), 208 + .sram_pdn_ack_bits = BIT(12), 209 + .bp_cfg = { 210 + BUS_PROT_WR_IGN(SPM, MT8196_SPM_PROT_EN_BUS_PEXTP_MAC1, 211 + MT8196_SPM_BUS_PROTECT_CON_SET, 212 + MT8196_SPM_BUS_PROTECT_CON_CLR, 213 + MT8196_SPM_BUS_PROTECT_RDY), 214 + }, 215 + .rtff_type = SCPSYS_RTFF_TYPE_PCIE_PHY, 216 + }, 217 + [MT8196_POWER_DOMAIN_PEXTP_MAC2] = { 218 + .name = "pextp-mac2", 219 + .sta_mask = MT8196_PWR_ACK, 220 + .sta2nd_mask = MT8196_PWR_ACK_2ND, 221 + .ctl_offs = 0xe3c, 222 + .pwr_sta_offs = 0xe3c, 223 + .pwr_sta2nd_offs = 0xe3c, 224 + .sram_pdn_bits = BIT(8), 225 + .sram_pdn_ack_bits = BIT(12), 226 + .bp_cfg = { 227 + BUS_PROT_WR_IGN(SPM, MT8196_SPM_PROT_EN_BUS_PEXTP_MAC2, 228 + MT8196_SPM_BUS_PROTECT_CON_SET, 229 + MT8196_SPM_BUS_PROTECT_CON_CLR, 230 + MT8196_SPM_BUS_PROTECT_RDY), 231 + }, 232 + .rtff_type = SCPSYS_RTFF_TYPE_PCIE_PHY, 233 + }, 234 + [MT8196_POWER_DOMAIN_PEXTP_PHY0] = { 235 + .name = "pextp-phy0", 236 + .sta_mask = MT8196_PWR_ACK, 237 + .sta2nd_mask = MT8196_PWR_ACK_2ND, 238 + .ctl_offs = 0xe40, 239 + .pwr_sta_offs = 0xe40, 240 + .pwr_sta2nd_offs = 0xe40, 241 + .bp_cfg = { 242 + BUS_PROT_WR_IGN(SPM, MT8196_SPM_PROT_EN_BUS_PEXTP_PHY0, 243 + MT8196_SPM_BUS_PROTECT_CON_SET, 244 + MT8196_SPM_BUS_PROTECT_CON_CLR, 245 + MT8196_SPM_BUS_PROTECT_RDY), 246 + }, 247 + .rtff_type = SCPSYS_RTFF_TYPE_PCIE_PHY, 248 + }, 249 + [MT8196_POWER_DOMAIN_PEXTP_PHY1] = { 250 + .name = "pextp-phy1", 251 + .sta_mask = MT8196_PWR_ACK, 252 + .sta2nd_mask = MT8196_PWR_ACK_2ND, 253 + .ctl_offs = 0xe44, 254 + .pwr_sta_offs = 0xe44, 255 + .pwr_sta2nd_offs = 0xe44, 256 + .bp_cfg = { 257 + BUS_PROT_WR_IGN(SPM, MT8196_SPM_PROT_EN_BUS_PEXTP_PHY1, 258 + MT8196_SPM_BUS_PROTECT_CON_SET, 259 + MT8196_SPM_BUS_PROTECT_CON_CLR, 260 + MT8196_SPM_BUS_PROTECT_RDY), 261 + }, 262 + .rtff_type = SCPSYS_RTFF_TYPE_PCIE_PHY, 263 + }, 264 + [MT8196_POWER_DOMAIN_PEXTP_PHY2] = { 265 + .name = "pextp-phy2", 266 + .sta_mask = MT8196_PWR_ACK, 267 + .sta2nd_mask = MT8196_PWR_ACK_2ND, 268 + .ctl_offs = 0xe48, 269 + .pwr_sta_offs = 0xe48, 270 + .pwr_sta2nd_offs = 0xe48, 271 + .bp_cfg = { 272 + BUS_PROT_WR_IGN(SPM, MT8196_SPM_PROT_EN_BUS_PEXTP_PHY2, 273 + MT8196_SPM_BUS_PROTECT_CON_SET, 274 + MT8196_SPM_BUS_PROTECT_CON_CLR, 275 + MT8196_SPM_BUS_PROTECT_RDY), 276 + }, 277 + .rtff_type = SCPSYS_RTFF_TYPE_PCIE_PHY, 278 + }, 279 + [MT8196_POWER_DOMAIN_AUDIO] = { 280 + .name = "audio", 281 + .sta_mask = MT8196_PWR_ACK, 282 + .sta2nd_mask = MT8196_PWR_ACK_2ND, 283 + .ctl_offs = 0xe4c, 284 + .pwr_sta_offs = 0xe4c, 285 + .pwr_sta2nd_offs = 0xe4c, 286 + .sram_pdn_bits = BIT(8), 287 + .sram_pdn_ack_bits = BIT(12), 288 + .bp_cfg = { 289 + BUS_PROT_WR_IGN(SPM, MT8196_SPM_PROT_EN_BUS_AUDIO, 290 + MT8196_SPM_BUS_PROTECT_CON_SET, 291 + MT8196_SPM_BUS_PROTECT_CON_CLR, 292 + MT8196_SPM_BUS_PROTECT_RDY), 293 + }, 294 + .rtff_type = SCPSYS_RTFF_TYPE_GENERIC, 295 + }, 296 + [MT8196_POWER_DOMAIN_ADSP_TOP_DORMANT] = { 297 + .name = "adsp-top-dormant", 298 + .sta_mask = MT8196_PWR_ACK, 299 + .sta2nd_mask = MT8196_PWR_ACK_2ND, 300 + .ctl_offs = 0xe54, 301 + .pwr_sta_offs = 0xe54, 302 + .pwr_sta2nd_offs = 0xe54, 303 + /* Note: This is not managing powerdown (pdn), but sleep instead (slp) */ 304 + .sram_pdn_bits = BIT(9), 305 + .sram_pdn_ack_bits = BIT(13), 306 + .bp_cfg = { 307 + BUS_PROT_WR_IGN(SPM, MT8196_SPM_PROT_EN_BUS_ADSP_TOP, 308 + MT8196_SPM_BUS_PROTECT_CON_SET, 309 + MT8196_SPM_BUS_PROTECT_CON_CLR, 310 + MT8196_SPM_BUS_PROTECT_RDY), 311 + }, 312 + .caps = MTK_SCPD_SRAM_ISO | MTK_SCPD_SRAM_PDN_INVERTED, 313 + }, 314 + [MT8196_POWER_DOMAIN_ADSP_INFRA] = { 315 + .name = "adsp-infra", 316 + .sta_mask = MT8196_PWR_ACK, 317 + .sta2nd_mask = MT8196_PWR_ACK_2ND, 318 + .ctl_offs = 0xe58, 319 + .pwr_sta_offs = 0xe58, 320 + .pwr_sta2nd_offs = 0xe58, 321 + .bp_cfg = { 322 + BUS_PROT_WR_IGN(SPM, MT8196_SPM_PROT_EN_BUS_ADSP_INFRA, 323 + MT8196_SPM_BUS_PROTECT_CON_SET, 324 + MT8196_SPM_BUS_PROTECT_CON_CLR, 325 + MT8196_SPM_BUS_PROTECT_RDY), 326 + }, 327 + .caps = MTK_SCPD_ALWAYS_ON, 328 + .rtff_type = SCPSYS_RTFF_TYPE_GENERIC, 329 + }, 330 + [MT8196_POWER_DOMAIN_ADSP_AO] = { 331 + .name = "adsp-ao", 332 + .sta_mask = MT8196_PWR_ACK, 333 + .sta2nd_mask = MT8196_PWR_ACK_2ND, 334 + .ctl_offs = 0xe5c, 335 + .pwr_sta_offs = 0xe5c, 336 + .pwr_sta2nd_offs = 0xe5c, 337 + .bp_cfg = { 338 + BUS_PROT_WR_IGN(SPM, MT8196_SPM_PROT_EN_BUS_ADSP_AO, 339 + MT8196_SPM_BUS_PROTECT_CON_SET, 340 + MT8196_SPM_BUS_PROTECT_CON_CLR, 341 + MT8196_SPM_BUS_PROTECT_RDY), 342 + }, 343 + .caps = MTK_SCPD_ALWAYS_ON, 344 + .rtff_type = SCPSYS_RTFF_TYPE_GENERIC, 345 + }, 346 + }; 347 + 348 + static const struct scpsys_hwv_domain_data scpsys_hwv_domain_data_mt8196[] = { 349 + [MT8196_POWER_DOMAIN_MM_PROC_DORMANT] = { 350 + .name = "mm-proc-dormant", 351 + .set = 0x0218, 352 + .clr = 0x021c, 353 + .done = 0x141c, 354 + .en = 0x1410, 355 + .set_sta = 0x146c, 356 + .clr_sta = 0x1470, 357 + .setclr_bit = 0, 358 + .caps = MTK_SCPD_ALWAYS_ON, 359 + }, 360 + [MT8196_POWER_DOMAIN_SSR] = { 361 + .name = "ssrsys", 362 + .set = 0x0218, 363 + .clr = 0x021c, 364 + .done = 0x141c, 365 + .en = 0x1410, 366 + .set_sta = 0x146c, 367 + .clr_sta = 0x1470, 368 + .setclr_bit = 1, 369 + }, 370 + }; 371 + 372 + static const struct scpsys_hwv_domain_data hfrpsys_hwv_domain_data_mt8196[] = { 373 + [MT8196_POWER_DOMAIN_VDE0] = { 374 + .name = "vde0", 375 + .set = 0x0218, 376 + .clr = 0x021C, 377 + .done = 0x141C, 378 + .en = 0x1410, 379 + .set_sta = 0x146C, 380 + .clr_sta = 0x1470, 381 + .setclr_bit = 7, 382 + }, 383 + [MT8196_POWER_DOMAIN_VDE1] = { 384 + .name = "vde1", 385 + .set = 0x0218, 386 + .clr = 0x021C, 387 + .done = 0x141C, 388 + .en = 0x1410, 389 + .set_sta = 0x146C, 390 + .clr_sta = 0x1470, 391 + .setclr_bit = 8, 392 + }, 393 + [MT8196_POWER_DOMAIN_VDE_VCORE0] = { 394 + .name = "vde-vcore0", 395 + .set = 0x0218, 396 + .clr = 0x021C, 397 + .done = 0x141C, 398 + .en = 0x1410, 399 + .set_sta = 0x146C, 400 + .clr_sta = 0x1470, 401 + .setclr_bit = 9, 402 + }, 403 + [MT8196_POWER_DOMAIN_VEN0] = { 404 + .name = "ven0", 405 + .set = 0x0218, 406 + .clr = 0x021C, 407 + .done = 0x141C, 408 + .en = 0x1410, 409 + .set_sta = 0x146C, 410 + .clr_sta = 0x1470, 411 + .setclr_bit = 10, 412 + }, 413 + [MT8196_POWER_DOMAIN_VEN1] = { 414 + .name = "ven1", 415 + .set = 0x0218, 416 + .clr = 0x021C, 417 + .done = 0x141C, 418 + .en = 0x1410, 419 + .set_sta = 0x146C, 420 + .clr_sta = 0x1470, 421 + .setclr_bit = 11, 422 + }, 423 + [MT8196_POWER_DOMAIN_VEN2] = { 424 + .name = "ven2", 425 + .set = 0x0218, 426 + .clr = 0x021C, 427 + .done = 0x141C, 428 + .en = 0x1410, 429 + .set_sta = 0x146C, 430 + .clr_sta = 0x1470, 431 + .setclr_bit = 12, 432 + }, 433 + [MT8196_POWER_DOMAIN_DISP_VCORE] = { 434 + .name = "disp-vcore", 435 + .set = 0x0218, 436 + .clr = 0x021C, 437 + .done = 0x141C, 438 + .en = 0x1410, 439 + .set_sta = 0x146C, 440 + .clr_sta = 0x1470, 441 + .setclr_bit = 24, 442 + }, 443 + [MT8196_POWER_DOMAIN_DIS0_DORMANT] = { 444 + .name = "dis0-dormant", 445 + .set = 0x0218, 446 + .clr = 0x021C, 447 + .done = 0x141C, 448 + .en = 0x1410, 449 + .set_sta = 0x146C, 450 + .clr_sta = 0x1470, 451 + .setclr_bit = 25, 452 + }, 453 + [MT8196_POWER_DOMAIN_DIS1_DORMANT] = { 454 + .name = "dis1-dormant", 455 + .set = 0x0218, 456 + .clr = 0x021C, 457 + .done = 0x141C, 458 + .en = 0x1410, 459 + .set_sta = 0x146C, 460 + .clr_sta = 0x1470, 461 + .setclr_bit = 26, 462 + }, 463 + [MT8196_POWER_DOMAIN_OVL0_DORMANT] = { 464 + .name = "ovl0-dormant", 465 + .set = 0x0218, 466 + .clr = 0x021C, 467 + .done = 0x141C, 468 + .en = 0x1410, 469 + .set_sta = 0x146C, 470 + .clr_sta = 0x1470, 471 + .setclr_bit = 27, 472 + }, 473 + [MT8196_POWER_DOMAIN_OVL1_DORMANT] = { 474 + .name = "ovl1-dormant", 475 + .set = 0x0218, 476 + .clr = 0x021C, 477 + .done = 0x141C, 478 + .en = 0x1410, 479 + .set_sta = 0x146C, 480 + .clr_sta = 0x1470, 481 + .setclr_bit = 28, 482 + }, 483 + [MT8196_POWER_DOMAIN_DISP_EDPTX_DORMANT] = { 484 + .name = "disp-edptx-dormant", 485 + .set = 0x0218, 486 + .clr = 0x021C, 487 + .done = 0x141C, 488 + .en = 0x1410, 489 + .set_sta = 0x146C, 490 + .clr_sta = 0x1470, 491 + .setclr_bit = 29, 492 + }, 493 + [MT8196_POWER_DOMAIN_DISP_DPTX_DORMANT] = { 494 + .name = "disp-dptx-dormant", 495 + .set = 0x0218, 496 + .clr = 0x021C, 497 + .done = 0x141C, 498 + .en = 0x1410, 499 + .set_sta = 0x146C, 500 + .clr_sta = 0x1470, 501 + .setclr_bit = 30, 502 + }, 503 + [MT8196_POWER_DOMAIN_MML0_SHUTDOWN] = { 504 + .name = "mml0-shutdown", 505 + .set = 0x0218, 506 + .clr = 0x021C, 507 + .done = 0x141C, 508 + .en = 0x1410, 509 + .set_sta = 0x146C, 510 + .clr_sta = 0x1470, 511 + .setclr_bit = 31, 512 + }, 513 + [MT8196_POWER_DOMAIN_MML1_SHUTDOWN] = { 514 + .name = "mml1-shutdown", 515 + .set = 0x0220, 516 + .clr = 0x0224, 517 + .done = 0x142C, 518 + .en = 0x1420, 519 + .set_sta = 0x1474, 520 + .clr_sta = 0x1478, 521 + .setclr_bit = 0, 522 + }, 523 + [MT8196_POWER_DOMAIN_MM_INFRA0] = { 524 + .name = "mm-infra0", 525 + .set = 0x0220, 526 + .clr = 0x0224, 527 + .done = 0x142C, 528 + .en = 0x1420, 529 + .set_sta = 0x1474, 530 + .clr_sta = 0x1478, 531 + .setclr_bit = 1, 532 + }, 533 + [MT8196_POWER_DOMAIN_MM_INFRA1] = { 534 + .name = "mm-infra1", 535 + .set = 0x0220, 536 + .clr = 0x0224, 537 + .done = 0x142C, 538 + .en = 0x1420, 539 + .set_sta = 0x1474, 540 + .clr_sta = 0x1478, 541 + .setclr_bit = 2, 542 + }, 543 + [MT8196_POWER_DOMAIN_MM_INFRA_AO] = { 544 + .name = "mm-infra-ao", 545 + .set = 0x0220, 546 + .clr = 0x0224, 547 + .done = 0x142C, 548 + .en = 0x1420, 549 + .set_sta = 0x1474, 550 + .clr_sta = 0x1478, 551 + .setclr_bit = 3, 552 + }, 553 + [MT8196_POWER_DOMAIN_CSI_BS_RX] = { 554 + .name = "csi-bs-rx", 555 + .set = 0x0220, 556 + .clr = 0x0224, 557 + .done = 0x142C, 558 + .en = 0x1420, 559 + .set_sta = 0x1474, 560 + .clr_sta = 0x1478, 561 + .setclr_bit = 5, 562 + }, 563 + [MT8196_POWER_DOMAIN_CSI_LS_RX] = { 564 + .name = "csi-ls-rx", 565 + .set = 0x0220, 566 + .clr = 0x0224, 567 + .done = 0x142C, 568 + .en = 0x1420, 569 + .set_sta = 0x1474, 570 + .clr_sta = 0x1478, 571 + .setclr_bit = 6, 572 + }, 573 + [MT8196_POWER_DOMAIN_DSI_PHY0] = { 574 + .name = "dsi-phy0", 575 + .set = 0x0220, 576 + .clr = 0x0224, 577 + .done = 0x142C, 578 + .en = 0x1420, 579 + .set_sta = 0x1474, 580 + .clr_sta = 0x1478, 581 + .setclr_bit = 7, 582 + }, 583 + [MT8196_POWER_DOMAIN_DSI_PHY1] = { 584 + .name = "dsi-phy1", 585 + .set = 0x0220, 586 + .clr = 0x0224, 587 + .done = 0x142C, 588 + .en = 0x1420, 589 + .set_sta = 0x1474, 590 + .clr_sta = 0x1478, 591 + .setclr_bit = 8, 592 + }, 593 + [MT8196_POWER_DOMAIN_DSI_PHY2] = { 594 + .name = "dsi-phy2", 595 + .set = 0x0220, 596 + .clr = 0x0224, 597 + .done = 0x142C, 598 + .en = 0x1420, 599 + .set_sta = 0x1474, 600 + .clr_sta = 0x1478, 601 + .setclr_bit = 9, 602 + }, 603 + }; 604 + 605 + static const struct scpsys_soc_data mt8196_scpsys_data = { 606 + .domains_data = scpsys_domain_data_mt8196, 607 + .num_domains = ARRAY_SIZE(scpsys_domain_data_mt8196), 608 + .bus_prot_blocks = scpsys_bus_prot_blocks_mt8196, 609 + .num_bus_prot_blocks = ARRAY_SIZE(scpsys_bus_prot_blocks_mt8196), 610 + .type = SCPSYS_MTCMOS_TYPE_DIRECT_CTL, 611 + }; 612 + 613 + static const struct scpsys_soc_data mt8196_scpsys_hwv_data = { 614 + .hwv_domains_data = scpsys_hwv_domain_data_mt8196, 615 + .num_hwv_domains = ARRAY_SIZE(scpsys_hwv_domain_data_mt8196), 616 + .type = SCPSYS_MTCMOS_TYPE_HW_VOTER, 617 + }; 618 + 619 + static const struct scpsys_soc_data mt8196_hfrpsys_hwv_data = { 620 + .hwv_domains_data = hfrpsys_hwv_domain_data_mt8196, 621 + .num_hwv_domains = ARRAY_SIZE(hfrpsys_hwv_domain_data_mt8196), 622 + .type = SCPSYS_MTCMOS_TYPE_HW_VOTER, 623 + }; 624 + 625 + #endif /* __SOC_MEDIATEK_MT8196_PM_DOMAINS_H */
+1044
drivers/pmdomain/mediatek/mtk-mfg-pmdomain.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Driver for MediaTek MFlexGraphics Devices 4 + * 5 + * Copyright (C) 2025, Collabora Ltd. 6 + */ 7 + 8 + #include <linux/completion.h> 9 + #include <linux/clk.h> 10 + #include <linux/clk-provider.h> 11 + #include <linux/container_of.h> 12 + #include <linux/iopoll.h> 13 + #include <linux/mailbox_client.h> 14 + #include <linux/module.h> 15 + #include <linux/of.h> 16 + #include <linux/of_address.h> 17 + #include <linux/of_platform.h> 18 + #include <linux/of_reserved_mem.h> 19 + #include <linux/overflow.h> 20 + #include <linux/platform_device.h> 21 + #include <linux/pm_domain.h> 22 + #include <linux/pm_opp.h> 23 + #include <linux/regulator/consumer.h> 24 + #include <linux/units.h> 25 + 26 + #define GPR_LP_STATE 0x0028 27 + #define EB_ON_SUSPEND 0x0 28 + #define EB_ON_RESUME 0x1 29 + #define GPR_IPI_MAGIC 0x34 30 + 31 + #define RPC_PWR_CON 0x0504 32 + #define PWR_ACK_M GENMASK(31, 30) 33 + #define RPC_DUMMY_REG_2 0x0658 34 + #define RPC_GHPM_CFG0_CON 0x0800 35 + #define GHPM_ENABLE_M BIT(0) 36 + #define GHPM_ON_SEQ_M BIT(2) 37 + #define RPC_GHPM_RO0_CON 0x09A4 38 + #define GHPM_STATE_M GENMASK(7, 0) 39 + #define GHPM_PWR_STATE_M BIT(16) 40 + 41 + #define GF_REG_MAGIC 0x0000 42 + #define GF_REG_GPU_OPP_IDX 0x0004 43 + #define GF_REG_STK_OPP_IDX 0x0008 44 + #define GF_REG_GPU_OPP_NUM 0x000c 45 + #define GF_REG_STK_OPP_NUM 0x0010 46 + #define GF_REG_GPU_OPP_SNUM 0x0014 47 + #define GF_REG_STK_OPP_SNUM 0x0018 48 + #define GF_REG_POWER_COUNT 0x001c 49 + #define GF_REG_BUCK_COUNT 0x0020 50 + #define GF_REG_MTCMOS_COUNT 0x0024 51 + #define GF_REG_CG_COUNT 0x0028 /* CG = Clock Gate? */ 52 + #define GF_REG_ACTIVE_COUNT 0x002C 53 + #define GF_REG_TEMP_RAW 0x0030 54 + #define GF_REG_TEMP_NORM_GPU 0x0034 55 + #define GF_REG_TEMP_HIGH_GPU 0x0038 56 + #define GF_REG_TEMP_NORM_STK 0x003C 57 + #define GF_REG_TEMP_HIGH_STK 0x0040 58 + #define GF_REG_FREQ_CUR_GPU 0x0044 59 + #define GF_REG_FREQ_CUR_STK 0x0048 60 + #define GF_REG_FREQ_OUT_GPU 0x004C /* Guess: actual achieved freq */ 61 + #define GF_REG_FREQ_OUT_STK 0x0050 /* Guess: actual achieved freq */ 62 + #define GF_REG_FREQ_METER_GPU 0x0054 /* Seems unused, always 0 */ 63 + #define GF_REG_FREQ_METER_STK 0x0058 /* Seems unused, always 0 */ 64 + #define GF_REG_VOLT_CUR_GPU 0x005C /* in tens of microvolts */ 65 + #define GF_REG_VOLT_CUR_STK 0x0060 /* in tens of microvolts */ 66 + #define GF_REG_VOLT_CUR_GPU_SRAM 0x0064 67 + #define GF_REG_VOLT_CUR_STK_SRAM 0x0068 68 + #define GF_REG_VOLT_CUR_GPU_REG 0x006C /* Seems unused, always 0 */ 69 + #define GF_REG_VOLT_CUR_STK_REG 0x0070 /* Seems unused, always 0 */ 70 + #define GF_REG_VOLT_CUR_GPU_REG_SRAM 0x0074 71 + #define GF_REG_VOLT_CUR_STK_REG_SRAM 0x0078 72 + #define GF_REG_PWR_CUR_GPU 0x007C /* in milliwatts */ 73 + #define GF_REG_PWR_CUR_STK 0x0080 /* in milliwatts */ 74 + #define GF_REG_PWR_MAX_GPU 0x0084 /* in milliwatts */ 75 + #define GF_REG_PWR_MAX_STK 0x0088 /* in milliwatts */ 76 + #define GF_REG_PWR_MIN_GPU 0x008C /* in milliwatts */ 77 + #define GF_REG_PWR_MIN_STK 0x0090 /* in milliwatts */ 78 + #define GF_REG_LEAKAGE_RT_GPU 0x0094 /* Unknown */ 79 + #define GF_REG_LEAKAGE_RT_STK 0x0098 /* Unknown */ 80 + #define GF_REG_LEAKAGE_RT_SRAM 0x009C /* Unknown */ 81 + #define GF_REG_LEAKAGE_HT_GPU 0x00A0 /* Unknown */ 82 + #define GF_REG_LEAKAGE_HT_STK 0x00A4 /* Unknown */ 83 + #define GF_REG_LEAKAGE_HT_SRAM 0x00A8 /* Unknown */ 84 + #define GF_REG_VOLT_DAC_LOW_GPU 0x00AC /* Seems unused, always 0 */ 85 + #define GF_REG_VOLT_DAC_LOW_STK 0x00B0 /* Seems unused, always 0 */ 86 + #define GF_REG_OPP_CUR_CEIL 0x00B4 87 + #define GF_REG_OPP_CUR_FLOOR 0x00B8 88 + #define GF_REG_OPP_CUR_LIMITER_CEIL 0x00BC 89 + #define GF_REG_OPP_CUR_LIMITER_FLOOR 0x00C0 90 + #define GF_REG_OPP_PRIORITY_CEIL 0x00C4 91 + #define GF_REG_OPP_PRIORITY_FLOOR 0x00C8 92 + #define GF_REG_PWR_CTL 0x00CC 93 + #define GF_REG_ACTIVE_SLEEP_CTL 0x00D0 94 + #define GF_REG_DVFS_STATE 0x00D4 95 + #define GF_REG_SHADER_PRESENT 0x00D8 96 + #define GF_REG_ASENSOR_ENABLE 0x00DC 97 + #define GF_REG_AGING_LOAD 0x00E0 98 + #define GF_REG_AGING_MARGIN 0x00E4 99 + #define GF_REG_AVS_ENABLE 0x00E8 100 + #define GF_REG_AVS_MARGIN 0x00EC 101 + #define GF_REG_CHIP_TYPE 0x00F0 102 + #define GF_REG_SB_VERSION 0x00F4 103 + #define GF_REG_PTP_VERSION 0x00F8 104 + #define GF_REG_DBG_VERSION 0x00FC 105 + #define GF_REG_KDBG_VERSION 0x0100 106 + #define GF_REG_GPM1_MODE 0x0104 107 + #define GF_REG_GPM3_MODE 0x0108 108 + #define GF_REG_DFD_MODE 0x010C 109 + #define GF_REG_DUAL_BUCK 0x0110 110 + #define GF_REG_SEGMENT_ID 0x0114 111 + #define GF_REG_POWER_TIME_H 0x0118 112 + #define GF_REG_POWER_TIME_L 0x011C 113 + #define GF_REG_PWR_STATUS 0x0120 114 + #define GF_REG_STRESS_TEST 0x0124 115 + #define GF_REG_TEST_MODE 0x0128 116 + #define GF_REG_IPS_MODE 0x012C 117 + #define GF_REG_TEMP_COMP_MODE 0x0130 118 + #define GF_REG_HT_TEMP_COMP_MODE 0x0134 119 + #define GF_REG_PWR_TRACKER_MODE 0x0138 120 + #define GF_REG_OPP_TABLE_GPU 0x0314 121 + #define GF_REG_OPP_TABLE_STK 0x09A4 122 + #define GF_REG_OPP_TABLE_GPU_S 0x1034 123 + #define GF_REG_OPP_TABLE_STK_S 0x16c4 124 + #define GF_REG_LIMIT_TABLE 0x1d54 125 + #define GF_REG_GPM3_TABLE 0x223C 126 + 127 + #define MFG_MT8196_E2_ID 0x101 128 + #define GPUEB_SLEEP_MAGIC 0x55667788UL 129 + #define GPUEB_MEM_MAGIC 0xBABADADAUL 130 + 131 + #define GPUEB_TIMEOUT_US 10000UL 132 + #define GPUEB_POLL_US 50 133 + 134 + #define MAX_OPP_NUM 70 135 + 136 + #define GPUEB_MBOX_MAX_RX_SIZE 32 /* in bytes */ 137 + 138 + /* 139 + * This enum is part of the ABI of the GPUEB firmware. Don't change the 140 + * numbering, as you would wreak havoc. 141 + */ 142 + enum mtk_mfg_ipi_cmd { 143 + CMD_INIT_SHARED_MEM = 0, 144 + CMD_GET_FREQ_BY_IDX = 1, 145 + CMD_GET_POWER_BY_IDX = 2, 146 + CMD_GET_OPPIDX_BY_FREQ = 3, 147 + CMD_GET_LEAKAGE_POWER = 4, 148 + CMD_SET_LIMIT = 5, 149 + CMD_POWER_CONTROL = 6, 150 + CMD_ACTIVE_SLEEP_CONTROL = 7, 151 + CMD_COMMIT = 8, 152 + CMD_DUAL_COMMIT = 9, 153 + CMD_PDCA_CONFIG = 10, 154 + CMD_UPDATE_DEBUG_OPP_INFO = 11, 155 + CMD_SWITCH_LIMIT = 12, 156 + CMD_FIX_TARGET_OPPIDX = 13, 157 + CMD_FIX_DUAL_TARGET_OPPIDX = 14, 158 + CMD_FIX_CUSTOM_FREQ_VOLT = 15, 159 + CMD_FIX_DUAL_CUSTOM_FREQ_VOLT = 16, 160 + CMD_SET_MFGSYS_CONFIG = 17, 161 + CMD_MSSV_COMMIT = 18, 162 + CMD_NUM = 19, 163 + }; 164 + 165 + /* 166 + * This struct is part of the ABI of the GPUEB firmware. Changing it, or 167 + * reordering fields in it, will break things, so don't do it. Thank you. 168 + */ 169 + struct __packed mtk_mfg_ipi_msg { 170 + __le32 magic; 171 + __le32 cmd; 172 + __le32 target; 173 + /* 174 + * Downstream relies on the compiler to implicitly add the following 175 + * padding, as it declares the struct as non-packed. 176 + */ 177 + __le32 reserved; 178 + union { 179 + s32 __bitwise oppidx; 180 + s32 __bitwise return_value; 181 + __le32 freq; 182 + __le32 volt; 183 + __le32 power; 184 + __le32 power_state; 185 + __le32 mode; 186 + __le32 value; 187 + struct { 188 + __le64 base; 189 + __le32 size; 190 + } shared_mem; 191 + struct { 192 + __le32 freq; 193 + __le32 volt; 194 + } custom; 195 + struct { 196 + __le32 limiter; 197 + s32 __bitwise ceiling_info; 198 + s32 __bitwise floor_info; 199 + } set_limit; 200 + struct { 201 + __le32 target; 202 + __le32 val; 203 + } mfg_cfg; 204 + struct { 205 + __le32 target; 206 + __le32 val; 207 + } mssv; 208 + struct { 209 + s32 __bitwise gpu_oppidx; 210 + s32 __bitwise stack_oppidx; 211 + } dual_commit; 212 + struct { 213 + __le32 fgpu; 214 + __le32 vgpu; 215 + __le32 fstack; 216 + __le32 vstack; 217 + } dual_custom; 218 + } u; 219 + }; 220 + 221 + struct __packed mtk_mfg_ipi_sleep_msg { 222 + __le32 event; 223 + __le32 state; 224 + __le32 magic; 225 + }; 226 + 227 + /** 228 + * struct mtk_mfg_opp_entry - OPP table entry from firmware 229 + * @freq_khz: The operating point's frequency in kilohertz 230 + * @voltage_core: The operating point's core voltage in tens of microvolts 231 + * @voltage_sram: The operating point's SRAM voltage in tens of microvolts 232 + * @posdiv: exponent of base 2 for PLL frequency divisor used for this OPP 233 + * @voltage_margin: Number of tens of microvolts the voltage can be undershot 234 + * @power_mw: estimate of power usage at this operating point, in milliwatts 235 + * 236 + * This struct is part of the ABI with the EB firmware. Do not change it. 237 + */ 238 + struct __packed mtk_mfg_opp_entry { 239 + __le32 freq_khz; 240 + __le32 voltage_core; 241 + __le32 voltage_sram; 242 + __le32 posdiv; 243 + __le32 voltage_margin; 244 + __le32 power_mw; 245 + }; 246 + 247 + struct mtk_mfg_mbox { 248 + struct mbox_client cl; 249 + struct completion rx_done; 250 + struct mtk_mfg *mfg; 251 + struct mbox_chan *ch; 252 + void *rx_data; 253 + }; 254 + 255 + struct mtk_mfg { 256 + struct generic_pm_domain pd; 257 + struct platform_device *pdev; 258 + struct clk *clk_eb; 259 + struct clk_bulk_data *gpu_clks; 260 + struct clk_hw clk_core_hw; 261 + struct clk_hw clk_stack_hw; 262 + struct regulator_bulk_data *gpu_regs; 263 + void __iomem *rpc; 264 + void __iomem *gpr; 265 + void __iomem *shared_mem; 266 + phys_addr_t shared_mem_phys; 267 + unsigned int shared_mem_size; 268 + u16 ghpm_en_reg; 269 + u32 ipi_magic; 270 + unsigned short num_gpu_opps; 271 + unsigned short num_stack_opps; 272 + struct dev_pm_opp_data *gpu_opps; 273 + struct dev_pm_opp_data *stack_opps; 274 + struct mtk_mfg_mbox *gf_mbox; 275 + struct mtk_mfg_mbox *slp_mbox; 276 + const struct mtk_mfg_variant *variant; 277 + }; 278 + 279 + struct mtk_mfg_variant { 280 + const char *const *clk_names; 281 + unsigned int num_clks; 282 + const char *const *regulator_names; 283 + unsigned int num_regulators; 284 + /** @turbo_below: opp indices below this value are considered turbo */ 285 + unsigned int turbo_below; 286 + int (*init)(struct mtk_mfg *mfg); 287 + }; 288 + 289 + static inline struct mtk_mfg *mtk_mfg_from_genpd(struct generic_pm_domain *pd) 290 + { 291 + return container_of(pd, struct mtk_mfg, pd); 292 + } 293 + 294 + static inline void mtk_mfg_update_reg_bits(void __iomem *addr, u32 mask, u32 val) 295 + { 296 + writel((readl(addr) & ~mask) | (val & mask), addr); 297 + } 298 + 299 + static inline bool mtk_mfg_is_powered_on(struct mtk_mfg *mfg) 300 + { 301 + return (readl(mfg->rpc + RPC_PWR_CON) & PWR_ACK_M) == PWR_ACK_M; 302 + } 303 + 304 + static unsigned long mtk_mfg_recalc_rate_gpu(struct clk_hw *hw, 305 + unsigned long parent_rate) 306 + { 307 + struct mtk_mfg *mfg = container_of(hw, struct mtk_mfg, clk_core_hw); 308 + 309 + return readl(mfg->shared_mem + GF_REG_FREQ_OUT_GPU) * HZ_PER_KHZ; 310 + } 311 + 312 + static int mtk_mfg_determine_rate(struct clk_hw *hw, 313 + struct clk_rate_request *req) 314 + { 315 + /* 316 + * The determine_rate callback needs to be implemented to avoid returning 317 + * the current clock frequency, rather than something even remotely 318 + * close to the frequency that was asked for. 319 + * 320 + * Instead of writing considerable amounts of possibly slow code just to 321 + * somehow figure out which of the three PLLs to round for, or even to 322 + * do a search through one of two OPP tables in order to find the closest 323 + * OPP of a frequency, just return the rate as-is. This avoids devfreq 324 + * "rounding" a request for the lowest frequency to the possibly very 325 + * high current frequency, breaking the powersave governor in the process. 326 + */ 327 + 328 + return 0; 329 + } 330 + 331 + static unsigned long mtk_mfg_recalc_rate_stack(struct clk_hw *hw, 332 + unsigned long parent_rate) 333 + { 334 + struct mtk_mfg *mfg = container_of(hw, struct mtk_mfg, clk_stack_hw); 335 + 336 + return readl(mfg->shared_mem + GF_REG_FREQ_OUT_STK) * HZ_PER_KHZ; 337 + } 338 + 339 + static const struct clk_ops mtk_mfg_clk_gpu_ops = { 340 + .recalc_rate = mtk_mfg_recalc_rate_gpu, 341 + .determine_rate = mtk_mfg_determine_rate, 342 + }; 343 + 344 + static const struct clk_ops mtk_mfg_clk_stack_ops = { 345 + .recalc_rate = mtk_mfg_recalc_rate_stack, 346 + .determine_rate = mtk_mfg_determine_rate, 347 + }; 348 + 349 + static const struct clk_init_data mtk_mfg_clk_gpu_init = { 350 + .name = "gpu-core", 351 + .ops = &mtk_mfg_clk_gpu_ops, 352 + .flags = CLK_GET_RATE_NOCACHE, 353 + }; 354 + 355 + static const struct clk_init_data mtk_mfg_clk_stack_init = { 356 + .name = "gpu-stack", 357 + .ops = &mtk_mfg_clk_stack_ops, 358 + .flags = CLK_GET_RATE_NOCACHE, 359 + }; 360 + 361 + static int mtk_mfg_eb_on(struct mtk_mfg *mfg) 362 + { 363 + struct device *dev = &mfg->pdev->dev; 364 + u32 val; 365 + int ret; 366 + 367 + /* 368 + * If MFG is already on from e.g. the bootloader, skip doing the 369 + * power-on sequence, as it wouldn't work without powering it off first. 370 + */ 371 + if (mtk_mfg_is_powered_on(mfg)) 372 + return 0; 373 + 374 + ret = readl_poll_timeout(mfg->rpc + RPC_GHPM_RO0_CON, val, 375 + !(val & (GHPM_PWR_STATE_M | GHPM_STATE_M)), 376 + GPUEB_POLL_US, GPUEB_TIMEOUT_US); 377 + if (ret) { 378 + dev_err(dev, "timed out waiting for EB to power on\n"); 379 + return ret; 380 + } 381 + 382 + mtk_mfg_update_reg_bits(mfg->rpc + mfg->ghpm_en_reg, GHPM_ENABLE_M, 383 + GHPM_ENABLE_M); 384 + 385 + mtk_mfg_update_reg_bits(mfg->rpc + RPC_GHPM_CFG0_CON, GHPM_ON_SEQ_M, 0); 386 + mtk_mfg_update_reg_bits(mfg->rpc + RPC_GHPM_CFG0_CON, GHPM_ON_SEQ_M, 387 + GHPM_ON_SEQ_M); 388 + 389 + mtk_mfg_update_reg_bits(mfg->rpc + mfg->ghpm_en_reg, GHPM_ENABLE_M, 0); 390 + 391 + 392 + ret = readl_poll_timeout(mfg->rpc + RPC_PWR_CON, val, 393 + (val & PWR_ACK_M) == PWR_ACK_M, 394 + GPUEB_POLL_US, GPUEB_TIMEOUT_US); 395 + if (ret) { 396 + dev_err(dev, "timed out waiting for EB power ack, val = 0x%X\n", 397 + val); 398 + return ret; 399 + } 400 + 401 + ret = readl_poll_timeout(mfg->gpr + GPR_LP_STATE, val, 402 + (val == EB_ON_RESUME), 403 + GPUEB_POLL_US, GPUEB_TIMEOUT_US); 404 + if (ret) { 405 + dev_err(dev, "timed out waiting for EB to resume, status = 0x%X\n", val); 406 + return ret; 407 + } 408 + 409 + return 0; 410 + } 411 + 412 + static int mtk_mfg_eb_off(struct mtk_mfg *mfg) 413 + { 414 + struct device *dev = &mfg->pdev->dev; 415 + struct mtk_mfg_ipi_sleep_msg msg = { 416 + .event = 0, 417 + .state = 0, 418 + .magic = GPUEB_SLEEP_MAGIC 419 + }; 420 + u32 val; 421 + int ret; 422 + 423 + ret = mbox_send_message(mfg->slp_mbox->ch, &msg); 424 + if (ret < 0) { 425 + dev_err(dev, "Cannot send sleep command: %pe\n", ERR_PTR(ret)); 426 + return ret; 427 + } 428 + 429 + ret = readl_poll_timeout(mfg->rpc + RPC_PWR_CON, val, 430 + !(val & PWR_ACK_M), GPUEB_POLL_US, 431 + GPUEB_TIMEOUT_US); 432 + 433 + if (ret) { 434 + dev_err(dev, "Timed out waiting for EB to power off, val=0x%08X\n", val); 435 + return ret; 436 + } 437 + 438 + return 0; 439 + } 440 + 441 + /** 442 + * mtk_mfg_send_ipi - synchronously send an IPI message on the gpufreq channel 443 + * @mfg: pointer to this driver instance's private &struct mtk_mfg 444 + * @msg: pointer to a message to send; will have magic filled and response assigned 445 + * 446 + * Send an IPI message on the gpufreq channel, and wait for a response. Once a 447 + * response is received, assign a pointer to the response buffer (valid until 448 + * next response is received) to @msg. 449 + * 450 + * Returns 0 on success, negative errno on failure. 451 + */ 452 + static int mtk_mfg_send_ipi(struct mtk_mfg *mfg, struct mtk_mfg_ipi_msg *msg) 453 + { 454 + struct device *dev = &mfg->pdev->dev; 455 + unsigned long wait; 456 + int ret; 457 + 458 + msg->magic = mfg->ipi_magic; 459 + 460 + ret = mbox_send_message(mfg->gf_mbox->ch, msg); 461 + if (ret < 0) { 462 + dev_err(dev, "Cannot send GPUFreq IPI command: %pe\n", ERR_PTR(ret)); 463 + return ret; 464 + } 465 + 466 + wait = wait_for_completion_timeout(&mfg->gf_mbox->rx_done, msecs_to_jiffies(500)); 467 + if (!wait) 468 + return -ETIMEDOUT; 469 + 470 + msg = mfg->gf_mbox->rx_data; 471 + 472 + if (msg->u.return_value < 0) { 473 + dev_err(dev, "IPI return: %d\n", msg->u.return_value); 474 + return -EPROTO; 475 + } 476 + 477 + return 0; 478 + } 479 + 480 + static int mtk_mfg_init_shared_mem(struct mtk_mfg *mfg) 481 + { 482 + struct device *dev = &mfg->pdev->dev; 483 + struct mtk_mfg_ipi_msg msg = {}; 484 + int ret; 485 + 486 + dev_dbg(dev, "clearing GPUEB shared memory, 0x%X bytes\n", mfg->shared_mem_size); 487 + memset_io(mfg->shared_mem, 0, mfg->shared_mem_size); 488 + 489 + msg.cmd = CMD_INIT_SHARED_MEM; 490 + msg.u.shared_mem.base = mfg->shared_mem_phys; 491 + msg.u.shared_mem.size = mfg->shared_mem_size; 492 + 493 + ret = mtk_mfg_send_ipi(mfg, &msg); 494 + if (ret) 495 + return ret; 496 + 497 + if (readl(mfg->shared_mem + GF_REG_MAGIC) != GPUEB_MEM_MAGIC) { 498 + dev_err(dev, "EB did not initialise shared memory correctly\n"); 499 + return -EIO; 500 + } 501 + 502 + return 0; 503 + } 504 + 505 + static int mtk_mfg_power_control(struct mtk_mfg *mfg, bool enabled) 506 + { 507 + struct mtk_mfg_ipi_msg msg = {}; 508 + 509 + msg.cmd = CMD_POWER_CONTROL; 510 + msg.u.power_state = enabled ? 1 : 0; 511 + 512 + return mtk_mfg_send_ipi(mfg, &msg); 513 + } 514 + 515 + static int mtk_mfg_set_oppidx(struct mtk_mfg *mfg, unsigned int opp_idx) 516 + { 517 + struct mtk_mfg_ipi_msg msg = {}; 518 + int ret; 519 + 520 + if (opp_idx >= mfg->num_gpu_opps) 521 + return -EINVAL; 522 + 523 + msg.cmd = CMD_FIX_DUAL_TARGET_OPPIDX; 524 + msg.u.dual_commit.gpu_oppidx = opp_idx; 525 + msg.u.dual_commit.stack_oppidx = opp_idx; 526 + 527 + ret = mtk_mfg_send_ipi(mfg, &msg); 528 + if (ret) { 529 + dev_err(&mfg->pdev->dev, "Failed to set OPP %u: %pe\n", 530 + opp_idx, ERR_PTR(ret)); 531 + return ret; 532 + } 533 + 534 + return 0; 535 + } 536 + 537 + static int mtk_mfg_read_opp_tables(struct mtk_mfg *mfg) 538 + { 539 + struct device *dev = &mfg->pdev->dev; 540 + struct mtk_mfg_opp_entry e = {}; 541 + unsigned int i; 542 + 543 + mfg->num_gpu_opps = readl(mfg->shared_mem + GF_REG_GPU_OPP_NUM); 544 + mfg->num_stack_opps = readl(mfg->shared_mem + GF_REG_STK_OPP_NUM); 545 + 546 + if (mfg->num_gpu_opps > MAX_OPP_NUM || mfg->num_gpu_opps == 0) { 547 + dev_err(dev, "GPU OPP count (%u) out of range %u >= count > 0\n", 548 + mfg->num_gpu_opps, MAX_OPP_NUM); 549 + return -EINVAL; 550 + } 551 + 552 + if (mfg->num_stack_opps && mfg->num_stack_opps > MAX_OPP_NUM) { 553 + dev_err(dev, "Stack OPP count (%u) out of range %u >= count >= 0\n", 554 + mfg->num_stack_opps, MAX_OPP_NUM); 555 + return -EINVAL; 556 + } 557 + 558 + mfg->gpu_opps = devm_kcalloc(dev, mfg->num_gpu_opps, 559 + sizeof(struct dev_pm_opp_data), GFP_KERNEL); 560 + if (!mfg->gpu_opps) 561 + return -ENOMEM; 562 + 563 + if (mfg->num_stack_opps) { 564 + mfg->stack_opps = devm_kcalloc(dev, mfg->num_stack_opps, 565 + sizeof(struct dev_pm_opp_data), GFP_KERNEL); 566 + if (!mfg->stack_opps) 567 + return -ENOMEM; 568 + } 569 + 570 + for (i = 0; i < mfg->num_gpu_opps; i++) { 571 + memcpy_fromio(&e, mfg->shared_mem + GF_REG_OPP_TABLE_GPU + i * sizeof(e), 572 + sizeof(e)); 573 + if (mem_is_zero(&e, sizeof(e))) { 574 + dev_err(dev, "ran into an empty GPU OPP at index %u\n", 575 + i); 576 + return -EINVAL; 577 + } 578 + mfg->gpu_opps[i].freq = e.freq_khz * HZ_PER_KHZ; 579 + mfg->gpu_opps[i].u_volt = e.voltage_core * 10; 580 + mfg->gpu_opps[i].level = i; 581 + if (i < mfg->variant->turbo_below) 582 + mfg->gpu_opps[i].turbo = true; 583 + } 584 + 585 + for (i = 0; i < mfg->num_stack_opps; i++) { 586 + memcpy_fromio(&e, mfg->shared_mem + GF_REG_OPP_TABLE_STK + i * sizeof(e), 587 + sizeof(e)); 588 + if (mem_is_zero(&e, sizeof(e))) { 589 + dev_err(dev, "ran into an empty Stack OPP at index %u\n", 590 + i); 591 + return -EINVAL; 592 + } 593 + mfg->stack_opps[i].freq = e.freq_khz * HZ_PER_KHZ; 594 + mfg->stack_opps[i].u_volt = e.voltage_core * 10; 595 + mfg->stack_opps[i].level = i; 596 + if (i < mfg->variant->turbo_below) 597 + mfg->stack_opps[i].turbo = true; 598 + } 599 + 600 + return 0; 601 + } 602 + 603 + static const char *const mtk_mfg_mt8196_clk_names[] = { 604 + "core", 605 + "stack0", 606 + "stack1", 607 + }; 608 + 609 + static const char *const mtk_mfg_mt8196_regulators[] = { 610 + "core", 611 + "stack", 612 + "sram", 613 + }; 614 + 615 + static int mtk_mfg_mt8196_init(struct mtk_mfg *mfg) 616 + { 617 + void __iomem *e2_base; 618 + 619 + e2_base = devm_platform_ioremap_resource_byname(mfg->pdev, "hw-revision"); 620 + if (IS_ERR(e2_base)) 621 + return dev_err_probe(&mfg->pdev->dev, PTR_ERR(e2_base), 622 + "Couldn't get hw-revision register\n"); 623 + 624 + clk_prepare_enable(mfg->clk_eb); 625 + 626 + if (readl(e2_base) == MFG_MT8196_E2_ID) 627 + mfg->ghpm_en_reg = RPC_DUMMY_REG_2; 628 + else 629 + mfg->ghpm_en_reg = RPC_GHPM_CFG0_CON; 630 + 631 + clk_disable_unprepare(mfg->clk_eb); 632 + 633 + return 0; 634 + } 635 + 636 + static const struct mtk_mfg_variant mtk_mfg_mt8196_variant = { 637 + .clk_names = mtk_mfg_mt8196_clk_names, 638 + .num_clks = ARRAY_SIZE(mtk_mfg_mt8196_clk_names), 639 + .regulator_names = mtk_mfg_mt8196_regulators, 640 + .num_regulators = ARRAY_SIZE(mtk_mfg_mt8196_regulators), 641 + .turbo_below = 7, 642 + .init = mtk_mfg_mt8196_init, 643 + }; 644 + 645 + static void mtk_mfg_mbox_rx_callback(struct mbox_client *cl, void *mssg) 646 + { 647 + struct mtk_mfg_mbox *mb = container_of(cl, struct mtk_mfg_mbox, cl); 648 + 649 + if (mb->rx_data) 650 + mb->rx_data = memcpy(mb->rx_data, mssg, GPUEB_MBOX_MAX_RX_SIZE); 651 + complete(&mb->rx_done); 652 + } 653 + 654 + static int mtk_mfg_attach_dev(struct generic_pm_domain *pd, struct device *dev) 655 + { 656 + struct mtk_mfg *mfg = mtk_mfg_from_genpd(pd); 657 + struct dev_pm_opp_data *so = mfg->stack_opps; 658 + struct dev_pm_opp_data *go = mfg->gpu_opps; 659 + struct dev_pm_opp_data *prev_o; 660 + struct dev_pm_opp_data *o; 661 + int i, ret; 662 + 663 + for (i = mfg->num_gpu_opps - 1; i >= 0; i--) { 664 + /* 665 + * Adding the lower of the two OPPs avoids gaps of indices in 666 + * situations where the GPU OPPs are duplicated a couple of 667 + * times when only the Stack OPP is being lowered at that index. 668 + */ 669 + if (i >= mfg->num_stack_opps || go[i].freq < so[i].freq) 670 + o = &go[i]; 671 + else 672 + o = &so[i]; 673 + 674 + /* 675 + * Skip indices where both GPU and Stack OPPs are equal. Nominally, 676 + * OPP core shouldn't care about dupes, but not doing so will cause 677 + * dev_pm_opp_find_freq_ceil_indexed to -ERANGE later down the line. 678 + */ 679 + if (prev_o && prev_o->freq == o->freq) 680 + continue; 681 + 682 + ret = dev_pm_opp_add_dynamic(dev, o); 683 + if (ret) { 684 + dev_err(dev, "Failed to add OPP level %u from PD %s: %pe\n", 685 + o->level, pd->name, ERR_PTR(ret)); 686 + dev_pm_opp_remove_all_dynamic(dev); 687 + return ret; 688 + } 689 + prev_o = o; 690 + } 691 + 692 + return 0; 693 + } 694 + 695 + static void mtk_mfg_detach_dev(struct generic_pm_domain *pd, struct device *dev) 696 + { 697 + dev_pm_opp_remove_all_dynamic(dev); 698 + } 699 + 700 + static int mtk_mfg_set_performance(struct generic_pm_domain *pd, 701 + unsigned int state) 702 + { 703 + struct mtk_mfg *mfg = mtk_mfg_from_genpd(pd); 704 + 705 + /* 706 + * pmdomain core intentionally sets a performance state before turning 707 + * a domain on, and after turning it off. For the GPUEB however, it's 708 + * only possible to act on performance requests when the GPUEB is 709 + * powered on. To do this, return cleanly without taking action, and 710 + * defer setting what pmdomain core set in mtk_mfg_power_on. 711 + */ 712 + if (mfg->pd.status != GENPD_STATE_ON) 713 + return 0; 714 + 715 + return mtk_mfg_set_oppidx(mfg, state); 716 + } 717 + 718 + static int mtk_mfg_power_on(struct generic_pm_domain *pd) 719 + { 720 + struct mtk_mfg *mfg = mtk_mfg_from_genpd(pd); 721 + int ret; 722 + 723 + ret = regulator_bulk_enable(mfg->variant->num_regulators, 724 + mfg->gpu_regs); 725 + if (ret) 726 + return ret; 727 + 728 + ret = clk_prepare_enable(mfg->clk_eb); 729 + if (ret) 730 + goto err_disable_regulators; 731 + 732 + ret = clk_bulk_prepare_enable(mfg->variant->num_clks, mfg->gpu_clks); 733 + if (ret) 734 + goto err_disable_eb_clk; 735 + 736 + ret = mtk_mfg_eb_on(mfg); 737 + if (ret) 738 + goto err_disable_clks; 739 + 740 + mfg->ipi_magic = readl(mfg->gpr + GPR_IPI_MAGIC); 741 + 742 + ret = mtk_mfg_power_control(mfg, true); 743 + if (ret) 744 + goto err_eb_off; 745 + 746 + /* Don't try to set a OPP in probe before OPPs have been read from EB */ 747 + if (mfg->gpu_opps) { 748 + /* The aforementioned deferred setting of pmdomain's state */ 749 + ret = mtk_mfg_set_oppidx(mfg, pd->performance_state); 750 + if (ret) 751 + dev_warn(&mfg->pdev->dev, "Failed to set oppidx in %s\n", __func__); 752 + } 753 + 754 + return 0; 755 + 756 + err_eb_off: 757 + mtk_mfg_eb_off(mfg); 758 + err_disable_clks: 759 + clk_bulk_disable_unprepare(mfg->variant->num_clks, mfg->gpu_clks); 760 + err_disable_eb_clk: 761 + clk_disable_unprepare(mfg->clk_eb); 762 + err_disable_regulators: 763 + regulator_bulk_disable(mfg->variant->num_regulators, mfg->gpu_regs); 764 + 765 + return ret; 766 + } 767 + 768 + static int mtk_mfg_power_off(struct generic_pm_domain *pd) 769 + { 770 + struct mtk_mfg *mfg = mtk_mfg_from_genpd(pd); 771 + struct device *dev = &mfg->pdev->dev; 772 + int ret; 773 + 774 + ret = mtk_mfg_power_control(mfg, false); 775 + if (ret) { 776 + dev_err(dev, "power_control failed: %pe\n", ERR_PTR(ret)); 777 + return ret; 778 + } 779 + 780 + ret = mtk_mfg_eb_off(mfg); 781 + if (ret) { 782 + dev_err(dev, "eb_off failed: %pe\n", ERR_PTR(ret)); 783 + return ret; 784 + } 785 + 786 + clk_bulk_disable_unprepare(mfg->variant->num_clks, mfg->gpu_clks); 787 + clk_disable_unprepare(mfg->clk_eb); 788 + ret = regulator_bulk_disable(mfg->variant->num_regulators, mfg->gpu_regs); 789 + if (ret) { 790 + dev_err(dev, "Disabling regulators failed: %pe\n", ERR_PTR(ret)); 791 + return ret; 792 + } 793 + 794 + return 0; 795 + } 796 + 797 + static int mtk_mfg_init_mbox(struct mtk_mfg *mfg) 798 + { 799 + struct device *dev = &mfg->pdev->dev; 800 + struct mtk_mfg_mbox *gf; 801 + struct mtk_mfg_mbox *slp; 802 + 803 + gf = devm_kzalloc(dev, sizeof(*gf), GFP_KERNEL); 804 + if (!gf) 805 + return -ENOMEM; 806 + 807 + gf->rx_data = devm_kzalloc(dev, GPUEB_MBOX_MAX_RX_SIZE, GFP_KERNEL); 808 + if (!gf->rx_data) 809 + return -ENOMEM; 810 + 811 + gf->mfg = mfg; 812 + init_completion(&gf->rx_done); 813 + gf->cl.dev = dev; 814 + gf->cl.rx_callback = mtk_mfg_mbox_rx_callback; 815 + gf->cl.tx_tout = GPUEB_TIMEOUT_US / USEC_PER_MSEC; 816 + gf->ch = mbox_request_channel_byname(&gf->cl, "gpufreq"); 817 + if (IS_ERR(gf->ch)) 818 + return PTR_ERR(gf->ch); 819 + 820 + mfg->gf_mbox = gf; 821 + 822 + slp = devm_kzalloc(dev, sizeof(*slp), GFP_KERNEL); 823 + if (!slp) 824 + return -ENOMEM; 825 + 826 + slp->mfg = mfg; 827 + init_completion(&slp->rx_done); 828 + slp->cl.dev = dev; 829 + slp->cl.tx_tout = GPUEB_TIMEOUT_US / USEC_PER_MSEC; 830 + slp->cl.tx_block = true; 831 + slp->ch = mbox_request_channel_byname(&slp->cl, "sleep"); 832 + if (IS_ERR(slp->ch)) { 833 + mbox_free_channel(gf->ch); 834 + return PTR_ERR(slp->ch); 835 + } 836 + 837 + mfg->slp_mbox = slp; 838 + 839 + return 0; 840 + } 841 + 842 + static int mtk_mfg_init_clk_provider(struct mtk_mfg *mfg) 843 + { 844 + struct device *dev = &mfg->pdev->dev; 845 + struct clk_hw_onecell_data *clk_data; 846 + int ret; 847 + 848 + clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, 2), GFP_KERNEL); 849 + if (!clk_data) 850 + return -ENOMEM; 851 + 852 + clk_data->num = 2; 853 + 854 + mfg->clk_core_hw.init = &mtk_mfg_clk_gpu_init; 855 + mfg->clk_stack_hw.init = &mtk_mfg_clk_stack_init; 856 + 857 + ret = devm_clk_hw_register(dev, &mfg->clk_core_hw); 858 + if (ret) 859 + return dev_err_probe(dev, ret, "Couldn't register GPU core clock\n"); 860 + 861 + ret = devm_clk_hw_register(dev, &mfg->clk_stack_hw); 862 + if (ret) 863 + return dev_err_probe(dev, ret, "Couldn't register GPU stack clock\n"); 864 + 865 + clk_data->hws[0] = &mfg->clk_core_hw; 866 + clk_data->hws[1] = &mfg->clk_stack_hw; 867 + 868 + ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data); 869 + if (ret) 870 + return dev_err_probe(dev, ret, "Couldn't register clock provider\n"); 871 + 872 + return 0; 873 + } 874 + 875 + static int mtk_mfg_probe(struct platform_device *pdev) 876 + { 877 + struct mtk_mfg *mfg; 878 + struct device *dev = &pdev->dev; 879 + const struct mtk_mfg_variant *data = of_device_get_match_data(dev); 880 + struct resource res; 881 + int ret, i; 882 + 883 + mfg = devm_kzalloc(dev, sizeof(*mfg), GFP_KERNEL); 884 + if (!mfg) 885 + return -ENOMEM; 886 + 887 + mfg->pdev = pdev; 888 + mfg->variant = data; 889 + 890 + dev_set_drvdata(dev, mfg); 891 + 892 + mfg->gpr = devm_platform_ioremap_resource(pdev, 0); 893 + if (IS_ERR(mfg->gpr)) 894 + return dev_err_probe(dev, PTR_ERR(mfg->gpr), 895 + "Couldn't retrieve GPR MMIO registers\n"); 896 + 897 + mfg->rpc = devm_platform_ioremap_resource(pdev, 1); 898 + if (IS_ERR(mfg->rpc)) 899 + return dev_err_probe(dev, PTR_ERR(mfg->rpc), 900 + "Couldn't retrieve RPC MMIO registers\n"); 901 + 902 + mfg->clk_eb = devm_clk_get(dev, "eb"); 903 + if (IS_ERR(mfg->clk_eb)) 904 + return dev_err_probe(dev, PTR_ERR(mfg->clk_eb), 905 + "Couldn't get 'eb' clock\n"); 906 + 907 + mfg->gpu_clks = devm_kcalloc(dev, data->num_clks, sizeof(*mfg->gpu_clks), 908 + GFP_KERNEL); 909 + if (!mfg->gpu_clks) 910 + return -ENOMEM; 911 + 912 + for (i = 0; i < data->num_clks; i++) 913 + mfg->gpu_clks[i].id = data->clk_names[i]; 914 + 915 + ret = devm_clk_bulk_get(dev, data->num_clks, mfg->gpu_clks); 916 + if (ret) 917 + return dev_err_probe(dev, ret, "Couldn't get GPU clocks\n"); 918 + 919 + mfg->gpu_regs = devm_kcalloc(dev, data->num_regulators, 920 + sizeof(*mfg->gpu_regs), GFP_KERNEL); 921 + if (!mfg->gpu_regs) 922 + return -ENOMEM; 923 + 924 + for (i = 0; i < data->num_regulators; i++) 925 + mfg->gpu_regs[i].supply = data->regulator_names[i]; 926 + 927 + ret = devm_regulator_bulk_get(dev, data->num_regulators, mfg->gpu_regs); 928 + if (ret) 929 + return dev_err_probe(dev, ret, "Couldn't get GPU regulators\n"); 930 + 931 + ret = of_reserved_mem_region_to_resource(dev->of_node, 0, &res); 932 + if (ret) 933 + return dev_err_probe(dev, ret, "Couldn't get GPUEB shared memory\n"); 934 + 935 + mfg->shared_mem = devm_ioremap(dev, res.start, resource_size(&res)); 936 + if (!mfg->shared_mem) 937 + return dev_err_probe(dev, -ENOMEM, "Can't ioremap GPUEB shared memory\n"); 938 + mfg->shared_mem_size = resource_size(&res); 939 + mfg->shared_mem_phys = res.start; 940 + 941 + if (data->init) { 942 + ret = data->init(mfg); 943 + if (ret) 944 + return dev_err_probe(dev, ret, "Variant init failed\n"); 945 + } 946 + 947 + mfg->pd.name = dev_name(dev); 948 + mfg->pd.attach_dev = mtk_mfg_attach_dev; 949 + mfg->pd.detach_dev = mtk_mfg_detach_dev; 950 + mfg->pd.power_off = mtk_mfg_power_off; 951 + mfg->pd.power_on = mtk_mfg_power_on; 952 + mfg->pd.set_performance_state = mtk_mfg_set_performance; 953 + mfg->pd.flags = GENPD_FLAG_OPP_TABLE_FW; 954 + 955 + ret = pm_genpd_init(&mfg->pd, NULL, false); 956 + if (ret) 957 + return dev_err_probe(dev, ret, "Failed to initialise power domain\n"); 958 + 959 + ret = mtk_mfg_init_mbox(mfg); 960 + if (ret) { 961 + dev_err_probe(dev, ret, "Couldn't initialise mailbox\n"); 962 + goto err_remove_genpd; 963 + } 964 + 965 + ret = mtk_mfg_power_on(&mfg->pd); 966 + if (ret) { 967 + dev_err_probe(dev, ret, "Failed to power on MFG\n"); 968 + goto err_free_mbox; 969 + } 970 + 971 + ret = mtk_mfg_init_shared_mem(mfg); 972 + if (ret) { 973 + dev_err_probe(dev, ret, "Couldn't initialize EB shared memory\n"); 974 + goto err_power_off; 975 + } 976 + 977 + ret = mtk_mfg_read_opp_tables(mfg); 978 + if (ret) { 979 + dev_err_probe(dev, ret, "Error reading OPP tables from EB\n"); 980 + goto err_power_off; 981 + } 982 + 983 + ret = mtk_mfg_init_clk_provider(mfg); 984 + if (ret) 985 + goto err_power_off; 986 + 987 + ret = of_genpd_add_provider_simple(dev->of_node, &mfg->pd); 988 + if (ret) { 989 + dev_err_probe(dev, ret, "Failed to add pmdomain provider\n"); 990 + goto err_power_off; 991 + } 992 + 993 + return 0; 994 + 995 + err_power_off: 996 + mtk_mfg_power_off(&mfg->pd); 997 + err_free_mbox: 998 + mbox_free_channel(mfg->slp_mbox->ch); 999 + mfg->slp_mbox->ch = NULL; 1000 + mbox_free_channel(mfg->gf_mbox->ch); 1001 + mfg->gf_mbox->ch = NULL; 1002 + err_remove_genpd: 1003 + pm_genpd_remove(&mfg->pd); 1004 + 1005 + return ret; 1006 + } 1007 + 1008 + static const struct of_device_id mtk_mfg_of_match[] = { 1009 + { .compatible = "mediatek,mt8196-gpufreq", .data = &mtk_mfg_mt8196_variant }, 1010 + {} 1011 + }; 1012 + MODULE_DEVICE_TABLE(of, mtk_mfg_of_match); 1013 + 1014 + static void mtk_mfg_remove(struct platform_device *pdev) 1015 + { 1016 + struct mtk_mfg *mfg = dev_get_drvdata(&pdev->dev); 1017 + 1018 + if (mtk_mfg_is_powered_on(mfg)) 1019 + mtk_mfg_power_off(&mfg->pd); 1020 + 1021 + of_genpd_del_provider(pdev->dev.of_node); 1022 + pm_genpd_remove(&mfg->pd); 1023 + 1024 + mbox_free_channel(mfg->gf_mbox->ch); 1025 + mfg->gf_mbox->ch = NULL; 1026 + 1027 + mbox_free_channel(mfg->slp_mbox->ch); 1028 + mfg->slp_mbox->ch = NULL; 1029 + } 1030 + 1031 + static struct platform_driver mtk_mfg_driver = { 1032 + .driver = { 1033 + .name = "mtk-mfg-pmdomain", 1034 + .of_match_table = mtk_mfg_of_match, 1035 + .suppress_bind_attrs = true, 1036 + }, 1037 + .probe = mtk_mfg_probe, 1038 + .remove = mtk_mfg_remove, 1039 + }; 1040 + module_platform_driver(mtk_mfg_driver); 1041 + 1042 + MODULE_AUTHOR("Nicolas Frattaroli <nicolas.frattaroli@collabora.com>"); 1043 + MODULE_DESCRIPTION("MediaTek MFlexGraphics Power Domain Driver"); 1044 + MODULE_LICENSE("GPL");
+278 -28
drivers/pmdomain/mediatek/mtk-pm-domains.c
··· 2 2 /* 3 3 * Copyright (c) 2020 Collabora Ltd. 4 4 */ 5 + #include <linux/arm-smccc.h> 5 6 #include <linux/clk.h> 6 7 #include <linux/clk-provider.h> 7 8 #include <linux/init.h> ··· 16 15 #include <linux/regmap.h> 17 16 #include <linux/regulator/consumer.h> 18 17 #include <linux/soc/mediatek/infracfg.h> 18 + #include <linux/soc/mediatek/mtk_sip_svc.h> 19 19 20 20 #include "mt6735-pm-domains.h" 21 21 #include "mt6795-pm-domains.h" ··· 28 26 #include "mt8188-pm-domains.h" 29 27 #include "mt8192-pm-domains.h" 30 28 #include "mt8195-pm-domains.h" 29 + #include "mt8196-pm-domains.h" 31 30 #include "mt8365-pm-domains.h" 32 31 33 32 #define MTK_POLL_DELAY_US 10 34 33 #define MTK_POLL_TIMEOUT USEC_PER_SEC 34 + 35 + #define MTK_HWV_POLL_DELAY_US 5 36 + #define MTK_HWV_POLL_TIMEOUT (300 * USEC_PER_MSEC) 37 + 38 + #define MTK_HWV_PREPARE_DELAY_US 1 39 + #define MTK_HWV_PREPARE_TIMEOUT (3 * USEC_PER_MSEC) 35 40 36 41 #define PWR_RST_B_BIT BIT(0) 37 42 #define PWR_ISO_BIT BIT(1) ··· 54 45 #define PWR_RTFF_SAVE_FLAG BIT(27) 55 46 #define PWR_RTFF_UFS_CLK_DIS BIT(28) 56 47 48 + #define MTK_SIP_KERNEL_HWCCF_CONTROL MTK_SIP_SMC_CMD(0x540) 49 + 57 50 struct scpsys_domain { 58 51 struct generic_pm_domain genpd; 59 52 const struct scpsys_domain_data *data; 53 + const struct scpsys_hwv_domain_data *hwv_data; 60 54 struct scpsys *scpsys; 61 55 int num_clks; 62 56 struct clk_bulk_data *clks; ··· 83 71 static bool scpsys_domain_is_on(struct scpsys_domain *pd) 84 72 { 85 73 struct scpsys *scpsys = pd->scpsys; 86 - u32 status, status2; 74 + u32 mask = pd->data->sta_mask; 75 + u32 status, status2, mask2; 76 + 77 + mask2 = pd->data->sta2nd_mask ? pd->data->sta2nd_mask : mask; 87 78 88 79 regmap_read(scpsys->base, pd->data->pwr_sta_offs, &status); 89 - status &= pd->data->sta_mask; 80 + status &= mask; 90 81 91 82 regmap_read(scpsys->base, pd->data->pwr_sta2nd_offs, &status2); 92 - status2 &= pd->data->sta_mask; 83 + status2 &= mask2; 93 84 94 85 /* A domain is on when both status bits are set. */ 95 86 return status && status2; 87 + } 88 + 89 + static bool scpsys_hwv_domain_is_disable_done(struct scpsys_domain *pd) 90 + { 91 + const struct scpsys_hwv_domain_data *hwv = pd->hwv_data; 92 + u32 regs[2] = { hwv->done, hwv->clr_sta }; 93 + u32 val[2]; 94 + u32 mask = BIT(hwv->setclr_bit); 95 + 96 + regmap_multi_reg_read(pd->scpsys->base, regs, val, 2); 97 + 98 + /* Disable is done when the bit is set in DONE, cleared in CLR_STA */ 99 + return (val[0] & mask) && !(val[1] & mask); 100 + } 101 + 102 + static bool scpsys_hwv_domain_is_enable_done(struct scpsys_domain *pd) 103 + { 104 + const struct scpsys_hwv_domain_data *hwv = pd->hwv_data; 105 + u32 regs[3] = { hwv->done, hwv->en, hwv->set_sta }; 106 + u32 val[3]; 107 + u32 mask = BIT(hwv->setclr_bit); 108 + 109 + regmap_multi_reg_read(pd->scpsys->base, regs, val, 3); 110 + 111 + /* Enable is done when the bit is set in DONE and EN, cleared in SET_STA */ 112 + return (val[0] & mask) && (val[1] & mask) && !(val[2] & mask); 113 + } 114 + 115 + static int scpsys_sec_infra_power_on(bool on) 116 + { 117 + struct arm_smccc_res res; 118 + unsigned long cmd = on ? 1 : 0; 119 + 120 + arm_smccc_smc(MTK_SIP_KERNEL_HWCCF_CONTROL, cmd, 0, 0, 0, 0, 0, 0, &res); 121 + return res.a0; 96 122 } 97 123 98 124 static int scpsys_sram_enable(struct scpsys_domain *pd) ··· 299 249 { 300 250 return supply ? regulator_disable(supply) : 0; 301 251 } 252 + 253 + static int scpsys_hwv_power_on(struct generic_pm_domain *genpd) 254 + { 255 + struct scpsys_domain *pd = container_of(genpd, struct scpsys_domain, genpd); 256 + const struct scpsys_hwv_domain_data *hwv = pd->hwv_data; 257 + struct scpsys *scpsys = pd->scpsys; 258 + u32 val; 259 + int ret; 260 + 261 + if (MTK_SCPD_CAPS(pd, MTK_SCPD_INFRA_PWR_CTL)) { 262 + ret = scpsys_sec_infra_power_on(true); 263 + if (ret) 264 + return ret; 265 + } 266 + 267 + ret = scpsys_regulator_enable(pd->supply); 268 + if (ret) 269 + goto err_infra; 270 + 271 + ret = clk_bulk_prepare_enable(pd->num_clks, pd->clks); 272 + if (ret) 273 + goto err_reg; 274 + 275 + /* For HWV the subsys clocks refer to the HWV low power subsystem */ 276 + ret = clk_bulk_prepare_enable(pd->num_subsys_clks, pd->subsys_clks); 277 + if (ret) 278 + goto err_disable_clks; 279 + 280 + /* Make sure the HW Voter is idle and able to accept commands */ 281 + ret = regmap_read_poll_timeout_atomic(scpsys->base, hwv->done, val, 282 + val & BIT(hwv->setclr_bit), 283 + MTK_HWV_POLL_DELAY_US, 284 + MTK_HWV_POLL_TIMEOUT); 285 + if (ret) { 286 + dev_err(scpsys->dev, "Failed to power on: HW Voter busy.\n"); 287 + goto err_disable_subsys_clks; 288 + } 289 + 290 + /* 291 + * Instruct the HWV to power on the MTCMOS (power domain): after that, 292 + * the same bit will be unset immediately by the hardware. 293 + */ 294 + regmap_write(scpsys->base, hwv->set, BIT(hwv->setclr_bit)); 295 + 296 + /* 297 + * Wait until the HWV sets the bit again, signalling that its internal 298 + * state machine was started and it now processing the vote command. 299 + */ 300 + ret = regmap_read_poll_timeout_atomic(scpsys->base, hwv->set, val, 301 + val & BIT(hwv->setclr_bit), 302 + MTK_HWV_PREPARE_DELAY_US, 303 + MTK_HWV_PREPARE_TIMEOUT); 304 + if (ret) { 305 + dev_err(scpsys->dev, "Failed to power on: HW Voter not starting.\n"); 306 + goto err_disable_subsys_clks; 307 + } 308 + 309 + /* Wait for ACK, signalling that the MTCMOS was enabled */ 310 + ret = readx_poll_timeout_atomic(scpsys_hwv_domain_is_enable_done, pd, val, val, 311 + MTK_HWV_POLL_DELAY_US, MTK_HWV_POLL_TIMEOUT); 312 + if (ret) { 313 + dev_err(scpsys->dev, "Failed to power on: HW Voter ACK timeout.\n"); 314 + goto err_disable_subsys_clks; 315 + } 316 + 317 + /* It's done! Disable the HWV low power subsystem clocks */ 318 + clk_bulk_disable_unprepare(pd->num_subsys_clks, pd->subsys_clks); 319 + 320 + if (MTK_SCPD_CAPS(pd, MTK_SCPD_INFRA_PWR_CTL)) 321 + scpsys_sec_infra_power_on(false); 322 + 323 + return 0; 324 + 325 + err_disable_subsys_clks: 326 + clk_bulk_disable_unprepare(pd->num_subsys_clks, pd->subsys_clks); 327 + err_disable_clks: 328 + clk_bulk_disable_unprepare(pd->num_clks, pd->clks); 329 + err_reg: 330 + scpsys_regulator_disable(pd->supply); 331 + err_infra: 332 + if (MTK_SCPD_CAPS(pd, MTK_SCPD_INFRA_PWR_CTL)) 333 + scpsys_sec_infra_power_on(false); 334 + return ret; 335 + }; 336 + 337 + static int scpsys_hwv_power_off(struct generic_pm_domain *genpd) 338 + { 339 + struct scpsys_domain *pd = container_of(genpd, struct scpsys_domain, genpd); 340 + const struct scpsys_hwv_domain_data *hwv = pd->hwv_data; 341 + struct scpsys *scpsys = pd->scpsys; 342 + u32 val; 343 + int ret; 344 + 345 + if (MTK_SCPD_CAPS(pd, MTK_SCPD_INFRA_PWR_CTL)) { 346 + ret = scpsys_sec_infra_power_on(true); 347 + if (ret) 348 + return ret; 349 + } 350 + 351 + ret = clk_bulk_prepare_enable(pd->num_subsys_clks, pd->subsys_clks); 352 + if (ret) 353 + goto err_infra; 354 + 355 + /* Make sure the HW Voter is idle and able to accept commands */ 356 + ret = regmap_read_poll_timeout_atomic(scpsys->base, hwv->done, val, 357 + val & BIT(hwv->setclr_bit), 358 + MTK_HWV_POLL_DELAY_US, 359 + MTK_HWV_POLL_TIMEOUT); 360 + if (ret) 361 + goto err_disable_subsys_clks; 362 + 363 + 364 + /* 365 + * Instruct the HWV to power off the MTCMOS (power domain): differently 366 + * from poweron, the bit will be kept set. 367 + */ 368 + regmap_write(scpsys->base, hwv->clr, BIT(hwv->setclr_bit)); 369 + 370 + /* 371 + * Wait until the HWV clears the bit, signalling that its internal 372 + * state machine was started and it now processing the clear command. 373 + */ 374 + ret = regmap_read_poll_timeout_atomic(scpsys->base, hwv->clr, val, 375 + !(val & BIT(hwv->setclr_bit)), 376 + MTK_HWV_PREPARE_DELAY_US, 377 + MTK_HWV_PREPARE_TIMEOUT); 378 + if (ret) 379 + goto err_disable_subsys_clks; 380 + 381 + /* Poweroff needs 100us for the HW to stabilize */ 382 + udelay(100); 383 + 384 + /* Wait for ACK, signalling that the MTCMOS was disabled */ 385 + ret = readx_poll_timeout_atomic(scpsys_hwv_domain_is_disable_done, pd, val, val, 386 + MTK_HWV_POLL_DELAY_US, MTK_HWV_POLL_TIMEOUT); 387 + if (ret) 388 + goto err_disable_subsys_clks; 389 + 390 + clk_bulk_disable_unprepare(pd->num_subsys_clks, pd->subsys_clks); 391 + clk_bulk_disable_unprepare(pd->num_clks, pd->clks); 392 + 393 + scpsys_regulator_disable(pd->supply); 394 + 395 + if (MTK_SCPD_CAPS(pd, MTK_SCPD_INFRA_PWR_CTL)) 396 + scpsys_sec_infra_power_on(false); 397 + 398 + return 0; 399 + 400 + err_disable_subsys_clks: 401 + clk_bulk_disable_unprepare(pd->num_subsys_clks, pd->subsys_clks); 402 + err_infra: 403 + if (MTK_SCPD_CAPS(pd, MTK_SCPD_INFRA_PWR_CTL)) 404 + scpsys_sec_infra_power_on(false); 405 + return ret; 406 + }; 302 407 303 408 static int scpsys_ctl_pwrseq_on(struct scpsys_domain *pd) 304 409 { ··· 719 514 generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_node *node) 720 515 { 721 516 const struct scpsys_domain_data *domain_data; 517 + const struct scpsys_hwv_domain_data *hwv_domain_data; 722 518 struct scpsys_domain *pd; 723 519 struct property *prop; 724 520 const char *clk_name; ··· 735 529 return ERR_PTR(-EINVAL); 736 530 } 737 531 738 - if (id >= scpsys->soc_data->num_domains) { 739 - dev_err(scpsys->dev, "%pOF: invalid domain id %d\n", node, id); 740 - return ERR_PTR(-EINVAL); 741 - } 532 + switch (scpsys->soc_data->type) { 533 + case SCPSYS_MTCMOS_TYPE_DIRECT_CTL: 534 + if (id >= scpsys->soc_data->num_domains) { 535 + dev_err(scpsys->dev, "%pOF: invalid domain id %d\n", node, id); 536 + return ERR_PTR(-EINVAL); 537 + } 742 538 743 - domain_data = &scpsys->soc_data->domains_data[id]; 744 - if (domain_data->sta_mask == 0) { 745 - dev_err(scpsys->dev, "%pOF: undefined domain id %d\n", node, id); 539 + domain_data = &scpsys->soc_data->domains_data[id]; 540 + hwv_domain_data = NULL; 541 + 542 + if (domain_data->sta_mask == 0) { 543 + dev_err(scpsys->dev, "%pOF: undefined domain id %d\n", node, id); 544 + return ERR_PTR(-EINVAL); 545 + } 546 + 547 + break; 548 + case SCPSYS_MTCMOS_TYPE_HW_VOTER: 549 + if (id >= scpsys->soc_data->num_hwv_domains) { 550 + dev_err(scpsys->dev, "%pOF: invalid HWV domain id %d\n", node, id); 551 + return ERR_PTR(-EINVAL); 552 + } 553 + 554 + domain_data = NULL; 555 + hwv_domain_data = &scpsys->soc_data->hwv_domains_data[id]; 556 + 557 + break; 558 + default: 746 559 return ERR_PTR(-EINVAL); 747 560 } 748 561 ··· 770 545 return ERR_PTR(-ENOMEM); 771 546 772 547 pd->data = domain_data; 548 + pd->hwv_data = hwv_domain_data; 773 549 pd->scpsys = scpsys; 774 550 775 551 if (MTK_SCPD_CAPS(pd, MTK_SCPD_DOMAIN_SUPPLY)) { ··· 830 604 pd->subsys_clks[i].clk = clk; 831 605 } 832 606 607 + if (scpsys->domains[id]) { 608 + ret = -EINVAL; 609 + dev_err(scpsys->dev, 610 + "power domain with id %d already exists, check your device-tree\n", id); 611 + goto err_put_subsys_clocks; 612 + } 613 + 614 + if (pd->data && pd->data->name) 615 + pd->genpd.name = pd->data->name; 616 + else if (pd->hwv_data && pd->hwv_data->name) 617 + pd->genpd.name = pd->hwv_data->name; 618 + else 619 + pd->genpd.name = node->name; 620 + 621 + if (scpsys->soc_data->type == SCPSYS_MTCMOS_TYPE_DIRECT_CTL) { 622 + pd->genpd.power_off = scpsys_power_off; 623 + pd->genpd.power_on = scpsys_power_on; 624 + } else { 625 + pd->genpd.power_off = scpsys_hwv_power_off; 626 + pd->genpd.power_on = scpsys_hwv_power_on; 627 + 628 + /* HW-Voter code can be invoked in atomic context */ 629 + pd->genpd.flags |= GENPD_FLAG_IRQ_SAFE; 630 + } 631 + 833 632 /* 834 633 * Initially turn on all domains to make the domains usable 835 634 * with !CONFIG_PM and to get the hardware in sync with the ··· 866 615 dev_warn(scpsys->dev, 867 616 "%pOF: A default off power domain has been ON\n", node); 868 617 } else { 869 - ret = scpsys_power_on(&pd->genpd); 618 + ret = pd->genpd.power_on(&pd->genpd); 870 619 if (ret < 0) { 871 620 dev_err(scpsys->dev, "%pOF: failed to power on domain: %d\n", node, ret); 872 621 goto err_put_subsys_clocks; ··· 875 624 if (MTK_SCPD_CAPS(pd, MTK_SCPD_ALWAYS_ON)) 876 625 pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON; 877 626 } 878 - 879 - if (scpsys->domains[id]) { 880 - ret = -EINVAL; 881 - dev_err(scpsys->dev, 882 - "power domain with id %d already exists, check your device-tree\n", id); 883 - goto err_put_subsys_clocks; 884 - } 885 - 886 - if (!pd->data->name) 887 - pd->genpd.name = node->name; 888 - else 889 - pd->genpd.name = pd->data->name; 890 - 891 - pd->genpd.power_off = scpsys_power_off; 892 - pd->genpd.power_on = scpsys_power_on; 893 627 894 628 if (MTK_SCPD_CAPS(pd, MTK_SCPD_ACTIVE_WAKEUP)) 895 629 pd->genpd.flags |= GENPD_FLAG_ACTIVE_WAKEUP; ··· 1168 932 .data = &mt8195_scpsys_data, 1169 933 }, 1170 934 { 935 + .compatible = "mediatek,mt8196-power-controller", 936 + .data = &mt8196_scpsys_data, 937 + }, 938 + { 939 + .compatible = "mediatek,mt8196-hwv-hfrp-power-controller", 940 + .data = &mt8196_hfrpsys_hwv_data, 941 + }, 942 + { 943 + .compatible = "mediatek,mt8196-hwv-scp-power-controller", 944 + .data = &mt8196_scpsys_hwv_data, 945 + }, 946 + { 1171 947 .compatible = "mediatek,mt8365-power-controller", 1172 948 .data = &mt8365_scpsys_data, 1173 949 }, ··· 1194 946 struct device_node *node; 1195 947 struct device *parent; 1196 948 struct scpsys *scpsys; 1197 - int ret; 949 + int num_domains, ret; 1198 950 1199 951 soc = of_device_get_match_data(&pdev->dev); 1200 952 if (!soc) { ··· 1202 954 return -EINVAL; 1203 955 } 1204 956 1205 - scpsys = devm_kzalloc(dev, struct_size(scpsys, domains, soc->num_domains), GFP_KERNEL); 957 + num_domains = soc->num_domains + soc->num_hwv_domains; 958 + 959 + scpsys = devm_kzalloc(dev, struct_size(scpsys, domains, num_domains), GFP_KERNEL); 1206 960 if (!scpsys) 1207 961 return -ENOMEM; 1208 962
+48 -1
drivers/pmdomain/mediatek/mtk-pm-domains.h
··· 16 16 #define MTK_SCPD_SRAM_PDN_INVERTED BIT(9) 17 17 #define MTK_SCPD_MODEM_PWRSEQ BIT(10) 18 18 #define MTK_SCPD_SKIP_RESET_B BIT(11) 19 - #define MTK_SCPD_CAPS(_scpd, _x) ((_scpd)->data->caps & (_x)) 19 + #define MTK_SCPD_INFRA_PWR_CTL BIT(12) 20 + #define MTK_SCPD_CAPS(_scpd, _x) ((_scpd)->data ? \ 21 + (_scpd)->data->caps & (_x) : \ 22 + (_scpd)->hwv_data->caps & (_x)) 20 23 21 24 #define SPM_VDE_PWR_CON 0x0210 22 25 #define SPM_MFG_PWR_CON 0x0214 ··· 62 59 BUS_PROT_BLOCK_INFRA, 63 60 BUS_PROT_BLOCK_INFRA_NAO, 64 61 BUS_PROT_BLOCK_SMI, 62 + BUS_PROT_BLOCK_SPM, 65 63 BUS_PROT_BLOCK_COUNT, 66 64 }; 67 65 ··· 129 125 }; 130 126 131 127 /** 128 + * enum scpsys_mtcmos_type - Type of power domain controller 129 + * @SCPSYS_MTCMOS_TYPE_DIRECT_CTL: Power domains are controlled with direct access 130 + * @SCPSYS_MTCMOS_TYPE_HW_VOTER: Hardware-assisted voted power domain control 131 + * @SCPSYS_MTCMOS_TYPE_MAX: Number of supported power domain types 132 + */ 133 + enum scpsys_mtcmos_type { 134 + SCPSYS_MTCMOS_TYPE_DIRECT_CTL = 0, 135 + SCPSYS_MTCMOS_TYPE_HW_VOTER, 136 + SCPSYS_MTCMOS_TYPE_MAX 137 + }; 138 + 139 + /** 132 140 * struct scpsys_domain_data - scp domain data for power on/off flow 133 141 * @name: The name of the power domain. 134 142 * @sta_mask: The mask for power on/off status bit. 143 + * @sta2nd_mask: The mask for second power on/off status bit. 135 144 * @ctl_offs: The offset for main power control register. 136 145 * @sram_pdn_bits: The mask for sram power control bits. 137 146 * @sram_pdn_ack_bits: The mask for sram power control acked bits. ··· 157 140 struct scpsys_domain_data { 158 141 const char *name; 159 142 u32 sta_mask; 143 + u32 sta2nd_mask; 160 144 int ctl_offs; 161 145 u32 sram_pdn_bits; 162 146 u32 sram_pdn_ack_bits; ··· 170 152 int pwr_sta2nd_offs; 171 153 }; 172 154 155 + /** 156 + * struct scpsys_hwv_domain_data - Hardware Voter power domain data 157 + * @name: Name of the power domain 158 + * @set: Offset of the HWV SET register 159 + * @clr: Offset of the HWV CLEAR register 160 + * @done: Offset of the HWV DONE register 161 + * @en: Offset of the HWV ENABLE register 162 + * @set_sta: Offset of the HWV SET STATUS register 163 + * @clr_sta: Offset of the HWV CLEAR STATUS register 164 + * @setclr_bit: The SET/CLR bit to enable/disable the power domain 165 + * @sta_bit: The SET/CLR STA bit to check for on/off ACK 166 + * @caps: The flag for active wake-up action 167 + */ 168 + struct scpsys_hwv_domain_data { 169 + const char *name; 170 + u16 set; 171 + u16 clr; 172 + u16 done; 173 + u16 en; 174 + u16 set_sta; 175 + u16 clr_sta; 176 + u8 setclr_bit; 177 + u8 sta_bit; 178 + u16 caps; 179 + }; 180 + 173 181 struct scpsys_soc_data { 174 182 const struct scpsys_domain_data *domains_data; 175 183 int num_domains; 184 + const struct scpsys_hwv_domain_data *hwv_domains_data; 185 + int num_hwv_domains; 176 186 enum scpsys_bus_prot_block *bus_prot_blocks; 177 187 int num_bus_prot_blocks; 188 + enum scpsys_mtcmos_type type; 178 189 }; 179 190 180 191 #endif /* __SOC_MEDIATEK_MTK_PM_DOMAINS_H */
+27 -1
drivers/pmdomain/qcom/rpmhpd.c
··· 19 19 20 20 #define domain_to_rpmhpd(domain) container_of(domain, struct rpmhpd, pd) 21 21 22 - #define RPMH_ARC_MAX_LEVELS 16 22 + #define RPMH_ARC_MAX_LEVELS 32 23 23 24 24 /** 25 25 * struct rpmhpd - top level RPMh power domain resource data structure ··· 595 595 .num_pds = ARRAY_SIZE(sm8750_rpmhpds), 596 596 }; 597 597 598 + /* KAANAPALI RPMH powerdomains */ 599 + static struct rpmhpd *kaanapali_rpmhpds[] = { 600 + [RPMHPD_CX] = &cx, 601 + [RPMHPD_CX_AO] = &cx_ao, 602 + [RPMHPD_EBI] = &ebi, 603 + [RPMHPD_GFX] = &gfx, 604 + [RPMHPD_GMXC] = &gmxc, 605 + [RPMHPD_LCX] = &lcx, 606 + [RPMHPD_LMX] = &lmx, 607 + [RPMHPD_MX] = &mx, 608 + [RPMHPD_MX_AO] = &mx_ao, 609 + [RPMHPD_MMCX] = &mmcx, 610 + [RPMHPD_MMCX_AO] = &mmcx_ao, 611 + [RPMHPD_MSS] = &mss, 612 + [RPMHPD_MXC] = &mxc, 613 + [RPMHPD_MXC_AO] = &mxc_ao, 614 + [RPMHPD_NSP] = &nsp, 615 + [RPMHPD_NSP2] = &nsp2, 616 + }; 617 + 618 + static const struct rpmhpd_desc kaanapali_desc = { 619 + .rpmhpds = kaanapali_rpmhpds, 620 + .num_pds = ARRAY_SIZE(kaanapali_rpmhpds), 621 + }; 622 + 598 623 /* QDU1000/QRU1000 RPMH powerdomains */ 599 624 static struct rpmhpd *qdu1000_rpmhpds[] = { 600 625 [QDU1000_CX] = &cx, ··· 792 767 793 768 static const struct of_device_id rpmhpd_match_table[] = { 794 769 { .compatible = "qcom,glymur-rpmhpd", .data = &glymur_desc }, 770 + { .compatible = "qcom,kaanapali-rpmhpd", .data = &kaanapali_desc }, 795 771 { .compatible = "qcom,milos-rpmhpd", .data = &milos_desc }, 796 772 { .compatible = "qcom,qcs615-rpmhpd", .data = &qcs615_desc }, 797 773 { .compatible = "qcom,qcs8300-rpmhpd", .data = &qcs8300_desc },
+41
drivers/pmdomain/rockchip/pm-domains.c
··· 25 25 #include <soc/rockchip/rockchip_sip.h> 26 26 #include <dt-bindings/power/px30-power.h> 27 27 #include <dt-bindings/power/rockchip,rv1126-power.h> 28 + #include <dt-bindings/power/rockchip,rv1126b-power-controller.h> 28 29 #include <dt-bindings/power/rk3036-power.h> 29 30 #include <dt-bindings/power/rk3066-power.h> 30 31 #include <dt-bindings/power/rk3128-power.h> ··· 138 137 .active_wakeup = wakeup, \ 139 138 } 140 139 140 + #define DOMAIN_M_G(_name, pwr, status, req, idle, ack, g_mask, wakeup, keepon) \ 141 + { \ 142 + .name = _name, \ 143 + .pwr_w_mask = (pwr) << 16, \ 144 + .pwr_mask = (pwr), \ 145 + .status_mask = (status), \ 146 + .req_w_mask = (req) << 16, \ 147 + .req_mask = (req), \ 148 + .idle_mask = (idle), \ 149 + .ack_mask = (ack), \ 150 + .clk_ungate_mask = (g_mask), \ 151 + .active_wakeup = wakeup, \ 152 + } 153 + 141 154 #define DOMAIN_M_G_SD(_name, pwr, status, req, idle, ack, g_mask, mem, wakeup, keepon) \ 142 155 { \ 143 156 .name = _name, \ ··· 219 204 220 205 #define DOMAIN_RV1126(name, pwr, req, idle, wakeup) \ 221 206 DOMAIN_M(name, pwr, pwr, req, idle, idle, wakeup) 207 + 208 + #define DOMAIN_RV1126B(name, pwr, req, wakeup) \ 209 + DOMAIN_M_G(name, pwr, pwr, req, req, req, req, wakeup, true) 222 210 223 211 #define DOMAIN_RK3288(name, pwr, status, req, wakeup) \ 224 212 DOMAIN(name, pwr, status, req, req, (req) << 16, wakeup) ··· 1122 1104 [RV1126_PD_USB] = DOMAIN_RV1126("usb", BIT(9), BIT(15), BIT(15), false), 1123 1105 }; 1124 1106 1107 + static const struct rockchip_domain_info rv1126b_pm_domains[] = { 1108 + /* name pwr req wakeup */ 1109 + [RV1126B_PD_NPU] = DOMAIN_RV1126B("npu", BIT(0), BIT(8), false), 1110 + [RV1126B_PD_VDO] = DOMAIN_RV1126B("vdo", BIT(1), BIT(9), false), 1111 + [RV1126B_PD_AIISP] = DOMAIN_RV1126B("aiisp", BIT(2), BIT(10), false), 1112 + }; 1113 + 1125 1114 static const struct rockchip_domain_info rk3036_pm_domains[] = { 1126 1115 [RK3036_PD_MSCH] = DOMAIN_RK3036("msch", BIT(14), BIT(23), BIT(30), true), 1127 1116 [RK3036_PD_CORE] = DOMAIN_RK3036("core", BIT(13), BIT(17), BIT(24), false), ··· 1541 1516 .domain_info = rv1126_pm_domains, 1542 1517 }; 1543 1518 1519 + static const struct rockchip_pmu_info rv1126b_pmu = { 1520 + .pwr_offset = 0x210, 1521 + .status_offset = 0x230, 1522 + .req_offset = 0x110, 1523 + .idle_offset = 0x128, 1524 + .ack_offset = 0x120, 1525 + .clk_ungate_offset = 0x140, 1526 + 1527 + .num_domains = ARRAY_SIZE(rv1126b_pm_domains), 1528 + .domain_info = rv1126b_pm_domains, 1529 + }; 1530 + 1544 1531 static const struct of_device_id rockchip_pm_domain_dt_match[] = { 1545 1532 { 1546 1533 .compatible = "rockchip,px30-power-controller", ··· 1621 1584 { 1622 1585 .compatible = "rockchip,rv1126-power-controller", 1623 1586 .data = (void *)&rv1126_pmu, 1587 + }, 1588 + { 1589 + .compatible = "rockchip,rv1126b-power-controller", 1590 + .data = (void *)&rv1126b_pmu, 1624 1591 }, 1625 1592 { /* sentinel */ }, 1626 1593 };
+10 -1
drivers/usb/chipidea/ci_hdrc_imx.c
··· 79 79 CI_HDRC_HAS_PORTSC_PEC_MISSED, 80 80 }; 81 81 82 + static const struct ci_hdrc_imx_platform_flag imx95_usb_data = { 83 + .flags = CI_HDRC_SUPPORTS_RUNTIME_PM | CI_HDRC_OUT_BAND_WAKEUP, 84 + }; 85 + 82 86 static const struct ci_hdrc_imx_platform_flag s32g_usb_data = { 83 87 .flags = CI_HDRC_DISABLE_HOST_STREAMING, 84 88 }; ··· 98 94 { .compatible = "fsl,imx7d-usb", .data = &imx7d_usb_data}, 99 95 { .compatible = "fsl,imx7ulp-usb", .data = &imx7ulp_usb_data}, 100 96 { .compatible = "fsl,imx8ulp-usb", .data = &imx8ulp_usb_data}, 97 + { .compatible = "fsl,imx95-usb", .data = &imx95_usb_data}, 101 98 { .compatible = "nxp,s32g2-usb", .data = &s32g_usb_data}, 102 99 { /* sentinel */ } 103 100 }; ··· 709 704 710 705 pinctrl_pm_select_sleep_state(dev); 711 706 712 - if (data->wakeup_irq > 0 && device_may_wakeup(dev)) 707 + if (data->wakeup_irq > 0 && device_may_wakeup(dev)) { 713 708 enable_irq_wake(data->wakeup_irq); 709 + 710 + if (data->plat_data->flags & CI_HDRC_OUT_BAND_WAKEUP) 711 + device_set_out_band_wakeup(dev); 712 + } 714 713 715 714 return ret; 716 715 }
+3
drivers/usb/chipidea/core.c
··· 27 27 #include <linux/kernel.h> 28 28 #include <linux/slab.h> 29 29 #include <linux/pm_runtime.h> 30 + #include <linux/pm_domain.h> 30 31 #include <linux/pinctrl/consumer.h> 31 32 #include <linux/usb/ch9.h> 32 33 #include <linux/usb/gadget.h> ··· 915 914 ret = platform_device_add(pdev); 916 915 if (ret) 917 916 goto err; 917 + 918 + dev_pm_domain_detach(&pdev->dev, false); 918 919 919 920 return pdev; 920 921
+7 -2
drivers/usb/dwc3/dwc3-imx8mp.c
··· 334 334 335 335 ret = dwc3_imx8mp_suspend(dwc3_imx, PMSG_SUSPEND); 336 336 337 - if (device_may_wakeup(dwc3_imx->dev)) 337 + if (device_may_wakeup(dwc3_imx->dev)) { 338 338 enable_irq_wake(dwc3_imx->irq); 339 - else 339 + 340 + if (device_is_compatible(dev, "fsl,imx95-dwc3")) 341 + device_set_out_band_wakeup(dev); 342 + 343 + } else { 340 344 clk_disable_unprepare(dwc3_imx->suspend_clk); 345 + } 341 346 342 347 clk_disable_unprepare(dwc3_imx->hsio_clk); 343 348 dev_dbg(dev, "dwc3 imx8mp pm suspend.\n");
+58
include/dt-bindings/power/mediatek,mt8196-power.h
··· 1 + /* SPDX-License-Identifier: (GPL-2.0 OR MIT) */ 2 + /* 3 + * Copyright (c) 2025 Collabora Ltd 4 + * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> 5 + */ 6 + 7 + #ifndef _DT_BINDINGS_POWER_MT8196_POWER_H 8 + #define _DT_BINDINGS_POWER_MT8196_POWER_H 9 + 10 + /* SCPSYS Secure Power Manager - Direct Control */ 11 + #define MT8196_POWER_DOMAIN_MD 0 12 + #define MT8196_POWER_DOMAIN_CONN 1 13 + #define MT8196_POWER_DOMAIN_SSUSB_P0 2 14 + #define MT8196_POWER_DOMAIN_SSUSB_DP_PHY_P0 3 15 + #define MT8196_POWER_DOMAIN_SSUSB_P1 4 16 + #define MT8196_POWER_DOMAIN_SSUSB_P23 5 17 + #define MT8196_POWER_DOMAIN_SSUSB_PHY_P2 6 18 + #define MT8196_POWER_DOMAIN_PEXTP_MAC0 7 19 + #define MT8196_POWER_DOMAIN_PEXTP_MAC1 8 20 + #define MT8196_POWER_DOMAIN_PEXTP_MAC2 9 21 + #define MT8196_POWER_DOMAIN_PEXTP_PHY0 10 22 + #define MT8196_POWER_DOMAIN_PEXTP_PHY1 11 23 + #define MT8196_POWER_DOMAIN_PEXTP_PHY2 12 24 + #define MT8196_POWER_DOMAIN_AUDIO 13 25 + #define MT8196_POWER_DOMAIN_ADSP_TOP_DORMANT 14 26 + #define MT8196_POWER_DOMAIN_ADSP_INFRA 15 27 + #define MT8196_POWER_DOMAIN_ADSP_AO 16 28 + 29 + /* SCPSYS Secure Power Manager - HW Voter */ 30 + #define MT8196_POWER_DOMAIN_MM_PROC_DORMANT 0 31 + #define MT8196_POWER_DOMAIN_SSR 1 32 + 33 + /* HFRPSYS MultiMedia Power Control (MMPC) - HW Voter */ 34 + #define MT8196_POWER_DOMAIN_VDE0 0 35 + #define MT8196_POWER_DOMAIN_VDE1 1 36 + #define MT8196_POWER_DOMAIN_VDE_VCORE0 2 37 + #define MT8196_POWER_DOMAIN_VEN0 3 38 + #define MT8196_POWER_DOMAIN_VEN1 4 39 + #define MT8196_POWER_DOMAIN_VEN2 5 40 + #define MT8196_POWER_DOMAIN_DISP_VCORE 6 41 + #define MT8196_POWER_DOMAIN_DIS0_DORMANT 7 42 + #define MT8196_POWER_DOMAIN_DIS1_DORMANT 8 43 + #define MT8196_POWER_DOMAIN_OVL0_DORMANT 9 44 + #define MT8196_POWER_DOMAIN_OVL1_DORMANT 10 45 + #define MT8196_POWER_DOMAIN_DISP_EDPTX_DORMANT 11 46 + #define MT8196_POWER_DOMAIN_DISP_DPTX_DORMANT 12 47 + #define MT8196_POWER_DOMAIN_MML0_SHUTDOWN 13 48 + #define MT8196_POWER_DOMAIN_MML1_SHUTDOWN 14 49 + #define MT8196_POWER_DOMAIN_MM_INFRA0 15 50 + #define MT8196_POWER_DOMAIN_MM_INFRA1 16 51 + #define MT8196_POWER_DOMAIN_MM_INFRA_AO 17 52 + #define MT8196_POWER_DOMAIN_CSI_BS_RX 18 53 + #define MT8196_POWER_DOMAIN_CSI_LS_RX 19 54 + #define MT8196_POWER_DOMAIN_DSI_PHY0 20 55 + #define MT8196_POWER_DOMAIN_DSI_PHY1 21 56 + #define MT8196_POWER_DOMAIN_DSI_PHY2 22 57 + 58 + #endif /* _DT_BINDINGS_POWER_MT8196_POWER_H */
+3
include/dt-bindings/power/qcom,rpmhpd.h
··· 33 33 #define RPMH_REGULATOR_LEVEL_RETENTION 16 34 34 #define RPMH_REGULATOR_LEVEL_MIN_SVS 48 35 35 #define RPMH_REGULATOR_LEVEL_LOW_SVS_D3 50 36 + #define RPMH_REGULATOR_LEVEL_LOW_SVS_D2_1 51 36 37 #define RPMH_REGULATOR_LEVEL_LOW_SVS_D2 52 38 + #define RPMH_REGULATOR_LEVEL_LOW_SVS_D1_1 54 37 39 #define RPMH_REGULATOR_LEVEL_LOW_SVS_D1 56 38 40 #define RPMH_REGULATOR_LEVEL_LOW_SVS_D0 60 39 41 #define RPMH_REGULATOR_LEVEL_LOW_SVS 64 40 42 #define RPMH_REGULATOR_LEVEL_LOW_SVS_P1 72 43 + #define RPMH_REGULATOR_LEVEL_LOW_SVS_L0 76 41 44 #define RPMH_REGULATOR_LEVEL_LOW_SVS_L1 80 42 45 #define RPMH_REGULATOR_LEVEL_LOW_SVS_L2 96 43 46 #define RPMH_REGULATOR_LEVEL_SVS 128
+17
include/dt-bindings/power/rockchip,rv1126b-power-controller.h
··· 1 + /* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */ 2 + /* 3 + * Copyright (c) 2024 Rockchip Electronics Co., Ltd. 4 + * Author: Finley Xiao <finley.xiao@rock-chips.com> 5 + */ 6 + 7 + #ifndef __DT_BINDINGS_POWER_RV1126B_POWER_CONTROLLER_H__ 8 + #define __DT_BINDINGS_POWER_RV1126B_POWER_CONTROLLER_H__ 9 + 10 + /* VD_NPU */ 11 + #define RV1126B_PD_NPU 0 12 + 13 + /* VD_LOGIC */ 14 + #define RV1126B_PD_VDO 1 15 + #define RV1126B_PD_AIISP 2 16 + 17 + #endif
+1
include/linux/pm.h
··· 688 688 bool smart_suspend:1; /* Owned by the PM core */ 689 689 bool must_resume:1; /* Owned by the PM core */ 690 690 bool may_skip_resume:1; /* Set by subsystems */ 691 + bool out_band_wakeup:1; 691 692 bool strict_midlayer:1; 692 693 #else 693 694 bool should_wakeup:1;
+17
include/linux/pm_wakeup.h
··· 94 94 dev->power.wakeup_path = true; 95 95 } 96 96 97 + static inline void device_set_out_band_wakeup(struct device *dev) 98 + { 99 + dev->power.out_band_wakeup = true; 100 + } 101 + 102 + static inline bool device_out_band_wakeup(struct device *dev) 103 + { 104 + return dev->power.out_band_wakeup; 105 + } 106 + 97 107 /* drivers/base/power/wakeup.c */ 98 108 extern struct wakeup_source *wakeup_source_register(struct device *dev, 99 109 const char *name); ··· 171 161 } 172 162 173 163 static inline void device_set_wakeup_path(struct device *dev) {} 164 + 165 + static inline void device_set_out_band_wakeup(struct device *dev) {} 166 + 167 + static inline bool device_out_band_wakeup(struct device *dev) 168 + { 169 + return false; 170 + } 174 171 175 172 static inline void __pm_stay_awake(struct wakeup_source *ws) {} 176 173
+5
include/linux/smp.h
··· 168 168 169 169 void kick_all_cpus_sync(void); 170 170 void wake_up_all_idle_cpus(void); 171 + bool cpus_peek_for_pending_ipi(const struct cpumask *mask); 171 172 172 173 /* 173 174 * Generic and arch helpers ··· 217 216 218 217 static inline void kick_all_cpus_sync(void) { } 219 218 static inline void wake_up_all_idle_cpus(void) { } 219 + static inline bool cpus_peek_for_pending_ipi(const struct cpumask *mask) 220 + { 221 + return false; 222 + } 220 223 221 224 #define setup_max_cpus 0 222 225
+1
include/linux/usb/chipidea.h
··· 66 66 #define CI_HDRC_HAS_PORTSC_PEC_MISSED BIT(17) 67 67 #define CI_HDRC_FORCE_VBUS_ACTIVE_ALWAYS BIT(18) 68 68 #define CI_HDRC_HAS_SHORT_PKT_LIMIT BIT(19) 69 + #define CI_HDRC_OUT_BAND_WAKEUP BIT(20) 69 70 enum usb_dr_mode dr_mode; 70 71 #define CI_HDRC_CONTROLLER_RESET_EVENT 0 71 72 #define CI_HDRC_CONTROLLER_STOPPED_EVENT 1
+22
kernel/smp.c
··· 1088 1088 EXPORT_SYMBOL_GPL(wake_up_all_idle_cpus); 1089 1089 1090 1090 /** 1091 + * cpus_peek_for_pending_ipi - Check for pending IPI for CPUs 1092 + * @mask: The CPU mask for the CPUs to check. 1093 + * 1094 + * This function walks through the @mask to check if there are any pending IPIs 1095 + * scheduled, for any of the CPUs in the @mask. It does not guarantee 1096 + * correctness as it only provides a racy snapshot. 1097 + * 1098 + * Returns true if there is a pending IPI scheduled and false otherwise. 1099 + */ 1100 + bool cpus_peek_for_pending_ipi(const struct cpumask *mask) 1101 + { 1102 + unsigned int cpu; 1103 + 1104 + for_each_cpu(cpu, mask) { 1105 + if (!llist_empty(per_cpu_ptr(&call_single_queue, cpu))) 1106 + return true; 1107 + } 1108 + 1109 + return false; 1110 + } 1111 + 1112 + /** 1091 1113 * struct smp_call_on_cpu_struct - Call a function on a specific CPU 1092 1114 * @work: &work_struct 1093 1115 * @done: &completion to signal