Skip to content
Open
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
25 changes: 23 additions & 2 deletions Documentation/devicetree/bindings/rtc/apple,smc-rtc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,36 @@ properties:
const: apple,smc-rtc

nvmem-cells:
minItems: 1
items:
- description:
RTC offset. By default a 48bit value, specified in 32768 (2^15) Hz
clock ticks. With apple,rtc-offset-seconds, a 64bit little-endian
count of whole seconds.
- description:
PMU alarm control byte, with the alarm enable, the monitor bit and
the latched alarm event.
- description:
PMU alarm compare value, a 32-bit count of whole seconds of the RTC
counter without the offset.
- description: PMU alarm mask byte.

nvmem-cell-names:
items:
- const: rtc_offset
oneOf:
- items:
- const: rtc_offset
- items:
- const: rtc_offset
- const: rtc_ctrl
- const: rtc_alarm
- const: rtc_alarm_mask

interrupts:
maxItems: 1
description:
The PMU's RTC alarm interrupt. Only used with the three alarm cells.

wakeup-source: true

apple,rtc-offset-seconds:
type: boolean
Expand Down
23 changes: 21 additions & 2 deletions arch/arm64/boot/dts/apple/t6030.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -1060,6 +1060,8 @@
#size-cells = <0>;
interrupt-parent = <&aic>;
interrupts = <AIC_IRQ 485 IRQ_TYPE_LEVEL_HIGH>;
interrupt-controller;

Check warning on line 1063 in arch/arm64/boot/dts/apple/t6030.dtsi

View workflow job for this annotation

GitHub Actions / ci / device trees

dt-check style

[property-order] property 'interrupt-controller' out of canonical order (should sort before 'interrupts')
#interrupt-cells = <2>;

