i.MX6qSabreLite内核源码阅读笔记-----board-mx6q_sabrelite.c 分析----1

这个文件是sabrelite板子的bsp支持文件。大致阅读如下。

mx6_sabrelite_board_init函数 对板子进行初始化

static void __init mx6_sabrelite_board_init(void)
{
int i;
int ret;
struct clk *clko2;
struct clk *new_parent;
int rate;
struct platform_device *voutdev;


mxc_iomux_v3_setup_multiple_pads(mx6q_sabrelite_pads,
ARRAY_SIZE(mx6q_sabrelite_pads));// 这一句好像是对io资源进行的初始化


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 {
/* J5 - Camera GP */
iomux_v3_cfg_t camera_gpio_pad =
MX6Q_PAD_GPIO_6__GPIO_1_6;
mxc_iomux_v3_setup_pad(camera_gpio_pad);
}


#ifdef CONFIG_FEC_1588
/* Set GPIO_16 input for IEEE-1588 ts_clk and RMII reference clock
* For MX6 GPR1 bit21 meaning:
* Bit21:       0 - GPIO_16 pad output
*              1 - GPIO_16 pad input
*/
mxc_iomux_set_gpr_register(1, 21, 1, 1);
#endif


gp_reg_id = sabrelite_dvfscore_data.reg_id;
soc_reg_id = sabrelite_dvfscore_data.soc_id;
pu_reg_id = sabrelite_dvfscore_data.pu_id;
mx6q_sabrelite_init_uart();//对串口进行初始化,只初始化了 串口1 和串口2
imx6q_add_mxc_hdmi_core(&hdmi_core_data);//hdmi进程初始化。


imx6q_add_ipuv3(0, &ipu_data[0]);
imx6q_add_ipuv3(1, &ipu_data[1]);


for (i = 0; i < ARRAY_SIZE(sabrelite_fb_data); i++)//ARRAY_SIZE 其实就是计算结构体重元素的个数,这里其实是设备的个数。然后逐一初始化。显示设备的初始化。
imx6q_add_ipuv3fb(i, &sabrelite_fb_data[i]);


imx6q_add_vdoa();
imx6q_add_lcdif(&lcdif_data);
imx6q_add_ldb(&ldb_data);//添加lvds驱动的平台设备。
voutdev = imx6q_add_v4l2_output(0);//添加v4l2 平台设备  平台设备注册
if (vout_mem.res_msize && voutdev) {
dma_declare_coherent_memory(&voutdev->dev,
   vout_mem.res_mbase,
   vout_mem.res_mbase,
   vout_mem.res_msize,
   (DMA_MEMORY_MAP |
    DMA_MEMORY_EXCLUSIVE));
}




imx6q_add_v4l2_capture(0, &capture_data[0]);
imx6q_add_v4l2_capture(1, &capture_data[1]);
imx6q_add_mipi_csi2(&mipi_csi2_pdata);
imx6q_add_imx_snvs_rtc();//RTC 时钟


if (1 == caam_enabled)
imx6q_add_imx_caam();


imx6q_add_imx_i2c(0, &mx6q_sabrelite_i2c_data);//I2C平台设备注册
imx6q_add_imx_i2c(1, &mx6q_sabrelite_i2c_data);
imx6q_add_imx_i2c(2, &mx6q_sabrelite_i2c_data);
i2c_register_board_info(0, mxc_i2c0_board_info,
ARRAY_SIZE(mxc_i2c0_board_info));
i2c_register_board_info(1, mxc_i2c1_board_info,
ARRAY_SIZE(mxc_i2c1_board_info));
i2c_register_board_info(2, mxc_i2c2_board_info,
ARRAY_SIZE(mxc_i2c2_board_info));


/* SPI */
imx6q_add_ecspi(0, &mx6q_sabrelite_spi_data);
spi_device_init();


imx6q_add_mxc_hdmi(&hdmi_data);//添加hdmi设备


imx6q_add_anatop_thermal_imx(1, &mx6q_sabrelite_anatop_thermal_data);
if (enet_to_gpio_6)
/* Make sure the IOMUX_OBSRV_MUX1 is set to ENET_IRQ. */
mxc_iomux_set_specialbits_register(
IOMUX_OBSRV_MUX1_OFFSET,
OBSRV_MUX1_ENET_IRQ,
OBSRV_MUX1_MASK);
else
fec_data.gpio_irq = -1;


imx6_init_fec(fec_data);//初始化网卡设备
imx6q_add_pm_imx(0, &mx6q_sabrelite_pm_data);//电源管理
imx6q_add_sdhci_usdhc_imx(3, &mx6q_sabrelite_sd4_data);//SD卡
imx6q_add_sdhci_usdhc_imx(2, &mx6q_sabrelite_sd3_data);//硬盘
imx_add_viv_gpu(&imx6_gpu_data, &imx6q_gpu_pdata);//GPU初始化
imx6q_sabrelite_init_usb();//USB初始化
imx6q_add_ahci(0, &mx6q_sabrelite_sata_data);//
imx6q_add_vpu();
imx6q_init_audio();
platform_device_register(&sabrelite_vmmc_reg_devices);
imx_asrc_data.asrc_core_clk = clk_get(NULL, "asrc_clk");
imx_asrc_data.asrc_audio_clk = clk_get(NULL, "asrc_serial_clk");
imx6q_add_asrc(&imx_asrc_data);


/* release USB Hub reset */
gpio_set_value(MX6Q_SABRELITE_USB_HUB_RESET, 1);


imx6q_add_mxc_pwm(0);//PWM
imx6q_add_mxc_pwm(1);
imx6q_add_mxc_pwm(2);
imx6q_add_mxc_pwm(3);
imx6q_add_mxc_pwm_backlight(3, &mx6_sabrelite_pwm_backlight_data);//PWM 背光控制


imx6q_add_otp();
imx6q_add_viim();
imx6q_add_imx2_wdt(0, NULL);
imx6q_add_dma();


imx6q_add_dvfs_core(&sabrelite_dvfscore_data);//DVFS 动态电压频率调整


sabrelite_add_device_buttons();//按键添加


imx6q_add_hdmi_soc();
imx6q_add_hdmi_soc_dai();


ret = gpio_request_array(mx6q_sabrelite_flexcan_gpios,
ARRAY_SIZE(mx6q_sabrelite_flexcan_gpios));//申请io
if (ret)
pr_err("failed to request flexcan1-gpios: %d\n", ret);
else
imx6q_add_flexcan0(&mx6q_sabrelite_flexcan0_pdata);


clko2 = clk_get(NULL, "clko2_clk");
if (IS_ERR(clko2))
pr_err("can't get CLKO2 clock.\n");


new_parent = clk_get(NULL, "osc_clk");//获取时钟
if (!IS_ERR(new_parent)) {
clk_set_parent(clko2, new_parent);
clk_put(new_parent);
}
rate = clk_round_rate(clko2, 24000000);
clk_set_rate(clko2, rate);
clk_enable(clko2);
imx6q_add_busfreq();//总线


imx6q_add_perfmon(0);
imx6q_add_perfmon(1);
imx6q_add_perfmon(2);
}



