㉔AW-H3 Linux驱动开发之HDMI驱动程序

HDMI: High Definition Multimedia Interface,高清多媒体接口,是一种全数字化视频和声音发送接口,可以发送未压缩的音频及视频信号。HDMI有4种类型的接口,分别为 type A, type B, type C和type D,下面我们来看一下这4种接口的定义:Pin type A type B type C type D 1 ...
摘要由CSDN通过智能技术生成

HDMI: High Definition Multimedia Interface,高清多媒体接口,是一种全数字化视频和声音发送接口,可以发送未压缩的音频及视频信号。HDMI有4种类型的接口,分别为 type A, type B, type C和type D,下面我们来看一下这4种接口的定义:

Pin type A type B type C type D
1 TMDS Data2+ TMDS Data2+ TMDS Data2 Shield Hot Plug Detect
2 TMDS Data2 Shield TMDS Data2 Shield TMDS Data2+ Utility
3 TMDS Data2– TMDS Data2– TMDS Data2– TMDS Data2+
4 TMDS Data1+ TMDS Data1+ TMDS Data1 Shield TMDS Data2 Shield
5 TMDS Data1 Shield TMDS Data1 Shield TMDS Data1+ TMDS Data2-
6 TMDS Data1– TMDS Data1– TMDS Data1– TMDS Data1+
7 TMDS Data0+ TMDS Data0+ TMDS Data0 Shield TMDS Data1 Shield
8 TMDS Data0 Shield TMDS Data0 Shield TMDS Data0+ TMDS Data1-
9 TMDS Data0– TMDS Data0– TMDS Data0– TMDS Data0+
10 TMDS Clock+ TMDS Clock+ TMDS Clock Shield TMDS Data0 Shield
11 TMDS Clock Shield TMDS Clock Shield TMDS Clock+ TMDS Data0-
12 TMDS Clock– TMDS Clock– TMDS Clock– TMDS Clock+
13 CEC TMDS Data5+ DDC/CEC Ground TMDS Clock Shield
14 Reserved(N.C. on device) TMDS Data5 Shield CEC TMDS Clock-
15 SCL TMDS Data5- SCL CEC
16 SDA TMDS Data4+ SDA DDC/CEC Ground
17 DDC/CEC Ground TMDS Data4 Shield Reserved(N.C. on device) SCL
18 +5V Power TMDS Data4- +5V Power SDA
19 Hot Plug Detect TMDS Data3+ Hot Plug Detect +5V Power
20 ---- TMDS Data3 Shield ---- ----
21 ---- TMDS Data3- ---- ----
22 ---- CEC ---- ----
23 ---- Reserved(N.C. on device) ---- ----
24 ---- Reserved(N.C. on device) ---- ----
25 ---- SCL ---- ----
26 ---- SDA ---- ----
27 ---- DDC/CEC Ground ---- ----
28 ---- +5V Power ---- ----
29 ---- Hot Plug Detect ---- ----

这里我们用的是type A的接口,电路图如下:

从上面可以看出HDMI采用差分数据的形式进行数据传输,有3组数据差分和一组时钟差分,类似的形式比如CAN, USB等都是通过差分的形式进行数据交互的,采用这种形式的好处是抗干扰能力强,而且速度快,比较新的HDMI 2.1最大传输速率可以达到42.6G bit/s,我们这里用到的全志的CPU是HDMI 1.4,理论上最大支持速率到8.16G bit/s,这个其实已经很快了,allwinner官方的datasheet上说可以支持30 fps的4K画质播放.下边是不同HDMI版本的区别:

接下来我们分析一下HDMI的硬件框架,上面的电路图上pin脚可以分为4部分:

第一部分:4组差分线,数据交互等工作.
第二部分:一组I2C总线,这里称为DDC,主要进行CPU和显示设备之间HDCP数据密钥交换和获取EDID的接口.
第三部分:CEC线,在HDMI上有多个显示器时,如果显示器都支持CEC,那么一个遥控就可以控制其它设备.
第四部分:HHPD线,热插拔检测引脚,驱动程序中会根据这个引脚的变化做拔插相关工作.