pmic1: pmic@b {
compatible = "apple,chapel-pmic", "apple,spmi-nvmem";
Expand All @@ -1070,10 +1072,22 @@
#address-cells = <1>;
#size-cells = <1>;

rtc_ctrl: rtc-ctrl@2000 {
reg = <0x2000 0x1>;
};

pm_setting: pm-setting@2001 {
reg = <0x2001 0x1>;
};

rtc_alarm: rtc-alarm@2008 {
reg = <0x2008 0x4>;
};

rtc_alarm_mask: rtc-alarm-mask@200e {
reg = <0x200e 0x1>;
};

rtc_offset: rtc-offset@2100 {
reg = <0x2100 0x6>;
};
Expand Down Expand Up @@ -1182,8 +1196,13 @@

rtc {
compatible = "apple,smc-rtc";
nvmem-cells = <&rtc_offset>;
nvmem-cell-names = "rtc_offset";
nvmem-cells = <&rtc_offset>, <&rtc_ctrl>, <&rtc_alarm>,
<&rtc_alarm_mask>;

Check warning on line 1200 in arch/arm64/boot/dts/apple/t6030.dtsi

View workflow job for this annotation

GitHub Actions / ci / device trees

dt-check style

[continuation-alignment] continuation should align to column 47 (under "<" or \")
nvmem-cell-names = "rtc_offset", "rtc_ctrl", "rtc_alarm",
"rtc_alarm_mask";

Check warning on line 1202 in arch/arm64/boot/dts/apple/t6030.dtsi

View workflow job for this annotation

GitHub Actions / ci / device trees

dt-check style

[continuation-alignment] continuation should align to column 52 (under "<" or \")
/* The PMIC's RTC alarm, peripheral interrupt 2 of nub-spmi0 */

Check warning on line 1203 in arch/arm64/boot/dts/apple/t6030.dtsi

View workflow job for this annotation

GitHub Actions / ci / device trees

dt-check style

[line-length] line exceeds 80 columns (95)
interrupts-extended = <&nub_spmi 2 IRQ_TYPE_EDGE_RISING>;

Check warning on line 1204 in arch/arm64/boot/dts/apple/t6030.dtsi

View workflow job for this annotation

GitHub Actions / ci / device trees

dt-check style

[property-order] property 'interrupts-extended' out of canonical order (should sort before 'nvmem-cell-names')
wakeup-source;
};
};

Expand Down Expand Up @@ -1520,7 +1539,7 @@
port02: pci@2,0 {
device_type = "pci";
reg = <0x1000 0x0 0x0 0x0 0x0>;
reset-gpios = <&pinctrl_ap 169 GPIO_ACTIVE_LOW>; // perst

Check warning on line 1542 in arch/arm64/boot/dts/apple/t6030.dtsi

View workflow job for this annotation

GitHub Actions / ci / device trees

dt-check style

[line-length] line exceeds 80 columns (89)

#address-cells = <3>;
#size-cells = <2>;
Expand All @@ -1547,7 +1566,7 @@
ranges;

interrupt-controller;
#interrupt-cells = <1>;

Check warning on line 1569 in arch/arm64/boot/dts/apple/t6030.dtsi

View workflow job for this annotation

GitHub Actions / ci / device trees

dt-check style

[property-order] property '#interrupt-cells' out of canonical order (should sort before 'interrupt-controller')

interrupt-map-mask = <0 0 0 7>;
interrupt-map = <0 0 0 1 &port03 0 0 0 0>,
Expand Down Expand Up @@ -2063,7 +2082,7 @@

dwc3_2: usb@f02280000 {
compatible = "apple,t6030-dwc3", "apple,t8103-dwc3";
reg = <0xf 0x02280000 0x0 0xcd00>, <0xf 0x0228cd00 0x0 0x3200>;

Check warning on line 2085 in arch/arm64/boot/dts/apple/t6030.dtsi

View workflow job for this annotation

GitHub Actions / ci / device trees

dt-check style

[line-length] line exceeds 80 columns (87)
reg-names = "dwc3-core", "dwc3-apple";
interrupt-parent = <&aic>;
interrupts = <AIC_IRQ 1203 IRQ_TYPE_LEVEL_HIGH>;
Expand Down
22 changes: 8 additions & 14 deletions drivers/gpu/drm/apple/dcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -4823,11 +4823,12 @@ static void dcp_release_after_sleep(struct apple_dcp *dcp)
/*
* Why an external processor must keep the system awake, or NULL. The manual
* path refuses sleep once its firmware was ever started. A native processor
* refuses while its firmware starts or holds a display link, and while a
* display is attached to it at all, lit or not: resume does not bring an
* attached display back. Idle with nothing attached, its firmware stays
* powered across s2idle like the panel's (the gate holds its CPU domain at
* the active floor) and the next attach reconnects through it.
* refuses while its firmware starts or a display is lit (user space turns
* displays off before sleep). A dark attached display sleeps with it:
* suspend releases an HDMI link and keeps a Type-C tunnel, and resume finds
* the display again as after DPMS off. Its firmware stays powered across
* s2idle like the panel's (the gate holds its CPU domain at the active
* floor), and the next attach reconnects through it.
*
* A processor that failed (its start, or its session later) never refuses
* sleep: it drives no display until reboot, attached or not, and its power
Expand All @@ -4845,15 +4846,8 @@ static const char *dcp_external_sleep_vetoed(struct apple_dcp *dcp)
why = iomfb_v14_7_external_busy(dcp);
if (why)
return why;
if (iomfb_v14_7_external_failed(dcp)) {
if (dcp->v14)
dev_info(dcp->dev, "external display processor failed earlier: sleeping with it as it is\n");
return NULL;
}
if (READ_ONCE(dcp->active_typec_route) || READ_ONCE(dcp->typec_cable_connected))
return "a USB-C display is attached";
if (dcp->hdmi_hpd && gpiod_get_value_cansleep(dcp->hdmi_hpd) > 0)
return "an HDMI display is attached";
if (iomfb_v14_7_external_failed(dcp) && dcp->v14)
dev_info(dcp->dev, "external display processor failed earlier: sleeping with it as it is\n");
return NULL;
}

Expand Down
106 changes: 97 additions & 9 deletions drivers/gpu/drm/apple/iomfb_v14_7.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/soc/apple/pmp-report.h>
#include <linux/suspend.h>
#include <linux/soc/apple/rtkit.h>
#include <linux/unaligned.h>
#include <linux/workqueue.h>
Expand Down Expand Up @@ -304,8 +305,14 @@ struct apple_dcp_v14 {
enum dcp_v14_bl_gate bl_gate;
u32 nits_sent;
u64 nits_presents, brightness_presents, nits_refused;
/* Panel: its display controller is stopped (A472 hardware power off). */
bool panel_off;
};

static bool panel_hw_off = true;
module_param(panel_hw_off, bool, 0644);
MODULE_PARM_DESC(panel_hw_off, "Internal 14.7 panel: stop its display controller on DPMS off, not only blank it [default: true]");

/*
* The panel's DCP session; one per boot, RTKit is never started twice. The
* manual external start waits for it, as the PMP runs once the panel's
Expand Down Expand Up @@ -1150,6 +1157,24 @@ static int dcp_v14_callback(void *cookie, u32 tag, const void *input, u32 in_siz
/* Swap information for a completed swap; the link checks its id. */
if (tag == D(589) && SHAPE(0x6f0, 0))
return 0;
/*
* The panel's display-controller power transitions (A472 with the
* hardware selector): will power off and an intent swap, both
* notifications; display DART power and a kernel power assertion, both
* held by the host throughout, so status 0; and the backlight message
* at power on, which the backlight restore after A472(1) answers. Only
* the J514S/J516S panel sends A472 so; elsewhere these stay unhandled.
*/
if (dcp_v14_board_nits(v14) &&
((tag == D(2) && SHAPE(0, 0)) || (tag == D(591) && SHAPE(20, 0)) ||
(tag == D(593) && SHAPE(4, 0))))
return 0;
if (dcp_v14_board_nits(v14) && (tag == D(574) || tag == D(700)) && SHAPE(4, 4)) {
if (tag == D(574) && in[0] > 1)
return -EINVAL;
put_unaligned_le32(0, out);
return 0;
}
if ((tag == D(588) && SHAPE(8, 0)) || (tag == D(598) && SHAPE(0, 0)))
return 0;
/* Main-display query, answered by asking the firmware. */
Expand Down Expand Up @@ -2082,8 +2107,8 @@ bool iomfb_v14_7_external_ready(struct apple_dcp *dcp)

/*
* What this processor's firmware holds that system sleep would not hand
* back, or NULL: a start in progress, or a display link or a powered
* display. The caller also refuses sleep while a display is attached.
* back, or NULL: a start in progress, or a powered display. Suspend
* releases a dark display's link itself.
*/
const char *iomfb_v14_7_external_busy(struct apple_dcp *dcp)
{
Expand All @@ -2094,10 +2119,8 @@ const char *iomfb_v14_7_external_busy(struct apple_dcp *dcp)
/* A stopped session drives nothing, whatever it held last. */
if (dcp->v14 && READ_ONCE(dcp->v14->failed))
return NULL;
if (READ_ONCE(dcp->dptxport[0].connected) ||
READ_ONCE(dcp->external_link_ready) ||
(dcp->v14 && READ_ONCE(dcp->v14->powered)))
return "a display link is up";
if (dcp->v14 && READ_ONCE(dcp->v14->powered))
return "a display is lit";
return NULL;
default:
return NULL;
Expand Down Expand Up @@ -3108,6 +3131,32 @@ static int dcp_v14_set_power(struct apple_dcp_v14 *v14, bool on)
return ret;
}

/*
* A472 with the hardware selector (+8) and a null output word (+11): the
* panel's display controller off or on. Off stops scanout and the panel once
* a blank has been presented, on restarts them; the soft form (+8 clear)
* leaves the controller running. The client, the RTKit session and every
* mapping are kept.
*/
static int dcp_v14_panel_power(struct apple_dcp_v14 *v14, bool on)
{
u8 in[12] = {}, out[8] = {};
int ret;

put_unaligned_le64(on, in);
in[8] = 1;
in[11] = 1;
ret = dcp_v14_call(v14, A(472), in, sizeof(in), out, sizeof(out), 0);
if (!ret && get_unaligned_le32(out + 4)) {
dev_err(v14->dev, "display controller %s refused: %#x\n", on ? "on" : "off",
get_unaligned_le32(out + 4));
ret = -EIO;
}
if (!ret)
v14->panel_off = !on;
return ret;
}

/* The display is fully described, and no description is in transfer. */
static bool dcp_v14_external_described(struct apple_dcp_v14 *v14)
{
Expand Down Expand Up @@ -3344,8 +3393,35 @@ void iomfb_v14_7_flush(struct apple_dcp *dcp, struct drm_crtc *crtc,
dcp_v14_cancel_event(dcp);
}

/* A system sleep is in progress, as opposed to a DPMS change. */
static bool dcp_v14_system_sleep(void)
{
KUNIT_STATIC_STUB_REDIRECT(dcp_v14_system_sleep);
return pm_suspend_in_progress();
}

void iomfb_v14_7_poweron(struct apple_dcp *dcp)
{
struct apple_dcp_v14 *v14 = dcp->v14;
bool dark;

/*
* The display controller first, then the backlight, as at boot. A
* refused power on is tried once more. If the controller stays off,
* so does the backlight, rather than light a dark panel; the next
* power on tries again.
*/
if (!dcp->external && v14 && v14->panel_off) {
mutex_lock(&v14->lock);
if (v14->panel_off && dcp_v14_panel_power(v14, true))
dcp_v14_panel_power(v14, true);
dark = v14->panel_off;
mutex_unlock(&v14->lock);
if (dark) {
dev_err(dcp->dev, "display controller did not power on: backlight left off\n");
return;
}
}
/* The next present restores a level only after Linux has set one. */
if (dcp->v14 && dcp_v14_bl_dpms_applies(dcp->v14, dcp))
dcp_backlight_dpms(dcp, true);
Expand All @@ -3369,9 +3445,21 @@ void iomfb_v14_7_poweroff(struct apple_dcp *dcp)
dcp_mode_invalidate(&dcp->mode_state);
return;
}
/* Blank to black; the panel and the DCP stay powered. */
if (v14 && v14->started)
dcp_v14_blank(v14, dcp);
/* Blank to black, then stop the display controller; the DCP stays powered. */
if (!v14 || !v14->started)
return;
dcp_v14_blank(v14, dcp);
/*
* Only the J514S/J516S panel, the one this was measured on, and only
* on DPMS off: suspend-to-idle cuts that power itself.
*/
if (!panel_hw_off || !dcp_v14_board_nits(v14) || dcp_v14_system_sleep())
return;
mutex_lock(&v14->lock);
if (!v14->panel_off && !READ_ONCE(v14->failed) && !READ_ONCE(dcp->crashed) &&
!v14->active_fb && dcp_v14_panel_power(v14, false))
dev_err(dcp->dev, "display controller did not power off\n");
mutex_unlock(&v14->lock);
}

#if IS_ENABLED(CONFIG_DRM_APPLE_DISPLAY_KUNIT_TEST)
Expand Down
Loading
Loading