Skip to content

Ayn Odin2 kernel 7.0 support#9706

Open
kasimling wants to merge 3 commits intoarmbian:mainfrom
kasimling:odin2_kernel_7.0
Open

Ayn Odin2 kernel 7.0 support#9706
kasimling wants to merge 3 commits intoarmbian:mainfrom
kasimling:odin2_kernel_7.0

Conversation

@kasimling
Copy link
Copy Markdown
Contributor

@kasimling kasimling commented Apr 21, 2026

Description

This PR adds kernel 7.0 support Ayn Odin2 device

Summary by CodeRabbit

  • New Features

    • Added many new drivers: UART gamepad, multiple DRM MIPI‑DSI panels, backlights, PWM/LED controllers, regulator, PWM and PWM‑fan defaults; new board device trees for AYN Odin2 family and UART15.
  • Bug Fixes & Improvements

    • Touch/reset/backlight reliability, GPU/display timing, USB handoff, SDHCI mode support, runtime PM and interconnect QoS/bandwidth, cache/clock topology and battery sysfs name; platform serial can seed MAC/BD_ADDR; opt‑in compat input syscalls enabled.
  • Configuration & Updates

    • Kernel baseline advanced from 6.18 → 7.0; device‑tree CPU/EAS/OPP and interconnect tuning applied.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 21, 2026

📝 Walkthrough

Walkthrough

Bumps SM8550 kernel baseline from 6.18 to 7.0 for the edge channel; adds ~40 kernel patches that introduce many new drivers (panels, backlight, LED, PWM, regulator, joystick), DT board includes and boards for multiple AYN devices, NoC/QoS/OPP DTS updates, driver fixes, soc-serial-derived MAC/BD_ADDR, and a compat-input prctl flag.

Changes

Kernel Version & Defconfig

Layer / File(s) Summary
Manifest / Config Source
config/sources/families/sm8550.conf
Edge channel kernel defaults changed from KERNEL_MAJOR_MINOR="6.18" / branch:linux-6.18.yKERNEL_MAJOR_MINOR="7.0" / branch:linux-7.0.y; board-specific override added to force 6.18 for BOARD == ayn-odin2portal and set LINUXCONFIG="linux-sm8550-current".
Defconfig header & options
config/kernel/linux-sm8550-edge.config
Defconfig header updated to “generated with 7.0”; assorted config option adjustments (DRM/panel, framebuffer/logo, crypto symbols removed/relocated).

Drivers, Panels, Backlights, PWM, LEDs, Regulators, Input

Layer / File(s) Summary
Kconfig / Makefile wiring
drivers/*/*/Kconfig, */Makefile (panels, leds, pwm, backlight, regulator, joystick)
New Kconfig symbols and Makefile object wiring for many added drivers: multiple DRM panel options, JOYSTICK_RSINPUT, LEDS_HTR3212, PWM_SN3112, BACKLIGHT_ODIN2MINI, BACKLIGHT_SY7758, REGULATOR_SGM3804, etc.
New drivers / cores
drivers/gpu/drm/panel/*.c, drivers/input/joystick/rsinput.c, drivers/leds/leds-htr3212.c, drivers/pwm/pwm-sn3112.c, drivers/video/backlight/*.c, drivers/regulator/sgm3804-regulator.c
Introduces many new drivers: multiple MIPI-DSI panel drivers, RSInput serdev joystick driver, HTR3212 LED driver, SN3112 PWM driver, Odin2Mini & SY7758 backlight drivers, SGM3804 regulator. Each implements probe/remove, DT/I2C/OF match tables, and runtime ops.
Driver enhancements & internal changes
drivers/input/rmi4/*, drivers/input/edt-ft5x06/*, drivers/input/hynitron_*, drivers/input/joystick/rsinput.c
Add optional reset GPIO to RMI4 transport and move default reset delay macro into header; edt-ft5x06 adds no_regmap_bulk_read fallback; hynitron touchscreen acquires/enables vdd and reports width major; RSInput integrates vdd regulator and reorders GPIO init to init commands.
Audio / ASoC / codec tweaks
sound/soc/codecs/aw88166.c, sound/*
AW88166: conditional DSP raw writes, lower log level for PA stop, add ASoC DAI ops, use DT firmware-name for ACF, add OF match table. SC8280XP machine driver: optional i2s_clk and startup hook enabling I2S clock and DAI formats.
MMC/SDHCI tweaks
drivers/mmc/host/sdhci-msm.c, arch/arm64/boot/dts/qcom/*
Add FIFO write clock toggle helper and host flag for certain core revisions; DTS updates remove sdhci-caps-mask and change xo clock for some controllers enabling SDR50/SDR104 negotiation.
Small driver fixes
drivers/gpu/drm/msm/msm_drv.c, drivers/usb/host/pci-quirks.c, drivers/hwmon/pwm-fan.c
Remove DRIVER_SYNCOBJ_TIMELINE flag from msm DRM; drop xHCI handshake readiness wait in USB quirk; set pwm-fan boot PWM to 70 in probe.

Interconnect / QoS / NoC / OPP / Caches / EAS (DTS changes)

Layer / File(s) Summary
Cache topology & EAS constants
arch/arm64/boot/dts/qcom/sm8550.dtsi
Add explicit L1/L2/L3 cache geometry properties; fix CPU2 L2 mapping; update EAS capacity-dmips-mhz and dynamic-power-coefficient values across clusters.
OPP / interconnect / bandwidth
arch/arm64/boot/dts/qcom/sm8550.dtsi, drivers/interconnect/qcom/sm8550.c
Add operating-points-v2 tables for CPU clusters, introduce epss_l3 interconnect node and attach interconnects to CPU nodes; add qcom,opp-acd-level entries for GPU OPPs; enrich many qcom_icc_node descriptors with qosbox settings and add regmap configs for NoC descriptors.
GPU_CC power-domains
arch/arm64/boot/dts/qcom/sm8550.dtsi
Declare power-domains for GPU_CC node listing RPMHPD domains.

Device-tree: AYN common include and board DTs

Layer / File(s) Summary
Common platform include
arch/arm64/boot/dts/qcom/qcs8550-ayn-common.dtsi
New AYN common include: removes inherited reserved-memory/remoteproc nodes, sets board identifiers, adds gpio-keys, pmic-glink USB-C endpoints, pwm-fan node, thermal zones/cooling maps, sound card wiring, RPMh regulator definitions and many PMIC/regulator nodes.
Board DTS & Makefile wiring
arch/arm64/boot/dts/qcom/qcs8550-ayn-*.dts, arch/arm64/boot/dts/qcom/Makefile
Add multiple new board DTs and DTB build entries: qcs8550-ayn-odin2.dts, qcs8550-ayn-odin2mini.dts, qcs8550-ayn-odin2portal.dts, qcs8550-ayn-thor.dts; each wires panels, backlight/LED controllers, touch controllers, PWM/ regulators, firmware names, HDMI bridge endpoints and other board-specific nodes.
Auxiliary DTS additions
arch/arm64/boot/dts/qcom/pmk8550.dtsi
Add pmk8550_pwm node (disabled by default).

Soc-serial derived MAC / BD_ADDR

Layer / File(s) Summary
Socinfo export
drivers/soc/qcom/socinfo.c
Define and EXPORT_SYMBOL a global const char *qcom_serial_number set from SMEM during socinfo probe and cleared on remove.
Bluetooth BD_ADDR generation
drivers/bluetooth/btqca.c
Add generate_bdaddr_from_serial() to derive BD_ADDR from last 6 hex chars of qcom_serial_number; use generated BD_ADDR in qca_uart_setup() and disable previous BD_ADDR read path.
ath12k MAC generation
drivers/net/wireless/ath/ath12k/mac.c
Add generate_macaddr_from_serial() and reverse helper; ath12k_mac_hw_register() attempts serial-derived MAC (fixed prefix) and falls back to prior logic on failure.

Compat input syscalls via prctl

Layer / File(s) Summary
Task flag & headers
include/linux/sched.h, include/uapi/linux/prctl.h
Add bool compat_input to struct task_struct and new UAPI prctl constants: PR_GET_COMPAT_INPUT, PR_SET_COMPAT_INPUT, and enable/disable values.
Input compat handling
drivers/input/input-compat.c, drivers/input/input-compat.h
Extend compat-selection logic to consult current->compat_input and adjust input_event_size() to use compat struct size when the flag is set.
prctl implementation
kernel/sys.c
Implement PR_GET_COMPAT_INPUT and PR_SET_COMPAT_INPUT handling in prctl syscall, validating args and toggling current->compat_input.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Poem

🐇 I hopped the tree from six to seven, bright and merry,
New panels, LEDs, and PWM queues I carry,
DTs and drivers stitched in a patchy braid,
I nibble bugs, hum kernels, and stash a carrot braid. 🥕

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

@github-actions github-actions Bot added 05 Milestone: Second quarter release size/large PR with 250 lines or more Needs review Seeking for review Hardware Hardware related like kernel, U-Boot, ... Patches Patches related to kernel, U-Boot, ... labels Apr 21, 2026
@kasimling
Copy link
Copy Markdown
Contributor Author

Audio is not working yet.

@kasimling
Copy link
Copy Markdown
Contributor Author

Now audio is working

@kasimling kasimling changed the title [WIP] Ayn Odin2 kernel 7.0 support Ayn Odin2 kernel 7.0 support Apr 25, 2026
@kasimling kasimling marked this pull request as ready for review April 25, 2026 09:07
@kasimling kasimling requested a review from igorpecovnik as a code owner April 25, 2026 09:07
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

Note

Due to the large number of review comments, Critical severity comments were prioritized as inline comments.

🟠 Major comments (14)
patch/kernel/archive/sm8550-7.0/0022-Input-hynitron_cstxxx-specific-patch-for-Odin2-Mini.patch-44-58 (1)

44-58: ⚠️ Potential issue | 🟠 Major

Regulator left enabled on driver unbind / late probe failure.

devm_regulator_get() only releases the reference on detach; it does not call regulator_disable(). The vdd regulator is enabled with no matching disable in any error path (e.g., failures from init_input, request_threaded_irq, etc.) nor on .remove(). Each unbind/rebind cycle will leave the regulator with an extra enable count, eventually preventing it from being disabled by other consumers.

Prefer devm_regulator_get_enable() (available since 5.18) so disable is tied to device lifetime, or register a devm action.

🛡️ Suggested fix using devm_regulator_get_enable
-	ts_data->vdd = devm_regulator_get(&client->dev, "vdd");
-	if (IS_ERR(ts_data->vdd)) {
-		err = PTR_ERR(ts_data->vdd);
-		if (err != -EPROBE_DEFER)
-			dev_err(&client->dev, "Failed to request vdd regulator: %d\n", err);
-		return err;
-	}
-
-	err = regulator_enable(ts_data->vdd);
-	if (err) {
-		dev_err(&client->dev, "enable regulator failed: %d\n", err);
-		return err;
-	}
+	err = devm_regulator_get_enable(&client->dev, "vdd");
+	if (err)
+		return dev_err_probe(&client->dev, err,
+				     "Failed to enable vdd regulator\n");

If you go this route, the struct regulator *vdd field added to hynitron_ts_data (line 27) can also be dropped, since it is otherwise unused.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@patch/kernel/archive/sm8550-7.0/0022-Input-hynitron_cstxxx-specific-patch-for-Odin2-Mini.patch`
around lines 44 - 58, The patch enables the vdd regulator with
devm_regulator_get() + regulator_enable() but never disables it on error or
device remove, leaking enable counts; replace the get+enable sequence by using
devm_regulator_get_enable(&client->dev, "vdd") (available since 5.18) so the
regulator is automatically disabled on device detach, or alternatively register
a devm_add_action to call regulator_disable on cleanup; update references to
ts_data->vdd and, if you choose devm_regulator_get_enable and the vdd field is
otherwise unused, remove the struct regulator *vdd from hynitron_ts_data to
avoid holding an unused pointer.
patch/kernel/archive/sm8550-7.0/0027-HACK-fix-usb-boot-hang.patch-15-30 (1)

15-30: ⚠️ Potential issue | 🟠 Major

HACK acknowledged — please scope and document the workaround.

A few concerns with removing the XHCI_STS_CNR (Controller-Not-Ready) handshake wholesale:

  1. Spec compliance. The xHCI spec requires software to wait for CNR=0 before writing operational registers. The op_reg_base halt/XHCI_IRQS writes immediately following the deletion may now race with controller-ready state on slow-to-init xHCIs and produce undefined behavior — though on the affected Odin2 hardware the original 5s wait was apparently never clearing, hence the hang.
  2. Blast radius. quirk_usb_handoff_xhci() runs for every xHCI device on the system. Removing the wait globally in the SM8550 kernel affects all current/future xHCI controllers, not just the SoC-internal one that triggered the hang. Consider bounding the workaround with a pci_match_id() check for the specific vendor/device that hangs, or shortening the timeout (e.g., 100 ms) instead of dropping it entirely.
  3. Silent regression risk. The accompanying dev_warn("xHCI HW not ready after 5 sec...") is also removed, so if a future regression re-introduces a non-ready controller, there will be no log signal.
  4. Commit metadata. Please expand the commit message to describe the root cause (which xHCI / firmware revision hangs in CNR), so the next person rebasing this onto kernel 7.1+ knows whether the HACK is still needed.

Acknowledging the HACK: prefix indicates this is intentional for now; treating as a major (not blocker) flag for a more targeted follow-up.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@patch/kernel/archive/sm8550-7.0/0027-HACK-fix-usb-boot-hang.patch` around
lines 15 - 30, The removed XHCI CNR handshake in quirk_usb_handoff_xhci (removal
of the XHCI_STS_CNR wait and dev_warn) is too broad; reinstate a bounded
workaround: detect the specific problematic controller (use pci_match_id with
the vendor/device ID for the Odin2/SoC-internal xHCI) and only skip or shorten
the CNR handshake for that ID, otherwise perform a short timeout handshake
(e.g., handshake(op_reg_base + XHCI_STS_OFFSET, XHCI_STS_CNR, 0, 100000, 10))
and keep the dev_warn logging on timeout (including the readl status). Also
update the commit message to document the affected xHCI device/firmware and
rationale for the scoped HACK so future rebases can assess necessity.
patch/kernel/archive/sm8550-7.0/0025-input-RSInput-Add-regulator.patch-67-76 (1)

67-76: ⚠️ Potential issue | 🟠 Major

Regulator enable leaks on probe failure.

regulator_enable(drv->vdd) is called early in probe (line 73) but subsequent error paths—GPIO failures (lines 80–82), serdev_device_open failure (line 102), and rsinput_init_commands failure—all return error without a matching regulator_disable. The disable only runs in rsinput_remove(), which is not called when probe fails. This leaves the regulator enabled with an unbalanced refcount, preventing re-probe/rebind and potentially keeping power on a non-functional device.

Prefer the device-managed variant so cleanup is automatic:

🔧 Suggested fix using devm_regulator_get_enable
-	drv->vdd = devm_regulator_get(&serdev->dev, "vdd");
-	if (IS_ERR(drv->vdd)) {
-		error = PTR_ERR(drv->vdd);
-		return error;
-	}
-
-	error = regulator_enable(drv->vdd);
-	if (error < 0) {
-		return error;
-	}
+	error = devm_regulator_get_enable(&serdev->dev, "vdd");
+	if (error)
+		return dev_err_probe(&serdev->dev, error,
+				     "Failed to enable vdd regulator\n");

Then drop the struct regulator *vdd; field from struct rsinput_driver and remove the regulator_disable(drv->vdd); call in rsinput_remove() (line 109).

The function is available in Linux 6.2+ and your target kernel 7.0, and since the driver needs only simple enable-on-probe/disable-on-remove lifecycle with no runtime control, devm_regulator_get_enable() is the correct and idiomatic choice.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@patch/kernel/archive/sm8550-7.0/0025-input-RSInput-Add-regulator.patch`
around lines 67 - 76, The probe enables the regulator via
regulator_enable(drv->vdd) after getting it with devm_regulator_get, but on
later probe failures the code returns without disabling the regulator, leaking a
refcount; replace the get+enable pair with the device-managed
devm_regulator_get_enable(&serdev->dev, "vdd") and remove manual
regulator_disable(drv->vdd) and the vdd field from struct rsinput_driver so the
regulator is automatically disabled on probe failure and removal; update
references to drv->vdd (e.g., in probe and rsinput_remove) accordingly and drop
regulator_disable(drv->vdd) from rsinput_remove().
patch/kernel/archive/sm8550-7.0/0006-ASoC-qcom-sc8280xp-Add-support-for-Primary-I2S.patch-36-57 (1)

36-57: ⚠️ Potential issue | 🟠 Major

Clock refcount leak: clk_prepare_enable is unbalanced.

sc8280xp_snd_startup() calls clk_prepare_enable(pdata->i2s_clk) on every PCM open for PRIMARY/SECONDARY_MI2S_RX, but sc8280xp_be_ops.shutdown is still wired to qcom_snd_sdw_shutdown, which won't disable i2s_clk. Each open increments the prepare/enable refcount permanently — across stream churn this leaks the clock and keeps the I2S block powered.

Also, clk_prepare_enable() and the two snd_soc_dai_set_fmt() return values are silently ignored.

🛠️ Suggested fix

Add a corresponding shutdown that releases the clock for the same DAI ids, and propagate errors from startup:

+static void sc8280xp_snd_shutdown(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct sc8280xp_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card);
+	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+
+	switch (cpu_dai->id) {
+	case PRIMARY_MI2S_RX:
+	case SECONDARY_MI2S_RX:
+		clk_disable_unprepare(pdata->i2s_clk);
+		break;
+	}
+
+	qcom_snd_sdw_shutdown(substream);
+}
@@
 static const struct snd_soc_ops sc8280xp_be_ops = {
 	.startup = sc8280xp_snd_startup,
-	.shutdown = qcom_snd_sdw_shutdown,
+	.shutdown = sc8280xp_snd_shutdown,

Also applies to: 62-69

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@patch/kernel/archive/sm8550-7.0/0006-ASoC-qcom-sc8280xp-Add-support-for-Primary-I2S.patch`
around lines 36 - 57, The startup currently calls
clk_prepare_enable(pdata->i2s_clk) and ignores return values from
clk_prepare_enable and snd_soc_dai_set_fmt, leaking the clock; add a matching
shutdown handler (e.g., implement sc8280xp_snd_shutdown and wire it into
sc8280xp_be_ops.shutdown or call clk_disable_unprepare in the existing shutdown
path) that checks cpu_dai->id for PRIMARY_MI2S_RX and SECONDARY_MI2S_RX and
calls clk_disable_unprepare(pdata->i2s_clk); in sc8280xp_snd_startup check and
propagate errors from clk_prepare_enable and from the two snd_soc_dai_set_fmt
calls, and on any error undo prior work (disable/unprepare the clock if it was
enabled) before returning the error code so refcounts stay balanced.
patch/kernel/archive/sm8550-7.0/0024-regulator-add-sgm3804-i2c-regulator-for-panel-power-.patch-69-93 (1)

69-93: ⚠️ Potential issue | 🟠 Major

Broken error handling and partial-enable state in sgm3804_enable.

Two issues here:

  1. ret |= regmap_write(...) ORs three potentially-negative errno values together. The result is not a meaningful errno (e.g., (-EIO) | (-ENODEV)-1) and silently masks which write failed. Errors must be checked sequentially and returned immediately.
  2. On a write failure mid-sequence, the chip is left half-programmed, the reset GPIOs remain asserted high, and data->enabled stays false, so the regulator core thinks the rail is off while the silicon is partially enabled. A subsequent enable() retry then re-asserts everything from a non-clean state.
🛠️ Suggested fix
-    ret |= regmap_write(regmap, 0x00, 0x0c);
-    ret |= regmap_write(regmap, 0x01, 0x0c);
-    ret |= regmap_write(regmap, 0x03, 0x03);
-    if (ret) {
-        dev_err(rdev->dev.parent, "Failed to enable SGM3804 regulator\n");
-        return ret;
-    }
+    ret = regmap_write(regmap, 0x00, 0x0c);
+    if (ret)
+        goto err;
+    ret = regmap_write(regmap, 0x01, 0x0c);
+    if (ret)
+        goto err;
+    ret = regmap_write(regmap, 0x03, 0x03);
+    if (ret)
+        goto err;

     data->enabled = true;
     return 0;
+
+err:
+    dev_err(rdev->dev.parent, "Failed to enable SGM3804 regulator: %d\n", ret);
+    if (data->reset_gpio[1])
+        gpiod_set_value_cansleep(data->reset_gpio[1], 0);
+    if (data->reset_gpio[0])
+        gpiod_set_value_cansleep(data->reset_gpio[0], 0);
+    return ret;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@patch/kernel/archive/sm8550-7.0/0024-regulator-add-sgm3804-i2c-regulator-for-panel-power-.patch`
around lines 69 - 93, The sgm3804_enable function must check each regmap_write
sequentially and return the first negative errno instead of OR-ing results;
perform regmap_write to 0x00, check ret and return on error, then 0x01,
check/return, then 0x03, check/return. On any failure undo any previous
successful state changes: drive any reset_gpio[] back to their previous (low)
state and ensure data->enabled remains false before returning the error; only
set data->enabled = true after all writes succeed. Also include the actual errno
in the dev_err message using the failed return value to aid debugging.
patch/kernel/archive/sm8550-7.0/0040-arm64-dts-qcom-Add-AYN-Thor.patch-133-187 (1)

133-187: ⚠️ Potential issue | 🟠 Major

LED node-name suffixes are inverted vs. declared colors and grouping.

Across both htr3212l and htr3212r controllers the per-channel node names use _b/_g/_r suffixes that don't match either the label string or the color value. For example:

  • ledl_b1 (suffix "b") → label = "l:r1", color = LED_COLOR_ID_RED
  • ledl_r1 (suffix "r") → label = "l:b1", color = LED_COLOR_ID_BLUE
  • ledl_g1 (suffix "g") → label = "l:g1", color = LED_COLOR_ID_GREEN

The multi-led* parents then list channels in declaration order:

multi-ledr1 {
    leds = <&ledr_r4>, <&ledr_g4>, <&ledr_b4>;  // RED, GREEN, BLUE order?
};

But by the actual color values, ledr_r4 = BLUE and ledr_b4 = RED, so this group is effectively wired BGR rather than RGB. Some leds-group-multicolor consumers do honor list order for color reporting/debug, and userspace-visible labels (l:r1 vs node ledl_b1) will not match what callers expect when looking at sysfs paths.

Please reconcile naming so node-name suffix, label, and color agree, and update the multi-led* leds = <…> lists accordingly. If the current wiring is intentional (e.g., to expose a particular hardware-channel-to-color mapping), document it in a comment so it isn't read as a copy/paste mistake.

Minor: line 343 has a space-before-tab on color = <LED_COLOR_ID_BLUE>; inside ledr_r2.

Also applies to: 217-277, 315-375

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@patch/kernel/archive/sm8550-7.0/0040-arm64-dts-qcom-Add-AYN-Thor.patch`
around lines 133 - 187, Per the review, per-channel node names and their color
metadata are inconsistent: nodes like ledl_b1/ledl_r1/ledl_g1 have suffixes that
don't match their label or color properties (e.g., ledl_b1 labeled "l:r1" but
color LED_COLOR_ID_RED), which in turn makes multi-led groupings
(multi-ledr1/multi-ledl1/... using leds = <&ledr_r4>, <&ledr_g4>, <&ledr_b4>;
etc.) ordered wrongly (BGR vs RGB). Fix by renaming per-channel nodes or
correcting their label and color properties so the node-name suffix (_r/_g/_b),
the label string (e.g., "l:r1"/"l:g1"/"l:b1"), and the color property
(LED_COLOR_ID_RED/GREEN/BLUE) all agree for each htr3212l/htr3212r channel
(ledr_*/ledl_*), and then reorder the leds = <...> lists in multi-ledr1,
multi-ledl1, multi-ledr2, multi-ledl2, multi-ledr3, multi-ledl3, multi-ledr4,
multi-ledl4 to match RGB order accordingly; if wiring intentionally maps
differently, add a comment above the affected multi-led* node explaining the
hardware mapping. Also fix the whitespace issue at the noted color =
<LED_COLOR_ID_BLUE>; to remove the space-before-tab.
patch/kernel/archive/sm8550-7.0/0042-drivers-use-soc-serial-for-wifi-and-bluetooth.patch-116-135 (1)

