pmdomain providers:

- amlogic: Add support for A9 power domains
  - bcm: Raise ASB poll timeout to 100us for bcm2835-power
  - imx: Allow building power domain drivers as a modules
  - mediatek: Add support for the MT6858 power domains
  - mediatek: Add support for the MT8196 HFRP DirectCTL power domains
  - qcom: Add support for RPMh power domains for Maili
  - qcom: Skip retention by default for rpmhpd
  - renesas: Add support for R-Car X5H Module Controller
  - rockchip: Add a regulator to the RK3568 NPU power domain
  - tegra: Add support for multi-socket platforms
 -----BEGIN PGP SIGNATURE-----
 
 iQJEBAABCgAuFiEEugLDXPmKSktSkQsV/iaEJXNYjCkFAmqC8RYQHHVsZmhAa2Vy
 bmVsLm9yZwAKCRD+JoQlc1iMKYloEADS2kGT/z2l2NgivbXZFvz0RSNRG18nIpML
 6HwJd0qKr5r+U9mpIkfwvHzI3BQGYWOAt0P8y9Wrf+b32lBoDeZqKAB7N7NSOOB7
 FhNHeI+U1BIKoDxjuh/zWlHpwTAIbVDdiEJnBk1uGiG5ydco/CmwaQnDNnJywJfz
 dsfiDM1q+okolagNxx+VzhvRaxgSqvGBiX52CAMJmcmiIXIlfNTMKK9rnQRhD3lh
 kfhSnZYRQwtl7MQ7990vULYrINxAidU4KIoRnCPSJ+eA7Rl2udtsiEdQYdFba6C5
 lzEhHzgDWN9YTExCHFhy/vLOWbehoW/z6Jfz3m/Lxmkv7Zd37t3SuMj/0KnPCrpM
 Vtg8ZirqG1hvhihcoUpk20jR7LlUGcX1k5ipsP/ptj8uVkdHKVzen6bHy2FvpMle
 bYNRWwd8TKqYxAGsxEMZ59GRpRdIRowFSUAOmcP09b5CI8wslkljpmZWZgBxk1f8
 31CpmIDMIIxuYY3m0GR5CHlcAXxZO7N+5kk7AqBgDh1IXKf1/CcvgABetAMcJl07
 jcUfBBaZDA64ulzqnAEclW+xjITX5+qONVjEy5D/JORo89ttbYaAKyL10BrAb2lm
 WbkAP3R15ueHAKsE9Q6xMZ66V3qJxdF9wqmq3f/4TE+QRntDzvE/KMhCjxG5LOJ4
 I1Bb9v3rYA==
 =6EOE
 -----END PGP SIGNATURE-----

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

Pull pmdomain updates from Ulf Hansson:
 - amlogic: Add support for A9 power domains
 - bcm: Raise ASB poll timeout to 100us for bcm2835-power
 - imx: Allow building power domain drivers as a modules
 - mediatek:
    - Add support for the MT6858 power domains
    - Add support for the MT8196 HFRP DirectCTL power domains
 - qcom:
    - Add support for RPMh power domains for Maili
    - Skip retention by default for rpmhpd
 - renesas: Add support for R-Car X5H Module Controller
 - rockchip: Add a regulator to the RK3568 NPU power domain
 - tegra: Add support for multi-socket platforms

* tag 'pmdomain-v7.3' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/linux-pm: (24 commits)
  pmdomain: renesas: Add R-Car X5H MDLC driver
  dt-bindings: power: Document Renesas R-Car X5H Module Controller
  pmdomain: amlogic: Add support for A9 power domains controller
  dt-bindings: power: Add Amlogic A9 power domains
  clk: imx: imx8qxp: add soft dependency on SCU power domain driver
  pmdomain: imx: scu-pd: allow building as a module
  of: export of_stdout symbol
  pmdomain: imx8m{p,}-blk-ctrl: Add MODULE_DESCRIPTION
  pmdomain: mediatek: Add support for MT6858 SoC
  pmdomain: mediatek: Add support for secure modem power domain control
  dt-bindings: power: Add MediaTek MT6858 power domain controller
  pmdomain: rockchip: Add a regulator to the RK3568 NPU power domain
  pmdomain: imx: Make IMX8M/IMX9 BLK_CTRL tristate
  dt-bindings: power: qcom,rpmpd: document RPMh power domain for Maili
  pmdomain: tegra: Add support for multi-socket platforms
  pmdomain: bcm: bcm2835-power: Raise ASB poll timeout to 100us
  pmdomain: mediatek: Add support for MT8196 HFRP DirectCTL domains
  pmdomain: mediatek: Add support for Direct CTL simple power sequence
  pmdomain: mediatek: Respect PD relationships during error cleanup
  dt-bindings: power: mediatek: Add support for MT8196 direct HFRP
  ...
This commit is contained in:
Linus Torvalds 2026-08-19 09:28:46 -07:00
commit ee1b6365f0
29 changed files with 1340 additions and 68 deletions

View File

@ -22,6 +22,7 @@ properties:
- amlogic,meson-s4-pwrc
- amlogic,a4-pwrc
- amlogic,a5-pwrc
- amlogic,a9-pwrc
- amlogic,c3-pwrc
- amlogic,t7-pwrc
- amlogic,s6-pwrc

View File

@ -25,6 +25,7 @@ properties:
enum:
- mediatek,mt6735-power-controller
- mediatek,mt6795-power-controller
- mediatek,mt6858-power-controller
- mediatek,mt6893-power-controller
- mediatek,mt8167-power-controller
- mediatek,mt8173-power-controller
@ -34,6 +35,7 @@ properties:
- mediatek,mt8189-power-controller
- mediatek,mt8192-power-controller
- mediatek,mt8195-power-controller
- mediatek,mt8196-hfrp-power-controller
- mediatek,mt8196-hwv-hfrp-power-controller
- mediatek,mt8196-hwv-scp-power-controller
- mediatek,mt8196-power-controller
@ -55,7 +57,7 @@ properties:
faults while enabling or disabling a power domain.
For example, this may hold phandles to INFRACFG and SMI.
minItems: 1
maxItems: 3
maxItems: 6
patternProperties:
"^power-domain@[0-9a-f]+$":
@ -102,6 +104,7 @@ $defs:
description: |
Power domain index. Valid values are defined in:
"include/dt-bindings/power/mt6795-power.h" - for MT8167 type power domain.
"include/dt-bindings/power/mediatek,mt6858-power.h" - for MT6858 type power domain.
"include/dt-bindings/power/mediatek,mt6893-power.h" - for MT6893 type power domain.
"include/dt-bindings/power/mt8167-power.h" - for MT8167 type power domain.
"include/dt-bindings/power/mt8173-power.h" - for MT8173 type power domain.
@ -155,6 +158,23 @@ required:
- compatible
allOf:
- if:
properties:
compatible:
contains:
enum:
- mediatek,mt6858-power-controller
then:
properties:
access-controllers:
items:
- description: handle to INFRACFG register block
- description: handle to IMG_SUB0 register block
- description: handle to CAM_SUB1 register block
- description: handle to CAM_SUB0 register block
- description: handle to IPE_SUB0 register block
- description: handle to VLPCFG register block
- if:
properties:
compatible:

View File

@ -75,6 +75,10 @@ properties:
- enum:
- qcom,msm8937-rpmpd
- const: qcom,msm8917-rpmpd
- items:
- enum:
- qcom,maili-rpmhpd
- const: qcom,hawi-rpmhpd
'#power-domain-cells':
const: 1

View File

@ -0,0 +1,61 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/power/renesas,r8a78000-mdlc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Renesas R-Car X5H Module Controller
maintainers:
- Geert Uytterhoeven <geert+renesas@glider.be>
description:
Each instance of the R-Car X5H Module Controller (MODULE CONTROL) provides
Power Gating for up to 64 Power Domains, and Module Standby and Reset for up
to 256 modules in the Power Domain of each Module hierarchy.
properties:
compatible:
const: renesas,r8a78000-mdlc
reg:
maxItems: 1
'#power-domain-cells':
description: |
- The first power domain specifier cell is the power domain part, and
must be either the Module Power Domain Gating (MPDG) register index
(0x00-0x3f) from the datasheet, for power domains which are backed by
MPDG bits and which can be controlled in that manner, or a Power
Domain number, as defined in
<dt-bindings/power/renesas,r8a78000-mdlc.h>, for power domains which
are always on, and for which there are no MPDG bits to control them.
- The second power domain specifier cell is the module standby part, and
must be the module number (0x00-0xff), composed of the Module System
Reset (MSRES) register index in the high nibble, and the Module Reset
Destination bitfield index in the low nibble.
const: 2
'#reset-cells':
description:
The single reset specifier cell must be the module number (0x00-0xff),
and thus identical to the second power domain specifier cell.
const: 1
required:
- compatible
- reg
- '#power-domain-cells'
- '#reset-cells'
additionalProperties: false
examples:
- |
system-controller@c3060000 {
compatible = "renesas,r8a78000-mdlc";
reg = <0xc3060000 0x1000>;
#power-domain-cells = <2>;
#reset-cells = <1>;
};

View File

@ -373,3 +373,4 @@ module_exit(imx8qxp_clk_exit);
MODULE_AUTHOR("Aisheng Dong <aisheng.dong@nxp.com>");
MODULE_DESCRIPTION("NXP i.MX8QXP clock driver");
MODULE_LICENSE("GPL v2");
MODULE_SOFTDEP("pre: scu_pd");

View File

@ -39,6 +39,7 @@ struct device_node *of_chosen;
EXPORT_SYMBOL(of_chosen);
struct device_node *of_aliases;
struct device_node *of_stdout;
EXPORT_SYMBOL_GPL(of_stdout);
static const char *of_stdout_options;
struct kset *of_kset;

View File

