高通平台Driver开发的参考文档.docx
《高通平台Driver开发的参考文档.docx》由会员分享,可在线阅读,更多相关《高通平台Driver开发的参考文档.docx(32页珍藏版)》请在冰点文库上搜索。
高通平台Driver开发的参考文档
高通平台Driver开发的参考文档
版权说明
本文本中所包含的一切信息,包括文字,图表,数据,图形,图象,方法和思想都是联想移动通信科技有限公司财产,未经联想移动通信科技有限公司书面授权,任何个人和组织都无权透露,拷贝,复制,拍照和传输该文本中的一切信息。
联想移动通信科技有限公司版权所有
修订记录
版本
作者
审核
批准
日期
修改说明
1.00
Chenljc
2009/11/13
Create
第1章前言
1.1文档目的及开发背景
本文为高通平台driver开发的学习文档,对部分概念性的东西进行了学习和总结。
由于driver的跨度太大,内容很多,加上本人水平有限。
如有不足之处及遗漏地方,麻烦大家多多包涵!
希望这份文档能对大家学习高通平台的驱动开发有所帮助!
1.2参考文献
序号
文档名称
作者
出版单位
1
80-VC881-1&QSC6055&QSC6065QSC6075ANDQSC6085SINGLECHIPDEVICESPECIFICATION
Qualcomm
--
2
80-VC881-2&QSC6055,QSC6065,QSC6075,QSC6085SOFTWAREINTERFACE
Qualcomm
3
注:
高通提供的文档比较详细,各个模块都有相关文档!
因为文档提供比较齐全(需要自己去下,对于初学者是个难题),相对来说他的技术支持不怎么样!
有得必有失!
1.3术语和缩写解释
术语和缩写
解释
DS
DATAService
SIO
SerialInput&Output
RDM
RuntimeDeviceMappe
BT
BlueTooth
PBL
PrimaryBootLoader
第2章综述
2.1高通平台的硬件架构
目前开发EVDO的手机或模块大部分采用了QSC6085平台。
高通QSC系列的平台是高度集成化,它将PMIC、RF相关模块也集成到一块芯片里(其他公司很少做到这点),对硬件来说可以省很多事。
除了上述特殊模块之外,当然也包括一般的LCD、KPD、AUDIOCODEC等很多驱动模块!
具体如下图所示:
QSC6085处理器采用ARM9核+DSP的架构,一般就不需要再加DSP去处理Audio和图片。
它集成这么多,其他硬件厂商的饭碗都被他抢了,不过这也是大势所趋!
2.2高通平台驱动文件结构
在一般高通工程(60X5系列)目录下有一个Drivers文件夹,在该文件夹下包含了60X5系列平台上所有驱动文件,分门别类!
从上图中我们可以看到,每一个驱动都有独立的文件夹,这样对于新手学习代码来说比较容易找到相关代码。
2.3ARM相关知识
因为高通处理器采用的ARM内核,遵循ARM指令,我们有必要学习一下ARM的一些基础知识。
一般驱动开发中很少涉及到ARM指令,除了BOOT以及flash开发,大部分都在C语言环境中开发。
在这部分我讲的不会太深入,如果大家想深入了解ARM架构,可以去看《ARM体系结构与编程》这本书,相当经典!
2.3.1ARM基本知识
ARM采用的是32位架构。
也就是说ARMCPU内部的总线是32位的,每条ARM汇编指令都是32位的指令。
一个CPU时钟周期最多可以处理一条32位指令或者读取一个32位的数据。
32位的指令意味着,与8位和16位的CPU相比,在一个时钟周期内,指令可以携带更多的信息。
ARM有7个基本工作模式:
User:
非特权模式,大部分任务执行在这种模式
正常程序执行的模式
FIQ:
当一个高优先级(fast)中断产生时将会进入这种模式
高速数据传输和通道处理
IRQ:
当一个低优先级(normal)中断产生时将会进入这种模式
通常的中断处理
Supervisor:
当复位或软中断指令执行时将会进入这种模式
供操作系统使用的一种保护模式
Abort:
当存取异常时将会进入这种模式
虚拟存储及存储保护
Undef:
当执行未定义指令时会进入这种模式
软件仿真硬件协处理器
System:
使用和User模式相同寄存器集的特权模式
特权级的操作系统任务
ARM有37个32-Bits长的寄存器.
1个用作PC(programcounter)
1个用作CPSR(currentprogramstatusregister)
5个用作SPSR(savedprogramstatusregisters)
30个通用寄存器
当前处理器的模式决定着哪组寄存器可操作.任何模式都可以存取:
相应的r0-r12子集
相应的r13(thestackpointer,sp)andr14(thelinkregister,lr)
相应的r15(theprogramcounter,pc)
相应的CPSR(currentprogramstatusregister,cpsr)
特权模式(除system模式)还可以存取;
相应的spsr(savedprogramstatusregister)
CPSR寄存器表示当前ARM的工作状态
条件位:
N=1-结果为负,0-结果为正或0
Z=1-结果为0,0-结果不为0
C=1-进位,0-借位
V=1-结果溢出,0结果没溢出
Q位:
仅ARM5TE/J架构支持,指示增强型DSP指令是否溢出
J位:
ARM5TE/J架构支持J=1:
处理器处于Jazelle状态
中断禁止位:
I=1:
禁止IRQ.
F=1:
禁止FIQ.
TBit
:
T=0:
处理器处于ARM状态T=1:
处理器处于Thumb状态
Mode位(处理器模式位):
0b10000User
0b10001FIQ
0b10010IRQ
0b10011Supervisor
0b10111Abort
0b11011Undefined
0b11111System
2.3.2ARM存储器格式
在ARM体系中,每个字单元包含4个字节单元或者两个半字单元;一个半字单元中包含两个字节单元。
但是在字单元中,4个字节哪一个是高位字节,哪一个是低位字节则有两种不同的格式;big_endian格式和little-endian格式。
比如一个整型数0x12345678在内存中如下图所示
-----------
| 78 |xxxx_0000
-----------
| 56 |xxxx_0001
-----------
| 34 |xxxx_0002
-----------
| 12 |xxxx_0003
-----------
LittleEndian
-----------
| 12 |xxxx_0000
-----------
| 34 |xxxx_0001
-----------
| 56 |xxxx_0002
-----------
| 78 |xxxx_0003
-----------
BigEndian
第3章Driver相关模块介绍
3.1REX简介
虽说目前QSC60x5平台上采用L4操作系统,REX只是L4上面的一个Task。
但高通为了开发的兼容性,提供的API仍然采用老的一套接口(可能内部实现不一样),很容易将老的代码移植到新的架构中。
那么我还试必要介绍一下REX。
REX是一个操作系统的名字,它是Real-timeExecutive的缩写。
它是美国的QUALCOMM开发的,REX是一个简单的、高效的、抢占式的、多任务的、嵌入式实时操作系统。
它最初是为应用于Intel的80186而设计的,如今它已经被移植到了ARM微处理器上。
下面是它比较重要的几个概念(其实和其他操作系统一样):
1、Task
REX把任务当作独立运作的实体,每一个任务都有自己独立的堆栈和优先级。
每个任务都有一个数据结构,我们称为“任务控制块”(TCB)。
REX允许在运行时,在任何时间动态的创建任意数量的任务。
但是创建的任务越多,REX的性能便稍微递降,这是因为你创建的任务越多,任务列表越长。
所以你需要确保你创建的任务数量尽量小。
另外,REX任务的负载量还跟你选择的处理器有关。
下面的图描述了REX任务的启动过程:
TCB也是一个比较重要的结构体,各个task都有一个全局变量tcb,这个tcb包含了很多重要信息如,任务优先级、堆栈指针,信号量等,这些有时对查死机问题很有帮助。
2、任务调度
REX总是选择处于就绪态的最高优先级的任务进行调度,如果任务的优先级不是唯一的,REX可能选择任何一个处于就绪态的最高优先级的任务进行调度。
被选择的任务会一直执行,直到它自愿挂起或者中断发生而激活了更高优先级的任务。
当被挂起的任务的等待条件得到满足时,该任务就变成了就绪态。
如果所有的认为都挂起的时候,那么空闲认为就被执行。
REX提供了一种机制,允许任务可以动态的提高或降低自己或其它任务的优先级。
3、信号量
信号量是任务之间进行通信和同步的桥梁。
信号量是REX提供的一种任务间通信的机制。
每个任务都有一套与之相关联的通用信号量,信号量通常作为任务的TCB的一部分,它们被用来通知任务某种事件的发生,任务的信号量可以被任何其它任务或中断设置或清除。
信号量实际上是一种约定机制,在多任务内核中普遍使用,信号量用于:
控制共享资源的使用权(满足互斥条件);
标志某事件的发生;
使2个任务的行为同步。
4、中断
REX是一个可剥夺的内核。
当从中断返回的时候,控制权就被传递给处于最高优先级的就绪任务,而没有必要返回到被ISR中断了的任务处。
一般我们只会挂载GPIO中断,后续会介绍。
5、定时器
定时器,英文是timer。
和其它内核一样,REX要求给用户提供定时时间,来实现超时控制等功能。
REX中有些信号是事件触发引起,也可以由timer引起。
一旦由于某种原因,等待的事件信号一直等不到,这时可以用timer定时来产生信号量。
关于以上几个概念,高通都提供了相关接口操作,具体参看代码!
3.2Boot
高通平台系统Memory组成可以分为:
NAND+SDRAM和NOR+PSRAM。
两者配置不能并存,这也就决定了有两种boot模式,具体决定采用哪种Boots方式是Boot_mode引脚决定。
高通60x5系列采用了Multi-Image-Boot技术,这可以从高通的代码看出,
从上述枚举变量中可以看出,flash中有多个image.其中QCSBL+OEMSBL=SBL,SBL就相当于bootloader,Bootloader主要是在Nand启动方式中起作用!
原因后续介绍!
其中每个Image又是由三个部分组成:
其中签名段和证书段是用来校验代码段的完整性与合法性的。
在启动过程中就可以看到校验的相关步骤。
代码段就不需要我说了吧。
3.2.1NorBoot
Norflash有地址线,存在NorFlash的代码可以本地执行,变量存在PSRAM,所以从NOR启动不需要Bootloader
NOR启动模式太简单,一般只要将NorFlash挂载到EBI1上,然后做些简单的操作,就可以直接运行。
在高通代码中关于这方面的注释也很少。
3.2.2NandBoot
NandFlash没有地址线,代码不能直接运行,因此需要Bootloader,那么bootloader的作用:
可以看出相对NORboot,Nandboot复杂很多。
它需要将falsh中的Image复制到SDRAM,然后才能执行。
并且要对各个image进行校验。
3.2.3Boot流程
Boot是一个很复杂的过程,尤其是NandBoot,需要你对ARM架构很深的了解,这边只是简单示意相关流程,具体大家可以参考代码!
3.3Gpio
3.3.1GPIO的作用
GPIO作为QSC60X5与外界沟通的桥梁,主要有四个作用:
1.通过GPIO向外部输出一个高/低电平,控制外部的器件或者通知外部器件某事件的发生。
例如我们可以通过GPIO输出一个高电平点亮一个LED,或者输出低电平关掉一个LED。
2.通过GPIO读入一个外界的高低电平输入,检测外部器件的当前状态。
例如键盘按键是否
按下的探测。
3.将GPIO口作为外部中断信号的一个输入口,实时检测外部事件的发生。
4.将GPIO用作其他特定用途。
例如用作I2C通信、数据线、地址线等。
3.3.2GPIO的用法
1.配置一个GPIO口。
通常一个GPIO有多种功能,我们可以将GPIO配置为符合我们当前需要的功能;同时我们也可以将GPIO配置为内部具有上拉电阻、下拉电阻或者没有任何上下拉电阻。
文件GPIO_60x5.c中定义了配置GPIO的函数接口
voidgpio_tlmm_config(GPIO_SignalTypegpio_signal)
{
…
…
}
gpio_signal指定要配置成的功能,文件GPIO_60x5.h枚举出了每个GPIO的可配置的功能选项:
typedefenum
{
…
…
GPIO_OUTPUT_3=GPIO_OUT(3,0),
GPIO_INPUT_3=GPIO_IN(3,0,GPIO_PULL_DOWN),
SDCC_DATA0=GPIO_ALT(3,0,1,GPIO_PULL_UP),
DBG_BUS_IN_7=GPIO_ALT(3,0,2,GPIO_PULL_DOWN),…
…
}
例子:
SDCC_DATA0=GPIO_ALT(3,0,1,GPIO_PULL_UP)gpio_tlmm_config(SDCC_DATA);/*将GPIO3配置为SD卡的数据线1*/gpio_tlmm_config(GPIO_INTPUT_3);/*将GPIO26配置为通用的有下拉电阻的输入端口*/
2.从GPIO输出高/低电平。
首先应该通过函数接口gpio_out来确定GPIO输出高电平或者低电平,然后通过函数接口gpio_tlmm_config把该GPIO配置为通用功能(非特定功能),在该配置函数中调用一个宏函数接口BIO_TRISTATE打开GPIO使能,将此电平输出出去。
voidgpio_out(GPIO_SignalTypegpio_signal,GPIO_ValueTypegpio_value)/*将GPIO寄存器设置输出的电平*/BIO_TRISTATE(io,mask,val)/*GPIO寄存器中的值输出出去:
输出使能*/
例子:
使GPIO31输出低电平
gpio_out(GPIO_OUTPUT_31,GPIO_LOW_VALUE);
gpio_tlmm_config(GPIO_OUTPUT_31);
3.从GPIO读入外部器件输入的高/低电平,检测外部的事件或者状态。
只能从一个输出已被disable的GPIO读入输入的高/低电平,也就是说只能从一个已被设置为输入模式的GPIO读入高/低电平。
从GPIO读入外部输入的高/低电平的宏函数接口:
GPIO_ValueTypegpio_in
(
GPIO_SignalTypegpio_signal
),
gpio_signal解释见上面的说明,而返回值
typedefenum
{
GPIO_LOW_VALUE=0,
GPIO_HIGH_VALUE=1
}GPIO_ValueType;
例:
判断GPIO3的当前状态
gpio_tlmm_config(GPIO_INTPUT_3);
if(gpio_in(GPIO_INTPUT_3)==GPIO_LOW_VALUE)
{
…..
}
4.将GPIO设置为某个中断信号的输入口。
这样外部器件一旦有中断信号(高电平或者低电平)输入到此GPIO端口,将直接触发一个中断,指定的ISR将被调用,处理中断事件。
中断的好处在于中断事件可以实时得到处理,无论系统是否处于睡眠状态。
接口函数有两个:
A)gpio_int_set_detect(gpio_int_typewhich_group_int,gpio_int_detect_typedetect)/*指定边沿触发还是电平触发*/
B)booleangpio_int_set_handler
(
gpio_int_typewhich_group_int,
gpio_int_polarity_typepolarity,
gpio_int_handler_typehandler
)/*指定ISR以及触发极性*/
typedefenum
{
/*GPIO_GROUP1*/
GPIO_INT_0=0,
GPIO_INT_1,
GPIO_INT_2,
GPIO_INT_3,
GPIO_INT_4,
…
…
}gpio_int_type;
typedefenum
{
DETECT_LEVEL=0,
DETECT_EDGE
}gpio_int_detect_type;
typedefenum
{
ACTIVE_LOW=0,
ACTIVE_HIGH
}gpio_int_polarity_type;
A)参数which_group_int指定GPIO,detect指定中断是电平触发方式还是边沿触发方式。
B)参数which_group_int指定GPIO,polarity与gpio_int_set_detect中指定的detect值相关,若detect指定电平触发方式,polarity就表示指定中断是高电平触发还是低电平触发;若detect指定边沿触发方式,polarity就表示指定中断是上升沿触发还是下降沿触发。
handler指定该中断的ISR,若handle为NULL则表示取消此GPIO的中断处理,
也就是说以后此GPIO输入任何信号都不会触发中断了。
例子:
/*将GPIO3设置为中断高电平触发*/
gpio_int_set_detect(GPIO_INT_3,DETECT_LEVEL);
gpio_int_set_handler(GPIO_INT_3,ACTIVE_HIGH,&GPIO_3_isr);
3.3.3GPIO注意事项
1.必须保证我们要用的GPIO没有已被其他地方用作其它用途,否则可能会出现一些莫名其妙的现象。
2.确保GPIO已被正确配置。
每个GPIO都有缺省的配置,如果缺省的配置不符合我们的要求,我们就需要对GPIO进行重新配置。
3.注意GPIO的上拉电阻或者下拉电阻的设置情况。
例如:
将GPIO设置为有下来电阻输入口,若外部输入的高电平电压不够高,就可能导致读入电平介于高低电平电压之间,从而无法准确辨别出高电平还是低电平。
3.4内存管理
高通平台上内存管理机制由三个部分组成:
队列(Queue)、DS存储池、Watermark。
其中真正存放数据的DS存储池,其他两个则是管理机制。
3.4.1队列(Queue)
•Single-linkedlistofdatablocks(数据块单链表)
•Eachdatablockhasalinkfieldtothenextdatablock(每个数据块有一个指针域(linkfield)指向下一个数据块)
•Alwaysusequeuefunctionstousethequeues(总是使用队列函数来操作队列)
–Declaredinqueue.h
–q_init()–initializesthequeue(初始化队列)
–q_link()–initializesthelinkfieldoftheitem(初始化队列的指针域)
–q_get()–removestheelementfromtheheadofthequeue(从队列头部取出一个元素并将其从队列中去除)
–q_check()–returnsthepointertothefirstelement;doesnotremove(返回队列的第一个元素的指针,但不删除它)
–q_put()–putstheelementatthetailofthequeue(添加一个元素到队列尾部)
–q_cnt()–countsthenumberofelementsinthequeue(计算队列中有几个元素)
ThemodelofQueue:
队列广泛使用在DS的存储池中,贯穿于整个DS的相关代码中。
3.4.2DS存储池
在高通软件平台上,它的数据存储方式比较特别。
事先划分一块区域用于数据存储,并且为不同应用再细分一个Pool(池),这个Pool是由固定大小item(用于存储数据块)组成。
应用不同,这个item的数据容量也不一样。
每个用户申请的就是这个item.它的具体特点:
•StaticallyallocatedmemoryinRAM(静态分配于RAM中)
•AnumberofDSMpools(不止一个DSMpool)
–Eachpoolisallocatedasastaticarray(每一个pool都是以一个静态数组的形式分配空间的)
–Flowcontrolisbuiltintoeachpoolbasedonthenumberoffreeitemsmany,few,dont_exceed(流控制被构造于每个DSMpool中)
•Eachpoolhasafixednumberofitems(calledDSMitems)(每个存储池都有固定数量的item成为DSMitems)
–EachDSMitemineachpoolhasthesamefixednumberofpayloadbytes(在同一个存储池中的所有DSMitem都有相同的有效字节数)
–AllDSMitemsacrossallpoolshavethesameoverheadbytes(所有存储池中的所有DSMitem都有相同的字节数?
)