为瑞芯微设备手动创建emmc镜像

Device description

设备:rk3566
emmc:8GB/32GB Sandisk emmc
Host: Ubuntu22.04(24.04's qemu has problem when creating ubuntu base rootfs, so skip it)
参考: 【每周学习摘要06(23/10/27-23/11/10)】

制作过程

编译组件

DDR+SPL loader

U-boot

Kernel

Image, ko and dtb files,TBD

制作boot.img

boot.img包含kernel以及设备树等,以及uboot保存的env(saveenv)
预留63M空间足以(未压缩的Image最大50MiB), 如果要更大,请修改parameter.txt以防止烧录时干涉rootfs分区

touch boot.img
dd if=/dev/zero of=boot.img bs=1M count=63
sync
mkfs.fat boot.img
sync
sudo mount boot.img /mnt
sudo cp -a -r boot/* /mnt
sync
sudo umount /mnt

制作Ubuntu 2204 rootfs

下载Ubuntu base 2204

地址:https://cdimage.ubuntu.com/ubuntu-base/releases/jammy/release/

wget https://cdimage.ubuntu.com/ubuntu-base/releases/jammy/release/ubuntu-base-22.04.5-base-arm64.tar.gz
mkdir rootfs && tar --same-owner -xf ubuntu-base-22.04.5-base-arm64.tar.gz -C rootfs

Note you shall
添加dns解析

echo nameserver 114.114.114.114 > rootfs/etc/resolv.conf

以及apt源(vim rootfs/etc/apt/source.list)

deb [trusted=yes] http://mirrors.aliyun.com/ubuntu-ports/ jammy main restricted
deb [trusted=yes] http://mirrors.aliyun.com/ubuntu-ports/ jammy-updates main restricted
deb [trusted=yes] http://mirrors.aliyun.com/ubuntu-ports/ jammy universe
deb [trusted=yes] http://mirrors.aliyun.com/ubuntu-ports/ jammy-updates universe
deb [trusted=yes] http://mirrors.aliyun.com/ubuntu-ports/ jammy multiverse
deb [trusted=yes] http://mirrors.aliyun.com/ubuntu-ports/ jammy-updates multiverse
deb [trusted=yes] http://mirrors.aliyun.com/ubuntu-ports/ jammy-backports main restricted universe multiverse
deb [trusted=yes] http://mirrors.aliyun.com/ubuntu-ports/ jammy-security main restricted
deb [trusted=yes] http://mirrors.aliyun.com/ubuntu-ports/ jammy-security universe
deb [trusted=yes] http://mirrors.aliyun.com/ubuntu-ports/ jammy-security multiverse

进入环境后更新apt 源并且下载必要包

sudo chroot rootfs
apt update
apt upgrade
apt install vim sudo kmod net-tools ethtool ifupdown language-pack-en-base rsyslog htop iputils-ping udev systemd network-manager -y

change passwd for root

passwd root

create user meta

adduser meta

add meta to sudoers
chmod +w /etc/sudoers
vim /etc/sudoers
on line 44

# User privilege specification
root    ALL=(ALL:ALL) ALL
meta    ALL=(ALL:ALL) ALL

Finally pack it
return to the father of rootfs directory.
Create a rootfs.img buffer with 1G size
shrink its size by e2fsck and resize2fs

touch rootfs.img
dd if=/dev/zero of=rootfs.img bs=1M count=900
sync
mkfs.ext4 rootfs.img
sudo mount rootfs.img /mnt
sudo cp -a -r rootfs/* /mnt
sync
sudo umount /mnt
e2fsck -f -p rootfs.img
resize2fs -M rootfs.img

You can adjust count in the second command by check fs usage by mounting it to /mnt and then check df -h. To achieve a smaller image size, better make the Available space to be less than 50M.
example:

➜  my-emmc-image df -h
Filesystem      Size  Used Avail Use% Mounted on
tmpfs           6.3G  2.2M  6.3G   1% /run
/dev/nvme1n1p3   60G   31G   27G  54% /
tmpfs            32G  148M   32G   1% /dev/shm
tmpfs           5.0M  4.0K  5.0M   1% /run/lock
efivarfs        268K  144K  120K  55% /sys/firmware/efi/efivars
/dev/nvme0n1p1  256M   49M  208M  19% /boot/efi
tmpfs           6.3G   64K  6.3G   1% /run/user/1000
/dev/nvme0n1p5  480G  405G   51G  89% /media/ztn/4ca5df7c-065c-4b2b-b868-bab13a2816b0
/dev/loop10     868M  783M   24M  98% /mnt

拷贝网卡驱动

TBD, both kernel and user space

拷贝Mali GPU 显卡驱动

TBD, only mali so libs

zju weblogin script

if you want to accesss net after connecting to ZJUWLAN but lacks of a webbrowser to authenticate, you can use
https://github.com/Mythologyli/zju-web-login

First install python3

apt install python3

then follow https://pip.pypa.io/en/stable/installation/ to install pip
By using host's system's wget, we can get rid of downloading wget and its dependency.

su meta
cd ~
wget https://bootstrap.pypa.io/get-pip.py
python3 get-pip.py

In order to shrink the rootfs size, don't install git but rather clone by downloading.
Again, by using host's system's wget, to avoid downloading wget and its dependency. Then unzip it.

wget https://github.com/Mythologyli/zju-web-login/archive/refs/heads/master.zip
unzip master.zip
cd master
pip3 install -r requirements.txt

全志A33修改默认调试串口

tools/pack/chips/sun8iw5p1/configs/default/env.cfg

Line5:

# swap to uart2 by tz61 25/02/14
console=ttyS2,115200

tools/pack/chips/sun8iw5p1/configs/vstar/sys_config.fex

Line112

; swap to uart2 debug by tz61. 25/02/14
[uart_para]
uart_debug_port = 2
;uart_debug_tx   = port:PF02<3><1><default><default>
;uart_debug_rx   = port:PF04<3><1><default><default>
uart_debug_tx    = port:PB00<2><1><default><default>
uart_debug_rx    = port:PB01<2><1><default><default>
[force_uart_para]
force_uart_port  = 2
;force_uart_tx    = port:PF02<3><1><default><default>
;force_uart_rx    = port:PF04<3><1><default><default>
force_uart_tx    = port:PB00<2><1><default><default>
force_uart_rx    = port:PB01<2><1><default><default>

FBTFT源码解析

文件结构

目录:drivers/staging/fbtft
其中文件分为核心驱动与面板驱动

  • 核心(通用件,共性):fbtft-core.c, fbtft-bus.c, fbtft-sysfs.c, fbtft-io.c, fbtft.h
  • 面板驱动(下级,特性):(e.g.) fb_st7789v.c

    fbtftops

    write_reg -> fbtftops.write_register
    fbtftops.write_register -> fbtft_write_reg8_bus8 -> fbtft_write_buf_dc -> fbtftops.write
    fbtft_update_display -> fbtftops.write_vmem -> fbtft_write_vmem16_bus8 -> fbtftops.write
    reg,value对本质上就是两个u8参数.

    fbtft_merge_fbtftops

    用于覆盖默认的ops

    fbtft_update_display

    这个是更新整个屏幕的核心函数,首先调用特定的display驱动的set_addr_win,来指定行列起始(x start/end; y start/end)
    在设置完起始后write_reg(par, MIPI_DCS_WRITE_MEMORY_START);来直接写入屏幕的VRAM
    流程图如下(MIPI_DCS_WRITE_MEMORY_START)(0x2C)(RAMWR)

    deferred_io 上层接口

    deferred_io 每次调用会回调fbtftops.update_display来更新屏幕. deferred_io 是整个驱动的上层接口
    见https://docs.kernel.org/fb/deferred_io.html

    dirty机制以及局部更新

    TBD

    注册流程 registration process

    TBD
    fbtft.h有一个FBTFT_REGISTER_DRIVER宏,在每个display驱动里面调用这个.

折腾全志T113-s3 Tina Linux

编译

第一次编译

进入文件夹talowe-t113-linux-sdk然后运行./build.sh

解压Buildroot rootfs

在运行过一遍./build.sh后,将我编译的Mplayer1.5,以及测试视频,Qt5.12.6等等覆盖到默认的Buildroot下面,这样省得再重复上述操作重新编译一遍了.具体编译Qt和Mplayer的方法见后面

tar -xzf ~/target.tar.gz -C /home/talowe/talowe-t113-linux-sdk/out/t113/evb1_auto/longan/buildroot

运行完成后重新运行

./build.sh rootfs
./build.sh pack

out/pack下面就能看到打包好的img文件

如何烧录打包的emmc

打开PheonixSuit,选择要烧录的img,然后usb连接开发板,先安卓emmc按钮,然后再按rst按钮(然后马上松开),然后观察PheonixSuit软件,如果看到左下角红色字显示Begin XXXX则立刻松开emmc按钮,如果不松开则烧录不了emmc(原理是这个按键拉低了emmc 的D2脚)
烧录完成后T113s3会自动重启加载固件
此时使用MobaXterm打开串口,串口连接至板子的UART3(杜邦线3Pin处)就能看到内核启动日志及其他信息,或者使用adb shell命令进入终端

目标dts与配置

SDK/evb1_auto/.BoardConfig.mk可知

export DTS_NAME=talowe-t113-s3
export UBOOT_DTS_NAME=talowe-t113-s3-uboot

用的是kernel/arch/arm/boot/dts/talowe-t113-s3.dts
kernel的defconfig请见SDK根目录下的.buildconfig
可见

export LICHEE_KERN_DEFCONF_ABSOLUTE=/home/talowe/talowe-t113-linux-sdk/kernel/linux-5.4/arch/arm/configs/sun8iw20p1smp_t113_auto_defconfig

直接修改kernel下面的dts还有defconfig,不需要删除out下面的任何东西然后重新./build.sh然后./build.sh pack然后用Phoenix Suit烧录就行
记得更新rootfs里面的modules,具体在pack前面运行./build.sh rootfs

fex

fex是t113_auto下面的sys_config.fex

如果打包报错怎么办

删除out下面的pack_out
然后重新按照 ./build.sh kernel, ./build.sh rootfs, ./build.sh pack的顺序打包或者直接删除out重新·./build.sh(如果你不想保留buildroot rootfs里面放的东西)

编译Mplayer-1.5

./configure --cc=arm-linux-gnueabi-gcc --enable-cross-compile --strip=arm-linux-gnueabi-strip --target=arm-linux --enable-alsa --enable-fbdev --prefix=/home/talowe/talowe-t113-linux-sdk/out/t113/evb1_auto/longan/buildroot/target/usr --extra-ldflags=--sysroot=/home/talowe/talowe-t113-linux-sdk/out/t113/evb1_auto/longan/buildroot/host/arm-buildroot-linux-gnueabi/sysroot --extra-cflags=-I/home/talowe/talowe-t113-linux-sdk/out/t113/evb1_auto/longan/buildroot/host/arm-buildroot-linux-gnueabi/sysroot/usr/include

编译Qt 5.12.6

1.下载源码
2.编译脚本

export PATH="$PATH:"

mk.sh(不需要prefix,默认安装到sysroot/usr/local/Qt5.12.6):

#!/bin/sh
export PATH="$PATH:/home/talowe/talowe-t113-linux-sdk/out/gcc-linaro-5.3.1-2016.05-x86_64_arm-linux-gnueabi/bin"
./configure \
-release \
-opensource \
-shared \
-xplatform linux-arm-gnueabi-g++ \
-optimized-qmake \
-pch \
-qt-sqlite \
-qt-libjpeg \
-qt-libpng \
-qt-zlib \
-no-opengl \
-skip qt3d \
-skip qtcanvas3d \
-skip qtpurchasing \
-skip qtlocation \
-skip qttools \
-no-sse2 \
-no-openssl \
-no-cups \
-no-glib \
-no-dbus \
-no-xcb \
-no-iconv \
-no-separate-debug-info \
-no-fontconfig \
-tslib \
-I /home/talowe/talowe-t113-linux-sdk/out/t113/evb1_auto/longan/buildroot/host/arm-buildroot-linux-gnueabi/sysroot/usr/include \
-L /home/talowe/talowe-t113-linux-sdk/out/t113/evb1_auto/longan/buildroot/host/arm-buildroot-linux-gnueabi/sysroot/usr/lib \
-sysroot /home/talowe/talowe-t113-linux-sdk/out/t113/evb1_auto/longan/buildroot/host/arm-buildroot-linux-gnueabi/sysroot \
-recheck-all \
-make examples

记得把sysroot里面的/usr/include/vulkan文件夹重命名成别的否则会编译一坨vulkan的玩意然后卡报错
编译完成后把sysroot/usr/local/Qt*拷贝到target/usr/local
运行Qt程序前设置环境变量(fb0/fb1):

export QT_PLUGIN_PATH=/usr/local/Qt-5.12.6/plugins
export QT_QPA_PLATFORM=linuxfb:fb=/dev/fb0
export LD_LIBRARY_PATH=/usr/local/Qt-5.12.6/lib

参考:在全志V853开发板试编译QT测试

添加CST816X驱动以及环境变量

驱动:尚未合并主线
input: add driver for Hynitron CST816X touchscreen

export QT_QPA_GENERIC_PLUGINS=tslib:/dev/input/event5

此处event5和event6为屏幕驱动事件.
更多参数:How to configure Qt to use tslib instead of evdev?

增加可用字体

mkdir /usr/local/Qt-5.12.6/lib/fonts

dejavu的所有ttf文件放到该目录下.

开发

参考 linux下如何利用QtCreator编译ARM版本的Qt程序

播放视频

mplayer -vo fbdev2:/dev/fb1 -ao alsa:device=hw=1.0 -fps 30 maimai240.mp4
mplayer -vo fbdev2:/dev/fb0 -vf scale=360:212 -geometry 0:77 -ao alsa:device=hw=1.0 -fps 30 ba_360x212_30fps.mp4

TSlib 测试

首先设定要测试的input设备.

export TSLIB_TSDEVICE=/dev/input/event5

然后

ts_print

关于CST816X的问题

这个屏幕貌似没有压力检测,所以tslib的pthres没有作用,要么上报0要么上报255(可以通过运行ts_print观察第三个参数)所以这个在屏幕上点击按钮需要长一点时间

关于wlan0有时候没检测到怎么办?

参考How to turn USB-connected device on and off in linux?
也许有用,没试过,多数情况是kernel module和rootfs没更新导致驱动没加载

使用Mplayer播放MaiMai

mplayer -vo fbdev2:/dev/fb1 -ao alsa:device=hw=1.0 maimai240.mp4

录音

使用arecord,声卡是hw0, 由于只有单声道所以-c1

arecord -d 10 -f S16_LE -c1 -r44100 -t wav -D "hw:0,0" test.wav

上网

vim /etc/wpa_supplicant.con

输入密码和SSID
然后

wpa_supplicant -i wlan0 -B -c /etc/wpa_supplicant.conf

最后观察ip

ip addr

RIGOL DHO802/DHO804/DHO812/DHO814 示波器 东方启动

1.联网

插网线到电脑(或者路由器都可以,我直接直连PC,PC当NAT)
参考用Windows通过网线共享网络给其他电脑(Windows、Ubuntu)

2.下载桌面(Android 7.1.2 com.android.launcher3)

Launcher3 of AOSP 7.1.2.apk

3. 用adb 连接示波器并且install apk并启动桌面

连接

adb connect 192.168.137.35:55555

下载完apk后安装launcher3

adb install launcher3.apk

启动设置(可以把桌面设成launcher3),在触摸屏里面手动设置

adb shell monkey -p com.android.settings -c android.intent.category.LAUNCHER 1

启动Launcher3的activity

adb shell am start -n com.android.launcher3/com.android.launcher3.Launcher

然后就ok了

4.安装手势MyGesture(策划返回等等)

MyGesture - 全面屏手势/导航手势操作扩展
根据提示设置权限,然后在设置的无障碍里面开启这个服务.

关于瑞芯微的一些image

以下所有的操作基于``
kernel下面生成的boot.imgRKIMG(RKIMG is a format customized by Rockchip from Android boot image)的镜像,因为u-boot里面用的命令是android_boot(之前不知道这个东西是用安卓启动的方式启动linux内核的,误解成是bootrkp)
然后FIT镜像是uboot.itb,在uboot目录下的fit,可以用dumpimage -l uboot.itb查看.
TSPI的原厂固件boot.img,recovery.img也是一个FIT镜像
所以镜像分两种,一个是uboot FIT一个是android镜像

分区信息可以在执行完./make.sh orangepi-3b-rk3566后看见fit/u-boot.its


/*
 * Copyright (C) 2020 Rockchip Electronic Co.,Ltd
 *
 * Simple U-boot fit source file containing ATF/OP-TEE/U-Boot/dtb/MCU
 */

/dts-v1/;

/ {
    description = "FIT Image with ATF/OP-TEE/U-Boot/MCU";
    #address-cells = <1>;

    images {

        uboot {
            description = "U-Boot";
            data = /incbin/("u-boot-nodtb.bin");
            type = "standalone";
            arch = "arm64";
            os = "U-Boot";
            compression = "none";
            load = <0x00a00000>;
            hash {
                algo = "sha256";
            };
        };
        atf-1 {
            description = "ARM Trusted Firmware";
            data = /incbin/("./bl31_0x00040000.bin");
            type = "firmware";
            arch = "arm64";
            os = "arm-trusted-firmware";
            compression = "none";
            load = <0x00040000>;
            hash {
                algo = "sha256";
            };
        };
        atf-2 {
            description = "ARM Trusted Firmware";
            data = /incbin/("./bl31_0xfdcc1000.bin");
            type = "firmware";
            arch = "arm64";
            os = "arm-trusted-firmware";
            compression = "none";
            load = <0xfdcc1000>;
            hash {
                algo = "sha256";
            };
        };
        atf-3 {
            description = "ARM Trusted Firmware";
            data = /incbin/("./bl31_0x0006b000.bin");
            type = "firmware";
            arch = "arm64";
            os = "arm-trusted-firmware";
            compression = "none";
            load = <0x0006b000>;
            hash {
                algo = "sha256";
            };
        };
        atf-4 {
            description = "ARM Trusted Firmware";
            data = /incbin/("./bl31_0xfdcd0000.bin");
            type = "firmware";
            arch = "arm64";
            os = "arm-trusted-firmware";
            compression = "none";
            load = <0xfdcd0000>;
            hash {
                algo = "sha256";
            };
        };
        atf-5 {
            description = "ARM Trusted Firmware";
            data = /incbin/("./bl31_0xfdcce000.bin");
            type = "firmware";
            arch = "arm64";
            os = "arm-trusted-firmware";
            compression = "none";
            load = <0xfdcce000>;
            hash {
                algo = "sha256";
            };
        };
        atf-6 {
            description = "ARM Trusted Firmware";
            data = /incbin/("./bl31_0x00069000.bin");
            type = "firmware";
            arch = "arm64";
            os = "arm-trusted-firmware";
            compression = "none";
            load = <0x00069000>;
            hash {
                algo = "sha256";
            };
        };
        fdt {
            description = "U-Boot dtb";
            data = /incbin/("./u-boot.dtb");
            type = "flat_dt";
            arch = "arm64";
            compression = "none";
            hash {
                algo = "sha256";
            };
        };
    };

    configurations {
        default = "conf";
        conf {
            description = "rk3566-orangepi-3b";
            rollback-index = <0x0>;
            firmware = "atf-1";
            loadables = "uboot", "atf-2", "atf-3", "atf-4", "atf-5", "atf-6";

            fdt = "fdt";
            signature {
                algo = "sha256,rsa2048";

                key-name-hint = "dev";
                sign-images = "fdt", "firmware", "loadables";
            };
        };
    };
};

如何pack idblock(idbloader)?

在u-boot下面进行

./make.sh --idblock

shell源码:

function pack_idblock()
{
    INI=${INI_LOADER}
    if [ ! -f ${INI} ]; then
        echo "ERROR: No ${INI}"
        exit 1
    fi

    # chip
    COMMON_H=`grep "_common.h:" include/autoconf.mk.dep | awk -F "/" '{ printf $3 }'`
    PLAT=${COMMON_H%_*}

    # file
    SPL_BIN=${RKBIN}/`filt_val "FlashBoot" ${INI}`
    TPL_BIN=${RKBIN}/`filt_val "FlashData" ${INI}`
    if [ ! -z "${ARG_SPL_BIN}" ]; then
        SPL_BIN=${ARG_SPL_BIN}
    fi
    if [ ! -z "${ARG_TPL_BIN}" ]; then
        TPL_BIN=${ARG_TPL_BIN}
    fi

    # pack
    rm idblock.bin -f
    ./tools/mkimage -n ${PLAT} -T rksd -d ${TPL_BIN}:${SPL_BIN} idblock.bin
    echo "Input:"
    echo "    ${INI}"
    echo "    ${TPL_BIN}"
    echo "    ${SPL_BIN}"
    echo
    echo "Pack ${PLAT} idblock.bin okay!"
    echo
}

运行后终端提示:

(py2) ➜  u-boot-orangepi git:(v2017.09-rk3588) ./make.sh --idblock         
Image Type:   Rockchip RK35 boot image
Init Data Size: 55296 bytes
Boot Data Size: 241664 bytes
Input:
    /home/ztn/Embedded/RK/rkbin/RKBOOT/RK3566MINIALL.ini
    /home/ztn/Embedded/RK/rkbin/bin/rk35/rk3566_ddr_1056MHz_v1.18.bin
    /home/ztn/Embedded/RK/rkbin/bin/rk35/rk356x_spl_v1.12.bin

Pack rk3568 idblock.bin okay!

在运行./make.sh xxx时候INI_LOADER如何被选中?

看源码make.sh, 是从当前目录下的.config中寻找CONFIG_LOADER_INI

function select_ini_file()
{
    # default
    INI_LOADER=${RKBIN}/RKBOOT/${RKCHIP_LOADER}MINIALL.ini
    if [ "${ARM64_TRUSTZONE}" == "y" ]; then
        INI_TRUST=${RKBIN}/RKTRUST/${RKCHIP_TRUST}TRUST.ini
    else
        INI_TRUST=${RKBIN}/RKTRUST/${RKCHIP_TRUST}TOS.ini
    fi

    # defconfig
    NAME=`filt_val "CONFIG_LOADER_INI" .config`
    if [ ! -z "${NAME}" ]; then
        INI_LOADER=${RKBIN}/RKBOOT/${NAME}
    fi
    NAME=`filt_val "CONFIG_TRUST_INI" .config`
    if [ ! -z "${NAME}" ]; then
        INI_TRUST=${RKBIN}/RKTRUST/${NAME}
    fi

    # args
    if [ ! -z "${ARG_INI_TRUST}" ]; then
        INI_TRUST=${ARG_INI_TRUST}
    fi
    if [ ! -z "${ARG_INI_LOADER}" ]; then
        INI_LOADER=${ARG_INI_LOADER}
    fi
}

小勘误

rockchip wiki上面是这样从bin 制作img的(img烧录到sd卡中)

tools/mkimage -n rkxxxx -T rksd -d rkxx_ddr_vx.xx.bin idbloader.img
cat rkxx_miniloader_vx.xx.bin >> idbloader.img

但是这样会有问题(提示文件过大)
然后用make.sh里面的方法:

./tools/mkimage -n ${PLAT} -T rksd -d ${TPL_BIN}:${SPL_BIN} idblock.bin

【每周学习摘要01(25/01/23-25/01/29)】

Rk3566 OV2640调试记录

参考文献

camera调试:RK3588 MIPI/DVP camera关键配置
基于瑞芯微平台cif接口dvp相机的视频接入(ov2640、rv1126为例)
(BT656)rk3568制冷项目驱动开发流程汇总(只适用于部分模块CIF DVP等,自用)
瑞芯微摄像头移植流程和注意事项
(全志平台,仅供参考)MQ-r T113 ov2640驱动

订阅了个博客,可以当做文档?

https://blog.csdn.net/weixin_35723192/category_11824879_3.html

Rk3566 VI version 2.1 能力

其中注意瑞芯微rk3566/68平台的VICAP(rkcif)和ISP是两个不同的IP核,两个IP核都能进行capture.
其中rk3566的ISP21是lite版本,看描述是不支持HDR
rk3566/3568没有ispp这个东西,只有rv1126/rv1109/rk3588有(可能是因为VI 3.0才有这个)

详见ISP21/Rockchip_Driver_Guide_VI_CN_v1.1.3.pdf

GPIO/GRF/GRF_SYS

➜  ~ cd /sys/class/gpio
➜  gpio cd gpio144
➜  gpio144 echo 0 > value 
➜  gpio144 cd ../145
cd: no such file or directory: ../145
➜  gpio144 echo 0 > value
➜  gpio144 cd../g
➜  gpio144 cd ../gpio145
➜  gpio145 echo 0 > value
➜  gpio145 echo 1 > value
➜  gpio145 cd ../gpio144
➜  gpio144 echo 1 > value
➜  gpio144 devmem2 0xFDC60070 w 0x00FF0011
/dev/mem opened.
Memory mapped at address 0x7fb954d000.
Value at address 0xFDC60070 (0x7fb954d070): 0x0
Written 0xFF0011; readback 0x11

GRF 是 General Register File 的意思,其中有IOMUX的作用.
其中的SYS_GRF掌管了GPIO的IOMUX工作

我们可以通过devmem2 0xFDC60070 w 0x00FF0011来改变GPIO4_C bank 的复用,其中一个pin 4bit,高16位是用来做mask的.

GPIO 复用/linux pinctrl

比如dts长这样

device {
        pinctrl-names = "active", "idle";
        pinctrl-0 = <&state_0_node_a>;
        pinctrl-1 = <&state_1_node_a>, <&state_1_node_b>;
    };

然后active对应pinctrl-0.

#define OF_CAMERA_PINCTRL_STATE_DEFAULT "rockchip,camera_default"
gc4c33->pins_default = pinctrl_lookup_state(gc4c33->pinctrl, OF_CAMERA_PINCTRL_STATE_DEFAULT);
pinctrl_select_state(gc4c33->pinctrl, gc4c33->pins_default);

当然这里的names可以是任何名字, 然后每个组内可以有多个pins.
对于标有defaultpinstate, 驱动会默认进行pinctrl_select, 不需要在像i2c这种设备的源码里面手动再mux一遍. source:
The pin control core will automatically claim the default pinctrl state for us when the device is probed. If one defines an init state, the pinctrl core will automatically set pinctrl to this state before the probe() function, and then switch to the default state after probe() (unless the driver explicitly changed states already).

GPIO 复用查看

cat /sys/kernel/debug/pinctrl/pinctrl-rockchip-pinctrl/pinmux-pins

系统时钟树信息查看

➜  / cd /sys/kernel/debug/clk/clk_cif_out
➜  clk_cif_out cat clk_enable_count 
4

可以看到clock被开启了4次, 位于gc1054.c的测试代码:


// should enable 4 times
    ret = __gc1054_power_on(gc1054);
    ret = __gc1054_power_on(gc1054);
    ret = __gc1054_power_on(gc1054);
    ret = __gc1054_power_on(gc1054);

驱动c源码

需要在g_mbus_config中设置V4L2_MBUS_BT656, PARALLEL是给BT601用的

Linux 源码查看当前版本

找根目录Makefile前几行

25/01/23


可以看到pinmux 还没mux上去.可能mux工作是在rkcif_dvp驱动里面做的,但是i2c摄像头节点没有注册成功?(但是需要开起来).

[    8.849418] rkcif_dvp: get_remote_sensor: remote pad is null

看了下源码, pinmux在userspace不能通过sysfs改变, 只能查看. 然后根据迅为电子的教程看到改pinmux用到了这个函数:pinctrl_select_state, 于是查看了driver/media/i2c下面的调用, 发现改pinmux是在i2c driver里面做的,然后从linux4.19搬过来的gc1054驱动没有调用这个函数.

现在尝试把这个加进powerup函数里面

25/01/25

现在发现之前无法读取ov2640,第一个是因为CLK_CIF_OUT并非开启,然而IOMUX和clock确实都是开过的.后来用电压表量了一下,发现是clk在设备probe失败后自动关闭了,即使我在i2c设备内注释了所有关闭clock的函数.(可能是i2c驱动的上级驱动帮忙关闭的). 当我在开启clock后,关闭probe结束前加入一段很长的delay, 这样示波器能观察到稳定的波形。 delay 代码如下

    dev_info(&client->dev, "[debug] ov2640 xvclk start extreme long sleep(5s) - trial 1!");
    usleep_range(5 * 1000000, 6 * 1000000); // sleep 10s
    dev_info(&client->dev, "[debug] ov2640 xvclk stop extreme long sleep(5s) - trial 1!");
    i2c_smbus_write_byte_data(client, BANK_SEL, BANK_SEL_SENS);
    pid  = i2c_smbus_read_byte_data(client, PID);
    ver  = i2c_smbus_read_byte_data(client, VER);
    midh = i2c_smbus_read_byte_data(client, MIDH);
    midl = i2c_smbus_read_byte_data(client, MIDL);

然后发现OV2640的i2c地址(ID地址)是0x30. 然后现在dmesg信息如下, 看描述是因为ov2640这个驱动是主线的驱动(linux 5.10.160),并非能在rockchip那套平台(rkcif/rkisp)下面正常工作,因为rkcif(rkcif_dvp)会通过设备树里的endpoint链接,从而获取i2c v4l2subdev的信息,并且通过一些函数进行对应操作。
例如v4l2_subdev_video_ops里面缺乏.g_frame_interval, 然后v4l2_subdev_pad_ops里面缺乏.get_mbus_config,该函数是rkcif判断该摄像头是否为BT656/BT1120还是BT601,亦或是CSI2等类型,所以必须得有.可能在别的platform下面这个函数并非必须的.
还有一个很严重的误解, 才发现有外同步信号的叫BT.601/PARALLEL, 然后BT656没有外同步(HS,VS), 27MHz 的一般是BT656

[    5.273685] i2c /dev entries driver
[    5.276240] fan53555-regulator 0-001c: FAN53555 Option[12] Rev[15] Detected!
[    5.278280] vdd_cpu: supplied by vcc5v0_sys
[    5.288395] ov2640 2-0030: [debug] ov2640 xvclk start extreme long sleep(5s) - trial 1!
[   10.290330] ov2640 2-0030: [debug] ov2640 xvclk stop extreme long sleep(5s) - trial 1!
[   10.292579] ov2640 2-0030: ov2640 Product ID 26:42 Manufacturer ID 7f:a2
[   10.292613] ov2640 2-0030: [debug] ov2640 xvclk start extreme long sleep(5s) - trial 2!
[   15.320326] ov2640 2-0030: [debug] ov2640 xvclk stop extreme long sleep(5s) - trial 2!
[   15.320357] i2c i2c-2: OV2640 Probed
[   15.321788] rkcifhw fdfe0000.rkcif: Adding to iommu group 7
[   15.322363] rkcifhw fdfe0000.rkcif: can't request region for resource [mem 0xfdfe0000-0xfdfe7fff]
[   15.322494] rkcifhw fdfe0000.rkcif: No reserved memory region assign to CIF
[   15.322720] rkcif rkcif_dvp: rkcif driver version: v00.02.00
[   15.322880] rkcif rkcif_dvp: attach to cif hw node
[   15.322898] rkcif rkcif_dvp: rkcif wait line 0
[   15.322913] : terminal subdev does not exist
[   15.322925] : terminal subdev does not exist
[   15.322935] : terminal subdev does not exist
[   15.322946] : terminal subdev does not exist
[   15.324769] ov2640 2-0030: Async registered subdev
[   15.324792] rkcif_dvp: get mbus config failed for linking
[   15.324809] rkcif rkcif_dvp: Entity type for entity rkcif-dvp-sof was not initialized!
[   15.325155] rkcif_dvp: rkcif_update_sensor_info: get terminal ov2640 2-0030 g_frame_interval failed!
[   15.325182] rkcif_dvp: input mbus_code 0x2006, can't transform to RG10
[   15.325196] rkcif_dvp: input mbus_code 0x2006, can't transform to RG10
[   15.325208] rkcif_dvp: input mbus_code 0x2006, can't transform to RG10
[   15.325220] rkcif_dvp: input mbus_code 0x2006, can't transform to RG10
[   15.325241] rkcif_dvp: Async subdev notifier completed
[   15.325264] rkcif_dvp: rkcif_update_sensor_info: get terminal ov2640 2-0030 g_frame_interval failed!
[   15.325283] rkcif_dvp: There is not terminal subdev, not synchronized with ISP
[   15.325483] rkcif rkcif_dvp: No memory-region-thunderboot specified
[   15.327104] rockchip-mipi-csi2-hw fdfb0000.mipi-csi2-hw: enter mipi csi2 hw probe!
[   15.327343] rockchip-mipi-csi2-hw fdfb0000.mipi-csi2-hw: probe success, v4l2_dev:mipi-csi2-hw!
[   15.329032] rkisp_hw fdff0000.rkisp: Adding to iommu group 8
[   15.329287] rkisp_hw fdff0000.rkisp: is_thunderboot: 0
[   15.329330] rkisp_hw fdff0000.rkisp: can't request region for resource [mem 0xfdff0000-0xfdffffff]
[   15.329370] rkisp_hw fdff0000.rkisp: max input:0x0@0fps
[   15.329601] rkisp_hw fdff0000.rkisp: no find phandle sram
[   15.330220] rkisp rkisp-vir0: rkisp driver version: v02.03.00
[   15.330429] rkisp rkisp-vir0: No memory-region-thunderboot specified
[   15.330706] rkisp rkisp-vir0: Entity type for entity rkisp-isp-subdev was not initialized!
[   15.330738] rkisp rkisp-vir0: Entity type for entity rkisp-csi-subdev was not initialized!
[   15.334198] usbcore: registered new interface driver uvcvideo
[   15.334221] USB Video Class driver (1.1.1)
[   15.336410] Bluetooth: HCI UART driver ver 2.3
[   15.336436] Bluetooth: HCI UART protocol H4 registered
[   15.336447] Bluetooth: HCI UART protocol ATH3K registered

待做事项

现在可以直接参考gc2145的文档,因为这个是BT-601 YUV(外同步)来移植OV2640
也可以参考这个全志平台的移植MQ-r T113 ov2640驱动 因为都是MEDIA_BUS_FMT_UYUV8_2X8. 有些驱动是1X12,但我的硬件做的是2X8(8根CIF数据线). 所以只能看gc2145的代码和全志的这个(gc1054的驱动是MEDIA_BUS_FMT_SRGGB10_1X10, bayer RGB) 关于一个摄像头驱动用的哪种格式读取图像信息直接搜索关键词MEDIA_BUS_FMT. 然后RK的框架/硬件貌似不支持RGB565,见附录B MEDIA_BUS_FMT表,因为在整个文档都没搜到
这里说的RAW RGB 就是Bayer RAW RGB的意思.然后还有个RAW BW
主线的摄像头驱动貌似支持多种MEDIA_BUS_FMT, 详见ov2640/ov5640,不过一般在probe的时候都会选一个default类型.
基本上rk的摄像头只支持了一种特定的camera output数据格式,毕竟没必要写那么多别output format支持,主打一个能用就行.
gc2145用的是MEDIA_BUS_FMT_UYVY8_2X8,主线ov2640的default也是MEDIA_BUS_FMT_UYVY8_2X8
接下来的工作是照着这些资料完善主线ov2640的一些函数,基本上只要上报正确信息就好
注意gc2145 的vsync是low active,(见手册 7.1. Timing), 而ov2640的vsync是high active(待确认?,因为那个全志的人写的是high active但是我看手册确实是low active,可以看到gc1054也是vsync low active,凭逻辑判断也是这样,不放心多看几个V4L2_MBUS_PARALLEL的驱动,看了七八个都是这样的估计全志那个人写错了)但是hsync(href)都是high active,然后pclk_sample 基本上都是rising

设备树哪些必须要配置

关于ar0230为什么vs hs 都是高有效?

ar0230是一个桥接芯片并不是camera, 见手册第23页

当rkcif_dvp 成功链接后media拓扑长啥样?

这里的source(虽然是BT656的):rk3568制冷项目驱动开发流程汇总(只适用于部分模块CIF DVP等,自用)

第二个参考,虽然是rv1126的,但完整的展现了既有rkcif又有isp的情况下的拓扑(主要是知道哪个video设备是哪个产生的,哪个是裸的,哪个是经过处理的)
media-ctl 工具打印media control框架下media设备节点拓扑结构
第三个参考:

第四个参考:
(Rk的wiki,虽然是ISPv1)Rockchip-isp1

24/01/26

subdev-formats大全-kernel.org