board-mx6q_sabresd.c原始碼閱讀筆記
阿新 • • 發佈:2019-01-02
MACHINE_START(MX6Q_SABRESD, "Freescale i.MX 6Quad/DualLite/Solo Sabre-SD Board") /* Maintainer: Freescale Semiconductor, Inc. */ .boot_params = MX6_PHYS_OFFSET + 0x100, .fixup = fixup_mxc_board, .map_io = mx6_map_io, .init_irq = mx6_init_irq, .init_machine = mx6_sabresd_board_init, .timer = &mx6_sabresd_timer, .reserve = mx6q_sabresd_reserve, MACHINE_END
跟蹤MACHINE_START的巨集定義,位於arch.h中:
#define MACHINE_START(_type,_name) \
static const struct machine_desc __mach_desc_##_type \
__used \
__attribute__((__section__(".arch.info.init"))) = { \
.nr = MACH_TYPE_##_type, \
.name = _name,
#define MACHINE_END \
};
##為連線符,跟蹤machine_desc這個結構體的定義:
struct machine_desc { unsigned int nr; /* architecture number *///架構編號 const char *name; /* architecture name *///架構名稱 unsigned long boot_params; /* tagged list */標籤列表? const char **dt_compat; /* array of device tree * 'compatible' strings */ unsigned int nr_irqs; /* number of IRQs */ unsigned int video_start; /* start of video RAM */ unsigned int video_end; /* end of video RAM */ unsigned int reserve_lp0 :1; /* never has lp0 */ unsigned int reserve_lp1 :1; /* never has lp1 */ unsigned int reserve_lp2 :1; /* never has lp2 */ unsigned int soft_reboot :1; /* soft reboot */ void (*fixup)(struct machine_desc *, struct tag *, char **, struct meminfo *);//這個函式有初始化,待看 void (*reserve)(void);/* reserve mem blocks *///待看 void (*map_io)(void);/* IO mapping function *///猜測可能是初始化IO的,待看 void (*init_early)(void); void (*init_irq)(void);//初始化中斷的,待看 struct sys_timer *timer; /* system tick timer */系統時鐘 void (*init_machine)(void);//板級初始化,先跟蹤這個 #ifdef CONFIG_MULTI_IRQ_HANDLER void (*handle_irq)(struct pt_regs *); #endif };
回到board-mx6q_sabresd.c,跟蹤mx6_sabresd_board_init:
首先跟蹤這個函式mxc_iomux_v3_setup_multiple_pads:字面意思就是多個pad的設定static void __init mx6_sabresd_board_init(void) { int i; int ret; struct clk *clko, *clko2; struct clk *new_parent; int rate; struct platform_device *voutdev; if (cpu_is_mx6q()) { mxc_iomux_v3_setup_multiple_pads(mx6q_sabresd_pads, ARRAY_SIZE(mx6q_sabresd_pads)); if (enet_to_gpio_6) { iomux_v3_cfg_t enet_gpio_pad = MX6Q_PAD_GPIO_6__ENET_IRQ_TO_GPIO_6; mxc_iomux_v3_setup_pad(enet_gpio_pad); } else { iomux_v3_cfg_t i2c3_pad = MX6Q_PAD_GPIO_6__I2C3_SDA; mxc_iomux_v3_setup_pad(i2c3_pad); } } else if (cpu_is_mx6dl()) { mxc_iomux_v3_setup_multiple_pads(mx6dl_sabresd_pads, ARRAY_SIZE(mx6dl_sabresd_pads));
int mxc_iomux_v3_setup_multiple_pads(iomux_v3_cfg_t *pad_list, unsigned count)
{
iomux_v3_cfg_t *p = pad_list;
int i;
int ret;
for (i = 0; i < count; i++) {
ret = mxc_iomux_v3_setup_pad(*p);
if (ret)
return ret;
p++;
}
return 0;
}
然後跟蹤這個函式mxc_iomux_v3_setup_pad,這是單個pad的初始化:
int mxc_iomux_v3_setup_pad(iomux_v3_cfg_t pad)//typedef u64 iomux_v3_cfg_t;注意到函式引數是隻是一個64位整型值
{
u32 mux_ctrl_ofs = (pad & MUX_CTRL_OFS_MASK) >> MUX_CTRL_OFS_SHIFT;
u32 mux_mode = (pad & MUX_MODE_MASK) >> MUX_MODE_SHIFT;
u32 sel_input_ofs = (pad & MUX_SEL_INPUT_OFS_MASK) >> MUX_SEL_INPUT_OFS_SHIFT;
u32 sel_input = (pad & MUX_SEL_INPUT_MASK) >> MUX_SEL_INPUT_SHIFT;
u32 pad_ctrl_ofs = (pad & MUX_PAD_CTRL_OFS_MASK) >> MUX_PAD_CTRL_OFS_SHIFT;
u32 pad_ctrl = (pad & MUX_PAD_CTRL_MASK) >> MUX_PAD_CTRL_SHIFT;
if (mux_ctrl_ofs)
__raw_writel(mux_mode, base + mux_ctrl_ofs);
if (sel_input_ofs)
__raw_writel(sel_input, base + sel_input_ofs);
if (!(pad_ctrl & NO_PAD_CTRL) && pad_ctrl_ofs)
__raw_writel(pad_ctrl, base + pad_ctrl_ofs);
return 0;
}
跟蹤引數pad,往回查詢,檢視傳入的引數是什麼?
static iomux_v3_cfg_t mx6q_sabresd_pads[] = {
/* AUDMUX */
MX6Q_PAD_CSI0_DAT4__AUDMUX_AUD3_TXC,
MX6Q_PAD_CSI0_DAT5__AUDMUX_AUD3_TXD,
MX6Q_PAD_CSI0_DAT6__AUDMUX_AUD3_TXFS,
MX6Q_PAD_CSI0_DAT7__AUDMUX_AUD3_RXD,
/* CAN1 */
MX6Q_PAD_KEY_ROW2__HDMI_TX_CEC_LINE,
/* MX6Q_PAD_KEY_COL2__CAN1_TXCAN, */
MX6Q_PAD_GPIO_1__WDOG2_WDOG_B, /*WDOG_B to reset pmic*/
MX6Q_PAD_GPIO_2__GPIO_1_2, /* user defined red led */
MX6Q_PAD_GPIO_7__GPIO_1_7, /* NERR */
/* CCM */
MX6Q_PAD_GPIO_0__CCM_CLKO, /* SGTL500 sys_mclk */
MX6Q_PAD_GPIO_3__CCM_CLKO2, /* J5 - Camera MCLK */
/* ECSPI1 */
MX6Q_PAD_KEY_COL0__ECSPI1_SCLK,
MX6Q_PAD_KEY_ROW0__ECSPI1_MOSI,
MX6Q_PAD_KEY_COL1__ECSPI1_MISO,
很長的一段,我們跟蹤其中的一個串列埠巨集:MX6Q_PAD_EIM_D24__UART3_TXD
#define MX6Q_PAD_EIM_D24__UART3_TXD \
(_MX6Q_PAD_EIM_D24__UART3_TXD | MUX_PAD_CTRL(MX6Q_UART_PAD_CTRL))
跟蹤_MX6Q_PAD_EIM_D24__UART3_TXD:
#define _MX6Q_PAD_EIM_D24__UART3_TXD \
IOMUX_PAD(0x03C8, 0x00B4, 2, 0x0000, 0, 0)
跟蹤這個:IOMUX_PAD:
#define IOMUX_PAD(_pad_ctrl_ofs, _mux_ctrl_ofs, _mux_mode, _sel_input_ofs, \
_sel_input, _pad_ctrl) \
(((iomux_v3_cfg_t)(_mux_ctrl_ofs) << MUX_CTRL_OFS_SHIFT) | \
((iomux_v3_cfg_t)(_mux_mode) << MUX_MODE_SHIFT) | \
((iomux_v3_cfg_t)(_pad_ctrl_ofs) << MUX_PAD_CTRL_OFS_SHIFT) | \
((iomux_v3_cfg_t)(_pad_ctrl) << MUX_PAD_CTRL_SHIFT) | \
((iomux_v3_cfg_t)(_sel_input_ofs) << MUX_SEL_INPUT_OFS_SHIFT) | \
((iomux_v3_cfg_t)(_sel_input) << MUX_SEL_INPUT_SHIFT))
顯然,這是將6個引數左移然後相與,別問我為什麼,我他媽也不知道。其中#define MUX_CTRL_OFS_SHIFT 0,然後依次是36,12,41,24,59.然後我們將引數替換一下。得到下面的公式:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<string.h>
4 typedef unsigned long long u64;
5 int main(int argc,char* argv[])
6 {
7 u64 ret;
8 ret=(u64)argv[1]<<0|
9 (u64)argv[2]<<36|
10 (u64)argv[3]<<12|
11 (u64)argv[4]<<41|
12 (u64)argv[5]<<24|
13 (u64)argv[6]<<59;
14 printf("%p\n",ret);
15 return 0;
16 }
這程式碼我寫的,不是核心程式碼,肯定不靠譜,然後算出來的結果是:0xfffffffdffdd61b6。也不確定對不對。但很顯然這裡包含了大量從晶片手冊上獲得的資訊。而且這還只是一部分,另一部分需要跟蹤MUX_PAD_CTRL。這裡就不詳細展開了。關鍵是展開了也不知道對錯。然後我們再回到這個函式:mxc_iomux_v3_setup_pad。前面6個變數是我們剛才分析傳入引數再與上一個掩碼(簡直沒完沒了),然後再右移得到的。而且這六個變數是32位的。應該是截斷了64位值得到的。然後跟蹤這個函式:__raw_writel:
static inline void __raw_writel(unsigned int b, volatile void __iomem *addr)
{
*(volatile unsigned int __force *) addr = b;
}
有很多修飾,都不管,主要的意思應該是向addr這個實體地址寫入資料b。寫的資料咱們分析過了(雖然沒有完成),再看看這個實體地址是啥。
static void *base = (void *)IOMUXC_BASE_ADDR;
#define IOMUXC_BASE_ADDR 0x43FAC000
後面這句程式碼在imx-regs.h中。代表imx晶片的暫存器定義。(後面好像是什麼裝置樹定義?)這個實體地址也算不出來。總的來說就是根據board-mx6q_sabresd.h這個檔案中的定義,向一系列的實體地址中寫入了相應的值。