高通gpio调试

Gpio调试方法
1:高通文档说明
通过直接读取gpio相应配置寄存器的值来分析对应gpio的配置情况;
 
寄存器地址:




上面说明的是寄存器每位代表的含义,是以msm8940为例的,对于我们的msm8940可以参考msm8940的芯片手册《80-p4978-2x_a_msm8940_hardware_register_description.pdf》
第15 TLMM control and status registers这章节的说明
 
2读写方法:
Android 里有一个工具/system/bin/r  ,这个工具只有在userdebug版本中会被编译出来,源码放在android/system/core/toolbox/r.c  里面。(有兴趣的同学可以看下它的源码)
 
这个工具会依赖于/dev/mem这个节点,可以先看一下/dev/mem这个节点是否已经存在,如果不存在需要打开kernel里的配置宏:CONFIG_DEVMEM=y,如果存在的话就不用管了。
如果上面条件都具备了,就可以用/system/bin/r 这个工具来读写GPIO寄存器,来控制GPIO 了。下面说一下这个工具的具体用法。
 
以GPIO 64为例,通过上面的高通文档里可以看到寄存器配置:
Register – TLMM_GPIO_CFGn, n=[0..133]: 0x01000000 + 0x1000* (n)
GPIO64 ,TLMM_GPIO_CFG64: 0x01000000 +0x1000*0x40 = 0x01040000
(64换成16进制为0x40)
读寄存器:
adb root
adb shell
#X596:/ # system/bin/r  0x1040000
01040000: 000002c3
 
bit[1:0] is 3, that means PULL_UP
bit[5:2] is 0, that means FUNC_0 (normal GPIO)
(FUNC_SEL在80-p4978-1b_a_msm8940_gpio_configuration_spreadsheet.xlsm可以查到):
bit[8:6] is 3, that means DRV_8_MA( 8mA drive strength)
bit[9] is 1, that means output enabled(GPIO behaves as output).
 
Register – TLMM_GPIO_IN_OUTn, n=[0..133]: 0x01000004 + 0x00001000* (n)
GPIO64, TLMM_GPIO_CFG64: 0x01000004+0x1000*0x40 = 0x01040004
读寄存器:
X596:/ # system/bin/r  0x1040004
01040004: 00000003
 
写寄存器:
X596:/ # system/bin/r  0x1040004 2
01040004: 00000002
 
Bit [1] 为 0, 表示GPIO64 输出低,Bit [1] 为 1, 表示GPIO64 输出高。
 
注意:如果要设置modem中用到的GPIO, 需要把modem中的配置去掉,用/system/bin/r命令才可以配置成功,这里有个patch, 是用GPIO108 为例的:
 
到此为止就是/system/bin/r 的使用方法。
 
 
下面说一下/system/bin/r 这个工具(有兴趣的可以看一下,没兴趣的下面的就不用看了),源码在android/system/core/toolbox/r.c 里面用到节点/dev/mem。这个节点应该是在android/kernel/msm-3.18/drivers/char/mem.c 里创建的,需要打开宏 CONFIG_DEVMEM。这个文件里不只创建一个节点,还有一个/dem/kmem节点。
/dev/mem: 物理内存的全镜像。可以用来访问物理内存。
用来访问物理IO设备,比如X用来访问显卡的物理内存,或嵌入式中访问GPIO。用法一般就是open,然后mmap,接着可以使用map之后的地址来访问物理内存。这其实就是实现用户空间驱动的一种方法。
Mmap的使用方法:https://baike.baidu.com/item/mmap/1322217?fr=aladdin
/dev/kmem: kernel看到的虚拟内存的全镜像。可以用来访问kernel的内容。
一般可以用来查看kernel的变量,或者用作rootkit之类的。
/dev/mem节点的使用方法可以查看r.c 代码。
下面是一段/dev/kmem使用的一段代码:
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
 
#define DEVKMEM         "/dev/kmem"
 
#define PAGE_SIZE       0x1000
#define PAGE_MASK       (~(PAGE_SIZE-1))
 
 
int main(int argc, char* argv[])
{
    int fd;
    char *mbase;
    char read_buf[10];
    unsigned int regAddr;
    unsigned int varAddr;
 
    varAddr = strtoul(argv[1], 0, 16);
 
    unsigned int ptr = varAddr & ~(PAGE_MASK);
 
    fd = open(DEVKMEM, O_RDONLY);
    if (fd == -1) {
        perror("open");
        exit(-1);
    }
 
    mbase = mmap(0,PAGE_SIZE,PROT_READ,MAP_SHARED,fd, (varAddr & PAGE_MASK));
    if (mbase == MAP_FAILED) {
        printf("map failed %s\n",strerror(errno));
    }
 
    printf("varAddr = 0x%X \n", varAddr);
    printf("mapbase = 0x%X \n", (unsigned int)mbase);
    printf("value   = 0x%X \n",*(unsigned int*)(mbase+ptr));
    printf("char    = %c%c%c%c \n",
                    *(char *)(mbase+ptr), *(char *)(mbase+ptr+1),
                    *(char *)(mbase+ptr+2), *(char *)(mbase+ptr+3));
 
    close(fd);
    munmap(mbase,PAGE_SIZE);
 
    return 0;
}

上一篇:STM32io口基本模式


下一篇:Linux驱动 | 从0写一个设备树节点实例