@ -16,6 +16,7 @@
#include <dt-bindings/power/amlogic,t7-pwrc.h>
#include <dt-bindings/power/amlogic,a4-pwrc.h>
#include <dt-bindings/power/amlogic,a5-pwrc.h>
#include <dt-bindings/power/amlogic,a9-pwrc.h>
#include <dt-bindings/power/amlogic,s6-pwrc.h>
#include <dt-bindings/power/amlogic,s7-pwrc.h>
#include <dt-bindings/power/amlogic,s7d-pwrc.h>
@ -175,6 +176,65 @@ static const struct meson_secure_pwrc_domain_desc a5_pwrc_domains[] = {
SEC_PD(A5_DSPA, 0),
};
static const struct meson_secure_pwrc_domain_desc a9_pwrc_domains[] = {
SEC_PD(A9_DSPA, 0),
SEC_PD(A9_U3HSG_U3, 0),
SEC_PD(A9_DP, 0),
SEC_PD(A9_DOS_HCODEC, 0),
SEC_PD(A9_TAHOE, 0),
SEC_PD(A9_DOS_HEVC, 0),
SEC_PD(A9_U2H, 0),
SEC_PD(A9_U3DRD_B, 0),
SEC_PD(A9_VPU_HDMI, 0),
SEC_PD(A9_U2DRD, 0),
SEC_PD(A9_U3DRD_A, 0),
SEC_PD(A9_SD_EMMC_C, 0),
SEC_PD(A9_GE2D, 0),
SEC_PD(A9_AMFC, 0),
SEC_PD(A9_EDPTX, 0),
SEC_PD(A9_OPP, 0),
SEC_PD(A9_VICP, 0),
SEC_PD(A9_SD_EMMC_A, 0),
SEC_PD(A9_SD_EMMC_B, 0),
SEC_PD(A9_ETH, 0),
SEC_PD(A9_PCIE_A, 0),
SEC_PD(A9_PCIE_B, 0),
SEC_PD(A9_NNA_4T, 0),
SEC_PD(A9_HDMIRX, 0),
SEC_PD(A9_CVE, 0),
SEC_PD(A9_ISP, 0),
SEC_PD(A9_ETH_1G, 0),
SEC_PD(A9_U3HSG_HSG, 0),
SEC_PD(A9_U3DPPHY_U3, 0),
SEC_PD(A9_U3DPPHY_DP, 0),
SEC_PD(A9_PCIE3PHY, 0),
SEC_PD(A9_U3HSG_PCIE2, 0),
SEC_PD(A9_MALI_TOP, 0),
SEC_PD(A9_AO_SED, 0),
SEC_PD(A9_AO_IR, 0),
/* UART_B is for console log, and should be always on */
SEC_PD(A9_AO_UART_B, GENPD_FLAG_ALWAYS_ON),
SEC_PD(A9_AO_UART_C, 0),
SEC_PD(A9_AO_UART_D, 0),
SEC_PD(A9_AO_SPISG, 0),
SEC_PD(A9_AO_UART_E, 0),
SEC_PD(A9_AO_CEC, 0),
/* SRAMA is used as ATF runtime memory, and should be always on */
SEC_PD(A9_EE_SRAMA, GENPD_FLAG_ALWAYS_ON),
SEC_PD(A9_AUDIO, 0),
/* DMC0 is for DDR PHY ana/dig and DMC, and should be always on */
SEC_PD(A9_DMC0, GENPD_FLAG_ALWAYS_ON),
/*GIC needs to be used consistently, and should be always on */
SEC_PD(A9_GIC, GENPD_FLAG_ALWAYS_ON),
/* DDRPHY is for DDR Work, and should be always on */
SEC_PD(A9_DDRPHY, GENPD_FLAG_ALWAYS_ON),
SEC_PD(A9_AUCPU, 0),
SEC_PD(A9_DSI0, 0),
SEC_PD(A9_DSI1, 0),
SEC_PD(A9_CAN0, 0),
SEC_PD(A9_CAN1, 0),
};
static const struct meson_secure_pwrc_domain_desc c3_pwrc_domains[] = {
SEC_PD(C3_NNA, 0),
SEC_PD(C3_AUDIO, 0),
@ -425,6 +485,11 @@ static const struct meson_secure_pwrc_domain_data amlogic_secure_a5_pwrc_data =
.count = ARRAY_SIZE(a5_pwrc_domains),
};
static const struct meson_secure_pwrc_domain_data amlogic_secure_a9_pwrc_data = {
.domains = a9_pwrc_domains,
.count = ARRAY_SIZE(a9_pwrc_domains),
};
static const struct meson_secure_pwrc_domain_data amlogic_secure_c3_pwrc_data = {
.domains = c3_pwrc_domains,
.count = ARRAY_SIZE(c3_pwrc_domains),
@ -468,6 +533,10 @@ static const struct of_device_id meson_secure_pwrc_match_table[] = {
.compatible = "amlogic,a5-pwrc",
.data = &amlogic_secure_a5_pwrc_data,
},
{
.compatible = "amlogic,a9-pwrc",
.data = &amlogic_secure_a9_pwrc_data,
},
{
.compatible = "amlogic,c3-pwrc",
.data = &amlogic_secure_c3_pwrc_data,

View File

@ -21,7 +21,7 @@ config ARM_SCMI_POWER_DOMAIN
enabled or disabled via the SCP firmware
This driver can also be built as a module. If so, the module
will be called scmi_pm_domain. Note this may needed early in boot
will be called scmi_pm_domain. Note this may be needed early in boot
before rootfs may be available.
config ARM_SCPI_POWER_DOMAIN

View File

@ -175,7 +175,7 @@ static int bcm2835_asb_control(struct bcm2835_power *power, u32 reg, bool enable
writel(PM_PASSWORD | val, base + reg);
if (readl_poll_timeout_atomic(base + reg, val,
!!(val & ASB_ACK) != enable, 0, 5))
!!(val & ASB_ACK) != enable, 0, 100))
return -ETIMEDOUT;
return 0;
@ -677,7 +677,12 @@ static int bcm2835_power_probe(struct platform_device *pdev)
if (ret)
goto fail;
of_genpd_add_provider_onecell(dev->parent->of_node, &power->pd_xlate);
ret = of_genpd_add_provider_onecell(dev->parent->of_node,
&power->pd_xlate);
if (ret) {
dev_err_probe(dev, ret, "failed to add genpd provider\n");
goto fail;
}
dev_info(dev, "Broadcom BCM2835 power domains driver");
return 0;

View File

@ -10,18 +10,21 @@ config IMX_GPCV2_PM_DOMAINS
default y if SOC_IMX7D
config IMX8M_BLK_CTRL
bool
default SOC_IMX8M && IMX_GPCV2_PM_DOMAINS
tristate "i.MX8M BLK CTRL driver"
depends on SOC_IMX8M
depends on IMX_GPCV2_PM_DOMAINS
depends on PM_GENERIC_DOMAINS
depends on COMMON_CLK
default y
config IMX9_BLK_CTRL
bool
default SOC_IMX9 && IMX_GPCV2_PM_DOMAINS
tristate "i.MX93 BLK CTRL driver"
depends on SOC_IMX9
depends on PM_GENERIC_DOMAINS
default y
config IMX_SCU_PD
bool "IMX SCU Power Domain driver"
tristate "IMX SCU Power Domain driver"
depends on IMX_SCU
help
The System Controller Firmware (SCFW) based power domain driver.

View File

@ -953,4 +953,5 @@ static struct platform_driver imx8m_blk_ctrl_driver = {
},
};
module_platform_driver(imx8m_blk_ctrl_driver);
MODULE_DESCRIPTION("NXP i.MX8M power domain driver");
MODULE_LICENSE("GPL");

View File

@ -890,4 +890,5 @@ static struct platform_driver imx8mp_blk_ctrl_driver = {
},
};
module_platform_driver(imx8mp_blk_ctrl_driver);
MODULE_DESCRIPTION("NXP i.MX8MP power domain driver");
MODULE_LICENSE("GPL");

View File

