Skip to content

Porting cmos sensor to mainline next

99degree edited this page May 29, 2024 · 21 revisions

Generally speaking this porting is very limited and soc/board dependent.

A very detail how-to is written by Yassine Oudjana, https://emainline.gitlab.io/2022/08/24/camera.html

The devlopment flow is as below:

  1. get camss sybsys on and dump test pattern from csid. Usually a similar soc is available inside camss.c so copy and paste then modify is a key.
  2. Get camcc and CCI up and running, for cmos sensor communication. And this is independent to camss so either doing this or camss first is free to choose.
  3. Enable debug info in vendor kernel, best is to switch on debug options like
    1. /dev/mem for debugcc direct camcc access and dump clk rate/enablement
    2. debugfs for debug_mdl boot param debug change on the fly
    3. Add pr_info in cam_sensor_module/cam_cci, dump all req that written to CCI, for cmos init reg val. Note[a]
  4. Find relevant cmos driver on other soc especially good source from MTK SOCs.
    1. Find/Search from github.com repo for example, search model name s5k5e9/ov16a1q/ov16a1x/gc8034 or its cmos_id like 559b
  5. Determine topoligy of component connection about cmos_sensor and csiphy (c-phy newer, d-phy only atm for camss)
    1. Lane number, and lane assigment (some case might use abnormal lane assigment instead of incremental e.g. [0 1] and [0 1 2], [0, 1 2 3])
  6. Lane clk determination, according to various source, it is 240000000 as usual both in MTK and qcom soc, and 36000000 is also found a case.
  7. Usual case there are cmos product family, so found a similar driver from mainline/mail-list is a good start. Quite funny example, s5k5e9 cmos have very similar reg pattern (almost identical) with imx214. So lets use it as code base.

It is hightly believe that cmos init reg write also depend on d-phy lane number. So lets make use of those value like dummy.

On some platform using libcamera, there are some important v4l control to present. Implement a dummy control to pass the libcamera check is a good choice too.

The debug information of sensor config is at below, it is a s5k5e9 cmos connected to sm7125 soc, aka miatoll phone. https://github.com/99degree/linux/wiki/developing-qcom-camss#get-more-info-from-los-kernel

and the debug procedure is at: https://github.com/99degree/linux/wiki/developing-qcom-camss#debugging-with-vendor-kernel

Custom kernel bootloop

[a] There is a difficulty due to custom local build kernel vs LOS compiled kernel/OS with fs AVB, it fastboot with local kernel, Android eventually reboot. To get around this, need to build the kernel with nothing changed, replace it to the content of LOS boot.img kernel, repack it and most importantly AVB sign it. It is easier to do with https://github.com/cfig/Android_boot_image_editor, ./gradlew unpack and replace kernel, fastboot boot test, flash to boot partition, factory reset data partition. Test normal boot.

Then apply the pr_info debug log into kernel source and recompile as new one. Regenerate test image as above and do test with "fastboot boot". That should be fine.

Calculating settle_cnt for csiphy link_freq

below is a calculation of settle cnt

	#include <stdio.h>
	#include <limits.h>
	#include <stdlib.h>
	typedef int u8;
	typedef int u32;
	typedef long s64;

	static u8 csiphy_settle_cnt_calc(s64 link_freq, u32 timer_clk_rate)
	{
			u32 ui; /* ps */
			u32 timer_period; /* ps */
			u32 t_hs_prepare_max; /* ps */
			u32 t_hs_settle; /* ps */
			u8 settle_cnt;

			lldiv_t div_d;

			if (link_freq <= 0)
					return 0;

			div_d = lldiv(1000000000000LL, link_freq);
			ui = div_d.quot;

			//ui = div_u64(1000000000000LL, link_freq);
			ui /= 2;
			t_hs_prepare_max = 85000 + 6 * ui;
			t_hs_settle = t_hs_prepare_max;

			div_d = lldiv(1000000000000LL, timer_clk_rate);
			timer_period = div_d.quot;
			//timer_period = div(1000000000000LL, timer_clk_rate);
			settle_cnt = t_hs_settle / timer_period - 6;

			return settle_cnt;
	}

	int main() {
	   // printf() displays the string inside quotation

	//      s64 link_freq;
			u32 timer_clk_rate = 300000000;
			long i=1;
			u8 cnt;
			for (long i ; i < ULONG_MAX/2; i*=10) {
					cnt = csiphy_settle_cnt_calc(i, timer_clk_rate);
					printf("link_f 0x%lx, cnt 0x%x\n", i, cnt);
			}
	   return 0;
	}

And the result is:

root@DESKTOP-JU1IHIS:~/source# ./a.out
link_f 0x1000, cnt 0x35a78
link_f 0xa000, cnt 0x55ea
link_f 0x64000, cnt 0x8a8
link_f 0x3e8000, cnt 0xef
link_f 0x2710000, cnt 0x29
link_f 0x186a0000, cnt 0x15
link_f 0xf4240000, cnt 0x13
link_f 0x989680000, cnt 0x13
link_f 0x5f5e100000, cnt 0x13
link_f 0x3b9aca00000, cnt 0x13
link_f 0x2540be400000, cnt 0x13
link_f 0x174876e800000, cnt 0x13
link_f 0xe8d4a51000000, cnt 0x13
link_f 0x9184e72a000000, cnt 0x13
link_f 0x5af3107a4000000, cnt 0x13
link_f 0x38d7ea4c68000000, cnt 0x13
link_f 0x386f26fc10000000, cnt 0x13
link_f 0x345785d8a0000000, cnt 0x13
link_f 0xb6b3a7640000000, cnt 0x13
link_f 0x7230489e80000000, cnt 0x13
link_f 0x75e2d63100000000, cnt 0x13