高通平台GPIO引脚复用指导
1. 概述
1.1 平台有多少个GPIO?
1.2 这些GPIO都有哪些可复用的功能?
2. 软件配置
2.1 TZ侧GPIO配置
2.2 SBL侧GPIO配置
2.3 AP侧GPIO配置
2.3.1 Linux DTS机制与设备驱动模型概述
2.3.2高通平台的pinctrl控制器
2.3.2.1 SDX12 CPU pinctrl
2.3.2.2 PMD9655 pinctrl
2.3.2.3 sys文件节点来观察pinctrl
2.3.3 GPIO如何进行复用?
2.3.3.1增加一个PIN脚用于按键功能
2.3.3.2 增加一个PIN脚用于WIFI使能
2.3.3.2 增加一个PIN脚用于电池电量ADC检测
3.3.3.2.1 ADC通道配置
2.3.3.2.2 ADC功能复用
2.4 Modem侧GPIO配置
2.4.1 GPIO配置
2.4.2GPIO API接口使用
该文档以SDX12平台为例,介绍如何对高通平台的GPIO PIN脚功能进行软件配置。
1. 概述
1.1 平台有多少个GPIO?
在软件配置前需要先了解平台的GPIO引脚资源有哪些。如何获得这些信息?
以SDX12平台为例,需要获取如下几个平台文档。
平台的原理图参考设计文档
该文档可以从高通网站下载,文档编号80-12402-41,文档名称 SDX12 PMD9655 Reference Schematic。从该文档中1.3章节系统框图可以知道,参考设计中SDX12通过SPMI总线连接和控制PMD9655的工作。
从该文档的1.4.17章节我们可以知道,电源管理芯片PMD9655提供了10个GPIO PIN脚。
从该文档的1.4.4章节,我们可以了解到SDX12 CPU内部提供100个GPIO PIN脚。
显然该平台总计提供了110个GPIO PIN脚,其中SDX12提供GPIO_0 ~ GPIO_99,PMD9655提供GPIO_01~GPIO_10.
1.2 这些GPIO都有哪些可复用的功能?
在讨论GPIO可复用功能前,需要先清楚这些GPIO的电气特性是什么样的?比如该GPIO是否可以作为模拟或者数字输入输出,当GPIO作为ADC PIN脚需要能够工作在模拟输入模式,当GPIO作为时钟 PIN脚需要能够工作在数字输出模式。比如GPIO的工作电压范围 1.2V、1.8V、3.0V,这个取决于该GPIO与哪个电源网络连接。这些信息需要查看平台的以下文档:
1.data sheet文档,文档编号80-12402-1,文档名称 SDX12 Data Sheet.
截取上述文档一部分,用于说明每个GPIO PIN脚电气特性信息的来源,这个对于后面的软件配置非常重要。
2.SDX12 GPIO PIN脚定义文档文档编号 80-12402-1A,文档名称 SDX12 Pin Assignment Spreadsheet,该文档中GPIO Configuration章节详细描述了GPIO_0~GPIO_99每个PIN脚的默认功能以及其他可复用的功能。
3.电源管理芯片PMD9655 GPIO PIN脚定义.文档编号 80-P1085-1,文档名称PMD9655 Power Management Device Specification.
2. 软件配置
高通平台是一个多核非对称的SOC架构,不同的子系统运行着不同OS,对于GPIO引脚的控制各个子系统有着不同的配置方法。
2.1 TZ侧GPIO配置
高通平台对于低速外设的访问采用QUP(Qualcomm Universal Peripheral高通统一外设)配置,TrustZone(TZ)子系统管理者哪些子系统有权限访问哪些BLSP的QUP权限,换句话讲TZ管控这个各个子系统访问不同外设GPIO的权限。关于QUP的介绍的文档编号为:80-NU767-1,文档名称:BAM BLSP User Guide。
SDX12配置位置为:
trustzone_images/core/buses/qup_accesscontrol/bear/config/QUPAC_9x55_Access.xml
目前平台相关常用的外设已经加入到该配置文件,一般不需要修改,如有特殊需求可参考如下说明。该文件修改完后,需要重新编译,再烧录devcfg.mbn镜像。
该配置文件节点说明如下:
device id 是一个约定的好的节点别名,此处代表低速外设uart3
CHIP_BUS_INDEX 是一个外设ID,可以选择的外设ID定义在./bear/inc/QupACCommonIds.h
BUS_PROTOCOL 是一个协议ID,可以选择的协议ID定义在 ./bear/inc/TzBlspAC.h
IS_GPIO_PROTECTED 表示该GPIO是否被保护,只有该GPIO被TZ子系统使用的时候,才需要启用保护
GPIO_NUMBERS 当GPIO启用保护后,代表需要被保护的GPIO PIN脚
SUBSYSTEM_ID 代表可以被哪个子系统访问,定义在./bear/inc/QupACCommonIds.h,可选参数有:AC_TZ,仅有TZ可以访问;AC_RPM,仅有RPM可以访问;AC_ADSP_Q6_ELF仅ADSP可以访问AC_HLOS,仅AP可以访问;AC_NONE,所有子系统都可以访问该外设的寄存器,仅AP可以访问外设BAM
IS_PERSISTENT 设置为1代表该外设的配置不能够在运行时改变,如果需要运行时改变设置为0.
2.2 SBL侧GPIO配置
SBL作为bootloader用于引导加载AP侧镜像,在PBL之后初始化阶段运行,该阶段的GPIO初始化配置位于:
boot_images/core/systemdrivers/tlmm/config/mdm9x55/TLMMChipset.xml
该配置文件将被/core/systemdrivers/tlmm/src/DALTLMM.c 中的DALTLMMState_Init 进行解析和配置:
该xml文件定义了GPIO_0~GPIO_99 100个GPIO在SBL阶段的初始配置,简要说明一下。
GPIO方向:DALTLMM_INPUT代表配置为输入,DALTLMM_OUTPUT代表配置为输出。
GPIO内部上下拉电阻配置:DALTLMM_PULL_UP 内部上拉,DALTLMM_PULL_DOWN代表内部下拉, DALTLMM_KEEPER 保持,一般用于GOIO作为输入时候的配置。
GPIO输出:DALTLMM_OUT_HIGH输出高电平,DALTLMM_OUT_LOW输出低电平
DALTLMM_PRG_YES or DALTLMM_PRG_NO,用于在SBL启动阶段,GPIO是否配置为低功耗模式。
2.3 AP侧GPIO配置
2.3.1 Linux DTS机制与设备驱动模型概述
由于AP侧运行Linux 5.4内核,AP侧的GPIO配置需要遵循Linux 设备树DTS的规范以及Linux 设备驱动模型框架来进行相关的配置,这部分也是定制化程度较高的部分,本章节将深入展开讨论。
该章节需要对设备树DTS语法有一定的基础,该部分请参考devicetree-specification。文档也可devicetree官网下载
另外需要对Linux platform 平台设备驱动框架有深入了解,DTS定义的设备最终都是通过platform设备驱动总线模型进行匹配的,同时需要对Linux pinctl 子系统与GPIO子系统有一定的认识,高通平台提供的驱动程序也都是基于上述两个子系统扩展而来。
DTS里面定义的设备节点最终都会通过 compatible兼容性属性通过platform总线驱动模型,在内核中匹配到对应的 platform_driver,本身被转换为 platform_device。platform_device 中含有 resource 数组, 它来自 device_node 的reg, interrupts 等属性。
设备树的处理过程是: DTS ->dtb -> device_node -> platform_device
2.3.2高通平台的pinctrl控制器
如下图是高通平台的一个CPU GPIO引脚内部的数字电路结构图,该PIN脚内部的功能通过芯片内部的pinctrl控制器来进行配置:
Pinctrl控制器在软件中如何描述?需要通过设备树DTS来完成。从1.1章节我们了解到SDX12平台GPIO分别由SDX12 CPU和PMD9655两部分提供,所以在DTS里面也就定义了两个pinctrl控制器。
2.3.2.1 SDX12 CPU pinctrl
设备树源码位置:
apps_proc\vendor\qcom\proprietary\devicetree\qcom\sdxnightjar-pinctrl.dtsi
Pinctrl 控制器的设备树节点:
设备树中定义的设备最终都通过 compatible兼容性属性中定义的 "qcom,sdxnightjar-pinctrl"通过platform驱动设备总线模型找到他对应的内核驱动。
pinctrl@1000000控制器设备对应的驱动源码位于:
sdx12-ap/kernel/msm-5.4/drivers/pinctrl/qcom/pinctrl-sdxnightjar.c
2.3.2.2 PMD9655 pinctrl
设备树源码位置:
apps_proc\vendor\qcom\proprietary\devicetree\qcom\pmd9650.dtsi
Pinctrl 控制器的设备树节点:
设备树中定义的设备最终都通过 compatible兼容性属性中定义的 "qcom,pmd9650-gpio"通过platform驱动设备总线模型找到他对应的内核驱动。
pinctrl@c000控制器设备对应的驱动源码位于:
sdx12-ap/kernel/msm-5.4/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
2.3.2.3 sys文件节点来观察pinctrl
系统运行后从/sys/kernel/debug/pinctrl 这个节点也可以观察到,当前系统里面注册的两个pinctrl控制器。
上面是一个典型的DTS设备描述方式,由于pinctrl@c000的父节点是pmd9650@0,再上一层的设备节点是200f000.qcom,spmi,最终可以从DTS的根节点一路找到该设备。
2.3.3 GPIO如何进行复用?
本章节将根据项目实际开发过程遇到的定制需求,来指导如何进行GPIO复用。
2.3.3.1增加一个PIN脚用于按键功能
实际项目开发过程有客户需要从模组空闲的PIN脚中找一个作为WIFI WPS按键功能来使用,结合客户的原理图,发现PCIE_EP_RESET_N 这个PIN脚客户没有使用,通过查询平台文档《SDX12 Pin Assignment Spreadsheet》发现该PIN脚对应的是GPIO_65,查询项目的设备树文件,发现该PIN脚未被使用过。
如何增加?首先与客户沟通了解到,当前客户使用的按键驱动为Linux 内核自带的gpio_keys驱动。在apps_proc/vendor/qcom/proprietary/devicetree/qcom/sdxnightjar.dtsi找到gpio_keys节点,修改补丁如下:
在gpio-keys节点增加一个子节点wps,该节点又如下几个属性:
label = “wps” 取一个别名标识该节点
gpios = <&tlmm_pinmux 65 1>,&tlmm_pinmux符合代表在tlmm_pinmux节点的基础上追加,tlmm_pinmux就是2.3.2.1中sdx12 CPU上pinctrl@1000000的别名,65 代表是该控制器的65 PIN,1代表低电平有效,既当GPIO_65为低电平时候代表按键按下。
linux,input-type = <1>按键事件类型
linux,code = <528> 该按键在input子系统中上报的key值
debounce-interval = <15> 按键消抖时间15ms
上述DTS节点的信息为什么是这样解读的?这个完全是靠该设备对应的驱动程序进行的,通过属性compatible = "gpio-keys"可以找到该设备驱动位于./driver/input/keyboard/gpio_keys.c。设备树节点的解析通过驱动程序gpio_keys_get_devtree_pdata(struct device *dev)接口来完成,然后通过接口gpio_keys_setup_key完成GPIO方向、中断申请的配置,最终完成input 设备的注册。
由于是个按键驱动,所以GPIO PIN脚肯定是作为一个输入来使用的,并且是要通过电平中断触发来上报。但是这些并没有体现在DTS配置中,这些已经通过内核的gpio_keys驱动框架实现了。
2.3.3.2 增加一个PIN脚用于WIFI使能
实际项目开发过程有客户需要从模组空闲的PIN脚中找一个作为WIFI PWR使能功能来使用,需要在wifi驱动加载的时候设置为高电平。高通参考设计是长供电的,结合客户的原理图,发现PMD9650 GPIO_07 这个PIN脚客户没有使用。
如何添加?首先找到在设备树中查找PMD9650 pinctrl控制器上面GPIO使用的情况:
如上图所示PMD9650 pinctrl控制器上面在该项目中使用GPIO_03用于LED灯控制,GPIO_08用于蓝牙复位控制。注意两处使用的地方都是通过“&pmd9650_gpios”来使用,pmd9650_gpios是PMD9650 pinctrl控制器的别名(标号),在PMD9650 DTS节点定义时候有说明:
然后找到WIFI驱动设备树节点,如下图增加一个GPIO控制节点,wlan-pwr-en-gpio。
WIFI驱动设备树文件位置:devicetree/qcom/sdxnightjar-cnss.dtsi
驱动中如何使用该GPIO控制呢?通过兼容性属性compatible = "qcom,cnss"可以在内核驱动源码找到该驱动位于:kernel/msm-5.4/drivers/net/wireless/cnss/cnss_pci.c。
驱动中增加一个接口cnss_configure_wlan_pwr_en_gpio用于gpio设备树解析、gpio申请、gpio配置:
2.3.3.2 增加一个PIN脚用于电池电量ADC检测
3.3.3.2.1 ADC通道配置
实际项目开发过程有客户需要从模组空闲的PIN脚中找一个作为ADC检测功能使用用于电池ID检测,从1.2章节中PMD9650 spec文档中3.7.1了解到,GPIO_02,GPIO_04,GPIO_06,GPIO_10四个引脚可以作为ADC检测功能进行复用:
在进行ADC配置前,需要先了解下高通平台PMIC ADC基本的工作原理,参考文档编号 80-P0711-23,文档名称PMIC ADC Software:
高通ADC控制器是一个可编程的非常灵活的框架,可以配置不同的GPIO引脚内部与ADC控制器连接,ADC内部上拉电阻可以根据需要灵活配置为open、30K、100K、400K,ADC采样范围也可以进行1/3缩放配置应对高电压测量。
这些不同的配置,已经通过硬件channel来区分,软件的配置只需要根据(80-P1085-1)下面表格中不同的channel ID来进行读取。
表格中前两列代表,不同的配置索引,Source列代表该配置行对应的外部哪路PIN脚作为ADC测量,Scaling列代表缩放范围,Internal pull-up列代表内部上拉电阻的可配置范围。结合客户硬件原理图设计,选取PMD9650 GPIO_02 PIN脚接到电池ID上面,作为ADC功能使用,测量电池ID电压。
软件上面首先在设备树中找到PMD9650 ADC控制器,文件源码地址:
apps_proc\vendor\qcom\proprietary\devicetree\qcom\pmd9650.dtsi
从兼容性属性compatible = “qcom,spmi-adc-rev2”,我们可以从内核驱动源码中找到PMD9650 ADC控制器驱动程序位于:
kernel/msm-5.4/drivers/iio/adc/qcom-spmi-adc5.c
下面ADC控制器新增的DTS设备节点信息,都要依据qcom-spmi-adc5驱动。增加GPIO_02 ADC配置DTS节点信息:
reg寄存器值配置为ADC5_GPIO2,注意DTS中也有宏定义语法,定义在头文件qcom,spmi-vadc.h,ADC5_GPIO3值为0X13,从驱动程序中调用adc5_get_dt_channel_data接口进行进一步的解析,reg解析后最终作为硬件的channel ID,然后驱动软件通过iio总线进行ADC值获取:
总结一下上面DTS配置就是选择0X13这个配置,ADC输入来自GPIO_02引脚,无内部上拉,输出无缩放。
2.3.3.2.2 ADC功能复用
由于GPIO_02要用作ADC功能,所以需要在PMD9650 pinctrl控制器中进行PIN脚功能复用的配置。
关于PMD9650详细的GPIO DTS配置,官方的参考文档在如下位置:
apps_proc\vendor\qcom\proprietary\devicetree\bindings\pinctrl\qcom,pmic-gpio.txt.
该文档是结合pinctrl-spmi-gpio驱动来对DTS 配置参数进行说明,主要有如下几个方面:
按照高通文档说明,GPIO作为ADC时候,需要配置为高阻态。GPIO ADC pin脚定义地方:
GPIO ADC pin脚使用的地方,在oem_bms这个子节点下面,增加了adc2这个节点,用于iio驱动通过PMD9650 ADC控制器下面的ADC5_GPIO02通道读取GPIO 2PIN脚的ADC电压采样值:
oem_bms 驱动会解析“adc2”这个节点,最终把电池ID adc channel与该节点关联,最终注册到内核驱动的power_supply子系统,通过工作队列完成电池信息的ADC采样。
2.4 Modem侧GPIO配置
Modem 侧高通有一套独立的GPIO配置框架和GPIO使用指导,文档编号80-NL239-3, 文档名称Modem Subsystem GPIO Software
2.4.1 GPIO配置
以SDX12平台为例,modem侧GPIO PIN脚配置在如下xml文件:
/modem_proc/core/systemdrivers/tlmm/config/sdx12/PlatformIO_MDMX_ROUTER.xml
name 标签,代表PIN脚名称,这个依据参考文档2,后面modem侧软件获取gpio ID需要name参数。
Type 标签,“{a,b}”a代表GPIO的编号;b代表复用功能编号,这个也已经参考文档2,0代表function 0
既GPIO功能,1代表function1功能,依次类推。
2.4.2GPIO API接口使用
高通平台在modem侧通过硬件抽象层HAL屏蔽一些硬件差异,通过设备抽象层DAL提供统一的API接口用于GPIO控制。API接口定义位于:
modem_proc\core\api\systemdrivers\DDITlmm.h
DAL GPIO接口说明: