上一篇我们讲解了如何编写gpio驱动,但是实际操作中,经常发现gpio引脚被占用的情况发生,那么本篇文章就详细讲解rxw平台下如何快速定位gpio复用问题以及如何解决。

一、GPIO寄存器查找

要想查看某个GPIO引脚可以配置的功能以及地址信息,需要查看TRM手册:

《Rockchip RK3568 TRM Part1》
  • 第一步:

    对于GPIO2 A2,我们转换成下面字符串然后搜索
gpio2a2_sel



这样我们就可以直接找到该引脚iomux配置寄存器,bit[10:8]。

该寄存器地址:

基地址+0x0020

那么如何找到基地址呢?

  • 第二步:

搜索该引脚寄存器的名字:

GRF_GPIO2A_IOMUX_L

注意向上搜索



可以得到该寄存器基地址名称:

SYS_GRF
  • 第三步

    直接进入chapter 3



可得SYS_GRF 基地址

0xFDC60000

那么我们就得到了GPIO2 A2的IOMUX配置寄存器地址为

0xFDC60000 + 0x0020

该寄存器的bit[10:8]用于设置该寄存器功能。

当然也可以用下图来查找,更加方便:

那么找到了这个寄存器地址,我要如何来直接读取这个寄存器的值呢?

这个可以借助于一个命令io。

二、io命令

io命令可以直接操作某个寄存器,用于查看设置某个PIO 引脚配置了什么iomux,非常方便。

1. 移植io命令需要的驱动

RK 的 Android 平台,默认有包含 io 工具(源码位置: external\io), linux 系统平台如果没有此源码, 可以将 Android 平台此源码打包过去编译即可( linux 平台代码同步最新都已带有 IO 工具,可直接使用命令)。

  • 第一步:修改Makefile、Kconfig
vim  drivers/char/Makefile

增加
+obj-$(CONFIG_DEVMEM) += mem.o
vim drivers/char/Kconfig
改文件已经包含下面信息
10 config DEVMEM
11 bool "/dev/mem virtual device support"
12 default y
13 help
14 Say Y here if you want to support the /dev/mem device.
15 The /dev/mem device is used to access areas of physical
16 memory.
17 When in doubt, say "Y".
  • 第二步:修改驱动文件

io命令需要内核驱动支持,驱动文件如下:

drivers/char/mem.c

找到下面代码:

#ifdef CONFIG_DEVMEM
[1] = { "mem", 0, &mem_fops, FMODE_UNSIGNED_OFFSET },
#endif

修改为


+//#ifdef CONFIG_DEVMEM
[1] = { "mem", 0, &mem_fops, FMODE_UNSIGNED_OFFSET },
+//#endif
  • 第三步:修改配置文件rockchip_defconfig
vim  arch/arm64/configs/rockchip_defconfig
增加
+CONFIG_DEVMEM=y

重新编译内核,烧录重启。

rockchip_defconfig需要根据平台选择

  • 第四步:查看mem字符设备:
rk3568_r:/ # ls /dev/mem -l
ls /dev/mem -l
crw------- 1 media media 1, 1 2017-08-04 09:00 /dev/mem

io命令正是通过这个字符设备来实现寄存器的读写的。

2. 命令说明

rk3568_r:/dev # io
io
Raw memory i/o utility - $Revision: 1.5 $ io -v -1|2|4 -r|w [-l <len>] [-f <file>] <addr> [<value>] -v Verbose, asks for confirmation
-1|2|4 Sets memory access size in bytes (default byte)
-l <len> Length in bytes of area to access (defaults to
one access, or whole file length)
-r|w Read from or Write to memory (default read)
-f <file> File to write on memory read, or
to read on memory write
<addr> The memory address to access
<val> The value to write (implies -w) Examples:
io 0x1000 Reads one byte from 0x1000
io 0x1000 0x12 Writes 0x12 to location 0x1000
io -2 -l 8 0x1000 Reads 8 words from 0x1000
io -r -f dmp -l 100 200 Reads 100 bytes from addr 200 to file
io -w -f img 0x10000 Writes the whole of file to memory Note access size (-1|2|4) does not apply to file based accesses.

