1. 程式人生 > >board-mx6q_sabresd.c原始碼閱讀筆記

board-mx6q_sabresd.c原始碼閱讀筆記


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:
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));
首先跟蹤這個函式mxc_iomux_v3_setup_multiple_pads:字面意思就是多個pad的設定
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這個檔案中的定義,向一系列的實體地址中寫入了相應的值。