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
 -----BEGIN PGP SIGNATURE-----
 
 iQJLBAABCgA1FiEEugLDXPmKSktSkQsV/iaEJXNYjCkFAmkt1HYXHHVsZi5oYW5z
 c29uQGxpbmFyby5vcmcACgkQ/iaEJXNYjCk3PQ//W24ZdZ5cqXJASrw4YihTovbR
 Pk/cVBacua32r3uBAf+GKdhAXrC7zaPbohp4tou5tpuY6I54NDJ4mpaTLUr+iZ6A
 aiKGprBrNCNMU7Mu6Af23peQNo0t+0sdsxp3wjZAMcSK0/ioOnc2R+IZhjHI9dPh
 Us7Ke/Pa1DRu78T0P2quRvIIRPv5iGep2vL8LFkQtPNS4tAU5ZHTWghVip+Q0m7x
 660WwZ5a9Bkzii/mqxFlXnXMnFjaJwi7zEPEKEMKd88cTjZXZGqScq8Ojfxto4Jx
 mdn9kPqwUR2QILTVKyBy2nJTeCB5nLvLhldi5/1nVxhqopN5ll4VwFx8CVsEPVTQ
 l76IUMzdAmztnVqs1p7qZ8dyFKdYztNRSESapumpu10/DIIOgWW4eLNk5Sk+7d0K
 1fZDL/hWV2j4gnY0wSjGht2JQ2jhDBsgkxInxvQY2a8Ik91gwyUsD7r3mCq/YwaA
 97GJHk9YO75jolFPy6PniXttzVuoJXPEcvgpBR3br1iFRQhSoGIEfFcDnZEaH9Sw
 m7nSc1Q99a6rsmq+WavB5JVPZBr2UkBhE6x+IU+MEBPwykjNj/1cZ7x4rtqzX666
 eOn1FBDQ63CLEQl3hAPp1pxy3YB0nHcxKR9CPAZjECwZTfsYgJCrRNHyZb+yhPsU
 qKKXXMaOyyowoLraGbQ=
 =Fkue
 -----END PGP SIGNATURE-----

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
  ...
This commit is contained in:
Linus Torvalds 2025-12-04 13:50:39 -08:00
commit 52206f82d9
30 changed files with 2417 additions and 60 deletions

View File

@ -0,0 +1,117 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/power/mediatek,mt8196-gpufreq.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek MFlexGraphics Power and Frequency Controller
maintainers:
- Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
description:
A special-purpose embedded MCU to control power and frequency of GPU devices
using MediaTek Flexible Graphics integration hardware.
properties:
$nodename:
pattern: '^power-controller@[a-f0-9]+$'
compatible:
enum:
- mediatek,mt8196-gpufreq
reg:
items:
- description: GPR memory area
- description: RPC memory area
- description: SoC variant ID register
reg-names:
items:
- const: gpr
- const: rpc
- const: hw-revision
clocks:
items:
- description: main clock of the embedded controller (EB)
- description: core PLL
- description: stack 0 PLL
- description: stack 1 PLL
clock-names:
items:
- const: eb
- const: core
- const: stack0
- const: stack1
mboxes:
items:
- description: FastDVFS events
- description: frequency control
- description: sleep control
- description: timer control
- description: frequency hopping control
- description: hardware voter control
- description: FastDVFS control
mbox-names:
items:
- const: fast-dvfs-event
- const: gpufreq
- const: sleep
- const: timer
- const: fhctl
- const: ccf
- const: fast-dvfs
memory-region:
items:
- description: phandle to the GPUEB shared memory
"#clock-cells":
const: 1
"#power-domain-cells":
const: 0
required:
- compatible
- reg
- reg-names
- clocks
- clock-names
- mboxes
- mbox-names
- memory-region
- "#clock-cells"
- "#power-domain-cells"
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/mediatek,mt8196-clock.h>
power-controller@4b09fd00 {
compatible = "mediatek,mt8196-gpufreq";
reg = <0x4b09fd00 0x80>,
<0x4b800000 0x1000>,
<0x4b860128 0x4>;
reg-names = "gpr", "rpc", "hw-revision";
clocks = <&topckgen CLK_TOP_MFG_EB>,
<&mfgpll CLK_MFG_AO_MFGPLL>,
<&mfgpll_sc0 CLK_MFGSC0_AO_MFGPLL_SC0>,
<&mfgpll_sc1 CLK_MFGSC1_AO_MFGPLL_SC1>;
clock-names = "eb", "core", "stack0", "stack1";
mboxes = <&gpueb_mbox 0>, <&gpueb_mbox 1>, <&gpueb_mbox 2>,
<&gpueb_mbox 3>, <&gpueb_mbox 4>, <&gpueb_mbox 5>,
<&gpueb_mbox 7>;
mbox-names = "fast-dvfs-event", "gpufreq", "sleep", "timer", "fhctl",
"ccf", "fast-dvfs";
memory-region = <&gpueb_shared_memory>;
#clock-cells = <1>;
#power-domain-cells = <0>;
};

View File

@ -33,6 +33,9 @@ properties:
- mediatek,mt8188-power-controller
- mediatek,mt8192-power-controller
- mediatek,mt8195-power-controller
- mediatek,mt8196-hwv-hfrp-power-controller
- mediatek,mt8196-hwv-scp-power-controller
- mediatek,mt8196-power-controller
- mediatek,mt8365-power-controller
'#power-domain-cells':
@ -157,6 +160,7 @@ allOf:
contains:
enum:
- mediatek,mt8183-power-controller
- mediatek,mt8196-power-controller
then:
properties:
access-controllers:

View File

@ -18,6 +18,7 @@ properties:
oneOf:
- enum:
- qcom,glymur-rpmhpd
- qcom,kaanapali-rpmhpd
- qcom,mdm9607-rpmpd
- qcom,milos-rpmhpd
- qcom,msm8226-rpmpd

View File

@ -46,6 +46,7 @@ properties:
- rockchip,rk3576-power-controller
- rockchip,rk3588-power-controller
- rockchip,rv1126-power-controller
- rockchip,rv1126b-power-controller
"#power-domain-cells":
const: 1
@ -126,6 +127,7 @@ $defs:
"include/dt-bindings/power/rk3568-power.h"
"include/dt-bindings/power/rk3588-power.h"
"include/dt-bindings/power/rockchip,rv1126-power.h"
"include/dt-bindings/power/rockchip,rv1126b-power-controller.h"
clocks:
minItems: 1

View File

@ -13,23 +13,21 @@ description: |
maintainers:
- Nicolas Saenz Julienne <nsaenz@kernel.org>
allOf:
- $ref: /schemas/watchdog/watchdog.yaml#
properties:
compatible:
items:
- enum:
- brcm,bcm2835-pm
- brcm,bcm2711-pm
- brcm,bcm2712-pm
- const: brcm,bcm2835-pm-wdt
reg:
minItems: 2
minItems: 1
maxItems: 3
reg-names:
minItems: 2
minItems: 1
items:
- const: pm
- const: asb
@ -62,7 +60,35 @@ required:
- reg
- "#power-domain-cells"
- "#reset-cells"
- clocks
allOf:
- $ref: /schemas/watchdog/watchdog.yaml#
- if:
properties:
compatible:
contains:
enum:
- brcm,bcm2835-pm
- brcm,bcm2711-pm
then:
required:
- clocks
properties:
reg:
minItems: 2
reg-names:
minItems: 2
else:
properties:
reg:
maxItems: 1
reg-names:
maxItems: 1
additionalProperties: false

View File

@ -291,15 +291,14 @@ static int amba_probe(struct device *dev)
if (ret < 0)
break;
ret = dev_pm_domain_attach(dev, PD_FLAG_ATTACH_POWER_ON);
ret = dev_pm_domain_attach(dev, PD_FLAG_ATTACH_POWER_ON |
PD_FLAG_DETACH_POWER_OFF);
if (ret)
break;
ret = amba_get_enable_pclk(pcdev);
if (ret) {
dev_pm_domain_detach(dev, true);
if (ret)
break;
}
pm_runtime_get_noresume(dev);
pm_runtime_set_active(dev);
@ -314,7 +313,6 @@ static int amba_probe(struct device *dev)
pm_runtime_put_noidle(dev);
amba_put_disable_pclk(pcdev);
dev_pm_domain_detach(dev, true);
} while (0);
return ret;
@ -336,7 +334,6 @@ static void amba_remove(struct device *dev)
pm_runtime_put_noidle(dev);
amba_put_disable_pclk(pcdev);
dev_pm_domain_detach(dev, true);
}
static void amba_shutdown(struct device *dev)

View File

@ -2148,6 +2148,7 @@ static int device_prepare(struct device *dev, pm_message_t state)
device_lock(dev);
dev->power.wakeup_path = false;
dev->power.out_band_wakeup = false;
if (dev->power.no_pm_callbacks)
goto unlock;

View File

