/*********************************************************************************************
* TI AM335x Linux MUX hacking
* 声明:
* 1. 本文主要是对TI的AM335x Linux驱动中的引脚复用配置代码进行跟踪;
* 2. 参考书籍:AM335x ARM® Cortex™-A8 Microprocessors (MPUs) Technical Reference Manual
*
* 2015-6-25 阵雨 深圳 南山平山村 曾剑锋
*********************************************************************************************/ \\\\\\\\\\\\\-*- 目录 -*-/////////////
| 一、跟踪板级文件:
| 二、跟踪am335x_evm_init()函数:
| 三、跟踪board_mux参数:
| 四、跟踪am33xx_mux_init()函数:
| 五、跟踪am33xx_muxmodes参数:
| 六、跟踪omap_mux_init()函数:
| 七、跟踪omap_mux_init_list()函数:
| 八、跟踪omap_mux_init_signals函数:
\\\\\\\\\\\\\\\\\\\\////////////////// 一、跟踪板级文件:
......
MACHINE_START(AM335XEVM, "am335xevm")
/* Maintainer: Texas Instruments */
.atag_offset = 0x100,
.map_io = am335x_evm_map_io,
.init_early = am33xx_init_early,
.init_irq = ti81xx_init_irq,
.handle_irq = omap3_intc_handle_irq,
.timer = &omap3_am33xx_timer,
.init_machine = am335x_evm_init, // 跟踪该函数
MACHINE_END ^
|
MACHINE_START(AM335XIAEVM, "am335xiaevm") |
/* Maintainer: Texas Instruments */ |
.atag_offset = 0x100, |
.map_io = am335x_evm_map_io, |
.init_irq = ti81xx_init_irq, |
.init_early = am33xx_init_early, |
.timer = &omap3_am33xx_timer, |
.init_machine = am335x_evm_init, -------------+
MACHINE_END 二、跟踪am335x_evm_init()函数:
static void __init am335x_evm_init(void)
{
am33xx_cpuidle_init();
am33xx_mux_init(board_mux); // 跟踪函数、参数
omap_serial_init();
am335x_evm_i2c_init();
omap_sdrc_init(NULL, NULL);
usb_musb_init(&musb_board_data);
omap_board_config = am335x_evm_config;
omap_board_config_size = ARRAY_SIZE(am335x_evm_config);
/* Create an alias for icss clock */
if (clk_add_alias("pruss", NULL, "pruss_uart_gclk", NULL))
pr_warn("failed to create an alias: icss_uart_gclk --> pruss\n");
/* Create an alias for gfx/sgx clock */
if (clk_add_alias("sgx_ck", NULL, "gfx_fclk", NULL))
pr_warn("failed to create an alias: gfx_fclk --> sgx_ck\n");
} 三、跟踪board_mux参数:
. 跟踪board_mux[]数组:
static struct omap_board_mux board_mux[] __initdata = {
/*
* Setting SYSBOOT[5] should set xdma_event_intr0 pin to mode 3 thereby
* allowing clkout1 to be available on xdma_event_intr0.
* However, on some boards (like EVM-SK), SYSBOOT[5] isn't properly
* latched.
* To be extra cautious, setup the pin-mux manually.
* If any modules/usecase requries it in different mode, then subsequent
* module init call will change the mux accordingly.
*
* 参考书籍:AM335x ARM® Cortex™-A8 Microprocessors (MPUs) Technical Reference Manual -- 760页
* --------------------------------------------------------------------
* | Offset | Acronym | Register | Description Section |
* --------------------------------------------------------------------
* | 9B0h | conf_xdma_event_intr0 | | Section 9.3.51 |
* --------------------------------------------------------------------
* 观察上面的内容和接下来要配置引脚,我们只需要将Acronym中的conf_前缀去掉,
* 然后将剩下的字符串大写,就能配置对应的引脚了,如:
* 1. conf_xdma_event_intr0
* 2. xdma_event_intr0
* 3. XDMA_EVENT_INTR0
* |
* |
*/ V
AM33XX_MUX(XDMA_EVENT_INTR0, OMAP_MUX_MODE3 | AM33XX_PIN_OUTPUT), // 跟踪宏
AM33XX_MUX(I2C0_SDA, OMAP_MUX_MODE0 | AM33XX_SLEWCTRL_SLOW |
AM33XX_INPUT_EN | AM33XX_PIN_OUTPUT),
AM33XX_MUX(I2C0_SCL, OMAP_MUX_MODE0 | AM33XX_SLEWCTRL_SLOW |
AM33XX_INPUT_EN | AM33XX_PIN_OUTPUT),
{ .reg_offset = OMAP_MUX_TERMINATOR }, //后面的程序通过判断这个表示来结束注册
};
. 跟踪struct omap_board_mux结构体:
/**
* struct omap_board_mux - data for initializing mux registers
* @reg_offset: mux register offset from the mux base
* @mux_value: desired mux value to set
*/
struct omap_board_mux {
u16 reg_offset;
u16 value;
};
. 跟踪AM33XX_MUX()宏:
/* If pin is not defined as input, pull would get disabled.
* If defined as input, flags supplied will determine pull on/off.
*/
// 以此为例:
// AM33XX_MUX(XDMA_EVENT_INTR0, OMAP_MUX_MODE3 | AM33XX_PIN_OUTPUT)
//
// .reg_offset = (AM33XX_CONTROL_PADCONF_XDMA_EVENT_INTR0_OFFSET) // 跟踪宏
// .value = (((OMAP_MUX_MODE3 | AM33XX_PIN_OUTPUT) & AM33XX_INPUT_EN) \
// ? (OMAP_MUX_MODE3 | AM33XX_PIN_OUTPUT) \
// : ((mux_value) | AM33XX_PULL_DISA))
#define AM33XX_MUX(mode0, mux_value) \
{ \
.reg_offset = (AM33XX_CONTROL_PADCONF_##mode0##_OFFSET), \
.value = (((mux_value) & AM33XX_INPUT_EN) ? (mux_value)\
: ((mux_value) | AM33XX_PULL_DISA)), \
}
. 跟踪模式宏声明:
/* 34xx mux mode options for each pin. See TRM for options */
#define OMAP_MUX_MODE0 0
#define OMAP_MUX_MODE1 1
#define OMAP_MUX_MODE2 2
#define OMAP_MUX_MODE3 3
#define OMAP_MUX_MODE4 4
#define OMAP_MUX_MODE5 5
#define OMAP_MUX_MODE6 6
#define OMAP_MUX_MODE7 7
. 跟踪输出宏声明:
/* Definition of output pin could have pull disabled, but
* this has not been done due to two reasons
* 1. AM33XX_MUX will take care of it
* 2. If pull was disabled for out macro, combining out & in pull on macros
* would disable pull resistor and AM33XX_MUX cannot take care of the
* correct pull setting and unintentionally pull would get disabled
*/
#define AM33XX_PIN_OUTPUT (0)
. 跟踪引脚配置偏移宏,并对比数据手册:
// 参考书籍:AM335x ARM® Cortex™-A8 Microprocessors (MPUs) Technical Reference Manual -- 760页
// -----------------------------------------------------------------------
// | Offset | Acronym | Register | Description Section |
// +--------+-----------------------+------------+-----------------------+
// | 9B0h | conf_xdma_event_intr0 | | Section 9.3.51 |
// -----------------------------------------------------------------------
#define AM33XX_CONTROL_PADCONF_XDMA_EVENT_INTR0_OFFSET 0x09B0 四、跟踪am33xx_mux_init()函数:
. 跟踪am33xx_mux_init()函数:
int __init am33xx_mux_init(struct omap_board_mux *board_subset)
{
return omap_mux_init("core", , AM33XX_CONTROL_PADCONF_MUX_PBASE, // 跟踪参数
AM33XX_CONTROL_PADCONF_MUX_SIZE, am33xx_muxmodes,
NULL, board_subset, NULL);
}
. 跟踪AM33XX_CONTROL_PADCONF_MUX_PBASE宏:
// 参考书籍:AM335x ARM® Cortex™-A8 Microprocessors (MPUs) Technical Reference Manual -- 158页
// ----------------------------------------------------------------------------------------------------
// | Region Name | Start Address (hex) | End Address (hex) | Size | Description |
// +-----------------+---------------------+--------------------+--------+----------------------------+
// | Control Module | 0x44E1_0000 | 0x44E1_1FFF | 128KB | Control Module Registers |
// ----------------------------------------------------------------------------------------------------
#define AM33XX_CONTROL_PADCONF_MUX_PBASE 0x44E10000LU
. 跟踪AM33XX_CONTROL_PADCONF_MUX_SIZE宏:
// 参考书籍:AM335x ARM® Cortex™-A8 Microprocessors (MPUs) Technical Reference Manual -- 761页
// 这里的大小没有搞懂,在datasheet中是1444h,而这里是B34h,没搞懂
// ----------------------------------------------------------------
// | Offset | Acronym | Register | Description Section |
// +--------+-------------------+----------+----------------------+
// | 1444h | ddr_data1_ioctrl | | Section 9.3.92 |
// ----------------------------------------------------------------
#define AM33XX_CONTROL_PADCONF_VREFN_OFFSET 0x0B34
#define AM33XX_CONTROL_PADCONF_MUX_SIZE \
(AM33XX_CONTROL_PADCONF_VREFN_OFFSET + 0x4) 五、跟踪am33xx_muxmodes参数:
. 跟踪am33xx_muxmodes[]数组:
/* AM33XX pin mux super set */
static struct omap_mux am33xx_muxmodes[] = {
_AM33XX_MUXENTRY(GPMC_AD0, ,
"gpmc_ad0", "mmc1_dat0", NULL, NULL,
NULL, NULL, NULL, "gpio1_0"),
_AM33XX_MUXENTRY(GPMC_AD1, ,
"gpmc_ad1", "mmc1_dat1", NULL, NULL,
NULL, NULL, NULL, "gpio1_1"),
_AM33XX_MUXENTRY(GPMC_AD2, ,
"gpmc_ad2", "mmc1_dat2", NULL, NULL,
NULL, NULL, NULL, "gpio1_2"),
_AM33XX_MUXENTRY(GPMC_AD3, ,
"gpmc_ad3", "mmc1_dat3", NULL, NULL,
NULL, NULL, NULL, "gpio1_3"),
_AM33XX_MUXENTRY(GPMC_AD4, ,
"gpmc_ad4", "mmc1_dat4", NULL, NULL,
NULL, NULL, NULL, "gpio1_4"),
......
{ .reg_offset = OMAP_MUX_TERMINATOR }, //后面的程序通过判断这个表示来结束注册
}
. 跟踪struct omap_mux结构体:
/**
* struct omap_mux - data for omap mux register offset and it's value
* @reg_offset: mux register offset from the mux base
* @gpio: GPIO number
* @muxnames: available signal modes for a ball
* @balls: available balls on the package
* @partition: mux partition
*/
struct omap_mux {
u16 reg_offset;
u16 gpio;
#ifdef CONFIG_OMAP_MUX
char *muxnames[OMAP_MUX_NR_MODES];
#ifdef CONFIG_DEBUG_FS
char *balls[OMAP_MUX_NR_SIDES];
#endif
#endif
};
. 跟踪_AM33XX_MUXENTRY宏:
//
// 以此为例:
// _AM33XX_MUXENTRY(GPMC_AD0, 0, "gpmc_ad0", "mmc1_dat0", NULL, NULL, NULL, NULL, NULL, "gpio1_0")
//
// .reg_offset = AM33XX_CONTROL_PADCONF_GPMC_AD0_OFFSET
// .gpio = 0 // 相当于取下面muxnames中的第0个
// .muxnames = {"gpmc_ad0", "mmc1_dat0", NULL, NULL, NULL, NULL, NULL, "gpio1_0"}
#define _AM33XX_MUXENTRY(M0, g, m0, m1, m2, m3, m4, m5, m6, m7) \
{ \
.reg_offset = (AM33XX_CONTROL_PADCONF_##M0##_OFFSET), \
.gpio = (g), \
.muxnames = { m0, m1, m2, m3, m4, m5, m6, m7 }, \
}
. 跟踪AM33XX_CONTROL_PADCONF_GPMC_AD0_OFFSET宏,并对比datasheet:
// 参考书籍:AM335x ARM® Cortex™-A8 Microprocessors (MPUs) Technical Reference Manual -- 758页
// ------------------------------------------------------------------------------------------------------------
// | Offset | Acronym | Register | Description Section
// +--------+----------------+-----------+---------------------------------------------------------------------
// | 800h | conf_gpmc_ad0 | | See the device datasheet for information on default pin Section 9.3.51
// ------------------------------------------------------------------------------------------------------------
#define AM33XX_CONTROL_PADCONF_GPMC_AD0_OFFSET 0x0800 六、跟踪omap_mux_init()函数:
int __init omap_mux_init(const char *name, u32 flags,
u32 mux_pbase, u32 mux_size,
struct omap_mux *superset,
struct omap_mux *package_subset,
struct omap_board_mux *board_mux,
struct omap_ball *package_balls)
{
struct omap_mux_partition *partition; partition = kzalloc(sizeof(struct omap_mux_partition), GFP_KERNEL);
if (!partition)
return -ENOMEM; partition->name = name; // 分区的意思相当于模块的意思
partition->flags = flags;
partition->size = mux_size;
partition->phys = mux_pbase;
partition->base = ioremap(mux_pbase, mux_size); // 重新映射IO地址
if (!partition->base) {
pr_err("%s: Could not ioremap mux partition at 0x%08x\n",
__func__, partition->phys);
kfree(partition);
return -ENODEV;
} INIT_LIST_HEAD(&partition->muxmodes); // 初始化分区头结点链表 list_add_tail(&partition->node, &mux_partitions); // 将分区加入分区链表
mux_partitions_cnt++; // 分区总数统计
pr_info("%s: Add partition: #%d: %s, flags: %x\n", __func__,
mux_partitions_cnt, partition->name, partition->flags); omap_mux_init_package(superset, package_subset, package_balls); // 两个都是null
omap_mux_init_list(partition, superset); // 跟踪函数
omap_mux_init_signals(partition, board_mux); // 跟踪函数 return ;
} 七、跟踪omap_mux_init_list()函数:
. 跟踪omap_mux_init_list()函数:
/*
* Note if CONFIG_OMAP_MUX is not selected, we will only initialize
* the GPIO to mux offset mapping that is needed for dynamic muxing
* of GPIO pins for off-idle.
*/
static void __init omap_mux_init_list(struct omap_mux_partition *partition,
struct omap_mux *superset)
{
while (superset->reg_offset != OMAP_MUX_TERMINATOR) {
struct omap_mux *entry; // 去掉一些不符合要求的的配置引脚
#ifdef CONFIG_OMAP_MUX
if (!superset->muxnames || !superset->muxnames[]) {
superset++;
continue;
}
#else
/* Skip pins that are not muxed as GPIO by bootloader */
if (!OMAP_MODE_GPIO(omap_mux_read(partition,
superset->reg_offset))) {
superset++;
continue;
}
#endif entry = omap_mux_list_add(partition, superset);
if (!entry) {
pr_err("%s: Could not add entry\n", __func__);
return;
}
superset++;
}
}
. 跟踪omap_mux_list_add()函数:
static struct omap_mux * __init omap_mux_list_add(
struct omap_mux_partition *partition,
struct omap_mux *src)
{
struct omap_mux_entry *entry;
struct omap_mux *m; entry = kzalloc(sizeof(struct omap_mux_entry), GFP_KERNEL);
if (!entry)
return NULL; m = &entry->mux;
entry->mux = *src; #ifdef CONFIG_OMAP_MUX
if (omap_mux_copy_names(src, m)) { // 将数据另存的感觉
kfree(entry);
return NULL;
}
#endif mutex_lock(&muxmode_mutex);
list_add_tail(&entry->node, &partition->muxmodes); // 将节点放入分区节点链表中
mutex_unlock(&muxmode_mutex); return m;
}
. 跟踪omap_mux_copy_names()函数:
// 这个函数的大概意思也就是转存的感觉
static int __init omap_mux_copy_names(struct omap_mux *src,
struct omap_mux *dst)
{
int i; for (i = ; i < OMAP_MUX_NR_MODES; i++) {
if (src->muxnames[i]) {
dst->muxnames[i] = kstrdup(src->muxnames[i],
GFP_KERNEL);
if (!dst->muxnames[i])
goto free;
}
} #ifdef CONFIG_DEBUG_FS
for (i = ; i < OMAP_MUX_NR_SIDES; i++) {
if (src->balls[i]) {
dst->balls[i] = kstrdup(src->balls[i], GFP_KERNEL);
if (!dst->balls[i])
goto free;
}
}
#endif return ; free:
omap_mux_free_names(dst);
return -ENOMEM; } 八、跟踪omap_mux_init_signals函数:
. 跟踪omap_mux_init_signals()函数:
static void omap_mux_init_signals(struct omap_mux_partition *partition,
struct omap_board_mux *board_mux)
{
omap_mux_set_cmdline_signals(); // 不知道这里是干啥的,不跟踪
omap_mux_write_array(partition, board_mux); // 跟踪该函数
}
. 跟踪omap_mux_write_array()函数:
void omap_mux_write_array(struct omap_mux_partition *partition,
struct omap_board_mux *board_mux)
{
if (!board_mux)
return; while (board_mux->reg_offset != OMAP_MUX_TERMINATOR) {
omap_mux_write(partition, board_mux->value, // 跟踪函数
board_mux->reg_offset);
board_mux++;
}
}
. 跟踪am33xx_mux_init()函数:
/*
* int __init am33xx_mux_init(struct omap_board_mux *board_subset)
* {
* return omap_mux_init("core", 0 /* flag = 0 */, AM33XX_CONTROL_PADCONF_MUX_PBASE,
* AM33XX_CONTROL_PADCONF_MUX_SIZE, am33xx_muxmodes,
* NULL, board_subset, NULL);
* }
*/
void omap_mux_write(struct omap_mux_partition *partition, u16 val,
u16 reg)
{
if (partition->flags & OMAP_MUX_REG_8BIT)
__raw_writeb(val, partition->base + reg);
else
__raw_writew(val, partition->base + reg);
}
. 跟踪OMAP_MUX_REG_8BIT宏:
/*
* omap_mux_init flags definition:
*
* OMAP_MUX_REG_8BIT: Ensure that access to padconf is done in 8 bits.
* The default value is 16 bits.
* OMAP_MUX_GPIO_IN_MODE3: The GPIO is selected in mode3.
* The default is mode4.
*/
#define OMAP_MUX_REG_8BIT (1 << 0)