所有的函数调用起始点在这里   MACHINE_START

MACHINE_START(MX6Q_SABRELITE, "Freescale i.MX 6Quad Sabre-Lite Board")//u-booot 启动的id 和板子的名称,这些在启动信息里能够看到,id不对,u-boot无法启动内核
/* 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_sabrelite_board_init,
.timer = &mx6_sabrelite_timer,


.reserve = mx6q_sabrelite_reserve,

所以分析这个文件 不妨先分析这个地方,从这里开始 将分析完所有的程序。

不妨先看看这个函数的宏定义

struct machine_desc {
unsigned intnr;/* architecture number*/
const char*name;/* architecture name*/
unsigned longboot_params;/* tagged list*/
const char**dt_compat;/* array of device tree
* 'compatible' strings*/


unsigned intnr_irqs;/* number of IRQs */


unsigned intvideo_start;/* start of video RAM*/
unsigned intvideo_end;/* end of video RAM*/


unsigned intreserve_lp0 :1;/* never has lp0*/
unsigned intreserve_lp1 :1;/* never has lp1*/
unsigned intreserve_lp2 :1;/* never has lp2*/
unsigned intsoft_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*/
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
};


/*
 * Current machine - only accessible during boot.
 */
extern struct machine_desc *machine_desc;


/*
 * Machine type table - also only accessible during boot
 */
