资讯
论坛
词条
众包
招聘
商城
下载
问答
博客
工程师家园
帮助
搜索
登录
立即注册
一牛网论坛
一流研发工程师学习交流分享电子技术的论坛!
工作时间
周一到周五 9:00-11:30 13:30-19:30
热线电话
19168984579
论坛客服
QQ:
2064607811
微信:
19168984579
商城客服
QQ:
1911822682
微信:
18924675756
一牛网
›
芯片词条
›
Qualcomm
Qualcomm
高通创立于1985年,总部设于美国加利福尼亚州圣迭戈市,33,000多名员工遍布全球。高通公司是全球3G、4G与5G技术的企业,目前已经向全球多家制造商提供技术使用授权,涉及了世界上所有电信设备和消费电子设备的品
机械防抖摄像头
18-30倍可变焦模组
5G相关方案定制
T31/T40方案定制
全志方案定制
展讯4G/5G方案定制
FPGA高清视频方案
高通方案
显示屏方案
AMLOGIC相关方案
Ai硬件方案
PD超级快充方案
MTK4G/5G方案
wifi/cpe相关方案
RK相关方案
摄像头和测温模块
高精度定位模组
联咏相关方案
其他需求定制联系我
全部
帖子
资料
日志
“Qualcomm”
的帖子
主题
版块
作者
回复/查看
最后发表
Bypassing Camera Enable in Qualcomm based Phones
硬件基础知识
asimbro1472
2024-1-11
1
201
bfnhhk
2024-1-11 14:18
Qualcomm|高通QCC300x系列80MHz RISC CPU蓝牙音频系统芯片
高通硬件
8496512
2023-8-14
12
1248
billmtk
2023-12-28 09:34
Qualcomm|高通SM6350 8 nm 2.0 GHz Kryo 560 CPU Adreno 619 GPU 5G芯片datasheet
高通硬件
坑坑是吃货
2023-6-30
26
2548
tata1004
2024-2-4 08:54
802.11be WiFi7-Qualcomm IPQ9574 transmission rate up to 30 Gbps
高通硬件
wallystech
2023-5-6
0
628
wallystech
2023-5-6 10:25
Qualcomm IPQ8072/DR8072V01/wifi 6E/industrial router board/4T4R/wallys
高通硬件
James12138
2023-5-6
2
708
阿尼古
2023-5-8 09:07
Qualcomm's_processor_lines_2018_12_30
高通硬件
羽之中
2023-5-23
0
626
羽之中
2023-5-23 11:25
qualcomm-kryo-cpu-infographic
高通硬件
羽之中
2023-5-22
1
558
Extreme
2023-7-19 08:35
qualcomm-quick-charge-3-0-infographic
高通硬件
羽之中
2023-5-22
0
557
羽之中
2023-5-22 15:36
qualcomm-spectra-isp-infographic
高通硬件
羽之中
2023-5-22
1
754
cicixyle
2023-9-9 01:27
qualcomm-adreno-530-gpu-infographic
高通硬件
羽之中
2023-5-20
1
594
lwxays
2023-5-21 20:48
qualcomm-adreno-video-and-display-infographic
高通硬件
羽之中
2023-5-20
0
565
羽之中
2023-5-20 17:35
qualcomm-haven-security-solutions-infographic
高通硬件
羽之中
2023-5-20
1
599
billmtk
2023-5-21 00:50
Qualcomm SA8155P 7nm ARMV8架构八核CPU 64-bit USB3.0 3x 4KP60车规级芯片
高通硬件
342645317
2023-5-18
28
3093
inr8615
7 天前
Qualcomm QCA9880/DR600VX/DR900VX/network card/3x3 MIMO/wallys
高通硬件
James12138
2023-4-12
1
786
kof2000
2024-1-21 12:03
IPQ6010/wifi 6E/industrial wifi router/wallystech router/DR6018
高通硬件
James12138
2023-3-8
2
783
maozf
2023-3-9 08:48
IPQ5018/QNC6102/QNC6122/WIFI6/INDUSTRIAL WIFI ROUTER/WALLYS
高通硬件
James12138
2023-3-17
1
737
billmtk
2023-3-18 12:56
Qualcomm QCA9890 and QCA9882, Wave 2 Wave 1 Higher transmission speed, higher...
高通硬件
wallystech
2023-3-15
4
636
祈缘
2023-3-22 10:08
Qualcomm IPQ8072/DR8072V01/wifi 6E/industrial routerboard/4T4R/wallys
高通硬件
James12138
2023-3-13
2
742
James12138
2023-3-14 11:59
DR40X9/ IPQ4019(29) /Open Wrt/industrial routerboard/2t2r/wallys
高通硬件
James12138
2023-3-10
0
673
James12138
2023-3-10 09:10
5G Qualcomm modem issues
高通硬件
Basi
2023-12-3
0
567
Basi
2023-12-3 08:00
查看更多
“Qualcomm”
的资料
设备标记(俯视图,未按比例).jpg
大小:71.52 KB
更新日期:2023-11-17 09:57:08
免费
下载
80_PP662_4_F_SDR735_Device_Revision_Guide.Removed-Output.pdf
大小:1.69 MB
更新日期:2023-11-17 10:05:08
10rdb
下载
SM7250 高级框图和 945 PSP 图纸.jpg
大小:92.13 KB
更新日期:2023-11-07 15:18:29
免费
下载
图 1-1 SM7250 SDR865 功能框图和应用示例.jpg
大小:220.67 KB
更新日期:2023-11-07 15:19:19
免费
下载
80-pl808-1_r_sm7250_device_specification.pdf
大小:3.4 MB
更新日期:2023-11-07 15:31:22
200rdb
下载
查看更多
“Qualcomm”
的日志
高通专有代码git下载报错
热度
2
liujin
2016-10-17 17:24
1, 用git clone 高通专有代码时报错: gnutls_handshake() failed: A TLS packet with unexpected length was received. 这个问题和openssl有关,需要重新编译git 在网上找到解决方案如下:(这个链接:http://askubuntu.com/questions/186847/error-gnutls-handshake-failed-when-connecting-to-https-servers) Got reason of the problem, it was gnutls package. It's working weird behind a proxy. But openssl is working fine even in weak network. So workaround is that we should compile git with openssl. To do this, run the following commands: sudo apt-get update sudo apt-get install build-essential fakeroot dpkg-dev libcurl4-openssl-dev sudo apt-get build-dep git mkdir ~/git-openssl cd ~/git-openssl apt-get source git dpkg-source -x git_1.7.9.5-1.dsc cd git-1.7.9.5 (Remember to replace 1.7.9.5 with the actual version of git in your system.) Then, edit debian/control file (run the command: gksu gedit debian/control) and replace all instances of libcurl4-gnutls-dev with libcurl4-openssl-dev. Then build the package (if it's failing on test, you can remove the line TEST=test from the file debian/rules): sudo dpkg-buildpackage -rfakeroot -b Install new package: i386: sudo dpkg -i ../git_1.7.9.5-1_i386.deb x86_64: sudo dpkg -i ../git_1.7.9.5-1_amd64.deb 2, 另外还有一个问题,网速比较差的时候,curl的postBuffer 默认值较小导致出现如下错误 git clone: error: RPC failed; result=18, HTTP code = 200 解决办法 解决方法:加大curl的postBuffer 默认值大小。 git config --global http.postBuffer 524288000 git config --list 这里把postBuffer设置成500M
展开>>
收起<<
个人分类:
通信技术
|
2726 次阅读
|
2
个评论
高通msm8909平台电池温度检测电阻配置
热度
2
liujin
2016-10-13 20:44
高通msm8909平台电池温度检测电阻配置公式如下: 其中Rs1对应下图R1902, Rs2对应下图R1901 首先确定电池的工作温度范围,比如0-45度,然后根据电池内部热敏电阻规格书查到0和45度对应 的电阻值,即: Rcold 和 Rhot, 然后根据上图中公式算出对应的Rs1 和 Rs2的值 。上图中第一和第二 个公式的区别在于Rs1和Rs2这两个电阻的百分比不同, 第一个公式是传统的充电方式,第二个是 JEITA标准的充电方式。 我们用第一个即可。
展开>>
收起<<
个人分类:
android 驱动开发
|
3202 次阅读
|
2
个评论
高通平台学习
ouyang123456
2016-9-19 17:36
今天开启高通平台学习之旅。学海无涯,活到老学到老!加油,努力!
展开>>
收起<<
1689 次阅读
|
0
个评论
MTK/高通平台不开机分析
热度
5
jason303135
2016-7-28 17:01
RT,不开机分析有几个疑问: ①数据线接PC,有的提醒MTK65XXX或者未识别设备,这个识别是对CPU识别?还是flash代码识别?能排除cpu、PMU故障,确定是FLASH问题吗? ②不开机,虚焊问题分析有没有系统的办法?
展开>>
收起<<
个人分类:
终端故障分析
|
1268 次阅读
|
5
个评论
Linux驱动基础msm8916:msm平台,modem等framework加载
热度
1
gygyg2008
2016-6-14 16:34
msm 平台,AP和CP封装在一起,公用一块内存。所以AP需要负责把整个modem, TZ , rpm等binary拷贝到内存中以供modem等subsystem去运行。那AP这边是怎么分配这些内存,又是怎么读出来相关的binary,又如何 把binary上传上去的呢?? 相关的feature CONFIG_FW_LOADER CONFIG_FW_LOADER_USER_HELPER modem使用的内存申请 要设置modem的内存大小,必须首先需要确认modem binary的大小,modem需要使用的内存大小等。这个在CMA相关的内容中说过。这里在说一下高通msm8916平台,modem大小检查以及修改方法。 1) modem binary的大小可以从以下编译的log里边看出来!!(modem_proc/build/ms目录下的pplk-XXX.log或者build_xxxx.log)。 根据大小对齐1MB大小,就是modem binary需要流出来的大小。看如下例子里边的log,总的大小是77.04, 所以需要在上面的dtsi文件中留出来78MB就可以。 Image loaded at virtual address 0 xc0000000 Image: 55.44 MiB AMSS Heap: 7.50 MiB ( dynamic ) MPSS Heap: 4.00 MiB ( dynamic ) DSM Pools: 5.06 MiB Q6Zip RO, Swap Pool: 2.00 MiB ( dynamic ) Q6Zip RW, Swap Pool: 1.00 MiB ( dynamic ) Q6Zip RW, dlpager Heap: 1.00 MiB Extra: 0.54 MiB Pad ding: 0.37 MiB End Address Alignment: 0.13 MiB Total: 77.04 MiB Available: 7.96 MiB 2) 然后去修改modem_proc/config/xxx/ 目录下的cust_config.xml文件中修改modem大小 !-- 85 MB of physical pool-- physical_pool name = "DEFAULT_PHYSPOOL" region base = "0x88000000" size = "0x5500000" / region base = "0x88000000" size = "0x4E00000" / / physical_pool 以下是modem相关的device tree的设置。这些内容也在CMA和ion内存相关的帖子里边都讲过。 但 之前有一个疑问就是,在CMA预留了一段内存之后,会把这个赋值给modem的dev-cma_area,然后在分配需要使用的内存的时候从 dev-cma_area中取出来,那这个过程好像跟ion内存没有什么关系。能不能去掉下面msmxxx-ion.dtsi中 modem_adsp_mem相关的设置呢?? 是可以的!!!其他几个DMA区域,如果直接从CMA分配的话,应该都可以从msmxxx-ion.dtsi文件中去掉!! 也就是说下面qcom,ion-heap-type = “DMA”的部分其实都可以从msm8916-ion.dtsi文件中去掉,不影响。 //modem相关内存的device tree设置 //pil设备相关的device tree定义 qcom,mss@ 4080000 { compatible = "qcom,pil-q6v56-mss" ; .... linux,contiguous-region = modem_adsp_mem; }; //msmxxx-ion.dtsi定义了如下,上面说了这个部分其实是可以去掉的,不会影响相关内存的分配!! qcom,ion-heap@ 26 { /* MODEM HEAP */ compatible = "qcom,msm-ion-reserve" ; reg = 26 ; linux,contiguous-region = modem_adsp_mem; qcom,ion-heap-type = "DMA" ; }; //msmxxx-memory.dtsi定义了如下内容 modem_adsp_mem: modem_adsp_region@ 0 { linux,reserve-contiguous-region; linux,reserve-region; linux,remove-completely; reg = 0x0 0x86800000 0x0 0x05800000 ; label = "modem_adsp_mem" ; }; modem_adsp_mem指定的区域,需要分配出来,以供下载modem binary。 //pil_mss_driver_probe()-pil_subsys_init() static int pil_subsys_init( struct modem_data *drv, struct platform_device *pdev) { ... drv-subsys_desc.name = "modem" ; drv-subsys_desc.dev = pdev-dev; drv-subsys_desc.owner = THIS_MODULE; drv-subsys_desc.shutdown = modem_shutdown; drv-subsys_desc.powerup = modem_powerup; drv-subsys_desc.ramdump = modem_ramdump; drv-subsys_desc.free_memory = modem_free_memory; drv-subsys_desc.crash_shutdown = modem_crash_shutdown; drv-subsys_desc.err_fatal_handler = modem_err_fatal_intr_handler; drv-subsys_desc.stop_ack_handler = modem_stop_ack_intr_handler; drv-subsys_desc.wdog_bite_handler = modem_wdog_bite_intr_handler; drv-subsys = subsys_register(drv-subsys_desc); drv-ramdump_dev = create_ramdump_device( "modem" , pdev-dev); ... return ret; } 之后在modem_powerup()的时候,会先根据modem binary的elf结构独处modem的大小等,然后计算出align之后应该的大小。 pil_boot()- request_firmware()读出elf头并计算大小等。 在pil_setup_region()-pil_alloc_region()的时候,传进去的大小就是从上面读出来的大小。 pil_alloc_region min_addr = 0xc0000000 , max_addr = 0xc2b00000 , aligned_size = 0x2b00000 这里看着和实际的内存大小一致!! 可能是因为留出来的CMA区域的大小正好和这个大小一致才这样的。 在实际调试过程中,也可以打印这个大小之后,调整CMA大小。 再看看实际的CMA大小是怎么申请的。 // 调用顺序 pil_boot () - pil_init_mmap () - pil_setup_region () - pil_alloc_region () - dma_alloc_attrs () - arm_dma_alloc () - __dma_alloc () - __alloc_from_contiguous () - 这个调用的顺序,一步一步往下看可以看到,实际上分配的区域是一块CMA区域,而且就是在CMA注册之后,在相应的platform设备注册的时候保存到dev-cma_area中的区域。 在相应的设备注册的时候,如果设备的device tree中有”linux,contiguous-region”的时候,就会寻找相应的CMA区域并进行保留。这都是因为注册了platform_bus_typ的notifier函数 bus_register_notifier(platform_bus_type, cma_dev_init_nb); 看下面的log。 6 cma: Assigned CMA region at 0 to 1 de0000.qcom,venus device 6 cma: Assigned CMA region at 0 to 4080000. qcom,mss device 6 cma: Assigned CMA region at 0 to a21b000.qcom,pronto device 6 cma: Assigned CMA region at 0 to 8. qcom,ion-heap device 6 cma: Assigned CMA region at 0 to 1 b.qcom,ion-heap device 6 cma: Assigned CMA region at 0 to 1 c.qcom,ion-heap device 6 cma: Assigned CMA region at 0 to 17. qcom,ion-heap device 6 cma: Assigned CMA region at 0 to 1 a.qcom,ion-heap device 这里看到4080000.qcom,mss这个device相应的区域已经保留了CMA区域。 然后在上面进行分配的时候,在 __alloc_from_contiguous()-dma_alloc_from_contiguous()-dev_get_cma_area()函数中取到 相应的dev-cma_area。 modem相关内存的使用和下载 pil_load_seg()-request_firmware_direct()-_request_firmware() 函数身生成相应的device节点,并通知ueventd去读取相应的binary然后下载。以下是pil_load_seg里边打印的正在试图下载的 binary。 6 pil_load_seg fw_name = modem.b02 6 pil_load_seg fw_name = modem.b07 6 pil_load_seg fw_name = modem.b17 6 pil_load_seg fw_name = modem.b19 6 pil_load_seg fw_name = modem.b20 6 pil_load_seg fw_name = modem.b23 6 pil_load_seg fw_name = modem.b24 6 pil_load_seg fw_name = modem.b25 6 pil_load_seg fw_name = modem.b27 6 pil_load_seg fw_name = wcnss.b02 6 pil_load_seg fw_name = wcnss.b04 6 pil_load_seg fw_name = wcnss.b06 6 pil_load_seg fw_name = wcnss.b09 6 pil_load_seg fw_name = wcnss.b10 6 pil_load_seg fw_name = wcnss.b11 6 pil_load_seg fw_name = venus.b02 6 pil_load_seg fw_name = venus.b03 6 pil_load_seg fw_name = venus.b04 在 _request_firmware()-fw_load_from_user_helper()-_request_firmware_load()函数中就在生成相应的dev节点,并通知ueventd。 static int _request_firmware_load( struct firmware_priv *fw_priv, bool uevent, long timeout) { int retval = 0 ; struct device *f_dev = fw_priv-dev; struct firmware_buf *buf = fw_priv-buf; struct bin_attribute *fw_attr_data = buf-dest_addr ? firmware_direct_attr_data : firmware_attr_data; /* fall back on userspace loading */ buf-is_paged_buf = buf-dest_addr ? false : true ; dev_set_uevent_suppress(f_dev, true ); /* Need to pin this module until class device is destroyed */ __module_get(THIS_MODULE); retval = device_add(f_dev); //以下生成的data和loading节点,用于ueventd读取相应的binary,然后通过节点加载到内存的。 //用于下载的节点, retval = device_create_bin_file(f_dev, fw_attr_data); //生成一个loading的节点,loading节点用于控制的 retval = device_create_file(f_dev, dev_attr_loading); if (retval) { dev_err(f_dev, "%s: device_create_file failed\n" , __func__); goto err_del_bin_attr; } if (uevent) { //这里正在通知ueventd dev_set_uevent_suppress(f_dev, false ); dev_dbg(f_dev, "firmware: requesting %s\n" , buf-fw_id); if (timeout != MAX_SCHEDULE_TIMEOUT) schedule_delayed_work(fw_priv-timeout_work, timeout); kobject_uevent(fw_priv-dev.kobj, KOBJ_ADD); } wait_for_completion(buf-completion); cancel_delayed_work_sync(fw_priv-timeout_work); } _request_firmware() - assign_firmware_buf() 这是做什么的?? 来看一下ueventd.c文件中是怎么检测这个然后读binary,通过loading节点加载binary的。 int ueventd_main( int argc, char **argv){ ... while ( 1 ) { ufd.revents = 0 ; nr = poll(ufd, 1 , - 1 ); if (nr = 0 ) continue ; if (ufd.revents POLLIN) handle_device_fd(); } } void handle_device_fd(){ ... handle_firmware_event(uevent); //process_firmware_event() } #define SYSFS_PREFIX "/sys" #define FIRMWARE_DIR1 "/etc/firmware" #define FIRMWARE_DIR2 "/vendor/firmware" #define FIRMWARE_DIR3 "/firmware/image" #define FIRMWARE_DIR4 "/firmware-modem/image" #define DEVICES_BASE "/devices/soc.0" static void process_firmware_event( struct uevent *uevent){ ... l = asprintf(root, SYSFS_PREFIX "%s/" , uevent-path); l = asprintf(loading, "%sloading" , root); l = asprintf(file1, FIRMWARE_DIR1 "/%s" , uevent-firmware); l = asprintf(file2, FIRMWARE_DIR2 "/%s" , uevent-firmware); l = asprintf(file3, FIRMWARE_DIR3 "/%s" , uevent-firmware); l = asprintf(file4, FIRMWARE_DIR4 "/%s" , uevent-firmware); loading_fd = open(loading, O_WRONLY); ... if (!load_firmware(fw_fd, loading_fd, data_fd)) //加载binary INFO( "firmware: copy success { '%s', '%s' }\n" , root, uevent-firmware); else INFO( "firmware: copy failure { '%s', '%s' }\n" , root, uevent-firmware); } 以下看看ueventd中,真正把读到的binary,传给kernel的函数 static int load_firmware( int fw_fd, int loading_fd, int data_fd) { struct stat st; long len_to_copy; int ret = 0 ; //fstat查看binary的信息,读出来size等 if (fstat(fw_fd, st) 0 ) return - 1 ; len_to_copy = st.st_size; write(loading_fd, "1" , 1 ); /* start transfer */ while (len_to_copy 0 ) { char buf ; ssize_t nr; //读 nr = read(fw_fd, buf, sizeof (buf)); if (!nr) break ; if (nr 0 ) { ret = - 1 ; break ; } len_to_copy -= nr; while (nr 0 ) { ssize_t nw = 0 ; //写到data节点 nw = write(data_fd, buf + nw, nr); if (nw = 0 ) { ret = - 1 ; goto out; } nr -= nw; } } out: if (!ret) //loading节点用于通知kernel加载情况!! write(loading_fd, "0" , 1 ); /* successful end of transfer */ else write(loading_fd, "-1" , 2 ); /* abort transfer */ return ret; } 内核中,data节点出来write的函数在_request_firmware_load()中根据buf-dest_addr的值有所不同 static int _request_firmware_load( struct firmware_priv *fw_priv, bool uevent, long timeout) { ... struct bin_attribute *fw_attr_data = buf-dest_addr ? firmware_direct_attr_data : firmware_attr_data; ... } 在下载modem.bxx的时候应该都是有buf-dest_addr才对 6 pil_load_seg fw_name = modem.b02 6 fw_load_from_user_helper start 6 _request_firmware_load buf-dest_addr = 0x86800000 6 firmware_loading_store started ... 6 pil_load_seg fw_name = modem.b07 6 fw_load_from_user_helper start 6 _request_firmware_load buf-dest_addr = 0x86840000 ... //write(data_fd, buf + nw, nr); buf对应buffer? offset? count对应nr?? static ssize_t firmware_direct_write( struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buffer, loff_t offset, size_t count) { struct device *dev = kobj_to_dev(kobj); struct firmware_priv *fw_priv = to_firmware_priv(dev); //获取uevent读取modem binary时候读到的内容,保存在firmware_priv中。firmware_priv中的firmware_buf保存了binary的物理地址,大小等等信息 struct firmware *fw; ssize_t retval; if (!capable(CAP_SYS_RAWIO)) return -EPERM; mutex_lock(fw_lock); fw = fw_priv-fw; if (!fw || test_bit(FW_STATUS_DONE, fw_priv-buf-status)) { retval = -ENODEV; goto out; } retval = __firmware_data_rw(fw_priv, buffer, offset, count, 0 ); if (retval 0 ) goto out; fw_priv-buf-size = max_t(size_t, offset, fw_priv-buf-size); out: mutex_unlock(fw_lock); return retval; } static int __firmware_data_rw( struct firmware_priv *fw_priv, char *buffer, loff_t *offset, size_t count, int read) { u8 __iomem *fw_buf; struct firmware_buf *buf = fw_priv-buf; int retval = count; if ((*offset + count) buf-dest_size) { pr_debug( "%s: Failed size check.\n" , __func__); retval = -EINVAL; goto out; } //fw_buf 就是要拷贝到内存中的modem binary物理地址对应的虚拟地址。 //map_fw_mem函数中,会根据虚拟地址以及需要拷贝的大小,map出一段虚拟地址。 //map一段物理地址,然后返回内核可以访问的虚拟地址,,这个是通过ioremap相关的函数实现的 fw_buf = buf-map_fw_mem(buf-dest_addr + *offset, count, buf-map_data); if (!fw_buf) { pr_debug( "%s: Failed ioremap.\n" , __func__); retval = -ENOMEM; goto out; } //读写,直接拷贝就可以 if (read) memcpy (buffer, fw_buf, count); else memcpy (fw_buf, buffer, count); *offset += count; buf-unmap_fw_mem(fw_buf, count, buf-map_data); out: return retval; } static void *map_fw_mem(phys_addr_t paddr, size_t size, void *data) { struct pil_map_fw_info *info = data; return dma_remap(info-dev, info-region, paddr, size, info-attrs); } static inline void *dma_remap( struct device *dev, void *cpu_addr, dma_addr_t dma_handle, size_t size, struct dma_attrs *attrs) { const struct dma_map_ops *ops = get_dma_ops(dev); BUG_ON(!ops); if (!ops-remap) { WARN_ONCE( 1 , "Remap function not implemented for %pS\n" , ops-remap); return NULL; } return ops-remap(dev, cpu_addr, dma_handle, size, attrs); } static void *arm_dma_remap( struct device *dev, void *cpu_addr, dma_addr_t handle, size_t size, struct dma_attrs *attrs) { struct page *page = pfn_to_page(dma_to_pfn(dev, handle)); pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL); unsigned long offset = handle ~PAGE_MASK; size = PAGE_ALIGN(size + offset); return __dma_alloc_remap(page, size, GFP_KERNEL, prot, __builtin_return_address( 0 )) + offset; } static void * __dma_alloc_remap( struct page *page, size_t size, gfp_t gfp, pgprot_t prot, const void *caller) { struct vm_struct *area; unsigned long addr; /* * DMA allocation can be mapped to user space, so lets * set VM_USERMAP flags too. */ //得到一段满足要求的vm_struct。这里 area = get_vm_area_caller(size, VM_ARM_DMA_CONSISTENT | VM_USERMAP, caller); if (!area) return NULL; addr = ( unsigned long )area-addr; area-phys_addr = __pfn_to_phys(page_to_pfn(page)); //addr是得到的vm_struct对应的虚拟地址,内核可以访问的 //所以根据物理地址以及对应的虚拟地址以及大小等情况,ioremap_page_range会做一个page table //这样内核就可以直接访问这段内存 if (ioremap_page_range(addr, addr + size, area-phys_addr, prot)) { vunmap(( void *)addr); return NULL; } return ( void *)addr; //返回虚拟内存,现在这个虚拟内存就可以直接访问了 } 和ioremap_page_range()比较像。 顶0 踩0
展开>>
收起<<
个人分类:
qualcomm
|
1 次阅读
|
1
个评论
安森美半导体实现高通快速充电QC 3.0的方案优化能效
热度
3
big白菜
2016-5-16 11:58
MicrosoftInternetExplorer4 0 2 DocumentNotSpecified 7.8 磅 Normal 0 如今,智能手机、平板电脑等便携式设备随着用户的所需而不断增大屏幕和增多功能,耗电量明显增加,如何延长电池续航时间成为工程师需要解决的重要问题。同時,用户需要快速充电,使电源适配器所需的功率也增加,高通快速充电技术是应此需求而生。 高通快速充电技术概览 采用传统的 5 V 输入电压充电,由于输出大电流和线性阻抗产生的压降限制电池充电 IC 输入对输出电压余量,且产生更多热量和能效损失导致手机系统显著发热,而减小输出电流则需要更长的充电时间。高通快速充电技术突破传统 5 V 充电的限制,减少线路损耗,为电池充电 IC 提供充足的余量,改善热性能,实现更高转换能效,大大缩短充电时间。例如,若电缆电阻 300 m Ω ,便携式设备中总电阻 300 m Ω ,采用传统的 5 V 电压充电,根据 USB 电池充电规范 1.2 版 (USB BC 1.2) , Micro USB 电缆的最大电流限制在 1.8 A ,输入功率为 9 W ,功耗为 (1.8) 2 x(0.3 + 0.3)=1.94 W ,能效损失达到 22% ;若采用高通快速充电,将输入电压提高至 9 V ,在相同输入功率 9 W 的情况下,输入电流为 1 A ,此时功耗仅为 1 2 x (0.3 + 0.3) = 0.6 W ,能效损失仅为 5 V/1.8 A 的 1/3 ,减小发热量,且实现更快充电。 高通快速充电现已升级至 QC 3.0 ,比上一代 QC 2.0 更进一步提升充电效率和加快充电速度。 QC 2.0 提供 5V 、 9V 、 12V 和 20V 四档充电电压, QC 3.0 则以 200 mV 为步幅,提供从 3.6 V 到 20 V 电压的灵活选择。采用高通 QC 3.0 时,便携式设备通过 USB 接口的 D+ 和 D- 信号提交电压选择请求,在同一时间可能有不规律的 USB 数据通信。关于 QC3.0 支持的总线电压 (VBUS) 范围, A 级为 3.6 V 至 12 V , B 级为 3.6 V 至 20 V 。 QC 3.0 在分立模式下等同于 QC 2.0 ,以 0 V 、 0.6 v 、 3.3 V 三级逻辑通过静态 D+/D- 值选择 VBUS ;在连续模式下,新的 QC 3.0 以 200 mV 小步幅增加或降低 VBUS ,让便携式设备选择最适合的电压达到理想充电效率,更具灵活性,其最大负载电流限制为 3 A ,最高功率可达 60 W 。 QC 3.0 兼容于先前的 QC 版本,并可支持最新的 USB Type-C 接口,其工作原理是:在电源适配器里的次级端需要一个 IC 经由 USB 电缆来连接高通 IC , USB D+ 和 D- 用于发送来自便携式设备的信息到适配器,次级端控制器处理所需的输出电压,解码 D+ 和 D- 信号信息,请求初级端 AC-DC 控制器通过光耦来调节所需的输出电压,从而减小损耗,提高充电效率。 图 1 : QC 3.0 的工作原理图 安森美半导体实现高通 QC 3.0 的完整方案 安森美半导体致力于推动高能效创新,是全球电源方案的领袖,为配合新一代快速充电技术,公司推出符合新的高通 QC 3.0 的 AC-DC 适配器方案,支持更小尺寸的适配器,具有能效高、空载待机能耗低等优势,支持高通 QC 3.0 高压专用充电端口 (HVDCP)A 级和 B 级规格,和向后兼容旧的 QC 2.0 协议,并符合 UL 认证和欧盟能效标准 (CoC V5 Tier-2) 要求,提供领先业界的高能效。该方案集成 NCP4371 次级端充电控制器 、 NCP4308 同步整流 (SR) 控制器 和 NCP1361/6 初级端稳流准谐振 (QR) PWM 控制器 。 其中, NCP4371 次级端 QC3.0 充电控制器支持充电器 USB VBUS 根据手机或便携式设备的需求而变化,为优化电池充电时间, USB VBUS 可在 3.6 V-20 V 以分立步幅配置,兼容 USB BC 1.2 ,提供 +/-3% 的恒压和恒流调节,内置可配置的功率限制功能,具备内部或外部放电功能选择,软短路限流降至 VBUS = 2.2 V ,外部元件少,无需次级端并联稳压器如 TL431 ,就能实现一个充电器设计,节省了成本和所需空间。 图 2 : NCP4371 应用原理图 需要注意的是, NCP4371 支援恒定功率和恒定电流模式。一般而言, USB Type-A 的最大电流为 1.5 A 至 2.0 A , Type-C 的最大电流为 3.0 A 或 5.0 A 。在恒定功率模式下,如果降低输出电压,必然导致输出电流增加,进而产生更多损耗,因而我们必须限制恒定功率模式下的最大电流。 NCP4371 功率选择 A 针对采用 QC 3.0 A 级的小功率应用,并定义了 5 条电流限制曲线,功率选择 B 适用于 QC 3.0 A 级和 B 级的大功率应用,并定义了 8 条电流限制曲线,这样最大输出电流可被限制到期望值,功率选择 C 则无功率限制。在具体设计中,需根据实际需要,选择 NCP4371 的不同版本:首先选择所需的功率限制,然后从“ RSENSE vs. POUT 图”中选择电流检测电阻值,最后使用电流限制选型图选择电流限制器件代码。 图 3 : RSENSE vs. POUT 图及电流限制选型图 NCP1361 是针对混合架构 (PSR=CC; TL+Opto=CV) 配置的初级端稳压和稳流器。它工作在准谐振峰值电流模式,采用频率钳位控制 (80 kHz 或 110) ,轻载模式下提供固定峰值电流和深度频率反走,采用初级端稳流,而无需次级反馈回路,减少外部元件,节省占板空间,启动时间少,实现高平均能效和低待机能耗。准谐振模式的优势在于,谷底锁定防止带噪声的谷跳,而谷底开关提升能效。 图 4 : NCP1361 典型应用电路 NCP4308 同步整流控制器则作为实现高功率密度的一个选择,具有高灌电流和驱动电流 (8 A 灌电流 / 4 A 驱动电流 ) ,通过减少交叉导通提升正常模式能效,无需辅助电源绕组,提供宽电源电压范围,电流检测引脚高达 100 V ,具备超快关断触发、可调节的最小导通 / 关断时间、自适应门极驱动、精密的真正的零电流检测 (ZCD) 、低启动电流和低待机电流,带轻载和空载模式,用于 10 - 30 W 充电器。 能效测试 在安森美半导体的 QC 3.0 快速充电器评估板端,通过 USB 连接器测得该方案在 5 V 输出时的待机能耗低于 75 mW ,在 5 V 、 9 V 、 12 V 输出时的能效最高可接近 90% ,纹波和噪声小于 80 mV ,电压和电流调节精度达到 +/-5% ,启动时间小于 1.5 秒,并且提供极佳的共模噪声抑制、抗电磁辐射 (EMI) 传导干扰和辐射干扰。 总结 快充技术有效地解决了智能手机和平板电脑等便携式设备在续航时间方面的瓶颈问题,正迅速获得便携式厂商的认可和消费市场的极大关注。安森美半导体实现高通 QC 3.0 的方案提供从 3.6 V 至 20 V 更灵活的电压选择,优化充电时间,可理想地实现平滑的电压转换,在各种负载条件下都提供高能效,还有助于节省成本和所需空间,并向后兼容 QC 2.0 协议,同时符合 UL 认证和 CoC V5 Tier- 2 等欧盟能效标准要求。
展开>>
收起<<
32710 次阅读
|
0
个评论
高通Quick Charge 2.0 快速充电原理分析
热度
4
gygyg2008
2015-7-31 13:50
高通Quick Charge 2.0 快速充电原理分析 2014-06-10 14:09:56 分享: 支持QC 2.0快充的充电器根据手机端在micro USB接口DP/DM上加载的电压值来调整自身AC/DC的输出电压和电流,其对应关系如表1所示: 表1 具体调整原理如下: 当将充电器端通过数据线连到手机上时,充电器默认的是将D+和D-短接的,这样手机端探测充电器类型是DCP(参见本人另一篇博文《高通平台USB2.0和3.0接口充电器识别原理》),手机以默认的5V电压充电,接着过程如下: 1)如果手机端使能了快速充电协议,Android用户空间的hvdcp(high voltage dedicated charger port)进程启动,并且在D+上加载0.325V的电压维持超过1.25s上; 2) 充电器检测到D+上电压0.325V维持超过了1.25s,就断开D+和D-的短接,由于D+和D-断开,所以D-上的电压不再跟随D+上的电压0.325V变动,此时开始下降; 3) 手机端检测到D-上的电压从0.325V开始下降维持1ms以上时,hvdcp读取/sys/class/power_supply/usb /voltage_max的值,如果是9000000mV,就设置D+上的电压为3.3V,D-上 的电压为0.6V,否则设置D+为0.6V,D-为0V; 4) 充电器检测到D+和D-上的电压后,就调整充电器输出电压到9V
展开>>
收起<<
个人分类:
USB
|
1600 次阅读
|
2
个评论
高通平台 lcd driver
孤鹤与飞
2014-8-20 16:08
一、 概述 1.1 简介 本文档主要包括 LCD 模块的驱动流程分析、 Framebuffer 相关知识、 Gralloc 等相关内容,以及 LCD 调试的一些经验和相关 bug 的分析和讲解。 1.2 开发环境 Android:4.0 Kernel:Linux3.0 Ubuntu: 需要 10.04 以及之后的版本 Gcc:4.4.3toolchain 1.3 硬件平台 Msm8x25,pmic(pm8029) 1.4 操作系统 Android:4.0,Kernel:3.0 1.5 开发工具 VIM,SourceInsight,JTAG,ADB 二、 LCD 驱动流程分析 2.1 帧缓冲 2.1.1 帧缓冲概念 帧缓冲( framebuffer )是 Linux 系统为显示设备提供的一个接口,它将显示缓冲区抽象,屏蔽图像硬件的底层差异,允许上层应用程序在图形模式下直接对显示缓冲区进行读写操作。用户不必关系物理显示缓冲区的具体位置及存放方式,这些都由帧缓冲设备驱动本身来完成。对于帧缓冲设备而言,只要在显示缓冲区中与显示点对应的区域写入颜色值,对应的颜色会自动在屏幕上显示。帧缓冲为标准字符设备,主设备号为 29 ,对应于 /dev/fbn 。 2.1.2fb_info 结构体 帧缓冲设备最关键的一个数据结构体是 fb_info 结构,为了便于记忆,简称 FBI ,这个机构体在 fb.h 文件中定义了。 FBI 中包括了关于帧缓冲设备属性和操作的完整描述,这个结构体的定义如下所示。 其中 fb_ops 、 fb_var_screeninfo 和 fb_fix_screeninfo 这三个结构极为重要。 FBI 的成员变量 fbops 为指向底层操作的函数指针,这些函数是需要驱动程序开发人员编写的,不过高通平台已经定义好这些接口了,我们只需了解下这些接口的功能,不必修改。 fb_var_screeninfo 记录用户可修改的显示控制参数,包括屏幕分辨率和每个像素点的比特数。 fb_var_screeninfo 中的 xres 定义屏幕一行有多少个点, yres 定义屏幕一列有多少个点, bits_per_pixel 定义每个点用多少个字节表示。而 fb_fix_screeninfo 中记录用户不能修改的显示控制器的参数,如屏幕缓冲区的物理地址、长度。当对帧缓冲设备进行映射操作时,就是从 fb_fix_screeninfo 中取得缓冲区物理地址的。上述结构体都需要在驱动程序中初始化和设置,在后面的流程分析中会作具体的讲解。 2.1.3 帧缓冲设备驱动结构 从上图可以看出,注册 framebuffer 时需要用到 fb_info 结构体, fb_info 结构体又包含了 fb_ops 结构体,而 fb_ops 结构体中的 fb_read 、 fb_write 用于应用层对 framebuffer 的读写操作, fb_mmap 用于应用进程和 framebuffer 之间的内存映射, fb_ioctl 用于应用层对 framebuffer 进行的一些控制操作,具体的操作会在后面的流程分析中讲到。 fb_info 结构中的 fb_check_var 和 fb_set_par 分别用于获取和设置 framebuffer 的显示参数。 2.2LCDdriver 的注册以及 framebuffer 的建立 在分析 LCD 的流程时,从底层往上一层层的分析,这样更容易理解驱动层每一层的作用。 2.2.1LCD 驱动的注册以及 LCDCdevice 的创建 在注册 LCD 驱动前需要设置一些参数,包括分辨率大小、 bpp 、像素时钟频率等如下图, 在 probe 函数中会执行 msm_fb_add_device 这个接口,这个接口在 msm_fb.c 中定义,这个接口的功能就是传递 LCDdriver 的相关参数并根据 LCD 的类型(这里假设是 RGB 接口)创建一个 LCDCdevice ,此外还会创建一个 framebuffer 结构体,并将其添加到全局的 framebuffer 列表 fb_list 里面。 2.2.2MDPdevice 的创建 在根据 LCD 的类型创建新设备时,会去执行 lcdc.c 中的 probe 函数,这个接口会创建一个 mdpdevice ,然后设置 mdpdevice 的一些显示参数以及 on 和 off 接口,并将 lcdc 的 pdev 结构体的 next 指针指向 mdpdevice 的设备结构体,即 mdpdevice 是 lcdcdevice 的父节点。 2.2.3msm_fbdevice 的创建 在创建 MDPdevice 时,会去执行 mdp.c 中的 probe 函数,初始化 MDP 相关参数并创建 msm_fbdevice ,其 next 指针指向 mdpdevice 的设备结构体,即 msm_fbdevice 是 mdpdevice 的父节点。 2.2.4fb0 的创建 在创建 msmfb_device 时,会去执行 msm_fb.c 中的 probe 函数,此接口中最重要的一个函数就是 msm_fb_register ,该接口会对前面讲到的 fb_info 结构体进行填充,设置 fb_var_screen 和 fb_fix_screen 结构体的显示参数,包括图像显示格式、可见分辨率、虚拟分辨率、红绿蓝色域的偏移、帧率、虚拟基地址等等一些参数,并将高通平台自带的 fb_ops 接口填充到 fb_info 结构体里面,然后调用 register_framebuffer 来创建 fb0device 。至此, fb0 的建立已经完成,应用层可以对 fb0 节点的控制来操作 framebuffer 缓冲区。 2.2.5fb 设备创建流程图 从上图可清楚的看出从注册 LCD 驱动到创建 framebuffer 的流程。 2.3fb 设备的打开及 framebuffer 的使用 上面分析从 LCD 驱动的注册到 fb0 建立的流程,那么 fb0 创建好后,怎么使用它呢?现在来分析下打开 fb0 操作 framebuffer 的流程。 2.3.1gralloc 设备的打开过程 显示模块在初始化时会去通过 hw_get_module 加载 gralloc 库,该库存在于 /system/lib/hw 中,在加载成功 gralloc 库后,会调用 framebuffer_open 接口,这个接口最终会被指向 framebuffer.cpp 文件中的 fb_device_open 函数。执行 fb_device_open 时,首先会去打开先前已经加载成功的 gralloc 库。 Gralloc 模块在在文件 hardware/libhardware/include/hardware/gralloc.h 中定义了一个帮助函数 gralloc_open ,用来打开 gralloc 设备。 gralloc_open 最终会指向 gralloc.cpp 中的 gralloc_device_open 函数。 intgralloc_device_open(consthw_module_t*module,constchar*name, hw_device_t**device) { intstatus=-EINVAL; if(!strcmp(name,GRALLOC_HARDWARE_GPU0)){ gralloc_context_t*dev; dev=(gralloc_context_t*)malloc(sizeof(*dev)); /*initializeourstatehere*/ memset(dev,0,sizeof(*dev)); /*initializetheprocs*/ dev-device.common.tag=HARDWARE_DEVICE_TAG; dev-device.common.version=0; dev-device.common.module=const_casthw_module_t*(module); dev-device.common.close=gralloc_close; dev-device.alloc=gralloc_alloc; dev-device.free=gralloc_free; *device=dev-device.common; status=0; }else{ status=fb_device_open(module,name,device); } returnstatus; } 这个函数主要是用来创建一个 gralloc_context_t 结构体,并且对它的成员变量 device 进行初始化。结构体 gralloc_context_t 的成员变量 device 的类型为 gralloc_device_t ,它用来描述一个 gralloc 设备。 gralloc 设备是用来分配和释放图形缓冲区的,这是通过调用它的成员函数 alloc 和 free 来实现的。 2.3.2fb 设备的打开过程 在打开 gralloc 设备后,会去执行 fb_device_open 来打开 fb 设备。 fb 设备使用结构体 framebuffer_device_t 来描述。结构体 framebuffer_device_t 是用来描述系统帧缓冲区的信息,它定义在文 hardware/libhardware/include/hardware/fb.h 。 typedefstructframebuffer_device_t{ structhw_device_tcommon; /*flagsdescribingsomeattributesoftheframebuffer*/ constuint32_tflags;// 记录系统帧缓冲区的标志 /*dimensionsoftheframebufferinpixels*/ constuint32_twidth;// 描述设备显示屏的宽度 constuint32_theight;// 描述设备显示屏的高度 /*frambufferstrideinpixels*/ constintstride;// 描述设备显示屏的一行有多少个像素点 /*framebufferpixelformat*/ constintformat;// 描述系统帧缓冲区的像素格式 /*resolutionoftheframebuffer'sdisplaypanelinpixelperinch*/ constfloatxdpi;// 描述设备显示屏在宽度上的密度 constfloatydpi;// 描述设备显示屏在高度上的密度 /*framebuffer'sdisplaypanelrefreshrateinframespersecond*/ constfloatfps;// 描述设备显示屏的刷新频率,它的单位是帧每秒 /*minswapintervalsupportedbythisframebuffer*/ constintminSwapInterval;// 描述帧缓冲区交换前后两个图形缓冲区的最小时间间隔 /*maxswapintervalsupportedbythisframebuffer*/ constintmaxSwapInterval;// 描述帧缓冲区交换前后两个图形缓冲区的最大时间间隔 /*numberofframebuffers*/ constintnumFramebuffers; intreserved ; int(*setSwapInterval)(structframebuffer_device_t*window,intinterval); int(*setUpdateRect)(structframebuffer_device_t*window,intleft,inttop,intwidth,intheight); int(*post)(structframebuffer_device_t*dev,buffer_handle_tbuffer); int(*compositionComplete)(structframebuffer_device_t*dev); int(*lockBuffer)(structframebuffer_device_t*dev,int); void(*dump)(structframebuffer_device_t*dev,char*buff,intbuff_len); int(*enableScreen)(structframebuffer_device_t*dev,intenable); int(*perform)(structframebuffer_device_t*dev,intevent,intvalue); }framebuffer_device_t; Gralloc 模块在在文件 hardware/libhardware/include/hardware/fb.h 中定义了一个帮助函数 framebuffer_open ,用来打开 fb 设备。这个接口最终会被指向 framebuffer.cpp 文件中的 fb_device_open 函数。 intfb_device_open(hw_module_tconst*module,constchar*name, hw_device_t**device) { intstatus=-EINVAL; if(!strcmp(name,GRALLOC_HARDWARE_FB0)){ alloc_device_t*gralloc_device; status=gralloc_open(module,gralloc_device); if(status0) returnstatus; /*initializeourstatehere*/ fb_context_t*dev=(fb_context_t*)malloc(sizeof(*dev)); memset(dev,0,sizeof(*dev)); /*initializetheprocs*/ dev-device.common.tag=HARDWARE_DEVICE_TAG; dev-device.common.version=0; dev-device.common.module=const_casthw_module_t*(module); dev-device.common.close=fb_close; dev-device.setSwapInterval=fb_setSwapInterval; dev-device.post=fb_post; dev-device.setUpdateRect=0; dev-device.compositionComplete=fb_compositionComplete; dev-device.lockBuffer=fb_lockBuffer; #ifdefined(HDMI_DUAL_DISPLAY) dev-device.perform=fb_perform; #endif private_module_t*m=(private_module_t*)module; status=mapFrameBuffer(m); if(status=0){ intstride=m-finfo.line_length/(m-info.bits_per_pixel3); const_castuint32_t(dev-device.flags)=0; const_castuint32_t(dev-device.width)=m-info.xres; const_castuint32_t(dev-device.height)=m-info.yres; const_castint(dev-device.stride)=stride; const_castint(dev-device.format)=m-fbFormat; const_castfloat(dev-device.xdpi)=m-xdpi; const_castfloat(dev-device.ydpi)=m-ydpi; const_castfloat(dev-device.fps)=m-fps; const_castint(dev-device.minSwapInterval)=private_module_t::PRIV_MIN_SWAP_INTERVAL; const_castint(dev-device.maxSwapInterval)=private_module_t::PRIV_MAX_SWAP_INTERVAL; const_castint(dev-device.numFramebuffers)=m-numBuffers; if(m-finfo.reserved ==0x5444 m-finfo.reserved ==0x5055){ dev-device.setUpdateRect=fb_setUpdateRect; LOGD("UPDATE_ON_DEMANDsupported"); } *device=dev-device.common; } //Closethegrallocmodule gralloc_close(gralloc_device); } returnstatus; } fb_device_open 用来创建一个 fb_context_t 结构体,并且对它的成员变量 device 进行初始化。结构体 fb_context_t 的成员变量 device 的类型为 framebuffer_device_t ,前面提到,它是用来描述 fb 设备的。 fb 设备主要是用来渲染图形缓冲区的,这是通过调用它的成员函数 post 来实现的。从这里可以看出,函数 fb_device_open 所打开的 fb 设备的成员函数 post 被设置为 Gralloc 模块中的函数 fb_post. 。 函数 fb_device_open 在打开 fb 设备的过程中,会调用另外一个函数 mapFrameBuffer 来获得系统帧缓冲区的信息,并且将这些信息保存在参数 module 所描述的一个 private_module_t 结构体的各个成员变量中。有了系统帧缓冲区的信息之后,函数 fb_device_open 接下来就可以对前面所打开的一个 fb 设备的各个成员变量进行初始化。这些成员变量的含义可以参考前面对结构体 framebuffer_device_t 的介绍。函数 mapFrameBuffer 除了用来获得系统帧缓冲区的信息之外,还会将系统帧缓冲区映射到当前进程的地址空间来。 函数 mapFrameBuffer 实现在文件 hardware/libhardware/modules/gralloc/framebuffer.cpp ,如下所示: staticintmapFrameBuffer(structprivate_module_t*module) { pthread_mutex_lock(module-lock); interr=mapFrameBufferLocked(module); pthread_mutex_unlock(module-lock); returnerr; } 这个函数调用了同一个文件中的另外一个函数 mapFrameBufferLocked 来初始化参数 module 以及将系统帧缓冲区映射到当前进程的地址空间来。 intmapFrameBufferLocked(structprivate_module_t*module) { //alreadyinitialized... if(module-framebuffer){ return0; } charconst*constdevice_template ; charproperty ; /* 首先在系统中检查是否存在设备文件 /dev/graphics/fb0 或者 /dev/fb0 。如果存在的话,那么就调用函数 open 来打开它,并且将得到的文件描述符保存在变量 fd 中。这样,接下来函数 mapFrameBufferLocked 就可以通过文件描述符 fd 来与内核中的帧缓冲区驱动程序交互 */ while((fd==-1)device_template ){ snprintf(name,64,device_template ,0); fd=open(name,O_RDWR,0); i++; } if(fd0) return-errno; /* 以下几行代码分别通过 IO 控制命令 FBIOGET_FSCREENINFO 和 FBIOGET_VSCREENINFO 来获得系统帧缓冲区的信息,分别保存在 fb_fix_screeninfo 结构体 finfo 和 fb_var_screeninfo 结构体 info 中 */ structfb_fix_screeninfofinfo; if(ioctl(fd,FBIOGET_FSCREENINFO,finfo)==-1) return-errno; structfb_var_screeninfoinfo; if(ioctl(fd,FBIOGET_VSCREENINFO,info)==-1) return-errno; /* 设置设备显示屏的虚拟分辨率,结构体 fb_var_screeninfo 的成员变量 xres 和 yres 用来描述显示屏的可视分辨率,而成员变量 xres_virtual 和 yres_virtual 用来描述显示屏的虚拟分辨率。这里保持可视分辨率以及虚拟分辨率的宽度值不变,而将虚拟分辨率的高度值设置为可视分辨率的高度值的 NUM_BUFFERS 倍。 NUM_BUFFERS 是一个宏,它的值被定义为 2 。这样,我们就可以将系统帧缓冲区划分为两个图形缓冲区来使用,即可以通过硬件来实现双缓冲技术。在结构体 fb_var_screeninfo 中,与显示屏的可视分辨率和虚拟分辨率相关的另外两个成员变量是 xoffset 和 yoffset ,它们用来告诉帧缓冲区当前要渲染的图形缓冲区是哪一个 */ info.reserved =0; info.reserved =0; info.reserved =0; info.xoffset=0; info.yoffset=0; info.activate=FB_ACTIVATE_NOW; if(info.bits_per_pixel==32){ /* *ExplicitlyrequestRGBA_8888 */ info.bits_per_pixel=32; info.red.offset=24; info.red.length=8; info.green.offset=16; info.green.length=8; info.blue.offset=8; info.blue.length=8; info.transp.offset=0; info.transp.length=8; /*Note:theGLdriverdoesnothavear=8g=8b=8a=0config,soifwedo *notusetheMDPforcomposition(i.e.hwcomposition==0),askfor *RGBAinsteadofRGBX.*/ if(property_get("debug.sf.hw",property,NULL)0atoi(property)==0) module-fbFormat=HAL_PIXEL_FORMAT_RGBX_8888; elseif(property_get("debug.composition.type",property,NULL)0(strncmp(property,"mdp",3)==0)) module-fbFormat=HAL_PIXEL_FORMAT_RGBX_8888; else module-fbFormat=HAL_PIXEL_FORMAT_RGBA_8888; }else{ info.bits_per_pixel=16; info.red.offset=11; info.red.length=5; info.green.offset=5; info.green.length=6; info.blue.offset=0; info.blue.length=5; info.transp.offset=0; info.transp.length=0; module-fbFormat=HAL_PIXEL_FORMAT_RGB_565; } //adrenoneeds4kalignedoffsets.Maxholesizeis4096-1 intsize=roundUpToPageSize(info.yres*info.xres*(info.bits_per_pixel/8)); /* *RequestNUM_BUFFERSscreens(atlest2forpageflipping) */ intnumberOfBuffers=(int)(finfo.smem_len/size); LOGV("numsupportedframebuffersinkernel=%d",numberOfBuffers); if(property_get("debug.gr.numframebuffers",property,NULL)0){ intnum=atoi(property); if((num=NUM_FRAMEBUFFERS_MIN)(num=NUM_FRAMEBUFFERS_MAX)){ numberOfBuffers=num; } } if(numberOfBuffersNUM_FRAMEBUFFERS_MAX) numberOfBuffers=NUM_FRAMEBUFFERS_MAX; LOGV("Wesupport%dbuffers",numberOfBuffers); //considertheincludedholeby4kalignment uint32_tline_length=(info.xres*info.bits_per_pixel/8); info.yres_virtual=(size*numberOfBuffers)/line_length; /* 通过 IO 控制命令 FBIOPUT_VSCREENINFO 来设置设备显示屏的虚拟分辨率以及像素格式,如果设置失败,即调用函数 ioctl 的返回值等于 -1 ,那么很可能是因为系统帧缓冲区在硬件上不支持双缓冲,因此,接下来的代码就会重新将显示屏的虚拟分辨率的高度值设置为可视分辨率的高度值,并且将变量 flags 的 PAGE_FLIP 位置为 0*/ uint32_tflags=PAGE_FLIP; if(ioctl(fd,FBIOPUT_VSCREENINFO,info)==-1){ info.yres_virtual=size/line_length; flags=~PAGE_FLIP; LOGW("FBIOPUT_VSCREENINFOfailed,pageflippingnotsupported"); } /* 另一方面,如果调用函数 ioctl 成功,但是最终获得的显示屏的虚拟分辨率的高度值小于可视分辨率的高度值的 2 倍,那么也说明系统帧缓冲区在硬件上不支持双缓冲。在这种情况下,接下来的代码也会重新将显示屏的虚拟分辨率的高度值设置为可视分辨率的高度值,并且将变量 flags 的 PAGE_FLIP 位置为 0 。 */ if(info.yres_virtual((size*2)/line_length)){ //weneedatleast2forpage-flipping info.yres_virtual=size/line_length; flags=~PAGE_FLIP; LOGW("pageflippingnotsupported(yres_virtual=%d,requested=%d)", info.yres_virtual,info.yres*2); } if(ioctl(fd,FBIOGET_VSCREENINFO,info)==-1) return-errno; if(int(info.width)=0||int(info.height)=0){ //thedriverdoesn'treturnthatinformation //defaultto160dpi info.width=((info.xres*25.4f)/160.0f+0.5f); info.height=((info.yres*25.4f)/160.0f+0.5f); } /* 首先计算显示屏的密度,即每英寸有多少个像素点,分别宽度和高度两个维度,分别保存在变量 xdpi 和 ydpi 中。注意, fb_var_screeninfo 结构体 info 的成员变量 width 和 height 用来描述显示屏的宽度和高度,它们是以毫米( mm )为单位的。 */ floatxdpi=(info.xres*25.4f)/info.width; floatydpi=(info.yres*25.4f)/info.height; //Thereserved fieldisusedtostoreFPSbythedriver. floatfps=info.reserved ; /* 通过 IO 控制命令 FBIOGET_FSCREENINFO 来获得系统帧缓冲区的固定信息,并且保存在 fb_fix_screeninfo 结构体 finfo 中,接下来再使用 fb_fix_screeninfo 结构体 finfo 以及前面得到的系统帧缓冲区的其它信息来初始化参数 module 所描述的一个 private_module_t 结构体 */ if(ioctl(fd,FBIOGET_FSCREENINFO,finfo)==-1) return-errno; module-flags=flags; module-info=info; module-finfo=finfo; module-xdpi=xdpi; module-ydpi=ydpi; module-fps=fps; /* 表达式 info.yres_virtual/info.yres 计算的是整个系统帧缓冲区可以划分为多少个图形缓冲区来使用 */ interr; module-numBuffers=info.yres_virtual/info.yres; /*bufferMask 的值接着被设置为 0 ,表示系统帧缓冲区中的所有图形缓冲区都是处于空闲状态 */ module-bufferMask=0; size_tfbSize=roundUpToPageSize(finfo.line_length*info.yres)*module-numBuffers; module-framebuffer=newprivate_handle_t(fd,fbSize, private_handle_t::PRIV_FLAGS_USES_PMEM,BUFFER_TYPE_UI,module-fbFormat,info.xres,info.yres); /* 系统帧缓冲区是通过调用函数 mmap 来映射到当前进程的地址空间来的。映射后得到的地址空间使用一个 private_handle_t 结构体来描述,这个结构体的成员变量 base 保存的即为系统帧缓冲区在当前进程的地址空间中的起始地址。这样, Gralloc 模块以后就可以从这块地址空间中分配图形缓冲区给当前进程使用 */ void*vaddr=mmap(0,fbSize,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0); if(vaddr==MAP_FAILED){ LOGE("Errormappingtheframebuffer(%s)",strerror(errno)); return-errno; } module-framebuffer-base=intptr_t(vaddr); memset(vaddr,0,fbSize); return0; } 至此, fb 设备的打开过程的分析完成了,系统缓冲区已经被映射到应用层的进程空间了。在 fb 设备被打开后,应用层就可以通过 ioctl 接口对底层的 framebuffer 进行操作了。 2.3.3fb 设备打开流程图 三、 LCD 调试经验 3.1 移植驱动代码 在调试之前,需要先将 LCD 的驱动代码移植好,使 LCD 的接口和平台的接口对应上,并根据硬件原理图,修改 gpio 的配置,修改上电相关的接口,给 LCD 加载正确的供电。移植代码包括板:板文件的修改、驱动源文件的添加、 Konfig 和 Makefile 的修改、工程 mk 的修改。代码移植 OK 后就可以开始准备调试 LCD 了。 3.2 点亮背光 调试 LCD 时,在效果出来之前首先要保证背光能点亮。目前背光的控制方式有两种:数字脉冲和 PWM 。现在用得比较多的是 PWM 方式, PWM 提供波形的源也有两种,一种是从 PMIC 提供的,另一种是从 LCD 内部出来的, CABC 控制方式。 使用 PMIC 提供的源时,需要硬件上将 pmic 的 PWM 输出脚(高通平台是 gpio01 )连接到 LCD 的背光控制脚,在系统起来时,调用 pwm 初始化接口,之后调用 pwm 设置背光等级的接口就可以设置背光亮度了。 使用 CABC 控制方式时,只需设置 LCD 的相关寄存器就可以控制背光的打开和关闭,以及背光亮度的调试,具体设置请参考对应的文档。 3.3 点亮 LCD 点亮 LCD 时,首先要给 LCD 上电(一般情况下,对上电时序没有严格的要求), LCD 的上电接口在板文件中实现了。上完电后要使 LCD 复位,之后再往 LCD 的寄存器里面写参数,对 LCD 进行初始化。初始化参数一般是由 LCD 屏厂提供的,在拿到初始化代码后需要对照 spec 进行适当的修改,将 LCD 的极性设置为当前项目平台的极性。当 LCD 点亮后,可能还会出现显示相关的问题,比如显示区域有偏移,显示的颜色不正确等等,需要对照 spec 修改相应的寄存器进行优化。 四、 问题总结 4.1LCD 相关问题 4.1.1 驱动代码移植完后,调试 LCD ,背光亮了,屏幕没有任何显示,一片漆黑 问题定位:测量 LCD 的相关脚的电压,是否达到正常工作所需电压; (1) 若工作电压没有达到 LCD 的正常工作电压 现象分析: LCD 上电不成功,没有正常工作; 解决方法:对照硬件原理图,修改软件代码,修改上电接口的参数; (2) 若工作电压已经达到 LCD 的正常工作电压 现象分析: LCD 正常工作了,但是 LCD 的极性不对; 解决方法:对照 LCD 的 spec ,参考当前平台的其他 LCD 驱动极性的设置,修改极性相关的寄存器。 4.1.2 屏幕点亮了,但是颜色显示不正确,红色和蓝色互换了 问题定位: LCD 有个寄存器是用来设置显示模式的,红色和蓝色互换,说明对应的寄存器设置不正确; 解决方法:对照 LCD 的 spec ,修改寄存器配置参数; 4.1.3LCD 屏闪,偶尔还会出现不明显的线条 问题定位:修改代码,提高 pclk 到一个较高的频率; (1) 若提高 pclk 后,屏闪现象消失 现象分析:说明此现象是刷新频率较低引起的; 解决方法:将 pclk 提高到一个合适的较高频率; (2) 若提高 pclk 后,屏闪现象仍然存在 现象分析:说明此现象不是刷新频率较低引起的,这种情况是 LCD 极性设置不正确造成的; 解决方法:对照 spec 修改 LCD 的极性; 4.1.4 当屏为 24 位 LCD 时, 24 位效果不明显,和 18 位 LCD 一样 问题定位:检查 LCD 驱动配置是否正确,包括 LCD 寄存器的配置,驱动参数 Bpp 和颜色显示模式 fb_img_type ;以及 LCD 的 gpio 配置,是否支持 24 位显示模式 (1) 若检查上述配置后,发现有些配置不满足要求 现象分析:说明底层驱动的配置不合理,需要修改; 解决方法:将不合理的配置修改为正确的配置,若仍有问题,参考 (2) ; (2) 若检查上述配置后,所有配置都正确 现象分析:说明底层驱动的配置都是 OK 的,那么应该跟上层有关; 解决方法:联系软件部的同事,检查并修改应用层的参数设置; 4.2 平台相关问题 4.2.1 开机时,在开机 logo 和开机动画之间会闪一下屏 现象分析:开机时,在 kernel 起来前是 LK 在支持 LCD 的显示, kernel 起来后会关掉 LK 那边的电源和 clk ,然后打开 kernel 这边的电源和 clk 等,这个时候如果点亮背光的接口的调用比 LCD 初始化接口的调用早,就会引 起屏幕闪烁一下的现象 解决方法:调整背光接口和 LCD 初始化接口的调用顺序,在需要的地方加上适当的延时 4.2.2 做 LCD 兼容功能时,读取到的 ADC 值老是有波动 问题定位:因为 LK 从共享内存中读取到的 ADC 值是 modem 那边读取后存到共享内存里面的,因此首先检查共享 内存的配置和使用是否正常 (1) 若共享内存的设置和读取没有问题 现象分析:说明不是共享内存传值是 OK 的,那么应该是 ADC 读取接口的问题,有波动说明可以读取到数据但是 不准确,那么应该是 adc 通道的初始化没有完成或者不正确引起的; 解决方法:将 adc 通道的初始化代码放到比较靠前的地方,保证在调用 adc 接口读取 adc 值时, adc 通道已经被正 确的初始化了; (2) 若共享内存的设置和读取有问题 解决方法:检查共享内存的申请和使用,注意,目前高通平台支持三个 id 可以被客户使用,分别是 vendor0 、 vendor1 和 vendor2 ; 4.2.3 修改开机 logo 后,系统起不来,串口没有任何 log 输出 现象分析:系统启动时,会给变量分配内存,若开机 logo 太大,有可能在分配开机 logo 的内存空间时将系统的 某些重要内存区域覆盖掉,这样就会造成系统无法启动了 解决方法:修改开机 logo 时,要控制转换后 logo 数组的大小,使数组尽可能的小,这样还可以节省刷 logo 的时 间,如果 logo 的背景是黑色的,则需要要显示 logo 的彩色区域就可以了; 4.2.4 开机 logo 和开机动画之间有一段较长的黑屏时间 现象分析: kernel 启动时,会关掉所有的 clk ,然后重新初始化需要使用的 clk , Mdp 相关的 clk 会在 kernel 启动时被 关掉,而在 mdp 初始化时才被打开,因此存在一段空白期; 解决方法:在 kernel 中对 mdp 相关的 clk 进行设置,使其不被关闭; 调试小结: 1 )调试 lcd 背光 , 背光主要分为 PMIC 自带的和单独的 DCDC ,如果为 PMIC 自带的背光,一般平台厂商已经做好,直接调用接口即可,如果为单独的 DCDC 驱动,则需要用 GPIO 控制 DCDC 的 EN 端 2 )确认 lcd 的模拟电, io 电是否正常 3 )根据 lcd 的分辨率, RGB / CPU / MIPI 等不同的接口,配置控制寄存器接口 4 )根据 lcdspec 配置 PCLK 的频率,配置 PCLK,VSYNC,HSYNC,DE 等控制线的极性 5 )使用示波器测试所有 clk 的波形,确认频率,极性是否符合要求 6 )使用示波器测试 data 线,看是否有数据输出, bpp 的设置是否正确 7 )如果 lcd 需要初始化,配置 spi 的接口,一般分为 cpu 自带的 spi 控制器,和 gpio 模拟的 spi 。 8 )根据 lcdspec 中的初始化代码进行 lcd 的初始化 9 )用示波器测量 lcd 的 spiclk 及数据线,确认是否正常输出 10 )正常情况下,此时 lcd 应该可以点亮。如果没有点亮,按照上述步骤 1 到 9 ,逐项进行检查测试,重点检查第 5 项, clk 的极性 11 )如果 lcd 点亮,但是花屏。则需要先确认数据格式是否正确,然后确认 fb 里的数据是否正常,有以下几种方法确认 fb 里的数据 i)cat/dev/graphics/fb0/sdcard/fb0 ,然后将 /sdcard/fb0 到另一台相同分辨率及相同格式的手机上,看图片显示是否正常 ii) 使用 irfanview 软件显示 cat/dev/graphics/fb0 出来的 raw 数据,注意要正确设置分辨率及格式,否则显示花屏 iii) 如果 adb 连接正常,可以使用豌豆莢等软件,查看 fb 中的数据是否正常 通过以上途径,如果确认 fb 中的数据正常显示,则很可能为 lcd 初始化代码的问题,或者 clk 极性的问题,如果 fb 数据不正常,则可能为 lcd 控制寄存器配置不正常导致 小结二 其实点亮 lcd 很简单必须保证以后几个步骤正确: 1 :确认 Lcd 信息所在文件被编译进去,并且 lcd 和 boardname 里面注册一质,倘若这部正确,那么 log 里面应该有对应分辨率的一段 framebuffer 同时调到相对应的 power_on 函数。对于 lcdcpanel 对应文件在 lcdc_xx.c ,对于 mipipanel 对应文件在 mipi_xx.c( 下序列操作 ) 和 mipi_xxxx.c ( timingpllclk 等初始化操作)。 2 :仔细检查上电同时测量,同时将 28 根 rgbinterface 对应 gpio 设为 lcdcfunc 。对于传统的 lcd 不需要 RST 操作只需拉高即可,对于 mipi 和需要下 code 的 RGBpanel 需要 RST 高低高操作,这样 code 才生效。注意一般 sleepout(0x11) 和 displayon(0x29) 之间需要 mdelay(100) 左右,貌似这个对于大部分 panel 是必须的。 3: 最后还要确认是否有 framebuffer 输出,要是改动了 display 这块的 clk 很有可能没有 buffer 输出的,可以通过 cat/dev/graphyics/fb0 查看有没有输出字符。曾经调试开机 logo 连续显示时遇到过好几次没有 buffer 输出导致 kernel 卡住,屏也不亮按 power 键没有反映的情况。 4 :如果以上操作正常同时序列正确,那么屏幕应该可以点亮。对于遇到的有以下显示问题: a: 屏幕呈花屏状态,说明 lcd 初始化成功,但是没有 rgb 刷过来。认真检查之后发现 pclk 时序不对,由于是新的平台所以设对以后,以后的屏就好办了。 b : RGBpane 内容 l 闪烁通常由 pclk 设置不对导致还有可能与 porch 有关。通常 wvga16bit 的 panel 使用 24.5M 的 PCLK , qhd 的 24bitpanel30MPCLK 。至于 porch 我们可以多替换几组试试或者找 FAE 发个可以点亮的。一般屏对 porch 要求不高,几乎都可以点亮的。 c:FPC 没有贴好也有可能导致屏幕不亮。 d:rest 有问题,一定仔细测量使用示波器看出波形,比如 lk 下面有时可能就没有控制对。 e: 许多 kernel 里面实现的但是在 lk 下面由于代码比较少,就不好实现,比如 pm 上电, vibrator 等等,其实在 kernel 里面归根也是写对应寄存器的,很简单,最好使的办法就是在 kernel 里面读出来,在在 lk 里面写进去,这样就好办了。 8x 平台许多上电我就是这样做的,还有 mipi 的 dsi 相关设置 clk 的 REG 。 f: 屏幕经常唤醒只显示灰色底面,最后查明寄存器没有使能外部升压电路。 g: 唤醒屏幕闪白光问题,说白了是背光早亮了,很有可能是下序列 mdelay 太久,改小点就没有这个问题了。根本原因屏幕初始化序列下慢了。亲身经历的。 h:lcd 唤醒闪屏问题,这个是由于每次重新 RST 下序列过程 delay 久了导致,适当减少 delay 时间即可。 i: 用厂商给的序列要么屏点不亮要么界面有水波纹,这些通常都是 rgbinterfacepolarity 导致,需要调整 pclkhsyncvsyncde 极性使之符合平台极性。 j: 结束开机 logo 至 android 动画出现之间好多屏会出现闪屏或者闪白光的情况。原因:在这个时间点 kernel 会会对屏再次初始化,我们可以软件上屏蔽第一次初始化动作从而解决。
展开>>
收起<<
2273 次阅读
|
0
个评论
更多...
小广播
一牛网是干什么的?1分钟了解一牛网
一牛网5G产品及方案:mtk5G/高通5G核心板/5GCPE/5G相关仪器
wifi6方案(IPQ807X/IPQ6000/QCA9984/MT7622/MT7621A)及整机定制
各类带AI算力开发板/定制(mtk/海思/算能/sigmastar/amlogic/rk等)
珠海海奇半导体A/B/C/D/E系列产品性能参数介绍
相关词条
QDM2311
QET4100
IPQ8078
Qualcomm
QSPR
热门资料下载
RK3368 V1.0_PCB文件.zip
必须弄懂的495个c语言问题.pdf
MT6356_PMIC_Data_Sheet_V1.3.pdf
很好的MTK-Android资料.doc
LinkIt_Assist_2502_pin_out_v1_0 .pdf
MT7623N_Datasheet_preliminary (1).pdf
MT7623A_Datasheet_preliminary (1).pdf
MediaTek_LinkIt_Assist_2502_Hardware_Reference_Design_v1_1.zip
4G IMEI 写号神器.rar
关于我们
关于我们
加入我们
新闻动态
联系我们
服务支持
官方商城
隐私声明
常见问题
论坛总则
合作/建议
TEL: 19168984579
工作时间:
周一到周五 9:00-11:30 13:30-19:30
扫一扫关注公众号
扫一扫打开小程序
Copyright © 2013-2024
一牛网
版权所有
All Rights Reserved.
帮助中心
|
隐私声明
|
联系我们
|
手机版
|
粤ICP备13053961号
|
营业执照
|
EDI证
搜索
扫一扫添加微信客服
QQ客服
返回顶部
返回顶部