And the lesson that cost the front camera: camss creates all sensor->csiphy links in the async notifier's .complete, which needs every declared subdev to bind. One non-probing sensor leaves the working front pair registered with zero links. Never leave a failing sensor node enabled; a rear-disabled DTB is parked on the device for one-cp recovery.
7.1 KiB
TASK 46 — Camera
Status: rear sensor written and building 2026-07-28; the front pair was
already wired. Repo: Pixel3Arch (kernel DT).
THE FRONT CAMERA WORKS — first frame captured 2026-07-29
No reboot, no new kernel, no DT change. On the running kernel
(7.1.1-sdm845-g2bb09876e66a) the whole front path was already live and
nobody had tried it: qcom_camss and imx355 loaded, /dev/media0 +
/dev/video0..13, and both front sensors bound and linked
ENABLED,IMMUTABLE — imx355 17-001a -> msm_csiphy1, imx355 17-0010 ->
msm_csiphy2. The sensor advertises exactly one format,
SRGGB10_1X10/3280x2464.
Captured a real 10,131,968-byte frame off /dev/video0 and debayered it: a
ceiling, a curtain rail with the curtains drawn, a doorframe, a smoke
detector. Correct geometry, correct colour, sane noise. This device has now
produced a camera image.
The exact recipe (RDI raw path, no ISP)
M=/dev/media0
media-ctl -d $M -l '"msm_csiphy1":1 -> "msm_csid0":0 [1]'
media-ctl -d $M -l '"msm_csid0":1 -> "msm_vfe0_rdi0":0 [1]'
F='[fmt:SRGGB10_1X10/3280x2464]'
for p in '"imx355 17-001a":0' '"msm_csiphy1":0' '"msm_csiphy1":1' \
'"msm_csid0":0' '"msm_csid0":1' '"msm_vfe0_rdi0":0' '"msm_vfe0_rdi0":1'; do
media-ctl -d $M -V "$p $F"
done
v4l2-ctl -d /dev/video0 --set-fmt-video=width=3280,height=2464,pixelformat=pRAA
v4l2-ctl -d /dev/video0 --stream-mmap --stream-count=1 --stream-to=/tmp/frame.raw
Gotchas that cost time, so they are written down:
- The node is Video Capture Multiplanar.
RG10is rejected; the format that matches SRGGB10 ispRAA(10-bit Bayer RGRG/GBGB Packed). - The row stride is 4112, not 4100. 3280 px x 10 bits = 4100 bytes of payload; the driver pads each row to 4112. Reshaping by 4100 shears the image diagonally and looks like a broken sensor.
- MIPI RAW10 packing: 4 pixels per 5 bytes — bytes 0-3 are the high 8 bits,
byte 4 packs the four low bit-pairs, pixel
itaking(b4 >> 2i) & 3. - Black level is ~64 in 10-bit (the
0x10floor visible in a raw hexdump). Subtract it before scaling or everything is a flat grey field. cam/qcam(libcamera) are NOT installed.media-ctlandv4l2-ctlare. There is no auto-exposure running, so the frame is whatever the sensor's power-on defaults give — dark indoors, and that is expected, not a fault.
What this changes
The rear IMX363 DT work (c7784b716, branch mic-race-fix) is still worth
finishing, but it is no longer the blocker for "does this phone have a camera".
Next real steps are exposure/gain controls (v4l2-ctl --list-ctrls on the
sensor subdev), then libcamera so something other than a shell script can open
it, then TASK-12's face-auth question.
What was actually missing
A first pass at this said blueline's DT declared no camera at all. Wrong — that
grep only looked at sdm845-google-blueline.dts, and the camera lives in the
sdm845-google-common.dtsi it includes. The real state:
| Piece | State |
|---|---|
| CAMSS driver (Titan 170 ISP) | present, CONFIG_VIDEO_QCOM_CAMSS=m |
imx363.c / imx355.c |
present, both =m |
| Front IMX355 ×2 (CCI1, CSIPHY1+2, ports 1/2) | already declared, with regulators, reset pins and shared MCLK2 |
| Rear IMX363 (CCI0, CSIPHY0, port 0) | was absent — added c7784b716 |
So the front half had been done and the rear was never finished. CSIPHY0 and CCI master 0 sat unused with the driver built and enabled.
What was added (kernel c7784b716, branch mic-race-fix)
Read off the downstream DTBO's cam-sensor@0 (~/pixel3-work/dtbo_9.dts),
which is the same source the front pair's numbers came from — every front value
in the tree matches its downstream node exactly, which is what made the rear
ones trustworthy:
- MCLK0 gpio13, RESET0 gpio80, VANA0 gpio16 (a GPIO switch off BOB, same shape as both front avdd regulators)
vdig→vreg_s3a_1p35,vif→vreg_lvs1_1p8,vana→ newcamera_rear_avdd- 24 MHz MCLK and a 636 MHz link frequency — what the driver's 24 MHz table expects; the front pair runs 19.2 MHz because the imx355 driver wants that
camssport@0 →csiphy0, 4 lanes
Verified by compiling the DTB: 117,471 bytes, no new warnings, every phandle and lane value correct in the decompiled output.
The one guess in it — ANSWERED 2026-08-01, and it cost the front camera
The slave address. 0x10 was Xiaomi beryllium's for the same IMX363, and the
address is in neither the downstream DTBO nor the eeprom node cam-sensor@0
points at (qcom,eeprom@1, phandle 0x25, cci-master = <0x00> — confirms CCI0,
carries no slave-addr). On glass, 0x10 NACKs:
imx363: 4 lanes
imx363 16-0010: Error reading reg 0x0016: -6
imx363 16-0010: failed to read chip id 363
-ENXIO, and imx363_probe() calls imx363_power_on() before
imx363_identify_module(), so the rail, reset and MCLK were all exercised and
nothing answered. Moved to 0x1a (8fc7623a3), the remaining candidate.
The expensive lesson is what a failed sensor probe does to the others.
camss_subdev_notifier_complete() creates every sensor→csiphy link, and
.complete only fires once all declared async subdevs have bound. The rear
sensor never bound, so the notifier never completed, so no sensor links were
created — the front pair stayed registered (entity 235/237) with 0 links
each, and the working front camera stopped working. Adding a broken sensor is
not a contained failure on this driver.
Practical consequence: never leave a non-probing sensor node enabled. A DTB with
the rear status = "disabled" is kept on the device as
/boot/dtbs/sdm845-google-blueline.dtb.rear-off for exactly this — it restores
the front camera in one cp and a reboot.
The DTB is loaded separately by extlinux (fdt /boot/dtbs/...), so testing an
address costs a DTB build and a reboot, not a kernel rebuild.
Acceptance
media-ctl -penumerates a pipeline and the rear sensor probes.v4l2-ctlstreams a frame off it.- A still lands on disk. Colour and tuning are not acceptance — libcamera needs a tuning file and there is none for this unit.
The driver is a WIP snapshot, and that is the next lever
imx363.c in our tree carries commented-out register writes, a commented-out
19.2 MHz link-frequency table, and a literal // NOT SURE HOW TO FIND THIS VALUE against the 636 MHz entry. Two modes only (4032×3024, 1920×1080), no
lens/actuator support — so no autofocus, though the downstream node has an
actuator and an eeprom on the same bus.
Casey has a Matrix conversation with Dylan Van Assche pointing at a newer commit with "all the possible fixes, focus and more". It is not in mainline or linux-next (both checked directly, 404), not in linux-media patchwork, and not on the branches of his GitLab fork or the sdm845-mainline group repo. Get the link from that conversation rather than re-searching — it is the difference between two modes and a working camera.
Connects to
TASK-12 (face auth wants the front sensors, already wired), TASK-40 (a camera stream is the sharpest inference-tiering case on the device), TASK-20 (where captured media would land).