Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,22 @@
$id: http://devicetree.org/schemas/soc/apple/apple,t8140-sleep.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: Apple T8140 system sleep controls
title: Apple SoC system sleep controls

maintainers:
- Diljit Singh <hey@djdev.me>

description: |
The registers a kernel running directly at EL2 on T8140 writes to enter and
return from suspend-to-RAM and to power its secondary CPUs off. They belong to
several hardware blocks, some of which other drivers also use, so this node
The registers a kernel running directly at EL2 on an Apple SoC writes to enter
and return from suspend-to-RAM and to power its secondary CPUs off. They belong
to several hardware blocks, some of which other drivers also use, so this node
overlaps those drivers' register ranges and the driver does not claim them.
Each SoC has its own compatible, as its power domains differ.

properties:
compatible:
const: apple,t8140-sleep
enum:
- apple,t8140-sleep

reg:
maxItems: 28
Expand Down
2 changes: 1 addition & 1 deletion MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -2132,7 +2132,7 @@ F: drivers/phy/apple/atc-j700-dp.h
F: drivers/rtc/rtc-apple-pmu.c
F: drivers/soc/apple/aop.rs
F: drivers/soc/apple/mcc.c
F: drivers/soc/apple/t8140-sleep.c
F: drivers/soc/apple/sleep*.c
F: drivers/tty/serial/apple_dockchannel*
F: include/linux/soc/apple/pci-apple-piodma.h
F: include/linux/soc/apple/sleep.h
Expand Down
2 changes: 1 addition & 1 deletion arch/arm64/configs/asahi.config
Original file line number Diff line number Diff line change
Expand Up @@ -160,4 +160,4 @@ CONFIG_EDAC_APPLE_SOC=m
# unless the bootloader supplies a window (/chosen/aurora,ctxr-exec-window) or
# the ctxr_exec_window= command-line option is given.
CONFIG_ARM64_CTXR_EXECMEM=y
CONFIG_APPLE_T8140_SLEEP=y
CONFIG_APPLE_SOC_SLEEP=y
9 changes: 8 additions & 1 deletion drivers/gpu/drm/apple/dcp-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,13 @@ struct apple_dcp_hw_data {
* (desktop 26.x), see dcp_sink_metadata().
*/
bool sink_metadata_edid;
/*
* With H17P firmware: a firmware-driven system sleep stops the internal processor's
* firmware and powers it down, as DPMS off does, then restarts it warm, see
* dcp_s2r_suspend(). @s2r_ext: the same for an external one, see dcp_s2r_ext_suspend().
*/
bool s2r;
bool s2r_ext;
};

