去年刚进实验室的时候,实验室有有人在从事Windows双屏显示驱动的开发。项目难度很大,因为相关Windows的东西基本都是闭源的,资料少之又少,因此项目进展也很慢。我也被配安排帮助开发驱动程序,当时给我的任务是写一个Windows驱动下读取显示器的EDID的程序。
EDID(Extended Display Identification Data :扩展显示标识数据,一种VESA标准数据格式(显卡有四种总线类型:IAS、VESA、PCI、APG,我们现有程序就是VESA总线)):包含有关显示器及其性能的参数,包括供应商信息、最大图像大小、厂商预设值、分辨率、频率范围的限制、显示器名和序列号的字符串等信息。基本EDID有128个字节,保存在display节中,这些信息可通过DDC与系统进行通信,是在显示器和GPU之间进行的。EDID数据读取到之后,可将相关参数传递给PC的显卡驱动,从而做出调整,使显示内容(数据)与显示屏相匹配。
基本的EDID拥有128个字节信息,其信息如下:

上述是HDMI的工作原理,然而显卡驱动代码中并没有类似HDMI数据传输过程的具体实现,只是通过命令直接获取数据,因此可以推测HDMI是通过一个控制器来获取数据的。果然,在HD40的主板原理图上发现了HDMI控制器anx7150。
关于anx7150,我也简要的阅读了其数据手册,主要了解了该控制器的读取EDID的流程图、状态转移图等,并与显卡驱动中进行了核对。
VGA(Video Graphics Array)视频图形阵列是IBM于1987年提出的一个使用模拟信号的电脑显示标准。VGA接口即电脑采用VGA标准输出数据的专用接口。如下图所示,VGA接口的接口一共有15个通道,主要的数据通道时: 1、2、3通道,分别传输R、G、B三原色信号,以及13、14通道传输行、场同步信号。

EDID
首先有必要了解一下EDID是什么?EDID(Extended Display Identification Data :扩展显示标识数据,一种VESA标准数据格式(显卡有四种总线类型:IAS、VESA、PCI、APG,我们现有程序就是VESA总线)):包含有关显示器及其性能的参数,包括供应商信息、最大图像大小、厂商预设值、分辨率、频率范围的限制、显示器名和序列号的字符串等信息。基本EDID有128个字节,保存在display节中,这些信息可通过DDC与系统进行通信,是在显示器和GPU之间进行的。EDID数据读取到之后,可将相关参数传递给PC的显卡驱动,从而做出调整,使显示内容(数据)与显示屏相匹配。
基本的EDID拥有128个字节信息,其信息如下:
- 0-7: 头信息,由00 FF FF FF FF FF FF 00 这8个字节组成
- 8-9: 厂商ID
- 10-11: 产品ID
- 12-15: 32-bit序列号
- 16-17 : 制造日期
- 18-19 : EDID 版本
- 20-24 : 显示器的基本信息(视频输入定义,最大横向图像尺寸,最大纵向图像尺寸,显示传输特性,特征支持)
- 25-34 : 显示器的颜色特征
- 35-37 : Established Timings
- 38-53 : Standard Timings Identification
- 54-125:Detailed Timing Description
- 126: 扩展标志位
- 127: 求和验证值
EDID能够为显示器的初始化配置提供环境参数,是显示驱动不可缺少的输入数据,因此读取EDID是我本次任务的最终目标。
HDMI:高清晰度多媒体接口
在我手里有参考价值的资料是Windows显卡驱动的中通过HDMI读取EDID的程序。虽然我的目标是通过VGA读取EDID,但是在没有任何驱动开发经验的情况下,有必要先了解一下显卡驱动中HDMI部分的代码,以作为VGA程序开发的借鉴和参考。在看代码的同时,我也调研了HDMI数据传输的机制。下面对此做简要介绍。
HDMI特点
- 支持EDID和DDC2B标准,设备之间可智能选择最佳匹配连接方式
- 强大的版权保护机制:HDCP
- 支持24bit色深处理,(RGB,YCbCr4-4-4,TCbCr4-2-2)
- 完全兼容DVI接口标准
- 支持热拔插
- 采用TMDS(最小传输差分传输技术),利用两个引脚间电压差来传送信号的技术
- 每个标准的HDMI连接,都包含3个用于传输数据的TMDS传输通道,1个独立的TMDS时钟通道(保证传输时所需的统一时序)。每个TMDS通道都能传输10bits的数据流(有多种编码格式)
- HDMI把视频信号分为:R、G、B、H、V五种信号,用TMDS技术编码
数据通道
- TMDS:三个通道传输R、G、B三原色,HV编码在B信号通道里传输,R、G的多余位置用来传输音频信号。
- DDC:显示数据通道,用来向视频接收装置发送配置信息和数据格式信息;接收装置读取这些E-EDID(增强扩展显示识别数据)
- CEC:消费电子控制通道,通过这条通道可以控制视听设备的工作
HDMI输入的源编码格式
- 视频像素数据(8位)
- 控制数据(2位)
- 数据包(4位):包含:音频数据、辅助信息数据
数据传输过程
视频数据传输期
- HDMI数据线上传送视频像素信号(数据)
- 视频信号经过编码,生成3路(3个TMDS数据传输通道,每路8位),共24位视频数据流,输入HDMI发射器中
- TMDS通道传输24位视频像素信号,将每通道的8位编码成10位,在每个10位像素时钟周期传送一个最小化的信号序列,视频信号被调制为TMDS数据信号传输出去,被接收器接收
岛屿数据传输期
- TMDS通道上将出现音频数据、辅助信息数据,这些数据每4位一组(即上述的4位数据包)
- 数据包也被调制成10位一组的TMDS信号,然后发出
- 视频数据传输期和岛屿数据传输期均开始于一个Guard Band保护频带,Guard Band由2个特殊的字符组成,为了明确限定控制数据传输期之后的跳转是视频数据传输期
控制数据传输期
- 在前面任意两个数据传输周期之间,每个TMDS包含2位的控制数据
- 3通道一共6位控制数据,分别为:HSYNC(行同步)、VSYNC(列同步)、CTL0、CTL1、CTL2、CTL3
- 每个TMDS通道包含2位控制数据,采用从2位到10位的编码方法,在每个控制周期的最后阶段
- CTL0、CTL1、CTL2、CTL3组成的头文件,说明下一个周期是:视频数据传输周期or岛屿数据传输周期?
上述是HDMI的工作原理,然而显卡驱动代码中并没有类似HDMI数据传输过程的具体实现,只是通过命令直接获取数据,因此可以推测HDMI是通过一个控制器来获取数据的。果然,在HD40的主板原理图上发现了HDMI控制器anx7150。
关于anx7150,我也简要的阅读了其数据手册,主要了解了该控制器的读取EDID的流程图、状态转移图等,并与显卡驱动中进行了核对。
VGA
本次的任务是通过VGA读取EDID,那么有必要了解一下VGA。VGA(Video Graphics Array)视频图形阵列是IBM于1987年提出的一个使用模拟信号的电脑显示标准。VGA接口即电脑采用VGA标准输出数据的专用接口。如下图所示,VGA接口的接口一共有15个通道,主要的数据通道时: 1、2、3通道,分别传输R、G、B三原色信号,以及13、14通道传输行、场同步信号。
在数据传输类型方面,VGA和HDMI有一定的区别:HDMI完全是数字信号的传输,而VGA则是由数字信号转换为模拟信号,进行传输,因此VGA的接口芯片CS7123或GM7123其实就是一个DAC的转换器。