3. 举例1,通过IO读寄存器:

读取gpio2 A2引脚配置寄存器

io -4 -l 0x30 0xFDC60000
-4 : 按字(4个字节) 访问内存
0x30 : 读取0x30(48)个字节
0xFDC60000 : 基地址

由上图可得0xFDC60020的bit[10:8]值为1

所以该io引脚被设置的iomux为

3'h1: SDMMC0_CLK

如果我们是希望通过设备树设置该引脚为普通gpio,那么该值应该为0,

那么这就说明了,我们设置失败了,

那就可以到设备树中查找设置SDMMC0的地方,将其注释掉。

要读取单个寄存器,可以用下面命令:

 io -4 -r 0xFDC60024

4. 举例2,通过IO写寄存器

比如已经通过命令: io -4 -r 0xFDC60024读出了寄存器的值,那么此时想把gpio2 A2修改为普通GPIO,

那么只需要对0xFDC60024这个寄存器的第 3 个 1 写 0,那么可以如下操作:

io -4 –w 0xFDC60024 0x01002011

注意:

  • 第三个1对应是bit[10:8]
  • 通过 io 写的寄存器值 reboot 后不会保留
  • 为什么寄存器地址后面的十六进制值的 bit [24]写 1?

    因为该寄存器的 16bit 至31 bit 是写有效位,默认为 0,即不可写。因为要往[8] bit 写 1,所以[8] bit 对应的

    写有效位 16 bit 也要对应置 1 才可写入,这个是根据寄存器描述而定的。

修改过后,再查看,可以发现对应的位的值变为了1:

三、 通过函数gpiod_direction_output()

思 路 :

驱 动 里 如 果 想 要 去 操 作 GPIO , 肯 定 会 调 用 到 gpio_direction_output 、gpio_direction_input、 gpiod_direction_output、 gpiod_direction_input 这几个接口, 他们的定义位置是:

 vim kernel/drivers/gpio/gpiolib.c

在这些接口里添加判断对应查询的 IO 口条件,通过以下函数就可以打印出哪些模块复用了该引脚:

dump_stack();

注意:

在 linux3.10 内核的 sdk 中用的是 gpio_direction_output 和gpio_direction_input 接 口 ,

在 linux4.4 内 核 中 则 是 gpiod_direction_output 和gpiod_direction_input。

下面以 linux4.4 版本为例来讲解如何查看引脚:gpio4 b3。

首先,需要计算出代表 gpio4b3 的值,算法如下:

gpio4_B3 = 4 *32 + (B-A) * 8 + 3 = 3 *32 + 1 * 8 + 3 = 139

计算方法参考:

《rk3568 | 瑞芯微平台GPIO引脚驱动编写》

  • 最前面和 32 相乘的数字因为是 gpio4,所以是 432。如果是 gpio3,那就是 332;
  • 括号里面的 A、 B、 C、 D 分别代表数值 0、 1、 2、 3,在计算时候分别对应去减即可,这里因为是 B3,所以用 B-A,如果是 C3,就是 C-A;
  • 最后的+3 是因为是 B3,如果是 GPIO4B2,那么最后就+2。

注:在 linux4.4 内核, io 引脚的值有些变化,也就是按照上文算法计算的结

果要+1000,所以 GPIO4B3 如果是 linux4.4 内核里要填 1139。

int gpiod_direction_output(struct gpio_desc *desc, int value)
{
if (!desc || !desc->chip) {
pr_warn("%s: invalid GPIO\n", __func__);
return -EINVAL;
}
+ if ( desc_to_gpio(desc) == 1139)
+ {
+ printk("dump_stack_start\n");
+ dump_stack();
+ printk("dump_stack_end\n");
+ }
if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
value = !value;
return _gpiod_direction_output_raw(desc, value);
}

添加后编译烧录,只要对应判断的引脚有被调用,启动 log 中就会打印出堆栈,可以根据找出结果查看,找到驱动调用函数。

四、通过函数rockchip_set_mux()

配置IOMUX会调用该接口,

仍然以引脚gpio4 b3为例。