@ -531,6 +531,7 @@ static const struct of_device_id imx_sc_pd_match[] = {
{ .compatible = "fsl,scu-pd", &imx8qxp_scu_pd},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, imx_sc_pd_match);
static struct platform_driver imx_sc_pd_driver = {
.driver = {
@ -540,7 +541,12 @@ static struct platform_driver imx_sc_pd_driver = {
},
.probe = imx_sc_pd_probe,
};
builtin_platform_driver(imx_sc_pd_driver);
static int __init imx_sc_pd_driver_init(void)
{
return platform_driver_register(&imx_sc_pd_driver);
}
subsys_initcall(imx_sc_pd_driver_init);
MODULE_AUTHOR("Dong Aisheng <aisheng.dong@nxp.com>");
MODULE_DESCRIPTION("IMX SCU Power Domain driver");

View File

@ -0,0 +1,466 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2025 MediaTek Inc.
* KY Liu <ky.liu@mediatek.com>
* Copyright (c) 2026 Jolla Mobile Ltd
* Nikolai Burov <nikolai.burov@jolla.com>
*/
#ifndef __SOC_MEDIATEK_MT6858_PM_DOMAINS_H
#define __SOC_MEDIATEK_MT6858_PM_DOMAINS_H
#include "mtk-pm-domains.h"
#include <dt-bindings/power/mediatek,mt6858-power.h>
/* TOP_AXI registers */
#define MT6858_TOP_AXI_PROT_EN_MMSYS_STA_0_SET 0x0c14
#define MT6858_TOP_AXI_PROT_EN_MMSYS_STA_0_CLR 0x0c18
#define MT6858_TOP_AXI_PROT_EN_MMSYS_STA_0_RDY 0x0c1c
#define MT6858_TOP_AXI_PROT_EN_MMSYS_STA_0_DIS0 (BIT(0) | BIT(1) | BIT(18))
#define MT6858_TOP_AXI_PROT_EN_MMSYS_STA_0_ISP_IPE BIT(2)
#define MT6858_TOP_AXI_PROT_EN_MMSYS_STA_0_ISP_IMG1 BIT(3)
#define MT6858_TOP_AXI_PROT_EN_MMSYS_STA_0_VEN0 BIT(12)
#define MT6858_TOP_AXI_PROT_EN_MMSYS_STA_0_VDE0 BIT(20)
#define MT6858_TOP_AXI_PROT_EN_MMSYS_STA_0_CAM_MAIN (BIT(30) | BIT(31))
#define MT6858_TOP_AXI_PROT_EN_MMSYS_STA_1_SET 0x0c24
#define MT6858_TOP_AXI_PROT_EN_MMSYS_STA_1_CLR 0x0c28
#define MT6858_TOP_AXI_PROT_EN_MMSYS_STA_1_RDY 0x0c2c
#define MT6858_TOP_AXI_PROT_EN_MMSYS_STA_1_ISP_IMG1 BIT(7)
#define MT6858_TOP_AXI_PROT_EN_MMSYS_STA_1_ISP_IPE BIT(8)
#define MT6858_TOP_AXI_PROT_EN_MMSYS_STA_1_CAM_MAIN (BIT(9) | BIT(10))
#define MT6858_TOP_AXI_PROT_EN_MMSYS_STA_1_VEN0 BIT(12)
#define MT6858_TOP_AXI_PROT_EN_MMSYS_STA_1_VDE0 BIT(13)
#define MT6858_TOP_AXI_PROT_EN_MMSYS_STA_1_MM_INFRA (GENMASK(3, 1) | BIT(6))
#define MT6858_TOP_AXI_PROT_EN_MMSYS_STA_1_MM_INFRA_2ND (BIT(0) | BIT(5) | GENMASK(15, 7))
#define MT6858_TOP_AXI_PROT_EN_INFRASYS_STA_0_SET 0x0c44
#define MT6858_TOP_AXI_PROT_EN_INFRASYS_STA_0_CLR 0x0c48
#define MT6858_TOP_AXI_PROT_EN_INFRASYS_STA_0_RDY 0x0c4c
#define MT6858_TOP_AXI_PROT_EN_INFRASYS_STA_0_CONN BIT(8)
#define MT6858_TOP_AXI_PROT_EN_INFRASYS_STA_0_MM_INFRA BIT(16)
#define MT6858_TOP_AXI_PROT_EN_INFRASYS_STA_1_SET 0x0c54
#define MT6858_TOP_AXI_PROT_EN_INFRASYS_STA_1_CLR 0x0c58
#define MT6858_TOP_AXI_PROT_EN_INFRASYS_STA_1_RDY 0x0c5c
#define MT6858_TOP_AXI_PROT_EN_INFRASYS_STA_1_MM_INFRA BIT(11)
#define MT6858_TOP_AXI_PROT_EN_INFRASYS_STA_1_CONN BIT(12)
#define MT6858_TOP_AXI_PROT_EN_EMISYS_STA_0_SET 0x0c64
#define MT6858_TOP_AXI_PROT_EN_EMISYS_STA_0_CLR 0x0c68
#define MT6858_TOP_AXI_PROT_EN_EMISYS_STA_0_RDY 0x0c6c
#define MT6858_TOP_AXI_PROT_EN_EMISYS_STA_0_MM_INFRA (BIT(20) | BIT(21))
#define MT6858_TOP_AXI_PROT_EN_PERISYS_STA_0_SET 0x0c84
#define MT6858_TOP_AXI_PROT_EN_PERISYS_STA_0_CLR 0x0c88
#define MT6858_TOP_AXI_PROT_EN_PERISYS_STA_0_RDY 0x0c8c
#define MT6858_TOP_AXI_PROT_EN_PERISYS_STA_0_AUDIO BIT(6)
#define MT6858_TOP_AXI_PROT_EN_PERISYS_STA_0_SSUSB BIT(7)
#define MT6858_TOP_AXI_PROT_EN_MCU_STA_0_SET 0x0c94
#define MT6858_TOP_AXI_PROT_EN_MCU_STA_0_CLR 0x0c98
#define MT6858_TOP_AXI_PROT_EN_MCU_STA_0_RDY 0x0c9c
#define MT6858_TOP_AXI_PROT_EN_MCU_STA_0_CONN BIT(1)
#define MT6858_TOP_AXI_PROT_EN_MCU_STA_0_CONN_2ND BIT(0)
/* {IMG,IPE,CAM}_SUBx registers */
#define MT6858_SUBx_PROT_EN_SET 0x03c4
#define MT6858_SUBx_PROT_EN_CLR 0x03c8
#define MT6858_SUBx_PROT_EN_STA 0x03cc
#define MT6858_IMG_SUB0_PROT_EN_SMI_ISP_IMG1 (BIT(0) | BIT(1))
#define MT6858_IPE_SUB0_PROT_EN_SMI_ISP_IPE (BIT(0) | BIT(1))
#define MT6858_CAM_SUB0_PROT_EN_SMI_CAM_MAIN BIT(0)
#define MT6858_CAM_SUB0_PROT_EN_SMI_CAM_SUBB BIT(1)
#define MT6858_CAM_SUB1_PROT_EN_SMI_CAM_MAIN BIT(0)
#define MT6858_CAM_SUB1_PROT_EN_SMI_CAM_SUBA BIT(1)
/* VLP_AXI registers */
#define MT6858_VLP_AXI_PROT_EN_SET 0x0214
#define MT6858_VLP_AXI_PROT_EN_CLR 0x0218
#define MT6858_VLP_AXI_PROT_EN_STA 0x021c
#define MT6858_VLP_AXI_PROT_EN_MM_PROC BIT(8)
#define MT6858_VLP_AXI_PROT_EN_MM_PROC_2ND (BIT(9) | BIT(10))
/* PWR_CON registers */
#define MT6858_PWR_ACK BIT(30)
#define MT6858_PWR_ACK_2ND BIT(31)
static enum scpsys_bus_prot_block scpsys_bus_prot_blocks_mt6858[] = {
BUS_PROT_BLOCK_INFRA,
BUS_PROT_BLOCK_IMG_SUB0,
BUS_PROT_BLOCK_CAM_SUB1,
BUS_PROT_BLOCK_CAM_SUB0,
BUS_PROT_BLOCK_IPE_SUB0,
BUS_PROT_BLOCK_VLP,
};
static const struct scpsys_domain_data scpsys_domain_data_mt6858[] = {
[MT6858_POWER_DOMAIN_MD] = {
.name = "md",
/*
* Note: the PWR_ACK_2ND bit is not used for the modem domain.
* Skip it and fall back to checking the 1st bit twice.
*/
.sta_mask = MT6858_PWR_ACK,
.ctl_offs = 0xe00,
.pwr_sta_offs = 0xe00,
.pwr_sta2nd_offs = 0xe00,
.ext_buck_iso_offs = 0xf20,
.ext_buck_iso_mask = GENMASK(1, 0),
.caps = MTK_SCPD_MODEM_SECURE_PWRSEQ | MTK_SCPD_EXT_BUCK_ISO |
MTK_SCPD_KEEP_DEFAULT_OFF,
},
[MT6858_POWER_DOMAIN_CONN] = {
.name = "conn",
.sta_mask = MT6858_PWR_ACK,
.sta2nd_mask = MT6858_PWR_ACK_2ND,
.ctl_offs = 0xe04,
.pwr_sta_offs = 0xe04,
.pwr_sta2nd_offs = 0xe04,
.bp_cfg = {
BUS_PROT_WR_IGN(INFRA,
MT6858_TOP_AXI_PROT_EN_MCU_STA_0_CONN,
MT6858_TOP_AXI_PROT_EN_MCU_STA_0_SET,
MT6858_TOP_AXI_PROT_EN_MCU_STA_0_CLR,
MT6858_TOP_AXI_PROT_EN_MCU_STA_0_RDY),
BUS_PROT_WR_IGN(INFRA,
MT6858_TOP_AXI_PROT_EN_INFRASYS_STA_1_CONN,
MT6858_TOP_AXI_PROT_EN_INFRASYS_STA_1_SET,
MT6858_TOP_AXI_PROT_EN_INFRASYS_STA_1_CLR,
MT6858_TOP_AXI_PROT_EN_INFRASYS_STA_1_RDY),
BUS_PROT_WR_IGN(INFRA,
MT6858_TOP_AXI_PROT_EN_MCU_STA_0_CONN_2ND,
MT6858_TOP_AXI_PROT_EN_MCU_STA_0_SET,
MT6858_TOP_AXI_PROT_EN_MCU_STA_0_CLR,
MT6858_TOP_AXI_PROT_EN_MCU_STA_0_RDY),
BUS_PROT_WR_IGN(INFRA,
MT6858_TOP_AXI_PROT_EN_INFRASYS_STA_0_CONN,
MT6858_TOP_AXI_PROT_EN_INFRASYS_STA_0_SET,
MT6858_TOP_AXI_PROT_EN_INFRASYS_STA_0_CLR,
MT6858_TOP_AXI_PROT_EN_INFRASYS_STA_0_RDY),
},
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
},
[MT6858_POWER_DOMAIN_AUDIO] = {
.name = "audio",
.sta_mask = MT6858_PWR_ACK,
.sta2nd_mask = MT6858_PWR_ACK_2ND,
.ctl_offs = 0xe18,
.pwr_sta_offs = 0xe18,
.pwr_sta2nd_offs = 0xe18,
.sram_pdn_bits = BIT(8),
.sram_pdn_ack_bits = BIT(12),
.bp_cfg = {
BUS_PROT_WR_IGN(INFRA,
MT6858_TOP_AXI_PROT_EN_PERISYS_STA_0_AUDIO,
MT6858_TOP_AXI_PROT_EN_PERISYS_STA_0_SET,
MT6858_TOP_AXI_PROT_EN_PERISYS_STA_0_CLR,
MT6858_TOP_AXI_PROT_EN_PERISYS_STA_0_RDY),
},
},
[MT6858_POWER_DOMAIN_ISP_IMG1] = {
.name = "isp-img1",
.sta_mask = MT6858_PWR_ACK,
.sta2nd_mask = MT6858_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(INFRA,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_0_ISP_IMG1,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_0_SET,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_0_CLR,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_0_RDY),
BUS_PROT_WR_IGN(INFRA,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_1_ISP_IMG1,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_1_SET,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_1_CLR,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_1_RDY),
BUS_PROT_WR_IGN(IMG_SUB0,
MT6858_IMG_SUB0_PROT_EN_SMI_ISP_IMG1,
MT6858_SUBx_PROT_EN_SET,
MT6858_SUBx_PROT_EN_CLR,
MT6858_SUBx_PROT_EN_STA),
},
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
},
[MT6858_POWER_DOMAIN_ISP_IMG2] = {
.name = "isp-img2",
.sta_mask = MT6858_PWR_ACK,
.sta2nd_mask = MT6858_PWR_ACK_2ND,
.ctl_offs = 0xe2c,
.pwr_sta_offs = 0xe2c,
.pwr_sta2nd_offs = 0xe2c,
.sram_pdn_bits = BIT(8),
.sram_pdn_ack_bits = BIT(12),
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
},
[MT6858_POWER_DOMAIN_ISP_IPE] = {
.name = "isp-ipe",
.sta_mask = MT6858_PWR_ACK,
.sta2nd_mask = MT6858_PWR_ACK_2ND,
.ctl_offs = 0xe30,
.pwr_sta_offs = 0xe30,
.pwr_sta2nd_offs = 0xe30,
.sram_pdn_bits = BIT(8),
.sram_pdn_ack_bits = BIT(12),
.bp_cfg = {
BUS_PROT_WR_IGN(INFRA,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_0_ISP_IPE,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_0_SET,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_0_CLR,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_0_RDY),
BUS_PROT_WR_IGN(INFRA,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_1_ISP_IPE,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_1_SET,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_1_CLR,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_1_RDY),
BUS_PROT_WR_IGN(IPE_SUB0,
MT6858_IPE_SUB0_PROT_EN_SMI_ISP_IPE,
MT6858_SUBx_PROT_EN_SET,
MT6858_SUBx_PROT_EN_CLR,
MT6858_SUBx_PROT_EN_STA),
},
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
},
[MT6858_POWER_DOMAIN_VDE0] = {
.name = "vde0",
.sta_mask = MT6858_PWR_ACK,
.sta2nd_mask = MT6858_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(INFRA,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_0_VDE0,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_0_SET,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_0_CLR,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_0_RDY),
BUS_PROT_WR_IGN(INFRA,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_1_VDE0,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_1_SET,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_1_CLR,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_1_RDY),
},
},
[MT6858_POWER_DOMAIN_VEN0] = {
.name = "ven0",
.sta_mask = MT6858_PWR_ACK,
.sta2nd_mask = MT6858_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(INFRA,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_0_VEN0,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_0_SET,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_0_CLR,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_0_RDY),
BUS_PROT_WR_IGN(INFRA,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_1_VEN0,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_1_SET,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_1_CLR,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_1_RDY),
},
},
[MT6858_POWER_DOMAIN_CAM_MAIN] = {
.name = "cam-main",
.sta_mask = MT6858_PWR_ACK,
.sta2nd_mask = MT6858_PWR_ACK_2ND,
.ctl_offs = 0xe44,
.pwr_sta_offs = 0xe44,
.pwr_sta2nd_offs = 0xe44,
.sram_pdn_bits = BIT(8),
.sram_pdn_ack_bits = BIT(12),
.bp_cfg = {
BUS_PROT_WR_IGN(INFRA,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_0_CAM_MAIN,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_0_SET,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_0_CLR,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_0_RDY),
BUS_PROT_WR_IGN(INFRA,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_1_CAM_MAIN,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_1_SET,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_1_CLR,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_1_RDY),
BUS_PROT_WR_IGN(CAM_SUB0,
MT6858_CAM_SUB0_PROT_EN_SMI_CAM_MAIN,
MT6858_SUBx_PROT_EN_SET,
MT6858_SUBx_PROT_EN_CLR,
MT6858_SUBx_PROT_EN_STA),
BUS_PROT_WR_IGN(CAM_SUB1,
MT6858_CAM_SUB1_PROT_EN_SMI_CAM_MAIN,
MT6858_SUBx_PROT_EN_SET,
MT6858_SUBx_PROT_EN_CLR,
MT6858_SUBx_PROT_EN_STA),
},
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
},
[MT6858_POWER_DOMAIN_CAM_SUBA] = {
.name = "cam-suba",
.sta_mask = MT6858_PWR_ACK,
.sta2nd_mask = MT6858_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(CAM_SUB1,
MT6858_CAM_SUB1_PROT_EN_SMI_CAM_SUBA,
MT6858_SUBx_PROT_EN_SET,
MT6858_SUBx_PROT_EN_CLR,
MT6858_SUBx_PROT_EN_STA),
},
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
},
[MT6858_POWER_DOMAIN_CAM_SUBB] = {
.name = "cam-subb",
.sta_mask = MT6858_PWR_ACK,
.sta2nd_mask = MT6858_PWR_ACK_2ND,
.ctl_offs = 0xe50,
.pwr_sta_offs = 0xe50,
.pwr_sta2nd_offs = 0xe50,
.sram_pdn_bits = BIT(8),
.sram_pdn_ack_bits = BIT(12),
.bp_cfg = {
BUS_PROT_WR_IGN(CAM_SUB0,
MT6858_CAM_SUB0_PROT_EN_SMI_CAM_SUBB,
MT6858_SUBx_PROT_EN_SET,
MT6858_SUBx_PROT_EN_CLR,
MT6858_SUBx_PROT_EN_STA),
},
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
},
[MT6858_POWER_DOMAIN_DIS0] = {
.name = "dis0",
.sta_mask = MT6858_PWR_ACK,
.sta2nd_mask = MT6858_PWR_ACK_2ND,
.ctl_offs = 0xe6c,
.pwr_sta_offs = 0xe6c,
.pwr_sta2nd_offs = 0xe6c,
.sram_pdn_bits = BIT(8),
.sram_pdn_ack_bits = BIT(12),
.bp_cfg = {
BUS_PROT_WR_IGN(INFRA,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_0_DIS0,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_0_SET,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_0_CLR,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_0_RDY),
},
},
[MT6858_POWER_DOMAIN_MM_INFRA] = {
.name = "mm-infra",
.sta_mask = MT6858_PWR_ACK,
.sta2nd_mask = MT6858_PWR_ACK_2ND,
.ctl_offs = 0xe74,
.pwr_sta_offs = 0xe74,
.pwr_sta2nd_offs = 0xe74,
.sram_pdn_bits = BIT(8),
.sram_pdn_ack_bits = BIT(12),
.bp_cfg = {
BUS_PROT_WR_IGN(INFRA,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_1_MM_INFRA,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_1_SET,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_1_CLR,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_1_RDY),
BUS_PROT_WR_IGN(INFRA,
MT6858_TOP_AXI_PROT_EN_INFRASYS_STA_1_MM_INFRA,
MT6858_TOP_AXI_PROT_EN_INFRASYS_STA_1_SET,
MT6858_TOP_AXI_PROT_EN_INFRASYS_STA_1_CLR,
MT6858_TOP_AXI_PROT_EN_INFRASYS_STA_1_RDY),
BUS_PROT_WR_IGN(INFRA,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_1_MM_INFRA_2ND,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_1_SET,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_1_CLR,
MT6858_TOP_AXI_PROT_EN_MMSYS_STA_1_RDY),
BUS_PROT_WR_IGN(INFRA,
MT6858_TOP_AXI_PROT_EN_INFRASYS_STA_0_MM_INFRA,
MT6858_TOP_AXI_PROT_EN_INFRASYS_STA_0_SET,
MT6858_TOP_AXI_PROT_EN_INFRASYS_STA_0_CLR,
MT6858_TOP_AXI_PROT_EN_INFRASYS_STA_0_RDY),
BUS_PROT_WR_IGN(INFRA,
MT6858_TOP_AXI_PROT_EN_EMISYS_STA_0_MM_INFRA,
MT6858_TOP_AXI_PROT_EN_EMISYS_STA_0_SET,
MT6858_TOP_AXI_PROT_EN_EMISYS_STA_0_CLR,
MT6858_TOP_AXI_PROT_EN_EMISYS_STA_0_RDY),
},
},
[MT6858_POWER_DOMAIN_MM_PROC_DORMANT] = {
.name = "mm-proc-dormant",
.sta_mask = MT6858_PWR_ACK,
.sta2nd_mask = MT6858_PWR_ACK_2ND,
.ctl_offs = 0xe78,
.pwr_sta_offs = 0xe78,
.pwr_sta2nd_offs = 0xe78,
.sram_pdn_bits = BIT(9),
.sram_pdn_ack_bits = BIT(13),
.bp_cfg = {
BUS_PROT_WR_IGN(VLP,
MT6858_VLP_AXI_PROT_EN_MM_PROC,
MT6858_VLP_AXI_PROT_EN_SET,
MT6858_VLP_AXI_PROT_EN_CLR,
MT6858_VLP_AXI_PROT_EN_STA),
BUS_PROT_WR_IGN(VLP,
MT6858_VLP_AXI_PROT_EN_MM_PROC_2ND,
MT6858_VLP_AXI_PROT_EN_SET,
MT6858_VLP_AXI_PROT_EN_CLR,
MT6858_VLP_AXI_PROT_EN_STA),
},
.caps = MTK_SCPD_SRAM_ISO | MTK_SCPD_SRAM_PDN_INVERTED,
},
[MT6858_POWER_DOMAIN_CSI_RX] = {
.name = "csi-rx",
.sta_mask = MT6858_PWR_ACK,
.sta2nd_mask = MT6858_PWR_ACK_2ND,
.ctl_offs = 0xe98,
.pwr_sta_offs = 0xe98,
.pwr_sta2nd_offs = 0xe98,
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
},
[MT6858_POWER_DOMAIN_SSUSB] = {
.name = "ssusb",
.sta_mask = MT6858_PWR_ACK,
.sta2nd_mask = MT6858_PWR_ACK_2ND,
.ctl_offs = 0xea4,
.pwr_sta_offs = 0xea4,
.pwr_sta2nd_offs = 0xea4,
.sram_pdn_bits = BIT(8),
.sram_pdn_ack_bits = BIT(12),
.bp_cfg = {
BUS_PROT_WR_IGN(INFRA,
MT6858_TOP_AXI_PROT_EN_PERISYS_STA_0_SSUSB,
MT6858_TOP_AXI_PROT_EN_PERISYS_STA_0_SET,
MT6858_TOP_AXI_PROT_EN_PERISYS_STA_0_CLR,
MT6858_TOP_AXI_PROT_EN_PERISYS_STA_0_RDY),
},
},
};
static const struct scpsys_soc_data mt6858_scpsys_data = {
.domains_data = scpsys_domain_data_mt6858,
.num_domains = ARRAY_SIZE(scpsys_domain_data_mt6858),
.bus_prot_blocks = scpsys_bus_prot_blocks_mt6858,
.num_bus_prot_blocks = ARRAY_SIZE(scpsys_bus_prot_blocks_mt6858),
.type = SCPSYS_MTCMOS_TYPE_DIRECT_CTL,
};
#endif /* __SOC_MEDIATEK_MT6858_PM_DOMAINS_H */

