首页
关于我
Search
1
阿明的个人博客站今日上线
10 阅读
2
V4L2 sensor驱动中.s_ctrl() 自陷死锁问题排查全过程总结
8 阅读
3
RK3588 SD启动卡系统备份
2 阅读
4
AM5728绕过hpd信号,强制输出hdmi/dvi的设置方法
2 阅读
5
新站链接提交百度的方法
1 阅读
嵌入式软件
C/C++
Linux v4l2
RK3588
UEFI
AM5728
嵌入式硬件
网站建设
生活
其他
Search
标签搜索
v4l2
linux driver
sensor
website
RK3588
Linux
u-boot
spl
Armin
累计撰写
5
篇文章
累计收到
2
条评论
首页
栏目
嵌入式软件
C/C++
Linux v4l2
RK3588
UEFI
AM5728
嵌入式硬件
网站建设
生活
其他
页面
关于我
搜索到
3
篇与
的结果
2025-07-03
AM5728绕过hpd信号,强制输出hdmi/dvi的设置方法
公司基于 AM5728 处理器为客户定制了一款linux视频源板,主要输出一路hdmi视频信号。由于特殊原因,需要绕过hpd信号,强制hdmi输出视频。最简单的方法当然是直接将hpd信号拉高到板内的3.3v,便可以实现不再检测hpd信号。但由于板卡已经设计完成,强行拉高hpd信号需要飞线,因此只能从内核驱动下手,通过修改linux-drm驱动的方法,绕过hpd信号。另一个问题是板卡输出使用的应用是基于gstreamer的播放程序,sink使用的是waylandsink,热插拔会造成gstreamer播放程序被kill的问题。现将调试解决问题的方法记录如下:omapdrm目录说明AM5728 的hdmi驱动路径是 /linux-sdk/kernel/drivers/gpu/drm/omapdrm/ ,该目录实现的是 TI OMAP DSS 显示子系统的 DRM 驱动(omapdrm),支持 HDMI、DSI、DPI、LVDS 等显示接口。主要负责:实现 DRM framework 所需的 crtc、encoder、connector、plane 等核心对象提供 TI 特有显示硬件的控制逻辑(DSS 管理、VENC、HDMI)子目录说明dss/ — DSS 子系统 HAL 封装层,DSS = Display SubSystem,是 TI SoC 显示硬件的控制核心,提供与具体硬件寄存器、时钟、reset、overlay、video port 等的接口。此处并不直接处理 DRM 接口,而是为 DRM CRTC/Plane 提供驱动支撑。 displays/ — 具体显示屏的 panel 驱动,实现具体 LCD 面板或显示器的驱动逻辑,注册 panel 信息给 DRM,如果自己开发了一个 LCD 面板,可以仿照这里写法。当前的hdmi接了一个 TPD12S015 芯片,该芯片是HDMI 接口保护和信号路由集成器件,主要应用于 HDMI 发射端(HDMI_TX)电路中,因此也在这个目录下。关键代码说明1、 encoder-tpd12s015.c 中的 tpd_hpd_isr 函数最终调用 omap_connector.c 中的 omap_connector_hpd_cb 函数,里边的 drm_kms_helper_hotplug_event 函数会影响并关闭gstreamer程序。"encoder-tpd12s015.c" static irqreturn_t tpd_hpd_isr(int irq, void *data) { struct panel_drv_data *ddata = data; mutex_lock(&ddata->hpd_lock); if (ddata->hpd_enabled && ddata->hpd_cb) { enum drm_connector_status status; if (tpd_detect(&ddata->dssdev)) status = connector_status_connected; else status = connector_status_disconnected; ddata->hpd_cb(ddata->hpd_cb_data, status); } mutex_unlock(&ddata->hpd_lock); return IRQ_HANDLED; }板卡开机,linux内核启动过程中的hpd连接检测不在 tpd_hpd_isr 里,第一次触发 tpd_hpd_isr 时,if判断条件中的ddata->hpd_cb还不满足,此时还没有注册热插拔callback函数。因此该函数主要处理的是进入系统之后的热插拔操作。2、linux内核启动过程中的hpd连接检测使用的是 omap_connector_detect 函数,让该函数直接返回 connector_status_connected ,后续的hdmi控制器配置初始化便可以继续进行。"omap_connector.c" static enum drm_connector_status omap_connector_detect( struct drm_connector *connector, bool force) { struct omap_connector *omap_connector = to_omap_connector(connector); struct omap_dss_device *dssdev = omap_connector->dssdev; struct omap_dss_driver *dssdrv = dssdev->driver; enum drm_connector_status ret; pr_info("ydbg : skip hpd detect\n"); return connector_status_connected;//ydbg 202506+ 跳过hpd检测,开机直接强制输出,不返回已连接的话,后续驱动不会初始化hdmi if (dssdrv->detect) { if (dssdrv->detect(dssdev)) ret = connector_status_connected; else ret = connector_status_disconnected; } else if (dssdev->type == OMAP_DISPLAY_TYPE_DPI || dssdev->type == OMAP_DISPLAY_TYPE_DBI || dssdev->type == OMAP_DISPLAY_TYPE_SDI || dssdev->type == OMAP_DISPLAY_TYPE_DSI) { ret = connector_status_connected; } else { ret = connector_status_unknown; } VERB("%s: %d (force=%d)", omap_connector->dssdev->name, ret, force); return ret; }static void omap_connector_hpd_cb(void *cb_data, enum drm_connector_status status) { struct omap_connector *omap_connector = cb_data; struct drm_connector *connector = &omap_connector->base; struct drm_device *dev = connector->dev; enum drm_connector_status old_status; status = connector_status_connected; pr_info("ydbg : force the status to be connector_status_connected\n"); mutex_lock(&dev->mode_config.mutex); old_status = connector->status; connector->status = status; mutex_unlock(&dev->mode_config.mutex); /*if (old_status != status) drm_kms_helper_hotplug_event(dev);*/ //ydbg encoder-tpd12s015.c中的tpd_hpd_isr这里会调用这里,会影响并关闭gstreamer应用,因此注释掉 }同时注释掉 drm_kms_helper_hotplug_event ,在进入系统之后便不会因为拔插连接器而关闭gstreamer播放程序。{lamp/}**最终跳过hpd并强制输出hdmi/dvi的方法:omap_connector.c中 omap_connector_detect 函数直接返回 connector_status_connected 。注释 drm_kms_helper_hotplug_event 。hdmi5.c中的函数 hdmi_set_hdmi_mode 令 hdmi.cfg.hdmi_dvi_mode 等于HDMI_HDMI或者HDMI_DVI,即可设置输出类型是HDMI或DVI。**
2025年07月03日
2 阅读
0 评论
0 点赞
2025-05-23
RK3588 SD启动卡系统备份
一、制作rootfs.img和userdata.img映像文件 1.ubuntu虚拟机进入 rk3588_linux_release_v1.2.1/output/firmware/ 目录。 2.插上准备备份的SD卡,并查看需要备份的 rootfs、userdata 分区的大小。 3.使用如下命令,创建img映像文件。 dd if=/dev/zero of=rootfs.img bs=1M count=1600 dd if=/dev/zero of=userdata.img bs=1M count=5count=1600是因为rootfs的大小是860M,设置两倍大小足够保存所有文件,userdata同理。 4.设置文件系统,添加LABEL。 mkfs.ext4 -L rootfs rootfs.img mkfs.ext4 -L userdata userdata.img 5.创建目录,将刚刚创建的 rootfs.img 和 userdata.img 映像文件挂载到新建的目录。 mkdir rootfs mkdir userdata sudo mount rootfs.img rootfs sudo mount userdata.img userdata 6.拷贝SD卡rootfs和userdata分区的所有文件到刚刚创建的rootfs和userdata目录中去。 sudo cp -a /media/admin123/rootfs/* rootfs/ sudo cp -a /media/admin123/userdata/* userdata/ 7.取消挂载,删除文件夹。 sudo umount rootfs sudo umount userdata sudo rm -r rootfs sudo rm -r userdata二、其他映像文件的制作 1. uboot.img : 在 rk3588_linux_release_v1.2.1/ 目录下运行./build.sh uboot 即可在 rk3588_linux_release_v1.2.1/output/firmware/ 生成(软链接形式,实际文件不在该目录,不影响使用)。 2. boot.img : 在 rk3588_linux_release_v1.2.1/ 目录下运行./build.sh kernel 即可在 rk3588_linux_release_v1.2.1/output/firmware/ 生成(软链接形式,实际文件不在该目录,不影响使用)。 3. MiniLoaderAll.bin : 在 rk3588_linux_release_v1.2.1/ 目录下运行命令./build.sh uboot 即可生成,该文件的内容是 TPL+SPL 。 运行以上编译脚本时,最终生成的MiniLoaderAll.bin是从SDK中预编译好的文件直接拷贝后改了个名字得到的。 如果想要使用自己修改的,以修改spl文件为例: 修改 rk3588_linux_release_v1.2.1/u-boot/arch/arm/mach-rockchip/spl.c 文件后,运行以下命令编译一次。./build.sh uboot 编译的spl文件保存在 rk3588_linux_release_v1.2.1/u-boot/spl/u-boot-spl.bin,将预编译的spl原文件备份一下mv rkbin/bin/rk35/rk3588_spl_v1.12.bin rkbin/bin/rk35/bak_rk3588_spl_v1.12.bin 然后运行以下命令将预编译的spl文件替换为刚刚编译的spl文件。cp u-boot/spl/u-boot-spl.bin rkbin/bin/rk35/rk3588_spl_v1.12.bin 再次运行 ./build.sh uboot ,生成的 MiniLoaderAll.bin 即为修改后的。 4. oem.img、misc.img、parameter.txt : 在 rk3588_linux_release_v1.2.1/ 目录下运行以下命令即可编译生成。./build.sh firmware 5. recovery.img : 使用官方工具, RKDevTool.3.15 ->高级功能->固件->选择“创龙TL3588_SDK\4-软件资料\Linux\Makesdboot\v2.2\update.img”文件->点击解包。在 RKDevTool.3.15 根目录下会生成一个 Output 文件夹,其中 Output\Android\Image 目录里有update.img包含的所有映像文件,选择拷贝即可。三、打包所有映像文件 1.修改 rk3588_linux_release_v1.2.1/device/rockchip/rk3588/rk3588-package-file 文件,该文件是打包选项。 2.由于是完整包,因此可以包含所有的选项, # 号是注释,代表取消该选项,打包所有映像文件的示例如下。 # NAME PATH package-file package-file parameter parameter.txt bootloader MiniLoaderAll.bin uboot uboot.img misc misc.img boot boot.img #backup RESERVED rootfs rootfs.img recovery recovery.img oem oem.img userdata userdata.img 3.update.img :在 rk3588_linux_release_v1.2.1/ 目录下运行以下命令,将所有文件打包生成update.img。./build.sh updateimg四、批量制作SD卡 1.连接:使用读卡器将SD卡与PC连接。 2.清理磁盘:使用官方软件工具 SD_Firmware_Tool_1.74 (其他版本应该也可以),点击恢复磁盘,将SD卡格式化。 3.创建:SD_Firmware_Tool_1.74->选择磁盘设备->勾选SD启动->选择第三节生成的update.img->开始创建。 4.等待创建完成即可。如果不放在板卡上启动一次,userdata分区的空间大小是userdata.img的大小,上电启动一次后会自动扩展。
2025年05月23日
2 阅读
0 评论
0 点赞
2025-05-15
V4L2 sensor驱动中.s_ctrl() 自陷死锁问题排查全过程总结
一、问题背景在开发 LT9211C 的 V4L2 子设备驱动时,实现了一个控制接口:v4l2-ctl -d /dev/v4l-subdevX --set-ctrl=chip_init=1该命令触发 .s_ctrl() 中的设备初始化逻辑。驱动中使用了 mutex 来保护共享状态:mutex_lock(<9211c->confctl_mutex); ... mutex_unlock(<9211c->confctl_mutex);但执行命令时,.s_ctrl() 永远卡在 mutex_lock(),导致控制操作无法完成。二、初步怀疑与验证1:其他线程(如 workqueue)持有锁存在工作队列周期性使用 mutex_trylock(),怀疑抢占了锁注释掉所有 schedule_work() 和工作队列逻辑结果:问题仍然存在,.s_ctrl() 卡住不动2:驱动中其他路径加了锁全局查找所有 mutex_lock()、mutex_trylock() 路径结果:确认无其他加锁路径三、深入排查尝试用 mutex_is_locked() 检查锁状态在 .s_ctrl() 内部加打印:pr_info("locked = %d\n", mutex_is_locked(<->confctl_mutex));结果显示锁始终处于加锁状态,但代码中没人持有锁。四、关键线索发现在控件初始化函数中:handler->lock = <9211c->confctl_mutex; lt9211c->chip_init_ctrl = v4l2_ctrl_new_custom(handler, <9211c_ctrl_chip_init, NULL);.s_ctrl() 回调正好是 chip_init 控件对应的处理函数。这意味着:V4L2 框架在调用 .s_ctrl() 之前已经自动加了 handler->lock 对应的 mutex五、框架调用链分析VIDIOC_S_CTRL └── v4l2_ctrl_handler_setup() └── mutex_lock(handler->lock); //框架加锁 └── ctrl->ops->s_ctrl() //调用驱动 .s_ctrl() └── mutex_unlock(handler->lock);因此 .s_ctrl() 执行时已经处于加锁状态,若再次 mutex_lock() 同一把锁,就会死锁(线程阻塞等待自己)。六、最终修复方式删除 .s_ctrl() 中的重复加锁:- mutex_lock(<->confctl_mutex); // 不需要 ... - mutex_unlock(<->confctl_mutex); // 不需要改为直接执行逻辑(由框架管理加解锁)。七、验证结果编译驱动重新执行控制命令:v4l2-ctl --set-ctrl=chip_init=1控制操作立即成功返回,卡死问题彻底解决。八、经验总结项目说明问题类型自陷死锁(Self-deadlock)原因.s_ctrl() 中手动 mutex_lock() 框架已加锁的 mutex最大误导点锁好像“被别人持有”,实际是“自己卡自己”排查突破口handler->lock 设置 → 框架自动加锁机制分析根本解决方法不在 .s_ctrl() 中重复加锁 handler->lock 指向的 mutex凡设置了 handler->lock 的 V4L2 控制器,.s_ctrl() 中禁止重复加锁,否则极易造成自陷死锁。九、其他调试方法pr_info("s_ctrl: current thread = %s, is_locked = %d\n", current->comm, mutex_is_locked(<->confctl_mutex));可以查看当前的锁被谁持有。
2025年05月15日
8 阅读
0 评论
1 点赞