上面还有两个概念需要说一下:
HDCP: 高带宽数据内容保护,目的是对数据加密,保护知识产权.
EDID: 包含显示器及其性能参数.

allwinner H3上有集成HDMI控制器,大概的一个框架图如下:

从上面框架可以看出,支持HDMI和TV两种形式,datasheet上了解到,这款芯片支持同时输出HDMI和TV,这个的TV指的是CVBS,那么,我们可以通过这个功能实现双屏,说到双屏,这里简单提一下,双屏主要分为3种显示形式: 双屏同显, 双屏异显,双屏合显,当然,单屏也可以实现类似效果,这里只说一下双屏,实现双屏的形式有很多种方式,比如DSI + HDMI, DSI + CVBS,DSI + SPI,...有很多形式,当然,最好的方法其实是两个屏幕用同一组接口,通过片选或者地址选择,双屏同显看起来比较容易,双屏在公交车上也有用到,公交车的广告机屏1播放传媒视频,屏2播放PPT式广告,手机上比如努比亚,ZTE等都有推出双屏的手机.

好了,回到正题,继续说HDMI,接下来说一下软件部分:

本次使用的是Android进行验证,源码方面是7.0, Android N的代码,kernel使用的是Linux-4.4,和上次camera那一节使用的Linux-3.4代码上做了一些升级,HDMI这一部分还是有很大变动的,无论是HDMI专有部分还是通用部分,都进行了代码优化和变动,不过大致的框架还是差不多的,代码方面依然可以去参考Linux-3.4的,这里贴一下代码路径:

Linux-3.4在线看代码: https://github.com/orangepi-xunlong/orangepi_h3_linux

Android N全部压缩源代码: https://pan.baidu.com/s/1o9HIBii#list/path=%2F

这里简单说一下全志平台Android N的编译步骤,首先从百度云下载7.0的全部压缩包H3-sdk7.0-2017-11-03.tar.gzaa到*.gzan,然后在Ubuntu执行:

cat H3-sdk7.0-2017-11-03.tar.gza* > H3-Android7.0.tar.gz
tar -xvf H3-Android7.0.tar.gz

就可以解压得到Android和kernel源码,然后根据我之前写的编译环境搭建,安装以下Android源码的编译依赖,不过要注意,Android 7.0需要openjdk-8-jdk,不是6或者7,如果安装错了,则编译报错,如果有安装多个openjdk则根据我之前写的编译环境搭建,做一下切换即可.安装完编译依赖环境之后,上述所说的解压文件会得到两个文件夹,一个是android,另一个是lichee,我们进入lichee,做如下配置:

phoebus@Linux:~/xshark/Android/AndroidN/lichee$ ./build.sh config
Welcome to mkscript setup progress
All available chips:
   0. sun50iw1p1
   1. sun50iw2p1
   2. sun50iw6p1
   3. sun8iw11p1
   4. sun8iw12p1
   5. sun8iw6p1
   6. sun8iw7p1
   7. sun8iw8p1
   8. sun9iw1p1
Choice: 6
All available platforms:
   0. android
   1. dragonboard
   2. linux
   3. camdroid
Choice: 0
All available business:
   0. dolphin
   1. secure
   2. karaok
Choice: 0
LICHEE_BUSINESS=dolphin
using kernel 'linux-3.10':
All available kernel:
   0. linux-4.4
Choice: 0

然后会自动编译,如果没有自动编译,则直接运行./build.sh即可,等待编译完成,然后,进入android目录执行:

source ./build/envsetup.sh
lunch 28
extract-bsp
make -j8 && pack

因为我用的是H3,所以选择lunch 28,其它CPU根据实际情况选择编译对应版本的Android.下面主要说一下HDMI驱动的实现.在全志平台,video子系统这部分可以分为两部分,一部分是通用代码,另一部分是具体控制器专用驱动.这里用的H3只集成了HDMI和CVBS,所以目录结构如下:

通用部分代码量还是不少的,这里暂时主题是具体驱动实现,所以,暂时不讨论通用部分,CVBS使用的很少了,这里也先不说,重点说一下HDMI目录,目录结构如下:

