Watch
1
0
Fork
You've already forked SouveraineOS
0

TASK-63: touch on the glass, and a display pipe on T8010

Touch proven with real events, not a device node: three layers, the last
being runtime report activation gated to D11 so D10 went silent a second
after boot.

adp binds on 206200000.display-pipe with card1-DSI-1 — the first DRM
display pipe on this hardware; everyone else scans a dumb framebuffer.
Still unused because m1n1 re-enables /chosen/framebuffer and udev then
hands viewtop simpledrm.

Kernel patch kept as evidence; hoolock/ is not a repo.
This commit is contained in:
Fimeg 2026-08-09 22:09:18 -04:00
commit dd5e242227
2 changed files with 851 additions and 0 deletions

View file

@ -0,0 +1,750 @@
From 2e349ddf2fe35102ef7c281d356c0e9a53c0f526 Mon Sep 17 00:00:00 2001
From: Casey Tunturi <casey@samaritansolutions.net>
Date: Mon, 10 Aug 2026 02:05:11 +0000
Subject: [PATCH] apple: d10: touch runtime reports and the display pipe
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
apple_z2: D10 shares D11 gen2 runtime reports. Without the enable, boot
frames arrive and the panel goes silent about a second later.
adp: first display pipe on T8010. disp0 be 0x06200000/0x9000, fe
0x06400000/0x4000, irqs 154/158; dart 0x06304000 irq 156; dsi
0x06600000/0x100000 — byte-identical to T8012, which is A10 silicon.
Values read off the D10 ADT. panel-summit gains a 750x1334 mode; the
loader lights the panel, so there is no init sequence either way.
---
arch/arm64/boot/dts/apple/t8010-d10.dts | 179 ++++++++++++++++++++++++
arch/arm64/boot/dts/apple/t8010.dtsi | 57 ++++++++
drivers/gpu/drm/panel/panel-summit.c | 26 +++-
drivers/input/touchscreen/apple_z2.c | 110 +++++++++------
4 files changed, 327 insertions(+), 45 deletions(-)
diff --git a/arch/arm64/boot/dts/apple/t8010-d10.dts b/arch/arm64/boot/dts/apple/t8010-d10.dts
index 39cdd12db..5f00bbe19 100644
--- a/arch/arm64/boot/dts/apple/t8010-d10.dts
+++ b/arch/arm64/boot/dts/apple/t8010-d10.dts
@@ -2,6 +2,10 @@
/*
* Apple iPhone 7 (Qualcomm), D10, iPhone9,1 (A1660/A1778/A1779/A1780)
* Copyright (c) 2022, Konrad Dybcio <konradybcio@kernel.org>
+ *
+ * Board values derived from the D10 ADT read off hardware 2026-08-08.
+ * Bus topology is identical to D11; see d10-port/DELTAS.md for the five
+ * values that differ and which of them still need driver work.
*/
/dts-v1/;
@@ -11,4 +15,179 @@
/ {
compatible = "apple,d10", "apple,t8010", "apple,arm-platform";
model = "Apple iPhone 7 (Qualcomm)";
+
+ aliases {
+ touchscreen0 = &touchscreen;
+ };
+
+ d10_battery: battery {
+ compatible = "simple-battery";
+ constant-charge-current-max-microamp = <1950000>;
+ };
+};
+
+/*
+ * Wi-Fi is deliberately absent. The ADT describes BCM4350 on PCIe port 3
+ * (perst 15, clkreq 19, device_wake 88, reg_on pmu_gpio 10, module-instance
+ * "kristoff"), but no driver claims it, so PCI pwrctrl never completes and the
+ * deferred host bridge takes NVMe down with it:
+ * pcie-apple-h9p: waiting for PCI power controls
+ * Restore the port node only alongside a BCM4350 driver. Values: d10-port/DELTAS.md.
+ */
+
+&i2c0 {
+ status = "okay";
+
+ pmic@27 {
+ compatible = "apple,chestnut-pmic";
+ reg = <0x27>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ touch_hv: regulator-touch-hv {
+ compatible = "apple,chestnut-touch-hv-regulator";
+ regulator-name = "touch-hv";
+ };
+ };
+};
+
+&i2c1 {
+ charger@75 {
+ compatible = "apple,sn2400";
+ reg = <0x75>;
+
+ sn2400_charger: charger {
+ compatible = "apple,sn2400-charger";
+ monitored-battery = <&d10_battery>;
+ input-current-limit-microamp = <2000000>;
+ mux-states = <&hdq_mux 0>;
+ mux-state-names = "hdq";
+ };
+
+ hdq_mux: hdq-mux {
+ compatible = "apple,sn2400-hdq-mux";
+ #mux-state-cells = <1>;
+ };
+ };
+};
+
+&i2c2 {
+ status = "okay";
+
+ light-sensor@29 {
+ compatible = "apple,ct821", "amstaos,tsl2581";
+ reg = <0x29>;
+ interrupts-extended = <&pinctrl_ap 141 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+&pinctrl_ap {
+ battery_swi_pins: battery-swi-pins {
+ pinmux = <APPLE_PINMUX(173, 1)>;
+ };
+
+};
+
+&serial5 {
+ pinctrl-0 = <&battery_swi_pins>;
+ pinctrl-names = "default";
+ status = "okay";
+
+ onewire {
+ compatible = "ti,hdq-uart";
+ mux-states = <&hdq_mux 1>;
+ mux-state-names = "hdq";
+
+ /* ADT: gas-gauge,bq27540 — D11 is a bq27545. */
+ fuel-gauge {
+ compatible = "apple,d10-bq27540", "ti,bq27540-hdq";
+ monitored-battery = <&d10_battery>;
+ };
+ };
+};
+
+&spi2 {
+ cs-gpios = <&pinctrl_ap 81 GPIO_ACTIVE_LOW>;
+ dmas = <&sio 0x18>;
+ dma-names = "tx";
+ status = "okay";
+
+ touchscreen: touchscreen@0 {
+ compatible = "apple,d10-touchscreen";
+ reg = <0>;
+ spi-max-frequency = <3000000>;
+ spi-cpol;
+ spi-cpha;
+ apple,z2-no-init-ack;
+ interrupts-extended = <&pinctrl_ap 166 IRQ_TYPE_EDGE_FALLING>;
+ reset-gpios = <&pinctrl_ap 161 GPIO_ACTIVE_LOW>;
+ hv-supply = <&touch_hv>;
+ core-supply = <&touch_core>;
+ clocks = <&touchclk>;
+ /* ADT hid-merge-personality = C1F5D,2 (D11/D111 are C1F5E,2). */
+ firmware-name = "apple/dfrmtfw-d10-c1f5d-2.bin";
+ touchscreen-size-x = <750>;
+ touchscreen-size-y = <1334>;
+ };
+};
+
+&sio {
+ status = "okay";
+};
+
+&touchclk {
+ clock-frequency = <32768>;
+};
+
+/*
+ * Apple Display Pipe. ADP inherits bootloader-initialised state, so the
+ * back-end domain must stay powered or the driver loses the panel m1n1 lit.
+ */
+&ps_disp0_be {
+ apple,always-on;
+};
+
+&disp0 {
+ status = "okay";
+};
+
+&disp0_dart {
+ status = "okay";
+};
+
+&disp0_mipi {
+ status = "okay";
+};
+
+&mipi_out {
+ mipi_out_panel: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&panel_in>;
+ };
+};
+
+&disp0_mipi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ panel@0 {
+ compatible = "apple,d10-panel";
+ reg = <0>;
+ max-brightness = <2047>;
+
+ port {
+ panel_in: endpoint {
+ remote-endpoint = <&mipi_out_panel>;
+ };
+ };
+ };
+};
+
+/*
+ * ADP owns the panel, so the loader framebuffer must not also claim it:
+ * simpledrm binds first as the boot console and udev then names it the
+ * primary GPU, which is the card the compositor picks. One writer.
+ */
+&framebuffer0 {
+ status = "disabled";
};
diff --git a/arch/arm64/boot/dts/apple/t8010.dtsi b/arch/arm64/boot/dts/apple/t8010.dtsi
index 8dc02eb60..7ec65050e 100644
--- a/arch/arm64/boot/dts/apple/t8010.dtsi
+++ b/arch/arm64/boot/dts/apple/t8010.dtsi
@@ -358,6 +358,63 @@ ehci1: usb-ehci@20c400000 {
#endif
};
+ disp0: display-pipe@206200000 {
+ compatible = "apple,t8010-display-pipe", "apple,h7-display-pipe";
+ reg = <0x2 0x06200000 0x0 0x9000>,
+ <0x2 0x06400000 0x0 0x4000>;
+ reg-names = "be", "fe";
+ power-domains = <&ps_disp0_fe>, <&ps_disp0_be>;
+ interrupts = <AIC_IRQ 154 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 158 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "be", "fe";
+ iommus = <&disp0_dart 0>;
+ status = "disabled";
+
+ port {
+ adp_out_mipi: endpoint {
+ remote-endpoint = <&mipi_in_adp>;
+ };
+ };
+ };
+
+ disp0_dart: iommu@206304000 {
+ compatible = "apple,t8010-dart", "apple,s5l8960x-dart";
+ reg = <0x2 0x06304000 0x0 0x4000>;
+ interrupts = <AIC_IRQ 156 IRQ_TYPE_LEVEL_HIGH>;
+ #iommu-cells = <1>;
+ power-domains = <&ps_disp0_fe>;
+ status = "disabled";
+ };
+
+ disp0_mipi: dsi@206600000 {
+ compatible = "apple,t8010-display-pipe-mipi", "apple,h7-display-pipe-mipi";
+ reg = <0x2 0x06600000 0x0 0x100000>;
+ power-domains = <&ps_mipi_dsi>;
+ status = "disabled";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ mipi_in: port@0 {
+ reg = <0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ mipi_in_adp: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&adp_out_mipi>;
+ };
+ };
+
+ mipi_out: port@1 {
+ reg = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+ };
+
pcie0_dart0: iommu@601008000 {
compatible = "apple,t8010-dart", "apple,s5l8960x-dart";
reg = <0x6 0x01008000 0x0 0x4000>;
diff --git a/drivers/gpu/drm/panel/panel-summit.c b/drivers/gpu/drm/panel/panel-summit.c
index 6d40b9ddf..42e4c24fb 100644
--- a/drivers/gpu/drm/panel/panel-summit.c
+++ b/drivers/gpu/drm/panel/panel-summit.c
@@ -2,6 +2,7 @@
#include <linux/backlight.h>
#include <linux/mod_devicetable.h>
+#include <linux/of.h>
#include <linux/property.h>
#include <drm/drm_device.h>
#include <drm/drm_mipi_dsi.h>
@@ -48,15 +49,35 @@ static struct drm_display_mode summit_mode = {
.flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC,
};
+/* iPhone 7 (D10): 750x1334, lit by m1n1 before Linux starts. */
+static struct drm_display_mode d10_mode = {
+ .hdisplay = 750,
+ .vdisplay = 1334,
+ .hsync_start = 750 + 8,
+ .hsync_end = 750 + 8 + 16,
+ .htotal = 750 + 8 + 16 + 16,
+ .vsync_start = 1334 + 4,
+ .vsync_end = 1334 + 4 + 8,
+ .vtotal = 1334 + 4 + 8 + 8,
+ .clock = ((750 + 8 + 16 + 16) * (1334 + 4 + 8 + 8) * 60) / 1000,
+ .type = DRM_MODE_TYPE_DRIVER,
+ .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC,
+};
+
static int summit_get_modes(struct drm_panel *panel,
struct drm_connector *connector)
{
+ const struct drm_display_mode *mode =
+ of_device_get_match_data(panel->dev);
+
+ if (!mode)
+ mode = &summit_mode;
connector->display_info.non_desktop = true;
drm_object_property_set_value(&connector->base,
connector->dev->mode_config.non_desktop_property,
connector->display_info.non_desktop);
- return drm_connector_helper_get_modes_fixed(connector, &summit_mode);
+ return drm_connector_helper_get_modes_fixed(connector, mode);
}
static const struct drm_panel_funcs summit_panel_funcs = {
@@ -113,7 +134,8 @@ static DEFINE_SIMPLE_DEV_PM_OPS(summit_pm_ops, summit_suspend,
summit_set_brightness);
static const struct of_device_id summit_of_match[] = {
- { .compatible = "apple,summit" },
+ { .compatible = "apple,summit", .data = &summit_mode },
+ { .compatible = "apple,d10-panel", .data = &d10_mode },
{},
};
diff --git a/drivers/input/touchscreen/apple_z2.c b/drivers/input/touchscreen/apple_z2.c
index ec84de96f..065fa8214 100644
--- a/drivers/input/touchscreen/apple_z2.c
+++ b/drivers/input/touchscreen/apple_z2.c
@@ -93,6 +93,7 @@ enum apple_z2_protocol_state {
enum apple_z2_variant {
APPLE_Z2_VARIANT_GENERIC,
APPLE_Z2_VARIANT_J172,
+ APPLE_Z2_VARIANT_D10,
APPLE_Z2_VARIANT_D11,
APPLE_Z2_VARIANT_D111,
};
@@ -150,19 +151,35 @@ static bool apple_z2_is_j172(const struct apple_z2 *z2)
return z2->variant == APPLE_Z2_VARIANT_J172;
}
+static bool apple_z2_is_d10(const struct apple_z2 *z2)
+{
+ return z2->variant == APPLE_Z2_VARIANT_D10;
+}
+
static bool apple_z2_is_d11(const struct apple_z2 *z2)
{
return z2->variant == APPLE_Z2_VARIANT_D11;
}
+/* D10 and D11 share the gen2 runtime report protocol. Without the enable,
+ * boot frames arrive and the panel then goes silent — measured on d10
+ * 2026-08-09: touch reported for about a second after probe, then nothing. */
+static bool apple_z2_is_gen2_reports(const struct apple_z2 *z2)
+{
+ return z2->variant == APPLE_Z2_VARIANT_D10 ||
+ z2->variant == APPLE_Z2_VARIANT_D11;
+}
+
static bool apple_z2_is_d111(const struct apple_z2 *z2)
{
return z2->variant == APPLE_Z2_VARIANT_D111;
}
-static bool apple_z2_is_iphone7_plus(const struct apple_z2 *z2)
+/* Whole T8010 iPhone 7 generation, both panel sizes. */
+static bool apple_z2_is_iphone7(const struct apple_z2 *z2)
{
- return apple_z2_is_d11(z2) || apple_z2_is_d111(z2);
+ return apple_z2_is_d10(z2) || apple_z2_is_d11(z2) ||
+ apple_z2_is_d111(z2);
}
struct apple_z2_finger {
@@ -404,7 +421,7 @@ static void apple_z2_parse_touches(struct apple_z2 *z2,
msg_len, nfingers);
return;
}
- if (apple_z2_is_iphone7_plus(z2) && nfingers &&
+ if (apple_z2_is_iphone7(z2) && nfingers &&
!z2->surface_descriptor_valid) {
dev_warn_ratelimited(&z2->spidev->dev,
"iPhone 7 Plus touch packet without surface descriptor\n");
@@ -422,7 +439,7 @@ static void apple_z2_parse_touches(struct apple_z2 *z2,
input_mt_slot(z2->input_dev, slot);
if (!input_mt_report_slot_state(z2->input_dev, MT_TOOL_FINGER, slot_valid))
continue;
- if (apple_z2_is_iphone7_plus(z2)) {
+ if (apple_z2_is_iphone7(z2)) {
abs_x = (s16)le16_to_cpu(fingers[i].abs_x);
abs_y = (s16)le16_to_cpu(fingers[i].abs_y);
coords_valid = apple_z2_scale_iphone7_coord(abs_x,
@@ -454,7 +471,7 @@ static void apple_z2_parse_touches(struct apple_z2 *z2,
input_report_abs(z2->input_dev, ABS_MT_WIDTH_MINOR,
le16_to_cpu(fingers[i].tool_minor));
orientation = (s16)le16_to_cpu(fingers[i].orientation);
- if (apple_z2_is_iphone7_plus(z2))
+ if (apple_z2_is_iphone7(z2))
orientation = (s16)(0x4000 - orientation);
input_report_abs(z2->input_dev, ABS_MT_ORIENTATION, orientation);
input_report_abs(z2->input_dev, ABS_MT_TOUCH_MAJOR,
@@ -473,7 +490,7 @@ static void apple_z2_dispatch_frame(struct apple_z2 *z2, const u8 *payload,
u16 report_len;
/* iPhone 7 Plus Gen2 packets carry the legacy report header directly. */
- if (apple_z2_is_iphone7_plus(z2)) {
+ if (apple_z2_is_iphone7(z2)) {
if (payload_len < APPLE_Z2_FINGERS_OFFSET)
return;
@@ -572,11 +589,11 @@ static int apple_z2_read_packet(struct apple_z2 *z2)
return -EMSGSIZE;
}
wire_len = pkt_len;
- if (apple_z2_is_d11(z2))
+ if (apple_z2_is_gen2_reports(z2))
wire_len = max_t(size_t, wire_len,
APPLE_Z2_GEN2_MIN_RESULT_SIZE);
- if (apple_z2_is_j172(z2) || apple_z2_is_iphone7_plus(z2)) {
+ if (apple_z2_is_j172(z2) || apple_z2_is_iphone7(z2)) {
memset(z2->rx_buf, 0xa5, wire_len);
xfer.tx_buf = z2->rx_buf;
xfer.rx_buf = z2->rx_buf;
@@ -587,11 +604,11 @@ static int apple_z2_read_packet(struct apple_z2 *z2)
}
if (error)
return error;
- if (apple_z2_is_iphone7_plus(z2))
+ if (apple_z2_is_iphone7(z2))
apple_z2_post_z2_xfer_delay(z2);
/* D11 touch reports do not follow the requested alternating tag. */
- strict_counter = !apple_z2_is_d11(z2) ||
+ strict_counter = !apple_z2_is_gen2_reports(z2) ||
(pkt_len > 5 && z2->rx_buf[5] ==
APPLE_Z2_D11_STATUS_REPORT);
z2->runtime_frame_valid =
@@ -705,7 +722,7 @@ static void apple_z2_avoid_short_dma(struct apple_z2 *z2,
* an RX buffer makes shorter writes full-duplex, which the T8010
* controller handles through PIO without changing the wire transfer.
*/
- if (!apple_z2_is_iphone7_plus(z2) || !z2->dma_min_len ||
+ if (!apple_z2_is_iphone7(z2) || !z2->dma_min_len ||
!xfer->tx_buf || xfer->rx_buf ||
xfer->len >= z2->dma_min_len)
return;
@@ -831,7 +848,7 @@ static int apple_z2_write_report_locked(struct apple_z2 *z2, u8 report,
if (error)
return error;
- if (apple_z2_is_d11(z2) &&
+ if (apple_z2_is_gen2_reports(z2) &&
(z2->rx_buf[0] != APPLE_Z2_CMD_LAST ||
!apple_z2_z2_checksum_valid(z2->rx_buf, APPLE_Z2_CMD_SIZE)))
return -EPROTO;
@@ -978,7 +995,7 @@ static int apple_z2_store_surface_descriptor(struct apple_z2 *z2, u16 len)
return 0;
}
-static int apple_z2_iphone7_plus_init_locked(struct apple_z2 *z2)
+static int apple_z2_iphone7_init_locked(struct apple_z2 *z2)
{
static const u8 disable_legacy_reports[] = { 0 };
u16 surface_len;
@@ -1289,17 +1306,17 @@ static void apple_z2_platform_power_off(struct apple_z2 *z2)
{
int error;
- if (apple_z2_is_iphone7_plus(z2))
+ if (apple_z2_is_iphone7(z2))
gpiod_set_value_cansleep(z2->reset_gpio, 1);
if (z2->clk_enabled) {
clk_disable_unprepare(z2->clk);
z2->clk_enabled = false;
}
- if (apple_z2_is_j172(z2) || apple_z2_is_iphone7_plus(z2))
+ if (apple_z2_is_j172(z2) || apple_z2_is_iphone7(z2))
usleep_range(1000, 2000);
- if (apple_z2_is_iphone7_plus(z2)) {
+ if (apple_z2_is_iphone7(z2)) {
if (z2->core_enabled) {
error = regulator_disable(z2->core_supply);
if (error) {
@@ -1381,7 +1398,7 @@ static int apple_z2_j172_power_on(struct apple_z2 *z2)
APPLE_Z2_STATE_POWERED);
}
-static int apple_z2_iphone7_plus_power_on(struct apple_z2 *z2)
+static int apple_z2_iphone7_power_on(struct apple_z2 *z2)
{
int error;
@@ -1422,8 +1439,8 @@ static int apple_z2_platform_power_on(struct apple_z2 *z2)
if (apple_z2_is_j172(z2))
return apple_z2_j172_power_on(z2);
- if (apple_z2_is_iphone7_plus(z2))
- return apple_z2_iphone7_plus_power_on(z2);
+ if (apple_z2_is_iphone7(z2))
+ return apple_z2_iphone7_power_on(z2);
apple_z2_set_gpio(z2->power_ana_gpio, 1);
usleep_range(1000, 2000);
@@ -1609,14 +1626,14 @@ static int apple_z2_send_firmware_blob(struct apple_z2 *z2, const u8 *data,
* SmartIO may still DMA these transfers, but using 16-bit SPI words would
* swap every byte pair a second time.
*/
- if (!init && !apple_z2_is_iphone7_plus(z2) &&
+ if (!init && !apple_z2_is_iphone7(z2) &&
size >= z2->bpw16_min_len)
blob_xfer.bits_per_word = 16;
dev_dbg(&z2->spidev->dev, "firmware blob len=%u bpw=%u\n",
size, blob_xfer.bits_per_word);
- if ((apple_z2_is_j172(z2) || apple_z2_is_iphone7_plus(z2)) && init) {
+ if ((apple_z2_is_j172(z2) || apple_z2_is_iphone7(z2)) && init) {
if (size != 4 || data[0] != 0x1a || data[1] != 0xa1 ||
data[2] != 0x18 || data[3] != 0xe1)
return dev_err_probe(&z2->spidev->dev, -EINVAL,
@@ -1634,7 +1651,7 @@ static int apple_z2_send_firmware_blob(struct apple_z2 *z2, const u8 *data,
if (error)
return error;
- if ((apple_z2_is_j172(z2) || apple_z2_is_iphone7_plus(z2)) && init) {
+ if ((apple_z2_is_j172(z2) || apple_z2_is_iphone7(z2)) && init) {
ready = z2->rx_buf[0] == 0x1f && z2->rx_buf[1] == 0x01;
if (!ready)
return dev_err_probe(&z2->spidev->dev, -EPROTO,
@@ -1648,7 +1665,7 @@ static int apple_z2_send_firmware_blob(struct apple_z2 *z2, const u8 *data,
return error;
apple_z2_post_ack_delay(z2);
}
- if ((apple_z2_is_j172(z2) || apple_z2_is_iphone7_plus(z2)) && init) {
+ if ((apple_z2_is_j172(z2) || apple_z2_is_iphone7(z2)) && init) {
error = apple_z2_advance_protocol(z2, APPLE_Z2_STATE_BOOT_IRQ,
APPLE_Z2_STATE_HBPP_READY);
if (error)
@@ -1741,7 +1758,7 @@ static int apple_z2_wait_ready_irq(struct apple_z2 *z2, u32 timeout_ms)
{
if (!apple_z2_wait_firmware_irq(z2, timeout_ms))
return -ETIMEDOUT;
- if (!apple_z2_is_j172(z2) && !apple_z2_is_iphone7_plus(z2))
+ if (!apple_z2_is_j172(z2) && !apple_z2_is_iphone7(z2))
return 0;
if (apple_z2_is_j172(z2) &&
@@ -1778,7 +1795,7 @@ static int apple_z2_apply_fw_config(struct apple_z2 *z2, const u8 *data,
cpol = apple_z2_fw_config_word(data, 5);
boot_timeout = apple_z2_fw_config_word(data, 9);
if ((valid & APPLE_Z2_FW_CONFIG_MIN_DMA) && min_dma) {
- if (apple_z2_is_iphone7_plus(z2)) {
+ if (apple_z2_is_iphone7(z2)) {
if (min_dma > APPLE_Z2_RX_BUF_SIZE)
return -EINVAL;
z2->dma_min_len = min_dma;
@@ -1790,7 +1807,7 @@ static int apple_z2_apply_fw_config(struct apple_z2 *z2, const u8 *data,
z2->z2_inter_packet_delay_us = z2_delay;
/* iPhone 7 Plus uses zero to retain the required 1 ms CS delay. */
if ((valid & APPLE_Z2_FW_CONFIG_CS_DELAY) &&
- (!apple_z2_is_iphone7_plus(z2) || cs_delay))
+ (!apple_z2_is_iphone7(z2) || cs_delay))
z2->z2_cs_delay_us = cs_delay;
if ((valid & APPLE_Z2_FW_CONFIG_BOOT_TIMEOUT) && boot_timeout)
z2->boot_timeout_ms = boot_timeout;
@@ -1922,7 +1939,7 @@ static int apple_z2_upload_firmware(struct apple_z2 *z2)
u32 max_size;
u32 provider;
- if (!apple_z2_is_iphone7_plus(z2))
+ if (!apple_z2_is_iphone7(z2))
return -EINVAL;
if (size != sizeof(struct apple_z2_fw_calibration) ||
size > fw->size - fw_idx)
@@ -1969,19 +1986,19 @@ static int apple_z2_upload_firmware(struct apple_z2 *z2)
fw_idx = round_up(fw_idx, 4);
}
- if (apple_z2_is_iphone7_plus(z2)) {
+ if (apple_z2_is_iphone7(z2)) {
msleep(50);
mutex_lock(&z2->io_lock);
- error = apple_z2_iphone7_plus_init_locked(z2);
+ error = apple_z2_iphone7_init_locked(z2);
if (!error) {
z2->booted = true;
error = apple_z2_read_packet(z2);
}
- if (!error && apple_z2_is_d11(z2) &&
+ if (!error && apple_z2_is_gen2_reports(z2) &&
(!z2->runtime_frame_valid ||
z2->rx_buf[5] != APPLE_Z2_D11_STATUS_REPORT))
error = -EPROTO;
- if (!error && apple_z2_is_d11(z2))
+ if (!error && apple_z2_is_gen2_reports(z2))
error = apple_z2_enable_d11_reports_locked(z2);
mutex_unlock(&z2->io_lock);
return error;
@@ -2087,7 +2104,7 @@ static int apple_z2_boot_preamble(struct apple_z2 *z2, bool full_duplex)
APPLE_Z2_STATE_SPI_CONFIGURED);
}
-static int apple_z2_iphone7_plus_post_boot_preamble(struct apple_z2 *z2)
+static int apple_z2_iphone7_post_boot_preamble(struct apple_z2 *z2)
{
struct spi_transfer xfer = {
.tx_buf = z2->tx_buf,
@@ -2114,7 +2131,7 @@ static int apple_z2_boot(struct apple_z2 *z2)
if (error)
return error;
- if (apple_z2_is_j172(z2) || apple_z2_is_iphone7_plus(z2)) {
+ if (apple_z2_is_j172(z2) || apple_z2_is_iphone7(z2)) {
error = apple_z2_apply_initial_config(z2);
if (error)
goto err_stop;
@@ -2123,7 +2140,7 @@ static int apple_z2_boot(struct apple_z2 *z2)
error = apple_z2_boot_preamble(z2, false);
if (error)
goto err_stop;
- } else if (apple_z2_is_iphone7_plus(z2)) {
+ } else if (apple_z2_is_iphone7(z2)) {
/* iPhone 7 Plus performs a legacy reset and zero preamble first. */
error = apple_z2_pulse_reset(z2);
if (error)
@@ -2142,7 +2159,7 @@ static int apple_z2_boot(struct apple_z2 *z2)
irq_enabled = true;
if (apple_z2_is_j172(z2)) {
error = apple_z2_pulse_reset(z2);
- } else if (apple_z2_is_iphone7_plus(z2)) {
+ } else if (apple_z2_is_iphone7(z2)) {
gpiod_set_value_cansleep(z2->reset_gpio, 0);
usleep_range(1000, 2000);
error = 0;
@@ -2158,20 +2175,20 @@ static int apple_z2_boot(struct apple_z2 *z2)
error = -ETIMEDOUT;
goto err_stop;
}
- if (apple_z2_is_j172(z2) || apple_z2_is_iphone7_plus(z2)) {
+ if (apple_z2_is_j172(z2) || apple_z2_is_iphone7(z2)) {
error = apple_z2_advance_protocol(z2,
APPLE_Z2_STATE_SPI_CONFIGURED,
APPLE_Z2_STATE_BOOT_IRQ);
if (error)
goto err_stop;
}
- if (apple_z2_is_iphone7_plus(z2)) {
- error = apple_z2_iphone7_plus_post_boot_preamble(z2);
+ if (apple_z2_is_iphone7(z2)) {
+ error = apple_z2_iphone7_post_boot_preamble(z2);
if (error)
goto err_stop;
}
- if (apple_z2_is_j172(z2) || apple_z2_is_iphone7_plus(z2)) {
+ if (apple_z2_is_j172(z2) || apple_z2_is_iphone7(z2)) {
disable_irq(z2->spidev->irq);
z2->upload_irq_masked = true;
}
@@ -2211,6 +2228,11 @@ static const struct apple_z2_chip_info apple_z2_j172_info = {
.variant = APPLE_Z2_VARIANT_J172,
};
+static const struct apple_z2_chip_info apple_z2_d10_info = {
+ .name = "iPhone9,1 Touchscreen",
+ .variant = APPLE_Z2_VARIANT_D10,
+};
+
static const struct apple_z2_chip_info apple_z2_d11_info = {
.name = "iPhone9,2 Touchscreen",
.variant = APPLE_Z2_VARIANT_D11,
@@ -2249,7 +2271,7 @@ static int apple_z2_probe(struct spi_device *spi)
z2->spidev = spi;
z2->variant = info->variant;
z2->boot_timeout_ms = 20;
- if (apple_z2_is_iphone7_plus(z2)) {
+ if (apple_z2_is_iphone7(z2)) {
z2->z2_inter_packet_delay_us = 1000;
z2->z2_cs_delay_us = 1000;
z2->boot_timeout_ms = 500;
@@ -2269,7 +2291,7 @@ static int apple_z2_probe(struct spi_device *spi)
if (IS_ERR(z2->reset_gpio))
return dev_err_probe(dev, PTR_ERR(z2->reset_gpio),
"unable to get reset GPIO\n");
- if (apple_z2_is_iphone7_plus(z2)) {
+ if (apple_z2_is_iphone7(z2)) {
z2->hv_supply = devm_regulator_get(dev, "hv");
if (IS_ERR(z2->hv_supply))
return dev_err_probe(dev, PTR_ERR(z2->hv_supply),
@@ -2316,7 +2338,7 @@ static int apple_z2_probe(struct spi_device *spi)
error = device_property_read_string(dev, "firmware-name", &z2->fw_name);
if (error)
return dev_err_probe(dev, error, "unable to get firmware name\n");
- if (apple_z2_is_iphone7_plus(z2)) {
+ if (apple_z2_is_iphone7(z2)) {
static const struct {
const char *name;
unsigned int max_size;
@@ -2361,7 +2383,7 @@ static int apple_z2_probe(struct spi_device *spi)
if (apple_z2_is_j172(z2)) {
slots = APPLE_Z2_J172_MAX_CONTACTS;
- } else if (apple_z2_is_iphone7_plus(z2)) {
+ } else if (apple_z2_is_iphone7(z2)) {
slots = 10;
if (apple_z2_is_d11(z2))
mt_flags |= INPUT_MT_DROP_UNUSED;
@@ -2415,6 +2437,7 @@ static const struct of_device_id apple_z2_of_match[] = {
{ .compatible = "apple,j293-touchbar", .data = &apple_z2_j293_info },
{ .compatible = "apple,j493-touchbar", .data = &apple_z2_j493_info },
{ .compatible = "apple,j172-touchscreen", .data = &apple_z2_j172_info },
+ { .compatible = "apple,d10-touchscreen", .data = &apple_z2_d10_info },
{ .compatible = "apple,d11-touchscreen", .data = &apple_z2_d11_info },
{ .compatible = "apple,d111-touchscreen", .data = &apple_z2_d111_info },
{}
@@ -2425,6 +2448,7 @@ static struct spi_device_id apple_z2_of_id[] = {
{ .name = "j293-touchbar", .driver_data = (kernel_ulong_t)&apple_z2_j293_info },
{ .name = "j493-touchbar", .driver_data = (kernel_ulong_t)&apple_z2_j493_info },
{ .name = "j172-touchscreen", .driver_data = (kernel_ulong_t)&apple_z2_j172_info },
+ { .name = "d10-touchscreen", .driver_data = (kernel_ulong_t)&apple_z2_d10_info },
{ .name = "d11-touchscreen", .driver_data = (kernel_ulong_t)&apple_z2_d11_info },
{ .name = "d111-touchscreen", .driver_data = (kernel_ulong_t)&apple_z2_d111_info },
{}
--
2.55.0

View file

@ -58,6 +58,107 @@ writes into a dumb buffer while the panel scans the same memory. This is
structural, not a setting. Fixing it means either a fence-free damage/copy
discipline in the KMS path or double-buffering the dumb BO by hand.
## Touch, and the display pipe — 2026-08-09 night
**Touch works on the glass.** `evtest`-grade proof, not a device node: 2407 events,
270 `SYN_REPORT`, 13 balanced down/up, X 53..735, Y 107..1333, with
`MT_TOUCH_MAJOR` and `MT_ORIENTATION`. Kernel-native `apple_z2` — no `hx-touchd`,
no Sandcastle daemon. Three layers, each hiding the next:
1. **`apple/t8010-smartio.bin` was not on the rootfs.** SIO DMA times out
(`-ETIMEDOUT` after the 60 s sysfs fallback), so `apple-spi` gets no TX DMA
and the SPI bus never probes. Both blobs were built from the IPSW on
2026-08-08 into the *install ramdisk only*, and the disk-boot blob carries no
initramfs. Now `CONFIG_EXTRA_FIRMWARE`, compiled into the Image, which is the
only placement that beats rootfs to the probe.
2. **`# CONFIG_REGULATOR is not set`.** That silently dropped
`REGULATOR_APPLE_PMIC_TOUCH` (`drivers/regulator/apple-pmic-touch-regulator.c`,
marked `default y if ARCH_APPLE`), so `apple_z2`'s mandatory `hv`/`core`
supplies resolved to no-op stubs and the controller was never powered. **A
registered input node with dead rails is indistinguishable from working
touch** — verify with events, never dmesg.
3. **Runtime report activation was gated to D11.**
`apple_z2_enable_d11_reports_locked()` is what switches runtime reports on;
D10 never called it, so boot frames arrived and the panel went silent about a
second later. All four `is_d11()` sites now go through
`apple_z2_is_gen2_reports()` = D10 D11.
**The Apple Display Pipe runs on a T8010 — the first anywhere.**
`[drm] Initialized adp 0.1.0 for 206200000.display-pipe on minor 1`, with
`card1-DSI-1` and the panel attached at `206600000.dsi.0`. Every other port on
this hardware scans out a dumb framebuffer: Sandcastle, pmOS
(`linux-postmarketos-apple-16k` has no `APPLE_SIO` at all), uPhone
(`CONFIG_FB_SIMPLE=y`, `TOUCHSCREEN_HX`, an `hx-touchd.service`), and
qwertyoruiopz's original 5.4.14 boot. That is why the wiki's *"abnormal screen
color"* has no owner.
Addresses came off the D10 ADT and were checked against
`HoolockLinux/linux:tests/adp` commit `2b3b1a7fc` "t8012 dts: display pipe" —
T8012 is T2, A10-family, and its `disp0_dart` is literally `apple,t8010-dart`:
| node | reg | irq |
|---|---|---|
| `disp0` | be `0x06200000/0x9000`, fe `0x06400000/0x4000` | be 154, fe 158 |
| `disp0_dart` | `0x06304000/0x4000` | 156 |
| `disp0_mipi` | `0x06600000/0x100000`**byte-identical to T8012's** | 163 |
The be/fe split is not guesswork: ADP binds only `be`/`fe` by name, pokes `be` to
`0x40f4` and `fe` to `0x100`, and T8012's own IRQ layout has its DART sitting
*between* the pipe's two — 210/212/214 there, 154/156/158 here. `panel-summit` is
134 lines with no init sequence because the loader lights the panel, which is
exactly our situation; it gained a 750×1334 mode under `apple,d10-panel`.
**Still on simpledrm, and the reason matters.** `status = "disabled"` on
`framebuffer0` in the DT does nothing — m1n1's `kboot` fills and re-enables
`/chosen/framebuffer` itself, so the loader wins. udev then names simpledrm the
primary GPU and `primary_device()` (`kms.rs:447`) hands viewtop `card0`. So the
shell composites through the fenceless framebuffer while ADP holds the same
panel — two drivers, one panel, which reads as tearing *and* lock-ups. The fix
is `initcall_blacklist=simpledrm_platform_driver_init` on the cmdline (now in
`boot.sh`), or `CONFIG_DRM_SIMPLEDRM=n`. **Untested as of this writing.**
Kernel work is committed on archdev as `2e349ddf2` and exported to
`hoolock/d10-port/patch/`. That commit also captured the 141-line `t8010-d10.dts`
port, which had been uncommitted against the 14-line mainline stub.
## The session is real now
greetd → `/usr/bin/souveraine-session-viewtop` as `casey`, no greeter, same shape
as blueline. `casey` is uid 1000 with blueline's exact groups
(`wheel input video seat souveraine`); the stock `alarm` account is gone and its
home preserved at `/home/alarm.stock-preserved`. sessiond and the shell run as
supervised user units and are enabled at boot, so §0's `no Display session for
uid 0` drift is gone — `loginctl` shows a real `seat0`/tty1 session and
`LockedHint` tracks it.
Carried across and worth knowing: the QML config is a **symlink farm with
absolute targets**, so moving it between homes needs all 432 links repointed, not
just a copy. Shell tree parity against blueline was verified file-by-file — 1056
files, one difference, and it is a file the *Pixel* lacks.
`hoolock/boot.sh` is the whole boot: waits for DFU, runs checkm8 → m1n1 → kernel
handoff, then prints kernel/touch/spi/drm/adp/deferred/session. `./boot.sh` for
everything, `1`/`2`/`3` for one stage, `-l` to list staged kernels, `-k` to pick.
## Open on the d10
- **The buttons do nothing.** `gpio-keys` is on event1 and nothing routes it to
sessiond's `button` verb — the blueline path came from `hyprland.lua` bindings
ported into the state machine, and no equivalent exists here. The ADT names
four: `hold`, `volup`, `voldown`, `ringerab` (the mute switch).
- **`Dim` was device-specific and is fixed but unshipped.** `brightnessctl set 10`
is an absolute: 4% of blueline's 255-step backlight, 0.5% of the iPhone's
2047-step Apple DWI, where it reads as fully off. `souveraine eb0292c` makes it
`4%`; it needs a CI build and `pacman -Syu` to reach the device.
- **`touchKeypad` binds before its config loads.** `Lock.qml:137` defaults it
`false` and `:148` binds the surface from that, so the lock came up as the
keyboard variant with no keypad — and `surfaceComponent` cannot change once the
lock is live. Patched on-device only (`Lock.qml.bak-touchkeypad` beside it);
the repo fix is still owed.
- **`casey` has password `123456`.** It is also the lock-screen PIN.
- Sensors report nothing and say so honestly: proximity, light and accel are all
`source-never-reported`, because no reporter exists on this board.
## Where the split is
The device does not need `souveraine-upower-iphone`. It needs the base to stop