116-135: ⚠️ Potential issue | 🟠 Major

Serial-derived BD_ADDR unconditionally overrides the device's NVM/factory address.

generate_bdaddr_from_serial() is now called before any check of the existing/factory BD_ADDR, and on success the driver writes that synthetic address into hdev->public_addr and hdev->bdaddr. Devices that ship with a valid, vendor-programmed BD_ADDR (from QCA NVM) lose it after this patch — including across unrelated boards that also use btqca.c.

Since this driver is shared with all QCA Bluetooth UART devices, this change has broad impact. Please gate the new behavior behind a board/DT property (or a Kconfig option) so non-AYN boards keep the upstream NVM-based logic.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@patch/kernel/archive/sm8550-7.0/0042-drivers-use-soc-serial-for-wifi-and-bluetooth.patch`
around lines 116 - 135, The patch currently unconditionally generates and writes
a serial-derived BD_ADDR (via generate_bdaddr_from_serial, qca_set_bdaddr and
bacpy to hdev->public_addr/hdev->bdaddr), which overwrites a valid NVM/factory
address; modify the logic to first check for an existing valid BD_ADDR using
qca_check_bdaddr (or the existing check in this file) and only proceed to call
generate_bdaddr_from_serial/qca_set_bdaddr and update hdev addresses if no valid
NVM BD_ADDR exists AND a board-enabling flag is set; add a DT property (or
Kconfig flag) check (e.g., ofdev/bdaddr-from-serial or a new bool like
allow_serial_bdaddr) before generating/setting the synthetic address so non-AYN
boards retain upstream NVM behavior.
patch/kernel/archive/sm8550-7.0/0042-drivers-use-soc-serial-for-wifi-and-bluetooth.patch-279-303 (1)

279-303: ⚠️ Potential issue | 🟠 Major

Race condition: qcom_serial_number updated without synchronization.

qcom_socinfo_remove() clears qcom_serial_number = NULL without any synchronization, while btqca and ath12k dereference the same pointer from their own probe/setup paths. If socinfo is unloaded (or its probe is repeated for any reason) while a consumer is in the middle of generate_bdaddr_from_serial() / generate_macaddr_from_serial(), you get a TOCTOU NULL deref between the if (!serial) check and the subsequent strlen(serial) / strncpy(...).

Also note qs->attr.serial_number is allocated with devm_kasprintf(), so when qcom_socinfo is removed the memory backing the global pointer is freed by devres before any consumer is told to stop using it — i.e. a use-after-free is possible even in the absence of a NULL race.

Practical mitigations:

  • Pass the serial through a stable interface (e.g., qcom_smem_get(...) directly, or a getter that returns a copy under a lock/RCU).
  • At minimum, make qcom_serial_number point to a string with module/static lifetime (not devm_*) so it remains valid for the lifetime of the kernel.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@patch/kernel/archive/sm8550-7.0/0042-drivers-use-soc-serial-for-wifi-and-bluetooth.patch`
around lines 279 - 303, The global qcom_serial_number is assigned in
qcom_socinfo_probe and cleared in qcom_socinfo_remove without synchronization,
allowing TOCTOU NULL-deref or use-after-free in consumers like
generate_bdaddr_from_serial/generate_macaddr_from_serial (used by btqca/ath12k).
Fix by giving consumers a stable string lifetime or a safe getter: either
allocate a module/static copy (e.g., kstrdup at probe and kfree at remove) and
publish it via rcu_assign_pointer/synchronize_rcu, or implement a getter
function that returns a freshly allocated copy under a lock/RCU; ensure
qcom_socinfo_remove uses synchronize_rcu (or the lock) before freeing/clearing
the pointer so consumers cannot see freed memory.
patch/kernel/archive/sm8550-7.0/0042-drivers-use-soc-serial-for-wifi-and-bluetooth.patch-249-268 (1)

249-268: ⚠️ Potential issue | 🟠 Major

Same concern in ath12k: forcing serial-derived MAC affects all ath12k devices.

ath12k_mac_hw_register() now prefers generate_macaddr_from_serial() over the existing pdevs_macaddr_valid / ar->ab->mac_addr paths. Like the btqca change, this affects every ath12k-based device, not just AYN Odin 2 — boards that have valid per-pdev factory MAC addresses will now have them silently replaced by an OUI-00:03:7F synthetic address derived from the SoC serial.

Please make this opt-in (DT property, module parameter, or Kconfig) so other ath12k users retain upstream behavior.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@patch/kernel/archive/sm8550-7.0/0042-drivers-use-soc-serial-for-wifi-and-bluetooth.patch`
around lines 249 - 268, The patch forces a serial-derived MAC for all ath12k
devices by unconditionally calling generate_macaddr_from_serial() in
ath12k_mac_hw_register(), replacing existing pdevs_macaddr_valid /
ar->ab->mac_addr behavior; make this opt-in by adding a runtime flag (prefer a
device-tree boolean like "qcom,use-serial-mac" on the ath12k DT node or a module
parameter) and only call generate_macaddr_from_serial() when that flag is set,
otherwise keep the original logic that checks ar->ab->pdevs_macaddr_valid and
falls back to ar->ab->mac_addr with ar->pdev_idx adjustment; update the
conditional around generate_macaddr_from_serial(), and ensure log messages
(ath12k_info) clearly state when the serial-derived MAC path was chosen (include
the DT/module flag name and the generated MAC), leaving all other code paths and
variables (ar->mac_addr, ath12k_reverse_mac, pdevs_macaddr_valid) unchanged.
patch/kernel/archive/sm8550-7.0/0021-backlight-odin2mini-backlight-Add-support-for-AYN-Od.patch-151-194 (1)

151-194: ⚠️ Potential issue | 🟠 Major

Regulator enable refcount leak on probe error and remove paths.

The regulator_bulk_enable() call at line 99 is not matched by a regulator_bulk_disable() call:

  • On probe error after this point (e.g., regmap init failure at line 108, backlight register failure at line 116), the regulators stay enabled.
  • odin2miniled_remove() (lines 128-133) only updates backlight state; it does not disable the supplies or de-assert the enable GPIO, so the regulator enable refcount grows by one with each removal.

Use devm_regulator_bulk_get_enable() (available in kernel 6.0+) instead of devm_regulator_bulk_get_const() followed by manual regulator_bulk_enable(). This automatically balances enable/disable on devm release and simplifies error handling. Alternatively, add explicit regulator_bulk_disable() calls in both the error path and odin2miniled_remove().

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@patch/kernel/archive/sm8550-7.0/0021-backlight-odin2mini-backlight-Add-support-for-AYN-Od.patch`
around lines 151 - 194, The probe enables regulators with
regulator_bulk_enable(ARRAY_SIZE(miniled_supplies), miniled->supplies) but never
disables them on errors or in odin2miniled_remove(), leaking regulator
refcounts; replace the manual get+enable pattern with
devm_regulator_bulk_get_enable(&client->dev, ARRAY_SIZE(miniled_supplies),
miniled->supplies) (or, if not available, call regulator_bulk_disable(...) on
all error exits after enable and in odin2miniled_remove()) so that the supplies
are properly balanced; update the probe error paths (after regmap init and
backlight registration failures) and odin2miniled_remove() to either rely on
devm_regulator_bulk_get_enable or explicitly call regulator_bulk_disable for
miniled->supplies to release the regulators and deassert the enable GPIO.
patch/kernel/archive/sm8550-7.0/0004-input-Add-driver-for-RSInput-Gamepad.patch-327-361 (1)

327-361: ⚠️ Potential issue | 🟠 Major

Don't call rsinput_init_commands() (which sleeps) from the serdev RX callback.

rsinput_rx() runs on the serdev RX path; on a bad checksum it invokes rsinput_init_commands(drv) which calls msleep(100) twice and serdev_device_write_buf(). Sleeping/blocking from the receive callback can deadlock against the controller's own write/RX completion or simply stall the UART. Either schedule the re-init from a workqueue, or just discard the bad frame and let the next valid one resume processing.

Also note: validating one large checksum across count here is redundant with the per-frame validation already done in rsinput_process_data() (line 298-304). The MCU may legitimately deliver multiple packets per RX chunk; treating a multi-frame buffer as a single CRC region rejects valid data.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@patch/kernel/archive/sm8550-7.0/0004-input-Add-driver-for-RSInput-Gamepad.patch`
around lines 327 - 361, The serdev RX callback rsinput_rx must not call
rsinput_init_commands (which sleeps and writes) or perform a single checksum
across the entire received chunk; instead drop that global checksum logic and
forward the raw buffer to rsinput_process_data so its per-frame validation can
handle multiple packets per RX, and if you still need to trigger a re-init on
persistent errors, queue a work item (work_struct/delayed_work) from rsinput_rx
that calls rsinput_init_commands context-safely; specifically remove the
compute_checksum vs. received_checksum branch in rsinput_rx, stop invoking
rsinput_init_commands there, copy into drv->rx_buf and call
rsinput_process_data(drv, drv->rx_buf, count), and implement a workqueue handler
that calls rsinput_init_commands when scheduled.
patch/kernel/archive/sm8550-7.0/0005-leds-Add-driver-for-HEROIC-HTR3212.patch-184-207 (1)

184-207: ⚠️ Potential issue | 🟠 Major

always-on is read from the parent device, not the LED child node.

htr3212_parse_child_dt() receives child (the per-LED OF node) but Line 203 passes dev (the parent I²C device) to device_property_read_bool("always-on"). The result is the same for every LED registered, so the per-LED always-on semantics implied by the helper name don't actually work — and a parent-level always-on (rare on multi-LED controllers) will silently disable suspend/resume for all children.

🔧 Suggested fix
-	if (!device_property_read_bool(dev, "always-on"))
+	if (!of_property_read_bool(child, "always-on"))
 		cdev->flags |= LED_CORE_SUSPENDRESUME;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@patch/kernel/archive/sm8550-7.0/0005-leds-Add-driver-for-HEROIC-HTR3212.patch`
around lines 184 - 207, htr3212_parse_child_dt currently calls
device_property_read_bool(dev, "always-on") which reads the parent device
instead of the per-LED OF child node, so every LED gets the same always-on
behavior; change that call to of_property_read_bool(child, "always-on") (i.e.,
use the child device_node and of_property_read_bool) to honor per-LED
"always-on" properties and keep the existing logic that sets cdev->flags |=
LED_CORE_SUSPENDRESUME when the per-LED "always-on" is absent.
patch/kernel/archive/sm8550-7.0/0004-input-Add-driver-for-RSInput-Gamepad.patch-248-287 (1)

248-287: ⚠️ Potential issue | 🟠 Major

prev_states should be per-device, not a function-static.

static unsigned long prev_states; (Line 250) is shared across every probed rsinput instance and persists across module load/unload boundaries via BSS. With more than one gamepad attached the second device sees the first device's previous state and emits spurious key changes. Move it into struct rsinput_driver.

🔧 Suggested fix
 struct rsinput_driver {
     struct serdev_device *serdev;
     struct input_dev *input;
     struct gpio_desc *boot_gpio;
     struct gpio_desc *enable_gpio;
     struct gpio_desc *reset_gpio;
     uint8_t rx_buf[256];
     uint8_t sequence_number;
+    unsigned long prev_key_states;
 };
…
-    static unsigned long prev_states;
     unsigned long keys = data[FRAME_POS_DATA_1] | (data[FRAME_POS_DATA_2] << 8);
-    unsigned long current_states = keys, changes;
+    unsigned long current_states = keys, changes;
     int i;

-    bitmap_xor(&changes, &current_states, &prev_states, ARRAY_SIZE(keymap));
+    bitmap_xor(&changes, &current_states, &drv->prev_key_states, ARRAY_SIZE(keymap));-    prev_states = keys;
+    drv->prev_key_states = keys;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@patch/kernel/archive/sm8550-7.0/0004-input-Add-driver-for-RSInput-Gamepad.patch`
around lines 248 - 287, The bug is that prev_states is a function-static shared
across devices; move it into struct rsinput_driver and update handle_cmd_status
to use a per-device bitmap: add a field like unsigned long
prev_states[BITS_TO_LONGS(ARRAY_SIZE(keymap))] to struct rsinput_driver, in
handle_cmd_status allocate local unsigned long arrays for current_states and
changes sized with BITS_TO_LONGS(ARRAY_SIZE(keymap)) (initialize current_states
from the 16/32-bit keys value), call bitmap_xor(changes, current_states,
drv->prev_states, ARRAY_SIZE(keymap)), iterate for_each_set_bit over changes to
report keys, then copy current_states back into drv->prev_states using
bitmap_copy(drv->prev_states, current_states, ARRAY_SIZE(keymap)) instead of the
existing prev_states = keys assignment; keep all other reporting logic
unchanged.
patch/kernel/archive/sm8550-7.0/0019-drm-panel-Add-panel-driver-for-Chipone-ICNA35XX-base.patch-120-140 (1)

120-140: ⚠️ Potential issue | 🟠 Major

prepare() accesses mode from stale atomic state.

icna35xx_get_current_mode() reads from connector->state->crtc->state during prepare(), which runs before the new atomic state is committed. In the DRM atomic modeset path, the new mode is in the new atomic state and not yet swapped into crtc->state. Since both icna3512_init_sequence() and icna3520_init_sequence() depend on this lookup to select vastly different register sequences for 60 Hz vs 120 Hz operation, a stale mode lookup can silently program incorrect panel timings. The fallback return 0 selects the 120 Hz descriptor, which may not match the requested mode.

The proper approach is to use drm_atomic_get_new_crtc_state() to access the committed mode during atomic operations, or migrate to a drm_bridge with atomic callbacks that receive the atomic state. Panel prepare() is not the right place for mode-dependent initialization; mode-aware setup belongs in enable() or bridge atomic hooks, called after the atomic state is finalized.

Applies to both icna3512_init_sequence() and icna3520_init_sequence().

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@patch/kernel/archive/sm8550-7.0/0019-drm-panel-Add-panel-driver-for-Chipone-ICNA35XX-base.patch`
around lines 120 - 140, icna35xx_get_current_mode currently reads
connector->state->crtc->state during prepare(), which can return stale atomic
state; change the lookup to use drm_atomic_get_new_crtc_state(...) against the
incoming atomic state (or otherwise obtain the new crtc_state passed into atomic
callbacks) so the chosen index reflects the pending mode, and move
mode-dependent register selection out of prepare() into enable() or bridge
atomic hooks where the new atomic state is finalized; update callers
icna3512_init_sequence() and icna3520_init_sequence() to call
icna35xx_get_current_mode from those later, atomic-aware contexts rather than
from prepare().
🟡 Minor comments (12)
patch/kernel/archive/sm8550-7.0/0023-Add-Silergy-SY7758-backlight-driver.patch-181-186 (1)

181-186: ⚠️ Potential issue | 🟡 Minor

Minor: remove() does not power down the controller.

