RK3399 HDMI
回帖(1)
2022-3-7 09:54:54
0 前言
刚买的HDMI没有配DSI接口的屏幕,大多数情况下使用的是HDMI屏幕,所以搞清楚HDMI驱动对后面的学习很有必要。
1 HDMI驱动相关代码查询
要想找到HDMI驱动位置,先编译一遍kernel,然后找相关的.o文件:
zhu@zhu-VirtualBox:~/Work/Projects/rk3399/srcs/Android-8.1/android/kernel/drivers$ find -name *hdmi*.o
./gpu/drm/rockchip/dw_hdmi-rockchip.o
./gpu/drm/rockchip/inno_hdmi.o
./gpu/drm/bridge/synopsys/dw-hdmi-hdcp.o
./gpu/drm/bridge/synopsys/dw-hdmi.o
./gpu/drm/bridge/synopsys/dw-hdmi-cec.o
./gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.o
./video/hdmi.o
./video/hdmi-notifier.o
./phy/rockchip/phy-rockchip-inno-hdmi-phy.o
2 驱动接口分析
不管是HDMI还是DSI接口的屏,最后都会使用DRM框架的crtc来操作,先grep下file_operations结构体:
2.1 在./gpu/drm/rockchip/下grep
rockchip_drm_drv.c:1658:static const struct file_operations rockchip_drm_driver_fops = {
进去看看其对应的驱动设备,这应该就是DRM驱动接口,里面的ioctl是给libdrm使用的,填图刷图在里面。
static const struct file_operations rockchip_drm_driver_fops = {
.owner = THIS_MODULE,
.open = drm_open,
.mmap = rockchip_gem_mmap,
.poll = drm_poll,
.read = drm_read,
.unlocked_ioctl = drm_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = drm_compat_ioctl,
#endif
.release = drm_release,
};
一个DRM驱动一定有一个drm_driver结构体:
static struct drm_driver rockchip_drm_driver = {
.driver_features = DRIVER_MODESET | DRIVER_GEM |
DRIVER_PRIME | DRIVER_ATOMIC |
DRIVER_RENDER, // 告诉 DRM Core 当前驱动支持 modeset/gem等操作
.preclose = rockchip_drm_preclose,
.lastclose = rockchip_drm_lastclose,
.get_vblank_counter = drm_vblank_no_hw_counter,
.open = rockchip_drm_open,
.postclose = rockchip_drm_postclose,
.enable_vblank = rockchip_drm_crtc_enable_vblank,
.disable_vblank = rockchip_drm_crtc_disable_vblank,
.gem_vm_ops = &rockchip_drm_vm_ops,
.gem_free_object = rockchip_gem_free_object,
.dumb_create = rockchip_gem_dumb_create, // 创建buffer
.dumb_map_offset = rockchip_gem_dumb_map_offset, // mmap buffer
.dumb_destroy = drm_gem_dumb_destroy,
.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
.gem_prime_import = drm_gem_prime_import,
.gem_prime_export = drm_gem_prime_export,
.gem_prime_get_sg_table = rockchip_gem_prime_get_sg_table,
.gem_prime_import_sg_table = rockchip_gem_prime_import_sg_table,
.gem_prime_vmap = rockchip_gem_prime_vmap,
.gem_prime_vunmap = rockchip_gem_prime_vunmap,
.gem_prime_mmap = rockchip_gem_mmap_buf,
.gem_prime_begin_cpu_access = rockchip_gem_prime_begin_cpu_access,
.gem_prime_end_cpu_access = rockchip_gem_prime_end_cpu_access,
#ifdef CONFIG_DEBUG_FS
.debugfs_init = rockchip_drm_debugfs_init,
.debugfs_cleanup = rockchip_drm_debugfs_cleanup,
#endif
.ioctls = rockchip_ioctls,
.num_ioctls = ARRAY_SIZE(rockchip_ioctls),
.fops = &rockchip_drm_driver_fops, // 对应上面的fops
.name = DRIVER_NAME,
.desc = DRIVER_DESC,
.date = DRIVER_DATE,
.major = DRIVER_MAJOR,
.minor = DRIVER_MINOR,
};
DRM初始化过程:
rockchip_drm_platform_probe // 驱动入口 @kernel/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
|-->component_master_add_with_match(dev, &rockchip_drm_ops, match) // @kernel-4.14/drivers/base/component.c
|-->try_to_bring_up_master
|-->master->ops->bind(master->dev)
|-->rockchip_drm_bind // @kernel/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
|-->drm_dev = drm_dev_alloc(&rockchip_drm_driver, dev) // struct drm_device * drm_dev @kernel/drivers/gpu/drm/drm_drv.c 分配并初始化一个DRM设备
// drm_dev->driver = rockchip_drm_driver
|-->rockchip_drm_init_iommu
|-->drm_mode_config_init(drm_dev) // @kernel/drivers/gpu/drm/drm_crtc.c
| |-->drm_mode_create_standard_properties(dev) // 创建DRM属性
|-->rockchip_drm_mode_config_init(drm_dev) // 设置fb的最大最小宽高
|-->rockchip_drm_create_properties(drm_dev) // 创建CABC等属性
|-->component_bind_all(dev, drm_dev) //Try to bind all sub drivers
|-->rockchip_attach_connector_property(drm_dev) // 对于每个connector, 亮度、饱和度、对比度、色调都设置为100
|-->drm_vblank_init(drm_dev, drm_dev->mode_config.num_crtc) // 初始化vblank
|-->drm_mode_config_reset(drm_dev)
|-->rockchip_drm_set_property_default(drm_dev) // 对于每个connector, 亮度、饱和度、对比度、色调都设置为50
|-->drm_dev->irq_enabled = true // 可以使用vblank feature
|-->drm_kms_helper_poll_init(drm_dev)
|-->drm_dev->vblank_disable_allowed = true // vblank中断disable
|-->rockchip_gem_pool_init(drm_dev)
|-->of_reserved_mem_device_init(drm_dev->dev)
|-->rockchip_drm_fbdev_init(drm_dev)
|-->drm_dev_register(drm_dev, 0) // 注册drm设备
|-->drm_minor_register(dev, DRM_MINOR_CONTROL)
|-->drm_minor_register(dev, DRM_MINOR_RENDER)
|-->drm_minor_register(dev, DRM_MINOR_PRIMARY)
|-->dev->driver->load(dev, flags)
还有1个很重要的结构体:
static const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs = {
.fb_create = rockchip_user_fb_create, // 创建buffer
.output_poll_changed = rockchip_drm_output_poll_changed,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = rockchip_drm_atomic_commit, // 属性生效
};
2.2 在./gpu/drm/bridge/synopsys/下grep
dw-hdmi.c:3264:static const struct file_operations dw_hdmi_status_fops = {
dw-hdmi.c:3354:static const struct file_operations dw_hdmi_ctrl_fops = {
dw-hdmi.c:3404:static const struct file_operations dw_hdmi_phy_fops = {
以上三个fops都是debugfs文件节点操作函数:在/d/dw-hdmi/status、/d/dw-hdmi/ctrl和/d/dw-hdmi/phy
所以他们应该是用来调试的,其中dw_hdmi_ctrl_fops中的write可以用来写寄存器:
static ssize_t
dw_hdmi_ctrl_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
struct dw_hdmi *hdmi =
((struct seq_file *)file->private_data)->private;
u32 reg, val;
char kbuf[25];
if (hdmi->dev_type == RK3228_HDMI)
return -EFAULT;
if (copy_from_user(kbuf, buf, count))
return -EFAULT;
if (sscanf(kbuf, "%x%x", ®, &val) == -1)
return -EFAULT;
if ((reg < 0) || (reg > HDMI_I2CM_FS_SCL_LCNT_0_ADDR)) {
dev_err(hdmi->dev, "it is no a hdmi registern");
return count;
}
dev_info(hdmi->dev, "/**********hdmi register config******/");
dev_info(hdmi->dev, "n reg=%x val=%xn", reg, val);
hdmi_writeb(hdmi, val, reg);
return count;
}
dw_hdmi_phy_fops中的write可以用来写寄存器:
static ssize_t
dw_hdmi_phy_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
struct dw_hdmi *hdmi =
((struct seq_file *)file->private_data)->private;
u32 reg, val;
char kbuf[25];
if (copy_from_user(kbuf, buf, count))
return -EFAULT;
if (sscanf(kbuf, "%x%x", ®, &val) == -1)
return -EFAULT;
if ((reg < 0) || (reg > 0x100)) {
dev_err(hdmi->dev, "it is not a hdmi phy registern");
return count;
}
dev_info(hdmi->dev, "/*******hdmi phy register config******/");
dev_info(hdmi->dev, "n reg=%x val=%xn", reg, val);
dw_hdmi_phy_i2c_write(hdmi, val, reg);
return count;
}
那么上面写的HDMI相关寄存器到底是啥?
根据read系统调用(read使用到了seq_file方法[5]),grep 寄存器宏定义得到:
#define HDMI_FC_DRM_UP 0x1167
#define HDMI_FC_DRM_HB0 0x1168
#define HDMI_FC_DRM_HB1 0x1169
#define HDMI_FC_DRM_PB0 0x116a
#define HDMI_FC_DRM_PB1 0x116b
#define HDMI_FC_DRM_PB2 0x116c
#define HDMI_FC_DRM_PB3 0x116d
#define HDMI_FC_DRM_PB4 0x116e
#define HDMI_FC_DRM_PB5 0x116f
#define HDMI_FC_DRM_PB6 0x1170
#define HDMI_FC_DRM_PB7 0x1171
#define HDMI_FC_DRM_PB8 0x1172
#define HDMI_FC_DRM_PB9 0x1173
#define HDMI_FC_DRM_PB10 0x1174
#define HDMI_FC_DRM_PB11 0x1175
#define HDMI_FC_DRM_PB12 0x1176
#define HDMI_FC_DRM_PB13 0x1177
#define HDMI_FC_DRM_PB14 0x1178
#define HDMI_FC_DRM_PB15 0x1179
#define HDMI_FC_DRM_PB16 0x117a
#define HDMI_FC_DRM_PB17 0x117b
#define HDMI_FC_DRM_PB18 0x117c
#define HDMI_FC_DRM_PB19 0x117d
#define HDMI_FC_DRM_PB20 0x117e
#define HDMI_FC_DRM_PB21 0x117f
#define HDMI_FC_DRM_PB22 0x1180
#define HDMI_FC_DRM_PB23 0x1181
#define HDMI_FC_DRM_PB24 0x1182
#define HDMI_FC_DRM_PB25 0x1183
#define HDMI_FC_DRM_PB26 0x1184
0 前言
刚买的HDMI没有配DSI接口的屏幕,大多数情况下使用的是HDMI屏幕,所以搞清楚HDMI驱动对后面的学习很有必要。
1 HDMI驱动相关代码查询
要想找到HDMI驱动位置,先编译一遍kernel,然后找相关的.o文件:
zhu@zhu-VirtualBox:~/Work/Projects/rk3399/srcs/Android-8.1/android/kernel/drivers$ find -name *hdmi*.o
./gpu/drm/rockchip/dw_hdmi-rockchip.o
./gpu/drm/rockchip/inno_hdmi.o
./gpu/drm/bridge/synopsys/dw-hdmi-hdcp.o
./gpu/drm/bridge/synopsys/dw-hdmi.o
./gpu/drm/bridge/synopsys/dw-hdmi-cec.o
./gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.o
./video/hdmi.o
./video/hdmi-notifier.o
./phy/rockchip/phy-rockchip-inno-hdmi-phy.o
2 驱动接口分析
不管是HDMI还是DSI接口的屏,最后都会使用DRM框架的crtc来操作,先grep下file_operations结构体:
2.1 在./gpu/drm/rockchip/下grep
rockchip_drm_drv.c:1658:static const struct file_operations rockchip_drm_driver_fops = {
进去看看其对应的驱动设备,这应该就是DRM驱动接口,里面的ioctl是给libdrm使用的,填图刷图在里面。
static const struct file_operations rockchip_drm_driver_fops = {
.owner = THIS_MODULE,
.open = drm_open,
.mmap = rockchip_gem_mmap,
.poll = drm_poll,
.read = drm_read,
.unlocked_ioctl = drm_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = drm_compat_ioctl,
#endif
.release = drm_release,
};
一个DRM驱动一定有一个drm_driver结构体:
static struct drm_driver rockchip_drm_driver = {
.driver_features = DRIVER_MODESET | DRIVER_GEM |
DRIVER_PRIME | DRIVER_ATOMIC |
DRIVER_RENDER, // 告诉 DRM Core 当前驱动支持 modeset/gem等操作
.preclose = rockchip_drm_preclose,
.lastclose = rockchip_drm_lastclose,
.get_vblank_counter = drm_vblank_no_hw_counter,
.open = rockchip_drm_open,
.postclose = rockchip_drm_postclose,
.enable_vblank = rockchip_drm_crtc_enable_vblank,
.disable_vblank = rockchip_drm_crtc_disable_vblank,
.gem_vm_ops = &rockchip_drm_vm_ops,
.gem_free_object = rockchip_gem_free_object,
.dumb_create = rockchip_gem_dumb_create, // 创建buffer
.dumb_map_offset = rockchip_gem_dumb_map_offset, // mmap buffer
.dumb_destroy = drm_gem_dumb_destroy,
.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
.gem_prime_import = drm_gem_prime_import,
.gem_prime_export = drm_gem_prime_export,
.gem_prime_get_sg_table = rockchip_gem_prime_get_sg_table,
.gem_prime_import_sg_table = rockchip_gem_prime_import_sg_table,
.gem_prime_vmap = rockchip_gem_prime_vmap,
.gem_prime_vunmap = rockchip_gem_prime_vunmap,
.gem_prime_mmap = rockchip_gem_mmap_buf,
.gem_prime_begin_cpu_access = rockchip_gem_prime_begin_cpu_access,
.gem_prime_end_cpu_access = rockchip_gem_prime_end_cpu_access,
#ifdef CONFIG_DEBUG_FS
.debugfs_init = rockchip_drm_debugfs_init,
.debugfs_cleanup = rockchip_drm_debugfs_cleanup,
#endif
.ioctls = rockchip_ioctls,
.num_ioctls = ARRAY_SIZE(rockchip_ioctls),
.fops = &rockchip_drm_driver_fops, // 对应上面的fops
.name = DRIVER_NAME,
.desc = DRIVER_DESC,
.date = DRIVER_DATE,
.major = DRIVER_MAJOR,
.minor = DRIVER_MINOR,
};
DRM初始化过程:
rockchip_drm_platform_probe // 驱动入口 @kernel/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
|-->component_master_add_with_match(dev, &rockchip_drm_ops, match) // @kernel-4.14/drivers/base/component.c
|-->try_to_bring_up_master
|-->master->ops->bind(master->dev)
|-->rockchip_drm_bind // @kernel/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
|-->drm_dev = drm_dev_alloc(&rockchip_drm_driver, dev) // struct drm_device * drm_dev @kernel/drivers/gpu/drm/drm_drv.c 分配并初始化一个DRM设备
// drm_dev->driver = rockchip_drm_driver
|-->rockchip_drm_init_iommu
|-->drm_mode_config_init(drm_dev) // @kernel/drivers/gpu/drm/drm_crtc.c
| |-->drm_mode_create_standard_properties(dev) // 创建DRM属性
|-->rockchip_drm_mode_config_init(drm_dev) // 设置fb的最大最小宽高
|-->rockchip_drm_create_properties(drm_dev) // 创建CABC等属性
|-->component_bind_all(dev, drm_dev) //Try to bind all sub drivers
|-->rockchip_attach_connector_property(drm_dev) // 对于每个connector, 亮度、饱和度、对比度、色调都设置为100
|-->drm_vblank_init(drm_dev, drm_dev->mode_config.num_crtc) // 初始化vblank
|-->drm_mode_config_reset(drm_dev)
|-->rockchip_drm_set_property_default(drm_dev) // 对于每个connector, 亮度、饱和度、对比度、色调都设置为50
|-->drm_dev->irq_enabled = true // 可以使用vblank feature
|-->drm_kms_helper_poll_init(drm_dev)
|-->drm_dev->vblank_disable_allowed = true // vblank中断disable
|-->rockchip_gem_pool_init(drm_dev)
|-->of_reserved_mem_device_init(drm_dev->dev)
|-->rockchip_drm_fbdev_init(drm_dev)
|-->drm_dev_register(drm_dev, 0) // 注册drm设备
|-->drm_minor_register(dev, DRM_MINOR_CONTROL)
|-->drm_minor_register(dev, DRM_MINOR_RENDER)
|-->drm_minor_register(dev, DRM_MINOR_PRIMARY)
|-->dev->driver->load(dev, flags)
还有1个很重要的结构体:
static const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs = {
.fb_create = rockchip_user_fb_create, // 创建buffer
.output_poll_changed = rockchip_drm_output_poll_changed,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = rockchip_drm_atomic_commit, // 属性生效
};
2.2 在./gpu/drm/bridge/synopsys/下grep
dw-hdmi.c:3264:static const struct file_operations dw_hdmi_status_fops = {
dw-hdmi.c:3354:static const struct file_operations dw_hdmi_ctrl_fops = {
dw-hdmi.c:3404:static const struct file_operations dw_hdmi_phy_fops = {
以上三个fops都是debugfs文件节点操作函数:在/d/dw-hdmi/status、/d/dw-hdmi/ctrl和/d/dw-hdmi/phy
所以他们应该是用来调试的,其中dw_hdmi_ctrl_fops中的write可以用来写寄存器:
static ssize_t
dw_hdmi_ctrl_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
struct dw_hdmi *hdmi =
((struct seq_file *)file->private_data)->private;
u32 reg, val;
char kbuf[25];
if (hdmi->dev_type == RK3228_HDMI)
return -EFAULT;
if (copy_from_user(kbuf, buf, count))
return -EFAULT;
if (sscanf(kbuf, "%x%x", ®, &val) == -1)
return -EFAULT;
if ((reg < 0) || (reg > HDMI_I2CM_FS_SCL_LCNT_0_ADDR)) {
dev_err(hdmi->dev, "it is no a hdmi registern");
return count;
}
dev_info(hdmi->dev, "/**********hdmi register config******/");
dev_info(hdmi->dev, "n reg=%x val=%xn", reg, val);
hdmi_writeb(hdmi, val, reg);
return count;
}
dw_hdmi_phy_fops中的write可以用来写寄存器:
static ssize_t
dw_hdmi_phy_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
struct dw_hdmi *hdmi =
((struct seq_file *)file->private_data)->private;
u32 reg, val;
char kbuf[25];
if (copy_from_user(kbuf, buf, count))
return -EFAULT;
if (sscanf(kbuf, "%x%x", ®, &val) == -1)
return -EFAULT;
if ((reg < 0) || (reg > 0x100)) {
dev_err(hdmi->dev, "it is not a hdmi phy registern");
return count;
}
dev_info(hdmi->dev, "/*******hdmi phy register config******/");
dev_info(hdmi->dev, "n reg=%x val=%xn", reg, val);
dw_hdmi_phy_i2c_write(hdmi, val, reg);
return count;
}
那么上面写的HDMI相关寄存器到底是啥?
根据read系统调用(read使用到了seq_file方法[5]),grep 寄存器宏定义得到:
#define HDMI_FC_DRM_UP 0x1167
#define HDMI_FC_DRM_HB0 0x1168
#define HDMI_FC_DRM_HB1 0x1169
#define HDMI_FC_DRM_PB0 0x116a
#define HDMI_FC_DRM_PB1 0x116b
#define HDMI_FC_DRM_PB2 0x116c
#define HDMI_FC_DRM_PB3 0x116d
#define HDMI_FC_DRM_PB4 0x116e
#define HDMI_FC_DRM_PB5 0x116f
#define HDMI_FC_DRM_PB6 0x1170
#define HDMI_FC_DRM_PB7 0x1171
#define HDMI_FC_DRM_PB8 0x1172
#define HDMI_FC_DRM_PB9 0x1173
#define HDMI_FC_DRM_PB10 0x1174
#define HDMI_FC_DRM_PB11 0x1175
#define HDMI_FC_DRM_PB12 0x1176
#define HDMI_FC_DRM_PB13 0x1177
#define HDMI_FC_DRM_PB14 0x1178
#define HDMI_FC_DRM_PB15 0x1179
#define HDMI_FC_DRM_PB16 0x117a
#define HDMI_FC_DRM_PB17 0x117b
#define HDMI_FC_DRM_PB18 0x117c
#define HDMI_FC_DRM_PB19 0x117d
#define HDMI_FC_DRM_PB20 0x117e
#define HDMI_FC_DRM_PB21 0x117f
#define HDMI_FC_DRM_PB22 0x1180
#define HDMI_FC_DRM_PB23 0x1181
#define HDMI_FC_DRM_PB24 0x1182
#define HDMI_FC_DRM_PB25 0x1183
#define HDMI_FC_DRM_PB26 0x1184
举报
更多回帖