日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

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

發布時間:2023/12/10 linux 53 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux下TI omap芯片 MUX 配置分析(以AM335X芯片为例) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
在移植內核的時候,通常會遇到引腳復用(MUX)的配置問題。在現在的Linux內核中,對于TI的ARM芯片,早已經有了比較通用的MUX配置框架。這對于許多TI的芯片都是通用的,這次看AM335X的代碼順手寫一下分析,以備后用。
一、硬件 對于許多TI的芯片來說,引腳復用的配置是在Control Module(配置模塊)的寄存器里配置的,(這個和三星的CPU有點不同,三星的一般在GPIO的寄存器中配置)。所以當你需要配置這些寄存器的時候,請到數據手冊的Control Module的Pad Control Registers查找。
  • TI的CPU芯片手冊有兩種:
  • 一種是datasheet(DS:數據手冊),較小,只是大概介紹下芯片的結構;
  • 另一種是Technical Reference Manual(TRM:技術參考手冊),較大,詳細介紹芯片的各部分功能原理和寄存器定義。
  • 在開發過程中,這兩個手冊都需要參考,是互補的。

  • 對于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
  • mux.h
  • mux.c
  • mux33xx.h
  • mux33xx.c
  • board-am335xevm.c

  • (還有一些用到了:arch/arm/plat-omap/include/plat/omap_hwmod.h)

  • 其中他們的層次關系是:

    (1)重要的數據結構
  • /**
  • ?* struct mux_partition - 包含分區相關信息
  • ?* @name: 當前分區名
  • ?* @flags: 本分區的特定標志
  • ?* @phys: 物理地址
  • ?* @size: 分區大小
  • ?* @base: ioremap 映射過的虛擬地址
  • ?* @muxmodes: 本分區mux節點鏈表頭
  • ?* @node: 分區鏈表頭
  • ?*/
  • struct omap_mux_partition {
  • ????const char????????*name;
  • ????u32????????????flags;
  • ????u32????????????phys;
  • ????u32????????????size;
  • ????void __iomem????????*base;
  • ????struct list_head????muxmodes;
  • ????struct list_head????node;
  • };

  • 這個數據結構中包含了芯片中幾乎所有定義好的mux的數據,它在mux數據初始化函數omap_mux_init中初始化,并添加到全局mux_partitions鏈表中(通過node成員)。而其中的muxmodes是所有mux信息節點的鏈表頭,用來鏈接以下數據結構:
  • /**
  • ?* struct omap_mux_entry - mux信息節點
  • ?* @mux: omap_mux結構體
  • ?* @node: 鏈表節點
  • ?*/
  • struct omap_mux_entry {
  • ????struct omap_mux????????mux;
  • ????struct list_head????node;
  • };

  • 而在以上數據結構中,struct omap_mux是記錄單個mux節點數據的結構體:
  • /**
  • ?* struct omap_mux - omap mux 寄存器偏移和值的數據
  • ?* @reg_offset:????從Control Module寄存器基地址算起的mux寄存器偏移
  • ?* @gpio:????GPIO 編號
  • ?* @muxnames:????引腳可用的信號模式字符串指針數組
  • ?* @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鏈表及其節點數據的初始化都是在omap_mux_init初始化函數中(omap_mux_init_list(partition, superset);),而struct omap_mux節點數據中信息是由mux33xx.h和mux33xx.c中提供的。你可以在mux33xx.c中看到一個巨大的struct omap_mux結構體數組初始化代碼,這個代碼一看就明了。不同的芯片只需要根據芯片資料修改這個結構體就好了,但是am33xx的這個結構體(當前)還不完善,gpio的數據還都是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 },????????\
  • }
  • 這個宏使得這個結構體數組的初始化變得清晰明了。
    以上的數據結構是在系統初始化的時候使用的,在struct omap_mux_partition完成初始化后,omap_mux_init初始化函數最后會根據不同的板子初始化部分mux寄存器(omap_mux_init_signals(partition, board_mux);),其中牽涉到了以下結構體:
  • /**
  • ?* struct omap_board_mux - 初始化mux寄存器的數據
  • ?* @reg_offset:????從Control Module寄存器基地址算起的mux寄存器偏移
  • ?* @mux_value:????希望設置的mux寄存器值
  • ?*/
  • struct omap_board_mux {
  • ????u16????reg_offset;
  • ????u16????value;
  • };

  • 在最上層的板級初始化文件(board-am335xevm.c)中會定義一個這樣的結構體數組,確定所要初始化的引腳復用寄存器,交由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
  • 其中用到了一個宏:
  • /* 如果引腳沒有定義為輸入,拉動電阻將會被禁用
  • ?* 如果定義為輸入,所提供的標志位將確定拉動電阻的配置
  • ?*/
  • #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_MUXENTRYAM33XX_MUX這兩個宏,前者是用于struct omap_mux的;后者是用于struct omap_board_mux的。
    (2)重要的接口函數
  • /**
  • ?* omap_mux_init - MUX初始化的私有函數,請勿使用
  • ?* 由各板級特定的MUX初始化函數調用
  • ?*/
  • 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);
  • 這個函數是內部用于初始化struct mux_partition的最總要的函數,但是這個函數并不作為接口函數使用,而是供各芯片初始化函數“*_mux_init”所使用的。比如AM33XX芯片:
  • /**
  • ?* am33xx_mux_init() - 用板級特定的設置來初始化MUX系統
  • ?* @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);
  • }

  • 有了已經初始化好的struct mux_partition結構體,我們可以利用mux.h提供的許多函數方便的初始化各mux寄存器:
  • /**
  • ?* omap_mux_init_signal - 根據信號名字符串初始化一個引腳的mux
  • ?* @muxname:????????mode0_name.signal_name的格式的Mux名稱
  • ?* @val:????????mux寄存器值
  • ?*/
  • int omap_mux_init_signal(const char *muxname, int val);

  • /**
  • ?* omap_mux_get() - 通過名字返回一個mux分區
  • ?* @name:????????mux分區名
  • ?*
  • ?*/
  • struct omap_mux_partition *omap_mux_get(const char *name);

  • /**
  • ?* omap_mux_read() - 讀取mux寄存器(通過分區結構體指針和寄存器偏移值)
  • ?* @partition:????????Mux分區
  • ?* @mux_offset:????????mux寄存器偏移
  • ?*
  • ?*/
  • u16 omap_mux_read(struct omap_mux_partition *p, u16 mux_offset);

  • /**
  • ?* omap_mux_write() - 寫mux寄存器(通過分區結構體指針和寄存器偏移值)
  • ?* @partition:????????Mux分區
  • ?* @val:????????新的mux寄存器值
  • ?* @mux_offset:????????mux寄存器偏移
  • ?*
  • ?* 這個函數僅有在非GPIO信號的動態復用需要
  • ?*/
  • void omap_mux_write(struct omap_mux_partition *p, u16 val, u16 mux_offset);

  • /**
  • ?* omap_mux_write_array() - 寫mux寄存器陣列
  • ?* @partition:????????Mux分區
  • ?* @board_mux:????????mux寄存器陣列 (用MAP_MUX_TERMINATOR結尾)
  • ?*
  • ?* 這個函數僅有在非GPIO信號的動態復用需要
  • ?*/
  • void omap_mux_write_array(struct omap_mux_partition *p,
  • ???????????? struct omap_board_mux *board_mux);
  • 在代碼比較完備的芯片中,struct omap_mux中的gpio成員有被初始化過,這樣就可以使用以下接口函數:
  • /**
  • ?* omap_mux_init_gpio - 根據GPIO編號初始化一個信號引腳
  • ?* @gpio:????????GPIO編號
  • ?* @val:????????mux寄存器值
  • ?*/
  • int omap_mux_init_gpio(int gpio, int val);

  • /**
  • ?* omap_mux_get_gpio() - 根據GPIO編號獲取一個mux寄存器值
  • ?* @gpio:????????GPIO編號
  • ?*
  • ?*/
  • u16 omap_mux_get_gpio(int gpio);

  • /**
  • ?* omap_mux_set_gpio() - 根據GPIO編號設定一個mux寄存器值
  • ?* @val:????????新的mux寄存器值
  • ?* @gpio:????????GPIO編號
  • ?*
  • ?*/
  • 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中使用了自己封裝的一個函數和結構體:
  • /* 模塊引腳復用結構體 */
  • struct pinmux_config {
  • ????const char *string_name; /* 信號名格式化字符串,“模式0字符串.目標模式字符串“ */
  • ????int val; /* 其他mux寄存器可選配置值 */
  • };

  • /*
  • * @pin_mux - 單個模塊引腳復用結構體
  • *????????????其中定義了本模塊所有引腳復用細節.
  • */
  • 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;
  • ????}
  • }
  • 三、使用注意
    ?上面初始化過的結構體和接口函數的定義都是帶有"__init"和“__initdata”的,所以這些都只能在內核初始化代碼中使用,一旦系統初始化結束并進入了文件系統,這些定義都會被free。所有它們不能在內核模塊(.ok)中被調用,否則你就等著Oops吧。因為一個芯片的引腳復用一般是硬件設計的時候定死的,一般不可能在啟動后更改。如果你是在要在模塊中改變引腳復用配置,你只能通過自己ioremap相關寄存器再修改它們來實現。

    總結

    以上是生活随笔為你收集整理的Linux下TI omap芯片 MUX 配置分析(以AM335X芯片为例)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。