sy7758_remove() only forces brightness to 0 via the backlight core; the IC remains enabled (register 0x01 = 0x85 from init). Devm cleanup will release the regmap/backlight, but on devices where the regulator/pins stay live, the controller may sit in its "on" state with brightness clamped to 0. If that is intentional (e.g. handled by DT regulators or pinctrl sleep state from the AYN DTS), feel free to ignore; otherwise consider an explicit shutdown register write here.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@patch/kernel/archive/sm8550-7.0/0023-Add-Silergy-SY7758-backlight-driver.patch`
around lines 181 - 186, sy7758_remove currently only zeros the backlight via
backlight_update_status but doesn't power down the IC; update sy7758_remove to
fetch the driver state (e.g. struct sy7758 *sy = i2c_get_clientdata(client)),
perform a guarded regmap write to the power/control register used in init (write
the shutdown value to register 0x01, e.g. regmap_write(sy->regmap, 0x01, 0x00)),
handle NULL checks for sy and sy->regmap, then set
backlight_dev->props.brightness = 0 and call
backlight_update_status(backlight_dev); ensure the order powers down the chip
before releasing/devm cleanup so the controller isn’t left enabled.
config/sources/families/sm8550.conf-23-27 (1)

23-27: ⚠️ Potential issue | 🟡 Minor

Regenerate or update edge kernel config header to reflect 7.0.

The config/kernel/linux-sm8550-edge.config header still reads # Armbian defconfig generated with 6.18. With KERNEL_MAJOR_MINOR now "7.0" and KERNELBRANCH='branch:linux-7.0.y', regenerate the edge config against 7.0 or refresh the header comment so maintainers can identify which kernel version produced the defconfig. Regeneration will also surface any CONFIG symbols that were dropped or renamed between 6.18 and 7.0.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@config/sources/families/sm8550.conf` around lines 23 - 27, The edge kernel
defconfig header is stale relative to KERNEL_MAJOR_MINOR="7.0" and
KERNELBRANCH='branch:linux-7.0.y'; regenerate the edge defconfig against kernel
7.0 (or at minimum update the header comment) so the top-of-file comment and
CONFIG symbols match the 7.0 build, and ensure any dropped/renamed CONFIG_*
entries are resolved; look for the edge defconfig referenced by the sm8550 edge
profile and update the header and contents to reflect kernel 7.0 accordingly.
patch/kernel/archive/sm8550-7.0/0038-arm64-dts-qcom-Add-AYN-Odin2-Mini.patch-46-57 (1)

46-57: ⚠️ Potential issue | 🟡 Minor

hdmi-pwr-supply is not part of the hdmi-connector binding.