@ -382,8 +382,8 @@ static int psci_idle_init_cpu(struct device *dev, int cpu)
drv->states[0].exit_latency = 1;
drv->states[0].target_residency = 1;
drv->states[0].power_usage = UINT_MAX;
strcpy(drv->states[0].name, "WFI");
strcpy(drv->states[0].desc, "ARM WFI");
strscpy(drv->states[0].name, "WFI");
strscpy(drv->states[0].desc, "ARM WFI");
/*
* If no DT idle states are detected (ret == 0) let the driver

View File

@ -79,6 +79,7 @@
#define PM_IMAGE 0x108
#define PM_GRAFX 0x10c
#define PM_PROC 0x110
#define PM_GRAFX_2712 0x304
#define PM_ENAB BIT(12)
#define PM_ISPRSTN BIT(8)
#define PM_H264RSTN BIT(7)
@ -381,6 +382,9 @@ static int bcm2835_power_pd_power_on(struct generic_pm_domain *domain)
return bcm2835_power_power_on(pd, PM_GRAFX);
case BCM2835_POWER_DOMAIN_GRAFX_V3D:
if (!power->asb)
return bcm2835_asb_power_on(pd, PM_GRAFX_2712,
0, 0, PM_V3DRSTN);
return bcm2835_asb_power_on(pd, PM_GRAFX,
ASB_V3D_M_CTRL, ASB_V3D_S_CTRL,
PM_V3DRSTN);
@ -447,6 +451,9 @@ static int bcm2835_power_pd_power_off(struct generic_pm_domain *domain)
return bcm2835_power_power_off(pd, PM_GRAFX);
case BCM2835_POWER_DOMAIN_GRAFX_V3D:
if (!power->asb)
return bcm2835_asb_power_off(pd, PM_GRAFX_2712,
0, 0, PM_V3DRSTN);
return bcm2835_asb_power_off(pd, PM_GRAFX,
ASB_V3D_M_CTRL, ASB_V3D_S_CTRL,
PM_V3DRSTN);
@ -635,10 +642,12 @@ static int bcm2835_power_probe(struct platform_device *pdev)
power->asb = pm->asb;
power->rpivid_asb = pm->rpivid_asb;
id = readl(power->asb + ASB_AXI_BRDG_ID);
if (id != BCM2835_BRDG_ID /* "BRDG" */) {
dev_err(dev, "ASB register ID returned 0x%08x\n", id);
return -ENODEV;
if (power->asb) {
id = readl(power->asb + ASB_AXI_BRDG_ID);
if (id != BCM2835_BRDG_ID /* "BRDG" */) {
dev_err(dev, "ASB register ID returned 0x%08x\n", id);
return -ENODEV;
}
}
if (power->rpivid_asb) {

View File

@ -1551,7 +1551,8 @@ static int genpd_finish_suspend(struct device *dev,
if (ret)
return ret;
if (device_awake_path(dev) && genpd_is_active_wakeup(genpd))
if (device_awake_path(dev) && genpd_is_active_wakeup(genpd) &&
!device_out_band_wakeup(dev))
return 0;
if (genpd->dev_ops.stop && genpd->dev_ops.start &&
@ -1606,7 +1607,8 @@ static int genpd_finish_resume(struct device *dev,
if (IS_ERR(genpd))
return -EINVAL;
if (device_awake_path(dev) && genpd_is_active_wakeup(genpd))
if (device_awake_path(dev) && genpd_is_active_wakeup(genpd) &&
!device_out_band_wakeup(dev))
return resume_noirq(dev);
genpd_lock(genpd);

View File

@ -408,15 +408,21 @@ static bool cpu_power_down_ok(struct dev_pm_domain *pd)
if ((idle_duration_ns >= (genpd->states[i].residency_ns +
genpd->states[i].power_off_latency_ns)) &&
(global_constraint >= (genpd->states[i].power_on_latency_ns +
genpd->states[i].power_off_latency_ns))) {
genpd->state_idx = i;
genpd->gd->last_enter = now;
genpd->gd->reflect_residency = true;
return true;
}
genpd->states[i].power_off_latency_ns)))
break;
} while (--i >= 0);
return false;
if (i < 0)
return false;
if (cpus_peek_for_pending_ipi(genpd->cpus))
return false;
genpd->state_idx = i;
genpd->gd->last_enter = now;
genpd->gd->reflect_residency = true;
return true;
}
static bool cpu_system_power_down_ok(struct dev_pm_domain *pd)

View File

@ -26,6 +26,23 @@ config MTK_SCPSYS_PM_DOMAINS
Control Processor System (SCPSYS) has several power management related
tasks in the system.
config MTK_MFG_PM_DOMAIN
bool "MediaTek MFlexGraphics power domain"
default ARCH_MEDIATEK
depends on PM
depends on OF
depends on COMMON_CLK
select MAILBOX
select PM_GENERIC_DOMAINS
imply MTK_GPUEB_MBOX
help
Say y or m here to enable the power domains driver for MediaTek
MFlexGraphics. This driver allows for power and frequency control of
GPUs on MediaTek SoCs such as the MT8196 or MT6991.
This driver is required for the Mali GPU to work at all on MT8196 and
MT6991.
config AIROHA_CPU_PM_DOMAIN
tristate "Airoha CPU power domain"
default ARCH_AIROHA

View File

@ -1,4 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_MTK_MFG_PM_DOMAIN) += mtk-mfg-pmdomain.o
obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o
obj-$(CONFIG_MTK_SCPSYS_PM_DOMAINS) += mtk-pm-domains.o
obj-$(CONFIG_AIROHA_CPU_PM_DOMAIN) += airoha-cpu-pmdomain.o

View File

