在移植内核的时候,通常会遇到引脚复用(MUX)的配置问题。在现在的Linux内核中,对于TI的ARM芯片,早已经有了比较通用的MUX配置框架。这对于许多TI的芯片都是通用的,这次看AM335X的代码顺手写一下分析,以备后用。

一、硬件
对于许多TI的芯片来说,引脚复用的配置是在Control Module(配置模块)的寄存器里配置的,(这个和三星的CPU有点不同,三星的一般在GPIO的寄存器中配置)。所以当你需要配置这些寄存器的时候,请到数据手册的Control Module的Pad Control Registers查找。
  1. TI的CPU芯片手册有两种:
  2. 一种是datasheet(DS:数据手册),较小,只是大概介绍下芯片的结构;
  3. 另一种是Technical Reference Manual(TRM:技术参考手册),较大,详细介绍芯片的各部分功能原理和寄存器定义。
  4. 在开发过程中,这两个手册都需要参考,是互补的。
对于AM335X,关于引脚复用的列表及模式号与功能的对应可以在数据手册中找到:
2 Terminal Description:
2.2 Ball Characteristics
关于引脚复用寄存器定义及各引脚相应寄存器的偏移可以在TRM中找到:
9 Control Module
9.1 Control Module
9.1.3 Functional Description
9.1.3.2 Pad Control Registers (包含引脚复用寄存器定义)
9.1.5 Registers
9.1.5.1 CONTROL_MODULE Registers (包含引脚相应寄存器的偏移)
二、软件
由于TI的芯片构架类似,对于Linux内核来说,早就已经为这个做好了一个软件上的框架,无论是在启动的初始化阶段还是在系统运行时,都可以通过这个框架提供的接口函数配置芯片的MUX。下面就来简要的分析一下。
以AM335X为例,相关代码位置:arch/arm/mach-omap2
  1. mux.h
  2. mux.c
  3. mux33xx.h
  4. mux33xx.c
  5. board-am335xevm.c
  6. (还有一些用到了:arch/arm/plat-omap/include/plat/omap_hwmod.h)
其中他们的层次关系是:
(1)重要的数据结构
  1. /**
  2. * struct mux_partition - 包含分区相关信息
  3. * @name: 当前分区名
  4. * @flags: 本分区的特定标志
  5. * @phys: 物理地址
  6. * @size: 分区大小
  7. * @base: ioremap 映射过的虚拟地址
  8. * @muxmodes: 本分区mux节点链表头
  9. * @node: 分区链表头
  10. */
  11. struct omap_mux_partition {
  12. const char        *name;
  13. u32            flags;
  14. u32            phys;
  15. u32            size;
  16. void __iomem        *base;
  17. struct list_head    muxmodes;
  18. struct list_head    node;
  19. };
这个数据结构中包含了芯片中几乎所有定义好的mux的数据,它在mux数据初始化函数omap_mux_init中初始化,并添加到全局mux_partitions链表中(通过node成员)。而其中的muxmodes是所有mux信息节点的链表头,用来链接以下数据结构:
  1. /**
  2. * struct omap_mux_entry - mux信息节点
  3. * @mux: omap_mux结构体
  4. * @node: 链表节点
  5. */
  6. struct omap_mux_entry {
  7. struct omap_mux        mux;
  8. struct list_head    node;
  9. };
而在以上数据结构中,struct omap_mux是记录单个mux节点数据的结构体:
  1. /**
  2. * struct omap_mux - omap mux 寄存器偏移和值的数据
  3. * @reg_offset:    从Control Module寄存器基地址算起的mux寄存器偏移
  4. * @gpio:    GPIO 编号
  5. * @muxnames:    引脚可用的信号模式字符串指针数组
  6. * @balls:    封装中可用的引脚
  7. */
  8. struct omap_mux {
  9. u16    reg_offset;
  10. u16    gpio;
  11. #ifdef CONFIG_OMAP_MUX
  12. char    *muxnames[OMAP_MUX_NR_MODES];
  13. #ifdef CONFIG_DEBUG_FS
  14. char    *balls[OMAP_MUX_NR_SIDES];
  15. #endif
  16. #endif
  17. };