[drivers/pinctrl/pinctrl-rockchip.c]

	 @@ -1224,6 +1224,17 @@ static int rockchip_set_mux(struct rockchip_pin_bank *bank, int pin, int mux)
dev_dbg(info->dev, "setting mux of GPIO%d-%d to %d\n",
bank->bank_num, pin, mux);
+ if((bank->bank_num == 4)&&(pin == 11)){
+ printk("6902 setting mux of GPIO%d-%d to %d\n",
+ bank->bank_num, pin, mux);
+ dump_stack();
+ }
if (bank->iomux[iomux_num].type & IOMUX_SOURCE_PMU)
regmap = info->regmap_pmu;
  • bank_num 表示gpio4
  • 这里“ pin ==”后面跟的值计算方式为:

    将 A0 至 D7 32 个引脚顺序对应数值 0 至 31,b3为11。

五、如何去掉设备树中的复用引脚信息?

刚才分析,发现GPIO2 A2被SDMMC0占用,那么如何来解决这个冲突呢?

只要从设备树下手即可。

瑞芯微平台的设备树,根据平台区分,往往前缀是:

rk + 平台  + 板子型号 + ddr型号 + 版本

比如rk3568系列设计的设备树文件如下:

arch/arm64/boot/dts/rockchip/rk3568-amp.dtsi
arch/arm64/boot/dts/rockchip/rk3568-android9.dtsi
arch/arm64/boot/dts/rockchip/rk3568-android.dtsi
arch/arm64/boot/dts/rockchip/rk3568-dram-default-timing.dtsi
arch/arm64/boot/dts/rockchip/rk3568.dtsi
arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10-android9.dts
arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10.dtb
arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10.dts
arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10.dtsi
arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10-linux.dts
arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10-linux-spi-nor.dts
arch/arm64/boot/dts/rockchip/rk3568-evb2-lp4x-v10-bt1120-to-hdmi.dts
arch/arm64/boot/dts/rockchip/rk3568-evb2-lp4x-v10.dts
arch/arm64/boot/dts/rockchip/rk3568-evb2-lp4x-v10.dtsi
arch/arm64/boot/dts/rockchip/rk3568-evb4-lp3-v10.dts
arch/arm64/boot/dts/rockchip/rk3568-evb5-ddr4-v10.dts
arch/arm64/boot/dts/rockchip/rk3568-evb5-ddr4-v10.dtsi
arch/arm64/boot/dts/rockchip/rk3568-evb6-ddr3-v10.dts
arch/arm64/boot/dts/rockchip/rk3568-evb6-ddr3-v10.dtsi
arch/arm64/boot/dts/rockchip/rk3568-evb6-ddr3-v10-linux.dts
arch/arm64/boot/dts/rockchip/rk3568-evb6-ddr3-v10-rk628-bt1120-to-hdmi.dts
arch/arm64/boot/dts/rockchip/rk3568-evb6-ddr3-v10-rk628-rgb2hdmi.dts
arch/arm64/boot/dts/rockchip/rk3568-evb6-ddr3-v10-rk630-bt656-to-cvbs.dts
arch/arm64/boot/dts/rockchip/rk3568-evb7-ddr4-v10.dts
arch/arm64/boot/dts/rockchip/rk3568-evb.dtsi
arch/arm64/boot/dts/rockchip/rk3568-iotest-ddr3-v10.dts
arch/arm64/boot/dts/rockchip/rk3568-iotest-ddr3-v10-linux.dts
arch/arm64/boot/dts/rockchip/rk3568-linux.dtsi
arch/arm64/boot/dts/rockchip/rk3568-nvr-demo-v10.dts
arch/arm64/boot/dts/rockchip/rk3568-nvr-demo-v10.dtsi
arch/arm64/boot/dts/rockchip/rk3568-nvr-demo-v10-linux.dts
arch/arm64/boot/dts/rockchip/rk3568-nvr-demo-v10-linux-spi-nand.dts
arch/arm64/boot/dts/rockchip/rk3568-nvr-demo-v12.dtsi
arch/arm64/boot/dts/rockchip/rk3568-nvr-demo-v12-linux.dts
arch/arm64/boot/dts/rockchip/rk3568-nvr-demo-v12-linux-spi-nand.dts
arch/arm64/boot/dts/rockchip/rk3568-nvr.dtsi
arch/arm64/boot/dts/rockchip/rk3568-nvr-linux.dtsi
arch/arm64/boot/dts/rockchip/rk3568-pinctrl.dtsi

