Skip to content

Latest commit

 

History

History
76 lines (50 loc) · 6.01 KB

File metadata and controls

76 lines (50 loc) · 6.01 KB

Design decisions

Why this fix takes the shape it does. Background reading for anyone debugging mainline CAMSS on SM7125 or porting to a sibling Atoll SoC.

The bug in upstream

drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c in the sm7125-mainline/linux tree ships a 5-lane × 23-entry table labeled /* GEN2 1.2.2 2PH */. The label is correct (SM7125 is v1.2.2). The contents are a botched hybrid:

  • Lane 0 first six entries hit 0x0900..0x0910 — those are 3-phase / combo-mode register offsets, not 2PH.
  • Lane 0 entry for register 0x0000 writes value 0x91. The downstream Qualcomm reference (cam_csiphy_1_2_2_hwreg.h::csiphy_2ph_v1_2_2_reg[0]) writes 0xD4 there.
  • Per-lane base offset for v1.2.2 is 0x200; the upstream table uses 0x100 spacing (SC7180-class). Lane 1's writes therefore hit lane 0's bank etc.
  • Several common-control writes the v1.2.2 silicon requires before per-lane programming are missing entirely.

Net effect: CSIPHY appears to bring up — s_stream(1) returns 0, sensor power-on completes, CCI register writes flow, CSIPHY IRQ counter stays at 0 (error-only IRQs, no errors fired) — but no MIPI packets reach CSID. CSID0 IRQ counter stays at 0 throughout VIDIOC_STREAMON, capture file is 0 bytes, dmesg is silent.

Silicon identification

Downstream arch/arm64/boot/dts/qcom/atoll-camera.dtsi declares compatible = "qcom,csiphy-v1.2.2" for all four CSIPHYs. The downstream cam_csiphy_soc.c driver maps that compatible to cam_csiphy_1_2_2_hwreg.h + CSI_3PHASE_HW_12.

Upstream's csiphy_hw_version_read uses the SHOW_REV_ID strobe trick: write BIT(1) to CTRLn(6) = 0x818, then read 4 bytes from STATUSn(12..15) = 0x8e0..0x8ec and compose. On joyeuse:

qcom-camss acb3000.camss: CSIPHY 3PH HW Version = 0x40010000

The 4 bytes are a Qualcomm vendor composite, not a packed {gen, rev, stepping} word — upstream dev_dbgs the raw value without decoding. Bytes [0x00, 0x00, 0x01, 0x40] correspond to v1.2.2 silicon when cross-referenced with downstream rev-ID readbacks.

Why not add a new compatible

A clean upstream-shape patch would:

  • Add enum camss_version { ..., CAMSS_7125 } in camss.h
  • Add lane_regs_sm7125[5][19] separately from lane_regs_sc7180
  • Add sm7125_resources struct reusing SC7180 csiphy/csid/vfe/icc sub-resources
  • Add { .compatible = "qcom,sm7125-camss", .data = &sm7125_resources } to camss_dt_match[]
  • Override the camss compatible in sm7125.dtsi (which currently inherits SC7180's via #include)

That's a DT change and a .h enum change. Per the project's constraint of no /boot writes and no kernel-image rebuild (the goal is a .ko swap, not a fresh kernel + DTB flash), the DT change is non-starter for an on-device fix.

This patch instead hijacks the SC7180 case: replace lane_regs_sc7180[][] body in-place with the v1.2.2 content. pmaports/device/testing/linux-postmarketos-qcom-sm7125 is SM7125-only, so no SC7180-class device consumes this .ko. The upstream-friendly form is the path for linux-media@vger.kernel.org; the hijack form is the path for the running phone.

The two missing writes

Patch 2 adds two writes to csiphy_lanes_enable:

writel_relaxed(0x02, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(0));   /* v1.2.2 PHY-enable */
writel_relaxed(0x01, csiphy->base + 0x0884);                                /* CTRLn(33) kickoff */

Both come from downstream csiphy_common_reg_1_2_2[5]. Upstream's csiphy_lanes_enable matches 3 of the 5 downstream common writes by computing the equivalent value at runtime (CTRL5 lane mask, CTRL6 PWRDN_B, CTRL7 = 0x02). The other 2 are missing:

  • CTRL0 = 0x02 (downstream writes 0x02; upstream writes 0x00). On v1.2.2 this is the top-level PHY-enable bit. With 0x00, the lane table loads but the PHY top stays in standby.
  • CTRLn(33) = 0x01. The lane-config-done strobe. Latches the preceding writes onto the analog plane. Without it, even with PHY-enable set, MIPI symbol lock doesn't fire.

Both must land in the same csiphy_lanes_enable call. Order matters: lane table walk first, then these two writes, then the IRQ-mask loop.

Why the lane register layout differs

v1.0/v1.1 PHYs (sdm845, sc7180, sc8280xp class) use 0x100 per-lane spacing in one register cluster. v1.2.x PHYs (sm6350 = v1.2.3, atoll = v1.2.2, sm6125/sm6150 = v1.2) use 0x200 spacing with an auxiliary register cluster at 0x900+. Programming a v1.2.2 PHY with v1.0/v1.1 register addresses hits the wrong fields (or unmapped MMIO regions that return 0).

The PHY-rev mapping per public source:

SoC upstream lane_regs_* Rev (per downstream)
SDM845 lane_regs_sdm845 v1.0
SC7180 lane_regs_sc7180 (annotated 1.2.2 but contents wrong) v1.1 (?)
SC8280XP lane_regs_sc8280xp v1.1
SM8250 / SC7280 lane_regs_sm8250 unlabelled
SM6350 (in-flight v4) v1.2.3
SM7125 (Atoll) THIS PATCH v1.2.2

Outstanding bugs not fixed here

  • Hot-reload IRQ leak: modprobe -r qcom-camss; modprobe qcom-camss fails at probe with error -ENXIO: IRQ csiphy0 not found. Reproduces with the unpatched original .ko too. Likely a missed platform_irq_count reset or per-CSIPHY IRQ resource state in camss_remove(). Workaround: cold boot only.
  • SMMU sticky-fault (Bug C): vfe_wm_start enables the VFE write master at STREAMON, but WM_IMAGE_ADDR is programmed in a separate vfe_wm_update call afterwards in a tight loop over pending buffers. If the pending queue is empty at STREAMON instant, WM goes live with stale or zero WM_IMAGE_ADDR. First DMA hits unmapped iova → SMMU SID=0x820 fault → camera black until reboot. Combined with the pre-existing vfe_flush_buffers use-after-vb2_buffer_done (does not NULL output->buf[0/1]), the second-session window is widened. Fix is a two-line move of the WM_CFG_EN write from vfe_wm_start into vfe_wm_update. Planned for v0.2.0.
  • libcamera tuning: no ov16a1q.yaml or s5k5e9.yaml upstream. Stack falls back to uncalibrated.yaml + SoftwareIsp. Preview works but colour calibration is wrong.