View File

@ -602,6 +602,27 @@ static const struct scpsys_hwv_domain_data hfrpsys_hwv_domain_data_mt8196[] = {
},
};
static const struct scpsys_domain_data hfrpsys_domain_data_mt8196[] = {
[MT8196_POWER_DOMAIN_EDPTX] = {
.name = "edp-tx",
.sta_mask = MT8196_PWR_ACK,
.sta2nd_mask = MT8196_PWR_ACK_2ND,
.ctl_offs = 0x74,
.pwr_sta_offs = 0x74,
.pwr_sta2nd_offs = 0x74,
.caps = MTK_SCPD_SIMPLE_PWRSEQ,
},
[MT8196_POWER_DOMAIN_DPTX] = {
.name = "dp-tx",
.sta_mask = MT8196_PWR_ACK,
.sta2nd_mask = MT8196_PWR_ACK_2ND,
.ctl_offs = 0x78,
.pwr_sta_offs = 0x78,
.pwr_sta2nd_offs = 0x78,
.caps = MTK_SCPD_SIMPLE_PWRSEQ,
},
};
static const struct scpsys_soc_data mt8196_scpsys_data = {
.domains_data = scpsys_domain_data_mt8196,
.num_domains = ARRAY_SIZE(scpsys_domain_data_mt8196),
@ -616,6 +637,12 @@ static const struct scpsys_soc_data mt8196_scpsys_hwv_data = {
.type = SCPSYS_MTCMOS_TYPE_HW_VOTER,
};
static const struct scpsys_soc_data mt8196_hfrpsys_data = {
.domains_data = hfrpsys_domain_data_mt8196,
.num_domains = ARRAY_SIZE(hfrpsys_domain_data_mt8196),
.type = SCPSYS_MTCMOS_TYPE_DIRECT_CTL,
};
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),

View File