一口君的板子是evb1,ddr4,v10版本,所以去掉其他的文件,

我们只需要关注以下文件即可。

arch/arm64/boot/dts/rockchip/rk3568-android.dtsi
与安卓相关的信息 arch/arm64/boot/dts/rockchip/rk3568.dtsi
描述cpu、memory、timer、clk、sata、usb host、gic、视频控制器、sram、cru、i2c控制器、uart、pwm、pmu等各种Soc内部硬件信息 arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10.dts
arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10.dtsi
arch/arm64/boot/dts/rockchip/rk3568-evb.dtsi
与evb1底板相关的外设硬件信息 arch/arm64/boot/dts/rockchip/rk3568-pinctrl.dtsi
pinctl相关硬件信息

还有1个描述pinctl引脚驱动能力的文件:

rockchip-pinconf.dtsi

使用grep命令来查询:

grep sdmmc0 arch/arm64/boot/dts/rockchip/rk3568* -nr

好在信息不多,逐个查看,下面这个文件,我们找到了复用的地方。

rk3568-pinctrl.dtsi

该引脚被定义为sdmmc0_clk,作为时钟被使用了。

	sdmmc0 {
………………
/omit-if-no-ref/
sdmmc0_clk: sdmmc0-clk {
rockchip,pins =
/* sdmmc0_clk */
<2 RK_PA2 1 &pcfg_pull_up_drv_level_2>;
};

修改的方法有很多种:

  1. 投机取巧法

    将sdmmc0_clk改成其他没有用的gpio

  2. 简单粗暴法

    如果确定没有使用sdmmc0,可以将所有sdmmc0地方全部注释掉

设备树支持下面这种方法:

#if 0
#endif
  1. 硬件飞线法

找硬件工程师飞线,改用其他的GPIO

  1. 最优法

    如果sdmmc0也用到了,

那就只能修改冲突的GPIO,

但是这种情况,往往会牵一发而动全身,

要改好几处,那就需要各位老铁细心慢慢修改了。

好了,本文到底结束。

一口君目标是写100篇瑞芯微平台的文章,

有喜欢瑞芯微的老铁,

欢迎大家关注学习。

rk3568 | rk平台GPIO冲突检测小技巧的更多相关文章

  1. Windows统一平台: 开发小技巧

    Windows统一平台: 开发小技巧 技巧一: 在手机端拓展你应用的显示区域.(WP8.1中也适用) 对于Windows Phone系统的手机, 手机屏幕最上方为系统状态栏(System Tray), ...

  2. IT咨询顾问:一次吐血的项目救火 java或判断优化小技巧 asp.net core Session的测试使用心得 【.NET架构】BIM软件架构02:Web管控平台后台架构 NetCore入门篇:(十一)NetCore项目读取配置文件appsettings.json 使用LINQ生成Where的SQL语句 js_jquery_创建cookie有效期问题_时区问题

    IT咨询顾问:一次吐血的项目救火   年后的一个合作公司上线了一个子业务系统,对接公司内部的单点系统.我收到该公司的技术咨询:项目启动后没有规律的突然无法登录了,重新启动后,登录一断时间后又无法重新登 ...

  3. React Native工作小技巧及填坑记录

    以下是本人在React Native开发工作中使用的一些小技巧,记录一下. 1.从网络上拉取下来的React Native缺少React和React Native库. 终端 1. cd 项目根目录 2 ...

  4. 11个强大的Visual Studio调试小技巧

    简介 调试是软件开发周期中很重要的一部分.它具有挑战性,同时也很让人疑惑和烦恼.总的来说,对于稍大一点的程序,调试是不可避免的.最近几年,调试工具的发展让很多调试任务变的越来越简单和省时. 这篇文章总 ...

  5. iOS开发中调试小技巧

    对于软件开发而言,调试是必须学会的技能,重要性不言而喻.对于调试的技能,基本上是可以迁移的,也就是说你以前在其他平台上掌握的很多调试技巧,很多也是可以用在iOS开发中.不同语言.不同IDE.不同平台的 ...

  6. SSH框架构建微信公众帐号服务器小技巧

    SSH框架构建微信公众帐号服务器小技巧 熟悉struts2和servlet的同学应该清楚,struts2的方法多样性弥补了servlet单一的doGet 和doPost方法.如果自己的公众账号服务器是 ...

  7. 11个强大的Visual Studio调试小技巧(转)

    简介 调试是软件开发周期中很重要的一部分.它具有挑战性,同时也很让人疑惑和烦恼.总的来说,对于稍大一点的程序,调试是不可避免的.最近几年,调试工具的发展让很多调试任务变的越来越简单和省时. 这篇文章总 ...

  8. React Native底|顶部导航使用小技巧

    导航一直是App开发中比较重要的一个组件,ReactNative提供了两种导航组件供我们使用,分别是:NavigatorIOS和Navigator,但是前者只能用于iOS平台,后者在ReactNati ...

  9. .Net开发小技巧

    .NET项目开发中的小技巧 1.不要频繁的创建对象...这个损失是巨大的...new太多了,后果比较严重. 2.打开数据库后要及时的关闭连接,如果你不能做到一个open后跟一个close,那也没关系, ...

  10. Java开发小技巧(三):Maven多工程依赖项目

    前言 本篇文章基于Java开发小技巧(二):自定义Maven依赖中创建的父工程project-monitor实现,运用我们自定义的依赖包进行多工程依赖项目的开发. 下面以多可执行Jar包项目的开发为例 ...

随机推荐

  1. 小白也能懂的Mysql数据库索引详解

    核心概念 主键索引/二级索引 聚簇索引/非聚簇索引 回表/索引覆盖 索引下推 联合索引/最左联合匹配 前缀索引 explain 一.[索引定义] 1.索引定义 在数据之外,数据库系统还维护着满足特定查 ...

  2. Coap 协议学习:1-有关概念

    COAP协议简介 不像人接入互联网的简单方便,由于物联网设备大多都是资源限制型的,有限的CPU.RAM.Flash.网络宽带等.对于这类设备来说,想要直接使用现有网络的TCP和HTTP来实现设备实现信 ...

  3. VulnHub_DC-4渗透流程

    VulnHub_DC-4 DC-4 is another purposely built vulnerable lab with the intent of gaining experience in ...

  4. 洛谷P1464

    搜索优化后是记忆化搜索,再优化就是dp了 #include <iostream> #include <utility> using namespace std; typedef ...

  5. 《从零开始学习Python爬虫:顶点小说全网爬取实战》

    顶点小说 装xpath helper GitHub - mic1on/xpath-helper-plus: 这是一个xpath开发者的工具,可以帮助开发者快速的定位网页元素. Question:加载完 ...

  6. oeasy教您玩转vim - 21 - 状态横条

    状态横条 回忆上节课内容 我们上次研究了标尺 标尺 开启 se ru 关闭 se noru 行号 开启 se nu 关闭 se nonu 命令位置 开启 se showcmd 关闭 se noshow ...

  7. 为什么StampedLock会导致CPU100%?

    StampedLock 是 Java 8 引入的一种高级的锁机制,它位于 java.util.concurrent.locks 包中.与传统的读写锁(ReentrantReadWriteLock)相比 ...

  8. Docker Compose 基本概要

    Docker Compose 基本概要 Compose 是一个用于定义和运行多容器 Docker 应用程序的工具.使用 YAML 文件来配置多个应用程序的服务,包括生产.暂存.开发.测试以及 CI 工 ...

  9. 顺序表之单链表(C实现)

    // Code file created by C Code Develop #include "ccd.h"#include "stdio.h"#includ ...

  10. Python Kafka客户端confluent-kafka学习总结

    实践环境 Python 3.6.2 confluent-kafka 2.2.0 confluent-kafka简介 Confluent在GitHub上开发和维护的confluent-kafka-pyt ...