@ -0,0 +1,625 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2025 Collabora Ltd
* AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
*/
#ifndef __SOC_MEDIATEK_MT8196_PM_DOMAINS_H
#define __SOC_MEDIATEK_MT8196_PM_DOMAINS_H
#include "mtk-pm-domains.h"
#include <dt-bindings/power/mediatek,mt8196-power.h>
/*
* MT8196 and MT6991 power domain support
*/
/* INFRA TOP_AXI registers */
#define MT8196_TOP_AXI_PROT_EN_SET 0x4
#define MT8196_TOP_AXI_PROT_EN_CLR 0x8
#define MT8196_TOP_AXI_PROT_EN_STA 0xc
#define MT8196_TOP_AXI_PROT_EN_SLEEP0_MD BIT(29)
#define MT8196_TOP_AXI_PROT_EN_1_SET 0x24
#define MT8196_TOP_AXI_PROT_EN_1_CLR 0x28
#define MT8196_TOP_AXI_PROT_EN_1_STA 0x2c
#define MT8196_TOP_AXI_PROT_EN_1_SLEEP1_MD BIT(0)
/* SPM BUS_PROTECT registers */
#define MT8196_SPM_BUS_PROTECT_CON_SET 0xdc
#define MT8196_SPM_BUS_PROTECT_CON_CLR 0xe0
#define MT8196_SPM_BUS_PROTECT_RDY 0x208
#define MT8196_SPM_PROT_EN_BUS_CONN BIT(1)
#define MT8196_SPM_PROT_EN_BUS_SSUSB_DP_PHY_P0 BIT(6)
#define MT8196_SPM_PROT_EN_BUS_SSUSB_P0 BIT(7)
#define MT8196_SPM_PROT_EN_BUS_SSUSB_P1 BIT(8)
#define MT8196_SPM_PROT_EN_BUS_SSUSB_P23 BIT(9)
#define MT8196_SPM_PROT_EN_BUS_SSUSB_PHY_P2 BIT(10)
#define MT8196_SPM_PROT_EN_BUS_PEXTP_MAC0 BIT(13)
#define MT8196_SPM_PROT_EN_BUS_PEXTP_MAC1 BIT(14)
#define MT8196_SPM_PROT_EN_BUS_PEXTP_MAC2 BIT(15)
#define MT8196_SPM_PROT_EN_BUS_PEXTP_PHY0 BIT(16)
#define MT8196_SPM_PROT_EN_BUS_PEXTP_PHY1 BIT(17)
#define MT8196_SPM_PROT_EN_BUS_PEXTP_PHY2 BIT(18)
#define MT8196_SPM_PROT_EN_BUS_AUDIO BIT(19)
#define MT8196_SPM_PROT_EN_BUS_ADSP_TOP BIT(21)
#define MT8196_SPM_PROT_EN_BUS_ADSP_INFRA BIT(22)
#define MT8196_SPM_PROT_EN_BUS_ADSP_AO BIT(23)
#define MT8196_SPM_PROT_EN_BUS_MM_PROC BIT(24)
/* PWR_CON registers */
#define MT8196_PWR_ACK BIT(30)
#define MT8196_PWR_ACK_2ND BIT(31)
static enum scpsys_bus_prot_block scpsys_bus_prot_blocks_mt8196[] = {
BUS_PROT_BLOCK_INFRA, BUS_PROT_BLOCK_SPM
};
static const struct scpsys_domain_data scpsys_domain_data_mt8196[] = {
[MT8196_POWER_DOMAIN_MD] = {
.name = "md",
.sta_mask = MT8196_PWR_ACK,
.sta2nd_mask = MT8196_PWR_ACK_2ND,
.ctl_offs = 0xe00,
.pwr_sta_offs = 0xe00,
.pwr_sta2nd_offs = 0xe00,
.ext_buck_iso_offs = 0xefc,
.ext_buck_iso_mask = GENMASK(1, 0),
.bp_cfg = {
BUS_PROT_WR_IGN(INFRA, MT8196_TOP_AXI_PROT_EN_SLEEP0_MD,
MT8196_TOP_AXI_PROT_EN_SET,
MT8196_TOP_AXI_PROT_EN_CLR,
MT8196_TOP_AXI_PROT_EN_STA),
BUS_PROT_WR_IGN(INFRA, MT8196_TOP_AXI_PROT_EN_1_SLEEP1_MD,
MT8196_TOP_AXI_PROT_EN_1_SET,
MT8196_TOP_AXI_PROT_EN_1_CLR,
MT8196_TOP_AXI_PROT_EN_1_STA),
},
.caps = MTK_SCPD_MODEM_PWRSEQ | MTK_SCPD_EXT_BUCK_ISO |
MTK_SCPD_SKIP_RESET_B | MTK_SCPD_KEEP_DEFAULT_OFF,
},
[MT8196_POWER_DOMAIN_CONN] = {
.name = "conn",
.sta_mask = MT8196_PWR_ACK,
.sta2nd_mask = MT8196_PWR_ACK_2ND,
.ctl_offs = 0xe04,
.pwr_sta_offs = 0xe04,
.pwr_sta2nd_offs = 0xe04,
.bp_cfg = {
BUS_PROT_WR_IGN(SPM, MT8196_SPM_PROT_EN_BUS_CONN,
MT8196_SPM_BUS_PROTECT_CON_SET,
MT8196_SPM_BUS_PROTECT_CON_CLR,
MT8196_SPM_BUS_PROTECT_RDY),
},
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
.rtff_type = SCPSYS_RTFF_TYPE_GENERIC,
},
[MT8196_POWER_DOMAIN_SSUSB_DP_PHY_P0] = {
.name = "ssusb-dp-phy-p0",
.sta_mask = MT8196_PWR_ACK,
.sta2nd_mask = MT8196_PWR_ACK_2ND,
.ctl_offs = 0xe18,
.pwr_sta_offs = 0xe18,
.pwr_sta2nd_offs = 0xe18,
.bp_cfg = {
BUS_PROT_WR_IGN(SPM, MT8196_SPM_PROT_EN_BUS_SSUSB_DP_PHY_P0,
MT8196_SPM_BUS_PROTECT_CON_SET,
MT8196_SPM_BUS_PROTECT_CON_CLR,
MT8196_SPM_BUS_PROTECT_RDY),
},
.caps = MTK_SCPD_ALWAYS_ON,
.rtff_type = SCPSYS_RTFF_TYPE_GENERIC,
},
[MT8196_POWER_DOMAIN_SSUSB_P0] = {
.name = "ssusb-p0",
.sta_mask = MT8196_PWR_ACK,
.sta2nd_mask = MT8196_PWR_ACK_2ND,
.ctl_offs = 0xe1c,
.pwr_sta_offs = 0xe1c,
.pwr_sta2nd_offs = 0xe1c,
.sram_pdn_bits = BIT(8),
.sram_pdn_ack_bits = BIT(12),
.bp_cfg = {
BUS_PROT_WR_IGN(SPM, MT8196_SPM_PROT_EN_BUS_SSUSB_P0,
MT8196_SPM_BUS_PROTECT_CON_SET,
MT8196_SPM_BUS_PROTECT_CON_CLR,
MT8196_SPM_BUS_PROTECT_RDY),
},
.caps = MTK_SCPD_ALWAYS_ON,
.rtff_type = SCPSYS_RTFF_TYPE_GENERIC,
},
[MT8196_POWER_DOMAIN_SSUSB_P1] = {
.name = "ssusb-p1",
.sta_mask = MT8196_PWR_ACK,
.sta2nd_mask = MT8196_PWR_ACK_2ND,
.ctl_offs = 0xe20,
.pwr_sta_offs = 0xe20,
.pwr_sta2nd_offs = 0xe20,
.sram_pdn_bits = BIT(8),
.sram_pdn_ack_bits = BIT(12),
.bp_cfg = {
BUS_PROT_WR_IGN(SPM, MT8196_SPM_PROT_EN_BUS_SSUSB_P1,
MT8196_SPM_BUS_PROTECT_CON_SET,
MT8196_SPM_BUS_PROTECT_CON_CLR,
MT8196_SPM_BUS_PROTECT_RDY),
},
.caps = MTK_SCPD_ALWAYS_ON,
.rtff_type = SCPSYS_RTFF_TYPE_GENERIC,
},
[MT8196_POWER_DOMAIN_SSUSB_P23] = {
.name = "ssusb-p23",
.sta_mask = MT8196_PWR_ACK,
.sta2nd_mask = MT8196_PWR_ACK_2ND,
.ctl_offs = 0xe24,
.pwr_sta_offs = 0xe24,
.pwr_sta2nd_offs = 0xe24,
.bp_cfg = {
BUS_PROT_WR_IGN(SPM, MT8196_SPM_PROT_EN_BUS_SSUSB_P23,
MT8196_SPM_BUS_PROTECT_CON_SET,
MT8196_SPM_BUS_PROTECT_CON_CLR,
MT8196_SPM_BUS_PROTECT_RDY),
},
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
.rtff_type = SCPSYS_RTFF_TYPE_GENERIC,
},
[MT8196_POWER_DOMAIN_SSUSB_PHY_P2] = {
.name = "ssusb-phy-p2",
.sta_mask = MT8196_PWR_ACK,
.sta2nd_mask = MT8196_PWR_ACK_2ND,
.ctl_offs = 0xe28,
.pwr_sta_offs = 0xe28,
.pwr_sta2nd_offs = 0xe28,
.sram_pdn_bits = BIT(8),
.sram_pdn_ack_bits = BIT(12),
.bp_cfg = {
BUS_PROT_WR_IGN(SPM, MT8196_SPM_PROT_EN_BUS_SSUSB_PHY_P2,
MT8196_SPM_BUS_PROTECT_CON_SET,
MT8196_SPM_BUS_PROTECT_CON_CLR,
MT8196_SPM_BUS_PROTECT_RDY),
},
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
.rtff_type = SCPSYS_RTFF_TYPE_GENERIC,
},
[MT8196_POWER_DOMAIN_PEXTP_MAC0] = {
.name = "pextp-mac0",
.sta_mask = MT8196_PWR_ACK,
.sta2nd_mask = MT8196_PWR_ACK_2ND,
.ctl_offs = 0xe34,
.pwr_sta_offs = 0xe34,
.pwr_sta2nd_offs = 0xe34,
.sram_pdn_bits = BIT(8),
.sram_pdn_ack_bits = BIT(12),
.bp_cfg = {
BUS_PROT_WR_IGN(SPM, MT8196_SPM_PROT_EN_BUS_PEXTP_MAC0,
MT8196_SPM_BUS_PROTECT_CON_SET,
MT8196_SPM_BUS_PROTECT_CON_CLR,
MT8196_SPM_BUS_PROTECT_RDY),
},
.rtff_type = SCPSYS_RTFF_TYPE_PCIE_PHY,
},
[MT8196_POWER_DOMAIN_PEXTP_MAC1] = {
.name = "pextp-mac1",
.sta_mask = MT8196_PWR_ACK,
.sta2nd_mask = MT8196_PWR_ACK_2ND,
.ctl_offs = 0xe38,
.pwr_sta_offs = 0xe38,
.pwr_sta2nd_offs = 0xe38,
.sram_pdn_bits = BIT(8),
.sram_pdn_ack_bits = BIT(12),
.bp_cfg = {
BUS_PROT_WR_IGN(SPM, MT8196_SPM_PROT_EN_BUS_PEXTP_MAC1,
MT8196_SPM_BUS_PROTECT_CON_SET,
MT8196_SPM_BUS_PROTECT_CON_CLR,
MT8196_SPM_BUS_PROTECT_RDY),
},
.rtff_type = SCPSYS_RTFF_TYPE_PCIE_PHY,
},
[MT8196_POWER_DOMAIN_PEXTP_MAC2] = {
.name = "pextp-mac2",
.sta_mask = MT8196_PWR_ACK,
.sta2nd_mask = MT8196_PWR_ACK_2ND,
.ctl_offs = 0xe3c,
.pwr_sta_offs = 0xe3c,
.pwr_sta2nd_offs = 0xe3c,
.sram_pdn_bits = BIT(8),
.sram_pdn_ack_bits = BIT(12),
.bp_cfg = {
BUS_PROT_WR_IGN(SPM, MT8196_SPM_PROT_EN_BUS_PEXTP_MAC2,
MT8196_SPM_BUS_PROTECT_CON_SET,
MT8196_SPM_BUS_PROTECT_CON_CLR,
MT8196_SPM_BUS_PROTECT_RDY),
},
.rtff_type = SCPSYS_RTFF_TYPE_PCIE_PHY,
},
[MT8196_POWER_DOMAIN_PEXTP_PHY0] = {
.name = "pextp-phy0",
.sta_mask = MT8196_PWR_ACK,
.sta2nd_mask = MT8196_PWR_ACK_2ND,
.ctl_offs = 0xe40,
.pwr_sta_offs = 0xe40,
.pwr_sta2nd_offs = 0xe40,
.bp_cfg = {
BUS_PROT_WR_IGN(SPM, MT8196_SPM_PROT_EN_BUS_PEXTP_PHY0,
MT8196_SPM_BUS_PROTECT_CON_SET,
MT8196_SPM_BUS_PROTECT_CON_CLR,
MT8196_SPM_BUS_PROTECT_RDY),
},
.rtff_type = SCPSYS_RTFF_TYPE_PCIE_PHY,
},
[MT8196_POWER_DOMAIN_PEXTP_PHY1] = {
.name = "pextp-phy1",
.sta_mask = MT8196_PWR_ACK,
.sta2nd_mask = MT8196_PWR_ACK_2ND,
.ctl_offs = 0xe44,
.pwr_sta_offs = 0xe44,
.pwr_sta2nd_offs = 0xe44,
.bp_cfg = {
BUS_PROT_WR_IGN(SPM, MT8196_SPM_PROT_EN_BUS_PEXTP_PHY1,
MT8196_SPM_BUS_PROTECT_CON_SET,
MT8196_SPM_BUS_PROTECT_CON_CLR,
MT8196_SPM_BUS_PROTECT_RDY),
},
.rtff_type = SCPSYS_RTFF_TYPE_PCIE_PHY,
},
[MT8196_POWER_DOMAIN_PEXTP_PHY2] = {
.name = "pextp-phy2",
.sta_mask = MT8196_PWR_ACK,
.sta2nd_mask = MT8196_PWR_ACK_2ND,
.ctl_offs = 0xe48,
.pwr_sta_offs = 0xe48,
.pwr_sta2nd_offs = 0xe48,
.bp_cfg = {
BUS_PROT_WR_IGN(SPM, MT8196_SPM_PROT_EN_BUS_PEXTP_PHY2,
MT8196_SPM_BUS_PROTECT_CON_SET,
MT8196_SPM_BUS_PROTECT_CON_CLR,
MT8196_SPM_BUS_PROTECT_RDY),
},
.rtff_type = SCPSYS_RTFF_TYPE_PCIE_PHY,
},
[MT8196_POWER_DOMAIN_AUDIO] = {
.name = "audio",
.sta_mask = MT8196_PWR_ACK,
.sta2nd_mask = MT8196_PWR_ACK_2ND,
.ctl_offs = 0xe4c,
.pwr_sta_offs = 0xe4c,
.pwr_sta2nd_offs = 0xe4c,
.sram_pdn_bits = BIT(8),
.sram_pdn_ack_bits = BIT(12),
.bp_cfg = {
BUS_PROT_WR_IGN(SPM, MT8196_SPM_PROT_EN_BUS_AUDIO,
MT8196_SPM_BUS_PROTECT_CON_SET,
MT8196_SPM_BUS_PROTECT_CON_CLR,
MT8196_SPM_BUS_PROTECT_RDY),
},
.rtff_type = SCPSYS_RTFF_TYPE_GENERIC,
},
[MT8196_POWER_DOMAIN_ADSP_TOP_DORMANT] = {
.name = "adsp-top-dormant",
.sta_mask = MT8196_PWR_ACK,
.sta2nd_mask = MT8196_PWR_ACK_2ND,
.ctl_offs = 0xe54,
.pwr_sta_offs = 0xe54,
.pwr_sta2nd_offs = 0xe54,
/* Note: This is not managing powerdown (pdn), but sleep instead (slp) */
.sram_pdn_bits = BIT(9),
.sram_pdn_ack_bits = BIT(13),
.bp_cfg = {
BUS_PROT_WR_IGN(SPM, MT8196_SPM_PROT_EN_BUS_ADSP_TOP,
MT8196_SPM_BUS_PROTECT_CON_SET,
MT8196_SPM_BUS_PROTECT_CON_CLR,
MT8196_SPM_BUS_PROTECT_RDY),
},
.caps = MTK_SCPD_SRAM_ISO | MTK_SCPD_SRAM_PDN_INVERTED,
},
[MT8196_POWER_DOMAIN_ADSP_INFRA] = {
.name = "adsp-infra",
.sta_mask = MT8196_PWR_ACK,
.sta2nd_mask = MT8196_PWR_ACK_2ND,
.ctl_offs = 0xe58,
.pwr_sta_offs = 0xe58,
.pwr_sta2nd_offs = 0xe58,
.bp_cfg = {
BUS_PROT_WR_IGN(SPM, MT8196_SPM_PROT_EN_BUS_ADSP_INFRA,
MT8196_SPM_BUS_PROTECT_CON_SET,
MT8196_SPM_BUS_PROTECT_CON_CLR,
MT8196_SPM_BUS_PROTECT_RDY),
},
.caps = MTK_SCPD_ALWAYS_ON,
.rtff_type = SCPSYS_RTFF_TYPE_GENERIC,
},
[MT8196_POWER_DOMAIN_ADSP_AO] = {
.name = "adsp-ao",
.sta_mask = MT8196_PWR_ACK,
.sta2nd_mask = MT8196_PWR_ACK_2ND,
.ctl_offs = 0xe5c,
.pwr_sta_offs = 0xe5c,
.pwr_sta2nd_offs = 0xe5c,
.bp_cfg = {
BUS_PROT_WR_IGN(SPM, MT8196_SPM_PROT_EN_BUS_ADSP_AO,
MT8196_SPM_BUS_PROTECT_CON_SET,
MT8196_SPM_BUS_PROTECT_CON_CLR,
MT8196_SPM_BUS_PROTECT_RDY),
},
.caps = MTK_SCPD_ALWAYS_ON,
.rtff_type = SCPSYS_RTFF_TYPE_GENERIC,
},
};
static const struct scpsys_hwv_domain_data scpsys_hwv_domain_data_mt8196[] = {
[MT8196_POWER_DOMAIN_MM_PROC_DORMANT] = {
.name = "mm-proc-dormant",
.set = 0x0218,
.clr = 0x021c,
.done = 0x141c,
.en = 0x1410,
.set_sta = 0x146c,
.clr_sta = 0x1470,
.setclr_bit = 0,
.caps = MTK_SCPD_ALWAYS_ON,
},
[MT8196_POWER_DOMAIN_SSR] = {
.name = "ssrsys",
.set = 0x0218,
.clr = 0x021c,
.done = 0x141c,
.en = 0x1410,
.set_sta = 0x146c,
.clr_sta = 0x1470,
.setclr_bit = 1,
},
};
static const struct scpsys_hwv_domain_data hfrpsys_hwv_domain_data_mt8196[] = {
[MT8196_POWER_DOMAIN_VDE0] = {
.name = "vde0",
.set = 0x0218,
.clr = 0x021C,
.done = 0x141C,
.en = 0x1410,
.set_sta = 0x146C,
.clr_sta = 0x1470,
.setclr_bit = 7,
},
[MT8196_POWER_DOMAIN_VDE1] = {
.name = "vde1",
.set = 0x0218,
.clr = 0x021C,
.done = 0x141C,
.en = 0x1410,
.set_sta = 0x146C,
.clr_sta = 0x1470,
.setclr_bit = 8,
},
[MT8196_POWER_DOMAIN_VDE_VCORE0] = {
.name = "vde-vcore0",
.set = 0x0218,
.clr = 0x021C,
.done = 0x141C,
.en = 0x1410,
.set_sta = 0x146C,
.clr_sta = 0x1470,
.setclr_bit = 9,
},
[MT8196_POWER_DOMAIN_VEN0] = {
.name = "ven0",
.set = 0x0218,
.clr = 0x021C,
.done = 0x141C,
.en = 0x1410,
.set_sta = 0x146C,
.clr_sta = 0x1470,
.setclr_bit = 10,
},
[MT8196_POWER_DOMAIN_VEN1] = {
.name = "ven1",
.set = 0x0218,
.clr = 0x021C,
.done = 0x141C,
.en = 0x1410,
.set_sta = 0x146C,
.clr_sta = 0x1470,
.setclr_bit = 11,
},
[MT8196_POWER_DOMAIN_VEN2] = {
.name = "ven2",
.set = 0x0218,
.clr = 0x021C,
.done = 0x141C,
.en = 0x1410,
.set_sta = 0x146C,
.clr_sta = 0x1470,
.setclr_bit = 12,
},
[MT8196_POWER_DOMAIN_DISP_VCORE] = {
.name = "disp-vcore",
.set = 0x0218,
.clr = 0x021C,
.done = 0x141C,
.en = 0x1410,
.set_sta = 0x146C,
.clr_sta = 0x1470,
.setclr_bit = 24,
},
[MT8196_POWER_DOMAIN_DIS0_DORMANT] = {
.name = "dis0-dormant",
.set = 0x0218,
.clr = 0x021C,
.done = 0x141C,
.en = 0x1410,
.set_sta = 0x146C,
.clr_sta = 0x1470,
.setclr_bit = 25,
},
[MT8196_POWER_DOMAIN_DIS1_DORMANT] = {
.name = "dis1-dormant",
.set = 0x0218,
.clr = 0x021C,
.done = 0x141C,
.en = 0x1410,
.set_sta = 0x146C,
.clr_sta = 0x1470,
.setclr_bit = 26,
},
[MT8196_POWER_DOMAIN_OVL0_DORMANT] = {
.name = "ovl0-dormant",
.set = 0x0218,
.clr = 0x021C,
.done = 0x141C,
.en = 0x1410,
.set_sta = 0x146C,
.clr_sta = 0x1470,
.setclr_bit = 27,
},
[MT8196_POWER_DOMAIN_OVL1_DORMANT] = {
.name = "ovl1-dormant",
.set = 0x0218,
.clr = 0x021C,
.done = 0x141C,
.en = 0x1410,
.set_sta = 0x146C,
.clr_sta = 0x1470,
.setclr_bit = 28,
},
[MT8196_POWER_DOMAIN_DISP_EDPTX_DORMANT] = {
.name = "disp-edptx-dormant",
.set = 0x0218,
.clr = 0x021C,
.done = 0x141C,
.en = 0x1410,
.set_sta = 0x146C,
.clr_sta = 0x1470,
.setclr_bit = 29,
},
[MT8196_POWER_DOMAIN_DISP_DPTX_DORMANT] = {
.name = "disp-dptx-dormant",
.set = 0x0218,
.clr = 0x021C,
.done = 0x141C,
.en = 0x1410,
.set_sta = 0x146C,
.clr_sta = 0x1470,
.setclr_bit = 30,
},
[MT8196_POWER_DOMAIN_MML0_SHUTDOWN] = {
.name = "mml0-shutdown",
.set = 0x0218,
.clr = 0x021C,
.done = 0x141C,
.en = 0x1410,
.set_sta = 0x146C,
.clr_sta = 0x1470,
.setclr_bit = 31,
},
[MT8196_POWER_DOMAIN_MML1_SHUTDOWN] = {
.name = "mml1-shutdown",
.set = 0x0220,
.clr = 0x0224,
.done = 0x142C,
.en = 0x1420,
.set_sta = 0x1474,
.clr_sta = 0x1478,
.setclr_bit = 0,
},
[MT8196_POWER_DOMAIN_MM_INFRA0] = {
.name = "mm-infra0",
.set = 0x0220,
.clr = 0x0224,
.done = 0x142C,
.en = 0x1420,
.set_sta = 0x1474,
.clr_sta = 0x1478,
.setclr_bit = 1,
},
[MT8196_POWER_DOMAIN_MM_INFRA1] = {
.name = "mm-infra1",
.set = 0x0220,
.clr = 0x0224,
.done = 0x142C,
.en = 0x1420,
.set_sta = 0x1474,
.clr_sta = 0x1478,
.setclr_bit = 2,
},
[MT8196_POWER_DOMAIN_MM_INFRA_AO] = {
.name = "mm-infra-ao",
.set = 0x0220,
.clr = 0x0224,
.done = 0x142C,
.en = 0x1420,
.set_sta = 0x1474,
.clr_sta = 0x1478,
.setclr_bit = 3,
},
[MT8196_POWER_DOMAIN_CSI_BS_RX] = {
.name = "csi-bs-rx",
.set = 0x0220,
.clr = 0x0224,
.done = 0x142C,
.en = 0x1420,
.set_sta = 0x1474,
.clr_sta = 0x1478,
.setclr_bit = 5,
},
[MT8196_POWER_DOMAIN_CSI_LS_RX] = {
.name = "csi-ls-rx",
.set = 0x0220,
.clr = 0x0224,
.done = 0x142C,
.en = 0x1420,
.set_sta = 0x1474,
.clr_sta = 0x1478,
.setclr_bit = 6,
},
[MT8196_POWER_DOMAIN_DSI_PHY0] = {
.name = "dsi-phy0",
.set = 0x0220,
.clr = 0x0224,
.done = 0x142C,
.en = 0x1420,
.set_sta = 0x1474,
.clr_sta = 0x1478,
.setclr_bit = 7,
},
[MT8196_POWER_DOMAIN_DSI_PHY1] = {
.name = "dsi-phy1",
.set = 0x0220,
.clr = 0x0224,
.done = 0x142C,
.en = 0x1420,
.set_sta = 0x1474,
.clr_sta = 0x1478,
.setclr_bit = 8,
},
[MT8196_POWER_DOMAIN_DSI_PHY2] = {
.name = "dsi-phy2",
.set = 0x0220,
.clr = 0x0224,
.done = 0x142C,
.en = 0x1420,
.set_sta = 0x1474,
.clr_sta = 0x1478,
.setclr_bit = 9,
},
};
static const struct scpsys_soc_data mt8196_scpsys_data = {
.domains_data = scpsys_domain_data_mt8196,
.num_domains = ARRAY_SIZE(scpsys_domain_data_mt8196),
.bus_prot_blocks = scpsys_bus_prot_blocks_mt8196,
.num_bus_prot_blocks = ARRAY_SIZE(scpsys_bus_prot_blocks_mt8196),
.type = SCPSYS_MTCMOS_TYPE_DIRECT_CTL,
};
static const struct scpsys_soc_data mt8196_scpsys_hwv_data = {
.hwv_domains_data = scpsys_hwv_domain_data_mt8196,
.num_hwv_domains = ARRAY_SIZE(scpsys_hwv_domain_data_mt8196),
.type = SCPSYS_MTCMOS_TYPE_HW_VOTER,
};
static const struct scpsys_soc_data mt8196_hfrpsys_hwv_data = {
.hwv_domains_data = hfrpsys_hwv_domain_data_mt8196,
.num_hwv_domains = ARRAY_SIZE(hfrpsys_hwv_domain_data_mt8196),
.type = SCPSYS_MTCMOS_TYPE_HW_VOTER,
};
#endif /* __SOC_MEDIATEK_MT8196_PM_DOMAINS_H */

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,7 @@
/*
* Copyright (c) 2020 Collabora Ltd.
*/
#include <linux/arm-smccc.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/init.h>
@ -15,6 +16,7 @@
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/soc/mediatek/infracfg.h>
#include <linux/soc/mediatek/mtk_sip_svc.h>
#include "mt6735-pm-domains.h"
#include "mt6795-pm-domains.h"
@ -26,11 +28,18 @@
#include "mt8188-pm-domains.h"
#include "mt8192-pm-domains.h"
#include "mt8195-pm-domains.h"
#include "mt8196-pm-domains.h"
#include "mt8365-pm-domains.h"
#define MTK_POLL_DELAY_US 10
#define MTK_POLL_TIMEOUT USEC_PER_SEC
#define MTK_HWV_POLL_DELAY_US 5
#define MTK_HWV_POLL_TIMEOUT (300 * USEC_PER_MSEC)
#define MTK_HWV_PREPARE_DELAY_US 1
#define MTK_HWV_PREPARE_TIMEOUT (3 * USEC_PER_MSEC)
#define PWR_RST_B_BIT BIT(0)
#define PWR_ISO_BIT BIT(1)
#define PWR_ON_BIT BIT(2)
@ -45,9 +54,12 @@
#define PWR_RTFF_SAVE_FLAG BIT(27)
#define PWR_RTFF_UFS_CLK_DIS BIT(28)
#define MTK_SIP_KERNEL_HWCCF_CONTROL MTK_SIP_SMC_CMD(0x540)
struct scpsys_domain {
struct generic_pm_domain genpd;
const struct scpsys_domain_data *data;
const struct scpsys_hwv_domain_data *hwv_data;
struct scpsys *scpsys;
int num_clks;
struct clk_bulk_data *clks;
@ -71,18 +83,56 @@ struct scpsys {
static bool scpsys_domain_is_on(struct scpsys_domain *pd)
{
struct scpsys *scpsys = pd->scpsys;
u32 status, status2;
u32 mask = pd->data->sta_mask;
u32 status, status2, mask2;
mask2 = pd->data->sta2nd_mask ? pd->data->sta2nd_mask : mask;
regmap_read(scpsys->base, pd->data->pwr_sta_offs, &status);
status &= pd->data->sta_mask;
status &= mask;
regmap_read(scpsys->base, pd->data->pwr_sta2nd_offs, &status2);
status2 &= pd->data->sta_mask;
status2 &= mask2;
/* A domain is on when both status bits are set. */
return status && status2;
}
static bool scpsys_hwv_domain_is_disable_done(struct scpsys_domain *pd)
{
const struct scpsys_hwv_domain_data *hwv = pd->hwv_data;
u32 regs[2] = { hwv->done, hwv->clr_sta };
u32 val[2];
u32 mask = BIT(hwv->setclr_bit);
regmap_multi_reg_read(pd->scpsys->base, regs, val, 2);
/* Disable is done when the bit is set in DONE, cleared in CLR_STA */
return (val[0] & mask) && !(val[1] & mask);
}
static bool scpsys_hwv_domain_is_enable_done(struct scpsys_domain *pd)
{
const struct scpsys_hwv_domain_data *hwv = pd->hwv_data;
u32 regs[3] = { hwv->done, hwv->en, hwv->set_sta };
u32 val[3];
u32 mask = BIT(hwv->setclr_bit);
regmap_multi_reg_read(pd->scpsys->base, regs, val, 3);
/* Enable is done when the bit is set in DONE and EN, cleared in SET_STA */
return (val[0] & mask) && (val[1] & mask) && !(val[2] & mask);
}
static int scpsys_sec_infra_power_on(bool on)
{
struct arm_smccc_res res;
unsigned long cmd = on ? 1 : 0;
arm_smccc_smc(MTK_SIP_KERNEL_HWCCF_CONTROL, cmd, 0, 0, 0, 0, 0, 0, &res);
return res.a0;
}
static int scpsys_sram_enable(struct scpsys_domain *pd)
{
u32 expected_ack, pdn_ack = pd->data->sram_pdn_ack_bits;
@ -250,6 +300,161 @@ static int scpsys_regulator_disable(struct regulator *supply)
return supply ? regulator_disable(supply) : 0;
}
static int scpsys_hwv_power_on(struct generic_pm_domain *genpd)
{
struct scpsys_domain *pd = container_of(genpd, struct scpsys_domain, genpd);
const struct scpsys_hwv_domain_data *hwv = pd->hwv_data;
struct scpsys *scpsys = pd->scpsys;
u32 val;
int ret;
if (MTK_SCPD_CAPS(pd, MTK_SCPD_INFRA_PWR_CTL)) {
ret = scpsys_sec_infra_power_on(true);
if (ret)
return ret;
}
ret = scpsys_regulator_enable(pd->supply);
if (ret)
goto err_infra;
ret = clk_bulk_prepare_enable(pd->num_clks, pd->clks);
if (ret)
goto err_reg;
/* For HWV the subsys clocks refer to the HWV low power subsystem */
ret = clk_bulk_prepare_enable(pd->num_subsys_clks, pd->subsys_clks);
if (ret)
goto err_disable_clks;
/* Make sure the HW Voter is idle and able to accept commands */
ret = regmap_read_poll_timeout_atomic(scpsys->base, hwv->done, val,
val & BIT(hwv->setclr_bit),
MTK_HWV_POLL_DELAY_US,
MTK_HWV_POLL_TIMEOUT);
if (ret) {
dev_err(scpsys->dev, "Failed to power on: HW Voter busy.\n");
goto err_disable_subsys_clks;
}
/*
* Instruct the HWV to power on the MTCMOS (power domain): after that,
* the same bit will be unset immediately by the hardware.
*/
regmap_write(scpsys->base, hwv->set, BIT(hwv->setclr_bit));
/*
* Wait until the HWV sets the bit again, signalling that its internal
* state machine was started and it now processing the vote command.
*/
ret = regmap_read_poll_timeout_atomic(scpsys->base, hwv->set, val,
val & BIT(hwv->setclr_bit),
MTK_HWV_PREPARE_DELAY_US,
MTK_HWV_PREPARE_TIMEOUT);
if (ret) {
dev_err(scpsys->dev, "Failed to power on: HW Voter not starting.\n");
goto err_disable_subsys_clks;
}
/* Wait for ACK, signalling that the MTCMOS was enabled */
ret = readx_poll_timeout_atomic(scpsys_hwv_domain_is_enable_done, pd, val, val,
MTK_HWV_POLL_DELAY_US, MTK_HWV_POLL_TIMEOUT);
if (ret) {
dev_err(scpsys->dev, "Failed to power on: HW Voter ACK timeout.\n");
goto err_disable_subsys_clks;
}
/* It's done! Disable the HWV low power subsystem clocks */
clk_bulk_disable_unprepare(pd->num_subsys_clks, pd->subsys_clks);
if (MTK_SCPD_CAPS(pd, MTK_SCPD_INFRA_PWR_CTL))
scpsys_sec_infra_power_on(false);
return 0;
err_disable_subsys_clks:
clk_bulk_disable_unprepare(pd->num_subsys_clks, pd->subsys_clks);
err_disable_clks:
clk_bulk_disable_unprepare(pd->num_clks, pd->clks);
err_reg:
scpsys_regulator_disable(pd->supply);
err_infra:
if (MTK_SCPD_CAPS(pd, MTK_SCPD_INFRA_PWR_CTL))
scpsys_sec_infra_power_on(false);
return ret;
};
static int scpsys_hwv_power_off(struct generic_pm_domain *genpd)
{
struct scpsys_domain *pd = container_of(genpd, struct scpsys_domain, genpd);
const struct scpsys_hwv_domain_data *hwv = pd->hwv_data;
struct scpsys *scpsys = pd->scpsys;
u32 val;
int ret;
if (MTK_SCPD_CAPS(pd, MTK_SCPD_INFRA_PWR_CTL)) {
ret = scpsys_sec_infra_power_on(true);
if (ret)
return ret;
}
ret = clk_bulk_prepare_enable(pd->num_subsys_clks, pd->subsys_clks);
if (ret)
goto err_infra;
/* Make sure the HW Voter is idle and able to accept commands */
ret = regmap_read_poll_timeout_atomic(scpsys->base, hwv->done, val,
val & BIT(hwv->setclr_bit),
MTK_HWV_POLL_DELAY_US,
MTK_HWV_POLL_TIMEOUT);
if (ret)
goto err_disable_subsys_clks;
/*
* Instruct the HWV to power off the MTCMOS (power domain): differently
* from poweron, the bit will be kept set.
*/
regmap_write(scpsys->base, hwv->clr, BIT(hwv->setclr_bit));
/*
* Wait until the HWV clears the bit, signalling that its internal
* state machine was started and it now processing the clear command.
*/
ret = regmap_read_poll_timeout_atomic(scpsys->base, hwv->clr, val,
!(val & BIT(hwv->setclr_bit)),
MTK_HWV_PREPARE_DELAY_US,
MTK_HWV_PREPARE_TIMEOUT);
if (ret)
goto err_disable_subsys_clks;
/* Poweroff needs 100us for the HW to stabilize */
udelay(100);
/* Wait for ACK, signalling that the MTCMOS was disabled */
ret = readx_poll_timeout_atomic(scpsys_hwv_domain_is_disable_done, pd, val, val,
MTK_HWV_POLL_DELAY_US, MTK_HWV_POLL_TIMEOUT);
if (ret)
goto err_disable_subsys_clks;
clk_bulk_disable_unprepare(pd->num_subsys_clks, pd->subsys_clks);
clk_bulk_disable_unprepare(pd->num_clks, pd->clks);
scpsys_regulator_disable(pd->supply);
if (MTK_SCPD_CAPS(pd, MTK_SCPD_INFRA_PWR_CTL))
scpsys_sec_infra_power_on(false);
return 0;
err_disable_subsys_clks:
clk_bulk_disable_unprepare(pd->num_subsys_clks, pd->subsys_clks);
err_infra:
if (MTK_SCPD_CAPS(pd, MTK_SCPD_INFRA_PWR_CTL))
scpsys_sec_infra_power_on(false);
return ret;
};
static int scpsys_ctl_pwrseq_on(struct scpsys_domain *pd)
{
struct scpsys *scpsys = pd->scpsys;
@ -514,6 +719,7 @@ static struct
generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_node *node)
{
const struct scpsys_domain_data *domain_data;
const struct scpsys_hwv_domain_data *hwv_domain_data;
struct scpsys_domain *pd;
struct property *prop;
const char *clk_name;
@ -529,14 +735,33 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no
return ERR_PTR(-EINVAL);
}
if (id >= scpsys->soc_data->num_domains) {
dev_err(scpsys->dev, "%pOF: invalid domain id %d\n", node, id);
return ERR_PTR(-EINVAL);
}
switch (scpsys->soc_data->type) {
case SCPSYS_MTCMOS_TYPE_DIRECT_CTL:
if (id >= scpsys->soc_data->num_domains) {
dev_err(scpsys->dev, "%pOF: invalid domain id %d\n", node, id);
return ERR_PTR(-EINVAL);
}
domain_data = &scpsys->soc_data->domains_data[id];
if (domain_data->sta_mask == 0) {
dev_err(scpsys->dev, "%pOF: undefined domain id %d\n", node, id);
domain_data = &scpsys->soc_data->domains_data[id];
hwv_domain_data = NULL;
if (domain_data->sta_mask == 0) {
dev_err(scpsys->dev, "%pOF: undefined domain id %d\n", node, id);
return ERR_PTR(-EINVAL);
}
break;
case SCPSYS_MTCMOS_TYPE_HW_VOTER:
if (id >= scpsys->soc_data->num_hwv_domains) {
dev_err(scpsys->dev, "%pOF: invalid HWV domain id %d\n", node, id);
return ERR_PTR(-EINVAL);
}
domain_data = NULL;
hwv_domain_data = &scpsys->soc_data->hwv_domains_data[id];
break;
default:
return ERR_PTR(-EINVAL);
}
@ -545,6 +770,7 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no
return ERR_PTR(-ENOMEM);
pd->data = domain_data;
pd->hwv_data = hwv_domain_data;
pd->scpsys = scpsys;
if (MTK_SCPD_CAPS(pd, MTK_SCPD_DOMAIN_SUPPLY)) {
@ -604,6 +830,31 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no
pd->subsys_clks[i].clk = clk;
}
if (scpsys->domains[id]) {
ret = -EINVAL;
dev_err(scpsys->dev,
"power domain with id %d already exists, check your device-tree\n", id);
goto err_put_subsys_clocks;
}
if (pd->data && pd->data->name)
pd->genpd.name = pd->data->name;
else if (pd->hwv_data && pd->hwv_data->name)
pd->genpd.name = pd->hwv_data->name;
else
pd->genpd.name = node->name;
if (scpsys->soc_data->type == SCPSYS_MTCMOS_TYPE_DIRECT_CTL) {
pd->genpd.power_off = scpsys_power_off;
pd->genpd.power_on = scpsys_power_on;
} else {
pd->genpd.power_off = scpsys_hwv_power_off;
pd->genpd.power_on = scpsys_hwv_power_on;
/* HW-Voter code can be invoked in atomic context */
pd->genpd.flags |= GENPD_FLAG_IRQ_SAFE;
}
/*
* Initially turn on all domains to make the domains usable
* with !CONFIG_PM and to get the hardware in sync with the
@ -615,7 +866,7 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no
dev_warn(scpsys->dev,
"%pOF: A default off power domain has been ON\n", node);
} else {
ret = scpsys_power_on(&pd->genpd);
ret = pd->genpd.power_on(&pd->genpd);
if (ret < 0) {
dev_err(scpsys->dev, "%pOF: failed to power on domain: %d\n", node, ret);
goto err_put_subsys_clocks;
@ -625,21 +876,6 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no
pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON;
}
if (scpsys->domains[id]) {
ret = -EINVAL;
dev_err(scpsys->dev,
"power domain with id %d already exists, check your device-tree\n", id);
goto err_put_subsys_clocks;
}
if (!pd->data->name)
pd->genpd.name = node->name;
else
pd->genpd.name = pd->data->name;
pd->genpd.power_off = scpsys_power_off;
pd->genpd.power_on = scpsys_power_on;
if (MTK_SCPD_CAPS(pd, MTK_SCPD_ACTIVE_WAKEUP))
pd->genpd.flags |= GENPD_FLAG_ACTIVE_WAKEUP;
@ -931,6 +1167,18 @@ static const struct of_device_id scpsys_of_match[] = {
.compatible = "mediatek,mt8195-power-controller",
.data = &mt8195_scpsys_data,
},
{
.compatible = "mediatek,mt8196-power-controller",
.data = &mt8196_scpsys_data,
},
{
.compatible = "mediatek,mt8196-hwv-hfrp-power-controller",
.data = &mt8196_hfrpsys_hwv_data,
},
{
.compatible = "mediatek,mt8196-hwv-scp-power-controller",
.data = &mt8196_scpsys_hwv_data,
},
{
.compatible = "mediatek,mt8365-power-controller",
.data = &mt8365_scpsys_data,
@ -946,7 +1194,7 @@ static int scpsys_probe(struct platform_device *pdev)
struct device_node *node;
struct device *parent;
struct scpsys *scpsys;
int ret;
int num_domains, ret;
soc = of_device_get_match_data(&pdev->dev);
if (!soc) {
@ -954,7 +1202,9 @@ static int scpsys_probe(struct platform_device *pdev)
return -EINVAL;
}
scpsys = devm_kzalloc(dev, struct_size(scpsys, domains, soc->num_domains), GFP_KERNEL);
num_domains = soc->num_domains + soc->num_hwv_domains;
scpsys = devm_kzalloc(dev, struct_size(scpsys, domains, num_domains), GFP_KERNEL);
if (!scpsys)
return -ENOMEM;

View File

@ -16,7 +16,10 @@
#define MTK_SCPD_SRAM_PDN_INVERTED BIT(9)
#define MTK_SCPD_MODEM_PWRSEQ BIT(10)
#define MTK_SCPD_SKIP_RESET_B BIT(11)
#define MTK_SCPD_CAPS(_scpd, _x) ((_scpd)->data->caps & (_x))
#define MTK_SCPD_INFRA_PWR_CTL BIT(12)
#define MTK_SCPD_CAPS(_scpd, _x) ((_scpd)->data ? \
(_scpd)->data->caps & (_x) : \
(_scpd)->hwv_data->caps & (_x))
#define SPM_VDE_PWR_CON 0x0210
#define SPM_MFG_PWR_CON 0x0214
@ -59,6 +62,7 @@ enum scpsys_bus_prot_block {
BUS_PROT_BLOCK_INFRA,
BUS_PROT_BLOCK_INFRA_NAO,
BUS_PROT_BLOCK_SMI,
BUS_PROT_BLOCK_SPM,
BUS_PROT_BLOCK_COUNT,
};
@ -124,10 +128,23 @@ enum scpsys_rtff_type {
SCPSYS_RTFF_TYPE_MAX
};
/**
* enum scpsys_mtcmos_type - Type of power domain controller
* @SCPSYS_MTCMOS_TYPE_DIRECT_CTL: Power domains are controlled with direct access
* @SCPSYS_MTCMOS_TYPE_HW_VOTER: Hardware-assisted voted power domain control
* @SCPSYS_MTCMOS_TYPE_MAX: Number of supported power domain types
*/
enum scpsys_mtcmos_type {
SCPSYS_MTCMOS_TYPE_DIRECT_CTL = 0,
SCPSYS_MTCMOS_TYPE_HW_VOTER,
SCPSYS_MTCMOS_TYPE_MAX
};
/**
* struct scpsys_domain_data - scp domain data for power on/off flow
* @name: The name of the power domain.
* @sta_mask: The mask for power on/off status bit.
* @sta2nd_mask: The mask for second power on/off status bit.
* @ctl_offs: The offset for main power control register.
* @sram_pdn_bits: The mask for sram power control bits.
* @sram_pdn_ack_bits: The mask for sram power control acked bits.
@ -140,6 +157,7 @@ enum scpsys_rtff_type {
struct scpsys_domain_data {
const char *name;
u32 sta_mask;
u32 sta2nd_mask;
int ctl_offs;
u32 sram_pdn_bits;
u32 sram_pdn_ack_bits;
@ -152,11 +170,40 @@ struct scpsys_domain_data {
int pwr_sta2nd_offs;
};
/**
* struct scpsys_hwv_domain_data - Hardware Voter power domain data
* @name: Name of the power domain
* @set: Offset of the HWV SET register
* @clr: Offset of the HWV CLEAR register
* @done: Offset of the HWV DONE register
* @en: Offset of the HWV ENABLE register
* @set_sta: Offset of the HWV SET STATUS register
* @clr_sta: Offset of the HWV CLEAR STATUS register
* @setclr_bit: The SET/CLR bit to enable/disable the power domain
* @sta_bit: The SET/CLR STA bit to check for on/off ACK
* @caps: The flag for active wake-up action
*/
struct scpsys_hwv_domain_data {
const char *name;
u16 set;
u16 clr;
u16 done;
u16 en;
u16 set_sta;
u16 clr_sta;
u8 setclr_bit;
u8 sta_bit;
u16 caps;
};
struct scpsys_soc_data {
const struct scpsys_domain_data *domains_data;
int num_domains;
const struct scpsys_hwv_domain_data *hwv_domains_data;
int num_hwv_domains;
enum scpsys_bus_prot_block *bus_prot_blocks;
int num_bus_prot_blocks;
enum scpsys_mtcmos_type type;
};
#endif /* __SOC_MEDIATEK_MTK_PM_DOMAINS_H */

View File

@ -19,7 +19,7 @@
#define domain_to_rpmhpd(domain) container_of(domain, struct rpmhpd, pd)
#define RPMH_ARC_MAX_LEVELS 16
#define RPMH_ARC_MAX_LEVELS 32
/**
* struct rpmhpd - top level RPMh power domain resource data structure
@ -595,6 +595,31 @@ static const struct rpmhpd_desc sm8750_desc = {
.num_pds = ARRAY_SIZE(sm8750_rpmhpds),
};
/* KAANAPALI RPMH powerdomains */
static struct rpmhpd *kaanapali_rpmhpds[] = {
[RPMHPD_CX] = &cx,
[RPMHPD_CX_AO] = &cx_ao,
[RPMHPD_EBI] = &ebi,
[RPMHPD_GFX] = &gfx,
[RPMHPD_GMXC] = &gmxc,
[RPMHPD_LCX] = &lcx,
[RPMHPD_LMX] = &lmx,
[RPMHPD_MX] = &mx,
[RPMHPD_MX_AO] = &mx_ao,
[RPMHPD_MMCX] = &mmcx,
[RPMHPD_MMCX_AO] = &mmcx_ao,
[RPMHPD_MSS] = &mss,
[RPMHPD_MXC] = &mxc,
[RPMHPD_MXC_AO] = &mxc_ao,
[RPMHPD_NSP] = &nsp,
[RPMHPD_NSP2] = &nsp2,
};
static const struct rpmhpd_desc kaanapali_desc = {
.rpmhpds = kaanapali_rpmhpds,
.num_pds = ARRAY_SIZE(kaanapali_rpmhpds),
};
/* QDU1000/QRU1000 RPMH powerdomains */
static struct rpmhpd *qdu1000_rpmhpds[] = {
[QDU1000_CX] = &cx,
@ -767,6 +792,7 @@ static const struct rpmhpd_desc qcs615_desc = {
static const struct of_device_id rpmhpd_match_table[] = {
{ .compatible = "qcom,glymur-rpmhpd", .data = &glymur_desc },
{ .compatible = "qcom,kaanapali-rpmhpd", .data = &kaanapali_desc },
{ .compatible = "qcom,milos-rpmhpd", .data = &milos_desc },
{ .compatible = "qcom,qcs615-rpmhpd", .data = &qcs615_desc },
{ .compatible = "qcom,qcs8300-rpmhpd", .data = &qcs8300_desc },

View File

@ -25,6 +25,7 @@
#include <soc/rockchip/rockchip_sip.h>
#include <dt-bindings/power/px30-power.h>
#include <dt-bindings/power/rockchip,rv1126-power.h>
#include <dt-bindings/power/rockchip,rv1126b-power-controller.h>
#include <dt-bindings/power/rk3036-power.h>
#include <dt-bindings/power/rk3066-power.h>
#include <dt-bindings/power/rk3128-power.h>
@ -137,6 +138,20 @@ struct rockchip_pmu {
.active_wakeup = wakeup, \
}
#define DOMAIN_M_G(_name, pwr, status, req, idle, ack, g_mask, wakeup, keepon) \
{ \
.name = _name, \
.pwr_w_mask = (pwr) << 16, \
.pwr_mask = (pwr), \
.status_mask = (status), \
.req_w_mask = (req) << 16, \
.req_mask = (req), \
.idle_mask = (idle), \
.ack_mask = (ack), \
.clk_ungate_mask = (g_mask), \
.active_wakeup = wakeup, \
}
#define DOMAIN_M_G_SD(_name, pwr, status, req, idle, ack, g_mask, mem, wakeup, keepon) \
{ \
.name = _name, \
@ -205,6 +220,9 @@ struct rockchip_pmu {
#define DOMAIN_RV1126(name, pwr, req, idle, wakeup) \
DOMAIN_M(name, pwr, pwr, req, idle, idle, wakeup)
#define DOMAIN_RV1126B(name, pwr, req, wakeup) \
DOMAIN_M_G(name, pwr, pwr, req, req, req, req, wakeup, true)
#define DOMAIN_RK3288(name, pwr, status, req, wakeup) \
DOMAIN(name, pwr, status, req, req, (req) << 16, wakeup)
@ -1104,6 +1122,13 @@ static const struct rockchip_domain_info rv1126_pm_domains[] = {
[RV1126_PD_USB] = DOMAIN_RV1126("usb", BIT(9), BIT(15), BIT(15), false),
};
static const struct rockchip_domain_info rv1126b_pm_domains[] = {
/* name pwr req wakeup */
[RV1126B_PD_NPU] = DOMAIN_RV1126B("npu", BIT(0), BIT(8), false),
[RV1126B_PD_VDO] = DOMAIN_RV1126B("vdo", BIT(1), BIT(9), false),
[RV1126B_PD_AIISP] = DOMAIN_RV1126B("aiisp", BIT(2), BIT(10), false),
};
static const struct rockchip_domain_info rk3036_pm_domains[] = {
[RK3036_PD_MSCH] = DOMAIN_RK3036("msch", BIT(14), BIT(23), BIT(30), true),
[RK3036_PD_CORE] = DOMAIN_RK3036("core", BIT(13), BIT(17), BIT(24), false),
@ -1516,6 +1541,18 @@ static const struct rockchip_pmu_info rv1126_pmu = {
.domain_info = rv1126_pm_domains,
};
static const struct rockchip_pmu_info rv1126b_pmu = {
.pwr_offset = 0x210,
.status_offset = 0x230,
.req_offset = 0x110,
.idle_offset = 0x128,
.ack_offset = 0x120,
.clk_ungate_offset = 0x140,
.num_domains = ARRAY_SIZE(rv1126b_pm_domains),
.domain_info = rv1126b_pm_domains,
};
static const struct of_device_id rockchip_pm_domain_dt_match[] = {
{
.compatible = "rockchip,px30-power-controller",
@ -1585,6 +1622,10 @@ static const struct of_device_id rockchip_pm_domain_dt_match[] = {
.compatible = "rockchip,rv1126-power-controller",
.data = (void *)&rv1126_pmu,
},
{
.compatible = "rockchip,rv1126b-power-controller",
.data = (void *)&rv1126b_pmu,
},
{ /* sentinel */ },
};

View File

@ -79,6 +79,10 @@ static const struct ci_hdrc_imx_platform_flag imx8ulp_usb_data = {
CI_HDRC_HAS_PORTSC_PEC_MISSED,
};
static const struct ci_hdrc_imx_platform_flag imx95_usb_data = {
.flags = CI_HDRC_SUPPORTS_RUNTIME_PM | CI_HDRC_OUT_BAND_WAKEUP,
};
static const struct ci_hdrc_imx_platform_flag s32g_usb_data = {
.flags = CI_HDRC_DISABLE_HOST_STREAMING,
};
@ -94,6 +98,7 @@ static const struct of_device_id ci_hdrc_imx_dt_ids[] = {
{ .compatible = "fsl,imx7d-usb", .data = &imx7d_usb_data},
{ .compatible = "fsl,imx7ulp-usb", .data = &imx7ulp_usb_data},
{ .compatible = "fsl,imx8ulp-usb", .data = &imx8ulp_usb_data},
{ .compatible = "fsl,imx95-usb", .data = &imx95_usb_data},
{ .compatible = "nxp,s32g2-usb", .data = &s32g_usb_data},
{ /* sentinel */ }
};
@ -704,9 +709,13 @@ static int ci_hdrc_imx_suspend(struct device *dev)
pinctrl_pm_select_sleep_state(dev);
if (data->wakeup_irq > 0 && device_may_wakeup(dev))
if (data->wakeup_irq > 0 && device_may_wakeup(dev)) {
enable_irq_wake(data->wakeup_irq);
if (data->plat_data->flags & CI_HDRC_OUT_BAND_WAKEUP)
device_set_out_band_wakeup(dev);
}
return ret;
}

View File

@ -27,6 +27,7 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/pm_domain.h>
#include <linux/pinctrl/consumer.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
@ -915,6 +916,8 @@ struct platform_device *ci_hdrc_add_device(struct device *dev,
if (ret)
goto err;
dev_pm_domain_detach(&pdev->dev, false);
return pdev;
err:

View File

@ -334,10 +334,15 @@ static int dwc3_imx8mp_pm_suspend(struct device *dev)
ret = dwc3_imx8mp_suspend(dwc3_imx, PMSG_SUSPEND);
if (device_may_wakeup(dwc3_imx->dev))
if (device_may_wakeup(dwc3_imx->dev)) {
enable_irq_wake(dwc3_imx->irq);
else
if (device_is_compatible(dev, "fsl,imx95-dwc3"))
device_set_out_band_wakeup(dev);
} else {
clk_disable_unprepare(dwc3_imx->suspend_clk);
}
clk_disable_unprepare(dwc3_imx->hsio_clk);
dev_dbg(dev, "dwc3 imx8mp pm suspend.\n");

View File

@ -0,0 +1,58 @@
/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
/*
* Copyright (c) 2025 Collabora Ltd
* AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
*/
#ifndef _DT_BINDINGS_POWER_MT8196_POWER_H
#define _DT_BINDINGS_POWER_MT8196_POWER_H
/* SCPSYS Secure Power Manager - Direct Control */
#define MT8196_POWER_DOMAIN_MD 0
#define MT8196_POWER_DOMAIN_CONN 1
#define MT8196_POWER_DOMAIN_SSUSB_P0 2
#define MT8196_POWER_DOMAIN_SSUSB_DP_PHY_P0 3
#define MT8196_POWER_DOMAIN_SSUSB_P1 4
#define MT8196_POWER_DOMAIN_SSUSB_P23 5
#define MT8196_POWER_DOMAIN_SSUSB_PHY_P2 6
#define MT8196_POWER_DOMAIN_PEXTP_MAC0 7
#define MT8196_POWER_DOMAIN_PEXTP_MAC1 8
#define MT8196_POWER_DOMAIN_PEXTP_MAC2 9
#define MT8196_POWER_DOMAIN_PEXTP_PHY0 10
#define MT8196_POWER_DOMAIN_PEXTP_PHY1 11
#define MT8196_POWER_DOMAIN_PEXTP_PHY2 12
#define MT8196_POWER_DOMAIN_AUDIO 13
#define MT8196_POWER_DOMAIN_ADSP_TOP_DORMANT 14
#define MT8196_POWER_DOMAIN_ADSP_INFRA 15
#define MT8196_POWER_DOMAIN_ADSP_AO 16
/* SCPSYS Secure Power Manager - HW Voter */
#define MT8196_POWER_DOMAIN_MM_PROC_DORMANT 0
#define MT8196_POWER_DOMAIN_SSR 1
/* HFRPSYS MultiMedia Power Control (MMPC) - HW Voter */
#define MT8196_POWER_DOMAIN_VDE0 0
#define MT8196_POWER_DOMAIN_VDE1 1
#define MT8196_POWER_DOMAIN_VDE_VCORE0 2
#define MT8196_POWER_DOMAIN_VEN0 3
#define MT8196_POWER_DOMAIN_VEN1 4
#define MT8196_POWER_DOMAIN_VEN2 5
#define MT8196_POWER_DOMAIN_DISP_VCORE 6
#define MT8196_POWER_DOMAIN_DIS0_DORMANT 7
#define MT8196_POWER_DOMAIN_DIS1_DORMANT 8
#define MT8196_POWER_DOMAIN_OVL0_DORMANT 9
#define MT8196_POWER_DOMAIN_OVL1_DORMANT 10
#define MT8196_POWER_DOMAIN_DISP_EDPTX_DORMANT 11
#define MT8196_POWER_DOMAIN_DISP_DPTX_DORMANT 12
#define MT8196_POWER_DOMAIN_MML0_SHUTDOWN 13
#define MT8196_POWER_DOMAIN_MML1_SHUTDOWN 14
#define MT8196_POWER_DOMAIN_MM_INFRA0 15
#define MT8196_POWER_DOMAIN_MM_INFRA1 16
#define MT8196_POWER_DOMAIN_MM_INFRA_AO 17
#define MT8196_POWER_DOMAIN_CSI_BS_RX 18
#define MT8196_POWER_DOMAIN_CSI_LS_RX 19
#define MT8196_POWER_DOMAIN_DSI_PHY0 20
#define MT8196_POWER_DOMAIN_DSI_PHY1 21
#define MT8196_POWER_DOMAIN_DSI_PHY2 22
#endif /* _DT_BINDINGS_POWER_MT8196_POWER_H */

View File

@ -33,11 +33,14 @@
#define RPMH_REGULATOR_LEVEL_RETENTION 16
#define RPMH_REGULATOR_LEVEL_MIN_SVS 48
#define RPMH_REGULATOR_LEVEL_LOW_SVS_D3 50
#define RPMH_REGULATOR_LEVEL_LOW_SVS_D2_1 51
#define RPMH_REGULATOR_LEVEL_LOW_SVS_D2 52
#define RPMH_REGULATOR_LEVEL_LOW_SVS_D1_1 54
#define RPMH_REGULATOR_LEVEL_LOW_SVS_D1 56
#define RPMH_REGULATOR_LEVEL_LOW_SVS_D0 60
#define RPMH_REGULATOR_LEVEL_LOW_SVS 64
#define RPMH_REGULATOR_LEVEL_LOW_SVS_P1 72
#define RPMH_REGULATOR_LEVEL_LOW_SVS_L0 76
#define RPMH_REGULATOR_LEVEL_LOW_SVS_L1 80
#define RPMH_REGULATOR_LEVEL_LOW_SVS_L2 96
#define RPMH_REGULATOR_LEVEL_SVS 128

View File

@ -0,0 +1,17 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */
/*
* Copyright (c) 2024 Rockchip Electronics Co., Ltd.
* Author: Finley Xiao <finley.xiao@rock-chips.com>
*/
#ifndef __DT_BINDINGS_POWER_RV1126B_POWER_CONTROLLER_H__
#define __DT_BINDINGS_POWER_RV1126B_POWER_CONTROLLER_H__
/* VD_NPU */
#define RV1126B_PD_NPU 0
/* VD_LOGIC */
#define RV1126B_PD_VDO 1
#define RV1126B_PD_AIISP 2
#endif

View File

@ -688,6 +688,7 @@ struct dev_pm_info {
bool smart_suspend:1; /* Owned by the PM core */
bool must_resume:1; /* Owned by the PM core */
bool may_skip_resume:1; /* Set by subsystems */
bool out_band_wakeup:1;
bool strict_midlayer:1;
#else
bool should_wakeup:1;

View File

@ -94,6 +94,16 @@ static inline void device_set_wakeup_path(struct device *dev)
dev->power.wakeup_path = true;
}
static inline void device_set_out_band_wakeup(struct device *dev)
{
dev->power.out_band_wakeup = true;
}
static inline bool device_out_band_wakeup(struct device *dev)
{
return dev->power.out_band_wakeup;
}
/* drivers/base/power/wakeup.c */
extern struct wakeup_source *wakeup_source_register(struct device *dev,
const char *name);
@ -162,6 +172,13 @@ static inline bool device_wakeup_path(struct device *dev)
static inline void device_set_wakeup_path(struct device *dev) {}
static inline void device_set_out_band_wakeup(struct device *dev) {}
static inline bool device_out_band_wakeup(struct device *dev)
{
return false;
}
static inline void __pm_stay_awake(struct wakeup_source *ws) {}
static inline void pm_stay_awake(struct device *dev) {}

View File

@ -168,6 +168,7 @@ int smp_call_function_any(const struct cpumask *mask,
void kick_all_cpus_sync(void);
void wake_up_all_idle_cpus(void);
bool cpus_peek_for_pending_ipi(const struct cpumask *mask);
/*
* Generic and arch helpers
@ -216,6 +217,10 @@ smp_call_function_any(const struct cpumask *mask, smp_call_func_t func,
static inline void kick_all_cpus_sync(void) { }
static inline void wake_up_all_idle_cpus(void) { }
static inline bool cpus_peek_for_pending_ipi(const struct cpumask *mask)
{
return false;
}
#define setup_max_cpus 0

View File

@ -66,6 +66,7 @@ struct ci_hdrc_platform_data {
#define CI_HDRC_HAS_PORTSC_PEC_MISSED BIT(17)
#define CI_HDRC_FORCE_VBUS_ACTIVE_ALWAYS BIT(18)
#define CI_HDRC_HAS_SHORT_PKT_LIMIT BIT(19)
#define CI_HDRC_OUT_BAND_WAKEUP BIT(20)
enum usb_dr_mode dr_mode;
#define CI_HDRC_CONTROLLER_RESET_EVENT 0
#define CI_HDRC_CONTROLLER_STOPPED_EVENT 1

View File

@ -1087,6 +1087,28 @@ void wake_up_all_idle_cpus(void)
}
EXPORT_SYMBOL_GPL(wake_up_all_idle_cpus);
/**
* cpus_peek_for_pending_ipi - Check for pending IPI for CPUs
* @mask: The CPU mask for the CPUs to check.
*
* This function walks through the @mask to check if there are any pending IPIs
* scheduled, for any of the CPUs in the @mask. It does not guarantee
* correctness as it only provides a racy snapshot.
*
* Returns true if there is a pending IPI scheduled and false otherwise.
*/
bool cpus_peek_for_pending_ipi(const struct cpumask *mask)
{
unsigned int cpu;
for_each_cpu(cpu, mask) {
if (!llist_empty(per_cpu_ptr(&call_single_queue, cpu)))
return true;
}
return false;
}
/**
* struct smp_call_on_cpu_struct - Call a function on a specific CPU
* @work: &work_struct