Linux下TI omap芯片 MUX 配置分析(以AM335X芯片为例)
生活随笔
收集整理的這篇文章主要介紹了
Linux下TI omap芯片 MUX 配置分析(以AM335X芯片为例)
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
在移植內(nèi)核的時(shí)候,通常會(huì)遇到引腳復(fù)用(MUX)的配置問題。在現(xiàn)在的Linux內(nèi)核中,對于TI的ARM芯片,早已經(jīng)有了比較通用的MUX配置框架。這對于許多TI的芯片都是通用的,這次看AM335X的代碼順手寫一下分析,以備后用。
一、硬件 對于許多TI的芯片來說,引腳復(fù)用的配置是在Control Module(配置模塊)的寄存器里配置的,(這個(gè)和三星的CPU有點(diǎn)不同,三星的一般在GPIO的寄存器中配置)。所以當(dāng)你需要配置這些寄存器的時(shí)候,請到數(shù)據(jù)手冊的Control Module的Pad Control Registers查找。
TI的CPU芯片手冊有兩種: 一種是datasheet(DS:數(shù)據(jù)手冊),較小,只是大概介紹下芯片的結(jié)構(gòu); 另一種是Technical Reference Manual(TRM:技術(shù)參考手冊),較大,詳細(xì)介紹芯片的各部分功能原理和寄存器定義。 在開發(fā)過程中,這兩個(gè)手冊都需要參考,是互補(bǔ)的。
對于AM335X,關(guān)于引腳復(fù)用的列表及模式號與功能的對應(yīng)可以在數(shù)據(jù)手冊中找到: 2 Terminal Description: 2.2 Ball Characteristics
關(guān)于引腳復(fù)用寄存器定義及各引腳相應(yīng)寄存器的偏移可以在TRM中找到: 9 Control Module 9.1 Control Module 9.1.3 Functional Description 9.1.3.2 Pad Control Registers (包含引腳復(fù)用寄存器定義) 9.1.5 Registers 9.1.5.1 CONTROL_MODULE Registers (包含引腳相應(yīng)寄存器的偏移)
二、軟件 由于TI的芯片構(gòu)架類似,對于Linux內(nèi)核來說,早就已經(jīng)為這個(gè)做好了一個(gè)軟件上的框架,無論是在啟動(dòng)的初始化階段還是在系統(tǒng)運(yùn)行時(shí),都可以通過這個(gè)框架提供的接口函數(shù)配置芯片的MUX。下面就來簡要的分析一下。 以AM335X為例,相關(guān)代碼位置:arch/arm/mach-omap2mux.h mux.c mux33xx.h mux33xx.c board-am335xevm.c
(還有一些用到了:arch/arm/plat-omap/include/plat/omap_hwmod.h)
其中他們的層次關(guān)系是:
(1)重要的數(shù)據(jù)結(jié)構(gòu)/**
?* struct mux_partition - 包含分區(qū)相關(guān)信息
?* @name: 當(dāng)前分區(qū)名
?* @flags: 本分區(qū)的特定標(biāo)志
?* @phys: 物理地址
?* @size: 分區(qū)大小
?* @base: ioremap 映射過的虛擬地址
?* @muxmodes: 本分區(qū)mux節(jié)點(diǎn)鏈表頭
?* @node: 分區(qū)鏈表頭
?*/
struct omap_mux_partition {
????const char????????*name;
????u32????????????flags;
????u32????????????phys;
????u32????????????size;
????void __iomem????????*base;
????struct list_head????muxmodes;
????struct list_head????node;
};
這個(gè)數(shù)據(jù)結(jié)構(gòu)中包含了芯片中幾乎所有定義好的mux的數(shù)據(jù),它在mux數(shù)據(jù)初始化函數(shù)omap_mux_init中初始化,并添加到全局mux_partitions鏈表中(通過node成員)。而其中的muxmodes是所有mux信息節(jié)點(diǎn)的鏈表頭,用來鏈接以下數(shù)據(jù)結(jié)構(gòu):/**
?* struct omap_mux_entry - mux信息節(jié)點(diǎn)
?* @mux: omap_mux結(jié)構(gòu)體
?* @node: 鏈表節(jié)點(diǎn)
?*/
struct omap_mux_entry {
????struct omap_mux????????mux;
????struct list_head????node;
};
而在以上數(shù)據(jù)結(jié)構(gòu)中,struct omap_mux是記錄單個(gè)mux節(jié)點(diǎn)數(shù)據(jù)的結(jié)構(gòu)體:/**
?* struct omap_mux - omap mux 寄存器偏移和值的數(shù)據(jù)
?* @reg_offset:????從Control Module寄存器基地址算起的mux寄存器偏移
?* @gpio:????GPIO 編號
?* @muxnames:????引腳可用的信號模式字符串指針數(shù)組
?* @balls:????封裝中可用的引腳
?*/
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
};
而struct mux_partition中muxmodes鏈表及其節(jié)點(diǎn)數(shù)據(jù)的初始化都是在omap_mux_init初始化函數(shù)中(omap_mux_init_list(partition, superset);),而struct omap_mux節(jié)點(diǎn)數(shù)據(jù)中信息是由mux33xx.h和mux33xx.c中提供的。你可以在mux33xx.c中看到一個(gè)巨大的struct omap_mux結(jié)構(gòu)體數(shù)組初始化代碼,這個(gè)代碼一看就明了。不同的芯片只需要根據(jù)芯片資料修改這個(gè)結(jié)構(gòu)體就好了,但是am33xx的這個(gè)結(jié)構(gòu)體(當(dāng)前)還不完善,gpio的數(shù)據(jù)還都是0。值得一提的是其中用到了一個(gè)宏:#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 },????????\
} 這個(gè)宏使得這個(gè)結(jié)構(gòu)體數(shù)組的初始化變得清晰明了。
以上的數(shù)據(jù)結(jié)構(gòu)是在系統(tǒng)初始化的時(shí)候使用的,在struct omap_mux_partition完成初始化后,omap_mux_init初始化函數(shù)最后會(huì)根據(jù)不同的板子初始化部分mux寄存器(omap_mux_init_signals(partition, board_mux);),其中牽涉到了以下結(jié)構(gòu)體:/**
?* struct omap_board_mux - 初始化mux寄存器的數(shù)據(jù)
?* @reg_offset:????從Control Module寄存器基地址算起的mux寄存器偏移
?* @mux_value:????希望設(shè)置的mux寄存器值
?*/
struct omap_board_mux {
????u16????reg_offset;
????u16????value;
};
在最上層的板級初始化文件(board-am335xevm.c)中會(huì)定義一個(gè)這樣的結(jié)構(gòu)體數(shù)組,確定所要初始化的引腳復(fù)用寄存器,交由omap_mux_init_signals(partition, board_mux);使用。例如:
#ifdef CONFIG_OMAP_MUX
static struct omap_board_mux board_mux[] __initdata = {
????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 },
};
#else
#define????board_mux????NULL
#endif 其中用到了一個(gè)宏: /* 如果引腳沒有定義為輸入,拉動(dòng)電阻將會(huì)被禁用
?* 如果定義為輸入,所提供的標(biāo)志位將確定拉動(dòng)電阻的配置
?*/
#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)),????\
}
注意_AM33XX_MUXENTRY和AM33XX_MUX這兩個(gè)宏,前者是用于struct omap_mux的;后者是用于struct omap_board_mux的。
(2)重要的接口函數(shù)
/**
?* omap_mux_init - MUX初始化的私有函數(shù),請勿使用
?* 由各板級特定的MUX初始化函數(shù)調(diào)用
?*/
int 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); 這個(gè)函數(shù)是內(nèi)部用于初始化struct mux_partition的最總要的函數(shù),但是這個(gè)函數(shù)并不作為接口函數(shù)使用,而是供各芯片初始化函數(shù)“*_mux_init”所使用的。比如AM33XX芯片: /**
?* am33xx_mux_init() - 用板級特定的設(shè)置來初始化MUX系統(tǒng)
?* @board_mux:????????板級特定的MUX配置表
?*/
int __init am33xx_mux_init(struct omap_board_mux *board_subset)
{
????return omap_mux_init("core", 0, AM33XX_CONTROL_PADCONF_MUX_PBASE,
????????????AM33XX_CONTROL_PADCONF_MUX_SIZE, am33xx_muxmodes,
????????????NULL, board_subset, NULL);
}
有了已經(jīng)初始化好的struct mux_partition結(jié)構(gòu)體,我們可以利用mux.h提供的許多函數(shù)方便的初始化各mux寄存器:/**
?* omap_mux_init_signal - 根據(jù)信號名字符串初始化一個(gè)引腳的mux
?* @muxname:????????mode0_name.signal_name的格式的Mux名稱
?* @val:????????mux寄存器值
?*/
int omap_mux_init_signal(const char *muxname, int val);
/**
?* omap_mux_get() - 通過名字返回一個(gè)mux分區(qū)
?* @name:????????mux分區(qū)名
?*
?*/
struct omap_mux_partition *omap_mux_get(const char *name);
/**
?* omap_mux_read() - 讀取mux寄存器(通過分區(qū)結(jié)構(gòu)體指針和寄存器偏移值)
?* @partition:????????Mux分區(qū)
?* @mux_offset:????????mux寄存器偏移
?*
?*/
u16 omap_mux_read(struct omap_mux_partition *p, u16 mux_offset);
/**
?* omap_mux_write() - 寫mux寄存器(通過分區(qū)結(jié)構(gòu)體指針和寄存器偏移值)
?* @partition:????????Mux分區(qū)
?* @val:????????新的mux寄存器值
?* @mux_offset:????????mux寄存器偏移
?*
?* 這個(gè)函數(shù)僅有在非GPIO信號的動(dòng)態(tài)復(fù)用需要
?*/
void omap_mux_write(struct omap_mux_partition *p, u16 val, u16 mux_offset);
/**
?* omap_mux_write_array() - 寫mux寄存器陣列
?* @partition:????????Mux分區(qū)
?* @board_mux:????????mux寄存器陣列 (用MAP_MUX_TERMINATOR結(jié)尾)
?*
?* 這個(gè)函數(shù)僅有在非GPIO信號的動(dòng)態(tài)復(fù)用需要
?*/
void omap_mux_write_array(struct omap_mux_partition *p,
???????????? struct omap_board_mux *board_mux); 在代碼比較完備的芯片中,struct omap_mux中的gpio成員有被初始化過,這樣就可以使用以下接口函數(shù): /**
?* omap_mux_init_gpio - 根據(jù)GPIO編號初始化一個(gè)信號引腳
?* @gpio:????????GPIO編號
?* @val:????????mux寄存器值
?*/
int omap_mux_init_gpio(int gpio, int val);
/**
?* omap_mux_get_gpio() - 根據(jù)GPIO編號獲取一個(gè)mux寄存器值
?* @gpio:????????GPIO編號
?*
?*/
u16 omap_mux_get_gpio(int gpio);
/**
?* omap_mux_set_gpio() - 根據(jù)GPIO編號設(shè)定一個(gè)mux寄存器值
?* @val:????????新的mux寄存器值
?* @gpio:????????GPIO編號
?*
?*/
void omap_mux_set_gpio(u16 val, int gpio);
但是am33xx的gpio成員(當(dāng)前)還都是0,所有這些函數(shù)沒法使用。
此外,在mux.h中還導(dǎo)出了其他的軟件接口和數(shù)據(jù)結(jié)構(gòu),這些在am33xx中沒有使用,有需要的時(shí)候再看。
在板級初始化代碼(比如board-am335xevm.c)運(yùn)行完芯片特定的MUX初始化函數(shù)(am33xx_mux_init(board_mux);)之后,也可以在各子系統(tǒng)初始化時(shí)通過上面的接口函數(shù)修改配置MUX,比如在am33xx中使用了自己封裝的一個(gè)函數(shù)和結(jié)構(gòu)體:
/* 模塊引腳復(fù)用結(jié)構(gòu)體 */
struct pinmux_config {
????const char *string_name; /* 信號名格式化字符串,“模式0字符串.目標(biāo)模式字符串“ */
????int val; /* 其他mux寄存器可選配置值 */
};
/*
* @pin_mux - 單個(gè)模塊引腳復(fù)用結(jié)構(gòu)體
*????????????其中定義了本模塊所有引腳復(fù)用細(xì)節(jié).
*/
static void setup_pin_mux(struct pinmux_config *pin_mux)
{
????int i;
????for (i = 0; pin_mux->string_name != NULL; pin_mux++)
????????omap_mux_init_signal(pin_mux->string_name, pin_mux->val);
} 你可以在board-am335xevm.c中看到如下的代碼: static struct pinmux_config d_can_ia_pin_mux[] = {
????{"uart0_rxd.d_can0_tx", OMAP_MUX_MODE2 | AM33XX_PULL_ENBL},
????{"uart0_txd.d_can0_rx", OMAP_MUX_MODE2 | AM33XX_PIN_INPUT_PULLUP},
????{NULL, 0},
};
......
static void d_can_init(int evm_id, int profile)
{
????switch (evm_id) {
????case IND_AUT_MTR_EVM:
????????if ((profile == PROFILE_0) || (profile == PROFILE_1)) {
????????????setup_pin_mux(d_can_ia_pin_mux);
????????????/* Instance Zero */
????????????am33xx_d_can_init(0);
????????}
????????break;
????case GEN_PURP_EVM:
????????if (profile == PROFILE_1) {
????????????setup_pin_mux(d_can_gp_pin_mux);
????????????/* Instance One */
????????????am33xx_d_can_init(1);
????????}
????????break;
????default:
????????break;
????}
} 三、使用注意
?上面初始化過的結(jié)構(gòu)體和接口函數(shù)的定義都是帶有"__init"和“__initdata”的,所以這些都只能在內(nèi)核初始化代碼中使用,一旦系統(tǒng)初始化結(jié)束并進(jìn)入了文件系統(tǒng),這些定義都會(huì)被free。所有它們不能在內(nèi)核模塊(.ok)中被調(diào)用,否則你就等著Oops吧。因?yàn)橐粋€(gè)芯片的引腳復(fù)用一般是硬件設(shè)計(jì)的時(shí)候定死的,一般不可能在啟動(dòng)后更改。如果你是在要在模塊中改變引腳復(fù)用配置,你只能通過自己ioremap相關(guān)寄存器再修改它們來實(shí)現(xiàn)。
一、硬件 對于許多TI的芯片來說,引腳復(fù)用的配置是在Control Module(配置模塊)的寄存器里配置的,(這個(gè)和三星的CPU有點(diǎn)不同,三星的一般在GPIO的寄存器中配置)。所以當(dāng)你需要配置這些寄存器的時(shí)候,請到數(shù)據(jù)手冊的Control Module的Pad Control Registers查找。
對于AM335X,關(guān)于引腳復(fù)用的列表及模式號與功能的對應(yīng)可以在數(shù)據(jù)手冊中找到: 2 Terminal Description: 2.2 Ball Characteristics
關(guān)于引腳復(fù)用寄存器定義及各引腳相應(yīng)寄存器的偏移可以在TRM中找到: 9 Control Module 9.1 Control Module 9.1.3 Functional Description 9.1.3.2 Pad Control Registers (包含引腳復(fù)用寄存器定義) 9.1.5 Registers 9.1.5.1 CONTROL_MODULE Registers (包含引腳相應(yīng)寄存器的偏移)
二、軟件 由于TI的芯片構(gòu)架類似,對于Linux內(nèi)核來說,早就已經(jīng)為這個(gè)做好了一個(gè)軟件上的框架,無論是在啟動(dòng)的初始化階段還是在系統(tǒng)運(yùn)行時(shí),都可以通過這個(gè)框架提供的接口函數(shù)配置芯片的MUX。下面就來簡要的分析一下。 以AM335X為例,相關(guān)代碼位置:arch/arm/mach-omap2
其中他們的層次關(guān)系是:
(1)重要的數(shù)據(jù)結(jié)構(gòu)
這個(gè)數(shù)據(jù)結(jié)構(gòu)中包含了芯片中幾乎所有定義好的mux的數(shù)據(jù),它在mux數(shù)據(jù)初始化函數(shù)omap_mux_init中初始化,并添加到全局mux_partitions鏈表中(通過node成員)。而其中的muxmodes是所有mux信息節(jié)點(diǎn)的鏈表頭,用來鏈接以下數(shù)據(jù)結(jié)構(gòu):
而在以上數(shù)據(jù)結(jié)構(gòu)中,struct omap_mux是記錄單個(gè)mux節(jié)點(diǎn)數(shù)據(jù)的結(jié)構(gòu)體:
而struct mux_partition中muxmodes鏈表及其節(jié)點(diǎn)數(shù)據(jù)的初始化都是在omap_mux_init初始化函數(shù)中(omap_mux_init_list(partition, superset);),而struct omap_mux節(jié)點(diǎn)數(shù)據(jù)中信息是由mux33xx.h和mux33xx.c中提供的。你可以在mux33xx.c中看到一個(gè)巨大的struct omap_mux結(jié)構(gòu)體數(shù)組初始化代碼,這個(gè)代碼一看就明了。不同的芯片只需要根據(jù)芯片資料修改這個(gè)結(jié)構(gòu)體就好了,但是am33xx的這個(gè)結(jié)構(gòu)體(當(dāng)前)還不完善,gpio的數(shù)據(jù)還都是0。值得一提的是其中用到了一個(gè)宏:
以上的數(shù)據(jù)結(jié)構(gòu)是在系統(tǒng)初始化的時(shí)候使用的,在struct omap_mux_partition完成初始化后,omap_mux_init初始化函數(shù)最后會(huì)根據(jù)不同的板子初始化部分mux寄存器(omap_mux_init_signals(partition, board_mux);),其中牽涉到了以下結(jié)構(gòu)體:
在最上層的板級初始化文件(board-am335xevm.c)中會(huì)定義一個(gè)這樣的結(jié)構(gòu)體數(shù)組,確定所要初始化的引腳復(fù)用寄存器,交由omap_mux_init_signals(partition, board_mux);使用。例如:
注意_AM33XX_MUXENTRY和AM33XX_MUX這兩個(gè)宏,前者是用于struct omap_mux的;后者是用于struct omap_board_mux的。
(2)重要的接口函數(shù)
有了已經(jīng)初始化好的struct mux_partition結(jié)構(gòu)體,我們可以利用mux.h提供的許多函數(shù)方便的初始化各mux寄存器:
但是am33xx的gpio成員(當(dāng)前)還都是0,所有這些函數(shù)沒法使用。
此外,在mux.h中還導(dǎo)出了其他的軟件接口和數(shù)據(jù)結(jié)構(gòu),這些在am33xx中沒有使用,有需要的時(shí)候再看。
在板級初始化代碼(比如board-am335xevm.c)運(yùn)行完芯片特定的MUX初始化函數(shù)(am33xx_mux_init(board_mux);)之后,也可以在各子系統(tǒng)初始化時(shí)通過上面的接口函數(shù)修改配置MUX,比如在am33xx中使用了自己封裝的一個(gè)函數(shù)和結(jié)構(gòu)體:
?上面初始化過的結(jié)構(gòu)體和接口函數(shù)的定義都是帶有"__init"和“__initdata”的,所以這些都只能在內(nèi)核初始化代碼中使用,一旦系統(tǒng)初始化結(jié)束并進(jìn)入了文件系統(tǒng),這些定義都會(huì)被free。所有它們不能在內(nèi)核模塊(.ok)中被調(diào)用,否則你就等著Oops吧。因?yàn)橐粋€(gè)芯片的引腳復(fù)用一般是硬件設(shè)計(jì)的時(shí)候定死的,一般不可能在啟動(dòng)后更改。如果你是在要在模塊中改變引腳復(fù)用配置,你只能通過自己ioremap相關(guān)寄存器再修改它們來實(shí)現(xiàn)。
總結(jié)
以上是生活随笔為你收集整理的Linux下TI omap芯片 MUX 配置分析(以AM335X芯片为例)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 永不限速!阿里云盘功能升级:VIP支持4
- 下一篇: openssl-1.0.0b - lib