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

在移植内核的时候,通常会遇到引脚复用(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_MUXENTRYAM33XX_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相关寄存器再修改它们来实现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/433511.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

是网关吗_智能家居网关功能这么多,你都知道吗?

在科技发达的今天,我们的生活也开始趋向于智能化,智能家居已经迎来了新时代。电动窗帘、扫地机器人、电视、空调等电器都能智联wifi,可是使用的时候得一个个去控制,数量多的话懒癌们肯定嫌麻烦的。所以很多聪明的人都选择安装智能…

一个数据包大小是多少k_算法交流: 6046 数据包的调度机制 【2.6基本算法之动态规划】...

【题目描述】 6046 数据包的调度机制 By OIer14wa随着 Internet的迅猛发展,多媒体技术和电子商务应用日益广泛,Internet上的服务质量(QoS,Qualityof Service)问题已越来越受到重视。网络中采用的数据包调度机制与网络的服务质量 QoS 有着密切的关系。研究表明传统的基于队列的调…

iOS vs. Android,应用设计该如何对症下药?

摘要:从iOS到Android,两大平台应用设计有何不同?又都存在什么样的问题?Android定制性太高,该如何进行UI设计?在CMDN CLUB第28期活动中,咕咚网高级产品经理王磊,从iOS、Android谈起&a…

cs8900a网卡驱动--寄存器

1. CS8900内部有一个4k的RAM用于访问其内部寄存器,称为PacketPage。 2. LineCTL 网卡状态设置 从上图看到,此寄存器的6,7位用于设置网卡的收发使能。8,9位用于设置网卡状态。是10BASE-T还是 AUI。下面这图更详细介绍了8&…

jQuery图表插件 JS Charts

JS Charts 是一款免费的基于javascript的轻量级插件,用JS Charts 绘制图表是很轻松地事,因为你只需要关心客户端的脚本。 Loading...Loading...Loading...Loading...Loading...Loading...Loading...Loading...Loading...Loading...Loading...转载于:https://www.cnb…

使用正则把数字前面的符号替换_正则表达式(一) 基本表达式

定义 正则表达式(Regular Expression)用某种模式去匹配一类字符串的公式,主要用来描述字符串匹配的工具。 匹配文本或字符存在不止一个部分满足给定的正则表达式,这是每一个这样的部分都被称为一个匹配。 匹配分为以下三种类型: 形容词性的匹…

jsp思维导图_2019年经济法基础思维导图

参加2019年初级考试的考生们明天可以打印准考证啦时间:2019.4.26-5.5日(传送门:http://kjbm8.mof.gov.cn/ksbm/usercxzkz.jsp)为了帮助大家快速梳理教材考点,下面蓝星职业教育为大家整理了初级会计职称考试各章节思维导图,希望给大…

海量数据持久层解决方案_爱数AnyBackup重磅发布海量非结构化数据超可用解决方案...

海量非结构化数据有三大备份恢复问题一直没有得到有效解决:备份慢、恢复慢、备份数据不可查询。这三大问题已经对行业数字化转型造成了重大阻碍。今天,AnyBackup Family 7线上发布会——重磅发布海量非结构化数据超可用解决方案。AnyBackup以创新超可用技…

wpf 使子ui元素可视区域不超过父元素_对游戏UI设计的一点思考

UI决定了一个游戏的初体验,甚至决定了玩家的初始留存,甚至可以说决定了一个游戏的品质,虽然看起来是表象的,却是直指游戏核心的。简单讲,玩家认可一款游戏永远都是造型场景好,剧情好,画质棒&…

grpc入门到精通_Spring Cloud 从入门到精通(一)Nacos 服务中心初探

点击上方蓝色“Java精选”,选择“设为星标”技术文章第一时间送达!什么是Nacos?Nacos是阿里巴巴开源的项目,是一个更易于帮助构建云原生应用的动态服务发现、配置管理和服务管理平台。Nacos英文全称是Dynamic Naming and Configur…

百度新年贪吃蛇效果

闲来无事&#xff0c;在网上闲逛的时候开到有人说百度蛇年的贪吃蛇logo小游戏不错&#xff0c;于是乎就自己仿照写了一个。&#xff08;注&#xff1a;所有素材都来自百度&#xff09; 效果图 用到的图片 1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional…

贝叶斯公式设b_数据分析经典模型——朴素贝叶斯

编辑导语&#xff1a;做过数据分析的人&#xff0c;想必对贝叶斯模型都不会陌生。贝叶斯预测模型是运用贝叶斯统计进行的一种预测&#xff0c;不同于一般的统计方法&#xff0c;其不仅利用模型信息和数据信息&#xff0c;而且充分利用先验信息。通过实证分析的方法&#xff0c;…

Asterisk使用数据库配置方法

安装&#xff1a; 1、安装 unixODBC unixODBC-devel libtool-ltdl libtool-ltdl-devel &#xff0c;为了使asterisk支持数据库存储&#xff08;必须先安装&#xff09; 2、安装 mysql 并设置好 C_INCLUDE_PATH 和 LD_LIBRARY_PATH 3、从 http://www.asterisk.org/downloads 下载…

linux文件系统_Linux的文件系统简介

inux操作系统的本质可以说就是文件系统的集合&#xff0c;文件系统既包含文件的数据也包含文件系统的结构。在Linux文件系统中&#xff0c;EXT2文件系统、虚拟文件系统、/proc文件系统是三个具有代表性的文件系统。/proc文件系统是一个伪文件系统&#xff0c;它只存在内存当中&…

删除按钮_汪涵拜师学艺第七篇:往来单位查询删除按钮和新增判断的设计!

老师好&#xff01;大家好&#xff01;我叫汪涵&#xff1a;今天给大家分享往来单位查询删除按钮和新增判断的设计&#xff01;在开始具体内容之前&#xff0c;请让我先分享我们的价值观&#xff1a;用自律和勤奋来改变命运&#xff0c;不走捷径&#xff0c;有爱心&#xff0c;…

Ubuntu 12.04(32位)安装Oracle 11g(32位)全过程以及几乎所有问题的解决办法

这两天在Ubuntu上安装Oracle把人折腾毁了&#xff0c;即使照着网上的教程来&#xff0c;还是出了很多问题。好在最后终于搞定了。写出来总结一下&#xff0c;免得以后忘了。 标题注明32位是因为网上教程几乎全是以64位安装为例的&#xff0c;32位系统下照着做是绝对会安装失败的…

解决asterisk sip呼叫 488 no acceptable here

这两天实验了一下asterisk static realtime方案&#xff0c;将sip.conf的信息保存到mysql数据库里。但是呼叫的时候&#xff0c;总是 报 488 no acceptable here。 这是我的sip.conf文件&#xff0c;数据库里和sip.conf文件一模一样&#xff0c;但是就是不行。 [general] c…

关于浏览器模式和文本模式的困惑

什么是浏览器模式和文本模式&#xff1f; 经常使用IE开发者工具的同学&#xff0c;肯定见过浏览器模式和文本模式&#xff0c;对于这两个名词&#xff0c;综合相关文档解释如下&#xff1a; 浏览器模式&#xff08;Browser Mode&#xff09;&#xff0c;用于切换IE针对该网页的…

mysql 关联索引_mysql中关于关联索引的问题——对a,b,c三个字段建立联合索引,那么查询时使用其中的2个作为查询条件,是否还会走索引?...

情况描述&#xff1a;在MySQL的user表中&#xff0c;对a,b,c三个字段建立联合索引&#xff0c;那么查询时使用其中的2个作为查询条件&#xff0c;是否还会走索引&#xff1f;根据查询字段的位置不同来决定&#xff0c;如查询a, a,b a,b,c a,c 都可以走索引的&#…

android学习笔记之ProgressDialog的使用

在很多PC软件或手机软件中&#xff0c;我们都会看见 “加载中...” 类似的对话框&#xff0c;当然&#xff0c;在android应用程序中也是如此。如果我们想在android应用程序中使用这样的效果&#xff0c;那么就需要用到ProgressDialog。首先&#xff0c;我们来看一下ProgressDia…