extern struct machine_desc __arch_info_begin[], __arch_info_end[];
#define for_each_machine_desc(p) \
for (p = __arch_info_begin; p < __arch_info_end; p++)


/*
 * Set of macros to define architecture features.  This is built into
 * a table by the linker.
 */
#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 \
};

那么亲爱的,这个函数又是从哪里被调用的呢?

我们来找找。。。。

引用http://blog.chinaunix.net/uid-12617001-id-3767393.html 这篇文章

arch/arm/kernel/setup.c 里面的setup_arch()函数

这个函数

void __init setup_arch(char **cmdline_p)

{
struct machine_desc *mdesc;
unwind_init();
setup_processor();
mdesc = setup_machine_fdt(__atags_pointer);
if (!mdesc)
mdesc = setup_machine_tags(machine_arch_type);//就是这一句 把uboot的机器id 传递到内核里面了。
machine_desc = mdesc;
machine_name = mdesc->name;
if (mdesc->soft_reboot)
reboot_setup("s");
init_mm.start_code = (unsigned long) _text;
init_mm.end_code   = (unsigned long) _etext;
init_mm.end_data   = (unsigned long) _edata;
init_mm.brk  = (unsigned long) _end;
/* populate cmd_line too for later use, preserving boot_command_line */
strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);//uboot 传递过来的的启动参数。
*cmdline_p = cmd_line;
parse_early_param();
sanity_check_meminfo();
arm_memblock_init(&meminfo, mdesc);
paging_init(mdesc);
request_standard_resources(mdesc);
unflatten_device_tree();

  1. static int __init customize_machine(void)
  1.  {
  1.          /* customizes platform devices, or adds new ones */
  1.          if (machine_desc->init_machine)
  1.                  machine_desc->init_machine();
  1.          return 0;
  1.  }
  1.  arch_initcall(customize_machine);
  1. 找arch_initcall 函数

  1. extern initcall_t __initcall_start[], __initcall_end[], __early_initcall_end[];
  2.  
  3.  static void __init do_initcalls(void)
  4.  {
  5.          initcall_t *fn;
  6.  
  7.          for (fn = __early_initcall_end; fn < __initcall_end; fn++)
  8.                  do_one_initcall(*fn);
  9.  }
看到第1行,很熟悉吧。在for循环里依次调用了从__early_initcall_end开始到__initcall_end结束的所有函数。customize_machine()也是在其间被调用。
调用顺序为:
  1. extern initcall_t __initcall_start[], __initcall_end[], __early_initcall_end[];
  1.  
  1.  static void __init do_initcalls(void)
  1.  {
  1.          initcall_t *fn;
  1.  
  1.          for (fn = __early_initcall_end; fn < __initcall_end; fn++)
  1.                  do_one_initcall(*fn);
  1.  }
看到第1行,很熟悉吧。在for循环里依次调用了从__early_initcall_end开始到__initcall_end结束的所有函数。customize_machine()也是在其间被调用。
调用顺序为:

成员函数init_machine就是在这里被调用的。但是它没有被显式调用,而是放在了arch_initcall这个宏里,它被链接到了.initcall段里,现在简单看看 arch/arm/kernel/vmlinux.lds这个链接脚本里关于initcall的定义:可以看到customize_machine()被放到了.initcall3.init里。说了那么多定义,究竟它在哪里被调用啊?好吧,它是在/init/main.c里一个叫do_initcalls()的函数里被调用,去看看呗:

start_kernel()--->setup_arch()--->do_initcalls()--->customize_machine()--->mx6_sabrelite_board_init()

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值