Windows显示驱动中读取EDID

去年刚进实验室的时候,实验室有有人在从事Windows双屏显示驱动的开发。项目难度很大,因为相关Windows的东西基本都是闭源的,资料少之又少,因此项目进展也很慢。我也被配安排帮助开发驱动程序,当时给我的任务是写一个Windows驱动下读取显示器的EDID的程序。

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目前已经存在五种版本(数据格式),EDID1.0、EDID1.1、EDID1.2、EDID1.3、EDID2.0。另外还一种Enhanced EDID,它时基于EDID 1.3的结构,可以存储更多的数据,数据长度是128+N*128。

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技术编码
Windows显示驱动中读取EDID_第1张图片

数据通道

  • 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数据传输过程的具体实现,只是通过命令直接获取数据,因此可以推测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通道传输行、场同步信号。

Windows显示驱动中读取EDID_第2张图片
在数据传输类型方面,VGA和HDMI有一定的区别:HDMI完全是数字信号的传输,而VGA则是由数字信号转换为模拟信号,进行传输,因此VGA的接口芯片CS7123或GM7123其实就是一个DAC的转换器。
Windows显示驱动中读取EDID_第3张图片

由上面这两点就产生了一个疑问:
显卡驱动接上显示屏,要想正常工作。首先就必须读取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
从中推测实际中Pin12、Pin15很有可能被用来读取EDID,果然在HD40的板子上,有两个GPIO直接连接到了VGA的这两个管脚。另外,从管脚的作用来开,可以通过I2C协议来进行数据读取。在HD40中集成了I2C模块,看看是否能够直接使用处理器中的这个模块。但是处理器的I2C模块的对外管脚却没有连接到VGA管脚上,那么只能通过GPIO来模拟I2C进行VGA的读取。

GPIO

由于要进行软件模拟GPIO,就需要知道如何对GPIO进行操作。根据文档显示:GPIO中共有9个寄存器,其中一个为只读寄存器,2个为只写寄存器,另外6个为可读写寄存器。GPIO的基地址为0xee500000,下表为涉及到GPIO操作所需的寄存器的基本信息。
Windows显示驱动中读取EDID_第4张图片
方案确定后,直接编写代码。尽管代码中I2C的实现很容易,但是关于程序的初始化设置很复杂,涉及到虚拟内存到物理内存的映射,相关配置,这涉及到一系列的参数设置等等。
在读取EDID过程中,遇到了一个花了两天才解决的问题,即使用的显示器的EEPROM无法进行读取(之前据说该显示器就有些问题)。当时显示器能使用,但是却无法读取EDID,这让我不断的尝试修改代码,最后通过换了一个显示器,成功读取了EDID。


你可能感兴趣的:(驱动)