而struct mux_partition中muxmodes链表及其节点数据的初始化都是在omap_mux_init初始化函数中(omap_mux_init_list(partition, superset);),而struct omap_mux节点数据中信息是由mux33xx.h和mux33xx.c中提供的。你可以在mux33xx.c中看到一个巨大的struct omap_mux结构体数组初始化代码,这个代码一看就明了。不同的芯片只需要根据芯片资料修改这个结构体就好了,但是am33xx的这个结构体(当前)还不完善,gpio的数据还都是0。值得一提的是其中用到了一个宏:
  1. #define _AM33XX_MUXENTRY(M0, g, m0, m1, m2, m3, m4, m5, m6, m7)        \
  2. {                                    \
  3. .reg_offset    = (AM33XX_CONTROL_PADCONF_##M0##_OFFSET),    \
  4. .gpio        = (g),                        \
  5. .muxnames    = { m0, m1, m2, m3, m4, m5, m6, m7 },        \
  6. }
这个宏使得这个结构体数组的初始化变得清晰明了。
以上的数据结构是在系统初始化的时候使用的,在struct omap_mux_partition完成初始化后,omap_mux_init初始化函数最后会根据不同的板子初始化部分mux寄存器(omap_mux_init_signals(partition, board_mux);),其中牵涉到了以下结构体:
  1. /**
  2. * struct omap_board_mux - 初始化mux寄存器的数据
  3. * @reg_offset:    从Control Module寄存器基地址算起的mux寄存器偏移
  4. * @mux_value:    希望设置的mux寄存器值
  5. */
  6. struct omap_board_mux {
  7. u16    reg_offset;
  8. u16    value;
  9. };
在最上层的板级初始化文件(board-am335xevm.c)中会定义一个这样的结构体数组,确定所要初始化的引脚复用寄存器,交由omap_mux_init_signals(partition, board_mux);使用。例如:
  1. #ifdef CONFIG_OMAP_MUX
  2. static struct omap_board_mux board_mux[] __initdata = {
  3. AM33XX_MUX(I2C0_SDA, OMAP_MUX_MODE0 | AM33XX_SLEWCTRL_SLOW |
  4. AM33XX_INPUT_EN | AM33XX_PIN_OUTPUT),
  5. AM33XX_MUX(I2C0_SCL, OMAP_MUX_MODE0 | AM33XX_SLEWCTRL_SLOW |
  6. AM33XX_INPUT_EN | AM33XX_PIN_OUTPUT),
  7. { .reg_offset = OMAP_MUX_TERMINATOR },
  8. };
  9. #else
  10. #define    board_mux    NULL
  11. #endif
其中用到了一个宏:
  1. /* 如果引脚没有定义为输入,拉动电阻将会被禁用
  2. * 如果定义为输入,所提供的标志位将确定拉动电阻的配置
  3. */
  4. #define AM33XX_MUX(mode0, mux_value)                    \
  5. {                                    \
  6. .reg_offset    = (AM33XX_CONTROL_PADCONF_##mode0##_OFFSET),    \
  7. .value        = (((mux_value) & AM33XX_INPUT_EN) ? (mux_value)\
  8. : ((mux_value) | AM33XX_PULL_DISA)),    \
  9. }
注意_AM33XX_MUXENTRY和AM33XX_MUX这两个宏,前者是用于struct omap_mux的;后者是用于struct omap_board_mux的。
(2)重要的接口函数
  1. /**
  2. * omap_mux_init - MUX初始化的私有函数,请勿使用
  3. * 由各板级特定的MUX初始化函数调用
  4. */
  5. int omap_mux_init(const char *name, u32 flags,
  6. u32 mux_pbase, u32 mux_size,
  7. struct omap_mux *superset,
  8. struct omap_mux *package_subset,
  9. struct omap_board_mux *board_mux,
  10. struct omap_ball *package_balls);
这个函数是内部用于初始化struct mux_partition的最总要的函数,但是这个函数并不作为接口函数使用,而是供各芯片初始化函数“*_mux_init”所使用的。比如AM33XX芯片:
  1. /**
  2. * am33xx_mux_init() - 用板级特定的设置来初始化MUX系统
  3. * @board_mux:        板级特定的MUX配置表
  4. */
  5. int __init am33xx_mux_init(struct omap_board_mux *board_subset)
  6. {
  7. return omap_mux_init("core", 0, AM33XX_CONTROL_PADCONF_MUX_PBASE,
  8. AM33XX_CONTROL_PADCONF_MUX_SIZE, am33xx_muxmodes,
  9. NULL, board_subset, NULL);
  10. }
有了已经初始化好的struct mux_partition结构体,我们可以利用mux.h提供的许多函数方便的初始化各mux寄存器:
  1. /**
  2. * omap_mux_init_signal - 根据信号名字符串初始化一个引脚的mux
  3. * @muxname:        mode0_name.signal_name的格式的Mux名称
  4. * @val:        mux寄存器值
  5. */
  6. int omap_mux_init_signal(const char *muxname, int val);
  7. /**
  8. * omap_mux_get() - 通过名字返回一个mux分区
  9. * @name:        mux分区名
  10. *
  11. */
  12. struct omap_mux_partition *omap_mux_get(const char *name);
  13. /**
  14. * omap_mux_read() - 读取mux寄存器(通过分区结构体指针和寄存器偏移值)
  15. * @partition:        Mux分区
  16. * @mux_offset:        mux寄存器偏移
  17. *
  18. */
  19. u16 omap_mux_read(struct omap_mux_partition *p, u16 mux_offset);
  20. /**
  21. * omap_mux_write() - 写mux寄存器(通过分区结构体指针和寄存器偏移值)
  22. * @partition:        Mux分区
  23. * @val:        新的mux寄存器值
  24. * @mux_offset:        mux寄存器偏移
  25. *
  26. * 这个函数仅有在非GPIO信号的动态复用需要
  27. */
  28. void omap_mux_write(struct omap_mux_partition *p, u16 val, u16 mux_offset);
  29. /**
  30. * omap_mux_write_array() - 写mux寄存器阵列
  31. * @partition:        Mux分区
  32. * @board_mux:        mux寄存器阵列 (用MAP_MUX_TERMINATOR结尾)
  33. *
  34. * 这个函数仅有在非GPIO信号的动态复用需要
  35. */
  36. void omap_mux_write_array(struct omap_mux_partition *p,
  37. struct omap_board_mux *board_mux);
在代码比较完备的芯片中,struct omap_mux中的gpio成员有被初始化过,这样就可以使用以下接口函数:
  1. /**
  2. * omap_mux_init_gpio - 根据GPIO编号初始化一个信号引脚
  3. * @gpio:        GPIO编号
  4. * @val:        mux寄存器值
  5. */
  6. int omap_mux_init_gpio(int gpio, int val);
  7. /**
  8. * omap_mux_get_gpio() - 根据GPIO编号获取一个mux寄存器值
  9. * @gpio:        GPIO编号
  10. *
  11. */
  12. u16 omap_mux_get_gpio(int gpio);
  13. /**
  14. * omap_mux_set_gpio() - 根据GPIO编号设定一个mux寄存器值
  15. * @val:        新的mux寄存器值
  16. * @gpio:        GPIO编号
  17. *
  18. */
  19. void omap_mux_set_gpio(u16 val, int gpio);
但是am33xx的gpio成员(当前)还都是0,所有这些函数没法使用。
此外,在mux.h中还导出了其他的软件接口和数据结构,这些在am33xx中没有使用,有需要的时候再看。
在板级初始化代码(比如board-am335xevm.c)运行完芯片特定的MUX初始化函数(am33xx_mux_init(board_mux);)之后,也可以在各子系统初始化时通过上面的接口函数修改配置MUX,比如在am33xx中使用了自己封装的一个函数和结构体:
  1. /* 模块引脚复用结构体 */
  2. struct pinmux_config {
  3. const char *string_name; /* 信号名格式化字符串,“模式0字符串.目标模式字符串“ */
  4. int val; /* 其他mux寄存器可选配置值 */
  5. };
  6. /*
  7. * @pin_mux - 单个模块引脚复用结构体
  8. *            其中定义了本模块所有引脚复用细节.
  9. */
  10. static void setup_pin_mux(struct pinmux_config *pin_mux)
  11. {
  12. int i;
  13. for (i = 0; pin_mux->string_name != NULL; pin_mux++)
  14. omap_mux_init_signal(pin_mux->string_name, pin_mux->val);
  15. }
你可以在board-am335xevm.c中看到如下的代码:
  1. static struct pinmux_config d_can_ia_pin_mux[] = {
  2. {"uart0_rxd.d_can0_tx", OMAP_MUX_MODE2 | AM33XX_PULL_ENBL},
  3. {"uart0_txd.d_can0_rx", OMAP_MUX_MODE2 | AM33XX_PIN_INPUT_PULLUP},
  4. {NULL, 0},
  5. };
  6. ......
  7. static void d_can_init(int evm_id, int profile)
  8. {
  9. switch (evm_id) {
  10. case IND_AUT_MTR_EVM:
  11. if ((profile == PROFILE_0) || (profile == PROFILE_1)) {
  12.   setup_pin_mux(d_can_ia_pin_mux);
  13. /* Instance Zero */
  14. am33xx_d_can_init(0);
  15. }
  16. break;
  17. case GEN_PURP_EVM:
  18. if (profile == PROFILE_1) {
  19. setup_pin_mux(d_can_gp_pin_mux);
  20. /* Instance One */
  21. am33xx_d_can_init(1);
  22. }
  23. break;
  24. default:
  25. break;
  26. }
  27. }
三、使用注意
 上面初始化过的结构体和接口函数的定义都是带有"__init"和“__initdata”的,所以这些都只能在内核初始化代码中使用,一旦系统初始化结束并进入了文件系统,这些定义都会被free。所有它们不能在内核模块(.ok)中被调用,否则你就等着Oops吧。因为一个芯片的引脚复用一般是硬件设计的时候定死的,一般不可能在启动后更改。如果你是在要在模块中改变引脚复用配置,你只能通过自己ioremap相关寄存器再修改它们来实现。

Linux下TI omap芯片 MUX 配置分析(以AM335X芯片为例)相关推荐

  1. 安卓 体验linux mux,Linux下TI omap芯片 MUX 配置分析(以AM335X芯片为例)

    对于许多TI的芯片来说,引脚复用的配置是在Control Module(配置模块)的寄存器里配置的,(这个和三星的CPU有点不同,三星的一般在GPIO的寄存器中配置).所以当你需要配置这些寄存器的时候 ...

  2. LibOpenCM3(一) Linux下命令行开发环境配置

    目录 LibOpenCM3(一) Linux下命令行开发环境配置 LibOpenCM3(二) 项目模板 Makefile分析 LibOpenCM3(三) .ld文件(连接器脚本)和startup代码说 ...

  3. Linux下mysql支持中文,linux下mysql环境支持中文配置步骤

    sql脚本执行前加上: CREATE DATABASE IF NOT EXISTS mydatabase DEFAULT CHARSET utf8 COLLATE UTF8_GENERAL_CI; u ...

  4. Linux下samba的安装与配置

    physique 博客园 首页 新随笔 联系 管理 订阅 随笔- 203  文章- 0  评论- 33 Linux下samba的安装与配置 转载来源:http://blog.chinaunix.net ...

  5. Linux下USB suspend/resume源码分析【转】

    转自:http://blog.csdn.net/aaronychen/article/details/3928479 Linux下USB suspend/resume源码分析 Author:aaron ...

  6. Linux下Nagios的安装与配置

    Linux下Nagios的安装与配置 2017-03-23 17:40:20     来源:    点击:0 Nagios是企业普遍使用的最具影响力的网络信息监视系统之一,它可以动态监视指定的网络状态 ...

  7. Linux下MySQL数据库主从同步配置

    操作系统:CentOS 6.x 64位 MySQL数据库版本:mysql-5.5.35 MySQL主服务器:192.168.21.128 MySQL从服务器:192.168.21.129 准备篇: 说 ...

  8. WINDOWS与LINUX下的DNS轮询配置

    11月12日我参加了51CTO的技术沙龙"Exchange Server系统升级与迁移",两位老师的分享都比较精彩,也让我学到了一些EXCHANGE在升级和迁移方面的知识和经验.记 ...

  9. linux下jdk的安装与配置jdk-6u45-linux-i586.bin

    linux下jdk的安装与配置 一.安装JDK从sun网站上直接下载JDK:http://download.oracle.com/otn-pub/java/jdk/6u45-b06/jdk-6u45- ...

最新文章

  1. 《简明电路分析》——1.6节简单电路分析实例
  2. SAP各种产品中的客户主数据模型建模详解
  3. Mysql数据库多实例配置
  4. oracle中长字符串长度吗,Oracle 字符串长度函数
  5. 03-17 APP自动遍历测试技术
  6. 电脑账户与用户账户编码规则
  7. awt中监听输入框textField
  8. Andrew Ng机器学习课程17(1)
  9. AppStore图片尺寸以及内容要求Screenshot specifications
  10. 复制移动VMware Workstation虚拟机文件产生的问题【转】
  11. matlab 数据拟合相关
  12. Android iTOP-4412全能版 CAN通信集成(完整篇)
  13. 软件测试面试题(面试前准备篇)
  14. 维基百科放弃php,部署维基百科后页面出现的错误
  15. Linux系统 应急响应自动化检测工具 GScan ——使用教程
  16. 全面了解IDC数据中心
  17. 使用命令行生成文件目录树
  18. 巴拿赫空间的基本概念
  19. 老哥教你如何将springboot打包成exe程序
  20. MTK BROM 作用

热门文章

  1. Centos7 Greenplum6.1开源版本集群部署
  2. linux查看命令类型,查看linux命令类型
  3. 天猫整站SSM-分页-limit(做个人学习笔记整理用)
  4. 艾创机器人_世界教育机器人大赛 2019赛季世界锦标赛落幕曲靖代表队获多个奖项...
  5. 掘金浏览器插件安装图文教程
  6. 移植U-BOOT之支持烧写YAFFS文件系统以及制作U-BOOT补丁
  7. SpringBoot 使用教程
  8. 谈一下我对如何设计微服务接口的理解和思考
  9. ABAP:从例子学习ABAP
  10. $(document).ready()和window.onload之间的差异