TI AM335x Linux MUX hacking的更多相关文章

  1. ti processor sdk linux am335x evm Makefile hacking

    # # ti processor sdk linux am335x evm Makefile hacking # 说明: # 本文主要对TI的sdk中的Makefile脚本进行解读,是为了了解其工作机 ...

  2. TI AM335X处理器介绍

    AM335X是美国TI(德州仪器)公司基于 ARM Cortex-A8内核的AM335X微处理器,在图像.图形处理.外设方面进行了增强,并全面支持诸如 EtherCAT 和 PROFIBUS等工业接口 ...

  3. am335x Linux kernel DTS pinmux 定义记录

    记录am335x TI PDK3.0 Linux Kernel 设备的pinmux 的配置 在TI 的Linux kernel 设备树里面,有很多关于pinctrl-single,pins 的配置, ...

  4. TI AM335x ARM Cortex-A8工业级核心板,工业网关、工业HMI等用户首选

    创龙科技近期推出了ti AM335x ARM Cortex-A8工业级核心板,它拥有高性能.低功耗.低成本.接口丰富等优势,成为了工业网关.工业HMI等用户的首要选择.另外,核心板采用邮票孔连接方式, ...

  5. OK335xS pwm buzzer Linux driver hacking

    /**************************************************************************** * OK335xS pwm buzzer L ...

  6. TI am335x am437x PRU

    http://bbs.eeworld.com.cn/thread-355798-1-1.html

  7. AM335X启动(转)

    AM335x启动   参考文件: 1.TI.Reference_Manual_1.pdf http://pan.baidu.com/s/1c1BJNtm 2.TI_AM335X.pdf http:// ...

  8. AM335x启动

    参考文件: 1.TI.Reference_Manual_1.pdf http://pan.baidu.com/s/1c1BJNtm 2.TI_AM335X.pdf http://pan.baidu.c ...

  9. AM335X UBOOT(以UART为例分析UBOOT主要流程)

    UBOOT2016.05 UART初始化及设置 SPL阶段 第一部分C函数 |- s_init //(arch/arm/cpu/armv7/am33xx/board.c) |- set_uart_mu ...

随机推荐

  1. ubuntu16.04中开启和关闭防火墙

    开启防火墙 ufw enable 关闭防火墙 ufw disable

  2. 查询ORACLE存储关联表

    SELECT DISTINCT * FROM user_sourceWHERE TYPE = 'PROCEDURE'AND upper(text) LIKE '%PS_KL_ABS_002_DATA% ...

  3. 利用 AttachThreadInput 改变其它进程的输入法状态

    利用 AttachThreadInput 和 WM_INPUTLANGCHANGEREQUEST 消息 改变 其它 进程 的 输入 状态 ? 众所周知,通过 ActivateKeyboardLayou ...

  4. Vue.js Cookbook: 添加实例属性; 👍 axios(4万➕✨)访问API; filters过滤器;

    add instance properties //加上$,防止和已经定义的data,method, computed的名字重复,导致被覆写.//可以自定义添加其他符号. Vue.prototype. ...

  5. 在 Confluence 6 中的 Jira 高级权限

    启用嵌套用户组(Enable Nested Groups) 为嵌套组启用或禁用支持. 在启用嵌套用户组之前,你需要检查你在 JIRA 服务器中的嵌套用户组是否启用了.当嵌套用户组启用成功后,你可以将一 ...

  6. 带分数(dfs,next_permutation)

    问题描述 100 可以表示为带分数的形式:100 = 3 + 69258 / 714. 还可以表示为:100 = 82 + 3546 / 197. 注意特征:带分数中,数字1~9分别出现且只出现一次( ...

  7. MVC5 学习笔记 controller

    主要参考书籍<ASP.NET MVC5 高级编程(第5版) > 作者:Jon Galloway等 1. MVC 表示 模型-视图-控制器.MVC是一种用于开发应用程序的模式,具备良好的架构 ...

  8. sql 2005 代码导入excel数据

     select * into bm from OpenDataSource( 'Microsoft.ACE.OLEDB.12.0', 'Data Source="G:\bm.xls" ...

  9. 使用a标签实现软件下载及下载量统计

    通常最简单的软件下载就是采用如下方式: <a id="welcomeMiddleBtn" href="${basePath}/files/client/instal ...

  10. linux System V IPC Mechanisms

    Message Queues Semaphores Shared Memory