From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id AF8B0C88E56 for ; Sat, 12 Sep 2026 23:44:49 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id A624C10E532; Sat, 12 Sep 2026 23:44:48 +0000 (UTC) Authentication-Results: gabe.freedesktop.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=arm.com header.i=@arm.com header.b="IOz2ESQ1"; dkim-atps=neutral Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by gabe.freedesktop.org (Postfix) with ESMTP id 16F6210E532 for ; Sat, 12 Sep 2026 23:44:45 +0000 (UTC) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 608001682; Sat, 12 Sep 2026 16:44:41 -0700 (PDT) Received: from ryzen.lan (usa-sjc-mx-foss1.foss.arm.com [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 6BE883F7D8; Sat, 12 Sep 2026 16:44:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1789256684; bh=W69k13iWpQBYvt5U0bRgjjz2xuCB0uhzuDkimnsS7vo=; h=Date:From:To:Cc:Subject:In-Reply-To:References:From; b=IOz2ESQ1AHQfkT7kXZAQytgLnp68UioAbzlwg0NHvL3sF8szq1OlKplMpknO3yYKs vDD9Ts8MyaVWIK1xSfUogve6Hvy4BPn7GEedkOzVzF1U40fsO6z9H2YFisTSvtGovH XLf1vLQjylqgasXV8WCKq4ZSCr4TjqMDW2zG3Gz4= Date: Sun, 13 Sep 2026 01:39:55 +0200 From: Andre Przywara To: leow149 Cc: dri-devel@lists.freedesktop.org, linux-sunxi@lists.linux.dev, wens@kernel.org, jernej.skrabec@gmail.com, samuel@sholland.org, mripard@kernel.org, paulk@sys-base.io Subject: Re: [RFC PATCH v7] arm64: allwinner: add TrimUI Smart Pro (A133) board support Message-ID: <20260913013955.0fbc4acd@ryzen.lan> In-Reply-To: <20260912230131.109229-1-leow149@lucidmail.xyz> References: <20260912222429.107809-1-leow149@lucidmail.xyz> <20260912230131.109229-1-leow149@lucidmail.xyz> Organization: Arm Ltd. X-Mailer: Claws Mail 4.4.0 (GTK 3.24.31; x86_64-slackware-linux-gnu) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" On Sun, 13 Sep 2026 01:01:30 +0200 leow149 wrote: Hi, first: please stop posting in such a quick succession, just because sashiko had something to say. This puts off real reviewers, because you change things too quickly. Normally I'd say you wait for a few days, to give everyone a chance to have a look. second: this must not be a single patch, this is VERY wrong, even with an RFC tag. I guess people will just ignore it. You NEED to split this up into several patches, one patch per change, definitely split up by subsystem, with DT bindings separately, DT patches separately, driver changes separately. Please read the kernel documentation about this: https://docs.kernel.org/process/submitting-patches.html And by just glancing over this, I guess this overlaps with work-in-progress DE, HDMI, and PWM drivers for "nearby" SoCs. What you should focus on is to get the basic devicetree for the device upstream - with just the devices mentioned for which we have bindings for - so clocks, pinctrl, UART, MMC, PMIC, I guess. The rest of the features can the be worked on independently. Cheers, Andre > Board bring-up for the TrimUI Smart Pro handheld (Allwinner A133 Plus): >=20 > - New board DTS (sun50i-a133-trimui-smartpro.dts): display pipeline > (mixer/TCON/DSI/D-PHY), regulators, MMC, PWM backlight. > - New OTM1289A/ER68576 DSI panel driver (panel-orisetech-otm1289a.c), > including real panel timings and DCS init sequence. > - New PWM driver for this SoC's newer-generation PWM IP > (pwm-sun50i-a133.c), with binding doc. > - sun8i_mixer: A133 DE2 mixer0/mixer1 configs. > - sun8i_tcon_top: A133 quirks entry, plus two new helpers > (sun8i_tcon_top_set_dsi_gate/set_de0_port) needed because this > board's TCON quirks table has no .set_mux callback to reach them > through the existing paths. > - sun4i_tcon: CPU/8080-interface DSI bring-up (sun4i_tcon0_mode_set_cpu > register formulas, an hrtimer-driven TRIGGER_START retrigger, IRQ > ordering/ack fixes) plus TCON-TOP wiring for this board's DSI clock > gate and DE0 port routing. All of the CPU/8080-interface-specific > additions are gated behind a new, more specific > "allwinner,sun50i-a133-tcon-lcd" compatible string > (dsi_cpu_needs_retrigger quirk field), so none of it affects > Pinephone/Pinetab (A64), the one other real board sharing this > driver's shared DSI/CPU-mode code path. > - sun6i_mipi_dsi: an additional DSI_START_TRI instruction-jump-table > case for continuous per-frame retriggering (distinct from the > existing one-shot HS-clock-enable case), a DRQ_SET formula fix, and > reordering the HS-clock-enable step to run before the panel's DCS > init sequence. > - ccu-sun50i-a100: CLK_SET_RATE_PARENT on the tcon-lcd0 clock so its > rate request can actually explore parent PLL rates. >=20 > Sending as RFC rather than waiting for the display to fully work: > posting the board/DTS foundation now so it's in front of people who > know this hardware, rather than sitting on it indefinitely. >=20 > Known issue, and the actual reason for the RFC tag: the panel attaches > and the backlight lights, but no pixel data reaches it. > TCON0_CPU_IF_REG's TRIGGER_START bit (a documented self-clearing > one-shot) never self-clears, despite the rest of the pixel pipeline > matching a working vendor system register-for-register -- every > static register value, D-PHY lane state, control-flow/sequencing > cross-referenced against a symbol-resolved decompile of the vendor > kernel, and even measured real-time timing all confirmed matching. > Full writeup, including what's been ruled out and how: > https://github.com/leow149/trimui-a133-mainline-port/blob/main/COMMUNITY_= HELP_REQUEST.md >=20 > If anyone recognizes this symptom on the CPU/8080-interface DSI path, > or can spot something the writeup missed, I would very much like to > hear about it. >=20 > Cc: Chen-Yu Tsai > Cc: Jernej Skrabec > Cc: Samuel Holland > Cc: Maxime Ripard > Cc: Paul Kocialkowski > Signed-off-by: leow149 > --- >=20 > Changelog (kept below the cut, not in the commit message -- see the > automated-review replies on this thread for full per-finding detail): >=20 > v1 -> v2: Fixed sun6i_dsi_clear_int_status() using regmap_update_bits() > on a write-1-to-clear register, which silently no-op'd the write and > broke the retrigger timer's edge detection. Also fixed a timer/IRQ not > being torn down on CRTC disable, an IRQF_NO_AUTOEN regression that > would have permanently disabled vblank for other boards sharing this > TCON code, a spurious-vblank issue from treating bare FSYNC_INT as a > frame event, a clock-gate write getting silently undone by "disable > unused clocks", a PWM register race across channels, a PWM 100%-duty > truncation bug, a divide-by-zero guard, and a DT schema gap. Did not > resolve the core TRIGGER_START bug. >=20 > v2 -> v3: Fixed the retrigger timer racing sun6i_dsi_encoder_enable() > on a guessed 1000ms wall-clock delay instead of sequencing on real > completion (added a tcon back-reference so encoder_enable() arms the > timer itself once actually done). Fixed missing fast_io on two > regmaps (sun4i_tcon_handler() is a genuine hardirq handler; without > fast_io, regmap's default mutex-based locking is a sleep-in-hardirq > hazard), missing EXPORT_SYMBOL on three DSI helpers (a real modular > build failure, not just a modpost nag), and a non-DSI enable_irq() > call living in the wrong function (left vblank permanently disabled > after one DPMS cycle on other boards). Rejected two atomic-context > sleeping claims as false positives, checked directly against > drm_atomic_helper.c and the PWM core's own pwm_apply_might_sleep() > naming. >=20 > v3 -> v4: Fixed a bus-fault race between sun6i_dsi_encoder_disable() > gating DSI clocks/reset and this driver's own retrigger > timer/IRQ teardown running later, by moving the teardown into > sun6i_dsi_encoder_disable() itself (closing the window at its actual > source). Fixed the GINT0 acknowledge write missing TRI_COUNTER_INT > (a potential hard lockup if it were ever the bit driving the level > line). Hardened (not fully fixed -- it's a narrower, pre-existing > TOCTOU shared with the pristine hdmi_src/de_config functions) the > sun8i_tcon_top raw of_find_device_by_node()/dev_get_drvdata() lookup > with a NULL guard. Found and fixed a real quirks-scoping gap: this > board's TCON0 DT node reused sun8i_a83t_lcd_quirks verbatim with real > A83T hardware, so several of this series' changes applied to every > DSI board sharing that struct (including Pinephone/Pinetab on A64). > Fixed via a new "allwinner,sun50i-a133-tcon-lcd" compatible string and > a new dsi_cpu_needs_retrigger quirk field gating every one of this > series' additions to sun4i_tcon0_mode_set_cpu(), verified against > drivers/of/base.c's actual DT compatible-matching algorithm. (TBS-A711 > on A83T, cited earlier as another affected board, turned out to be > LVDS on checking its DTS, not DSI -- corrected.) >=20 > v4 -> v5: Fixed a PWM clock-gate leak (pwm_a133_apply()'s disable path > cleared PER_EN but never PCGR_GATING, leaving a disabled channel's > clock running indefinitely) and a DT binding schema gap > (allwinner,sun8i-r40-tcon-top.yaml required port@4/port@5 > unconditionally, which this board's HDMI-less tcon-top node can't > satisfy) -- restructured the schema so those ports are required > per-variant instead, verified with dt-validate against real compiled > DTBs (this board's own, and a real upstream H6 one). Rejected the same > atomic-context claims again, and a retrigger-timer TOCTOU claim (not > reachable: it requires TRI_FINISH_INT pending before TRIGGER_START has > ever been written even once). >=20 > v5 -> v6: Fixed a real IRQ re-enable race: a DPMS off/on cycle's > sun4i_tcon_dsi_stop_retrigger() masks the IRQ but never acks GINT0, so > a stale TRI_FINISH_INT/FSYNC_INT left latched from before the disable > can fire the hardirq the instant sun4i_tcon_dsi_retrigger_timer_fn() > re-enables it, double-kicking TRIGGER_START against this same > function's own about-to-happen kick. Fixed by clearing GINT0 right > before that enable_irq() call. Fixed the retrigger timer's own stop > condition never triggering once the hardirq-driven backstop is fast > enough to always win the race and keep TRIGGER_START looking busy from > the timer's perspective -- it would otherwise poll forever as a > low-frequency CPU hog instead of handing off. Fixed by adding an > explicit dsi_irq_retriggered flag the hardirq handler sets once it > successfully retriggers a frame, which the timer checks instead of > relying on sampling a transient register bit. Narrowed (not > eliminated) a separate, pre-existing write-0-to-clear TOCTOU window on > the same GINT0 acknowledge, by moving the ack earlier in the handler, > before the slower vblank/page-flip work. Rejected a front/back-porch- > swap claim on the panel's drm_display_mode: independently verified > against sun6i_dsi_setup_burst()'s DRQ_SET formula and a live register > read that the current horizontal front-porch value (88, not the > naively-derived 72) is the one already proven correct against real > hardware -- 72 was tried previously and directly disproven this same > way. Also caught and fixed a stale comment on that same mode struct > that had drifted to claim 72 was the confirmed/in-use value when the > code already correctly used 88; the mismatch is almost certainly what > the automated reviewer's static analysis flagged, since it has no way > to see the DRQ_SET hardware verification. Rejected the same > atomic-context claims a third time. >=20 > .../display/allwinner,sun4i-a10-tcon.yaml | 1 + > .../allwinner,sun8i-a83t-de2-mixer.yaml | 2 + > .../display/allwinner,sun8i-r40-tcon-top.yaml | 58 +- > .../pwm/allwinner,sun50i-a133-pwm.yaml | 67 ++ > arch/arm64/boot/dts/allwinner/Makefile | 1 + > .../allwinner/sun50i-a133-trimui-smartpro.dts | 697 ++++++++++++++++++ > drivers/clk/sunxi-ng/ccu-sun50i-a100.c | 16 +- > drivers/gpu/drm/panel/Kconfig | 8 + > drivers/gpu/drm/panel/Makefile | 1 + > .../gpu/drm/panel/panel-orisetech-otm1289a.c | 435 +++++++++++ > drivers/gpu/drm/sun4i/sun4i_tcon.c | 688 ++++++++++++++++- > drivers/gpu/drm/sun4i/sun4i_tcon.h | 122 +++ > drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 227 +++++- > drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h | 23 + > drivers/gpu/drm/sun4i/sun8i_mixer.c | 48 ++ > drivers/gpu/drm/sun4i/sun8i_tcon_top.c | 152 +++- > drivers/gpu/drm/sun4i/sun8i_tcon_top.h | 2 + > drivers/pwm/Kconfig | 14 + > drivers/pwm/Makefile | 1 + > drivers/pwm/pwm-sun50i-a133.c | 335 +++++++++ > 20 files changed, 2849 insertions(+), 49 deletions(-) > create mode 100644 Documentation/devicetree/bindings/pwm/allwinner,sun50= i-a133-pwm.yaml > create mode 100644 arch/arm64/boot/dts/allwinner/sun50i-a133-trimui-smar= tpro.dts > create mode 100644 drivers/gpu/drm/panel/panel-orisetech-otm1289a.c > create mode 100644 drivers/pwm/pwm-sun50i-a133.c >=20 > diff --git a/Documentation/devicetree/bindings/display/allwinner,sun4i-a1= 0-tcon.yaml b/Documentation/devicetree/bindings/display/allwinner,sun4i-a10= -tcon.yaml > index 724d93b91..c01a444cd 100644 > --- a/Documentation/devicetree/bindings/display/allwinner,sun4i-a10-tcon.= yaml > +++ b/Documentation/devicetree/bindings/display/allwinner,sun4i-a10-tcon.= yaml > @@ -45,6 +45,7 @@ properties: > - items: > - enum: > - allwinner,sun50i-a64-tcon-lcd > + - allwinner,sun50i-a133-tcon-lcd > - const: allwinner,sun8i-a83t-tcon-lcd > =20 > - items: > diff --git a/Documentation/devicetree/bindings/display/allwinner,sun8i-a8= 3t-de2-mixer.yaml b/Documentation/devicetree/bindings/display/allwinner,sun= 8i-a83t-de2-mixer.yaml > index cbd18fd83..ce72c1ba7 100644 > --- a/Documentation/devicetree/bindings/display/allwinner,sun8i-a83t-de2-= mixer.yaml > +++ b/Documentation/devicetree/bindings/display/allwinner,sun8i-a83t-de2-= mixer.yaml > @@ -23,6 +23,8 @@ properties: > - allwinner,sun20i-d1-de2-mixer-1 > - allwinner,sun50i-a64-de2-mixer-0 > - allwinner,sun50i-a64-de2-mixer-1 > + - allwinner,sun50i-a133-de2-mixer-0 > + - allwinner,sun50i-a133-de2-mixer-1 > - allwinner,sun50i-h6-de3-mixer-0 > - allwinner,sun50i-h616-de33-mixer-0 > =20 > diff --git a/Documentation/devicetree/bindings/display/allwinner,sun8i-r4= 0-tcon-top.yaml b/Documentation/devicetree/bindings/display/allwinner,sun8i= -r40-tcon-top.yaml > index 7d849c409..533b06fbd 100644 > --- a/Documentation/devicetree/bindings/display/allwinner,sun8i-r40-tcon-= top.yaml > +++ b/Documentation/devicetree/bindings/display/allwinner,sun8i-r40-tcon-= top.yaml > @@ -43,6 +43,7 @@ properties: > - allwinner,sun8i-r40-tcon-top > - allwinner,sun20i-d1-tcon-top > - allwinner,sun50i-h6-tcon-top > + - allwinner,sun50i-a133-tcon-top > =20 > reg: > maxItems: 1 > @@ -99,8 +100,6 @@ properties: > required: > - port@0 > - port@1 > - - port@4 > - - port@5 > =20 > required: > - "#clock-cells" > @@ -151,6 +150,8 @@ allOf: > required: > - port@2 > - port@3 > + - port@4 > + - port@5 > =20 > - if: > properties: > @@ -179,6 +180,13 @@ allOf: > - description: TCON TV0 output clock name > - description: DSI output clock name > =20 > + ports: > + required: > + - port@2 > + - port@3 > + - port@4 > + - port@5 > + > - if: > properties: > compatible: > @@ -201,6 +209,52 @@ allOf: > items: > - description: TCON TV0 output clock name > =20 > + ports: > + required: > + - port@4 > + - port@5 > + > + - if: > + properties: > + compatible: > + contains: > + const: allwinner,sun50i-a133-tcon-top > + > + then: > + properties: > + clocks: > + items: > + - description: The TCON TOP interface clock > + - description: > > + The TCON TOP TV0 clock. This SoC has no TCON-TV/HDMI out= put > + at all, so this is an otherwise-unused filler clock, only > + present because the driver unconditionally registers a T= V0 > + gate regardless of quirks. > + - description: The TCON TOP MIPI DSI clock > + > + clock-names: > + items: > + - const: bus > + - const: tcon-tv0 > + - const: dsi > + > + clock-output-names: > + items: > + - description: TCON TV0 output clock name (unused, see above) > + - description: DSI output clock name > + > + # This variant has no HDMI mux (no port@4/port@5) and, on the one > + # board using it so far, only mixer0 (no port@2/port@3). The base > + # schema's ports.required list only covers port@0/port@1, which every > + # variant wires up; port@2/port@3 and port@4/port@5 are required > + # per-variant above instead (R40 and D1 both use two mixers and an > + # HDMI/TCON-TV mux, so both are added to their own if/then blocks; > + # H6 has one mixer but still an HDMI mux, so only port@4/port@5 is > + # added there) -- checked against each SoC's actual in-tree > + # dtsi/dts (sun8i-r40.dtsi, sunxi-d1s-t113.dtsi, sun50i-h6.dtsi), not > + # guessed at. This compatible needs no addition here since it has > + # neither extra pair. > + > examples: > - | > #include > diff --git a/Documentation/devicetree/bindings/pwm/allwinner,sun50i-a133-= pwm.yaml b/Documentation/devicetree/bindings/pwm/allwinner,sun50i-a133-pwm.= yaml > new file mode 100644 > index 000000000..59e4fba3b > --- /dev/null > +++ b/Documentation/devicetree/bindings/pwm/allwinner,sun50i-a133-pwm.yaml > @@ -0,0 +1,67 @@ > +# SPDX-License-Identifier: GPL-2.0 > +%YAML 1.2 > +--- > +$id: http://devicetree.org/schemas/pwm/allwinner,sun50i-a133-pwm.yaml# > +$schema: http://devicetree.org/meta-schemas/core.yaml# > + > +title: Allwinner A133 PWM Controller > + > +description: | > + No public register documentation for this IP has ever been reused > + upstream: it's a newer, richer generation than the existing > + allwinner,sun4i-a10-pwm family (16 channels grouped in pairs, per-pair > + dead-zone/group-sync control) with no existing mainline driver, and no > + A100/A133-specific binding either. Confirmed real from the public A133 > + User Manual (chapter 10.11, base 0x0300a000), which documents this > + block down to bit level. > + > +maintainers: > + - out-of-tree hobbyist port, not yet upstream > + > +properties: > + compatible: > + const: allwinner,sun50i-a133-pwm > + > + reg: > + maxItems: 1 > + > + clocks: > + items: > + - description: Bus Clock (register access only =E2=80=94 the PWM o= utput > + clock source itself is internal to this IP, selected between > + OSC24M/APB1 per-pair in its own PCCR01/PCCR23 registers, not > + exposed as a separate CCU clock) > + > + clock-names: > + items: > + - const: bus > + > + resets: > + maxItems: 1 > + > + "#pwm-cells": > + const: 3 > + > +required: > + - compatible > + - reg > + - clocks > + - clock-names > + - resets > + - "#pwm-cells" > + > +additionalProperties: false > + > +examples: > + - | > + #include > + #include > + > + pwm: pwm@300a000 { > + compatible =3D "allwinner,sun50i-a133-pwm"; > + reg =3D <0x0300a000 0x400>; > + clocks =3D <&ccu CLK_BUS_PWM>; > + clock-names =3D "bus"; > + resets =3D <&ccu RST_BUS_PWM>; > + #pwm-cells =3D <3>; > + }; > diff --git a/arch/arm64/boot/dts/allwinner/Makefile b/arch/arm64/boot/dts= /allwinner/Makefile > index aa21f58a4..6132fda32 100644 > --- a/arch/arm64/boot/dts/allwinner/Makefile > +++ b/arch/arm64/boot/dts/allwinner/Makefile > @@ -26,6 +26,7 @@ dtb-$(CONFIG_ARCH_SUNXI) +=3D sun50i-h64-remix-mini-pc.= dtb > dtb-$(CONFIG_ARCH_SUNXI) +=3D sun50i-a100-allwinner-perf1.dtb > dtb-$(CONFIG_ARCH_SUNXI) +=3D sun50i-a133-helperboard.dtb > dtb-$(CONFIG_ARCH_SUNXI) +=3D sun50i-a133-liontron-h-a133l.dtb > +dtb-$(CONFIG_ARCH_SUNXI) +=3D sun50i-a133-trimui-smartpro.dtb > dtb-$(CONFIG_ARCH_SUNXI) +=3D sun50i-h5-bananapi-m2-plus.dtb > dtb-$(CONFIG_ARCH_SUNXI) +=3D sun50i-h5-bananapi-m2-plus-v1.2.dtb > dtb-$(CONFIG_ARCH_SUNXI) +=3D sun50i-h5-emlid-neutis-n5-devboard.dtb > diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a133-trimui-smartpro.dt= s b/arch/arm64/boot/dts/allwinner/sun50i-a133-trimui-smartpro.dts > new file mode 100644 > index 000000000..91adc18ab > --- /dev/null > +++ b/arch/arm64/boot/dts/allwinner/sun50i-a133-trimui-smartpro.dts > @@ -0,0 +1,697 @@ > +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) > +/* > + * Copyright (c) 2026 (out-of-tree hobbyist port, not yet upstream) > + * > + * Board: TrimUI Smart Pro (Allwinner A133 Plus / sun50iw10p1) > + * > + * Sourced from: > + * - vendor DTB extracted from Knulli image (dtb_86065152.dts, offset > + * 86065152 in knulli-a133-trimui-smart-pro-scarab-20260511.img) > + * - sun50i-a133-liontron-h-a133l.dts (mainline reference board, same S= oC) > + * - sun50i-h700-anbernic-rg35xx-2024.dts (mainline handheld reference = for > + * AXP717 regulator/battery wiring style) > + * - LIVE data pulled directly off the running unit over UART (root she= ll + > + * /sys/firmware/fdt, the kernel's own resolved device tree =E2=80=94= not a guess): > + * real regulator voltages (confirmed via U-Boot's PMIC init console = log), > + * real DRAM timing table (see trimui-smartpro_defconfig), real panel > + * timings (see the lcd0 comment block below). > + * > + * TODO markers below are places nothing above could resolve: buttons/ > + * joystick are NOT GPIO at all (confirmed: read over a UART-attached > + * co-microcontroller, see BUTTON_PROBING_PLAN.md =E2=80=94 needs a from= -scratch > + * serdev driver, not a DT gpio-keys node), and the panel's DSI init > + * command sequence (register writes for the otm1289a controller) is > + * not yet captured. > + */ > + > +/dts-v1/; > + > +#include "sun50i-a100.dtsi" > +#include "sun50i-a100-cpu-opp.dtsi" > + > +#include > +#include > +#include > +#include > + > +/ { > + model =3D "TrimUI Smart Pro"; > + chassis-type =3D "handset"; > + /* "trimui" is not a registered vendor prefix in dt-bindings yet; > + * fine for an out-of-tree hobbyist build, would need registering > + * (vendor-prefixes.yaml) before any upstream submission. */ > + compatible =3D "trimui,smart-pro", "allwinner,sun50i-a100"; > + > + aliases { > + serial0 =3D &uart0; > + }; > + > + chosen { > + /* confirmed from the vendor boot.img kernel cmdline */ > + stdout-path =3D "serial0:115200n8"; > + }; > + > + battery: battery { > + compatible =3D "simple-battery"; > + /* vendor DTB: pmu_battery_rdc =3D 0x93, pmu_battery_cap =3D 0x1388 (5= 000mAh) */ > + voltage-max-design-microvolt =3D <4200000>; > + }; > + > + reg_vcc5v: regulator-vcc5v { > + compatible =3D "regulator-fixed"; > + regulator-name =3D "vcc-5v"; > + regulator-min-microvolt =3D <5000000>; > + regulator-max-microvolt =3D <5000000>; > + regulator-always-on; > + }; > + > + de: display-engine { > + /* > + * The fallback compatible string matters: sun4i_drv.c's > + * of_match_table has no A133 entry, and matches here are what > + * probes the aggregate "sun4i-drm" platform driver that calls > + * component_bind_all() to wire the already-individually-probed > + * mixer/tcon/dsi devices together into one DRM device. Without > + * a match, this node binds no driver at all and the pipeline > + * sits in permanent -EPROBE_DEFER. sun4i_drv.c's probe function > + * isn't SoC-specific (it just walks the DT ports graph), so > + * reusing an existing entry here is safe -- same pattern used > + * on tcon_lcd0 below. > + */ > + compatible =3D "allwinner,sun50i-a133-display-engine", > + "allwinner,sun50i-a64-display-engine"; > + allwinner,pipelines =3D <&mixer0>; > + status =3D "okay"; > + }; > + > + /* > + * Real values from the vendor live DTB's power_sply block: > + * lcd_pwm_used=3D1, lcd_pwm_ch=3D0 (PWM channel 0 =E2=80=94 wired abov= e), > + * lcd_pwm_freq=3D0xc350=3D50000Hz (period_ns =3D 1e9/50000 =3D 20000), > + * lcd_pwm_pol=3D0 (normal polarity), lcd_pwm_max_limit=3D0xc8=3D200. > + * NOT included: a real backlight-enable GPIO. The vendor DTB has > + * a separate lcd_bl_en packed property (bank=3D7/pin=3D18, decoding to > + * PH18 by cross-checking the pinctrl driver's own bank-numbering > + * against an already-confirmed-real pin elsewhere in this file) =E2=80= =94 > + * tried driving it directly via a raw register poke on live > + * hardware (no kernel involved, just to test the hypothesis) and > + * it had no visible effect, so this pin guess is unconfirmed/likely > + * wrong (the vendor property has 8 packed fields where a plain > + * 6-cell gpio-spec would only have 7 =E2=80=94 there's a piece of that > + * encoding not accounted for). Left out entirely rather than wire > + * up a pin that's an unverified guess. > + */ > + backlight: backlight { > + compatible =3D "pwm-backlight"; > + pwms =3D <&pwm 0 20000 0>; > + default-brightness-level =3D <200>; > + power-supply =3D <®_cldo4>; > + }; > + > + /* TODO: face buttons (A/B/X/Y, D-pad, L1/L2/R1/R2, start/select, > + * joystick clicks). The vendor DTB has NO gpio-keys node and no > + * "trimui_keypad"-style driver string was found in the firmware =E2=80= =94 > + * only a 3-key ADC "allwinner,keyboard_1350mv" node exists (that's > + * volume/fastboot-combo, not the face buttons). Real GPIO/ADC > + * assignments need to come from live probing on the actual unit > + * (pinctrl debugfs, evtest against the stock kernel, or a UART > + * dmesg capture during boot) =E2=80=94 not guessed from another device. > + */ > +}; > + > +&cpu0 { > + /* TODO: verify against A133 PLUS-rated OPP ceiling, not just A100's */ > + cpu-supply =3D <®_dcdc1>; > +}; > + > +&mmc0 { > + /* SD card slot. cd-gpios still unconfirmed =E2=80=94 no hotplug detect= ion, but > + * that's fine for a card already inserted at boot (proven live: this is > + * literally how SPL/BROM read this same card to boot in the first > + * place). Pin/clock wiring already provided by sun50i-a100.dtsi. > + * vmmc-supply guessed as the same general IO rail as mmc2 =E2=80=94 un= confirmed, > + * first thing to revisit if this doesn't come up cleanly. */ > + bus-width =3D <4>; > + vmmc-supply =3D <®_cldo3>; > + status =3D "okay"; > +}; > + > +&mmc2 { > + /* eMMC =E2=80=94 pin group/clocks/etc. already wired by sun50i-a100.dt= si, this > + * board file only needs the board-specific bits. bus mode confirmed > + * from the live boot log: negotiated DDR52, NOT HS200/HS400 =E2=80=94 = the > + * vendor kernel actively strips those capability flags at runtime > + * ("delete mmc-hs200-1_8v from dtb" / "delete mmc-hs400-1_8v from dtb" > + * in dmesg), so we don't claim them here either. vmmc-supply is a > + * reasonable inference (cldo3/vcc-io, the general 3.3V IO rail) but > + * NOT directly confirmed =E2=80=94 no capture explicitly tied cldo3 to= mmc2. > + */ > + bus-width =3D <8>; > + non-removable; > + cap-mmc-hw-reset; > + mmc-ddr-1_8v; > + vmmc-supply =3D <®_cldo3>; /* inferred, not directly confirmed */ > + status =3D "okay"; > +}; > + > +&r_i2c0 { > + status =3D "okay"; > + > + axp717: pmic@34 { > + compatible =3D "x-powers,axp717"; > + reg =3D <0x34>; > + interrupt-controller; > + #interrupt-cells =3D <1>; > + interrupt-parent =3D <&r_intc>; > + interrupts =3D <0 IRQ_TYPE_LEVEL_LOW>; > + > + vin1-supply =3D <®_vcc5v>; > + vin2-supply =3D <®_vcc5v>; > + vin3-supply =3D <®_vcc5v>; > + vin4-supply =3D <®_vcc5v>; > + > + axp_adc: adc { > + compatible =3D "x-powers,axp717-adc"; > + #io-channel-cells =3D <1>; > + }; > + > + battery_power: battery-power { > + compatible =3D "x-powers,axp717-battery-power-supply"; > + monitored-battery =3D <&battery>; > + x-powers,no-thermistor; > + }; > + > + usb_power: usb-power { > + compatible =3D "x-powers,axp717-usb-power-supply"; > + }; > + > + /* > + * Regulator names carried over from the vendor DTB's "axp2202-*" > + * node names (AXP2202 =3D=3D AXP717, confirmed: Allwinner's BSP driver > + * for "axp2202" has been shown driving a chip physically marked > + * AXP717). Voltages below are REAL, read directly from U-Boot's own > + * PMIC-init console log on the live unit (not decoded/guessed) =E2=80= =94 > + * each line printed "_vol =3D , onoff=3D<0|1>" at boot. dcd= c2 > + * (GPU/sys) wasn't printed at that boot stage (probably brought up > + * later by the kernel) =E2=80=94 left undocumented rather than guesse= d. > + * dcdc1 (vdd-cpu) was 940mV at that instant but is DVFS-scaled by > + * cpufreq, so it's intentionally NOT hardcoded to a fixed value here. > + */ > + regulators { > + reg_dcdc1: dcdc1 { > + /* > + * regulator-always-on, not regulator-boot-on: > + * drivers/regulator/core.c's regulator_late_cleanup() > + * (the late-boot "disable unused regulators" sweep) > + * checks constraints->always_on, not ->boot_on -- > + * boot-on only means "was already on at boot," it > + * does nothing to stop this cleanup pass from > + * turning it back off. This board has no cpufreq/OPP > + * consumer wired up yet, so dcdc1 would otherwise > + * have zero regulator-API reference count despite > + * being the CPU's own supply -- disabling it hard > + * hangs the board. > + */ > + regulator-always-on; > + regulator-name =3D "vdd-cpu"; > + /* boot-time value was 940mV; real range needs the OPP table, not ha= rdcoded here */ > + }; > + reg_dcdc2: dcdc2 { > + /* > + * Same reasoning as dcdc1 above: no GPU driver > + * claims this rail yet, and nothing rules out > + * shared PLL/bias circuitry with the display > + * path, so it's kept on rather than left to the > + * late-boot unused-regulator cleanup. > + */ > + regulator-always-on; > + regulator-name =3D "vdd-gpu-sys"; > + }; > + reg_dcdc3: dcdc3 { > + /* confirmed real: matches boot0's "DRAM_VCC set to 1100 mv" exactly= */ > + regulator-always-on; > + regulator-min-microvolt =3D <1100000>; > + regulator-max-microvolt =3D <1100000>; > + regulator-name =3D "vdd-dram"; > + }; > + /* > + * aldo1/aldo2/aldo4/bldo2/bldo3/bldo4 all got > + * regulator-always-on added after real, reproducible > + * hard hangs: fixing vdd-cpu/vdd-gpu-sys (the first two > + * rails caught by the kernel's late-boot "disable > + * unused regulators" sweep) didn't stop the hang, it > + * just moved it =E2=80=94 the very next boot hung identically > + * but with "aldo4: disabling" this time. Whack-a-mole: > + * every rail the vendor bootloader left on (onoff=3D1 in > + * the real U-Boot PMIC log) that we don't have a > + * confirmed real consumer/purpose for is exactly this > + * same landmine, since nothing in our still-incomplete > + * DT claims them through the regulator API. Rather than > + * keep discovering these one hang at a time, all of > + * them get always-on now =E2=80=94 matches the vendor's own > + * actual default behavior anyway (leave them on). > + * bldo1 is the one confirmed exception: real U-Boot log > + * shows onoff=3D0 at boot (WiFi/BT driver switches it on > + * dynamically later), so it's deliberately left off here. > + */ > + reg_aldo1: aldo1 { > + /* real: 1800mV, onoff=3D1 at boot */ > + regulator-always-on; > + }; > + reg_aldo2: aldo2 { > + /* real: 3300mV, onoff=3D1 */ > + regulator-always-on; > + }; > + reg_aldo3: aldo3 { > + /* confirmed: WiFi/BT IO rail (wlan_io_regulator), real: 3300mV */ > + regulator-always-on; > + regulator-min-microvolt =3D <3300000>; > + regulator-max-microvolt =3D <3300000>; > + regulator-name =3D "vcc-wifi-io"; > + }; > + reg_aldo4: aldo4 { > + /* real: 1800mV, onoff=3D1 */ > + regulator-always-on; > + }; > + reg_bldo1: bldo1 { > + /* confirmed: WiFi/BT power rail (wlan_power1), real: 3300mV. > + * NOT always-on: U-Boot log shows onoff=3D0 at boot =E2=80=94 the > + * wifi/bt driver switches it on dynamically at runtime. */ > + regulator-min-microvolt =3D <3300000>; > + regulator-max-microvolt =3D <3300000>; > + regulator-name =3D "vcc-wifi"; > + }; > + reg_bldo2: bldo2 { > + /* real: 1800mV, onoff=3D1 */ > + regulator-always-on; > + }; > + reg_bldo3: bldo3 { > + /* real: 3300mV, onoff=3D1 */ > + regulator-always-on; > + }; > + reg_bldo4: bldo4 { > + /* real: 1800mV at boot, onoff=3D1 */ > + regulator-always-on; > + }; > + reg_cldo1: cldo1 { > + /* confirmed: LCD panel power0 (lcd_power0=3D"cldo1"), real: 1800mV = */ > + regulator-always-on; > + regulator-min-microvolt =3D <1800000>; > + regulator-max-microvolt =3D <1800000>; > + regulator-name =3D "vcc-lcd-1"; > + }; > + reg_cldo2: cldo2 { }; > + reg_cldo3: cldo3 { > + /* real: 3300mV */ > + regulator-always-on; > + regulator-min-microvolt =3D <3300000>; > + regulator-max-microvolt =3D <3300000>; > + regulator-name =3D "vcc-io"; > + }; > + reg_cldo4: cldo4 { > + /* confirmed: LCD panel power1 (lcd_power1=3D"cldo4"), real: 3300mV = */ > + regulator-always-on; > + regulator-min-microvolt =3D <3300000>; > + regulator-max-microvolt =3D <3300000>; > + regulator-name =3D "vcc-lcd-2"; > + }; > + reg_cpusldo: cpusldo { > + /* real: 900mV, onoff=3D1 */ > + regulator-always-on; > + regulator-boot-on; > + regulator-min-microvolt =3D <900000>; > + regulator-max-microvolt =3D <900000>; > + }; > + }; > + }; > +}; > + > +&uart0 { > + pinctrl-names =3D "default"; > + pinctrl-0 =3D <&uart0_pb_pins>; /* only pin group this SoC's dtsi defin= es; matches vendor cmdline's ttyS0 */ > + status =3D "okay"; > +}; > + > +&{/soc} { > + /* > + * A133 (sun50iw10) has no public DE/mixer register documentation > + * (A133 User Manual rev 1.1, chapter 4.1 "DE" is 2 pages of feature > + * bullets + a block diagram, no register list =E2=80=94 unlike every o= ther > + * chapter in that manual). Addresses/topology below are cross- > + * checked two ways instead: the manual's own top-level physical > + * memory map (DE0/DSI0/DPSS_TOP0/TCON_LCD0 base addresses + GIC IRQ > + * numbers, chapter 3) and Allwinner's own GPL disp2 driver source > + * for this exact SoC (lowlevel_v2x/sun50iw10 tree =E2=80=94 public on > + * GitHub from several vendor BSP forks, e.g. chainsx/kernel-sun50iw10, > + * engSinteck/A133_Image): de_feat.c gives the real channel/layer > + * topology (DISP0 =3D 2 VI + 2 UI channels, DISP1 =3D 1 VI + 2 UI, all > + * scaler-capable) that drives the sun8i_mixer.c cfg structs, and > + * de_rtmx_init()'s reg_base + 0x100000 / + 0x200000 offsets for > + * mixer0/mixer1 match the addresses used below (and match the > + * existing convention already used for every other DE2.0 SoC in > + * this driver =E2=80=94 A64, H3, R40). > + * > + * DPSS_TOP0 (0x06510000) is a real hardware crossbar between the > + * mixers and TCON_LCD0 -- CCU exposes its own bus clock/reset gate > + * (CLK_BUS_DPSS_TOP0/RST_BUS_DPSS_TOP0), and the vendor implementation > + * explicitly routes through it. Leaving it out of the ports graph > + * entirely is not survivable: mixer0/tcon_lcd0/dsi0 all probe and > + * bind fine without it, but every DRM atomic commit then times out > + * waiting for vblank -- the pixel path never physically reaches the > + * panel, because nothing keeps DPSS_TOP0's own bus clock enabled > + * once Linux's "disable unused clocks" cleanup runs. Modeled here by > + * reusing mainline's existing sun8i_tcon_top.c driver with an added > + * A133 compatible + quirks entry: the vendor's own register layout > + * for this block is bit-for-bit identical to what that driver > + * already assumes for R40/D1/H6 -- genuinely the same IP block, just > + * undocumented for this particular SoC. > + */ > + dpss_top0: dpss-top@6510000 { > + compatible =3D "allwinner,sun50i-a133-tcon-top"; > + reg =3D <0x06510000 0x1000>; > + /* > + * "tcon-tv0" is a required clock-name in sun8i_tcon_top_bind() > + * regardless of quirks (it unconditionally registers a TV0 > + * gate clock) even though this board has no TCON_TV/HDMI > + * output at all. Pointing it at CLK_TCON_LCD is a harmless > + * filler =E2=80=94 that gate output is never consumed by anything in > + * this DT, it just needs to exist so probe doesn't fail > + * resolving the clock-name. "dsi" is real and load-bearing > + * though (has_dsi=3Dtrue pulls it in): CLK_MIPI_DSI from CCU is > + * the actual upstream parent feeding DSI's gated clock inside > + * this block. Missed this the first time around =E2=80=94 dpss_top0's > + * own probe failed outright without it (of_property_match_string > + * couldn't find "dsi" in clock-names), which cascaded into > + * dsi0's own "mod" clock lookup failing too, since it points > + * at dpss_top0's now-never-registered clock provider. > + */ > + clocks =3D <&ccu CLK_BUS_DPSS_TOP0>, > + <&ccu CLK_TCON_LCD>, > + <&ccu CLK_MIPI_DSI>; > + clock-names =3D "bus", "tcon-tv0", "dsi"; > + clock-output-names =3D "tcon-top-tv0", "tcon-top-dsi"; > + resets =3D <&ccu RST_BUS_DPSS_TOP0>; > + #clock-cells =3D <1>; > + > + ports { > + #address-cells =3D <1>; > + #size-cells =3D <0>; > + > + dpss_top0_mixer0_in: port@0 { > + reg =3D <0>; > + > + dpss_top0_in_mixer0: endpoint { > + remote-endpoint =3D <&mixer0_out_dpss_top0>; > + }; > + }; > + > + dpss_top0_mixer0_out: port@1 { > + reg =3D <1>; > + > + dpss_top0_out_tcon_lcd0: endpoint { > + remote-endpoint =3D <&tcon_lcd0_in_dpss_top0>; > + }; > + }; > + }; > + }; > + > + mixer0: mixer@6100000 { > + compatible =3D "allwinner,sun50i-a133-de2-mixer-0"; > + reg =3D <0x06100000 0x100000>; > + clocks =3D <&ccu CLK_BUS_DE>, <&ccu CLK_DE>; > + clock-names =3D "bus", "mod"; > + resets =3D <&ccu RST_BUS_DE>; > + > + ports { > + #address-cells =3D <1>; > + #size-cells =3D <0>; > + > + mixer0_out: port@1 { > + reg =3D <1>; > + > + mixer0_out_dpss_top0: endpoint { > + remote-endpoint =3D <&dpss_top0_in_mixer0>; > + }; > + }; > + }; > + }; > + > + tcon_lcd0: lcd-controller@6511000 { > + /* > + * allwinner,sun50i-a133-tcon-lcd is this series' own addition > + * (same physical IP block as A83T's TCON0, but this board's > + * DSI/CPU-mode panel needs the driver's dsi_cpu_needs_retrigger > + * quirk, which real A83T boards using the bare > + * "allwinner,sun8i-a83t-tcon-lcd" compatible do not opt into > + * -- see the comment on that quirks field in sun4i_tcon.h). > + * The a83t-tcon-lcd fallback is kept, matching the existing > + * sun50i-a64-tcon-lcd precedent in this binding, so this node > + * would still bind (without the new quirk) even against an > + * older driver that doesn't know the new compatible yet. > + */ > + compatible =3D "allwinner,sun50i-a133-tcon-lcd", > + "allwinner,sun8i-a83t-tcon-lcd"; > + reg =3D <0x06511000 0x1000>; > + /* > + * Was GIC_SPI 101 (copied from a mismatched reference DTS) -- > + * the interrupt handler was silently never firing. Confirmed > + * correct via the live vendor DT + /proc/interrupts: vendor's > + * combined disp@06000000 node's third interrupt cell is raw > + * SPI 0x44 =3D 68, and that is the ONLY display-related > + * interrupt actively counting (~60Hz) on real hardware -- > + * cross-checked against dma0's SPI 0x2d=3D45, which matches > + * exactly between the vendor DT and its own /proc/interrupts > + * with no offset, confirming the raw-cell-value convention. > + */ > + interrupts =3D ; > + clocks =3D <&ccu CLK_BUS_TCON_LCD>, <&ccu CLK_TCON_LCD>; > + clock-names =3D "ahb", "tcon-ch0"; > + clock-output-names =3D "tcon-pixel-clock"; > + resets =3D <&ccu RST_BUS_TCON_LCD>; > + reset-names =3D "lcd"; > + #clock-cells =3D <0>; > + > + ports { > + #address-cells =3D <1>; > + #size-cells =3D <0>; > + > + tcon_lcd0_in: port@0 { > + reg =3D <0>; > + > + tcon_lcd0_in_dpss_top0: endpoint { > + remote-endpoint =3D <&dpss_top0_out_tcon_lcd0>; > + }; > + }; > + > + tcon_lcd0_out: port@1 { > + reg =3D <1>; > + #address-cells =3D <1>; > + #size-cells =3D <0>; > + > + /* > + * reg =3D <1> here (not 0) is load-bearing, not > + * cosmetic: sun4i_drv.c's component-matching > + * walk (sun4i_drv_traverse_endpoints()) treats > + * a channel-0 TCON's port@1 endpoint 0 as "our > + * directly-connected panel" and deliberately > + * skips adding it to the component match list. > + * Confirmed live on real hardware: with this > + * endpoint unaddressed (defaulting to reg=3D0), > + * the DSI encoder got silently treated as a > + * bare panel and never added to the component > + * list, so component_bind_all() never bound > + * it, dsi->drm never got set, and the panel's > + * mipi_dsi_attach() spun in EPROBE_DEFER > + * forever =E2=80=94 screen stayed black even though > + * mixer0 probed fine standalone. Matches the > + * real D1 reference DTS's own convention: > + * sunxi-d1s-t113.dtsi's tcon_lcd0_out_dsi is > + * also "endpoint@1 { reg =3D <1>; ... }", same > + * as here, not endpoint 0 =E2=80=94 this was a real > + * detail I should have carried over the first > + * time instead of dropping it. > + */ > + tcon_lcd0_out_dsi0: endpoint@1 { > + reg =3D <1>; > + remote-endpoint =3D <&dsi0_in_tcon_lcd0>; > + }; > + }; > + }; > + }; > + > + dsi0: dsi@6504000 { > + compatible =3D "allwinner,sun50i-a100-mipi-dsi"; > + reg =3D <0x06504000 0x1000>; > + interrupts =3D ; > + /* > + * REVERTED: tried sourcing "mod" from dpss_top0's gated DSI > + * output (matching the vendor's de_lcd.c, which gates > + * tcon_clk_gate.bits.dsi_clk_gate as part of enabling DSI, and > + * the real D1 reference DTS's identical convention) =E2=80=94 but this > + * creates a genuine circular dependency, not just an ordering > + * race: dpss_top0 only registers its clock-provider inside its > + * component .bind() callback, which only runs once every > + * matched component (including dsi0 itself) has *already* > + * succeeded its own individual .probe(). dsi0's probe() can't > + * succeed without this clock, so it can never reach > + * component_add(), so dpss_top0's bind() never fires, forever > + * =E2=80=94 confirmed live: "Couldn't get the DSI mod clock" repeated > + * on every deferred-probe retry with no path to resolution. > + * Back to sourcing directly from CCU, which is what actually > + * got the panel to attach successfully a few iterations ago. > + * dpss_top0 stays modeled in the ports graph regardless (for > + * its own bus-clock-keepalive purpose, now fully decoupled > + * from dsi0's clock lookup) =E2=80=94 whether A133 genuinely needs > + * this specific gate toggled for DSI to output correctly, as > + * opposed to just needing DPSS_TOP0 clocked/reset for its > + * routing mux to be live, is still an open question; CCU's > + * own CLK_MIPI_DSI already has its own independent gate bit, > + * so it's plausible this DPSS_TOP0 gate is a separate/optional > + * clock domain rather than something on the primary pixel path. > + */ > + clocks =3D <&ccu CLK_BUS_MIPI_DSI>, <&ccu CLK_MIPI_DSI>; > + clock-names =3D "bus", "mod"; > + resets =3D <&ccu RST_BUS_MIPI_DSI>; > + phys =3D <&dphy0>; > + phy-names =3D "dphy"; > + status =3D "okay"; > + #address-cells =3D <1>; > + #size-cells =3D <0>; > + > + port { > + dsi0_in_tcon_lcd0: endpoint { > + remote-endpoint =3D <&tcon_lcd0_out_dsi0>; > + }; > + }; > + > + panel@0 { > + /* > + * reset-gpios pin is a placeholder (PD0) =E2=80=94 the real > + * reset line hasn't been probed on hardware yet. > + * power-supply maps to the driver's > + * devm_regulator_get(dev, "power") lookup. backlight > + * maps to drm_panel_of_backlight()'s lookup, wired to > + * the pwm-backlight node above (real PWM channel 0 / > + * 50kHz values, but backlight-enable GPIO not included > + * =E2=80=94 see the comment on that node for why). > + * > + * No ports/endpoint graph needed here: sun6i_dsi_attach() > + * (drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c) finds the > + * panel via of_drm_find_panel() on this node directly, > + * not through of_graph =E2=80=94 the DSI parent/child > + * relationship (reg =3D virtual channel) is the only > + * link needed. > + */ > + compatible =3D "orisetech,otm1289a"; > + reg =3D <0>; > + reset-gpios =3D <&pio 3 0 GPIO_ACTIVE_LOW>; /* TODO: unconfirmed pin,= revisit on real hw */ > + power-supply =3D <®_cldo1>; > + backlight =3D <&backlight>; > + }; > + }; > + > + dphy0: phy@6505000 { > + compatible =3D "allwinner,sun50i-a100-mipi-dphy"; > + reg =3D <0x06505000 0x1000>; > + interrupts =3D ; > + clocks =3D <&ccu CLK_BUS_MIPI_DSI>, <&ccu CLK_MIPI_DSI>; > + clock-names =3D "bus", "mod"; > + resets =3D <&ccu RST_BUS_MIPI_DSI>; > + #phy-cells =3D <0>; > + }; > + > + /* > + * No mainline driver or A100/A133-specific binding exists upstream > + * for this IP (see drivers/pwm/pwm-sun50i-a133.c and its binding > + * doc) -- it's a newer, richer generation than allwinner,sun4i-a10-pwm. > + * Base address and register layout are from the A133 User Manual, > + * chapter 10.11 (fully documented down to bit level). Only > + * CLK_BUS_PWM (register-access gate) is needed -- the PWM output > + * clock source itself is internal to this IP, confirmed by > + * CLK_PWM's absence from the A100 CCU headers. > + */ > + pwm: pwm@300a000 { > + compatible =3D "allwinner,sun50i-a133-pwm"; > + reg =3D <0x0300a000 0x400>; > + clocks =3D <&ccu CLK_BUS_PWM>; > + clock-names =3D "bus"; > + resets =3D <&ccu RST_BUS_PWM>; > + pinctrl-names =3D "default"; > + pinctrl-0 =3D <&pwm0_pins>; > + #pwm-cells =3D <3>; > + }; > +}; > + > +&pio { > + /* > + * PD23/pwm0, muxsel 0x2 =E2=80=94 confirmed real from the vendor live = DTB's > + * lcd_pwm_ch =3D 0 (PWM channel 0 drives the panel backlight) cross- > + * checked against drivers/pinctrl/sunxi/pinctrl-sun50i-a100.c's own > + * SUNXI_PIN(D, 23) table, which already lists "pwm0" at the exact > + * same function value (0x2) the vendor DTB used =E2=80=94 mainline's > + * pinctrl driver already fully supports this pin/function, only > + * the PWM controller driving it needed writing. > + */ > + pwm0_pins: pwm0-pins { > + pins =3D "PD23"; > + function =3D "pwm0"; > + }; > +}; > + > +/* > + * TODO: WiFi/BT (XR829 on SDIO bus 1 / &mmc1, confirmed from strings: > + * boot_xr829.bin, fw_xr829.bin, fw_xr829_bt.bin, sdd_xr829.bin =E2=80= =94 and > + * confirmed live via the running kernel's "XRADIO WIFI OPEN" driver log, > + * MAC dc:44:60:xx:xx:xx (redacted)). Power rails: bldo1 (3300mV, switch= ed on > + * dynamically, not always-on) + aldo3 (3300mV, always-on) =E2=80=94 bot= h wired > + * above. GPIO wiring is REAL, read directly off the live unit's > + * /sys/kernel/debug/gpio (not decoded from packed vendor fields): > + * bt_rst =3D r_pio 0 2 (PL2) output, active low > + * bt_hostwake =3D r_pio 0 3 (PL3) input > + * bt_wake =3D r_pio 0 4 (PL4) output > + * wlan_regon =3D r_pio 0 5 (PL5) output > + * wlan_hostwake =3D r_pio 0 6 (PL6) input > + * Mainline equivalent is an mmc1 node + mmc-pwrseq-simple (using > + * wlan_regon as the reset-gpios line) + whatever XR829 driver ends up > + * used (no mainline driver exists yet =E2=80=94 see project notes for t= he > + * out-of-tree candidates). Not wired into an actual mmc1 node yet. > + */ > + > +/* > + * Display: mixer0/tcon_lcd0/dsi0/dphy0/panel@0 are all wired above > + * (&soc block + dsi0's panel@0 child). Status: > + * - Panel driver (panel-orisetech-otm1289a.c) written: real timings > + * (720x1280, 69MHz dclk, ht=3D880/hbp=3D88/hspw=3D4, vt=3D1320/vbp= =3D9/vspw=3D4) > + * plus a DSI init command sequence transcribed from a MediaTek LCM > + * driver for the same panel controller IC found via GitHub code > + * search (OrangePi4G-iot_kernel's otm1289a_hd720_dsi_vdo_auo.c) =E2= =80=94 > + * NOT from Allwinner's own disp2 tree, which was checked for this > + * board's exact panel and doesn't have it (its bundled lcd/ panel > + * library has ~90 entries but none named otm1289a; ours is probably > + * a TrimUI-added file in a downstream fork that isn't public). The > + * reference driver uses 3 DSI lanes; ours is set to the confirmed > + * real 4-lane value, so timing-sensitive parts of the init sequence > + * may need retuning once there's real hardware feedback. > + * - Mixer (sun8i_mixer.c): A133 cfg added, ported from the same vendor > + * tree's de_feat.c topology data (see &soc comment above the mixer0 > + * node for the full provenance/reasoning). > + * - TCON_LCD0/DSI0/D-PHY: real register addresses from the A133 User > + * Manual (chapter 6, which =E2=80=94 unlike the DE chapter =E2=80=94= is fully > + * documented down to bit level); DSI host + D-PHY already had > + * mainline driver support for A100 before this port touched anything. > + * Backlight: working. The `backlight` pwm-backlight node above (PWM > + * channel 0, 50kHz) is wired via `backlight =3D <&backlight>` on the pa= nel > + * node and confirmed on real hardware. > + * > + * The remaining open item is display output itself: the panel attaches > + * and the backlight lights, but TCON0's CPU/8080-interface TRIGGER_START > + * bit never self-clears, so no pixel data reaches the panel -- see the > + * project's investigation log for the current status. reset-gpios is > + * still an unverified placeholder, and the DPSS_TOP0 routing-register > + * risk noted above the mixer0 node is still unconfirmed. > + */ > + > +/* > + * TODO: GPU (img,gpu / PowerVR GE8300) =E2=80=94 no mainline binding to= reference > + * yet. > + */ > diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a100.c b/drivers/clk/sunxi-n= g/ccu-sun50i-a100.c > index 1f81c7ac4..9dee187ba 100644 > --- a/drivers/clk/sunxi-ng/ccu-sun50i-a100.c > +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a100.c > @@ -680,13 +680,27 @@ static const char * const tcon_lcd_parents[] =3D { = "pll-video0-4x", > "pll-video2-4x", > "pll-video3-4x", > "pll-periph0-2x" }; > +/* > + * No CLK_SET_RATE_PARENT here originally, unlike the other PLL_VIDEO > + * derivatives it can mux to (pll_video0_4x_clk etc, which do have it). > + * Confirmed via debugfs on real hardware: this left mainline's dclk > + * request landing on a 400MHz PLL_VIDEO0 parent, unable to explore other > + * PLL rates -- vendor's own live system has this same clock at exactly > + * 408MHz (=3D 24MHz x 17, a clean PLL multiple, the actual nearest > + * achievable rate to the ~414MHz our A133 board's CPU/8080 DSI panel > + * requests). Without this flag, ccu_mp_ops's own rate-rounding can't ask > + * its selected parent to change rate at all -- it can only divide down > + * from whatever that parent already happens to be at, which produced a > + * measurably worse (2%) result than vendor's real driver achieves for > + * this exact panel. > + */ > static SUNXI_CCU_MP_WITH_MUX_GATE(tcon_lcd_clk, "tcon-lcd0", > tcon_lcd_parents, 0xb60, > 0, 4, /* M */ > 8, 2, /* P */ > 24, 3, /* mux */ > BIT(31), /* gate */ > - 0); > + CLK_SET_RATE_PARENT); > =20 > static SUNXI_CCU_GATE(bus_tcon_lcd_clk, "bus-tcon-lcd0", "ahb3", > 0xb7c, BIT(0), 0); > diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig > index cbdf7b8f7..fab1ed5f4 100644 > --- a/drivers/gpu/drm/panel/Kconfig > +++ b/drivers/gpu/drm/panel/Kconfig > @@ -758,6 +758,14 @@ config DRM_PANEL_ORISETECH_OTM8009A > Say Y here if you want to enable support for Orise Technology > otm8009a 480x800 dsi 2dl panel. > =20 > +config DRM_PANEL_ORISETECH_OTM1289A > + tristate "Orise Technology otm1289a 720x1280 dsi panel" > + depends on OF > + depends on DRM_MIPI_DSI > + help > + Say Y here if you want to enable support for Orise Technology > + otm1289a 720x1280 dsi panel, as used on the TrimUI Smart Pro. > + > config DRM_PANEL_OSD_OSD101T2587_53TS > tristate "OSD OSD101T2587-53TS DSI 1920x1200 video mode panel" > depends on OF > diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makef= ile > index 3b523cf37..d824f0a9b 100644 > --- a/drivers/gpu/drm/panel/Makefile > +++ b/drivers/gpu/drm/panel/Makefile > @@ -74,6 +74,7 @@ obj-$(CONFIG_DRM_PANEL_MANTIX_MLAF057WE51) +=3D panel-m= antix-mlaf057we51.o > obj-$(CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO) +=3D panel-olimex-lcd-olinu= xino.o > obj-$(CONFIG_DRM_PANEL_ORISETECH_OTA5601A) +=3D panel-orisetech-ota5601a= .o > obj-$(CONFIG_DRM_PANEL_ORISETECH_OTM8009A) +=3D panel-orisetech-otm8009a= .o > +obj-$(CONFIG_DRM_PANEL_ORISETECH_OTM1289A) +=3D panel-orisetech-otm1289a= .o > obj-$(CONFIG_DRM_PANEL_OSD_OSD101T2587_53TS) +=3D panel-osd-osd101t2587-= 53ts.o > obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) +=3D panel-panasonic-vvx1= 0f034n00.o > obj-$(CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN) +=3D panel-raspberrypi-t= ouchscreen.o > diff --git a/drivers/gpu/drm/panel/panel-orisetech-otm1289a.c b/drivers/g= pu/drm/panel/panel-orisetech-otm1289a.c > new file mode 100644 > index 000000000..86d42bdab > --- /dev/null > +++ b/drivers/gpu/drm/panel/panel-orisetech-otm1289a.c > @@ -0,0 +1,435 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * DRM driver for the Orise Tech OTM1289A MIPI-DSI panel, as used on the > + * TrimUI Smart Pro (Allwinner A133). > + * > + * Timings (dot clock, hsync/vsync, panel size) are real, measured values > + * pulled directly from the stock vendor firmware's live device tree on > + * actual hardware, not datasheet guesses. > + * > + * The DCS init command sequence below is reverse-engineered directly fr= om > + * this device's own real vendor kernel binary (vendor_kernel.bin, Linux > + * 4.9.191, extracted from part1_boot.img), not transcribed from an > + * unrelated reference driver. Converted the raw Image to a symbolized E= LF > + * via vmlinux-to-elf (recovers the embedded kallsyms table + a correct > + * load-base guess), then disassembled lcd_panel_init(): it does a > + * runtime strncmp() of this board's configured panel name against a > + * table of known driver names ("gc9702c", "otm1289a", ...), and on a > + * match stores a pointer to that driver's own DCS command table -- > + * confirmed at VA 0xffffff8008b72190 for the "otm1289a" match on this > + * exact device. That table uses fixed 72-byte entries: byte at +0 is the > + * DCS command, byte at +4 is the data length (0xff =3D end-of-table > + * marker, 0xfe =3D delay marker with the ms value at +8), and the data > + * payload starts at +8 -- confirmed by reading lcd_panel_init()'s own > + * parsing loop, which calls sunxi_lcd_dsi_dcs_write(sel, entry[0], > + * &entry[8], entry[4]) for every non-marker entry. This is a real, > + * ground-truth match to this exact physical panel -- and differs in > + * concrete values (gamma curves, several power/timing registers) from > + * the earlier version of this table, which was transcribed from an > + * unrelated MediaTek-based reference driver chosen only because its > + * resolution happened to match. This board is wired for 4 DSI lanes > + * (confirmed from the vendor DTB) -- a host-side PHY configuration > + * independent of the panel's own init register values above. > + */ > + > +#include > +#include > +#include > +#include > +#include > + > +#include