mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
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:
@@ -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>;
|
||||
};
|
||||
@@ -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:
|
||||
|
||||
@@ -18,6 +18,7 @@ properties:
|
||||
oneOf:
|
||||
- enum:
|
||||
- qcom,glymur-rpmhpd
|
||||
- qcom,kaanapali-rpmhpd
|
||||
- qcom,mdm9607-rpmpd
|
||||
- qcom,milos-rpmhpd
|
||||
- qcom,msm8226-rpmpd
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
+3
-6
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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 */ },
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user