enum dcp_test_point {
Expand Down Expand Up @@ -641,7 +648,7 @@ struct apple_dcp {
/* Messages from the coprocessor are held in the mailbox for sleep. */
bool rx_held;

/* T8140 suspend-to-RAM stops the firmware, see dcp_s2r_suspend(). */
/* A firmware-driven suspend stops the firmware, see dcp_s2r_suspend(). */
bool s2r_active;
bool s2r_stopped;
/* DPMS off stopped the firmware and lowered the domains; DPMS on brings them back. */
Expand Down
19 changes: 9 additions & 10 deletions drivers/gpu/drm/apple/dcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -4533,7 +4533,7 @@ void dcp_poweroff(struct platform_device *pdev)
cancel_delayed_work(&dcp->swap_watchdog_wq);

/*
* Internal H17P DPMS is a brightness present, never a pipe stop. On T8140 the
* Internal H17P DPMS is a brightness present, never a pipe stop. With hw.s2r the
* display then powers off as well, after the backlight.
*/
if (dcp_uses_soft_dpms(dcp)) {
Expand Down Expand Up @@ -5630,8 +5630,7 @@ static int dcp_comp_bind_pipe(struct device *dev, struct device *main, void *dat
if (ret)
goto err_piodma;
/* After a warm restart its log counters need echoing, or it refuses its next idle. */
if (of_device_is_compatible(dev->of_node, "apple,t8140-dcp") ||
of_device_is_compatible(dev->of_node, "apple,t8140-dcpext"))
if (dcp->hw.s2r || dcp->hw.s2r_ext)
apple_rtkit_set_oslog_echo(dcp->rtk, true);
ret = dcp_secure_port_init(dcp);
if (ret)
Expand Down Expand Up @@ -6896,8 +6895,8 @@ static void dcp_platform_complete(struct device *dev)
}

/*
* T8140 suspend-to-RAM: the sleep engine waits for the DCP's domain to be off, so
* the firmware has to stop first. Measured from macOS, in order:
* Suspend-to-RAM with hw.s2r: the sleep engine waits for the DCP's domain to be off, so
* the firmware has to stop first. Measured from macOS on T8140, in order:
*
* 1. A414(0), A478 x2, A476(1), A478, A412, A473(0).
* 2. D572(0) from the firmware: the display DART's streams go off.
Expand Down Expand Up @@ -6967,8 +6966,7 @@ void dcp_s2r_dart_power(struct apple_dcp *dcp, u32 on)

static bool dcp_s2r_capable(struct apple_dcp *dcp)
{
return dcp->fw_compat == DCP_FIRMWARE_H17P &&
of_device_is_compatible(dcp->dev->of_node, "apple,t8140-dcp");
return dcp->fw_compat == DCP_FIRMWARE_H17P && dcp->hw.s2r;
}

static void dcp_s2r_cpu_stop(struct apple_dcp *dcp)
Expand Down Expand Up @@ -7158,8 +7156,7 @@ static int dcp_s2r_stop_firmware(struct apple_dcp *dcp)
*/
static bool dcp_s2r_ext_capable(struct apple_dcp *dcp)
{
return dcp->fw_compat == DCP_FIRMWARE_H17P &&
of_device_is_compatible(dcp->dev->of_node, "apple,t8140-dcpext");
return dcp->fw_compat == DCP_FIRMWARE_H17P && dcp->hw.s2r_ext;
}

/*
Expand Down Expand Up @@ -7940,7 +7937,7 @@ static void dcp_s2r_restart_failed_stop(struct apple_dcp *dcp)
}

/*
* DPMS on the internal T8140 panel as macOS does a display sleep: the backlight to 0,
* DPMS on an internal panel with hw.s2r as macOS does a display sleep: the backlight to 0,
* then the firmware stopped and the display domains off, and the reverse on wake. Not
* during a system sleep: that path stops the firmware itself.
*/
Expand Down Expand Up @@ -8211,6 +8208,7 @@ static const struct apple_dcp_hw_data apple_dcp_hw_t8140 = {
.firmware_display_windows = 5,
.firmware_scratch = 0x20000,
.firmware_request = 0x68000,
.s2r = true,
};

/* Separate from the established internal-panel H17P profile. */
Expand All @@ -8224,6 +8222,7 @@ static const struct apple_dcp_hw_data apple_dcp_hw_t8140_external = {
/* Native PMGR BWR agent 2 and boost agent 3 for DISPEXT0. */
.firmware_scratch = 0x28000,
.firmware_request = 0x70000,
.s2r_ext = true,
};

/*
Expand Down
14 changes: 8 additions & 6 deletions drivers/irqchip/irq-apple-aic.c
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,8 @@ struct aic_info {
* comes online.
*/
bool siq_cfg_routing;
/* A firmware-driven suspend powers the controller down: aic_syscore_ops keep it. */
bool fw_suspend;
};

static const struct aic_info aic1_info __initconst = {
Expand Down Expand Up @@ -336,6 +338,7 @@ static const struct aic_info aic3_t8140_info __initconst = {
.fast_ipi = true,
.local_fast_ipi = true,
.siq_cfg_routing = true,
.fw_suspend = true,
};

static const struct aic_info aic3_t8142_info __initconst = {
Expand Down Expand Up @@ -1131,7 +1134,7 @@ static void build_fiq_affinity(struct aic_irq_chip *ic, struct device_node *aff)

#ifdef CONFIG_PM_SLEEP
/*
* T8140's firmware-driven suspend powers the controller down and back up. How
* A firmware-driven suspend powers the controller down and back up. How
* much it keeps isn't measured, and macOS saves and restores it in software. So
* mask everything before the commit, so that no line can end the final WFI, and
* put it all back after. Linux never writes IRQ_CFG or these global registers
Expand Down Expand Up @@ -1239,10 +1242,9 @@ static struct syscore aic_syscore = {
.ops = &aic_syscore_ops,
};

static void __init aic_sleep_init(struct aic_irq_chip *irqc, struct device_node *node)
static void __init aic_sleep_init(struct aic_irq_chip *irqc)
{
/* The only Apple SoC with a suspend-to-RAM path. */
if (!of_device_is_compatible(node, "apple,t8140-aic3"))
if (!irqc->info.fw_suspend)
return;

aic_sleep.irq_cfg = kcalloc(irqc->nr_die * irqc->nr_irq, sizeof(u32), GFP_KERNEL);
Expand All @@ -1252,7 +1254,7 @@ static void __init aic_sleep_init(struct aic_irq_chip *irqc, struct device_node
register_syscore(&aic_syscore);
}
#else
static void __init aic_sleep_init(struct aic_irq_chip *irqc, struct device_node *node)
static void __init aic_sleep_init(struct aic_irq_chip *irqc)
{
}
#endif
Expand Down Expand Up @@ -1398,7 +1400,7 @@ static int __init aic_of_ic_init(struct device_node *node, struct device_node *p
"irqchip/apple-aic/ipi:starting",
aic_init_cpu, NULL);

aic_sleep_init(irqc, node);
aic_sleep_init(irqc);

if (is_kernel_in_hyp_mode()) {
struct irq_fwspec mi = {
Expand Down
29 changes: 26 additions & 3 deletions drivers/soc/apple/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -105,17 +105,34 @@ config APPLE_CLUSTER_PWRGATE
started and PMGR never powered on, such as the boot CPU, only
clock-gates in WFI.

config APPLE_T8140_SLEEP
bool "Apple T8140 system sleep at EL2"
config APPLE_SOC_SLEEP
bool "Apple SoC system sleep at EL2"
default APPLE_T8140_SLEEP
depends on ARM64 && (ARCH_APPLE || COMPILE_TEST)
depends on HOTPLUG_CPU && SUSPEND
select APPLE_TUNABLE
help
Powers the secondary CPUs off and suspends the system to RAM on an
Apple T8140 whose kernel runs directly at EL2, with no monitor to ask.
Apple SoC whose kernel runs directly at EL2, with no monitor to ask.
It does nothing unless the boot object asks for it through
/chosen/aurora,s2r-mailbox.

Only SoCs whose sleep has been measured and tested are supported,
each by its match data: today T8140. On every other SoC the driver
doesn't bind, and s2idle stays the only system sleep.

config APPLE_SOC_SLEEP_KUNIT_TEST
bool "KUnit tests for the Apple SoC sleep match data" if !KUNIT_ALL_TESTS
depends on APPLE_SOC_SLEEP && KUNIT=y
default KUNIT_ALL_TESTS
help
Checks each matched SoC's sleep data: that only tested SoCs are
matched, that every list names only words of the SoC's full lists,
with no duplicates, and that the lists fit the driver's books. The
tests touch no hardware.

If unsure, say N.

config APPLE_RTKIT
tristate "Apple RTKit co-processor IPC protocol"
depends on APPLE_MAILBOX
Expand Down Expand Up @@ -379,3 +396,9 @@ config APPLE_DISPLAY_GATE_KUNIT_TEST
endmenu

endif

config APPLE_T8140_SLEEP
bool
transitional
help
Transitional config for APPLE_T8140_SLEEP to APPLE_SOC_SLEEP migration.
3 changes: 2 additions & 1 deletion drivers/soc/apple/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ obj-$(CONFIG_APPLE_PMGR_MISC) += apple-pmgr-misc.o

obj-$(CONFIG_APPLE_CLUSTER_PWRGATE) += apple-cluster-pwrgate.o

obj-$(CONFIG_APPLE_T8140_SLEEP) += t8140-sleep.o
obj-$(CONFIG_APPLE_SOC_SLEEP) += apple-sleep.o
apple-sleep-y = sleep.o

obj-$(CONFIG_APPLE_RTKIT) += apple-rtkit.o
apple-rtkit-y = rtkit.o rtkit-crashlog.o
Expand Down
2 changes: 1 addition & 1 deletion drivers/soc/apple/pm_shim.c
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ int sep_pm_commit_prepare(void *ptr, void *mbox, u64 msg0, u32 msg1, u64 reply,
int ret;

/* Check capability before resources that legacy providers need not have. */
if (!READ_ONCE(sep_pm_suspending) || !IS_ENABLED(CONFIG_APPLE_T8140_SLEEP) ||
if (!READ_ONCE(sep_pm_suspending) || !IS_ENABLED(CONFIG_APPLE_SOC_SLEEP) ||
!is_kernel_in_hyp_mode())
return -EOPNOTSUPP;
if (c->registered)
Expand Down
Loading
Loading