@ -20,6 +20,7 @@
#include "mt6735-pm-domains.h"
#include "mt6795-pm-domains.h"
#include "mt6858-pm-domains.h"
#include "mt6893-pm-domains.h"
#include "mt8167-pm-domains.h"
#include "mt8173-pm-domains.h"
@ -57,6 +58,10 @@
#define MTK_SIP_KERNEL_HWCCF_CONTROL MTK_SIP_SMC_CMD(0x540)
/* Secure MTCMOS commands for modem subsystem */
#define MTK_MD_MTCMOS_ENABLE 18
#define MTK_MD_MTCMOS_DISABLE 19
struct scpsys_domain {
struct generic_pm_domain genpd;
const struct scpsys_domain_data *data;
@ -547,9 +552,11 @@ static int scpsys_ctl_pwrseq_on(struct scpsys_domain *pd)
return 0;
}
static void scpsys_ctl_pwrseq_off(struct scpsys_domain *pd)
static int scpsys_ctl_pwrseq_off(struct scpsys_domain *pd)
{
struct scpsys *scpsys = pd->scpsys;
bool tmp;
int ret;
switch (pd->data->rtff_type) {
case SCPSYS_RTFF_TYPE_GENERIC:
@ -581,6 +588,41 @@ static void scpsys_ctl_pwrseq_off(struct scpsys_domain *pd)
regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT);
regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_2ND_BIT);
regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_BIT);
/* wait until PWR_ACK = 0 */
ret = readx_poll_timeout(scpsys_domain_is_on, pd, tmp, !tmp, MTK_POLL_DELAY_US,
MTK_POLL_TIMEOUT);
if (ret < 0)
return ret;
return 0;
}
static int scpsys_simple_pwrseq_on(struct scpsys_domain *pd)
{
struct scpsys *scpsys = pd->scpsys;
/* Enable subsys clock input and trigger power domain reset state */
regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_CLK_DIS_BIT);
regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT);
/* Wait for the hardware to stabilize */
udelay(1);
/* Get out of reset: set power on */
regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT);
return 0;
}
static int scpsys_simple_pwrseq_off(struct scpsys_domain *pd)
{
struct scpsys *scpsys = pd->scpsys;
regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT);
regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_CLK_DIS_BIT);
return 0;
}
static int scpsys_modem_pwrseq_on(struct scpsys_domain *pd)
@ -603,14 +645,52 @@ static int scpsys_modem_pwrseq_on(struct scpsys_domain *pd)
return 0;
}
static void scpsys_modem_pwrseq_off(struct scpsys_domain *pd)
static int scpsys_modem_pwrseq_off(struct scpsys_domain *pd)
{
struct scpsys *scpsys = pd->scpsys;
bool tmp;
int ret;
regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_BIT);
if (!MTK_SCPD_CAPS(pd, MTK_SCPD_SKIP_RESET_B))
regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT);
/* wait until PWR_ACK = 0 */
ret = readx_poll_timeout(scpsys_domain_is_on, pd, tmp, !tmp, MTK_POLL_DELAY_US,
MTK_POLL_TIMEOUT);
if (ret < 0)
return ret;
return 0;
}
static bool scpsys_modem_sec_poll(unsigned long cmd)
{
struct arm_smccc_res res;
arm_smccc_smc(MTK_SIP_KERNEL_CCCI_CONTROL, cmd, 1, 0, 0, 0, 0, 0, &res);
return res.a0 == 0;
}
static int scpsys_modem_sec_power_on(bool on)
{
struct arm_smccc_res res;
unsigned long cmd = on ? MTK_MD_MTCMOS_ENABLE : MTK_MD_MTCMOS_DISABLE;
bool tmp;
int ret;
arm_smccc_smc(MTK_SIP_KERNEL_CCCI_CONTROL, cmd, 0, 0, 0, 0, 0, 0, &res);
if (res.a0 == 0)
return 0;
ret = readx_poll_timeout(scpsys_modem_sec_poll, cmd, tmp, tmp,
MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
if (ret < 0)
return ret;
return 0;
}
static int scpsys_power_on(struct generic_pm_domain *genpd)
@ -631,8 +711,12 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
regmap_clear_bits(scpsys->base, pd->data->ext_buck_iso_offs,
pd->data->ext_buck_iso_mask);
if (MTK_SCPD_CAPS(pd, MTK_SCPD_MODEM_PWRSEQ))
if (MTK_SCPD_CAPS(pd, MTK_SCPD_MODEM_SECURE_PWRSEQ))
ret = scpsys_modem_sec_power_on(true);
else if (MTK_SCPD_CAPS(pd, MTK_SCPD_MODEM_PWRSEQ))
ret = scpsys_modem_pwrseq_on(pd);
else if (MTK_SCPD_CAPS(pd, MTK_SCPD_SIMPLE_PWRSEQ))
ret = scpsys_simple_pwrseq_on(pd);
else
ret = scpsys_ctl_pwrseq_on(pd);
@ -660,9 +744,12 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
goto err_pwr_ack;
}
ret = scpsys_sram_enable(pd);
if (ret < 0)
goto err_disable_subsys_clks;
if (!MTK_SCPD_CAPS(pd, MTK_SCPD_SIMPLE_PWRSEQ) &&
!MTK_SCPD_CAPS(pd, MTK_SCPD_MODEM_SECURE_PWRSEQ)) {
ret = scpsys_sram_enable(pd);
if (ret < 0)
goto err_disable_subsys_clks;
}
ret = scpsys_bus_protect_disable(pd, 0);
if (ret < 0)
@ -680,7 +767,9 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
err_enable_bus_protect:
scpsys_bus_protect_enable(pd, 0);
err_disable_sram:
scpsys_sram_disable(pd);
if (!MTK_SCPD_CAPS(pd, MTK_SCPD_SIMPLE_PWRSEQ) &&
!MTK_SCPD_CAPS(pd, MTK_SCPD_MODEM_SECURE_PWRSEQ))
scpsys_sram_disable(pd);
err_disable_subsys_clks:
if (!MTK_SCPD_CAPS(pd, MTK_SCPD_STRICT_BUS_PROTECTION))
clk_bulk_disable_unprepare(pd->num_subsys_clks,
@ -695,16 +784,21 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
static int scpsys_power_off_internal(struct scpsys_domain *pd)
{
struct scpsys *scpsys = pd->scpsys;
bool tmp;
int ret;
ret = scpsys_bus_protect_enable(pd, 0);
if (ret < 0)
return ret;
ret = scpsys_sram_disable(pd);
if (ret < 0)
return ret;
if (MTK_SCPD_CAPS(pd, MTK_SCPD_MODEM_SECURE_PWRSEQ)) {
ret = scpsys_modem_sec_power_on(false);
if (ret)
return ret;
} else if (!MTK_SCPD_CAPS(pd, MTK_SCPD_SIMPLE_PWRSEQ)) {
ret = scpsys_sram_disable(pd);
if (ret < 0)
return ret;
}
if (pd->data->ext_buck_iso_offs && MTK_SCPD_CAPS(pd, MTK_SCPD_EXT_BUCK_ISO))
regmap_set_bits(scpsys->base, pd->data->ext_buck_iso_offs,
@ -717,15 +811,21 @@ static int scpsys_power_off_internal(struct scpsys_domain *pd)
return ret;
if (MTK_SCPD_CAPS(pd, MTK_SCPD_MODEM_PWRSEQ))
scpsys_modem_pwrseq_off(pd);
else
scpsys_ctl_pwrseq_off(pd);
ret = scpsys_modem_pwrseq_off(pd);
else if (MTK_SCPD_CAPS(pd, MTK_SCPD_SIMPLE_PWRSEQ))
ret = scpsys_simple_pwrseq_off(pd);
else if (!MTK_SCPD_CAPS(pd, MTK_SCPD_MODEM_SECURE_PWRSEQ))
ret = scpsys_ctl_pwrseq_off(pd);
if (ret < 0) {
/* Re-enable clocks so that next power off doesn't break the refcount */
int r = clk_bulk_prepare_enable(pd->num_subsys_clks, pd->subsys_clks);
if (r)
dev_warn(scpsys->dev, "Could not re-enable clocks: %d\n", r);
/* wait until PWR_ACK = 0 */
ret = readx_poll_timeout(scpsys_domain_is_on, pd, tmp, !tmp, MTK_POLL_DELAY_US,
MTK_POLL_TIMEOUT);
if (ret < 0)
return ret;
}
clk_bulk_disable_unprepare(pd->num_clks, pd->clks);
@ -742,7 +842,8 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
}
static struct
generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_node *node)
generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_node *node,
u8 *domains_idx, u8 *num_domains)
{
const struct scpsys_domain_data *domain_data;
const struct scpsys_hwv_domain_data *hwv_domain_data;
@ -917,6 +1018,7 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no
else
pm_genpd_init(&pd->genpd, NULL, false);
domains_idx[(*num_domains)++] = (u8) id;
scpsys->domains[id] = &pd->genpd;
return scpsys->pd_data.domains[id];
@ -928,7 +1030,8 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no
return ERR_PTR(ret);
}
static int scpsys_add_subdomain(struct scpsys *scpsys, struct device_node *parent)
static int scpsys_add_subdomain(struct scpsys *scpsys, struct device_node *parent,
u8 *domains_idx, u8 *num_domains)
{
struct generic_pm_domain *child_pd, *parent_pd;
struct device_node *child;
@ -951,7 +1054,7 @@ static int scpsys_add_subdomain(struct scpsys *scpsys, struct device_node *paren
parent_pd = scpsys->pd_data.domains[id];
child_pd = scpsys_add_one_domain(scpsys, child);
child_pd = scpsys_add_one_domain(scpsys, child, domains_idx, num_domains);
if (IS_ERR(child_pd)) {
ret = PTR_ERR(child_pd);
dev_err_probe(scpsys->dev, ret, "%pOF: failed to get child domain id\n",
@ -960,7 +1063,7 @@ static int scpsys_add_subdomain(struct scpsys *scpsys, struct device_node *paren
}
/* recursive call to add all subdomains */
ret = scpsys_add_subdomain(scpsys, child);
ret = scpsys_add_subdomain(scpsys, child, domains_idx, num_domains);
if (ret)
goto err_put_node;
@ -1001,7 +1104,7 @@ static void scpsys_remove_one_domain(struct scpsys_domain *pd)
if (scpsys_hwv_domain_is_enable_done(pd))
scpsys_hwv_power_off_internal(pd);
} else {
if (scpsys_domain_is_on(pd))
if (scpsys_domain_is_on(pd) || MTK_SCPD_CAPS(pd, MTK_SCPD_SIMPLE_PWRSEQ))
scpsys_power_off_internal(pd);
}
@ -1009,14 +1112,16 @@ static void scpsys_remove_one_domain(struct scpsys_domain *pd)
clk_bulk_put(pd->num_subsys_clks, pd->subsys_clks);
}
static void scpsys_domain_cleanup(struct scpsys *scpsys)
static void scpsys_domain_cleanup(struct scpsys *scpsys, u8 *domains_idx, u8 num_probed)
{
struct generic_pm_domain *genpd;
struct scpsys_domain *pd;
int i;
for (i = scpsys->pd_data.num_domains - 1; i >= 0; i--) {
genpd = scpsys->pd_data.domains[i];
for (i = num_probed - 1; i >= 0; i--) {
u8 pd_idx = domains_idx[i];
genpd = scpsys->pd_data.domains[pd_idx];
if (genpd) {
pd = to_scpsys_domain(genpd);
scpsys_remove_one_domain(pd);
@ -1104,6 +1209,12 @@ static int scpsys_get_bus_protection_legacy(struct device *dev, struct scpsys *s
regmap[2] = NULL;
}
/* If no access controllers are needed, don't allocate and don't fail */
if (num_regmaps == 0) {
scpsys->bus_prot = NULL;
return 0;
}
scpsys->bus_prot = devm_kmalloc_array(dev, num_regmaps,
sizeof(*scpsys->bus_prot), GFP_KERNEL);
if (!scpsys->bus_prot)
@ -1178,6 +1289,10 @@ static const struct of_device_id scpsys_of_match[] = {
.compatible = "mediatek,mt6795-power-controller",
.data = &mt6795_scpsys_data,
},
{
.compatible = "mediatek,mt6858-power-controller",
.data = &mt6858_scpsys_data,
},
{
.compatible = "mediatek,mt6893-power-controller",
.data = &mt6893_scpsys_data,
@ -1218,6 +1333,10 @@ static const struct of_device_id scpsys_of_match[] = {
.compatible = "mediatek,mt8196-power-controller",
.data = &mt8196_scpsys_data,
},
{
.compatible = "mediatek,mt8196-hfrp-power-controller",
.data = &mt8196_hfrpsys_data,
},
{
.compatible = "mediatek,mt8196-hwv-hfrp-power-controller",
.data = &mt8196_hfrpsys_hwv_data,
@ -1241,6 +1360,8 @@ static int scpsys_probe(struct platform_device *pdev)
struct device *parent;
struct scpsys *scpsys;
int num_domains, ret;
u8 num_added_pds = 0;
u8 *added_pds_idx;
soc = of_device_get_match_data(&pdev->dev);
if (!soc) {
@ -1254,6 +1375,19 @@ static int scpsys_probe(struct platform_device *pdev)
if (!scpsys)
return -ENOMEM;
/*
* Temporarily store the IDs of the power domains that are added as in
* case of a probe deferral this can be used to correctly cleanup all
* of what was added before.
*
* Note that this array is used only in the probe function and must be
* freed at the end, regardless of whether all of the power domains were
* probed successfully or any failure happened.
*/
added_pds_idx = devm_kmalloc_array(dev, num_domains, sizeof(*added_pds_idx), GFP_KERNEL);
if (!added_pds_idx)
return -ENOMEM;
scpsys->dev = dev;
scpsys->soc_data = soc;
@ -1284,13 +1418,15 @@ static int scpsys_probe(struct platform_device *pdev)
for_each_available_child_of_node_scoped(np, node) {
struct generic_pm_domain *domain;
domain = scpsys_add_one_domain(scpsys, node);
domain = scpsys_add_one_domain(scpsys, node,
added_pds_idx, &num_added_pds);
if (IS_ERR(domain)) {
ret = PTR_ERR(domain);
goto err_cleanup_domains;
}
ret = scpsys_add_subdomain(scpsys, node);
ret = scpsys_add_subdomain(scpsys, node,
added_pds_idx, &num_added_pds);
if (ret)
goto err_cleanup_domains;
}
@ -1306,10 +1442,11 @@ static int scpsys_probe(struct platform_device *pdev)
goto err_cleanup_domains;
}
devm_kfree(dev, added_pds_idx);
return 0;
err_cleanup_domains:
scpsys_domain_cleanup(scpsys);
scpsys_domain_cleanup(scpsys, added_pds_idx, num_added_pds);
return ret;
}

View File

@ -17,6 +17,8 @@
#define MTK_SCPD_MODEM_PWRSEQ BIT(10)
#define MTK_SCPD_SKIP_RESET_B BIT(11)
#define MTK_SCPD_INFRA_PWR_CTL BIT(12)
#define MTK_SCPD_SIMPLE_PWRSEQ BIT(13)
#define MTK_SCPD_MODEM_SECURE_PWRSEQ BIT(14)
#define MTK_SCPD_CAPS(_scpd, _x) ((_scpd)->data ? \
(_scpd)->data->caps & (_x) : \
(_scpd)->hwv_data->caps & (_x))
@ -64,6 +66,11 @@ enum scpsys_bus_prot_block {
BUS_PROT_BLOCK_INFRA_NAO,
BUS_PROT_BLOCK_SMI,
BUS_PROT_BLOCK_SPM,
BUS_PROT_BLOCK_IMG_SUB0,
BUS_PROT_BLOCK_CAM_SUB1,
BUS_PROT_BLOCK_CAM_SUB0,
BUS_PROT_BLOCK_IPE_SUB0,
BUS_PROT_BLOCK_VLP,
BUS_PROT_BLOCK_COUNT,
};

View File

@ -41,7 +41,6 @@
* @addr: Resource address as looped up using resource name from
* cmd-db
* @state_synced: Indicator that sync_state has been invoked for the rpmhpd resource
* @skip_retention_level: Indicate that retention level should not be used for the power domain
*/
struct rpmhpd {
struct device *dev;
@ -58,7 +57,6 @@ struct rpmhpd {
const char *res_name;
u32 addr;
bool state_synced;
bool skip_retention_level;
};
struct rpmhpd_desc {
@ -191,7 +189,6 @@ static struct rpmhpd mxc = {
.pd = { .name = "mxc", },
.peer = &mxc_ao,
.res_name = "mxc.lvl",
.skip_retention_level = true,
};
static struct rpmhpd mxc_ao = {
@ -199,7 +196,6 @@ static struct rpmhpd mxc_ao = {
.active_only = true,
.peer = &mxc,
.res_name = "mxc.lvl",
.skip_retention_level = true,
};
static struct rpmhpd nsp = {
@ -309,10 +305,10 @@ static struct rpmhpd *sa8775p_rpmhpds[] = {
[SA8775P_LMX] = &lmx,
[SA8775P_MMCX] = &mmcx,
[SA8775P_MMCX_AO] = &mmcx_ao,
[SA8775P_MXC] = &mxc,
[SA8775P_MXC_AO] = &mxc_ao,
[SA8775P_MX] = &mx,
[SA8775P_MX_AO] = &mx_ao,
[SA8775P_MXC] = &mxc,
[SA8775P_MXC_AO] = &mxc_ao,
[SA8775P_NSP0] = &nsp0,
[SA8775P_NSP1] = &nsp1,
};
@ -329,10 +325,10 @@ static struct rpmhpd *nord_rpmhpds[] = {
[RPMHPD_EBI] = &ebi,
[RPMHPD_GFX] = &gfx,
[RPMHPD_GFX1] = &gfx1,
[RPMHPD_MX] = &mx,
[RPMHPD_MX_AO] = &mx_ao,
[RPMHPD_MMCX] = &mmcx,
[RPMHPD_MMCX_AO] = &mmcx_ao,
[RPMHPD_MX] = &mx,
[RPMHPD_MX_AO] = &mx_ao,
[RPMHPD_MXC] = &mxc,
[RPMHPD_MXC_AO] = &mxc_ao,
[RPMHPD_NSP0] = &nsp0,
@ -484,9 +480,9 @@ static struct rpmhpd *sm7150_rpmhpds[] = {
[RPMHPD_GFX] = &gfx,
[RPMHPD_LCX] = &lcx,
[RPMHPD_LMX] = &lmx,
[RPMHPD_MSS] = &mss,
[RPMHPD_MX] = &mx,
[RPMHPD_MX_AO] = &mx_ao,
[RPMHPD_MSS] = &mss,
};
static const struct rpmhpd_desc sm7150_desc = {
@ -702,11 +698,11 @@ static struct rpmhpd *hawi_rpmhpds[] = {
[RPMHPD_LMX] = &lmx,
[RPMHPD_MMCX] = &mmcx,
[RPMHPD_MMCX_AO] = &mmcx_ao,
[RPMHPD_MSS] = &mss,
[RPMHPD_MX] = &mx,
[RPMHPD_MX_AO] = &mx_ao,
[RPMHPD_MXC] = &mxc,
[RPMHPD_MXC_AO] = &mxc_ao,
[RPMHPD_MSS] = &mss,
[RPMHPD_NSP] = &nsp,
[RPMHPD_NSP2] = &nsp2,
};
@ -813,18 +809,18 @@ static struct rpmhpd *glymur_rpmhpds[] = {
[RPMHPD_CX_AO] = &cx_ao,
[RPMHPD_EBI] = &ebi,
[RPMHPD_GFX] = &gfx,
[RPMHPD_GMXC] = &gmxc,
[RPMHPD_LCX] = &lcx,
[RPMHPD_LMX] = &lmx,
[RPMHPD_MMCX] = &mmcx,
[RPMHPD_MMCX_AO] = &mmcx_ao,
[RPMHPD_MSS] = &mss,
[RPMHPD_MX] = &mx,
[RPMHPD_MX_AO] = &mx_ao,
[RPMHPD_MXC] = &mxc,
[RPMHPD_MXC_AO] = &mxc_ao,
[RPMHPD_MSS] = &mss,
[RPMHPD_NSP] = &nsp,
[RPMHPD_NSP2] = &nsp2,
[RPMHPD_GMXC] = &gmxc,
};
static const struct rpmhpd_desc glymur_desc = {
@ -838,15 +834,15 @@ static struct rpmhpd *x1e80100_rpmhpds[] = {
[RPMHPD_CX_AO] = &cx_ao,
[RPMHPD_EBI] = &ebi,
[RPMHPD_GFX] = &gfx,
[RPMHPD_GMXC] = &gmxc,
[RPMHPD_LCX] = &lcx,
[RPMHPD_LMX] = &lmx,
[RPMHPD_MMCX] = &mmcx,
[RPMHPD_MMCX_AO] = &mmcx_ao,
[RPMHPD_MX] = &mx,
[RPMHPD_MX_AO] = &mx_ao,
[RPMHPD_NSP] = &nsp,
[RPMHPD_MXC] = &mxc,
[RPMHPD_GMXC] = &gmxc,
[RPMHPD_NSP] = &nsp,
};
static const struct rpmhpd_desc x1e80100_desc = {
@ -864,10 +860,10 @@ static struct rpmhpd *qcs8300_rpmhpds[] = {
[RPMHPD_LMX] = &lmx,
[RPMHPD_MMCX] = &mmcx_w_cx_parent,
[RPMHPD_MMCX_AO] = &mmcx_ao_w_cx_parent,
[RPMHPD_MXC] = &mxc,
[RPMHPD_MXC_AO] = &mxc_ao,
[RPMHPD_MX] = &mx,
[RPMHPD_MX_AO] = &mx_ao,
[RPMHPD_MXC] = &mxc,
[RPMHPD_MXC_AO] = &mxc_ao,
[RPMHPD_NSP0] = &nsp0,
[RPMHPD_NSP1] = &nsp1,
};
@ -1097,7 +1093,15 @@ static int rpmhpd_update_level_mapping(struct rpmhpd *rpmhpd)
return -EINVAL;
for (i = 0; i < rpmhpd->level_count; i++) {
if (rpmhpd->skip_retention_level && buf[i] == RPMH_REGULATOR_LEVEL_RETENTION)
/*
* Most HW won't function properly at Retention. The minimum
* operational level is the first level above Retention. The
* small subset of HW that can operate at Retention isn't
* controlled by HLOS. Skip the Retention level to avoid HW
* failures when the PD is enabled without first having an
* explicit OPP level set.
*/
if (buf[i] == RPMH_REGULATOR_LEVEL_RETENTION)
continue;
rpmhpd->level[i] = buf[i];

View File

@ -13,6 +13,10 @@ config SYSC_RMOBILE
bool "System Controller support for R-Mobile" if COMPILE_TEST
# SoC
config MDLC_R8A78000
bool "Module Controller support for R8A78000 (R-Car X5H)" if COMPILE_TEST
select RESET_CONTROLLER
config SYSC_R8A7742
bool "System Controller support for R8A7742 (RZ/G1H)" if COMPILE_TEST
select SYSC_RCAR

View File

@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
# SoC
obj-$(CONFIG_MDLC_R8A78000) += r8a78000-mdlc.o
obj-$(CONFIG_SYSC_R8A7742) += r8a7742-sysc.o
obj-$(CONFIG_SYSC_R8A7743) += r8a7743-sysc.o
obj-$(CONFIG_SYSC_R8A7745) += r8a7745-sysc.o

View File

@ -0,0 +1,325 @@
// SPDX-License-Identifier: GPL-2.0
/*
* R-Car X5H Module Controller
*
* Copyright (C) 2026 Glider bv
*/
#include <linux/dev_printk.h>
#include <linux/device-id/of.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/reset-controller.h>
#include <linux/slab.h>
#include <dt-bindings/power/renesas,r8a78000-mdlc.h>
struct mod_map {
int hw_id; /* Hardware module ID or -1 sentinel */
};
struct mdlc_info {
u32 base;
const struct mod_map *mod_map;
};
/**
* struct r8a78000_mdlc_priv - Module Controller Private Data
*
* @link: Link into list of MDLC instances
* @genpd_data: PM domain provider data
* @rcdev: Reset controller entity
* @dev: MDLC device
* @np: Device node in DT representing the MDLC
* @mod_map: Mapping from hardware module IDs
*/
struct r8a78000_mdlc_priv {
struct hlist_node link;
struct genpd_onecell_data genpd_data;
struct reset_controller_dev rcdev;
struct device *dev;
struct device_node *np;
const struct mod_map *mod_map;
};
static struct generic_pm_domain *r8a78000_genpd_always_on;
static HLIST_HEAD(r8a78000_mdlc_list);
static DEFINE_MUTEX(r8a78000_mdlc_lock); /* protects the two above */
static struct generic_pm_domain *r8a78000_genpd_xlate(
const struct of_phandle_args *spec, void *data)
{
struct r8a78000_mdlc_priv *priv = container_of(data,
struct r8a78000_mdlc_priv, genpd_data);
struct device *dev = priv->dev;
u32 id;
if (spec->args_count != 2)
return ERR_PTR(-EINVAL);
id = spec->args[0];
if (id >= R8A78000_MDLC_PD_AON) {
dev_dbg(dev,
"Mapping HW power domain 0x%x to always-on domain\n",
id);
return r8a78000_genpd_always_on;
}
/* For now only always-on domains are supported */
dev_err(dev, "Unknown power domain 0x%x\n", id);
return ERR_PTR(-ENOENT);
}
#define rcdev_to_priv(_rcdev) \
container_of(_rcdev, struct r8a78000_mdlc_priv, rcdev)
static const struct mod_map *mod_map_find(const struct mod_map *map, u32 id)
{
if (!map)
return NULL;
for (; map->hw_id >= 0; map++) {
if (map->hw_id == id)
return map;
}
return NULL;
}
static int r8a78000_mdlc_reset_xlate(struct reset_controller_dev *rcdev,
const struct of_phandle_args *spec)
{
struct r8a78000_mdlc_priv *priv = rcdev_to_priv(rcdev);
struct device *dev = priv->dev;
const struct mod_map *map;
u32 id;
if (spec->args_count != 1)
return -EINVAL;
id = spec->args[0];
map = mod_map_find(priv->mod_map, id);
if (!map) {
dev_err(dev, "Unknown reset 0x%x\n", id);
return -ENOENT;
}
dev_dbg(dev, "Ignoring HW reset 0x%x\n", id);
return id;
}
#define DEFINE_MDLC_RESET_WRAPPER(op) \
static int r8a78000_mdlc_ ## op(struct reset_controller_dev *rcdev, \
unsigned long id) \
{ \
struct r8a78000_mdlc_priv *priv = rcdev_to_priv(rcdev); \
\
dev_dbg(priv->dev, "%s: Ignoring\n", __func__); \
return 0; \
}
DEFINE_MDLC_RESET_WRAPPER(reset)
DEFINE_MDLC_RESET_WRAPPER(assert)
DEFINE_MDLC_RESET_WRAPPER(deassert)
DEFINE_MDLC_RESET_WRAPPER(status)
static const struct reset_control_ops r8a78000_mdlc_reset_ops = {
.reset = r8a78000_mdlc_reset,
.assert = r8a78000_mdlc_assert,
.deassert = r8a78000_mdlc_deassert,
.status = r8a78000_mdlc_status,
};
static int r8a78000_mdlc_attach_dev(struct generic_pm_domain *domain,
struct device *dev)
{
struct device_node *np = dev->of_node;
struct r8a78000_mdlc_priv *priv;
struct of_phandle_args pd_spec;
const struct mod_map *map;
unsigned int id;
int ret;
ret = of_parse_phandle_with_args(np, "power-domains",
"#power-domain-cells", 0, &pd_spec);
if (ret < 0)
return ret;
scoped_guard(mutex, &r8a78000_mdlc_lock) {
hlist_for_each_entry(priv, &r8a78000_mdlc_list, link) {
if (priv->np == pd_spec.np)
break;
}
}
if (!priv) {
dev_err(dev, "%s: MDLC %pOF not found\n", __func__, pd_spec.np);
of_node_put(pd_spec.np);
return -ENODEV;
}
id = pd_spec.args[1];
of_node_put(pd_spec.np);
map = mod_map_find(priv->mod_map, id);
if (!map) {
dev_err(dev, "Unknown module 0x%x\n", id);
return -ENOENT;
}
dev_dbg(dev, "Ignoring HW module 0x%x\n", id);
return 0;
}
static void r8a78000_mdlc_unlink(void *data)
{
struct r8a78000_mdlc_priv *priv = data;
scoped_guard(mutex, &r8a78000_mdlc_lock) {
hlist_del(&priv->link);
}
}
static void r8a78000_genpd_del_provider(void *data)
{
of_genpd_del_provider(data);
}
static int r8a78000_genpd_always_on_singleton(struct device *dev)
{
struct generic_pm_domain *genpd;
int ret;
guard(mutex)(&r8a78000_mdlc_lock);
if (r8a78000_genpd_always_on)
return 0;
genpd = kzalloc_obj(*genpd);
if (!genpd)
return -ENOMEM;
genpd->name = "always-on";
genpd->attach_dev = r8a78000_mdlc_attach_dev;
ret = pm_genpd_init(genpd, &pm_domain_always_on_gov, false);
if (ret) {
kfree(genpd);
return dev_err_probe(dev, ret,
"Failed to create always-on domain\n");
}
r8a78000_genpd_always_on = genpd;
return 0;
}
static int r8a78000_mdlc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct r8a78000_mdlc_priv *priv;
const struct mdlc_info *info;
struct resource *res;
int ret;
ret = r8a78000_genpd_always_on_singleton(dev);
if (ret)
return ret;
info = of_device_get_match_data(dev);
if (!info)
return -ENODEV;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->dev = dev;
priv->np = np;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
for (; info->base; info++) {
if (info->base == res->start)
break;
}
if (!info->base) {
dev_dbg(dev, "Unsupported MDLC instance 0x%pa\n", &res->start);
return -ENODEV;
}
priv->mod_map = info->mod_map;
scoped_guard(mutex, &r8a78000_mdlc_lock) {
hlist_add_head(&priv->link, &r8a78000_mdlc_list);
}
ret = devm_add_action_or_reset(dev, r8a78000_mdlc_unlink, priv);
if (ret)
return dev_err_probe(dev, ret, "failed to add action\n");
/* Note that no actual domains are registered, just need translation */
priv->genpd_data.xlate = r8a78000_genpd_xlate;
ret = of_genpd_add_provider_onecell(np, &priv->genpd_data);
if (ret)
return dev_err_probe(dev, ret,
"Failed to register genpd provider\n");
ret = devm_add_action_or_reset(dev, r8a78000_genpd_del_provider, np);
if (ret)
return dev_err_probe(dev, ret,
"failed to add unregister action\n");
priv->rcdev.ops = &r8a78000_mdlc_reset_ops;
priv->rcdev.of_node = np;
priv->rcdev.of_reset_n_cells = 1;
priv->rcdev.of_xlate = r8a78000_mdlc_reset_xlate;
ret = devm_reset_controller_register(dev, &priv->rcdev);
if (ret)
return dev_err_probe(dev, ret,
"Failed to register reset controller\n");
return 0;
}
static const struct mod_map r8a78000_mdlc_perw_mod_default[] = {
{ 0x54 }, /* HSCIF0 */
{ -1 }
};
static const struct mdlc_info r8a78000_mdlc_default[] = {
{
.base = 0xc05d0000 /* mdlc_perw */,
.mod_map = r8a78000_mdlc_perw_mod_default,
},
{ /* sentinel */ }
};
static const struct of_device_id r8a78000_mdlc_match[] = {
{
.compatible = "renesas,r8a78000-mdlc",
.data = &r8a78000_mdlc_default,
},
{ /* sentinel */ }
};
static struct platform_driver r8a78000_mdlc_driver = {
.probe = r8a78000_mdlc_probe,
.driver = {
.name = "r8a78000-mdlc",
.of_match_table = r8a78000_mdlc_match,
.suppress_bind_attrs = true,
},
};
builtin_platform_driver(r8a78000_mdlc_driver)
MODULE_DESCRIPTION("R-Car X5H MDLC Driver");

View File

@ -204,6 +204,20 @@ struct rockchip_pmu {
.active_wakeup = wakeup, \
}
#define DOMAIN_M_R(_name, pwr, status, req, idle, ack, wakeup, regulator) \
{ \
.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), \
.active_wakeup = wakeup, \
.need_regulator = regulator, \
}
#define DOMAIN_RK3036(_name, req, ack, idle, wakeup) \
{ \
.name = _name, \
@ -241,8 +255,8 @@ struct rockchip_pmu {
#define DOMAIN_RK3562(name, pwr, req, g_mask, mem, wakeup) \
DOMAIN_M_G_SD(name, pwr, pwr, req, req, req, g_mask, mem, wakeup, false)
#define DOMAIN_RK3568(name, pwr, req, wakeup) \
DOMAIN_M(name, pwr, pwr, req, req, req, wakeup)
#define DOMAIN_RK3568(name, pwr, req, wakeup, regulator) \
DOMAIN_M_R(name, pwr, pwr, req, req, req, wakeup, regulator)
#define DOMAIN_RK3576(name, p_offset, pwr, status, r_status, r_offset, req, idle, g_mask, wakeup) \
DOMAIN_M_O_R_G(name, p_offset, pwr, status, 0, r_status, r_status, r_offset, req, idle, idle, g_mask, wakeup)
@ -1274,15 +1288,15 @@ static const struct rockchip_domain_info rk3562_pm_domains[] = {
};
static const struct rockchip_domain_info rk3568_pm_domains[] = {
[RK3568_PD_NPU] = DOMAIN_RK3568("npu", BIT(1), BIT(2), false),
[RK3568_PD_GPU] = DOMAIN_RK3568("gpu", BIT(0), BIT(1), false),
[RK3568_PD_VI] = DOMAIN_RK3568("vi", BIT(6), BIT(3), false),
[RK3568_PD_VO] = DOMAIN_RK3568("vo", BIT(7), BIT(4), false),
[RK3568_PD_RGA] = DOMAIN_RK3568("rga", BIT(5), BIT(5), false),
[RK3568_PD_VPU] = DOMAIN_RK3568("vpu", BIT(2), BIT(6), false),
[RK3568_PD_RKVDEC] = DOMAIN_RK3568("vdec", BIT(4), BIT(8), false),
[RK3568_PD_RKVENC] = DOMAIN_RK3568("venc", BIT(3), BIT(7), false),
[RK3568_PD_PIPE] = DOMAIN_RK3568("pipe", BIT(8), BIT(11), false),
[RK3568_PD_NPU] = DOMAIN_RK3568("npu", BIT(1), BIT(2), false, true),
[RK3568_PD_GPU] = DOMAIN_RK3568("gpu", BIT(0), BIT(1), false, false),
[RK3568_PD_VI] = DOMAIN_RK3568("vi", BIT(6), BIT(3), false, false),
[RK3568_PD_VO] = DOMAIN_RK3568("vo", BIT(7), BIT(4), false, false),
[RK3568_PD_RGA] = DOMAIN_RK3568("rga", BIT(5), BIT(5), false, false),
[RK3568_PD_VPU] = DOMAIN_RK3568("vpu", BIT(2), BIT(6), false, false),
[RK3568_PD_RKVDEC] = DOMAIN_RK3568("vdec", BIT(4), BIT(8), false, false),
[RK3568_PD_RKVENC] = DOMAIN_RK3568("venc", BIT(3), BIT(7), false, false),
[RK3568_PD_PIPE] = DOMAIN_RK3568("pipe", BIT(8), BIT(11), false, false),
};
static const struct rockchip_domain_info rk3576_pm_domains[] = {

View File

@ -137,6 +137,13 @@ static char *tegra_bpmp_powergate_get_name(struct tegra_bpmp *bpmp,
if (err < 0 || msg.rx.ret < 0)
return NULL;
if (response.get_name.name[0] == '\0')
return NULL;
if (dev_to_node(bpmp->dev) != NUMA_NO_NODE)
return kasprintf(GFP_KERNEL, "%d-%s", dev_to_node(bpmp->dev),
response.get_name.name);
return kstrdup(response.get_name.name, GFP_KERNEL);
}
@ -234,7 +241,7 @@ tegra_bpmp_probe_powergates(struct tegra_bpmp *bpmp,
struct tegra_powergate_info *info = &powergates[count];
info->name = tegra_bpmp_powergate_get_name(bpmp, id);
if (!info->name || info->name[0] == '\0') {
if (!info->name) {
num_holes++;
continue;
}

View File

@ -357,6 +357,7 @@ config ARCH_R8A78000
bool "ARM64 Platform support for R8A78000 (R-Car X5H)"
default y if ARCH_RENESAS
select ARCH_RCAR_GEN5
select MDLC_R8A78000
help
This enables support for the Renesas R-Car X5H SoC.

View File

@ -0,0 +1,61 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */
/*
* Copyright (C) 2026 Amlogic, Inc. All rights reserved
*/
#ifndef _DT_BINDINGS_AMLOGIC_A9_POWER_H
#define _DT_BINDINGS_AMLOGIC_A9_POWER_H
#define PWRC_A9_DSPA_ID 0
#define PWRC_A9_U3HSG_U3_ID 1
#define PWRC_A9_DP_ID 2
#define PWRC_A9_DOS_HCODEC_ID 3
#define PWRC_A9_TAHOE_ID 4
#define PWRC_A9_DOS_HEVC_ID 5
#define PWRC_A9_U2H_ID 6
#define PWRC_A9_U3DRD_B_ID 7
#define PWRC_A9_VPU_HDMI_ID 8
#define PWRC_A9_U2DRD_ID 9
#define PWRC_A9_U3DRD_A_ID 10
#define PWRC_A9_SD_EMMC_C_ID 11
#define PWRC_A9_GE2D_ID 12
#define PWRC_A9_AMFC_ID 13
#define PWRC_A9_EDPTX_ID 14
#define PWRC_A9_OPP_ID 15
#define PWRC_A9_VICP_ID 16
#define PWRC_A9_SD_EMMC_A_ID 17
#define PWRC_A9_SD_EMMC_B_ID 18
#define PWRC_A9_ETH_ID 19
#define PWRC_A9_PCIE_A_ID 20
#define PWRC_A9_PCIE_B_ID 21
#define PWRC_A9_NNA_4T_ID 22
#define PWRC_A9_HDMIRX_ID 23
#define PWRC_A9_CVE_ID 24
#define PWRC_A9_ISP_ID 25
#define PWRC_A9_ETH_1G_ID 26
#define PWRC_A9_U3HSG_HSG_ID 27
#define PWRC_A9_U3DPPHY_U3_ID 28
#define PWRC_A9_U3DPPHY_DP_ID 29
#define PWRC_A9_PCIE3PHY_ID 30
#define PWRC_A9_U3HSG_PCIE2_ID 31
#define PWRC_A9_MALI_TOP_ID 32
#define PWRC_A9_AO_SED_ID 33
#define PWRC_A9_AO_IR_ID 34
#define PWRC_A9_AO_UART_B_ID 35
#define PWRC_A9_AO_UART_C_ID 36
#define PWRC_A9_AO_UART_D_ID 37
#define PWRC_A9_AO_SPISG_ID 38
#define PWRC_A9_AO_UART_E_ID 39
#define PWRC_A9_AO_CEC_ID 40
#define PWRC_A9_EE_SRAMA_ID 41
#define PWRC_A9_AUDIO_ID 42
#define PWRC_A9_DMC0_ID 43
#define PWRC_A9_GIC_ID 44
#define PWRC_A9_DDRPHY_ID 45
#define PWRC_A9_AUCPU_ID 46
#define PWRC_A9_DSI0_ID 47
#define PWRC_A9_DSI1_ID 48
#define PWRC_A9_CAN0_ID 49
#define PWRC_A9_CAN1_ID 50
#endif

View File

@ -0,0 +1,23 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
#ifndef _DT_BINDINGS_POWER_MT6858_POWER_H
#define _DT_BINDINGS_POWER_MT6858_POWER_H
#define MT6858_POWER_DOMAIN_MD 0
#define MT6858_POWER_DOMAIN_CONN 1
#define MT6858_POWER_DOMAIN_AUDIO 2
#define MT6858_POWER_DOMAIN_MM_INFRA 3
#define MT6858_POWER_DOMAIN_ISP_IMG1 4
#define MT6858_POWER_DOMAIN_ISP_IMG2 5
#define MT6858_POWER_DOMAIN_ISP_IPE 6
#define MT6858_POWER_DOMAIN_VDE0 7
#define MT6858_POWER_DOMAIN_VEN0 8
#define MT6858_POWER_DOMAIN_CAM_MAIN 9
#define MT6858_POWER_DOMAIN_CAM_SUBA 10
#define MT6858_POWER_DOMAIN_CAM_SUBB 11
#define MT6858_POWER_DOMAIN_DIS0 12
#define MT6858_POWER_DOMAIN_MM_PROC_DORMANT 13
#define MT6858_POWER_DOMAIN_CSI_RX 14
#define MT6858_POWER_DOMAIN_SSUSB 15
#endif /* _DT_BINDINGS_POWER_MT6858_POWER_H */

View File

@ -30,6 +30,10 @@
#define MT8196_POWER_DOMAIN_MM_PROC_DORMANT 0
#define MT8196_POWER_DOMAIN_SSR 1
/* HFRPSYS Multimedia Power Control (MMPC) - Direct Control */
#define MT8196_POWER_DOMAIN_EDPTX 0
#define MT8196_POWER_DOMAIN_DPTX 1
/* HFRPSYS MultiMedia Power Control (MMPC) - HW Voter */
#define MT8196_POWER_DOMAIN_VDE0 0
#define MT8196_POWER_DOMAIN_VDE1 1

View File

@ -0,0 +1,15 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
/*
* Copyright (C) 2026 Glider bv
*/
#ifndef __DT_BINDINGS_POWER_RENESAS_R8A78000_MDLC_H__
#define __DT_BINDINGS_POWER_RENESAS_R8A78000_MDLC_H__
/* R-Car X5H Module Controller Always-On Power Domains */
#define R8A78000_MDLC_PD_AON 0x40
#define R8A78000_MDLC_PD_SCP 0x41
#define R8A78000_MDLC_PD_APL 0x42
#define R8A78000_MDLC_PD_ACL 0x43
#endif /* __DT_BINDINGS_POWER_RENESAS_R8A78000_MDLC_H__ */

View File

@ -22,6 +22,9 @@
ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, MTK_SIP_SMC_CONVENTION, \
ARM_SMCCC_OWNER_SIP, fn_id)
/* Modem related SMC call */
#define MTK_SIP_KERNEL_CCCI_CONTROL MTK_SIP_SMC_CMD(0x505)
/* DVFSRC SMC calls */
#define MTK_SIP_DVFSRC_VCOREFS_CONTROL MTK_SIP_SMC_CMD(0x506)