由上面这两点就产生了一个疑问:
显卡驱动接上显示屏,要想正常工作。首先就必须读取EDID,然后解析EDID,从而完成对不同的显示屏的不同配置。但是根据数据传输通道和信号传输类型,EDID不太可能是通过这五个数据通道传输过来的,也不太可能是将数据转换为模拟信号传输过来的。并且EDID是存储在EEPROM中的一段序列,通常读取时通过I2C来读取的。所以,思考后觉得应该VGA接口上有通道可以构成一个读取EDID的DDC通道。经深入调研,发现VGA上的11、12、15、4引脚是有着其他功能的。根据资料显示:

由上面这两点就产生了一个疑问:
显卡驱动接上显示屏,要想正常工作。首先就必须读取EDID,然后解析EDID,从而完成对不同的显示屏的不同配置。但是根据数据传输通道和信号传输类型,EDID不太可能是通过这五个数据通道传输过来的,也不太可能是将数据转换为模拟信号传输过来的。并且EDID是存储在EEPROM中的一段序列,通常读取时通过I2C来读取的。所以,思考后觉得应该VGA接口上有通道可以构成一个读取EDID的DDC通道。经深入调研,发现VGA上的11、12、15、4引脚是有着其他功能的。根据资料显示:
- Pin11:ID0/RES formerly Monitor ID bit 0, reserved since E-DDC
- Pin12:ID1/SDA formerly Monitor ID bit 1, I2C data since DDC2
- Pin15:ID3/SCL formerly Monitor ID bit 3, I2C clock since DDC2
- Pin4 :ID2/RES formerly Monitor ID bit 2, reserved since E-DDC
GPIO
由于要进行软件模拟GPIO,就需要知道如何对GPIO进行操作。根据文档显示:GPIO中共有9个寄存器,其中一个为只读寄存器,2个为只写寄存器,另外6个为可读写寄存器。GPIO的基地址为0xee500000,下表为涉及到GPIO操作所需的寄存器的基本信息。方案确定后,直接编写代码。尽管代码中I2C的实现很容易,但是关于程序的初始化设置很复杂,涉及到虚拟内存到物理内存的映射,相关配置,这涉及到一系列的参数设置等等。
在读取EDID过程中,遇到了一个花了两天才解决的问题,即使用的显示器的EEPROM无法进行读取(之前据说该显示器就有些问题)。当时显示器能使用,但是却无法读取EDID,这让我不断的尝试修改代码,最后通过换了一个显示器,成功读取了EDID。
转自:http://blog.youkuaiyun.com/u014276460/article/details/46754451