可以看出来sun8iw11和sun50iw1工程,全志只是提供了动态库,并没有给出源码,应该是这部分涉及到一些全志的特色技术,但是不得不说,全志这种做法已经违反了GPL协议,GNU组织没有告全志,可能是觉得这个vendor应该太小了,来一趟还不够油钱,用<<惠子相梁>>形容一下.

因为这里用的是H3,代号是sun8iw7p1,这里正好这部分是开源的,所以动态库,对本次没有影响.我们先来看一下,这个目录的makefile:

obj-$(CONFIG_HDMI_DISP2_SUNXI) += hdmi.o

hdmi-y := drv_hdmi.o hdmi_core.o hdmi_edid.o
ifeq ($(CONFIG_ARM64),y)
$(shell cp $(obj)/libhdmi_sun50iw1 $(obj)/libhdmi_sun50iw1.a)
hdmi-$(CONFIG_ARCH_SUN50IW1P1) += libhdmi_sun50iw1.a
hdmi-$(CONFIG_ARCH_SUN50IW2P1) += libhdmi_sun50iw1.a
endif

ifeq ($(CONFIG_ARM),y)
$(shell cp $(obj)/libhdmi_sun8iw11 $(obj)/libhdmi_sun8iw11.a)
hdmi-$(CONFIG_ARCH_SUN50IW1P1) += libhdmi_sun8iw11.a
hdmi-$(CONFIG_ARCH_SUN50IW2P1) += libhdmi_sun8iw11.a
hdmi-$(CONFIG_ARCH_SUN8IW11)   += libhdmi_sun8iw11.a
hdmi-$(CONFIG_ARCH_SUN8IW12) += hdmi_bsp_sun8iw12.o
hdmi-$(CONFIG_ARCH_SUN8IW7) += hdmi_bsp_sun8iw7.o
endif

可以看出,这个目录的文件编译之后,会链接成一个hdmi.o,这个文件包括:drv_hdmi.c, hdmi_core.c, hdmi_edid.c,然后这里是sun8iw7p1,所以,还会包含:hdmi_bsp_sun8iw7.c,这就是HDMI功能实现的驱动代码,代码量不是很多,3K多行,它们的组织关系是, hdmi_bsp_sun8iw7.c和hdmi_edid.c为hdmi_core.c提供API, hdmi_core.c为drv_hdmi.c提供API,可以看出,主要实现就是在drv_hdmi.c中,这个文件是重点, 然后,需要我们实现的是hdmi_bsp_sun8iw7.c,不过这个全志已经实现了,所以,这里主要就是两个文件是我们比较关注的.因为时间比较紧,所以没有画这个驱动的框架图,这里先直接贴一下这两个文件的代码:

hdmi_bsp_sun8iw7.c

/*
 * Allwinner SoCs hdmi driver.
 *
 * Copyright (C) 2017 Allwinner.
 *
 * This file is licensed under the terms of the GNU General Public
 * License version 2.  This program is licensed "as is" without any
 * warranty of any kind, whether express or implied.
 */

#include "hdmi_bsp.h"
#include "hdmi_core.h"

static unsigned int hdmi_base_addr;
static unsigned int hdmi_version;
/*static struct audio_para glb_audio;*/
static unsigned int tmp_rcal_100, tmp_rcal_200;
static unsigned int rcal_flag;

#define get_bvalue(addr) (*((volatile unsigned char *)(addr)))
#define put_bvalue(addr, v) \
    (*((volatile unsigned char *)(addr)) = (unsigned char)(v))
#define get_wvalue(addr) (*((volatile unsigned long *)(addr)))
#define put_wvalue(addr, v) \
    (*((volatile unsigned long *)(addr)) = (unsigned long)(v))

static int hdmi_phy_set(struct video_para *video);

struct para_tab
{
    unsigned int para[19];
};

struct pcm_sf
{
    unsigned int sf;
    unsigned char cs_sf;
};

