热度 6
2023-7-27 17:21
1627 次阅读|
0 个评论
soc平台 开发板品牌 sdk版本 开发平台 rv1126 firefly 20211022 ubuntu18.04 64位 学嵌入式开发也有一段时间了,本来也是想搞一款音视频编码器产品,出于这个目的,也验证一下自己的能力。 由于现在开发板是现成的了,引出了对应MIPI CSI的两组总线,需要自己做个HDMI转MIPI的模块,自己根据芯片手册,简单设计了一个LT6911UXC的转换模块(调试板有点脏乱)。 image-20230714165528631 整个硬件平台算是搭建完成了。 这里说是移植,而不是开发的原因是,正好手头上有已经比较完美的驱动了。只是硬件平台的改动而已。 一、根据电路在设备树中增加I2C设备 这里设计的是挂载在I2C2上的,所以 &i2c2{ status = "okay"; clock-frequency = ; lt6911uxc: lt6911uxc@2b { compatible = "LT6911UXC"; reg = ; }; }; 二、根据源码改设备树 都知道,设备树是描述硬件资源的。既然硬件平台改了,那么对于新的硬件平台当然是要在设备树中加入设备和相关信息了 1. 看源码 源码中有这样一个函数 #ifdef CONFIG_OF static int lt6911uxc_parse_of(struct lt6911uxc *lt6911uxc) { struct device *dev = dev; of_node; struct v4l2_fwnode_endpoint *endpoint; struct device_node *ep; int ret; ret = of_property_read_u32(node, RKMODULE_CAMERA_MODULE_INDEX, module_index); ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_FACING, module_facing); ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_NAME, module_name); ret |= of_property_read_string(node, RKMODULE_CAMERA_LENS_NAME, len_name); if (ret) { dev_err(dev, "could not get module information!\n"); return -EINVAL; } #if 0 power_gpio = devm_gpiod_get_optional(dev, "power", //电源控制 GPIOD_OUT_LOW); power_gpio)) { dev_err(dev, "failed to get power gpio\n"); power_gpio); return ret; } #endif reset_gpio = devm_gpiod_get_optional(dev, "reset", //复位引脚 GPIOD_OUT_LOW); reset_gpio)) { dev_err(dev, "failed to get reset gpio\n"); reset_gpio); return ret; } plugin_det_gpio = devm_gpiod_get_optional(dev, "plugin-det", //插入检测 GPIOD_IN); plugin_det_gpio)) { dev_err(dev, "failed to get plugin det gpio\n"); plugin_det_gpio); return ret; } #if 0 hpd_ctl_gpio = devm_gpiod_get_optional(dev, "hpd-ctl", //热插拔控制 GPIOD_OUT_HIGH); hpd_ctl_gpio)) { dev_err(dev, "failed to get hpd ctl gpio\n"); hpd_ctl_gpio); return ret; } #endif //获取和配置v4l2相关端点 of_node, NULL); if (!ep) { dev_err(dev, "missing endpoint node\n"); ret = -EINVAL; return ret; } endpoint = v4l2_fwnode_endpoint_alloc_parse(of_fwnode_handle(ep)); if (IS_ERR(endpoint)) { dev_err(dev, "failed to parse endpoint\n"); ret = PTR_ERR(endpoint); return ret; } bus_type != V4L2_MBUS_CSI2 || bus.mipi_csi2.num_data_lanes == 0) { dev_err(dev, "missing CSI-2 properties in endpoint\n"); ret = -EINVAL; goto free_endpoint; } #if 1 xvclk = devm_clk_get(dev, "xvclk"); //如果lt6911的外部时钟是soc提供,则需要进行相关配置 xvclk)) { dev_err(dev, "failed to get xvclk\n"); ret = -EINVAL; goto free_endpoint; } xvclk); if (ret) { dev_err(dev, "Failed! to enable xvclk\n"); goto free_endpoint; } #endif bus.mipi_csi2.num_data_lanes; bus.mipi_csi2; enable_hdcp = false; hpd_ctl_gpio, 0); power_gpio, 1); lt6911uxc_reset(lt6911uxc); ret = 0; free_endpoint: v4l2_fwnode_endpoint_free(endpoint); return ret; } 从整个处理过程中,此函数是在通过devm_gpiod_get_optional这个函数查找设备树中 "power-gpios" , "reset-gpios", "plugin-det-gpios", "hpd-ctl-gpios"相关节点,并进行输入输出模式配置。将返回的结果存储到定义的lt6911uxc私有数据中。 2. 改设备树 根据以上源码,对设备树进行如下配置(根据电路设计,power和HPD的控制这里没有用到,所以这里不做配置) reset-gpios = ; plugin-det-gpios = ; //hpd-ctl-gpios = ; 3. 处理函数函数 复位函数 static void lt6911uxc_reset(struct lt6911uxc *lt6911uxc) { reset_gpio, 0); usleep_range(2000, 2100); reset_gpio, 1); usleep_range(120*1000, 121*1000); reset_gpio, 0); usleep_range(300*1000, 310*1000); } 插入检测函数 static inline bool tx_5v_power_present(struct v4l2_subdev *sd) { int val; struct lt6911uxc *lt6911uxc = to_state(sd); plugin_det_gpio); v4l2_dbg(1, debug, sd, "%s plug det: %s!\n", __func__, 0) ? "int" : "out"); 0); } static irqreturn_t plugin_detect_irq_handler(int irq, void *dev_id) { struct lt6911uxc *lt6911uxc = dev_id; struct v4l2_subdev *sd = sd; /* control hpd output level after 25ms */ // schedule_delayed_work( delayed_work_enable_hotplug, // HZ / 40); tx_5v_power_present(sd); return IRQ_HANDLED; } 三、根据其他摄像头配置完善设备树 &i2c2{ status = "okay"; clock-frequency = ; lt6911uxc: lt6911uxc@2b { compatible = "LT6911UXC"; reg = ; clocks = ; clock-names = "xvclk"; interrupt-parent= ; interrupts=; pinctrl-names = "default"; pinctrl-0 = < ; reset-gpios = ; plugin-det-gpios = ; // hpd-ctl-gpios = ; rockchip,camera-module-index = ; rockchip,camera-module-facing = "back"; rockchip,camera-module-name = "hdmi_in"; //摄像头名称 rockchip,camera-module-lens-name = "lt6911uxc"; //摄像头镜头 port { //v4l2端点配置 ucam_out0: endpoint { remote-endpoint = ; data-lanes = ; }; }; }; }; 四、其他设备树配置 &csi_dphy0 { status = "okay"; ports { #address-cells = ; #size-cells = ; port@0 { reg = ; #address-cells = ; #size-cells = ; /*mipi_in_ucam0: endpoint@1 { reg = ; remote-endpoint = ; data-lanes = ; };*/ mipi_in_ucam0: endpoint@1 { reg = ; remote-endpoint = ; data-lanes = ; }; }; port@1 { reg = ; #address-cells = ; #size-cells = ; csidphy0_out: endpoint@0 { reg = ; remote-endpoint = ; data-lanes = ; }; }; }; }; &mipi_csi2 { status = "okay"; ports { #address-cells = ; #size-cells = ; port@0 { reg = ; #address-cells = ; #size-cells = ; mipi_csi2_input: endpoint@1 { reg = ; remote-endpoint = ; data-lanes = ; }; }; port@1 { reg = ; #address-cells = ; #size-cells = ; mipi_csi2_output: endpoint@0 { reg = ; remote-endpoint = ; data-lanes = ; }; }; }; }; 五、总结 以上也就配置完成了,具体调试过程可以参看我的另一篇文章 RK628底层调试,使用V4L2调试工具抓图-面包板社区 (eet-china.com) rtsp获取demo可以使用瑞芯微SDK自带的 SDK/external/rkmedia/examples/rkmedia_vi_venc_rtsp_test.c