【我所認知的BIOS】—>Clock generator

【我所認知的BIOS—>Clock generator

By LightSeed

2009-7-22

1、什么是 Clock generator

顾名思义,就是时钟发生器。它是一个块芯片,通过外接的晶振输入到芯片内部,进过锁相,分频(倍频)等等过程向外部的设备提供clock。那么我们来看看实际主板上的Clock generator样子吧。见图1

【我所認知的BIOS】—>Clock generator_第1张图片

1 Clock generator的实物图

2Clock generator的作用

很显然,它是提供clock给其他设备的。那么它都提供给哪些设备呢?比如说CPUPCIUSB等等,且不说其他设备我们就看看CPU这个一个设备。假如是我们的Clock generator出了问题,那么CPUclock就必定要出问题,在主板上CPU是处理一切数据和命令的东东,那么它都出了问题后果可想而知。(以前我的同事就有遇到过这样的bugClock generator提供的clock出了问题,结果净出些很莫名其妙的bug。)

就其根本原因时钟发生器(clock generator)的电子组件,会不断产生稳定间隔的电压脉冲,主板上所有的组件将随着这个时钟来同步进行运算动作。简单的说,数字产品必须要有时钟的控制,才能精确地处理数字信号,就好比动物的心跳一样。若时钟不稳定,轻则造成数字信号传送上的失误,重则导致数字设备无法正常运作。

3、读Clock generator的寄存器(read by block的实战)

对于我们BIOS engineer来说比较关心的还是它的寄存器了。所以我会重点谈谈我们是怎么其寄存器的。Clock generator其实是SMBUS device,所以我们应该用smbus的协议来操作。在它的datasheet里也是有相应的说明的。

有意思的是,正如我在“【我所認知的BIOS—>SMBUS”这一章里说的slave address其实都是在业界有相应的规定的。比如说我下的这个颗芯片的slave address就是D2(H)。那么我们在操作的时候就要用D2H来和Clock generator通信。在实现通信的过程前,让我们来先读读datasheet。在datasheet里规定了,我们要读取里面的信息必须要用,read by block的形式。(当然读取的形式,一般都会在datasheet里有详细说明的。)所以让我们再来回顾一下“【我所認知的BIOS—>SMBUS”章节里所讲的read by block的理论,并且用到我们现在的实践当中来。图2是芯片datasheet里的how to read截图。

【我所認知的BIOS】—>Clock generator_第2张图片

2 Clock generator里的how to read

从图里我们可以看出读取Clock generator寄存器的操作步骤。图中第一个方框是D2H(datasheet直接告诉我们的哦),其中还要看一下图中中下部分的那个红色方框,这里是由Clock generator发给host的准备要读取的字节数。(不是我们操作的哦)当然上面的一系列过程都是SMBUS上面的操作过程,但是我们实际操作的时候其实只需要操作SMBUS controller就可以了。它可以帮我们完成上面的大部分事情。那就让我们来看看read by block的核心吧。步骤大致如下:

①通过遍历PCI设备,比较class code来找到SMbus controllerbase address。这个base address我们可以参考ICH6datasheet的相关说明。(当然只要是ICH系列的datasheet都是可以查阅的。)它代表了SMBUSsystem I/O base address。也就是前面我们提到的SMBUSIO端口。(因为我们都要通过这些IO来实现我们动作比如说readwrite等等。关于怎么在我们的板子上获取这个base address,如果您有兴趣可以参考我的好友peterhublog“戏说BIOSclock generator”里有相应的程序操作。)

②根据SMBUS的协议,我们要先向controlleroffset 04h也就是(Transmit Slave Address)发送slave address。然后等带这个SMBUS准备ok

③以上两步ok了以后,我们就可以准备发相应的命令来读取寄存器了。这是向controllerHost Command0ffset 03h)发的命令,但是这里我们不是想要改变这个寄存器什么,由于之后这个寄存器要被clock generator填的,目前我们只需要先把它清零即可了。

④有了上面的准备,那么我们就准备给controller说开始读取数据吧,这个动作是通过向Host Controloffset 02h)发送读取的命令54h。(如果不太清楚就自己对应到ICHdatasheet详细看看是什么意思。)

⑤经过SMbus准备好了以后,我们就可以从data0这个端口取得我们需要的读取的bytes数了(offset 05h)。

⑥当我们收到了slave发回给host的字节数了后,我们就可以循环地从data1处读取我们需要的数据了。

对于上面的过程我们可以用一些比较稳妥的办法来确保我们读取的数据更加可靠。这里有两个方法,一是如果我们把读取数据的循环次数手动增加到32次(也就是最大的字节读取数),那么以此确保不会丢失数据。笔者这样一直都是这样做的,(猜想可能是当slave的数据发完了以后,后面读取的数据本身就是无效的,而且一般情况下都是“00”)。二是,在我们读取完了以后,为了确保host能够恢复到正常状态,那么我们手动去操作host controller registerbit2来强制让host进入normal状态。如果以上两个方法同时用的话效果更好,屡试不爽。J

下面让我们来看看我们的核心程序吧。(老方法,我详细加注。)

;[]= ============[]

;Input : SI - Temp table index

; CH - device ID

;Output : None

;[]==================[]

SMbusReadBlock Proc Near

mov dx,5000h ;SMBus Base address,在我的机器上的

mov dl,04h ;选择Transmit Slave Address

mov al, ch ;slave address

inc al ;

out dx,al

IODELAY

;等待SMBUS准备好

call Chk_SMBus_Ready

mov dx,5000h ;SMBus Base address

mov dl,02h ;选择Host Control Register

in al,dx ;buffer

IODELAY

;reset一下counter

mov dx,5000h

mov dl,03h

mov al, 00 ;Reset index

out dx,al

iodelay

call Chk_SMBus_Ready

;Read block data

mov dx,5000h

mov dl,02h

mov al,54h ;block read,这个是改变相应的寄存器,去查相应的datasheet说明

out dx,al

iodelay

xor cx, cx

mov cl, 32 ;最大循环次数

;Read first byte

mov dx,5000h ;SMBus_Port

mov dl,05h data0

in al, dx ;读取将要传输的字节数(注意我没有处理它,直接存它起来了)

iodelay

mov byte ptr ds:[si], al ;save in buffer

inc si

;Read second byte

mov dl, 07H ;block data byte register

in al, dx ;Read data

mov byte ptr ds:[si], al ;save in buffer

inc si

call Chk_SMBus_Ready

dec cx

ReadNextByte_ReadBlock:

call Chk_SMBus_Ready

mov dl, 07H ;Block data byte

in al, dx ;Read data

mov ds:[si], al ;save in buffer

inc si

call Chk_SMBus_Ready

loop short ReadNextByte_ReadBlock

mov dl, 02h ;选择Host Control Register

in al, dx

IODELAY

or al, 20H ;手动终止SMBUS传输终止

out dx,al

call Chk_SMBus_Ready

clc

ret

SMbusReadBlock ENDP

你可能感兴趣的:(Blog,J#)