static struct para_tab ptbl[] = {
    {
  {6, 1, 1, 1, 5, 3, 0, 1, 4, 0, 0, 160, 20, 38, 124, 240, 22, 0, 0}},
    {
  {21, 11, 1, 1, 5, 3, 1, 1, 2, 0, 0, 160, 32, 24, 126, 32, 24, 0, 0}},
    {
  {2, 11, 0, 0, 2, 6, 1, 0, 9, 0, 0, 208, 138, 16, 62, 224, 45, 0, 0}},
    {
  {17, 11, 0, 0, 2, 5, 2, 0, 5, 0, 0, 208, 144, 12, 64, 64, 49, 0, 0}},
    {
  {19, 4, 0, 96, 5, 5, 2, 2, 5, 1, 0, 0, 188, 184, 40, 208, 30, 1, 1}},
    {
  {4, 4, 0, 96, 5, 5, 2, 1, 5, 0, 0, 0, 114, 110, 40, 208, 30, 1, 1}},
    {
  {20, 4, 0, 97, 7, 5, 4, 2, 2, 2, 0, 128, 208, 16, 44, 56, 22, 1, 1}},
    {
  {5, 4, 0, 97, 7, 5, 4, 1, 2, 0, 0, 128, 24, 88, 44, 56, 22, 1, 1}},
    {
  {31, 2, 0, 96, 7, 5, 4, 2, 4, 2, 0, 128, 208, 16, 44, 56, 45, 1, 1}},
    {
  {16, 2, 0, 96, 7, 5, 4, 1, 4, 0, 0, 128, 24, 88, 44, 56, 45, 1, 1}},
    {
  {32, 4, 0, 96, 7, 5, 4, 3, 4, 2, 0, 128, 62, 126, 44, 56, 45, 1, 1}},
    {
  {33, 4, 0, 0, 7, 5, 4, 2, 4, 2, 0, 128, 208, 16, 44, 56, 45, 1, 1}},
    {
  {34, 4, 0, 0, 7, 5, 4, 1, 4, 0, 0, 128, 24, 88, 44, 56, 45, 1, 1}},
    {
  {160, 2, 0, 96, 7, 5, 8, 3, 4, 2, 0, 128, 62, 126, 44, 157, 45, 1, 1}},
    {
  {147, 2, 0, 96, 5, 5, 5, 2, 5, 1, 0, 0, 188, 184, 40, 190, 30, 1, 1}},
    {
  {132, 2, 0, 96, 5, 5, 5, 1, 5, 0, 0, 0, 114, 110, 40, 160, 30, 1, 1}},
    {
  {257, 1, 0, 96, 15, 10, 8, 2, 8, 0, 0, 0, 48, 176, 88, 112, 90, 1, 1}},
    {
  {258, 1, 0, 96, 15, 10, 8, 5, 8, 4, 0, 0, 160, 32, 88, 112, 90, 1, 1}},
    {
  {259, 1, 0, 96, 15, 10, 8, 6, 8, 4, 0, 0, 124, 252, 88, 112, 90, 1, 1}},
    {
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
};

static unsigned char ca_table[64] = {
    0x00, 0x11, 0x01, 0x13, 0x02, 0x31, 0x03, 0x33, 0x04, 0x15, 0x05,
    0x17, 0x06, 0x35, 0x07, 0x37, 0x08, 0x55, 0x09, 0x57, 0x0a, 0x75,
    0x0b, 0x77, 0x0c, 0x5d, 0x0d, 0x5f, 0x0e, 0x7d, 0x0f, 0x7f, 0x10,
    0xdd, 0x11, 0xdf, 0x12, 0xfd, 0x13, 0xff, 0x14, 0x99, 0x15, 0x9b,
    0x16, 0xb9, 0x17, 0xbb, 0x18, 0x9d, 0x19, 0x9f, 0x1a, 0xbd, 0x1b,
    0xbf, 0x1c, 0xdd, 0x1d, 0xdf, 0x1e, 0xfd, 0x1f, 0xff,
};

static struct pcm_sf sf[10] = {
    {22050, 0x04},
    {44100, 0x00},
    {88200, 0x08},
    {176400, 0x0c},
    {24000, 0x06},
    {48000, 0x02},
    {96000, 0x0a},
    {192000, 0x0e},
    {32000, 0x03},
    {768000, 0x09},
};

static unsigned int n_t
  • 2
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值