The hdmi-connector binding only specifies label, type, hpd-gpios, ddc-i2c-bus, cec-* and the standard port graph. hdmi-pwr-supply will be silently ignored by the connector driver (and trigger a dt_binding_check warning). Since vdd_hdmi_1v8 is already pulled in via the LT8912 bridge's vdd-supply reference, this property is redundant.

 	hdmi-out {
 		compatible = "hdmi-connector";
 		type = "d";
 		hpd-gpios = <&tlmm 9 GPIO_ACTIVE_HIGH>;
-		hdmi-pwr-supply = <&vdd_hdmi_1v8>;

 		port {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@patch/kernel/archive/sm8550-7.0/0038-arm64-dts-qcom-Add-AYN-Odin2-Mini.patch`
around lines 46 - 57, The hdmi-out node uses the "hdmi-connector" binding which
doesn't include hdmi-pwr-supply, so remove the hdmi-pwr-supply =
<&vdd_hdmi_1v8>; line from the hdmi-out node (the hdmi-out node and its
port/hdmi_con: endpoint remain unchanged); rely on the LT8912 bridge's existing
vdd-supply reference (lt8912_out / LT8912 bridge) which already pulls in
vdd_hdmi_1v8 to avoid the dt_binding_check warning and redundant property.
patch/kernel/archive/sm8550-7.0/0014-Input-edt-ft5x06-add-no_regmap_bulk_read-option.patch-39-48 (1)

39-48: ⚠️ Potential issue | 🟡 Minor

Minor: avoid sleeping on the final retry; consider backoff for unrecognized errors.

Two small inefficiencies in the retry loop:

  • On the 3rd failing attempt with -ETIMEDOUT/-EAGAIN, the function still calls usleep_range(2000, 4000) and then immediately exits via the tries == 3 check. The sleep adds latency to the error return path with no benefit.
  • For any other error code, the loop spins three times without delay, which can hammer the bus on persistent faults.
♻️ Suggested tighter retry logic
 		for (tries = 0; tries < 3; tries++) {
 			ret = regmap_read(map, start + off, &v);
 			if (!ret) {
 				dst[off] = (u8)v;
 				break;
 			}
-			if (ret == -ETIMEDOUT || ret == -EAGAIN)
-				usleep_range(2000, 4000);
+			if (tries < 2 &&
+			    (ret == -ETIMEDOUT || ret == -EAGAIN))
+				usleep_range(2000, 4000);
 		}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@patch/kernel/archive/sm8550-7.0/0014-Input-edt-ft5x06-add-no_regmap_bulk_read-option.patch`
around lines 39 - 48, The retry loop calling regmap_read should avoid sleeping
after the final attempt and should back off on non-retry-specific errors instead
of busy-spinning; modify the block around regmap_read so that usleep_range(2000,
4000) is only invoked when tries < 2 (i.e. not after the last retry) and add a
small sleep/backoff (e.g. usleep_range with a smaller delay or exponential
backoff based on tries) for unexpected ret values before retrying; adjust the
logic that currently checks ret == -ETIMEDOUT || ret == -EAGAIN to only decide
sleep timing, and ensure the loop still fills dst[off] and breaks on success as
it does now (refer to regmap_read, usleep_range, tries, ret, start, off, dst).
patch/kernel/archive/sm8550-7.0/0037-arm64-dts-qcom-Add-AYN-Odin2.patch-234-267 (1)

234-267: ⚠️ Potential issue | 🟡 Minor

RMI4 touchscreen node is missing vdd-supply.

The RMI4 I2C transport driver requests two regulators via devm_regulator_bulk_get(): "vdd" and "vio". The Odin2 node only declares vio-supply = <&vreg_l12b_1p8>. Without vdd-supply, the driver cannot manage the VDD rail and the touchscreen may fail during suspend/resume or cold-boot probing if the rail is not latched on from the bootloader. Wire the actual VDD rail (e.g., another vreg_* regulator that feeds the controller) so the kernel can manage it explicitly.

Also on this hunk:

  • Line 247 has trailing whitespace.
  • Line 285 has reg = <0x48> ; (stray space before ;).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@patch/kernel/archive/sm8550-7.0/0037-arm64-dts-qcom-Add-AYN-Odin2.patch`
around lines 234 - 267, The touchscreen@20 RMI4 node only declares vio-supply
but the rmi4 driver also needs vdd-supply; add a vdd-supply property to
touchscreen@20 (pointing to the board's actual VDD regulator phandle, e.g.
replace &vreg_l12b_1p8 or add &vreg_<vdd_regulator_name> as appropriate) so the
driver can manage VDD, and keep the existing vio-supply; also remove the
trailing whitespace on the pinctrl line (after vio-supply) and fix the stray
space before the semicolon in the reg assignment (the "reg = <0x48> ;"
occurrence) so formatting is clean.
patch/kernel/archive/sm8550-7.0/0042-drivers-use-soc-serial-for-wifi-and-bluetooth.patch-22-25 (1)

22-25: ⚠️ Potential issue | 🟡 Minor

Dead code: static_bdaddr / static_macaddr are declared but never referenced.

static const bdaddr_t static_bdaddr (btqca lines 22-25) and static const struct macaddr_t static_macaddr (ath12k lines 161-163) are defined but never used anywhere in the patch. Either wire them up as a fallback when the serial-based generation fails, or drop them.

Also applies to: 161-163

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@patch/kernel/archive/sm8550-7.0/0042-drivers-use-soc-serial-for-wifi-and-bluetooth.patch`
around lines 22 - 25, The patch introduces unused constants static_bdaddr and
static_macaddr; either remove these dead declarations or wire them as fallbacks:
update the serial-based address generation code (e.g., the function(s) that call
into the serial/EFUSE path for Bluetooth and Wi-Fi address generation) to detect
failure and return the static_bdaddr or static_macaddr values as the fallback
BD_ADDR/MAC, or simply delete the static const bdaddr_t static_bdaddr and static
const struct macaddr_t static_macaddr definitions to eliminate dead code;
reference the exact symbols static_bdaddr and static_macaddr when making the
change.
patch/kernel/archive/sm8550-7.0/0042-drivers-use-soc-serial-for-wifi-and-bluetooth.patch-99-100 (1)

99-100: ⚠️ Potential issue | 🟡 Minor

Commented-out qca_check_bdaddr() and __maybe_unused mark left dead code in tree.

Lines 138-141 contain the original qca_check_bdaddr() flow as //-commented code, and the function is now annotated __maybe_unused (line 100) because it has no remaining callers. This leaves a permanently dead function plus dead commented logic in btqca.c.

If the new serial-derived BD_ADDR path is the intended permanent behavior, please remove qca_check_bdaddr() and the commented call entirely. If it's meant to be a fallback (e.g., when the serial number is unavailable or invalid), wire it up explicitly so both paths remain exercised and reviewable.

Also applies to: 138-142

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@patch/kernel/archive/sm8550-7.0/0042-drivers-use-soc-serial-for-wifi-and-bluetooth.patch`
around lines 99 - 100, The qca_check_bdaddr() function is now unused (marked
__maybe_unused) and the original call-flow is left commented out in btqca.c
(around the commented lines previously 138-142), leaving dead code; either
remove the qca_check_bdaddr() definition and the commented call-site entirely if
the serial-derived BD_ADDR path is intended as the permanent behavior, or
restore and wire the original check as an explicit fallback by removing the
__maybe_unused annotation and reintroducing a clear branch that calls
qca_check_bdaddr(hdev, config) when the serial-derived BD_ADDR is
missing/invalid so both paths are compiled and exercised (update any callers in
btqca.c accordingly and delete stale comment blocks).
patch/kernel/archive/sm8550-7.0/0010-gpu-panel-add-Pocket-ACE-panel-driver.patch-51-54 (1)

51-54: ⚠️ Potential issue | 🟡 Minor

Address FIXME placeholders before merge.

  • Line 52: // Copyright (c) 2025 FIXME
  • Line 54: // Copyright (c) 2013, The Linux Foundation. All rights reserved. (FIXME)
  • Line 283: MODULE_AUTHOR("linux-mdss-dsi-panel-driver-generator <fix@me>"); // FIXME

These leftover generator placeholders should be replaced with real copyright/author attribution.

Also applies to: 283-283

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@patch/kernel/archive/sm8550-7.0/0010-gpu-panel-add-Pocket-ACE-panel-driver.patch`
around lines 51 - 54, Replace the generator placeholders left in header comments
and the MODULE_AUTHOR string: update the comment lines containing "Copyright (c)
2025 FIXME" and the vendor-tree copyright comment with the correct copyright
holder(s) and year(s), and change
MODULE_AUTHOR("linux-mdss-dsi-panel-driver-generator <fix@me>"); to a real
author name and contact (or the vendor/maintainer) so no FIXME/fix@me
placeholders remain; locate the occurrences by searching for the top-of-patch
header comments and the MODULE_AUTHOR(...) symbol and substitute the real
attribution text.
patch/kernel/archive/sm8550-7.0/0039-arm64-dts-qcom-Add-AYN-Odin2-Portal.patch-143-213 (1)

143-213: ⚠️ Potential issue | 🟡 Minor

LED node names contradict their color attributes, causing phandle references to point to unexpected colors.

The pattern is systematic across all 12 LEDs on each controller:

  • ledl_b1 has color = LED_COLOR_ID_RED (node name says blue, but actually red)
  • ledl_g1 has color = LED_COLOR_ID_GREEN (matches)
  • ledl_r1 has color = LED_COLOR_ID_BLUE (node name says red, but actually blue)

The same pattern repeats for ledl_b2-b4, ledl_g2-g4, ledl_r2-r4 and all right-side LEDs (ledr_*).

This causes multi-ledX nodes (lines 68-122) to wire up LEDs in BGR order instead of RGB when they reference phandles like &ledr_r4 (which actually points to a BLUE LED due to the name/color mismatch).

Confirm this reflects intentional hardware-specific channel mapping, or rename the LED nodes to match their actual colors to avoid future confusion.

Minor: Line 276 has a stray space before the tab indentation.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@patch/kernel/archive/sm8550-7.0/0039-arm64-dts-qcom-Add-AYN-Odin2-Portal.patch`
around lines 143 - 213, The LED node names (ledl_b1..ledl_r4 and ledr_*) do not
match their color properties (e.g., ledl_b1 has color = LED_COLOR_ID_RED,
ledl_r1 has LED_COLOR_ID_BLUE) causing phandles used by the multi-led nodes
(multi-ledX) to map BGR instead of RGB; fix by either renaming the LED nodes to
reflect their actual color (e.g., rename ledl_b1 -> ledl_r1) or by swapping the
color properties to match the node names for each node in the &i2c0 htr3212l
block (nodes ledl_b1..ledl_r4 and corresponding ledr_* if present), and also
remove the stray space before the tab indentation near the multi-led definitions
to normalize formatting.
patch/kernel/archive/sm8550-7.0/0004-input-Add-driver-for-RSInput-Gamepad.patch-54-54 (1)

54-54: ⚠️ Potential issue | 🟡 Minor

Drop the global #define DEBUG.

Forcing DEBUG from a driver source is a debug artifact — it floods the log with dev_dbg from this and any header that conditionally enables debug. The follow-up patch 0025-input-RSInput-Add-regulator.patch already removes it, so consider folding the removal into this patch to avoid landing it in a release.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@patch/kernel/archive/sm8550-7.0/0004-input-Add-driver-for-RSInput-Gamepad.patch`
at line 54, Remove the global "#define DEBUG" from this patch (it forces dev_dbg
logging across the tree); instead leave DEBUG undefined here and fold its
removal into this patch so the follow-up
"0025-input-RSInput-Add-regulator.patch" change is not required; locate the
`#define DEBUG` line in the patch/diff and delete it so driver headers and other
sources aren’t forced into debug logging.
patch/kernel/archive/sm8550-7.0/0036-arm64-dts-qcom-Add-AYN-QCS8550-Common.patch-1397-1410 (1)

1397-1410: ⚠️ Potential issue | 🟡 Minor

Inconsistent label vs. node name for the primary DSI TE suspend state.

The label is dsi_p_te_suspend (primary) but the node name is dsi-s-te-suspend-state (secondary). The other three TE/PRESENT states are consistent (dsi_p_te_active: dsi-p-te-active-state, dsi_s_te_active: dsi-s-te-active-state, dsi_s_te_suspend: dsi-s-te-suspend-state), so this looks like a copy-paste typo. Two pinctrl entries currently share the name dsi-s-te-suspend-state, which is also a DTC duplicate-name concern.

🔧 Suggested fix
-	dsi_p_te_suspend: dsi-s-te-suspend-state {
+	dsi_p_te_suspend: dsi-p-te-suspend-state {
 		pins = "gpio86";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@patch/kernel/archive/sm8550-7.0/0036-arm64-dts-qcom-Add-AYN-QCS8550-Common.patch`
around lines 1397 - 1410, Label/node mismatch: the primary DSI TE suspend
pinctrl uses label dsi_p_te_suspend but the node is incorrectly named
dsi-s-te-suspend-state; rename the node to dsi-p-te-suspend-state to match the
label and the naming pattern used by dsi_p_te_active, and ensure no other
pinctrl node reuses the same node name to avoid DTC duplicate-name conflicts
(verify the nodes dsi_p_te_active, dsi_s_te_active, dsi_s_te_suspend for
consistency).
patch/kernel/archive/sm8550-7.0/0036-arm64-dts-qcom-Add-AYN-QCS8550-Common.patch-613-614 (1)

613-614: ⚠️ Potential issue | 🟡 Minor

Indentation: mixed spaces inside wcn7850-pmu.

bt-enable-gpios = ... (line 614) is indented with spaces while the rest of this node uses tabs. Just a cosmetic nit but inconsistent with the surrounding file style.

🔧 Suggested fix
 		wlan-enable-gpios = <&tlmm 80 GPIO_ACTIVE_HIGH>;
-        bt-enable-gpios = <&tlmm 81 GPIO_ACTIVE_HIGH>;
+		bt-enable-gpios = <&tlmm 81 GPIO_ACTIVE_HIGH>;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@patch/kernel/archive/sm8550-7.0/0036-arm64-dts-qcom-Add-AYN-QCS8550-Common.patch`
around lines 613 - 614, In the wcn7850-pmu device tree node the property lines
use mixed indentation: change the leading spaces on the bt-enable-gpios line so
it uses a tab like the surrounding lines (make the indentation consistent with
wlan-enable-gpios and other entries in the wcn7850-pmu node); locate the lines
declaring wlan-enable-gpios and bt-enable-gpios and replace the space
indentation of bt-enable-gpios with a tab to match file style.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8a71b2b0-8978-41cb-b933-2879b4cbee53

📥 Commits

Reviewing files that changed from the base of the PR and between 39fdcef and be4183d.

📒 Files selected for processing (45)
  • config/sources/families/sm8550.conf
  • patch/kernel/archive/sm8550-7.0/0001-msm-adreno-enable-A32.patch
  • patch/kernel/archive/sm8550-7.0/0002-qcom-dispcc-sm8550-Fix-disp_cc_mdss_mdp_clk_src.patch
  • patch/kernel/archive/sm8550-7.0/0003-input-rmi4-add-reset-gpio.patch
  • patch/kernel/archive/sm8550-7.0/0004-input-Add-driver-for-RSInput-Gamepad.patch
  • patch/kernel/archive/sm8550-7.0/0005-leds-Add-driver-for-HEROIC-HTR3212.patch
  • patch/kernel/archive/sm8550-7.0/0006-ASoC-qcom-sc8280xp-Add-support-for-Primary-I2S.patch
  • patch/kernel/archive/sm8550-7.0/0007-mmc-sdhci-msm-Toggle-the-FIFO-write-clock-after-unga.patch
  • patch/kernel/archive/sm8550-7.0/0008-ASoC-codecs-aw88166-AYN-SM8550-Specific-modification.patch
  • patch/kernel/archive/sm8550-7.0/0009-arm64-dts-qcom-Added-pmk8550_pwm.patch
  • patch/kernel/archive/sm8550-7.0/0010-gpu-panel-add-Pocket-ACE-panel-driver.patch
  • patch/kernel/archive/sm8550-7.0/0012-input-touchscreen-porting-downstream-hynitron-driver.patch
  • patch/kernel/archive/sm8550-7.0/0013-qcom_battmgr-Set-battery-name.patch
  • patch/kernel/archive/sm8550-7.0/0014-Input-edt-ft5x06-add-no_regmap_bulk_read-option.patch
  • patch/kernel/archive/sm8550-7.0/0016-pwm-Add-SI-EN-SN3112-PWM-support.patch
  • patch/kernel/archive/sm8550-7.0/0017-drm-panel-Add-WIP-panel-driver-for-AYN-Odin-2.patch
  • patch/kernel/archive/sm8550-7.0/0018-drm-panel-Add-panel-driver-for-Xm-Plus-XM91080G-base.patch
  • patch/kernel/archive/sm8550-7.0/0019-drm-panel-Add-panel-driver-for-Chipone-ICNA35XX-base.patch
  • patch/kernel/archive/sm8550-7.0/0020-drm-panel-Add-panel-driver-for-DDIC-CH13726A-based-p.patch
  • patch/kernel/archive/sm8550-7.0/0021-backlight-odin2mini-backlight-Add-support-for-AYN-Od.patch
  • patch/kernel/archive/sm8550-7.0/0022-Input-hynitron_cstxxx-specific-patch-for-Odin2-Mini.patch
  • patch/kernel/archive/sm8550-7.0/0023-Add-Silergy-SY7758-backlight-driver.patch
  • patch/kernel/archive/sm8550-7.0/0024-regulator-add-sgm3804-i2c-regulator-for-panel-power-.patch
  • patch/kernel/archive/sm8550-7.0/0025-input-RSInput-Add-regulator.patch
  • patch/kernel/archive/sm8550-7.0/0026-drm-msm-remove-DRIVER_SYNCOBJ_TIMELINE.patch
  • patch/kernel/archive/sm8550-7.0/0027-HACK-fix-usb-boot-hang.patch
  • patch/kernel/archive/sm8550-7.0/0028-SM8550-Fix-L2-cache-for-CPU2-and-add-cache-sizes.patch
  • patch/kernel/archive/sm8550-7.0/0029-SM8550-Add-DDR-LLCC-L3-CPU-bandwidth-scaling.patch
  • patch/kernel/archive/sm8550-7.0/0030-arm64-dts-qcom-sm8550-Update-EAS-properties.patch
  • patch/kernel/archive/sm8550-7.0/0031-arm64-dts-qcom-sm8550-add-UART15.patch
  • patch/kernel/archive/sm8550-7.0/0032-drm-panel-Add-Retroid-Pocket-6-panel.patch
  • patch/kernel/archive/sm8550-7.0/0033-arm64-dts-qcom-sm8550-Describe-GPU_CC-power-plumbing.patch
  • patch/kernel/archive/sm8550-7.0/0034-interconnect-qcom-sm8550-Enable-QoS-configuration.patch
  • patch/kernel/archive/sm8550-7.0/0035-dts-qcom-sm8550-add-opp-acd-level.patch
  • patch/kernel/archive/sm8550-7.0/0036-arm64-dts-qcom-Add-AYN-QCS8550-Common.patch
  • patch/kernel/archive/sm8550-7.0/0037-arm64-dts-qcom-Add-AYN-Odin2.patch
  • patch/kernel/archive/sm8550-7.0/0038-arm64-dts-qcom-Add-AYN-Odin2-Mini.patch
  • patch/kernel/archive/sm8550-7.0/0039-arm64-dts-qcom-Add-AYN-Odin2-Portal.patch
  • patch/kernel/archive/sm8550-7.0/0040-arm64-dts-qcom-Add-AYN-Thor.patch
  • patch/kernel/archive/sm8550-7.0/0041-ROCKNIX-set-boot-fanspeed.patch
  • patch/kernel/archive/sm8550-7.0/0042-drivers-use-soc-serial-for-wifi-and-bluetooth.patch
  • patch/kernel/archive/sm8550-7.0/0043-power-supply-rename-qcom-battmgr-sysfs.patch
  • patch/kernel/archive/sm8550-7.0/0044-Enable-64-bit-processes-to-use-compat-input-syscalls.patch
  • patch/kernel/archive/sm8550-7.0/v2_20260314_vladimir_zapolskiy_arm64_dts_qcom_sm8x50_enable_uhs_i_sdr50_and_sdr104_sd_card_modes.patch
  • patch/kernel/archive/sm8550-7.0/v5_20251120_quic_utiwari_crypto_qce_add_runtime_pm_and_interconnect_bandwidth_scaling_support.patch

Comment on lines +416 to +474
+ error = serdev_device_open(serdev);
+ if (error)
+ return dev_err_probe(&serdev->dev, error, "Unable to open UART device\n");
+
+ drv->serdev = serdev;
+ drv->sequence_number = 0;
+
+ serdev_device_set_drvdata(serdev, drv);
+
+ error = serdev_device_set_baudrate(serdev, 115200);
+ if (error < 0)
+ return dev_err_probe(&serdev->dev, error, "Failed to set up host baud rate\n");
+
+ serdev_device_set_flow_control(serdev, false);
+
+ drv->input = devm_input_allocate_device(&serdev->dev);
+ if (!drv->input)
+ return -ENOMEM;
+
+ drv->input->phys = "rsinput-gamepad/input0";
+
+ error = device_property_read_string(&serdev->dev, "gamepad-name", &drv->input->name);
+ if (error) {
+ drv->input->name = "RSInput Gamepad";
+ }
+
+ device_property_read_u32(&serdev->dev, "gamepad-bus", &gamepad_bus);
+ device_property_read_u32(&serdev->dev, "gamepad-vid", &gamepad_vid);
+ device_property_read_u32(&serdev->dev, "gamepad-pid", &gamepad_pid);
+ device_property_read_u32(&serdev->dev, "gamepad-rev", &gamepad_rev);
+
+ drv->input->id.bustype = (u16)gamepad_bus;
+ drv->input->id.vendor = (u16)gamepad_vid;
+ drv->input->id.product = (u16)gamepad_pid;
+ drv->input->id.version = (u16)gamepad_rev;
+
+ __set_bit(EV_KEY, drv->input->evbit);
+ for (int i = 0; i < ARRAY_SIZE(keymap); i++)
+ input_set_capability(drv->input, EV_KEY, keymap[i]);
+
+ __set_bit(EV_ABS, drv->input->evbit);
+ for (int i = ABS_X; i <= ABS_RZ; i++)
+ input_set_abs_params(drv->input, i, -0x580, 0x580,
+ 0, 0);
+
+ input_set_abs_params(drv->input, ABS_Z, 0, 1830, 0, 30);
+ input_set_abs_params(drv->input, ABS_RZ, 0, 1830, 0, 30);
+
+ error = input_register_device(drv->input);
+ if (error)
+ return error;
+
+ serdev_device_set_client_ops(serdev, &rsinput_rx_ops);
+
+ error = rsinput_init_commands(drv);
+ if (error < 0) {
+ serdev_device_close(serdev);
+ return error;
+ }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Probe ordering and error-path leaks around serdev_device_open().

Two related defects:

  1. serdev_device_open() is called before serdev_device_set_client_ops() (line 468), so any bytes the MCU pushes during this window have no receive_buf registered yet (and drv is set with serdev_device_set_drvdata only afterwards on line 423). RX is silently dropped, and the serdev_device_set_baudrate(115200) on line 425 also runs before client ops are set.
  2. Once serdev_device_open() succeeds (line 416), every subsequent error return must close the device. As written, serdev_device_set_baudrate failure (line 427), devm_input_allocate_device returning NULL (line 433), and input_register_device failing (line 466) all return without serdev_device_close(), leaking the open serdev.
🔧 Recommended ordering / cleanup
+	drv->serdev = serdev;
+	drv->sequence_number = 0;
+	serdev_device_set_drvdata(serdev, drv);
+	serdev_device_set_client_ops(serdev, &rsinput_rx_ops);
+
 	error = serdev_device_open(serdev);
 	if (error)
 		return dev_err_probe(&serdev->dev, error, "Unable to open UART device\n");
 
-	drv->serdev = serdev;
-	drv->sequence_number = 0;
-	
-	serdev_device_set_drvdata(serdev, drv);
-
 	error = serdev_device_set_baudrate(serdev, 115200);
-	if (error < 0)
-		return dev_err_probe(&serdev->dev, error, "Failed to set up host baud rate\n");
+	if (error < 0) {
+		serdev_device_close(serdev);
+		return dev_err_probe(&serdev->dev, error, "Failed to set up host baud rate\n");
+	}

 	serdev_device_set_flow_control(serdev, false);

 	drv->input = devm_input_allocate_device(&serdev->dev);
-	if (!drv->input)
-		return -ENOMEM;
+	if (!drv->input) {
+		serdev_device_close(serdev);
+		return -ENOMEM;
+	}
…
 	error = input_register_device(drv->input);
-	if (error)
-		return error;
-
-	serdev_device_set_client_ops(serdev, &rsinput_rx_ops);
+	if (error) {
+		serdev_device_close(serdev);
+		return error;
+	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@patch/kernel/archive/sm8550-7.0/0004-input-Add-driver-for-RSInput-Gamepad.patch`
around lines 416 - 474, The serdev client ops and driver data are being set
after serdev_device_open(), which allows RX to be dropped, and multiple error
returns after a successful serdev_device_open() leak the open device; move
serdev_device_set_client_ops(serdev, &rsinput_rx_ops) and
serdev_device_set_drvdata(serdev, drv) so they are set before calling
serdev_device_open(), or alternatively call serdev_device_open() only after
those are set, and ensure every path that returns after serdev_device_open()
succeeds (e.g., failures in serdev_device_set_baudrate,
devm_input_allocate_device, input_register_device, rsinput_init_commands) calls
serdev_device_close(serdev) to clean up the opened device.

Comment on lines +288 to +303
+ priv->sdb = devm_gpiod_get(dev, "sdb", GPIOD_OUT_HIGH);
+ if (PTR_ERR(priv->sdb) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ priv->vdd = devm_regulator_get(dev, "vdd");
+ if (IS_ERR(priv->vdd)) {
+ ret = PTR_ERR(priv->vdd);
+ return ret;
+ }
+
+ ret = regulator_enable(priv->vdd);
+ if (ret < 0) {
+ return ret;
+ }
+
+ gpiod_set_value_cansleep(priv->sdb, 1);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

SDB GPIO acquisition leaks ERR_PTR for non--EPROBE_DEFER failures, then dereferences it.

devm_gpiod_get(dev, "sdb", GPIOD_OUT_HIGH) returns an ERR_PTR on any failure; the code only handles -EPROBE_DEFER. For any other error (e.g. -ENOENT if not described in DT, -EBUSY, etc.) priv->sdb stays as the error pointer, the function continues into regulator_enable() and then on Line 303 calls gpiod_set_value_cansleep(priv->sdb, 1), which dereferences a non-NULL invalid pointer → kernel oops at probe time. The same pointer is later used in htr3212_remove() (Line 338).

Either treat sdb as truly required (handle all errors) or as optional (devm_gpiod_get_optional).

🔧 Suggested fix (treat sdb as optional, like the SN3112 driver does)
-	priv->sdb = devm_gpiod_get(dev, "sdb", GPIOD_OUT_HIGH);
-	if (PTR_ERR(priv->sdb) == -EPROBE_DEFER)
-		return -EPROBE_DEFER;
+	priv->sdb = devm_gpiod_get_optional(dev, "sdb", GPIOD_OUT_HIGH);
+	if (IS_ERR(priv->sdb))
+		return dev_err_probe(dev, PTR_ERR(priv->sdb),
+				     "failed to get sdb GPIO\n");

…and guard the gpiod_set_value_cansleep() calls with if (priv->sdb) in both probe and remove.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@patch/kernel/archive/sm8550-7.0/0005-leds-Add-driver-for-HEROIC-HTR3212.patch`
around lines 288 - 303, priv->sdb is left as an ERR_PTR when devm_gpiod_get(dev,
"sdb", GPIOD_OUT_HIGH) fails with errors other than -EPROBE_DEFER, then later
dereferenced by gpiod_set_value_cansleep and in htr3212_remove, causing an oops;
fix by acquiring the GPIO optionally (use devm_gpiod_get_optional or check
IS_ERR and return non-zero immediately) and then guard all uses of priv->sdb
(the gpiod_set_value_cansleep() call in probe and any accesses in
htr3212_remove()) with if (priv->sdb) so you never dereference an ERR_PTR.

Comment on lines +80 to +91
+struct sn3112 {
+ struct device *pdev;
+ struct regmap *regmap;
+ struct mutex lock;
+ struct regulator *vdd;
+ uint8_t pwm_val[SN3112_CHANNELS];
+ uint8_t pwm_en_reg[3];
+ bool pwm_en[SN3112_CHANNELS];
+#if IS_ENABLED(CONFIG_GPIOLIB)
+ struct gpio_desc *sdb;
+#endif
+};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

Linux kernel set_bit clear_bit alignment requirements unsigned long

💡 Result:

Top web search findings:

  1. include/linux/bitops.h at master · torvalds/linux: /* * Many architecture-specific non-atomic bitops contain inline asm code and due * to that the compiler can't optimize them to compile-time expressions or * constants. In contrary, generic_() helpers are defined in pure C and * compilers optimize them just well. * Therefore, to make unsigned long foo = 0; __set_bit(BAR, &foo) effectively * equal to unsigned long foo = BIT(BAR), pick the generic C alternative when * the arguments can be resolved at compile time. That expression itself is a * constant and doesn't bring any functional changes to the rest of cases. * The casts to uintptr_t are needed to mitigate -Waddress warnings when * passing a bitmap from .bss or .data (-> !!addr is always true). / #define bitop(op, nr, addr) \ ((__builtin_constant_p(nr) && \ __builtin_constant_p((uintptr_t)(addr) != (uintptr_t)NULL) && \ (uintptr_t)(addr) != (uintptr_t)NULL && \ __builtin_constant_p((const unsigned long )(addr))) ? \ const##op(nr, addr) : op(nr, addr)) [...] / * The following macros are non-atomic versions of their non-underscored * counterparts. / #define __set_bit(nr, addr) bitop(___set_bit, nr, addr) #define __clear_bit(nr, addr) bitop(___clear_bit, nr, addr) #define __change_bit(nr, addr) bitop(___change_bit, nr, addr) #define __test_and_set_bit(nr, addr) bitop(___test_and_set_bit, nr, addr) #define __test_and_clear_bit(nr, addr) bitop(___test_and_clear_bit, nr, addr) #define __test_and_change_bit(nr, addr) bitop(___test_and_change_bit, nr, addr) [...] __check_bitop_pr(__set_bit); __check_bitop_pr(__clear_bit); __check_bitop_pr(__change_bit); __check_bitop_pr(__test_and_set_bit); __check_bitop_pr(__test_and_clear_bit); __check_bitop_pr(__test_and_change_bit); __check_bitop_pr(test_bit); __ [...] bitop_pr(test_bit_acquire); [...] /* * assign_bit - Assign value to a bit in memory * @nr: the bit to set * @addr: the address to start counting from * @value: the value to assign / #define assign_bit(nr, addr, value) \ ((value) ? set_bit((nr), (addr)) : clear_bit((nr), (addr))) #define __assign_bit(nr, addr, value) \ ((value) ? __set_bit((nr), (addr)) : __clear_bit((nr), (addr))) [...] /* * ptr_set_bit - Set bit in a pointer's value * @nr: the bit to set * @addr: the address of the pointer variable * * Example: * void p = foo(); * ptr_set_bit(bit, &p); / #define __ptr_set_bit(nr, addr) \ ({ \ typecheck_pointer((addr)); \ set_bit(nr, (unsigned long )(addr)); \ }) [...] ifndef set_mask_bits [...] #define set_mask_bits(ptr, mask, bits) \ ({ \ const typeof((ptr)) mask = (mask), bits = (bits); \ typeof((ptr)) old, new__; \ \ old__ = READ_ONCE((ptr)); \ do { \ new__ = (old__ & ~mask__) | bits__; \ } while (!try_cmpxchg(ptr, &old__, new__)); \ \ old__; \ }) #endif
  2. arch/x86/include/asm/bitops.h at 16f73eb02d7e1765ccab3d2018e0bd98eb93d973 · torvalds/linux: /** * set_bit - Atomically set a bit in memory * @nr: the bit to set * @addr: the address to start counting from * * This function is atomic and may not be reordered. See __set_bit() * if you do not require the atomic guarantees. * * Note: there are no guarantees that this function will not be reordered * on non x86 architectures, so if you are writing portable code, * make sure not to rely on its reordering guarantees. * * Note that @nr may be almost arbitrarily large; this function is not * restricted to acting on a single-word quantity. / static __always_inline void set_bit(long nr, volatile unsigned long addr) { if (IS_IMMEDIATE(nr)) { asm volatile(LOCK_PREFIX "orb %1,%0" : CONST_MASK_ADDR(nr, addr) : "iq" ((u8)CONST_MASK(nr)) : "memory"); } else { asm volatile(LOCK_PREFIX "bts %1,%0" : BITOP_ADDR(addr) : "Ir" (nr) : "memory"); } } [...] / * __set_bit - Set a bit in memory * @nr: the bit to set * @addr: the address to start counting from * * Unlike set_bit(), this function is non-atomic and may be reordered. * If it's called on the same region of memory simultaneously, the effect * may be that only one operation succeeds. / static __always_inline void __set_bit(long nr, volatile unsigned long addr) { asm volatile("bts %1,%0" : ADDR : "Ir" (nr) : "memory"); } [...] / * test_and_set_bit - Set a bit and return its old value * @nr: Bit to set * @addr: Address to count from * * This operation is atomic and cannot be reordered. * It also implies a memory barrier. / static __always_inline bool test_and_set_bit(long nr, volatile unsigned long addr) { GEN_BINARY_RMWcc(LOCK_PREFIX "bts", addr, "Ir", nr, "%0", c [...] / * [...] test_and_set_bit - Set a bit and return its old value * @nr: Bit to set * @addr: Address to count from * * This operation is non-atomic and can be reordered. * If two examples of this operation race, one can appear to succeed * but [...] fail. You must protect multiple accesses with a lock [...] / static [...] bit(long nr, volatile unsigned [...] t" [...] ) [...] ) (old [...] ), ADDR : "Ir" (nr [...] / * ffs - find first set bit in word * @x: the word to search * * This is defined the same way as the libc and compiler builtin ffs * routines, therefore differs in spirit from [...] other bitops. * * ffs(value) returns 0 if value is 0 or the position of the first * set bit if value is nonzero. The first (least significant) bit * is at position 1. / static __always_inline int ffs( [...] /* * fls - find [...] set bit in word * @x: the word to search * * This is defined in a similar way as the libc and compiler builtin * ffs, but returns the position of the most significant set bit. * * fls(value) [...] 0 if value is [...] 0 or the position of the last * set bit if value is nonzero. The [...] (most significant) bit is * at position 32 [...] / static _always [...] int fls( [...] /* * fls64 - find last set bit in a 64-bit word * @x: the word to search * * This is defined in a similar way as the libc and compiler builtin * ffsll, but returns the position of the most significant set bit. * * fls64(value) returns 0 if value is 0 or the position of the last * set bit if value is nonzero. The last (most significant) bit is * at position 64. / #ifdef CONFIG_X86_64 [...] int fls64(__u64 x) [...] int [...] pos = -1; / * AMD [...] 4 says BSRQ won [...] t clobber [...] dest reg if x==0; Intel [...] 4 says the * dest reg is undefined if x==0, but their CPU architect says its * [...] is written to [...] it to the same as before [...] */ asm("bsrq %1,%q0" [...] )
  3. include/linux/bitops.h - kernel/common - Git at Google: | /* SPDX-License-Identifier: GPL-2.0 / | | --- | | #ifndef _LINUX_BITOPS_H | | #define _LINUX_BITOPS_H | | #include | | #include | | / Set bits in the first 'n' bytes when loaded from memory / | | #ifdef __LITTLE_ENDIAN | | # define aligned_byte_mask(n) ((1UL << 8(n))-1) | | #else | | # define aligned_byte_mask(n) (~0xffUL << (BITS_PER_LONG - 8 - 8*(n))) | | #endif | | #define BITS_PER_TYPE(type) (sizeof(type) * BITS_PER_BYTE) | | #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_TYPE(long)) | | #define BITS_TO_BYTES(nr) DIV_ROUND_UP(nr, BITS_PER_TYPE(char)) | [...] | extern unsigned int sw_hweight8(unsigned int w); | [...] | extern unsigned int sw_hweight16(unsigned int w); | [...] | extern unsigned int sw_hweight32(unsigned int w); | | extern unsigned long sw_hweight64(u64 w); | [...] /* | [...] here because some architectures need generic_ffs/fls in | | * scope | | / [...] | #define for_each_set_bit(bit, addr, size) \ | | for ((bit) = find_first_bit((addr), (size)); \ | | (bit) < (size); \ | | (bit) = find_next_bit((addr), (size), (bit) + 1)) | | / same as for_each_set_bit() but use bit as value to start with / | | #define for_each_set_bit_from(bit, addr, size) \ | | for ((bit) = find_next_bit((addr), (size), (bit)); \ | | (bit) < (size); \ | | (bit) = find_next_bit((addr), (size), (bit) + 1)) | [...] fls( [...] / We could be slightly more clever with -1 here [...] | } [...] | /** | | * assign_bit - Assign value to a bit in memory | | * @nr: the bit to set | | * @addr: the address to start counting from | | * @value: the value to assign | | */ | | static always_inline void assign_bit(long nr, volatile unsigned long addr, | | bool value) | | { | | if (value) | | set_bit(nr, addr); | | else | | clear_bit(nr, addr); | | } | [...] | static always_inline void assign_bit(long nr, volatile unsigned long addr, | | bool value) | | { | | if (value) | | __set_bit(nr, addr); | | else | | __clear_bit(nr, addr); | | } | [...] #ifdef KERNEL | [...] | #ifndef set_mask_bits | | #define set_mask_bits(ptr, mask, bits) \ | | ({ \ | | const typeof((ptr)) mask = (mask), bits = (bits); \ | | typeof((ptr)) old, new; \ | | \ | | do { \ | | old = READ_ONCE(*(ptr)); \ | | new = (old & ~mask) | bits__; \ | | } while (cmpxchg(ptr, old__, new__) != old__); \ | | \ | | old__; \ | | }) | [...] #endif |
  4. tools/include/linux/bitops.h at master · torvalds/linux: # File: torvalds/linux/tools/include/linux/bitops.h - Repository: torvalds/linux | Linux kernel source tree | 227K stars | C - Branch: master h /* SPDX-License-Identifier: GPL-2.0 */ `#ifndef` _TOOLS_LINUX_BITOPS_H_ `#define` _TOOLS_LINUX_BITOPS_H_ `#include` <asm/types.h> `#include` <limits.h> `#ifndef` __WORDSIZE `#define` __WORDSIZE (__SIZEOF_LONG__ * 8) `#endif` `#ifndef` BITS_PER_LONG # define BITS_PER_LONG __WORDSIZE `#endif` `#include` <linux/bits.h> `#include` <linux/compiler.h> `#define` BITS_PER_TYPE(type) (sizeof(type) * BITS_PER_BYTE) `#define` BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_TYPE(long)) `#define` BITS_TO_U64(nr) DIV_ROUND_UP(nr, BITS_PER_TYPE(u64)) `#define` BITS_TO_U32(nr) DIV_ROUND_UP(nr, BITS_PER_TYPE(u32)) `#define` BITS_TO_BYTES(nr) DIV_ROUND_UP(nr, BITS_PER_TYPE(char)) `#define` BYTES_TO_BITS(nb) ((nb) * BITS_PER_BYTE) extern unsigned int __sw_hweight8(unsigned int w); extern unsigned int __sw_hweight16(unsigned int w); extern unsigned int __sw_hweight32(unsigned int w); extern unsigned long __sw_hweight64(__u64 w); /* * Defined here because those may be needed by architecture-specific static * inlines. */ `#define` bitop(op, nr, addr) \ op(nr, addr) `#define` __set_bit(nr, addr) bitop(___set_bit, nr, addr) `#define` __clear_bit(nr, addr) bitop(___clear_bit, nr, addr) `#define` __change_bit(nr, addr) bitop(___change_bit, nr, addr) `#define` __test_and_set_bit(nr, addr) bitop(___test_and_set_bit, nr, addr) `#define` __test_and_clear_bit(nr, addr) bitop(___test_and_clear_bit, nr, addr) `#define` __test_and_change_bit(nr, addr) bitop(___test_and_change_bit, nr, addr) `#define` test_bit(nr, addr) bitop(_test_bit, nr, addr) /* * Include this here because some architectures need generic_ffs/fls in * scope * * XXX: this needs to be asm/bitops.h, when we get to per arch optimizations */ `#include` <asm-generic/bitops.h> `#define` for_each_set_bit(bit, addr, size) \ for ((bit) = find_first_bit((addr), (size)); \ (bit) < (size); \ (bit) = find_next_bit((addr), (size), (bit) + 1)) `#define` for_each_clear_bit(bit, addr, size) \ for ((bit) = find_first_zero_bit((addr), (size)); \ (bit) < (size); \ (bit) = find_next_zero_bit((addr), (size), (bit) + 1)) /* same as for_each_set_bit() but use bit as value to start with */ `#define` for_each_set_bit_from(bit, addr, size) \ for ((bit) = find_next_bit((addr), (size), (bit)); \ (bit) < (size); \ (bit) = find_next_bit((addr), (size), (bit) + 1)) static inline unsigned long hweight_long(unsigned long w) { return sizeof(w) == 4 ? hweight32(w) : hweight64(w); } static inline unsigned int fls_long(unsigned long l) { if (sizeof(l) == 4) return fls(l); return fls64(l); } /** * rol32 - rotate a 32-bit value left * `@word`: value to rotate * `@shift`: bits to roll */ static inline __u32 rol32(__u32 word, unsigned int shift) { return (word << shift) | (word >> ((-shift) & 31)); } /** * sign_extend64 - sign extend a 64-bit value using specified bit as sign-bit * `@value`: value to sign extend * `@index`: 0 based bit index (0<=index<64) to sign bit */ static __always_inline __s64 sign_extend64(__u64 value, int index) { __u8 shift = 63 - index; return (__s64)(value << shift) >> shift; } `#endif`

Citations:


🏁 Script executed:

find . -name "*0016*pwm*SN3112*" -o -name "0016*" | grep -i pwm | head -20

Repository: armbian/build

Length of output: 135


🏁 Script executed:

fd "0016.*pwm" --type f

Repository: armbian/build

Length of output: 133


🏁 Script executed:

find . -path "*sm8550-7.0*" -name "*0016*" -type f

Repository: armbian/build

Length of output: 135


🏁 Script executed:

cat -n patch/kernel/archive/sm8550-7.0/0016-pwm-Add-SI-EN-SN3112-PWM-support.patch | head -150

Repository: armbian/build

Length of output: 5576


🏁 Script executed:

# Verify struct field adjacency and potential clobbering
cat -n patch/kernel/archive/sm8550-7.0/0016-pwm-Add-SI-EN-SN3112-PWM-support.patch | sed -n '80,95p'

Repository: armbian/build

Length of output: 541


set_bit/clear_bit on a uint8_t[3] cast to unsigned long * causes buffer overflow and data corruption.

pwm_en_reg is declared as uint8_t pwm_en_reg[3] (3 bytes). Lines 132/134 pass (ulong *)&priv->pwm_en_reg[reg] to the atomic set_bit/clear_bit helpers, which operate on unsigned long-sized words. On arm64, these helpers execute 32-bit or 64-bit load-exclusive/store-exclusive sequences that read/write 4–8 bytes starting from the address—overflowing into the adjacent pwm_en[] field and corrupting data. Alignment is also incorrect; uint8_t elements have no guarantee of unsigned long alignment.

The data is mutex-protected and not visible to other CPUs, so atomic operations are not needed. Replace with plain bitwise operations on the byte:

🔧 Suggested fix
 	if (enabled)
-		set_bit(bit, (ulong *)&priv->pwm_en_reg[reg]);
+		priv->pwm_en_reg[reg] |= BIT(bit);
 	else
-		clear_bit(bit, (ulong *)&priv->pwm_en_reg[reg]);
+		priv->pwm_en_reg[reg] &= ~BIT(bit);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@patch/kernel/archive/sm8550-7.0/0016-pwm-Add-SI-EN-SN3112-PWM-support.patch`
around lines 80 - 91, The code uses set_bit/clear_bit on elements of
priv->pwm_en_reg (declared uint8_t pwm_en_reg[3]) by casting to unsigned long*,
causing buffer overflow and alignment issues; replace those atomic helper calls
with plain byte-wise bit operations on priv->pwm_en_reg[reg] (e.g.,
priv->pwm_en_reg[reg] |= BIT(bit); and priv->pwm_en_reg[reg] &= ~BIT(bit);) and
remove the (ulong *) casts, ensuring modifications remain protected by the
existing struct sn3112.lock mutex (use mutex_lock/mutex_unlock around the byte
writes if not already done) and leave pwm_en[] updates untouched.

Comment on lines +89 to +97
+static void ch13726a_reset(struct ch13726a_panel *ctx)
+{
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+ usleep_range(10000, 11000);
+ gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+ usleep_range(10000, 11000);
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+ usleep_range(10000, 11000);
+}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Look up reset-gpios polarity for ch13726a panel in the new sm8550-7.0 DTS files
rg -nP --type=dts -C2 'compatible\s*=\s*"ch13726a' 
rg -nP -C5 'compatible\s*=\s*"ch13726a'

Repository: armbian/build

Length of output: 17056


🏁 Script executed:

# Search for reset-gpios property in the Thor DTS patch
rg -n "reset-gpio|reset_gpio" patch/kernel/archive/sm8550-7.0/0040-arm64-dts-qcom-Add-AYN-Thor.patch -C 3

# Also look at the full panel node in the Thor patch
rg -n -A 20 'panel@0 {' patch/kernel/archive/sm8550-7.0/0040-arm64-dts-qcom-Add-AYN-Thor.patch | head -60

Repository: armbian/build

Length of output: 940


Reset sequence ends with reset GPIO asserted; inconsistent with DSI command transmission.

The ch13726a_reset() function sets the reset GPIO 1 → 0 → 1 and returns with the line at logical 1. With GPIO_ACTIVE_HIGH (as specified in the AYN Thor DTS at reset-gpios = <&tlmm 133 GPIO_ACTIVE_HIGH>), a value of 1 means the GPIO is in its active (asserted) state, leaving the panel held in reset. Immediately after this function returns, ch13726a_on() is called to send MIPI DSI commands, which cannot work while the panel is held in reset.

Other panel drivers in the same patch (td4328_reset, xm91080g_reset, ar06_4inch_reset) all end their reset sequences with the GPIO deasserted (0), and the error path in ch13726a_prepare() (line 149) also sets the GPIO to 0 for release.

The reset sequence should end with gpiod_set_value_cansleep(ctx->reset_gpio, 0) to release the panel from reset before DSI commands are transmitted.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@patch/kernel/archive/sm8550-7.0/0020-drm-panel-Add-panel-driver-for-DDIC-CH13726A-based-p.patch`
around lines 89 - 97, The ch13726a_reset() routine currently toggles reset GPIO
1→0→1 and leaves it asserted (logical 1), preventing DSI commands in
ch13726a_on(); change the final gpio state to deassert the line by ensuring the
function ends with gpiod_set_value_cansleep(ctx->reset_gpio, 0) so the panel is
released from reset before command transmission; mirror the behavior used in
td4328_reset/xm91080g_reset/ar06_4inch_reset and the error-path in
ch13726a_prepare() to keep reset semantics consistent.

Comment on lines +157 to +163
+ miniled->enable = devm_gpiod_get(&client->dev, "enable", GPIOD_OUT_HIGH);
+ if (PTR_ERR(miniled->enable) == -EPROBE_DEFER){
+ return -EPROBE_DEFER;
+ }
+
+ gpiod_set_value_cansleep(miniled->enable, 1);
+ usleep_range(10000, 11000);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Missing IS_ERR check on devm_gpiod_get() return value.

devm_gpiod_get() returns an ERR_PTR on failure. The code only checks for -EPROBE_DEFER; for any other error (e.g., -ENOENT, -EINVAL), miniled->enable will hold an error pointer that is then dereferenced by gpiod_set_value_cansleep() on line 162, causing a kernel oops.

🐛 Proposed fix
-    miniled->enable = devm_gpiod_get(&client->dev, "enable", GPIOD_OUT_HIGH);
-    if (PTR_ERR(miniled->enable) == -EPROBE_DEFER){
-        return -EPROBE_DEFER;
-    }
+    miniled->enable = devm_gpiod_get(&client->dev, "enable", GPIOD_OUT_HIGH);
+    if (IS_ERR(miniled->enable))
+        return dev_err_probe(&client->dev, PTR_ERR(miniled->enable),
+                             "Failed to get enable GPIO\n");
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
+ miniled->enable = devm_gpiod_get(&client->dev, "enable", GPIOD_OUT_HIGH);
+ if (PTR_ERR(miniled->enable) == -EPROBE_DEFER){
+ return -EPROBE_DEFER;
+ }
+
+ gpiod_set_value_cansleep(miniled->enable, 1);
+ usleep_range(10000, 11000);
miniled->enable = devm_gpiod_get(&client->dev, "enable", GPIOD_OUT_HIGH);
if (IS_ERR(miniled->enable))
return dev_err_probe(&client->dev, PTR_ERR(miniled->enable),
"Failed to get enable GPIO\n");
gpiod_set_value_cansleep(miniled->enable, 1);
usleep_range(10000, 11000);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@patch/kernel/archive/sm8550-7.0/0021-backlight-odin2mini-backlight-Add-support-for-AYN-Od.patch`
around lines 157 - 163, devm_gpiod_get() can return ERR_PTRs and the code
currently only handles -EPROBE_DEFER; change the logic around miniled->enable to
use IS_ERR(miniled->enable) and handle the error: if PTR_ERR(miniled->enable) ==
-EPROBE_DEFER return -EPROBE_DEFER, otherwise return PTR_ERR(miniled->enable)
(or appropriate errno) before calling gpiod_set_value_cansleep; ensure the
IS_ERR check precedes any use of miniled->enable to avoid dereferencing an error
pointer.

Comment on lines +159 to +161
+ data->reset_gpio[1] = devm_gpiod_get_index(dev, "reset", 1, GPIOD_OUT_HIGH);
+ if (IS_ERR(data->reset_gpio[1]))
+ dev_warn(dev, "failed to get second reset GPIO\n");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: secondary reset GPIO is left as ERR_PTR and later dereferenced.

The second reset GPIO is fetched with the non-optional devm_gpiod_get_index. On failure (i.e., DT only describes one reset GPIO, the common case), the code only logs a warning but does not clear data->reset_gpio[1]:

data->reset_gpio[1] = devm_gpiod_get_index(dev, "reset", 1, GPIOD_OUT_HIGH);
if (IS_ERR(data->reset_gpio[1]))
    dev_warn(dev, "failed to get second reset GPIO\n");

Then sgm3804_enable/sgm3804_disable do:

if (data->reset_gpio[1])
    gpiod_set_value_cansleep(data->reset_gpio[1], 1);

Since IS_ERR(p) is non-NULL, the guard is always true and gpiod_set_value_cansleep() is called on an ERR_PTR, which will dereference a kernel poison pointer (e.g., (void *)-ENOENT) and oops the first time the regulator is enabled on any board with only one reset GPIO.

🛠️ Suggested fix — use the optional variant
-    data->reset_gpio[1] = devm_gpiod_get_index(dev, "reset", 1, GPIOD_OUT_HIGH);
-    if (IS_ERR(data->reset_gpio[1]))
-        dev_warn(dev, "failed to get second reset GPIO\n");
+    data->reset_gpio[1] = devm_gpiod_get_index_optional(dev, "reset", 1,
+                                                       GPIOD_OUT_HIGH);
+    if (IS_ERR(data->reset_gpio[1]))
+        return dev_err_probe(dev, PTR_ERR(data->reset_gpio[1]),
+                             "failed to get second reset GPIO\n");

Also applies to: 76-81, 99-104

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@patch/kernel/archive/sm8550-7.0/0024-regulator-add-sgm3804-i2c-regulator-for-panel-power-.patch`
around lines 159 - 161, The secondary reset GPIO is obtained with
devm_gpiod_get_index and left as an ERR_PTR, which later causes
gpiod_set_value_cansleep to dereference it in sgm3804_enable/sgm3804_disable;
change the acquisition to the optional variant (devm_gpiod_get_index_optional)
or explicitly set data->reset_gpio[1] = NULL on IS_ERR, and update all similar
occurrences (the other reset GPIO fetches in the same patch) so that later
checks use a true NULL test before calling gpiod_set_value_cansleep; ensure you
modify the calls where data->reset_gpio[1] is assigned and the corresponding
guards in sgm3804_enable/sdm3804_disable to avoid using ERR_PTR.

Comment on lines +70 to +79
+ vdd_bl_5v0: vdd-bl-5v0-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vdd_bl_5v0";
+
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+
+ gpio = <&tlmm 55 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

GPIO 55 is claimed by two consumers — backlight will fail to probe.

Both vdd_bl_5v0 (fixed regulator at lines 70‑79) and the backlight@46 node (enable-gpios at line 126) request <&tlmm 55 GPIO_ACTIVE_HIGH> exclusively. Since &display_panel consumes vdd_bl_5v0 via blvdd-supply, both drivers will try to gpiod_get() GPIO 55, and whichever probes second will get -EBUSY. In practice this will leave either the panel power chain or the backlight controller un-initialized.

Pick one owner of the GPIO:

  • If the backlight chip itself drives the rail through its own enable pin, drop the vdd_bl_5v0 fixed regulator and remove blvdd-supply from &display_panel (or wire it through the backlight node instead).
  • If the rail must be a separate regulator, remove enable-gpios from backlight@46 and have the panel/backlight reference vdd_bl_5v0 as a supply.

Also applies to: 122-130

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@patch/kernel/archive/sm8550-7.0/0038-arm64-dts-qcom-Add-AYN-Odin2-Mini.patch`
around lines 70 - 79, GPIO 55 is being requested by both the fixed regulator
node vdd_bl_5v0 and the backlight node backlight@46 via enable-gpios, causing
probe conflicts; decide one owner and modify the DTS accordingly: either remove
the vdd_bl_5v0 node and delete blvdd-supply from &display_panel (or route the
supply via the backlight node) if the backlight chip should drive the rail, or
keep vdd_bl_5v0 as the regulator and remove enable-gpios from backlight@46 and
make the panel/backlight reference vdd_bl_5v0 via blvdd-supply so only the
regulator controls GPIO 55; update both the vdd_bl_5v0 node (lines 70-79) and
backlight@46 (lines ~122-130) to reflect the chosen single owner.

Comment on lines +47 to +52
{
- if (in_compat_syscall()) {
+ if (current->compat_input || (in_compat_syscall() && !COMPAT_USE_64BIT_TIME)) {
struct ff_effect_compat *compat_effect;

if (size != sizeof(struct ff_effect_compat))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

Linux kernel struct ff_effect_compat COMPAT_USE_64BIT_TIME input_ff_effect_from_user

💡 Result:

The Linux kernel provides 32-bit compatibility support for the input subsystem in drivers/input/input-compat.[ch], including handling of force feedback effects via struct ff_effect_compat. struct ff_effect_compat is defined in drivers/input/input-compat.h as a 32-bit compatible version of struct ff_effect (from include/uapi/linux/input.h). Key differences include using compat_ulong_t and compat_uptr_t for pointers and sizes in ff_periodic_effect_compat (e.g., custom_len and custom_data), while other fields match ff_effect. The function input_ff_effect_from_user(const char user *buffer, size_t size, struct ff_effect *effect) copies a user-space ff_effect into kernel space, handling compatibility: if (current->compat_input || (in_compat_syscall && !COMPAT_USE_64BIT_TIME)) { struct ff_effect_compat *compat_effect; if (size != sizeof(struct ff_effect_compat)) return -EINVAL; compat_effect = (struct ff_effect_compat )effect; / copy_from_user(compat_effect, buffer, sizeof(*compat_effect)); / / convert compat_effect -> effect / } else { / direct copy_from_user(effect, buffer, size); */ } COMPAT_USE_64BIT_TIME is an architecture-specific macro (defined in asm/compat.h, e.g., for x32 ABI on x86_64) indicating if 32-bit processes use 64-bit time_t. When true, compat handling for time fields (like input_event timestamps) is skipped, but for ff_effect, compat conversion occurs unconditionally during in_compat_syscall unless overridden by current->compat_input (a prctl opt-in for 64-bit processes). This ensures 32-bit userspace can upload ff_effects via ioctl(EVIOCSFF) on 64-bit kernels, with the kernel converting between struct ff_effect_compat and struct ff_effect for drivers. Sources confirm this behavior across kernel versions up to recent (e.g., v6.19-rc8). The patch in result 3 (not mainline as of 2026-04-25) adds prctl for 64-bit opt-in but uses !COMPAT_USE_64BIT_TIME consistently.

Citations:


🏁 Script executed:

find . -name "*0044-Enable-64-bit-processes-to-use-compat-input-syscalls.patch" -type f

Repository: armbian/build

Length of output: 155


🏁 Script executed:

cat ./patch/kernel/archive/sm8550-7.0/0044-Enable-64-bit-processes-to-use-compat-input-syscalls.patch

Repository: armbian/build

Length of output: 4479


🏁 Script executed:

# Search for COMPAT_USE_64BIT_TIME definitions to understand which architectures use it
rg "COMPAT_USE_64BIT_TIME\s*=" --type c --max-count=20

Repository: armbian/build

Length of output: 39


🌐 Web query:

ff_effect_compat structure time fields COMPAT_USE_64BIT_TIME architecture x86 x32

💡 Result:

The ff_effect_compat structure is the 32-bit compatibility version of struct ff_effect used in the Linux input subsystem for force feedback effects. It is defined in drivers/input/input-compat.h for CONFIG_COMPAT builds. Key differences relevant to time fields and COMPAT_USE_64BIT_TIME on x86 x32 architecture: - ff_effect.replay uses struct ff_replay { u16 length; u16 delay; }; - ff_trigger uses struct ff_trigger { u16 button; u16 interval; }; No direct time_t fields (like struct timeval or timespec) in ff_effect or ff_replay/ff_trigger, so no direct impact from COMPAT_USE_64BIT_TIME on these structures themselves. However, COMPAT_USE_64BIT_TIME affects the input event compatibility layer: - In input-compat.h and input-compat.c, input_event_size and input_event_from_user/to_user use: if (in_compat_syscall && !COMPAT_USE_64BIT_TIME) then use struct input_event_compat { compat_ulong_t sec; compat_ulong_t usec; ... } (32-bit time), else native 64-bit kernel_timespec or similar. - For x86 x32 (ILP32 on x86_64), COMPAT_USE_64BIT_TIME=1 by default, so it uses 64-bit time_t even in compat mode, bypassing the 32-bit compat_event conversion for input events. For ff_effect specifically: - input_ff_effect_from_user(const char user *buffer, size_t size, struct ff_effect *effect) in input-compat.c converts struct ff_effect_compat to ff_effect if in_compat_syscall. - struct ff_effect_compat has: - struct ff_periodic_effect_compat periodic with compat_uptr_t custom_data (pointer, 32-bit in compat). - No time_t fields, so unaffected by COMPAT_USE_64BIT_TIME directly. - x32 uses native ff_effect (64-bit pointers in u union via padding/array), but compat ioctls may trigger conversion if !COMPAT_USE_64BIT_TIME (though typically enabled). On x86 x32, since COMPAT_USE_64BIT_TIME=y, ff_effect_compat handling is used only for true 32-bit compat tasks wanting 32-bit time, but x32 apps see native 64-bit time layout. The "time fields" likely refer to replay.length/delay (in ms, u16) or envelope attack_length/fade_length (in ms, u16), which are identical in compat/native and not time_t. Sources confirm ff_effect_compat exists for compat ioctl EVIOCSFF/EVIOCGFF on 32-bit userspace, with x32 preferring native due to COMPAT_USE_64BIT_TIME.

Citations:


Behavioral regression in input_ff_effect_from_user on COMPAT_USE_64BIT_TIME architectures.

The original guard for force-feedback was just:

if (in_compat_syscall())

The patch adds !COMPAT_USE_64BIT_TIME:

if (current->compat_input || (in_compat_syscall() && !COMPAT_USE_64BIT_TIME))

COMPAT_USE_64BIT_TIME controls whether struct input_event timestamps use 32-bit or 64-bit representation. struct ff_effect_compat has no time fields — it differs from native ff_effect only in pointer size (compat_uptr_t vs pointer). The compat decision for FF must depend on in_compat_syscall() alone.

On architectures where COMPAT_USE_64BIT_TIME=1 (x86 x32, arm64 ILP32), a 32-bit task calling EVIOCSFF will now skip the compat path entirely:

  • Condition evaluates to: (FALSE) || (TRUE && FALSE) = FALSE
  • Userspace sends struct ff_effect_compat (32-bit pointers)
  • Kernel interprets it as native struct ff_effect (64-bit pointers)
  • Result: data corruption or EINVAL from size mismatch
🛠️ Fix — remove `!COMPAT_USE_64BIT_TIME` from ff path
-	if (current->compat_input || (in_compat_syscall() && !COMPAT_USE_64BIT_TIME)) {
+	if (current->compat_input || in_compat_syscall()) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@patch/kernel/archive/sm8550-7.0/0044-Enable-64-bit-processes-to-use-compat-input-syscalls.patch`
around lines 47 - 52, The compat guard in input_ff_effect_from_user incorrectly
mixes COMPAT_USE_64BIT_TIME into the decision, causing 32-bit tasks on
COMPAT_USE_64BIT_TIME architectures to be treated as native and corrupt
ff_effect handling; change the conditional back to depend only on
current->compat_input or in_compat_syscall() so that struct ff_effect_compat
(which has no time fields) is used whenever the syscall is a compat syscall:
remove the "&& !COMPAT_USE_64BIT_TIME" clause from the if that checks
current->compat_input || (in_compat_syscall() && !COMPAT_USE_64BIT_TIME) so it
becomes current->compat_input || in_compat_syscall().

@pdapandapda
Copy link
Copy Markdown

Odin2 portal seems failing to boot by merging this pull quest. edge-7.0.1

@kasimling
Copy link
Copy Markdown
Contributor Author

Odin2 portal seems failing to boot by merging this pull quest. edge-7.0.1

@pdapandapda, thanks for testing. What's the failure? Any error message?

@kasimling kasimling marked this pull request as draft April 27, 2026 00:30
@pdapandapda
Copy link
Copy Markdown

Odin2 portal seems failing to boot by merging this pull quest. edge-7.0.1

@pdapandapda, thanks for testing. What's the failure? Any error message?

When logging into the system during init boot,although the usbgadget is recognized by PC,
pda@pda:/new$ ssh root@172.16.42.1
ssh: connect to host 172.16.42.1 port 22: Connection timed out
pda@pda:
/new$
It just failed to connect.
While installing kernel debs with dpkg command,after reboot, the system became extremly slow, working at just like 15FPS.

@pdapandapda
Copy link
Copy Markdown

[ 153.577404] [drm:dpu_kms_wait_for_commit_done:525] [dpu error]wait for commit done returned -110
[ 153.676100] [drm:_dpu_encoder_phys_cmd_wait_for_ctl_start:654] [dpu error]enc33 intf2 ctl start interrupt wait failed
[ 153.687074] [drm:dpu_kms_wait_for_commit_done:525] [dpu error]wait for commit done returned -22
[ 153.782949] [drm:_dpu_encoder_phys_cmd_wait_for_ctl_start:654] [dpu error]enc33 intf2 ctl start interrupt wait failed
[ 153.793896] [drm:dpu_kms_wait_for_commit_done:525] [dpu error]wait for commit done returned -22
[ 153.892112] [drm:_dpu_encoder_phys_cmd_wait_for_ctl_start:654] [dpu error]enc33 intf2 ctl start interrupt wait failed
[ 153.903115] [drm:dpu_kms_wait_for_commit_done:525] [dpu error]wait for commit done returned -22
[ 153.998929] [drm:_dpu_encoder_phys_cmd_wait_for_ctl_start:654] [dpu error]enc33 intf2 ctl start interrupt wait failed
[ 154.009903] [drm:dpu_kms_wait_for_commit_done:525] [dpu error]wait for commit done returned -22
[ 154.066924] [drm:dpu_encoder_frame_done_timeout:2731] [dpu error]enc33 frame done timeout
[ 154.106930] [drm:_dpu_encoder_phys_cmd_handle_ppdone_timeout.isra.0] ERROR id:33 pp:0 kickoff timeout 0 cnt 1 koff_cnt 1
[ 154.118339] [drm:dpu_encoder_phys_cmd_wait_for_tx_complete] ERROR failed wait_for_idle: id:33 ret:-110 intf:2
[ 154.128759] [drm:dpu_kms_wait_for_commit_done:525] [dpu error]wait for commit done returned -110
[ 155.439337] [drm:_dpu_encoder_phys_cmd_wait_for_ctl_start:654] [dpu error]enc33 intf2 ctl start interrupt wait failed
[ 155.450355] [drm:dpu_kms_wait_for_commit_done:525] [dpu error]wait for commit done returned -22
[ 155.550727] [drm:_dpu_encoder_phys_cmd_wait_for_ctl_start:654] [dpu error]enc33 intf2 ctl start interrupt wait failed
[ 155.561665] [drm:dpu_kms_wait_for_commit_done:525] [dpu error]wait for commit done returned -22
[ 155.659872] [drm:_dpu_encoder_phys_cmd_wait_for_ctl_start:654] [dpu error]enc33 intf2 ctl start interrupt wait failed
[ 155.670872] [drm:dpu_kms_wait_for_commit_done:525] [dpu error]wait for commit done returned -22
[ 155.766716] [drm:_dpu_encoder_phys_cmd_wait_for_ctl_start:654] [dpu error]enc33 intf2 ctl start interrupt wait failed
[ 155.777670] [drm:dpu_kms_wait_for_commit_done:525] [dpu error]wait for commit done returned -22
[ 155.834679] [drm:dpu_encoder_frame_done_timeout:2731] [dpu error]enc33 frame done timeout
[ 155.875307] [drm:_dpu_encoder_phys_cmd_handle_ppdone_timeout.isra.0] ERROR id:33 pp:0 kickoff timeout 0 cnt 1 koff_cnt 1
[ 155.886783] [drm:dpu_encoder_phys_cmd_wait_for_tx_complete] ERROR failed wait_for_idle: id:33 ret:-110 intf:2
[ 155.897246] [drm:dpu_kms_wait_for_commit_done:525] [dpu error]wait for commit done returned -110
[ 155.995106] [drm:_dpu_encoder_phys_cmd_wait_for_ctl_start:654] [dpu error]enc33 intf2 ctl start interrupt wait failed
[ 156.006106] [drm:dpu_kms_wait_for_commit_done:525] [dpu error]wait for commit done returned -22
[ 157.130557] [drm:_dpu_encoder_phys_cmd_wait_for_ctl_start:654] [dpu error]enc33 intf2 ctl start interrupt wait failed
[ 157.141839] [drm:dpu_kms_wait_for_commit_done:525] [dpu error]wait for commit done returned -22
[ 157.238580] [drm:_dpu_encoder_phys_cmd_wait_for_ctl_start:654] [dpu error]enc33 intf2 ctl start interrupt wait failed
[ 157.249704] [drm:dpu_kms_wait_for_commit_done:525] [dpu error]wait for commit done returned -22
[ 157.346948] [drm:_dpu_encoder_phys_cmd_wait_for_ctl_start:654] [dpu error]enc33 intf2 ctl start interrupt wait failed
[ 157.357973] [drm:dpu_kms_wait_for_commit_done:525] [dpu error]wait for commit done returned -22
[ 157.414528] [drm:dpu_encoder_frame_done_timeout:2731] [dpu error]enc33 frame done timeout
[ 157.455095] [drm:_dpu_encoder_phys_cmd_handle_ppdone_timeout.isra.0] ERROR id:33 pp:0 kickoff timeout 0 cnt 1 koff_cnt 1
[ 157.466553] [drm:dpu_encoder_phys_cmd_wait_for_tx_complete] ERROR failed wait_for_idle: id:33 ret:-110 intf:2
[ 157.476986] [drm:dpu_kms_wait_for_commit_done:525] [dpu error]wait for commit done returned -110
[ 157.574476] [drm:_dpu_encoder_phys_cmd_wait_for_ctl_start:654] [dpu error]enc33 intf2 ctl start interrupt wait failed
[ 157.585432] [drm:dpu_kms_wait_for_commit_done:525] [dpu error]wait for commit done returned -22
[ 158.702394] [drm:_dpu_encoder_phys_cmd_wait_for_ctl_start:654] [dpu error]enc33 intf2 ctl start interrupt wait failed
[ 158.713356] [drm:dpu_kms_wait_for_commit_done:525] [dpu error]wait for commit done returned -22
[ 158.810744] [drm:_dpu_encoder_phys_cmd_wait_for_ctl_start:654] [dpu error]enc33 intf2 ctl start interrupt wait failed
[ 158.821906] [drm:dpu_kms_wait_for_commit_done:525] [dpu error]wait for commit done returned -22
[ 158.919484] [drm:_dpu_encoder_phys_cmd_wait_for_ctl_start:654] [dpu error]enc33 intf2 ctl start interrupt wait failed
[ 158.930648] [drm:dpu_kms_wait_for_commit_done:525] [dpu error]wait for commit done returned -22
[ 158.986286] [drm:dpu_encoder_frame_done_timeout:2731] [dpu error]enc33 frame done timeout
[ 159.027387] [drm:_dpu_encoder_phys_cmd_handle_ppdone_timeout.isra.0] ERROR id:33 pp:0 kickoff timeout 0 cnt 1 koff_cnt 1
[ 159.038826] [drm:dpu_encoder_phys_cmd_wait_for_tx_complete] ERROR failed wait_for_idle: id:33 ret:-110 intf:2
[ 159.049847] [drm:dpu_kms_wait_for_commit_done:525] [dpu error]wait for commit done returned -110
[ 159.146432] [drm:_dpu_encoder_phys_cmd_wait_for_ctl_start:654] [dpu error]enc33 intf2 ctl start interrupt wait failed
[ 159.157622] [drm:dpu_kms_wait_for_commit_done:525] [dpu error]wait for commit done returned -22
[ 159.286261] [drm:_dpu_encoder_phys_cmd_wait_for_ctl_start:654] [dpu error]enc33 intf2 ctl start interrupt wait failed
[ 159.297213] [drm:dpu_kms_wait_for_commit_done:525] [dpu error]wait for commit done returned -22
[ 159.398228] [drm:_dpu_encoder_phys_cmd_wait_for_ctl_start:654] [dpu error]enc33 intf2 ctl start interrupt wait failed
[ 159.409173] [drm:dpu_kms_wait_for_commit_done:525] [dpu error]wait for commit done returned -22
[ 159.506631] [drm:_dpu_encoder_phys_cmd_wait_for_ctl_start:654] [dpu error]enc33 intf2 ctl start interrupt wait failed
[ 159.517622] [drm:dpu_kms_wait_for_commit_done:525] [dpu error]wait for commit done returned -22
[ 159.574205] [drm:dpu_encoder_frame_done_timeout:2731] [dpu error]enc33 frame done timeout
[ 159.615317] [drm:_dpu_encoder_phys_cmd_handle_ppdone_timeout.isra.0] ERROR id:33 pp:0 kickoff timeout 0 cnt 1 koff_cnt 1
[ 159.626766] [drm:dpu_encoder_phys_cmd_wait_for_tx_complete] ERROR failed wait_for_idle: id:33 ret:-110 intf:2
[ 159.637214] [drm:dpu_kms_wait_for_commit_done:525] [dpu error]wait for commit done returned -110
[ 159.742200] [drm:_dpu_encoder_phys_cmd_wait_for_ctl_start:654] [dpu error]enc33 intf2 ctl start interrupt wait failed
[ 159.753173] [drm:dpu_kms_wait_for_commit_done:525] [dpu error]wait for commit done returned -22
pda@ayn-odin2portal:~$

@kasimling
Copy link
Copy Markdown
Contributor Author

@pdapandapda Thanks. Will take a look at it.

@kasimling
Copy link
Copy Markdown
Contributor Author

@pdapandapda , it seems I missed one display related patch. Added it now. Please help re-test and let me know if still any problems. Thanks!

@pdapandapda
Copy link
Copy Markdown

@pdapandapda , it seems I missed one display related patch. Added it now. Please help re-test and let me know if still any problems. Thanks!
Unable to boot into linux this time. I mean, the ABL loaded the cfg, Image,Initramfs, then the panel turned into blackout, and then rebooted back to the loader

@kasimling
Copy link
Copy Markdown
Contributor Author

Unable to boot into linux this time. I mean, the ABL loaded the cfg, Image,Initramfs, then the panel turned into blackout, and then rebooted back to the loader

@pdapandapda, did you build the whole image or only kernel deb files?

@pdapandapda
Copy link
Copy Markdown

Unable to boot into linux this time. I mean, the ABL loaded the cfg, Image,Initramfs, then the panel turned into blackout, and then rebooted back to the loader

@pdapandapda, did you build the whole image or only kernel deb files?

The full image

@kasimling
Copy link
Copy Markdown
Contributor Author

Unable to boot into linux this time. I mean, the ABL loaded the cfg, Image,Initramfs, then the panel turned into blackout, and then rebooted back to the loader

@pdapandapda, did you build the whole image or only kernel deb files?

The full image

OK. Let me try to get an odin2portal device to check it

@kasimling
Copy link
Copy Markdown
Contributor Author

Unable to boot into linux this time. I mean, the ABL loaded the cfg, Image,Initramfs, then the panel turned into blackout, and then rebooted back to the loader

@pdapandapda, did you build the whole image or only kernel deb files?

The full image

@pdapandapda , could you please try setting "DisableDisplayHW" to "false" in LinuxLoader.cfg? Thanks.

@SuperKali
Copy link
Copy Markdown
Member

@kasimling Just a random off-topic question: Does Armbian boot on the Odin 2 from the SD card, or do you have to flash the entire internal memory? I'm asking because they recently released the kernel for the Odin 3, and I'd like to know if we can add support for it—and avoid flashing the internal memory, since, as far as I can tell, there isn't even a guide for reflashing Android if you mess something up.

@kasimling
Copy link
Copy Markdown
Contributor Author

kasimling commented Apr 28, 2026

@kasimling Just a random off-topic question: Does Armbian boot on the Odin 2 from the SD card, or do you have to flash the entire internal memory? I'm asking because they recently released the kernel for the Odin 3, and I'd like to know if we can add support for it—and avoid flashing the internal memory, since, as far as I can tell, there isn't even a guide for reflashing Android if you mess something up.

It boots from SD card. Regarding to Odin 3 support, my understanding is if we can get a working ABL which can boot Linux, we can try building Armbian for it.

@SuperKali
Copy link
Copy Markdown
Member

It boots from SD card. Regarding to Odin 3 support, my understanding is if we can get a working ABL which can boot Linux, we can try building Armbian for it.

This is a good news! thank you for your reply, i have one odin 3 and i want try use linux but on micro sd for testing

@pdapandapda
Copy link
Copy Markdown

Unable to boot into linux this time. I mean, the ABL loaded the cfg, Image,Initramfs, then the panel turned into blackout, and then rebooted back to the loader

@pdapandapda, did you build the whole image or only kernel deb files?

The full image

@pdapandapda , could you please try setting "DisableDisplayHW" to "false" in LinuxLoader.cfg? Thanks.

IMG_1556

kasimling added 3 commits May 4, 2026 11:28
Signed-off-by: Alex Ling <ling_kasim@hotmail.com>
Signed-off-by: Alex Ling <ling_kasim@hotmail.com>
Kept odin2portal to 6.18 since there's boot issue reported

Signed-off-by: Alex Ling <ling_kasim@hotmail.com>
@kasimling kasimling force-pushed the odin2_kernel_7.0 branch from f7ff2d3 to 7e851a4 Compare May 4, 2026 10:15
@kasimling kasimling marked this pull request as ready for review May 4, 2026 10:17
@kasimling
Copy link
Copy Markdown
Contributor Author

Keep odin2portal to kernel 6.18. @pdapandapda , please let me know if still any problems. Thanks!

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Nitpick comments (3)
patch/kernel/archive/sm8550-7.0/0036-arm64-dts-qcom-Add-AYN-QCS8550-Common.patch (1)

1084-1102: Add explicit firmware-name property to both AW88166 speaker amp nodes.

The AW88166 driver now supports reading a firmware-name property from device tree (with fallback to AW88166_ACF_FILE if unset). The paired spk_amp_l and spk_amp_r nodes currently omit this property, leaving them reliant on the driver default. Since other devices in this same DTS already use explicit firmware-name entries (e.g., zap-shader, remoteproc_cdsp), adding it here would enable per-channel and board-variant firmware tuning.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@patch/kernel/archive/sm8550-7.0/0036-arm64-dts-qcom-Add-AYN-QCS8550-Common.patch`
around lines 1084 - 1102, Add an explicit firmware-name property to both AW88166
speaker amp nodes so the driver reads board/channel-specific firmware instead of
falling back to its default: update spk_amp_l (spk_amp_l@34) to include
firmware-name = "aw88166_spk_l.acf" and update spk_amp_r (spk_amp_r@35) to
include firmware-name = "aw88166_spk_r.acf" (or other board-specific filenames
matching your existing naming convention).
patch/kernel/archive/sm8550-7.0/0042-drivers-use-soc-serial-for-wifi-and-bluetooth.patch (2)

99-101: ⚡ Quick win

Remove the commented-out qca_check_bdaddr() call and its __maybe_unused workaround

Disabling the old call by comment rather than deletion leaves dead code and forces the function to be annotated __maybe_unused to suppress warnings. Either keep the function and call it (as a fallback — see the major issue above), or delete both the call site and the function entirely.

♻️ If the function is truly no longer needed, remove it cleanly
-static int __maybe_unused qca_check_bdaddr(struct hci_dev *hdev, const struct qca_fw_config *config)
+static int qca_check_bdaddr(struct hci_dev *hdev, const struct qca_fw_config *config)
 {
 	...
 }

And at the call site:

-	/* Disable reading BD_ADDR from NVM */
-	//err = qca_check_bdaddr(hdev, &config);
-	//if (err)
-	//	return err;
+	/* (call removed — address is set from serial number above) */

Or, preferably, restore the call as a fallback (see the major-issue comment).

Also applies to: 139-141

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@patch/kernel/archive/sm8550-7.0/0042-drivers-use-soc-serial-for-wifi-and-bluetooth.patch`
around lines 99 - 101, The qca_check_bdaddr function was left annotated
__maybe_unused because its call site was commented out; either remove the dead
function and its commented-out invocation together, or re-enable the call and
use qca_check_bdaddr as a proper fallback. Locate the function qca_check_bdaddr
and the commented-out invocation in the Wi‑Fi/BT init path, then either delete
both the function and the commented call, or restore the call so the function is
used (remove __maybe_unused if restored) and ensure error handling follows the
existing fallback logic.

20-20: ⚡ Quick win

Share extern const char *qcom_serial_number via a header instead of duplicating it

Both btqca.c and mac.c carry an identical independent extern declaration. If the definition in socinfo.c ever changes type, both consumers will silently diverge. The declaration belongs in a shared header (e.g., include/linux/soc/qcom/socinfo.h), which both files can include.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@patch/kernel/archive/sm8550-7.0/0042-drivers-use-soc-serial-for-wifi-and-bluetooth.patch`
at line 20, Move the shared declaration for qcom_serial_number into a single
shared header (e.g., socinfo.h): add one declaration for the symbol
qcom_serial_number to that header, include that header from btqca.c and mac.c,
and remove the duplicate extern declarations in those consumers; ensure the
definition in socinfo.c matches the declaration's type and update the include
directives in btqca.c and mac.c so both consume the single header-only
declaration before rebuilding.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@patch/kernel/archive/sm8550-7.0/0018-drm-panel-Add-panel-driver-for-Xm-Plus-XM91080G-base.patch`:
- Around line 23-31: Remove the spurious dependency on BACKLIGHT_CLASS_DEVICE
from the Kconfig for DRM_PANEL_BOE_XM91080G: edit the config block for
DRM_PANEL_BOE_XM91080G and delete the line "depends on BACKLIGHT_CLASS_DEVICE"
(the panel driver panel-boe-xm91080g.c does not include or use the backlight
API), leaving the other dependencies (OF, DRM_MIPI_DSI) and the select
DRM_KMS_HELPER intact so the driver can be built when BACKLIGHT_CLASS_DEVICE=n.

In
`@patch/kernel/archive/sm8550-7.0/0036-arm64-dts-qcom-Add-AYN-QCS8550-Common.patch`:
- Around line 1404-1409: Rename the duplicated node label and node name so the
primary TE suspend state uses the unique name matching its phandle label: change
the node labeled dsi_p_te_suspend currently defined as dsi-s-te-suspend-state to
dsi-p-te-suspend-state; ensure the label remains dsi_p_te_suspend and other
properties (pins, function, drive-strength, bias-pull-down) stay the same so it
no longer conflicts with the existing dsi_s_te_suspend: dsi-s-te-suspend-state
node.

In
`@patch/kernel/archive/sm8550-7.0/0038-arm64-dts-qcom-Add-AYN-Odin2-Mini.patch`:
- Around line 174-181: The hdmi_out_in endpoint's data-lanes value mismatches
the mdss_dsi0_out endpoint causing driver/DSI lane confusion; update the
hdmi_out_in endpoint (symbol: hdmi_out_in) so its data-lanes use the same
numbering as mdss_dsi0_out (symbol: mdss_dsi0_out) — i.e., change data-lanes
from <1 2 3 4> to <0 1 2 3> to follow the standard DSI convention where lane 0
is the clock lane and ensure both endpoints match.

In
`@patch/kernel/archive/sm8550-7.0/0042-drivers-use-soc-serial-for-wifi-and-bluetooth.patch`:
- Around line 279-302: The global qcom_serial_number currently causes a
use-after-free because it points at devm-managed qs->attr.serial_number set in
qcom_socinfo_probe and cleared in qcom_socinfo_remove; fix by making the pointer
RCU-safe: replace direct assignments with rcu_assign_pointer(qcom_serial_number,
qs->attr.serial_number) in qcom_socinfo_probe and
rcu_assign_pointer(qcom_serial_number, NULL) in qcom_socinfo_remove, and update
all consumers (e.g., code in btqca.c and mac.c) to acquire an RCU read-side lock
(rcu_read_lock()), load the pointer via rcu_dereference(qcom_serial_number), use
strlen/strncpy while holding the lock, then rcu_read_unlock(); alternatively, if
you prefer non-RCU semantics, protect qcom_serial_number with a mutex and have
consumers kstrdup the string under that lock before operating on it so they
never touch freed memory.
- Around line 266-267: The log is printing the wrong buffer and using the wrong
format: replace the call that currently logs generated_macaddr.b with one that
logs the installed address ar->mac_addr and use the %pM specifier; i.e., after
ath12k_reverse_mac(...) call, change the ath12k_info invocation to reference
ar->mac_addr and %pM so the log reflects the actual installed MAC (symbols to
edit: ath12k_reverse_mac, ath12k_info, ar->mac_addr, generated_macaddr.b).
- Around line 161-163: Remove the unused static variable static_macaddr (and any
identical dead code pattern like static_bdaddr in btqca.c) to eliminate the
-Wunused-variable warning: locate the declaration of static_macaddr and delete
it (or, if it was intended to be used, wire it into the appropriate
initialization function instead) so no unused static macaddr symbol remains.
- Around line 23-25: The variable static_bdaddr (bdaddr_t static_bdaddr) is
declared but never used, causing -Wunused-variable; remove the entire
static_bdaddr declaration (the block initializing .b = { 0x00, 0x03, 0x7F, 0x33,
0x22, 0x11 }) from the patch so the unused symbol is eliminated and no warning
is generated.
- Around line 119-123: generate_bdaddr_from_serial() can return -EINVAL when
qcom_serial_number is NULL, causing qca_uart_setup() to abort and prevent BT
from coming up; restore the NVM fallback by calling qca_check_bdaddr() when
generate_bdaddr_from_serial() fails with -EINVAL (or when qcom_serial_number is
NULL) instead of returning the error. Update qca_uart_setup() to: call
generate_bdaddr_from_serial(hdev, &generated_bdaddr), if it succeeds use that
address, but if it returns -EINVAL or indicates missing serial, log a warning
and call qca_check_bdaddr(hdev) to attempt NVM-based BD_ADDR; only return a
fatal error if both methods fail. Ensure logs clearly indicate which method
produced the BD_ADDR (serial vs NVM).

---

Nitpick comments:
In
`@patch/kernel/archive/sm8550-7.0/0036-arm64-dts-qcom-Add-AYN-QCS8550-Common.patch`:
- Around line 1084-1102: Add an explicit firmware-name property to both AW88166
speaker amp nodes so the driver reads board/channel-specific firmware instead of
falling back to its default: update spk_amp_l (spk_amp_l@34) to include
firmware-name = "aw88166_spk_l.acf" and update spk_amp_r (spk_amp_r@35) to
include firmware-name = "aw88166_spk_r.acf" (or other board-specific filenames
matching your existing naming convention).

In
`@patch/kernel/archive/sm8550-7.0/0042-drivers-use-soc-serial-for-wifi-and-bluetooth.patch`:
- Around line 99-101: The qca_check_bdaddr function was left annotated
__maybe_unused because its call site was commented out; either remove the dead
function and its commented-out invocation together, or re-enable the call and
use qca_check_bdaddr as a proper fallback. Locate the function qca_check_bdaddr
and the commented-out invocation in the Wi‑Fi/BT init path, then either delete
both the function and the commented call, or restore the call so the function is
used (remove __maybe_unused if restored) and ensure error handling follows the
existing fallback logic.
- Line 20: Move the shared declaration for qcom_serial_number into a single
shared header (e.g., socinfo.h): add one declaration for the symbol
qcom_serial_number to that header, include that header from btqca.c and mac.c,
and remove the duplicate extern declarations in those consumers; ensure the
definition in socinfo.c matches the declaration's type and update the include
directives in btqca.c and mac.c so both consume the single header-only
declaration before rebuilding.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 828cc796-b6bd-4828-9d8e-fa156f50a311

📥 Commits

Reviewing files that changed from the base of the PR and between 7f95f87 and 7e851a4.

📒 Files selected for processing (47)
  • config/kernel/linux-sm8550-edge.config
  • config/sources/families/sm8550.conf
  • patch/kernel/archive/sm8550-7.0/0001-msm-adreno-enable-A32.patch
  • patch/kernel/archive/sm8550-7.0/0002-qcom-dispcc-sm8550-Fix-disp_cc_mdss_mdp_clk_src.patch
  • patch/kernel/archive/sm8550-7.0/0003-input-rmi4-add-reset-gpio.patch
  • patch/kernel/archive/sm8550-7.0/0004-input-Add-driver-for-RSInput-Gamepad.patch
  • patch/kernel/archive/sm8550-7.0/0005-leds-Add-driver-for-HEROIC-HTR3212.patch
  • patch/kernel/archive/sm8550-7.0/0006-ASoC-qcom-sc8280xp-Add-support-for-Primary-I2S.patch
  • patch/kernel/archive/sm8550-7.0/0007-mmc-sdhci-msm-Toggle-the-FIFO-write-clock-after-unga.patch
  • patch/kernel/archive/sm8550-7.0/0008-ASoC-codecs-aw88166-AYN-SM8550-Specific-modification.patch
  • patch/kernel/archive/sm8550-7.0/0009-arm64-dts-qcom-Added-pmk8550_pwm.patch
  • patch/kernel/archive/sm8550-7.0/0010-gpu-panel-add-Pocket-ACE-panel-driver.patch
  • patch/kernel/archive/sm8550-7.0/0012-input-touchscreen-porting-downstream-hynitron-driver.patch
  • patch/kernel/archive/sm8550-7.0/0013-qcom_battmgr-Set-battery-name.patch
  • patch/kernel/archive/sm8550-7.0/0014-Input-edt-ft5x06-add-no_regmap_bulk_read-option.patch
  • patch/kernel/archive/sm8550-7.0/0016-pwm-Add-SI-EN-SN3112-PWM-support.patch
  • patch/kernel/archive/sm8550-7.0/0017-drm-panel-Add-WIP-panel-driver-for-AYN-Odin-2.patch
  • patch/kernel/archive/sm8550-7.0/0018-drm-panel-Add-panel-driver-for-Xm-Plus-XM91080G-base.patch
  • patch/kernel/archive/sm8550-7.0/0019-drm-panel-Add-panel-driver-for-Chipone-ICNA35XX-base.patch
  • patch/kernel/archive/sm8550-7.0/0020-drm-panel-Add-panel-driver-for-DDIC-CH13726A-based-p.patch
  • patch/kernel/archive/sm8550-7.0/0021-backlight-odin2mini-backlight-Add-support-for-AYN-Od.patch
  • patch/kernel/archive/sm8550-7.0/0022-Input-hynitron_cstxxx-specific-patch-for-Odin2-Mini.patch
  • patch/kernel/archive/sm8550-7.0/0023-Add-Silergy-SY7758-backlight-driver.patch
  • patch/kernel/archive/sm8550-7.0/0024-regulator-add-sgm3804-i2c-regulator-for-panel-power-.patch
  • patch/kernel/archive/sm8550-7.0/0025-input-RSInput-Add-regulator.patch
  • patch/kernel/archive/sm8550-7.0/0026-drm-msm-remove-DRIVER_SYNCOBJ_TIMELINE.patch
  • patch/kernel/archive/sm8550-7.0/0027-HACK-fix-usb-boot-hang.patch
  • patch/kernel/archive/sm8550-7.0/0028-SM8550-Fix-L2-cache-for-CPU2-and-add-cache-sizes.patch
  • patch/kernel/archive/sm8550-7.0/0029-SM8550-Add-DDR-LLCC-L3-CPU-bandwidth-scaling.patch
  • patch/kernel/archive/sm8550-7.0/0030-arm64-dts-qcom-sm8550-Update-EAS-properties.patch
  • patch/kernel/archive/sm8550-7.0/0031-arm64-dts-qcom-sm8550-add-UART15.patch
  • patch/kernel/archive/sm8550-7.0/0032-drm-panel-Add-Retroid-Pocket-6-panel.patch
  • patch/kernel/archive/sm8550-7.0/0033-arm64-dts-qcom-sm8550-Describe-GPU_CC-power-plumbing.patch
  • patch/kernel/archive/sm8550-7.0/0034-interconnect-qcom-sm8550-Enable-QoS-configuration.patch
  • patch/kernel/archive/sm8550-7.0/0035-dts-qcom-sm8550-add-opp-acd-level.patch
  • patch/kernel/archive/sm8550-7.0/0036-arm64-dts-qcom-Add-AYN-QCS8550-Common.patch
  • patch/kernel/archive/sm8550-7.0/0037-arm64-dts-qcom-Add-AYN-Odin2.patch
  • patch/kernel/archive/sm8550-7.0/0038-arm64-dts-qcom-Add-AYN-Odin2-Mini.patch
  • patch/kernel/archive/sm8550-7.0/0039-arm64-dts-qcom-Add-AYN-Odin2-Portal.patch
  • patch/kernel/archive/sm8550-7.0/0040-arm64-dts-qcom-Add-AYN-Thor.patch
  • patch/kernel/archive/sm8550-7.0/0041-ROCKNIX-set-boot-fanspeed.patch
  • patch/kernel/archive/sm8550-7.0/0042-drivers-use-soc-serial-for-wifi-and-bluetooth.patch
  • patch/kernel/archive/sm8550-7.0/0043-power-supply-rename-qcom-battmgr-sysfs.patch
  • patch/kernel/archive/sm8550-7.0/0044-Enable-64-bit-processes-to-use-compat-input-syscalls.patch
  • patch/kernel/archive/sm8550-7.0/0130-restore_widebus_calculation_for_CMDMode_panels.patch
  • patch/kernel/archive/sm8550-7.0/v2_20260314_vladimir_zapolskiy_arm64_dts_qcom_sm8x50_enable_uhs_i_sdr50_and_sdr104_sd_card_modes.patch
  • patch/kernel/archive/sm8550-7.0/v5_20251120_quic_utiwari_crypto_qce_add_runtime_pm_and_interconnect_bandwidth_scaling_support.patch
✅ Files skipped from review due to trivial changes (12)
  • patch/kernel/archive/sm8550-7.0/0043-power-supply-rename-qcom-battmgr-sysfs.patch
  • patch/kernel/archive/sm8550-7.0/0009-arm64-dts-qcom-Added-pmk8550_pwm.patch
  • patch/kernel/archive/sm8550-7.0/0013-qcom_battmgr-Set-battery-name.patch
  • patch/kernel/archive/sm8550-7.0/0001-msm-adreno-enable-A32.patch
  • patch/kernel/archive/sm8550-7.0/0002-qcom-dispcc-sm8550-Fix-disp_cc_mdss_mdp_clk_src.patch
  • patch/kernel/archive/sm8550-7.0/0031-arm64-dts-qcom-sm8550-add-UART15.patch
  • patch/kernel/archive/sm8550-7.0/0021-backlight-odin2mini-backlight-Add-support-for-AYN-Od.patch
  • patch/kernel/archive/sm8550-7.0/v2_20260314_vladimir_zapolskiy_arm64_dts_qcom_sm8x50_enable_uhs_i_sdr50_and_sdr104_sd_card_modes.patch
  • patch/kernel/archive/sm8550-7.0/0041-ROCKNIX-set-boot-fanspeed.patch
  • patch/kernel/archive/sm8550-7.0/0039-arm64-dts-qcom-Add-AYN-Odin2-Portal.patch
  • patch/kernel/archive/sm8550-7.0/0024-regulator-add-sgm3804-i2c-regulator-for-panel-power-.patch
  • patch/kernel/archive/sm8550-7.0/0005-leds-Add-driver-for-HEROIC-HTR3212.patch
🚧 Files skipped from review as they are similar to previous changes (21)
  • config/sources/families/sm8550.conf
  • patch/kernel/archive/sm8550-7.0/0027-HACK-fix-usb-boot-hang.patch
  • patch/kernel/archive/sm8550-7.0/0022-Input-hynitron_cstxxx-specific-patch-for-Odin2-Mini.patch
  • patch/kernel/archive/sm8550-7.0/0025-input-RSInput-Add-regulator.patch
  • patch/kernel/archive/sm8550-7.0/0030-arm64-dts-qcom-sm8550-Update-EAS-properties.patch
  • patch/kernel/archive/sm8550-7.0/0035-dts-qcom-sm8550-add-opp-acd-level.patch
  • patch/kernel/archive/sm8550-7.0/0040-arm64-dts-qcom-Add-AYN-Thor.patch
  • patch/kernel/archive/sm8550-7.0/0020-drm-panel-Add-panel-driver-for-DDIC-CH13726A-based-p.patch
  • patch/kernel/archive/sm8550-7.0/0006-ASoC-qcom-sc8280xp-Add-support-for-Primary-I2S.patch
  • patch/kernel/archive/sm8550-7.0/0014-Input-edt-ft5x06-add-no_regmap_bulk_read-option.patch
  • patch/kernel/archive/sm8550-7.0/0010-gpu-panel-add-Pocket-ACE-panel-driver.patch
  • config/kernel/linux-sm8550-edge.config
  • patch/kernel/archive/sm8550-7.0/0016-pwm-Add-SI-EN-SN3112-PWM-support.patch
  • patch/kernel/archive/sm8550-7.0/0008-ASoC-codecs-aw88166-AYN-SM8550-Specific-modification.patch
  • patch/kernel/archive/sm8550-7.0/0017-drm-panel-Add-WIP-panel-driver-for-AYN-Odin-2.patch
  • patch/kernel/archive/sm8550-7.0/0029-SM8550-Add-DDR-LLCC-L3-CPU-bandwidth-scaling.patch
  • patch/kernel/archive/sm8550-7.0/0032-drm-panel-Add-Retroid-Pocket-6-panel.patch
  • patch/kernel/archive/sm8550-7.0/0023-Add-Silergy-SY7758-backlight-driver.patch
  • patch/kernel/archive/sm8550-7.0/0028-SM8550-Fix-L2-cache-for-CPU2-and-add-cache-sizes.patch
  • patch/kernel/archive/sm8550-7.0/0004-input-Add-driver-for-RSInput-Gamepad.patch
  • patch/kernel/archive/sm8550-7.0/0037-arm64-dts-qcom-Add-AYN-Odin2.patch

Comment on lines +23 to +31
+config DRM_PANEL_BOE_XM91080G
+ tristate "Xm-Plus XM91080G-based panels"
+ depends on OF
+ depends on DRM_MIPI_DSI
+ depends on BACKLIGHT_CLASS_DEVICE
+ select DRM_KMS_HELPER
+ help
+ Say Y if you want to enable support for panels based on the
+ Xm-Plus XM91080G controller.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Remove spurious depends on BACKLIGHT_CLASS_DEVICE.

The driver (panel-boe-xm91080g.c) includes no backlight headers and makes zero calls into the backlight class device API. The depends on BACKLIGHT_CLASS_DEVICE constraint is not only unused — it unnecessarily prevents the driver from being enabled in configurations where BACKLIGHT_CLASS_DEVICE=n, which is a valid build scenario for minimal embedded targets.

🔧 Proposed fix
 config DRM_PANEL_BOE_XM91080G
 	tristate "Xm-Plus XM91080G-based panels"
 	depends on OF
 	depends on DRM_MIPI_DSI
-	depends on BACKLIGHT_CLASS_DEVICE
 	select DRM_KMS_HELPER
 	help
 	  Say Y if you want to enable support for panels based on the
 	  Xm-Plus XM91080G controller.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
+config DRM_PANEL_BOE_XM91080G
+ tristate "Xm-Plus XM91080G-based panels"
+ depends on OF
+ depends on DRM_MIPI_DSI
+ depends on BACKLIGHT_CLASS_DEVICE
+ select DRM_KMS_HELPER
+ help
+ Say Y if you want to enable support for panels based on the
+ Xm-Plus XM91080G controller.
config DRM_PANEL_BOE_XM91080G
tristate "Xm-Plus XM91080G-based panels"
depends on OF
depends on DRM_MIPI_DSI
select DRM_KMS_HELPER
help
Say Y if you want to enable support for panels based on the
Xm-Plus XM91080G controller.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@patch/kernel/archive/sm8550-7.0/0018-drm-panel-Add-panel-driver-for-Xm-Plus-XM91080G-base.patch`
around lines 23 - 31, Remove the spurious dependency on BACKLIGHT_CLASS_DEVICE
from the Kconfig for DRM_PANEL_BOE_XM91080G: edit the config block for
DRM_PANEL_BOE_XM91080G and delete the line "depends on BACKLIGHT_CLASS_DEVICE"
(the panel driver panel-boe-xm91080g.c does not include or use the backlight
API), leaving the other dependencies (OF, DRM_MIPI_DSI) and the select
DRM_KMS_HELPER intact so the driver can be built when BACKLIGHT_CLASS_DEVICE=n.

Comment on lines +1404 to +1409
+ dsi_p_te_suspend: dsi-s-te-suspend-state {
+ pins = "gpio86";
+ function = "mdp_vsync";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

python - <<'PY'
import pathlib, re, collections

path = pathlib.Path("patch/kernel/archive/sm8550-7.0/0036-arm64-dts-qcom-Add-AYN-QCS8550-Common.patch")
added = []
for line in path.read_text().splitlines():
    if line.startswith("+++"):
        continue
    if line.startswith("+"):
        added.append(line[1:])

text = "\n".join(added)
names = re.findall(r'^\s*(?:[A-Za-z0-9_]+:\s+)?([A-Za-z0-9,_-]+)\s*\{', text, re.M)
for name, count in collections.Counter(names).items():
    if name == "dsi-s-te-suspend-state":
        print(f"{name}: {count}")
PY

Repository: armbian/build

Length of output: 83


🏁 Script executed:

sed -n '1395,1415p' patch/kernel/archive/sm8550-7.0/0036-arm64-dts-qcom-Add-AYN-QCS8550-Common.patch

Repository: armbian/build

Length of output: 478


🏁 Script executed:

sed -n '1420,1445p' patch/kernel/archive/sm8550-7.0/0036-arm64-dts-qcom-Add-AYN-QCS8550-Common.patch

Repository: armbian/build

Length of output: 558


Rename the primary TE suspend state node.

Line 1404 defines dsi_p_te_suspend: dsi-s-te-suspend-state, which has the same node name as dsi_s_te_suspend: dsi-s-te-suspend-state at line 1432. In DTS, sibling nodes with identical names merge or conflict, causing compiler errors or unpredictable behavior. The first node must be renamed to dsi-p-te-suspend-state to match its phandle label convention.

Suggested fix
-	dsi_p_te_suspend: dsi-s-te-suspend-state {
+	dsi_p_te_suspend: dsi-p-te-suspend-state {
 		pins = "gpio86";
 		function = "mdp_vsync";
 		drive-strength = <2>;
 		bias-pull-down;
 	};
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
+ dsi_p_te_suspend: dsi-s-te-suspend-state {
+ pins = "gpio86";
+ function = "mdp_vsync";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
dsi_p_te_suspend: dsi-p-te-suspend-state {
pins = "gpio86";
function = "mdp_vsync";
drive-strength = <2>;
bias-pull-down;
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@patch/kernel/archive/sm8550-7.0/0036-arm64-dts-qcom-Add-AYN-QCS8550-Common.patch`
around lines 1404 - 1409, Rename the duplicated node label and node name so the
primary TE suspend state uses the unique name matching its phandle label: change
the node labeled dsi_p_te_suspend currently defined as dsi-s-te-suspend-state to
dsi-p-te-suspend-state; ensure the label remains dsi_p_te_suspend and other
properties (pins, function, drive-strength, bias-pull-down) stay the same so it
no longer conflicts with the existing dsi_s_te_suspend: dsi-s-te-suspend-state
node.

Comment on lines +174 to +181
+ port@0 {
+ reg = <0>;
+
+ hdmi_out_in: endpoint {
+ data-lanes = <1 2 3 4>;
+ remote-endpoint = <&mdss_dsi0_out>;
+ };
+ };
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check data-lanes usage patterns in other SM8550 DTS files
echo "=== DSI data-lanes patterns in sm8550 DTS files ==="
rg -n "data-lanes" --glob "*sm8550*.dts*" --glob "*qcs8550*.dts*"

echo ""
echo "=== mdss_dsi0_out configurations in qcom DTS ==="
ast-grep --pattern 'mdss_dsi0_out {
  $$$
}'

Repository: armbian/build

Length of output: 326


🏁 Script executed:

# Read the patch file to see the full context
cat -n patch/kernel/archive/sm8550-7.0/0038-arm64-dts-qcom-Add-AYN-Odin2-Mini.patch | sed -n '170,210p'

Repository: armbian/build

Length of output: 994


🏁 Script executed:

# Search for data-lanes in all patch files and other configs
echo "=== data-lanes in patch files ==="
rg -n "data-lanes" patch/kernel/archive/ -t patch

echo ""
echo "=== Search for mdss_dsi in patch files ==="
rg -n "mdss_dsi" patch/kernel/archive/sm8550-7.0/ -t patch | head -50

Repository: armbian/build

Length of output: 213


🏁 Script executed:

# Look for other HDMI bridge configurations in the patch directory
echo "=== HDMI/DSI bridge configs ==="
rg -n "lt8912|hdmi" patch/kernel/archive/sm8550-7.0/ -t patch -i | head -30

Repository: armbian/build

Length of output: 137


🏁 Script executed:

# Search for mdss_dsi0_out in source code and documentation
echo "=== mdss_dsi0_out in source directories ==="
rg -n "mdss_dsi0_out" --max-count=20

echo ""
echo "=== DSI data-lanes patterns in source ==="
rg "data-lanes.*=" -B2 -A2 --max-count=20 | head -100

Repository: armbian/build

Length of output: 12909


🏁 Script executed:

# Look for kernel documentation on DSI lanes
echo "=== Search for DSI lane documentation ==="
find . -type f \( -name "*.md" -o -name "*.txt" -o -name "*.rst" \) | xargs grep -l "data-lanes\|DSI.*lane" 2>/dev/null | head -10

Repository: armbian/build

Length of output: 99


🏁 Script executed:

# Search for other sm8550 related DTS or device tree files in the repo
echo "=== SM8550 DTS related files ==="
fd -t f "sm8550" | head -20

Repository: armbian/build

Length of output: 1533


🏁 Script executed:

# Search for LT8912 bridge driver and configuration
echo "=== LT8912 references in repo ==="
rg -i "lt8912" -A5 -B5 | head -100

Repository: armbian/build

Length of output: 8617


🏁 Script executed:

# Check kernel/linux directory for any bridge documentation or driver stubs
echo "=== Searching for bridge-related DT bindings documentation ==="
find . -type f \( -name "*.md" -o -name "*.txt" -o -name "*.rst" \) | xargs grep -l "lt8912\|hdmi.*bridge" 2>/dev/null

Repository: armbian/build

Length of output: 122


🏁 Script executed:

# Search patch comments or commit messages for LT8912 lane explanations
echo "=== Checking patch files for LT8912 context ==="
rg -n "lt8912|hdmi.*bridge" patch/kernel/archive/sm8550-7.0/0038 -B10 -A10 | head -80

Repository: armbian/build

Length of output: 200


🏁 Script executed:

# Search for any upstream kernel references or comments about LT8912B
echo "=== Checking for kernel driver stubs or references ==="
find . -type f -name "*.c" -o -name "*.h" | xargs grep -l "lt8912\|lontium" 2>/dev/null | head -20

Repository: armbian/build

Length of output: 112


🌐 Web query:

LT8912B kernel driver data-lanes DSI HDMI bridge configuration lane mapping

💡 Result:

The LT8912B MIPI DSI to HDMI bridge kernel driver (drivers/gpu/drm/bridge/lontium-lt8912b.c) configures data lanes through standard Linux DRM device tree bindings. Configuration: - Device tree port@0 endpoint requires 'data-lanes' property: array of lane indices (0-based) mapping DSI controller lanes to LT8912B physical pins, e.g., data-lanes = <1 2 3 4>; (ConnectCore 93) or <0 1 2 3>; (binding example). Supports 1-4 lanes. - Driver parses with drm_of_get_data_lanes_count_ep(dev->of_node, 0, -1, 1, 4), storing count in lt->data_lanes. - Sets mipi_dsi_device->lanes = lt->data_lanes. - Programs LT8912B register 0x13 (I2C_CEC_DSI bus) = lt->data_lanes & 3 (2-bit count value, e.g., 1=0x1, 2=0x2, 3=0x3, 4=0x0?). No explicit lane remapping/swizzling in driver; follows standard data-lanes convention where array order defines sequential mapping (index 0=first data lane, etc.). Hardware pinout per LT8912B datasheet (1 clock + 1-4 data lanes). Binding mandates data-lanes on DSI input endpoint.

Citations:


DSI data-lanes mismatch between bridge input and DSI output endpoints requires correction.

The hdmi_out_in endpoint specifies data-lanes = <1 2 3 4> while mdss_dsi0_out specifies data-lanes = <0 1 2 3>. The LT8912B kernel driver parses these values directly without any lane remapping and passes them to the DSI device. Standard DSI convention uses lane 0 for clock with data lanes numbered 1–4, making these specifications incompatible. Both endpoints must use the same lane numbering for correct operation.

This mismatch likely contributes to the DRM/display failures reported in the PR comments ("enc33 frame done timeout"). Align the data-lanes specifications on both endpoints—either both <0 1 2 3> or both <1 2 3 4>.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@patch/kernel/archive/sm8550-7.0/0038-arm64-dts-qcom-Add-AYN-Odin2-Mini.patch`
around lines 174 - 181, The hdmi_out_in endpoint's data-lanes value mismatches
the mdss_dsi0_out endpoint causing driver/DSI lane confusion; update the
hdmi_out_in endpoint (symbol: hdmi_out_in) so its data-lanes use the same
numbering as mdss_dsi0_out (symbol: mdss_dsi0_out) — i.e., change data-lanes
from <1 2 3 4> to <0 1 2 3> to follow the standard DSI convention where lane 0
is the clock lane and ensure both endpoints match.

Comment on lines +23 to +25
+static const bdaddr_t static_bdaddr = {
+ .b = { 0x00, 0x03, 0x7F, 0x33, 0x22, 0x11 }
+};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

static_bdaddr is declared but never used — remove it

This variable is a leftover from development and will produce a -Wunused-variable compiler warning. Many kernel build configurations treat warnings as errors.

🗑️ Proposed fix
-/* Define a static, predefined BD_ADDR structure */
-static const bdaddr_t static_bdaddr = {
-	.b = { 0x00, 0x03, 0x7F, 0x33, 0x22, 0x11 }
-};
-
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@patch/kernel/archive/sm8550-7.0/0042-drivers-use-soc-serial-for-wifi-and-bluetooth.patch`
around lines 23 - 25, The variable static_bdaddr (bdaddr_t static_bdaddr) is
declared but never used, causing -Wunused-variable; remove the entire
static_bdaddr declaration (the block initializing .b = { 0x00, 0x03, 0x7F, 0x33,
0x22, 0x11 }) from the patch so the unused symbol is eliminated and no warning
is generated.

Comment on lines +119 to +123
+ err = generate_bdaddr_from_serial(hdev, &generated_bdaddr);
+ if (err) {
+ bt_dev_err(hdev, "Failed to generate BD_ADDR from serial number");
+ return err;
+ }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Hard fatal failure when serial number is unavailable — no fallback

If qcom_serial_number is NULL (e.g., SMEM serial number absent, or socinfo not probed yet due to deferred init ordering), generate_bdaddr_from_serial() returns -EINVAL and qca_uart_setup() propagates it as a fatal error — BT will not come up at all. The previous qca_check_bdaddr() fallback (NVM-based address) is entirely removed.

For robustness, especially for any future SM8550 board that doesn't populate the SMEM serial field, the NVM path should be the fallback rather than a hard failure:

💡 Suggested approach
-	/* Generate BD_ADDR from qcom_serial_number */
-	err = generate_bdaddr_from_serial(hdev, &generated_bdaddr);
-	if (err) {
-		bt_dev_err(hdev, "Failed to generate BD_ADDR from serial number");
-		return err;
-	}
-
-	/* Set the generated BD_ADDR */
-	err = qca_set_bdaddr(hdev, &generated_bdaddr);
-	if (err) {
-		bt_dev_err(hdev, "Failed to set the generated BD_ADDR from serial number");
+	err = generate_bdaddr_from_serial(hdev, &generated_bdaddr);
+	if (!err) {
+		err = qca_set_bdaddr(hdev, &generated_bdaddr);
+		if (err) {
+			bt_dev_err(hdev, "Failed to set BD_ADDR from serial number");
+			return err;
+		}
+		bacpy(&hdev->public_addr, &generated_bdaddr);
+		bacpy(&hdev->bdaddr, &generated_bdaddr);
+		bt_dev_info(hdev, "BD_ADDR set to %pMR", &hdev->public_addr);
+	} else {
+		bt_dev_warn(hdev, "Serial-based BD_ADDR unavailable, falling back to NVM");
+		err = qca_check_bdaddr(hdev, &config);
+		if (err)
 		return err;
 	}
-
-	/* Update hdev->public_addr and hdev->bdaddr */
-	bacpy(&hdev->public_addr, &generated_bdaddr);
-	bacpy(&hdev->bdaddr, &generated_bdaddr);
-	bt_dev_info(hdev, "BD_ADDR set to %pMR", &hdev->public_addr);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@patch/kernel/archive/sm8550-7.0/0042-drivers-use-soc-serial-for-wifi-and-bluetooth.patch`
around lines 119 - 123, generate_bdaddr_from_serial() can return -EINVAL when
qcom_serial_number is NULL, causing qca_uart_setup() to abort and prevent BT
from coming up; restore the NVM fallback by calling qca_check_bdaddr() when
generate_bdaddr_from_serial() fails with -EINVAL (or when qcom_serial_number is
NULL) instead of returning the error. Update qca_uart_setup() to: call
generate_bdaddr_from_serial(hdev, &generated_bdaddr), if it succeeds use that
address, but if it returns -EINVAL or indicates missing serial, log a warning
and call qca_check_bdaddr(hdev) to attempt NVM-based BD_ADDR; only return a
fatal error if both methods fail. Ensure logs clearly indicate which method
produced the BD_ADDR (serial vs NVM).

Comment on lines +161 to +163
+static const struct macaddr_t static_macaddr = {
+ .b = { 0x00, 0x03, 0x7F, 0x11, 0x22, 0x33 }
+};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

static_macaddr is declared but never used — remove it

Identical issue to static_bdaddr in btqca.c; will generate a -Wunused-variable warning.

🗑️ Proposed fix
-/* Define a static, predefined MAC_ADDR structure */
-static const struct macaddr_t static_macaddr = {
-	.b = { 0x00, 0x03, 0x7F, 0x11, 0x22, 0x33 }
-};
-
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@patch/kernel/archive/sm8550-7.0/0042-drivers-use-soc-serial-for-wifi-and-bluetooth.patch`
around lines 161 - 163, Remove the unused static variable static_macaddr (and
any identical dead code pattern like static_bdaddr in btqca.c) to eliminate the
-Wunused-variable warning: locate the declaration of static_macaddr and delete
it (or, if it was intended to be used, wire it into the appropriate
initialization function instead) so no unused static macaddr symbol remains.

Comment on lines +266 to +267
+ ath12k_reverse_mac(ar->mac_addr, generated_macaddr.b);
+ ath12k_info(ab, "MAC_ADDR set to %pMR", generated_macaddr.b);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Log reports the wrong variable with the wrong format specifier

Line 267 logs generated_macaddr.b (the pre-reversal intermediate buffer) using %pMR, rather than ar->mac_addr (the value actually installed) using %pM. The displayed address happens to be numerically correct by a double-reversal coincidence, but the intent is opaque and fragile — any future change to the reversal logic will silently produce an incorrect log.

🐛 Proposed fix
-		ath12k_reverse_mac(ar->mac_addr, generated_macaddr.b);
-		ath12k_info(ab, "MAC_ADDR set to %pMR", generated_macaddr.b);
+		ath12k_reverse_mac(ar->mac_addr, generated_macaddr.b);
+		ath12k_info(ab, "MAC_ADDR set to %pM", ar->mac_addr);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
+ ath12k_reverse_mac(ar->mac_addr, generated_macaddr.b);
+ ath12k_info(ab, "MAC_ADDR set to %pMR", generated_macaddr.b);
ath12k_reverse_mac(ar->mac_addr, generated_macaddr.b);
ath12k_info(ab, "MAC_ADDR set to %pM", ar->mac_addr);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@patch/kernel/archive/sm8550-7.0/0042-drivers-use-soc-serial-for-wifi-and-bluetooth.patch`
around lines 266 - 267, The log is printing the wrong buffer and using the wrong
format: replace the call that currently logs generated_macaddr.b with one that
logs the installed address ar->mac_addr and use the %pM specifier; i.e., after
ath12k_reverse_mac(...) call, change the ath12k_info invocation to reference
ar->mac_addr and %pM so the log reflects the actual installed MAC (symbols to
edit: ath12k_reverse_mac, ath12k_info, ar->mac_addr, generated_macaddr.b).

Comment on lines +279 to +302
+/* Global variable to hold the serial number */
+const char *qcom_serial_number;
+EXPORT_SYMBOL(qcom_serial_number);
+
struct qcom_socinfo {
struct soc_device *soc_dev;
struct soc_device_attribute attr;
@@ -891,6 +895,9 @@ static int qcom_socinfo_probe(struct platform_device *pdev)
le32_to_cpu(info->serial_num));
if (!qs->attr.serial_number)
return -ENOMEM;
+
+ /* Assign the serial number to the global variable */
+ qcom_serial_number = qs->attr.serial_number;
}

qs->soc_dev = soc_device_register(&qs->attr);
@@ -914,6 +921,9 @@ static void qcom_socinfo_remove(struct platform_device *pdev)
soc_device_unregister(qs->soc_dev);

socinfo_debugfs_exit(qs);
+
+ /* Clear the global serial number */
+ qcom_serial_number = NULL;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Use-after-free race on qcom_serial_number

The global pointer is assigned during probe and cleared in remove(), but the memory it references (qs->attr.serial_number, a kasprintf-allocated string managed by devm) is freed only after remove() returns. A concurrent consumer in btqca.c or mac.c can:

  1. Read the non-NULL pointer into a local serial variable.
  2. qcom_socinfo_remove() runs, sets qcom_serial_number = NULL, returns.
  3. Platform core frees the devm memory (qs->attr.serial_number).
  4. Consumer calls strlen(serial)use-after-free.

The if (!serial) NULL-check in each consumer guards against a NULL pointer but not against freed memory, because the local serial captures the pointer value before the NULL-set.

The fix requires either:

  • RCU: export with rcu_assign_pointer / clear with rcu_assign_pointer(qcom_serial_number, NULL), and consumers use rcu_read_lock() + rcu_dereference() + hold the read-lock for the duration of strlen/strncpy.
  • A mutex or kstrdup-based copy: make consumers take a copy under a lock and operate on the copy.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@patch/kernel/archive/sm8550-7.0/0042-drivers-use-soc-serial-for-wifi-and-bluetooth.patch`
around lines 279 - 302, The global qcom_serial_number currently causes a
use-after-free because it points at devm-managed qs->attr.serial_number set in
qcom_socinfo_probe and cleared in qcom_socinfo_remove; fix by making the pointer
RCU-safe: replace direct assignments with rcu_assign_pointer(qcom_serial_number,
qs->attr.serial_number) in qcom_socinfo_probe and
rcu_assign_pointer(qcom_serial_number, NULL) in qcom_socinfo_remove, and update
all consumers (e.g., code in btqca.c and mac.c) to acquire an RCU read-side lock
(rcu_read_lock()), load the pointer via rcu_dereference(qcom_serial_number), use
strlen/strncpy while holding the lock, then rcu_read_unlock(); alternatively, if
you prefer non-RCU semantics, protect qcom_serial_number with a mutex and have
consumers kstrdup the string under that lock before operating on it so they
never touch freed memory.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

05 Milestone: Second quarter release Hardware Hardware related like kernel, U-Boot, ... Needs review Seeking for review Patches Patches related to kernel, U-Boot, ... size/large PR with 250 lines or more

Development

Successfully merging this pull request may close these issues.

3 participants