RK628F HDMI-IN调试:应用接口使用
RK628F对接RK3588等SOC平台,可以作为HDMI-IN功能使用,应用可以在用户层获取驱动的相关接口信息,例如:颜色格式、色域、颜色空间等等信息,这篇文章简单介绍一下驱动相关的接口,以及应用如何使用对应的接口进行开发。
1.接口介绍
介绍一下RK628F的驱动都支持哪些接口供应用读取使用,RK628F的接口可以分为V4l2标准接口,RK HDMI-IN的私有接口、RK camera的私有接口。一起来看一下这些接口。
1.1 V4L2接口
V4L2的标准接口,基于V4L2的标准框架实现,主要有如下:
1.1.1 VIDIOC_SUBDEV_G_FMT
调用驱动的rk628_csi_get_fmt获取当前输出的分辨率;
static int rk628_csi_get_fmt(struct v4l2_subdev *sd,struct v4l2_subdev_state *sd_state,struct v4l2_subdev_format *format)
{struct rk628_csi *csi = to_csi(sd);......mutex_lock(&csi->confctl_mutex);format->format.code = csi->mbus_fmt_code;format->format.width = ALIGN_DOWN(csi->timings.bt.width, 4);format->format.height = csi->timings.bt.height;format->format.field = csi->timings.bt.interlaced ?V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE;
......
1.1.2 VIDIOC_SUBDEV_S_FMT
设置输出分辨率,用户层一般不用
1.1.3 VIDIOC_SUBDEV_QUERY_DV_TIMINGS
获取当前HDMI-IN的Timings;
static int rk628_csi_query_dv_timings(struct v4l2_subdev *sd,struct v4l2_dv_timings *timings)
{int ret;struct rk628_csi *csi = to_csi(sd);struct v4l2_dv_timings default_timing =V4L2_DV_BT_CEA_640X480P59_94;if (!tx_5v_power_present(sd) || csi->nosignal) {*timings = default_timing;v4l2_info(sd, "%s: not detect 5v, set default timing\n", __func__);return 0;}mutex_lock(&csi->confctl_mutex);ret = rk628_csi_get_detected_timings(sd, timings);mutex_unlock(&csi->confctl_mutex);if (ret)return ret;if (debug)v4l2_print_dv_timings(sd->name, "rk628_csi_query_dv_timings: ",timings, false);if (!v4l2_valid_dv_timings(timings, &rk628_csi_timings_cap, NULL,NULL)) {v4l2_dbg(1, debug, sd, "%s: timings out of range\n", __func__);return -ERANGE;}return 0;
}
1.1.4 VIDIOC_SUBDEV_G_EDID
获取当前的EDID信息;
1.1.5 VIDIOC_SUBDEV_S_EDID
设置EDID,通常设置完会拉一下HPD,重新让信号源输出信号;
1.2 RK HDMI接口
这部分是RK HDMI-IN的私有接口,简要介绍如下:
1.2.1 RKMODULE_GET_HDMI_MODE
获取mode参数,判断当前是否是HDMI-IN的类型,通常HDMI-IN的转接芯片需要返回1即可。
case RKMODULE_GET_HDMI_MODE:*(int *)arg = RKMODULE_HDMIIN_MODE;break;
1.2.2 RK_HDMIRX_CMD_GET_FPS
读取当前的帧率信息。
1.2.3 RK_HDMIRX_CMD_GET_HDCP_ENC_STATUS
读取当前的驱动的HDCP状态;
1.2.4 RK_HDMIRX_CMD_GET_INPUT_MODE
获取当前的输入模式,判断是否是DVI模式
1.2.5 RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS
获取判断当前的信号锁定状态;
1.2.6 RK_HDMIRX_CMD_GET_SCAN_MODE
获取当前HDMI-RX的scan mode,即隔行还是逐行信号;
1.2.7 RK_HDMIRX_CMD_GET_COLOR_RANGE
获取当前hdmi-rx的色域信息
1.2.8 RK_HDMIRX_CMD_GET_COLOR_SPACE
获取当前hdmi-rx的颜色空间
1.2.9 RK_HDMIRX_CMD_GET_EDID_VERSION
获取当前的EDID版本;
1.2.10 RK_HDMIRX_CMD_SET_COLOR_RANGE
设置颜色空间转换方式;
1.2.11 RK_HDMIRX_CMD_SET_EDID_VERSION
设置EDID版本;
1.3 RK camera接口
这部分是RK camera相关的私有接口,主要介绍如下:
1.3.1 RKMODULE_GET_MODULE_INFO
获取当前的模块信息,注意module name的匹配与index的设置,需要在dts配置。
module name对接TV框架时候需要用到
1.3.2 RKMODULE_GET_CSI_DSI_INFO
获取判断当前输出是CSI还是DSI,一般驱动使用,用户无用
1.3.3 RKMODULE_GET_DSI_MODE
获取判断DSI模式的类别,有video mode跟command mode,对于用户没用
2.应用示例
以下以一个简要的示例介绍一下用户如何使用这些接口来获取驱动的相关信息。
1.获取找到当前的节点,RK628F的设备节点是/dev/v4l-subdev,需要根据接口RKMODULE_GET_HDMI_MODE来获取判断当前的节点是否为hdmi-in的节点,也可以通过RKMODULE_GET_MODULE_INFO接口获取设备名称来判断。
2.参考示例,可以根据VIDIOC_G_CTRL接口来获取当前驱动的拔插状态,在设备插入状态下载获取相关的信息。
3.执行相关ioctl获取驱动的信息。
4.获取完毕,关闭文件节点。
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <string.h>
#include <linux/videodev2.h>
#include <linux/v4l2-subdev.h>#define RKMODULE_GET_HDMI_MODE \_IOR('V', BASE_VIDIOC_PRIVATE + 34, __u32)#define RK_HDMIRX_CMD_GET_FPS \_IOR('V', BASE_VIDIOC_PRIVATE + 0, int)#define RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS \_IOR('V', BASE_VIDIOC_PRIVATE + 1, int)#define RK_HDMIRX_CMD_GET_COLOR_SPACE \_IOR('V', BASE_VIDIOC_PRIVATE + 10, int)const int kMaxDevicePathLen = 256;
const char* kDevicePath = "/dev/";
const char kPrefix[] = "v4l-subdev";
const int kPrefixLen = sizeof(kPrefix) - 1;
const int kDevicePrefixLen = sizeof(kDevicePath) + kPrefixLen + 1;
char kV4l2DevicePath[kMaxDevicePathLen];
int mipifd = 0;static const char *bus_color_space_str[8] = {"xvYCC601", "xvYCC709", "sYCC601", "Adobe_YCC601","Adobe_RGB", "BT2020_YcCbcCrc", "BT2020_RGB_OR_YCbCr", "RGB"
};int find_mipi_fd()
{DIR *devdir;struct dirent* de;int videofd;int ret;devdir = opendir(kDevicePath);if(devdir == 0) {printf("%s: cannot open %s!\n", __FUNCTION__, kDevicePath);return -1;}while ((de = readdir(devdir)) != 0) {if (!strncmp(kPrefix, de->d_name, kPrefixLen)) {printf("found %s\n", de->d_name);snprintf(kV4l2DevicePath, kMaxDevicePathLen,"%s%s", kDevicePath, de->d_name);videofd = open(kV4l2DevicePath, O_RDWR);if (videofd < 0){printf("[%s %d] open device failed:%x\n", __FUNCTION__, __LINE__, videofd);continue;} else {uint32_t ishdmi;ret = ioctl(videofd, RKMODULE_GET_HDMI_MODE, (void*)&ishdmi);if (ret < 0) {printf("RKMODULE_GET_HDMI_MODE Failed\n");close(videofd);continue;}printf("%s RKMODULE_GET_HDMI_MODE:%d\n",kV4l2DevicePath,ishdmi);if (ishdmi) {mipifd = videofd;printf("MipiHdmi fd:%d\n",mipifd);if (mipifd < 0) {return -1;}}}}} closedir(devdir);return ret;
}int main()
{int ret;int fd = -1;find_mipi_fd();fd = mipifd;if (fd < 0) {printf("find mipi dev fail\n");return -1;}//查询拔插状态struct v4l2_control control;control.id = V4L2_CID_DV_RX_POWER_PRESENT;ret = ioctl(fd, VIDIOC_G_CTRL, &control);if (ret < 0) {printf("Set POWER_PRESENT failed ,%d\n", ret);}if (control.value == 1) {//获取信号状态与分辨率int signal_status = 0;int ret = ioctl(fd, RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS, &signal_status);if (ret < 0)printf("RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS failed: %d\n", ret);printf("get signal status:%d\n", signal_status);struct v4l2_dv_timings timings;int err = ioctl(fd, VIDIOC_SUBDEV_QUERY_DV_TIMINGS, &timings);if (ret < 0)printf("VIDIOC_SUBDEV_QUERY_DV_TIMINGS failed: %d\n", ret);const struct v4l2_bt_timings *bt = &timings.bt;printf("hact:%d, hfp:%d, hs:%d, hbp:%d, vact:%d, vfp:%d, vs:%d, vbp:%d, interlace:%d\n",bt->width, bt->hfrontporch, bt->hsync, bt->hbackporch, bt->height, bt->vfrontporch, bt->vsync,bt->vbackporch, bt->interlaced);struct v4l2_subdev_format aFormat;err = ioctl(fd, VIDIOC_SUBDEV_G_FMT, &aFormat);if (err < 0)printf("VIDIOC_SUBDEV_G_FMT failed: %d\n", err);int fps;err = ioctl(fd, RK_HDMIRX_CMD_GET_FPS, &fps);if (err < 0)printf("RK_HDMIRX_CMD_GET_FPS failed: %d\n", err);printf("VIDIOC_SUBDEV_G_FMT: width: %d, height: %d, fps: %d\n", aFormat.format.width,aFormat.format.height, fps);int color_space = 0;ret = ioctl(fd, RK_HDMIRX_CMD_GET_COLOR_SPACE, &color_space);if (ret < 0)printf("RK_HDMIRX_CMD_GET_COLOR_SPACE failed: %d\n", ret);printf("get color space:%s\n", bus_color_space_str[color_space]);} else {printf("get 5V:%d, hdmi plug out\n", control.value);}close(fd);return 0;
}