rear imx363 is at 0x1a on blueline, shipped in r162 on edge with the rotation fix; blueline-camera 1-1 owns the userspace half. fingerprint row catches up to its own task doc: wall down, protocol recovered.
165 lines
8 KiB
Markdown
165 lines
8 KiB
Markdown
# TASK 46 — Camera
|
||
|
||
**Status:** front pair proven on glass 2026-07-29. Rear IMX363 wired
|
||
(`c7784b716`), answers at **0x1a** (`8fc7623a3`), rotation corrected
|
||
(`457a667bd`) — all three on `blueline`, shipped as
|
||
`linux-blueline-7.1.1.r162.g457a667bd3eb-1` on edge. Userspace half shipped as
|
||
`blueline-camera` 1-1. Left: exposure/gain controls and a fresh acceptance pass
|
||
on glass. **Repos:** `Fimeg/linux-blueline` (canonical kernel), `Pixel3Arch`
|
||
(DT, packages).
|
||
|
||
## 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)
|
||
|
||
```sh
|
||
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**. `RG10` is rejected; the format
|
||
that matches SRGGB10 is **`pRAA`** (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 `i` taking `(b4 >> 2i) & 3`.
|
||
- Black level is ~64 in 10-bit (the `0x10` floor visible in a raw hexdump).
|
||
Subtract it before scaling or everything is a flat grey field.
|
||
- **`cam` / `qcam` (libcamera) are NOT installed.** `media-ctl` and `v4l2-ctl`
|
||
are. 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 path is finished and shipped (see status). The userspace half is done
|
||
too: `blueline-camera` 1-1 — libcamera's simple-pipeline soft-ISP exported
|
||
through PipeWire, so a portal consumer sees a real camera — built by Pixel3Arch
|
||
CI and published into the shared multi-producer edge archive. Recipe:
|
||
`Pixel3Arch/pkgs/blueline-camera`. Remaining: exposure/gain controls
|
||
(`v4l2-ctl --list-ctrls` on the sensor subdev), a fresh acceptance pass on
|
||
glass for the rear path, 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` → new
|
||
`camera_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
|
||
- `camss` port@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 —
|
||
landed on `blueline`, which also carries the rotation fix. Trap with a date:
|
||
on 2026-08-20 both local kernel clones read that commit as missing, because
|
||
their `origin` points at the sibling checkout and neither had ever fetched the
|
||
forge branches. Fetch from `Fimeg/linux-blueline` before declaring a commit
|
||
lost. `mic-race-fix` still sits at the 0x10 state and is superseded by
|
||
`blueline`; fold or delete it.
|
||
|
||
**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 -p` enumerates a pipeline and the rear sensor probes.
|
||
- `v4l2-ctl` streams 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).
|