@[TOC]基础知识
计算法:
int 0x23 <<1
0x23 *2= 0x46 = 70
int 0x23 <<2
0x23*4 = 0x8c = 170
2*4 = 0x8 3*4 =0xc 0x8c
int 0x23 >>1
0x23 /2= 0x11 = 17 //取整
int 0x23 >>2
0x23/4 = 0x8 = 8
转换10进制
2*16+3 = 35/4 = 8
char类型是8位,最高位是符号位,0正1负,所以01111111是127。
-127是10000001,而10000000换算过来就是-128。
01111111 //127 127+1 = -128
10000001 //-128
&&的短路功能,当第一个表达式的值为false的时候,则不再计算第二个表达式;
&则两个表达式都执行。
对a的第三位清0,第四位置1.
#define BIT3 (1<<3)
#define BIT4 (1<<4)
a&=~BIT3;
a|=BIT4;
一、指定的某一位数置1
#define setbit(x,y) x|=(1<<y)
二、指定的某一位数置0
#define clrbit(x,y) x&=~(1<<y)
三、指定的某一位数取反
#define reversebit(x,y) x^=(1<<y)
三、获取的某一位的值
#define getbit(x,y) ((x) >> (y)&1)
int *p char *p 都占四个字节 指针变量里面保存的是地址,地址在操作系统中是固定长度的
数据类型长度
32 64
char 1 1 2^8
short 2 2
int 4 4 2^32
float 4 4
double 8 8
long 4 8
long long 8 8
size_t 4 8
sszie_t 4 8
@[TOC]空间分配
sizeof,测量一个变量或数据类型所占的字节长度,统计字符串长度的时候加上'\0',在编译阶段的时候就可以计算出长度
strlen,计算字符串长度,在统计字符串长度的时候不加上'\0',在函数运行的时候才计算出长度
用户空间供为3G,分为:栈空间,堆空间,数据区,代码段
栈空间保存:局部变量,函数形参,自动变量。栈空间特点,先进后出,空间由系统管理;栈空间生命周期所在函数执行结束
后释放;栈空间保存的局部变量未初始化时,默认初始化为随机值。
堆空间:由malloc , calloc ,ralloc,这些好函数分配的控件位堆空间,堆空间特点:先进先出,由用户管理
数据区:又分为.bss段、.data段、常量区。其中.bss段保存的是未初始化的全局变量,当全局变量未初始化时,系统默认初始
化为0,常量区保存的是常量,里面保存的值不能被修改,只能做读操作。.data段是保存已经初始化的全局变量以及被static修饰的
变量(静态变量)。数据区的声明周期是整个程序执行完之后再释放。
代码段保存的是代码。
//栈空间 有系统管理 存放局部变量 自动变量 函数执行完释放 先进后出
//堆空间 用户管理 malloc等函数分配 需要用户释放空间 先进先出
@[TOC]关于终端
中断:
上半部分 硬件操作 IRQ_GPIO 读取寄存器中断状态
触发方式:
上升沿 下降沿 高电平 低电平 快速中断 共享中断
下半部分 耗时操作 软中断 工作队列 tasklet
// 软中断
中断下半部实现
软中断、tasklet机制、工作队列。
软中断作为下半部机制的代表
tasklet是通过软中断实现的,所以它本身也是软中断。
总结下tasklet的优点:
(1)无类型数量限制;
(2)效率高,无需循环查表;
(3)支持SMP机制;
缺点 :
不能阻塞 不能休眠
下半部实现机制之工作队列(work queue)
工作队里线程是用内核线程实现的。而工作者线程是如何执行被推后的工作——有这样一个链表,
它由结构体work_struct组成,一旦这个工作被执行完,相应的work_struct对象就从链表上移去,
当链表上不再有对象时,工作者线程就会继续休眠。因为工作队列是线程,
所以我们可以使用所有可以在线程中使用的方法。
//kmalloc vmalloc malloc
malloc分配的是用户的内存
kmalloc和vmalloc是分配的是内核的内存
kmalloc保证分配的内存在物理上是连续的
vmalloc保证的是在虚拟地址空间上的连续
kmalloc能分配的大小有限, 4M
vmalloc和malloc能分配的大小相对较大
内存只有在要被DMA(Direct Memory Access,直接内存存取)访问的时候才需要物理上连续
//同步机制包括:原子操作、自旋锁和信号量。
自旋锁同时只会允许一个任务来访问临界区 ,不允许休眠
信号量允许多个任务同时访问临界区,允许休眠,适用较长的共享区
原子操作可以保证指令以原子的方式执行,执行过程不被打断
init_module()是真正的入口,module_init是宏,如果在模块中使用,
保护共享资源的方式有很多,例如:中断屏蔽、自旋锁、信号量...
自旋锁 spin_lock_init(); 同时只会允许一个任务来访问临界区 ,不允许休眠 资源被占用时,不断消耗cpu尝试获取该锁
互斥锁 mutex_init() 会有睡眠 资源被占时 会挂起 其他线程释放互斥锁时该线程被系统激活
信号量 semaphore 允许多个任务同时访问临界区,允许休眠,适用较长的共享区
原子操作 atomic_inc() 可以保证指令以原子的方式执行,执行过程不被打断
@[TOC]高通I2C配置
dts 把系统平台上的总线(I2C SPI UART)描述成节点
kernel启动时解析出dts保存在allnode链表中,然后加载系统总线和设备,将其注册在系统中。
高通BLSP配置
一个I2C 对应的BLSP和QUP
配置dts
根据列表计算APPS BLSP值
通过计算的值在TZ中配置
trustzone_images\core\hwengines\bam\8974\bamtgtcfgdata_tz.h
在/usr/share/data/adsp/blsp.config中定义串口设备和BAM端口的映射
@[TOC]DDR降频计算
DDR降频
// 19.2(40+(2/3))/2 780.8M
DDR 2GB 换3GB 增加ldo1供电
@[TOC]camera
camera imx214 imx350
camera_config.xml配置
id sensorname 方向 CSI_ID lane
dts
供电配置 DOVDD AVDD PWDM REST
imx350_lib.h
上电时序
power_setting_array
@[TOC]TP
TP 敦泰8719 汇顶
TP供电电压异常
射频干扰 ---- 打电话引起TP电压上下波动
TP校准异常
充电器干扰测试
阀值:
灵敏度
防水上线阀值 一只手按CTP 一只手按地
报点频率
1. input 机制
2. 中断
3. I2C
初始化硬件
注册I2C设备
注册中断
注册input设备
中断函数中上报坐标值
I2C
时钟在高电平时 数据从高到底 开始
时钟在高电平时 数据从低到高 结束
写:发送(7+1)写地址 收应答(ACK) 发送地址 ACK 发送数据 ACK
读:发送写地址 ACK 发送地址 ACK 发送读(7+0) ACK 获取数据
@[TOC]FP
FP 信炜科 汇顶
流程:
给中断
主控驱动收到中断之后通过netlink或者其他的跨进程上报信息给hal
hal收到中断开始识别
从IC中获取指纹图像 然后预处理为算法格式
进行模板库匹配
生成识别结果 用binder回调fingerprintseriver
keystore service 保存支付指纹
SPI
输入 MOSI
输出 MISO
时钟
片选
@[TOC]LCD
LCD
参数
Hsync Pulse Width 行同步 4 水平脉冲宽度
Hori. Back Porch 16 水平后沿值 表示从水平同步信号开始到一行的有效数据开始之间的VCLK的个数
Hori. Front Porch 16 水平前沿 表示一行的有效数据结束到下一个水平同步信号开始之间的VCLK的个数
Vsync Pulse Width 帧同步 4 垂直脉冲宽度
Vert. Back Porch 4
Vert. Front Porch 108(下半部宽度比较大)
kernel dts
lk UEFI Display Panel
tz
sensor ADSP
上报方式 : Polling
DRI
FIFO
输入子系统:
linux内核 原始数据上报给用户空间
InputManagerService java部分负责与WMS通讯 native部分是InputRead InputDispatcher 两个运行容器
EventHub 访问底层设备节点返回数据
InputRead 独立线程 从EventHub获取数据,做封装处理, 给InputDispatcher 进行派发
例如HOME键被InputDispatcherPolicy截取到PhoneWindowManager中处理,并阻止窗口收到HOME键按下的事件
由上到下:
开机注册InputManagerService
InputManagerService开启两个线程 InputRead InputDispatcher
InputRead 通过EventHub检测读取input上报的键值数据 将键值数据初步整理,封装之后,发送给InputDispatcher
InputDispatcher:不停的循环等待来自InputReader传过来的键值数据,在接收到键值数据之后,对键值进行整理分发,按键背光也会在该线程中点亮。
耳机
三段式 没有mic 只能接受声音 左声道 右声道 GND //L R GND
四段式 有mic
美标CTIA //L R G M
欧标OMTP //L R M G
//高通平台 BSP启动流程
一个dts文件确定一个项目
/*
/kernel/msm-4.4/arch/arm/boot/dts/qcom/sdm660-pm660a-qrd-h6630.dts
/dts-v1/;
#include "sdm660.dtsi"
#include "sdm660-qrd-h6630.dtsi"
#include "msm-pm660a.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM 660 PM660 + PM660A QRD h6630";
compatible = "qcom,sdm660-qrd", "qcom,sdm660", "qcom,qrd";
qcom,board-id = <0x0012000b 0>;
qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
<0x0001001b 0x0002001a 0x0 0x0>,
<0x0001001b 0x0202001a 0x0 0x0>;
};
&pm660a_oledb {
status = "okay";
qcom,oledb-default-voltage-mv = <6400>;
};
&mdss_mdp {
qcom,mdss-pref-prim-intf = "dsi";
};
&mdss_dsi {
hw-config = "single_dsi";
};
&mdss_dsi0 {
qcom,dsi-pref-prim-pan = <&dsi_rm69299_amoled_fhd_cmd>;
pinctrl-names = "mdss_default", "mdss_sleep";
pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
lab-supply = <&lab_regulator>;
ibb-supply = <&ibb_regulator>;
qcom,platform-reset-gpio = <&tlmm 53 0>;
qcom,platform-te-gpio = <&tlmm 59 0>;
};
&dsi_rm69299_amoled_fhd_cmd {
qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs";
qcom,mdss-dsi-bl-min-level = <1>;
qcom,mdss-dsi-bl-max-level = <255>;
qcom,panel-supply-entries = <&dsi_panel_pwr_supply_labibb_amoled>;
};
*/
//dts 符号含义
// / 根节点
// @ 如果是设备地址 此符号指定
// & 引用节点
// : 给节点起别名
// , 分割符
// # #并不表示注释。如 #address-cells ,#size-cells 用来决定reg属性的格式。
// ranges属性为一个地址转换表
// interrupt-parent 标识此设备节点属性
// interrupts 一个中断标识符列表
dts描述的设备树是如何通过register_device进行设备挂载的
//dts执行过程
dts是系统平台挂载总线 i2c spi uart 等,每个总线被描述成一个节点。
启动linux到kernel入口后会加载系统总线和设备
start_kernel ---> setup_arch ---> unflatten_device_tree
执行完unflatten_device_tree()后,dts的节点信息被解析出来,保存到allnodes链表中。
随后启动到board文件时,调用.init_machine,再调用of_platform_populate(....)接口,
加载平台总线和平台设备。至此,系统平台上的所有已配置的总线和设备将被注册到系统中
(对这句话更加正确的解释是:此时所说的设备指的是platform device,此时的总线指的是i2c,spi等,因为i2c总线和spi总线可以理解为注册在platform总线上的device)
注意:不是dtsi文件中所有的节点都会被注册,在注册总线和设备时,会对dts节点的状态作一个判断,如果节点里面的status属性没有被定义,或者status属性被定义了并且值被设为“ok”或者“okay”,其他情况则不被注册到系统中。
mach-qcom/board-660.c
41 static void __init sdm660_init(void)
42 {
43 board_dt_populate(NULL);
44 }
45
46 DT_MACHINE_START(SDM630_DT,
47 "Qualcomm Technologies, Inc. SDM 630 (Flattened Device Tree)")
48 .init_machine = sdm660_init, // 匹配dts
49 .dt_compat = sdm660_dt_match,
50 MACHINE_END
---------------------
18 static const char * sdm660_dt_match [] __initconst = {
19 "qcom,sdm660",
20 "qcom,sda660",
21 NULL
22 };
其中.dt_compat = ******_dt_compat 这个结构体是匹配是哪个dts文件, 如:
19 void __init board_dt_populate(struct of_dev_auxdata *adata)
20 {
21 of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
22
23 /* Explicitly parent the /soc devices to the root node to preserve
24 * the kernel ABI (sysfs structure, etc) until userspace is updated
25 */
26 of_platform_populate(of_find_node_by_path("/soc"),
27 of_default_bus_match_table, adata, NULL);
28 }
+++ b/BOOT.XF.1.4/boot_images/QcomPkg/Sdm660Pkg/Library/XBLLoaderLib/boot_cdt_array.c
26 uint8 config_data_table[CONFIG_DATA_TABLE_MAX_SIZE] =
27 {
28 /* Header */
29
30 0x43, 0x44, 0x54, 0x00,
31 0x01, 0x00, 0x00, 0x00,
32 0x00, 0x00, 0x00, 0x00,
33 0x00, 0x00,
34
35 /* Meta data */
36
37 0x16, 0x00, 0x06, 0x00,
38 0x1C, 0x00, 0xEF, 0x02,
39
40 /* Block data */
41
42 0x03, 0x0b, 0x12, 0x00,//mtp change to qrd qcom,board-id = <0x0012000b 0>;
43 0x00, 0x00, 0x02, 0x00,
44 0x00, 0x00, 0x00, 0x52,
45 0x44, 0x44, 0xFF, 0xFF,
Platform id信息解析:
0x02, 0x08, 0x01, 0x00,
Byte 0: platform_idVersion
Byte 1: platform_id ID:
0x01: Target is aSURF device
0x08: Target is aMTP device
0x0B: Target is aQRD device
Byte 2: platform_id Hardware version
SBL1的功能
初始化memory子系统(总线,DDR,clock和CDT),加载和验证TrustZone,DEVCFG,RPM_FW,APPS BL image,dump memory通过usb2.0和Sahara协议,
usb driver support,usb charging(usb充电),thermal check(温度检测),PMIC 的驱动,配置DDR,flash L1/L2/ETB
//编译选择kernel
h6630/AndroidBoard.mk
19 # Compile Linux Kernel
20 #----------------------------------------------------------------------
21 ifeq ($(KERNEL_DEFCONFIG),)
22 ifeq ($(TARGET_BUILD_VARIANT),user)
23 KERNEL_DEFCONFIG := sdm660-$(OEM_PRODUCT_NAME)-perf_defconfig
24 else
25 KERNEL_DEFCONFIG := sdm660-$(OEM_PRODUCT_NAME)_defconfig
26 endif
27 endif
开机流程
@[TOC]开机流程
//
上电加载引导程序BootLoader
主要是拷贝操作系统到RAM中 跳转到入口执行
第一阶段:
初始化硬件参数
加载stage2到ram
设置好堆栈
跳转C程序入口
第二阶段
初始化本阶段硬件
检测内存映射
见内核映像和文件系统从flash读到ram中
问内核设置启动参数
调用内核
kernel初始化
启动内核线程
驱动程序的初始化
启动用户空间的init进程
init进程
执行init.rc脚本
zygote进程
所有Java进程的父进程
startSystemServer
启动的SystemServer进程
初始化原生服务库
初始化系统上下文
创建SystemServiceManager对象
开启服务
初始化ActivityManagerService ----之后 广播形式---> Launcher程序
初始化PowerManagerService,
开启DisplayManagerService
开启PackageManagerService
@[TOC]UEFI
/UEFI
UEFI 代替LK
UEFI 由XBL ABL组成
XBL负责芯片驱动及充电等核心应用功能
ABL包括芯片无关的应用如fastboot。
ABL 的编译非常简单,依次执行命令source build/envsetup.sh、lunch 32、make aboot,
即可在out目录下生成abl.elf
ABL 主要碰到了两个问题,
一是没有生成abl.elf,
二是生成abl.elf后没有做签名。高通原生代码并不存在问题,是项目中修改了代码导致的。费了一番周折,最终成功编译出可正常工作的abl.elf
未签名的abl.elf大概98KB,签名后的abl.elf约108KB
需要注意的是,ABL在Android代码树下,而签名工具(secimage)在高通私有代码目录(vendor/qcom/proprietary)下,
在编译ABL时,一定要将高通提供的私有代码全部放到相应的目录下。
未签名的abl.elf会让系统无法启动,上电直接进入EDL紧急下载模式。
//UEFI启动流程:
对于高通平台启动过程依次为PBL->XBL->ABL.
一般用户定制化主要集中在ABL中
//高通启动流程
1,上电,加载PBL
------>对XBL region #1 进行身份认证,并将其从引导设备(as TCM)加载到L2
------>验证XBL region #2 (DDR/SDI equivalent)并将其加载到片上内部存储器(OCIMEM),然后跳转到XBL region #1
2在 XBL region #1中,XBL对PMIC镜像进行身份认证并将其从引导设备加载到内部缓冲区
a. 对QSEE进行身份认证,并将其从引导设备加载到pIMEM QSEE - Qualcomm Secure Execution Environment
b. 对QHEE (Hypervisor) image 进行身份认证,并将其从引导设备加载到DDR QHEE - Qualcomm Hypervisor Execution Environment
c. 对RPM firmware image 进行身份认证,并将其从引导设备加载 RPM code RAM
d. 对little kernel(LK) boot (or XBL region #3)进行身份认证,并将其从启动设备加载到DDR
4,XBL region #1 结束工作,下一步由QSEE执行
5 QSEE使RPM退出reset状态,启动并执行RPM firmware
6 QSEE建立一个安全的环境,并跳转到QHEE image,启动并执行它
7 QSEE跳转到LK boot(or XBL region #3),启动并执行
高通平台驱动常见问题
最新推荐文章于 2023-07-27 10:35:45 发布
本文详细探讨了在高通平台上进行驱动程序开发时遇到的常见问题,包括初始化失败、性能瓶颈、设备不识别等。通过分析这些问题的原因,提供了解决方案和预防措施,旨在帮助开发者更有效地进行驱动调试和优化。
摘要由CSDN通过智能技术生成