Linux啟動過程分析(十一)-----customize_machine(註冊開發板相關硬體資訊)
初始化過程進行到下面這一步:
c0599c48 t __initcall_customize_machine3
呼叫的函式及其位置如下:
Setup.c (arch\arm\kernel):arch_initcall(customize_machine)
static int __init customize_machine(void) { /* customizes platform devices, or adds new ones */ if (machine_desc->init_machine) machine_desc->init_machine(); return 0; }
machine_desc的來歷在前面已經提到過,這裡再重複一下,其讀取流程為Start_kernel()->setup_arch()
void __init setup_arch(char **cmdline_p) { struct machine_desc *mdesc; setup_processor(); mdesc = setup_machine_fdt(__atags_pointer); if (!mdesc) mdesc = setup_machine_tags(machine_arch_type); machine_desc = mdesc; machine_name = mdesc->name;
__atgs_pointer,定義在彙編檔案arch/arm/kernel/head-common.S中,由arm暫存器r2儲存要傳遞給核心引數的地址,定義變數__atags_pointer儲存這個地址,即__atags_pointer儲存了uboot要傳遞給核心引數的地址。
沒有采用裝置樹結構,所以實際上呼叫的是setup_machine_tags(machine_arch_type)來獲得mdesc,並將它賦值給machine_desc。machine_arch_type是uboot傳遞的machine id。
在setup_machine_tags中,
for_each_machine_desc(p) if (nr == p->nr) { printk("Machine: %s\n", p->name); mdesc = p; break; }
從machine_desc存放的段中選擇機器碼與從uboot傳遞過來的機器號nr比較,相等就可以得到machine_desc。
全域性變數machine_desc = mdesc賦值完成後,就可以使用machine_desc指向各個函式呼叫。
再來分析board_da850_evm.c這個檔案的入口,在檔案的最後幾行:
MACHINE_START(DAVINCI_DA850_EVM, "DaVinci DA850/OMAP-L138/AM18x EVM")
.atag_offset = 0x100,
.map_io = da850_evm_map_io,
.init_irq = cp_intc_init,
.timer = &davinci_timer,
.init_machine = da850_evm_init,
.dma_zone_size = SZ_128M,
.restart = da8xx_restart,
MACHINE_END
如何解析這個入口呢,可以在arch\arm\include\asm\mach中找到定義:
/*
* 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 \
};
MACHINE_START(DAVINCI_DA850_EVM, “DaVinci DA850/OMAP-L138/AM18x EVM”)
_type=DAVINCI_DA850_EVM;
_name=“DaVinci DA850/OMAP-L138/AM18x EVM”;
巨集展開就是:
static const struct machine_desc __mach_desc_DAVINCI_DA850_EVM={
.nr = MACH_TYPE_DAVINCI_DA850_EVM,
.name =“DaVinci DA850/OMAP-L138/AM18x EVM”,
.map_io = da850_evm_map_io,
.init_irq = cp_intc_init,
.timer = &davinci_timer,
.init_machine = da850_evm_init,
.dma_zone_size = SZ_128M,
.restart = da8xx_restart,
}
而struct machine_desc變數這個結構體定義如下:
struct tag;
struct meminfo;
struct sys_timer;
struct pt_regs;
struct machine_desc {
unsigned int nr; /* architecture number */
const char *name; /* architecture name */
unsigned long atag_offset; /* tagged list (relative) */
const char *const *dt_compat; /* array of device tree
* 'compatible' strings */
unsigned int nr_irqs; /* number of IRQs */
#ifdef CONFIG_ZONE_DMA
unsigned long dma_zone_size; /* size of DMA-able area */
#endif
unsigned int video_start; /* start of video RAM */
unsigned int video_end; /* end of video RAM */
unsigned char reserve_lp0 :1; /* never has lp0 */
unsigned char reserve_lp1 :1; /* never has lp1 */
unsigned char reserve_lp2 :1; /* never has lp2 */
char restart_mode; /* default restart mode */
void (*fixup)(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
void (*restart)(char, const char *);
};
所以,文章開頭的machine_desc->init_machine()對應的初始化函式就是:da850_evm_init();
這個函式定義在Board-da850-evm.c (arch\arm\mach-davinci) 檔案中,其內容如下:
static __init void da850_evm_init(void)
{
int ret;
char mask = 0;
struct davinci_soc_info *soc_info = &davinci_soc_info;
u8 rmii_en = soc_info->emac_pdata->rmii_en;
struct da8xx_lcdc_platform_data *lcd_pdata;
#if 0
ret = pmic_tps65070_init();
if (ret)
pr_warning("da850_evm_init: TPS65070 PMIC init failed: %d\n",
ret);
#endif
/*
* Though bootloader takes care to set emif clock at allowed
* possible rate. Kernel needs to reconfigure this rate to
* support platforms requiring fixed emif clock rate.
*/
ret = da850_set_emif_clk_rate();
if (ret)
pr_warning("da850_evm_init: Failed to set rate of pll0_sysclk3/emif clock: %d\n",
ret);
ret = da850_register_edma(da850_edma_rsv);
if (ret)
pr_warning("da850_evm_init: edma registration failed: %d\n",
ret);
ret = davinci_cfg_reg_list(da850_i2c0_pins);
if (ret)
pr_warning("da850_evm_init: i2c0 mux setup failed: %d\n",
ret);
#if 0
platform_device_register(&da850_gpio_i2c);
#endif
ret = da8xx_register_i2c(0, &da850_evm_i2c_pdata);
if (ret) {
pr_warning("da850_evm_init: i2c0 mux setup failed: %d\n",
ret);
return;
}
ret = da8xx_register_watchdog();
if (ret)
pr_warning("da830_evm_init: watchdog registration failed: %d\n",
ret);
#if defined(CONFIG_DAVINCI_UART0_RS485)
/* UART0_TXD.RXD cannot be used since it is being used by MII_RXDx */
/* Support for UART 0 */
ret = davinci_cfg_reg_list(da850_uart0_pins);
if (ret)
pr_warning("da850_evm_init: UART 0 mux setup failed:"
" %d\n", ret);
/* TL-OMAPL138 as it requires the GP8[1] pin for UART0 flow control. */
ret = davinci_cfg_reg(DA850_GPIO8_1);
if (ret)
pr_warning("da850_evm_init:GPIO(8,1) mux setup "
"failed\n");
#endif
#if defined(CONFIG_DAVINCI_UART1_RS485)
/* TL-OMAPL138 as it requires the GP0[11] pin for UART1 flow control. */
ret = davinci_cfg_reg(DA850_GPIO0_11);
if (ret)
pr_warning("da850_evm_init:GPIO(0,11) mux setup "
"failed\n");
#endif
/* UART1_RXD cannot be used since it is being used by ADC SPI1_CS3 */
/* Support for UART 1 */
ret = davinci_cfg_reg_list(da850_uart1_pins);
if (ret)
pr_warning("da850_evm_init: UART 1 mux setup failed:"
" %d\n", ret);
if (HAS_MMC) {
ret = davinci_cfg_reg_list(da850_evm_mmcsd0_pins);
if (ret)
pr_warning("da850_evm_init: mmcsd0 mux setup failed:"
" %d\n", ret);
ret = gpio_request(DA850_MMCSD_CD_PIN, "MMC CD\n");
if (ret)
pr_warning("da850_evm_init: can not open GPIO %d\n",
DA850_MMCSD_CD_PIN);
gpio_direction_input(DA850_MMCSD_CD_PIN);
ret = gpio_request(DA850_MMCSD_WP_PIN, "MMC WP\n");
if (ret)
pr_warning("da850_evm_init: can not open GPIO %d\n",
DA850_MMCSD_WP_PIN);
gpio_direction_input(DA850_MMCSD_WP_PIN);
ret = da8xx_register_mmcsd0(&da850_mmc_config);
if (ret)
pr_warning("da850_evm_init: mmcsd0 registration failed:"
" %d\n", ret);
ret = da850_wl12xx_init();
if (ret)
pr_warning("da850_evm_init: wl12xx initialization"
" failed: %d\n", ret);
}
davinci_serial_init(&da850_evm_uart_config);
#if 0
if (have_imager())
i2c_add_driver(&pca9543a_driver);
#endif
i2c_register_board_info(1, da850_evm_i2c_devices,
ARRAY_SIZE(da850_evm_i2c_devices));
#if 0
/*
* shut down uart 0 and 1; they are not used on the board and
* accessing them causes endless "too much work in irq53" messages
* with arago fs
*/
__raw_writel(0, IO_ADDRESS(DA8XX_UART0_BASE) + 0x30);
#endif
if (HAS_MCASP) {
if (HAS_UART1_AFE)
pr_warning("WARNING: both McASP and UART1_AFE are "
"enabled, but they share pins.\n"
"\tDisable one of them.\n");
ret = davinci_cfg_reg_list(da850_evm_mcasp_pins);
if (ret)
pr_warning("da850_evm_init: mcasp mux setup failed: %d\n",
ret);
da8xx_register_mcasp(0, &da850_evm_snd_data);
}
ret = da8xx_register_pruss_uio(&da8xx_pruss_uio_pdata);
if (ret)
pr_warning("%s: pruss_uio initialization failed: %d\n",
__func__, ret);
ret = davinci_cfg_reg_list(da850_lcdcntl_pins);
if (ret)
pr_warning("da850_evm_init: lcdcntl mux setup failed: %d\n",
ret);
/* Handle board specific muxing for LCD here */
ret = davinci_cfg_reg_list(da850_evm_lcdc_pins);
if (ret)
pr_warning("da850_evm_init: evm specific lcd mux setup "
"failed: %d\n", ret);
ret = da850_lcd_hw_init();
if (ret)
pr_warning("da850_evm_init: lcd initialization failed: %d\n",
ret);
#if 0
sharp_lk043t1dg01_pdata.panel_power_ctrl = da850_panel_power_ctrl,
ret = da8xx_register_lcdc(&sharp_lk043t1dg01_pdata);
#endif
#ifdef CONFIG_DA850_SDI_LCDC
lcd_pdata = &lnnolux_at070tn83_pdata;
#endif
#ifdef CONFIG_DA850_SDI_DVI_VGA
lcd_pdata = &vga_monitor_pdata;
#endif
if (da850_lcdc_panel != NULL)
lcd_pdata = da850_lcdc_panel;
lcd_pdata->panel_power_ctrl = da850_panel_power_ctrl;
ret = da8xx_register_lcdc(lcd_pdata);
if (ret)
pr_warning("da850_evm_init: lcdc registration failed: %d\n",
ret);
ret = da8xx_register_rtc();
if (ret)
pr_warning("da850_evm_init: rtc setup failed: %d\n", ret);
ret = da850_evm_init_cpufreq();
if (ret)
pr_warning("da850_evm_init: cpufreq registration failed: %d\n",
ret);
ret = da8xx_register_cpuidle();
if (ret)
pr_warning("da850_evm_init: cpuidle registration failed: %d\n",
ret);
ret = da850_register_pm(&da850_pm_device);
if (ret)
pr_warning("da850_evm_init: suspend registration failed: %d\n",
ret);
da850_evm_setup_nor_nand();
if (HAS_VPIF_DISPLAY || HAS_VPIF_CAPTURE) {
ret = da850_register_vpif();
if (ret)
pr_warning("da850_evm_init: VPIF setup failed: %d\n",
ret);
}
if (HAS_VPIF_CAPTURE) {
ret = davinci_cfg_reg_list(da850_vpif_capture_pins);
if (ret)
pr_warning("da850_evm_init: VPIF capture mux failed:"
"%d\n", ret);
ret = da850_register_vpif_capture(&da850_vpif_capture_config);
if (ret)
pr_warning("da850_evm_init: VPIF capture setup failed:"
"%d\n", ret);
}
if (HAS_VPIF_DISPLAY) {
ret = davinci_cfg_reg_list(da850_vpif_display_pins);
if (ret)
pr_warning("da850_evm_init : VPIF capture mux failed :"
"%d\n", ret);
ret = da850_register_vpif_display(&da850_vpif_display_config);
if (ret)
pr_warning("da850_evm_init: VPIF display setup failed:"
"%d\n", ret);
}
ret = davinci_cfg_reg(DA850_GPIO2_12);
if (ret)
pr_warning("da850_evm_init: TS mux failed:"
" %d\n", ret);
ret = davinci_cfg_reg_list(da850_spi1_pins);
if (ret)
pr_warning("da850_evm_init : SPI1 mux failed :"
"%d\n", ret);
da850evm_spi_info[1].irq = gpio_to_irq(DA850_TS_INT);
if (HAS_ADC) {
#if defined(CONFIG_AD7606_IFACE_SPI) || defined(CONFIG_AD7606_IFACE_SPI_MODULE)
ret = davinci_cfg_reg_list(ad7606_spi_gpio_pins);
if (ret)
pr_warning("da850_evm_init : "
"ad7606_spi_gpio_pins mux failed :%d\n", ret);
else {
pr_warning("da850_evm_init:"
" UART1 module UART1_RXD cannot be used since"
" it is being used by ADC SPI1_CS3\n");
pr_warning("da850_evm_init:"
" McASP module McASP_AFSR cannot be used since"
" it is being used by ADC reset pin\n");
}
da850evm_spi_info[3].irq = gpio_to_irq(AD7606_SPI_BUSY);
#endif
#if defined(CONFIG_AD7606_IFACE_PARALLEL) ||\
defined(CONFIG_AD7606_IFACE_PARALLEL_MODULE)
da850_evm_setup_ad7606_par();
#endif
}
ret = da8xx_register_spi(1, da850evm_spi_info,
ARRAY_SIZE(da850evm_spi_info));
if (ret)
pr_warning("da850_evm_init: spi 1 registration failed: %d\n",
ret);
ret = da850_register_sata(DA850EVM_SATA_REFCLKPN_RATE);
if (ret)
pr_warning("da850_evm_init: sata registration failed: %d\n",
ret);
da850_evm_setup_mac_addr();
da850_evm_usb_init();
if (HAS_EHRPWM) {
if (rmii_en) {
ret = davinci_cfg_reg_list(da850_ehrpwm0_pins);
if (ret)
pr_warning("da850_evm_init:"
" ehrpwm0 mux setup failed: %d\n", ret);
else
mask = BIT(0) | BIT(1);
} else {
pr_warning("da850_evm_init:"
" eHRPWM module 0 cannot be used"
" since it is being used by MII interface\n");
mask = 0;
}
if (!HAS_LCD) {
ret = davinci_cfg_reg_list(da850_ehrpwm1_pins);
if (ret)
pr_warning("da850_evm_init:"
" eHRPWM module1 output A mux"
" setup failed %d\n", ret);
else
mask = mask | BIT(2);
} else {
pr_warning("da850_evm_init:"
" eHRPWM module1 outputA cannot be"
" used since it is being used by LCD\n");
}
if (!HAS_SPI) {
ret = davinci_cfg_reg(DA850_EHRPWM1_B);
if (ret)
pr_warning("da850_evm_init:"
" eHRPWM module1 outputB mux"
" setup failed %d\n", ret);
else
mask = mask | BIT(3);
} else {
pr_warning("da850_evm_init:"
" eHRPWM module1 outputB cannot be"
" used since it is being used by spi1\n");
}
da850_register_ehrpwm(mask);
}
if (HAS_ECAP_PWM) {
ret = davinci_cfg_reg(DA850_ECAP2_APWM2);
if (ret)
pr_warning("da850_evm_init:ecap mux failed:"
" %d\n", ret);
ret = da850_register_ecap(2);
if (ret)
pr_warning("da850_evm_init:"
" eCAP registration failed: %d\n", ret);
}
if (HAS_BACKLIGHT) {
#if 0
ret = da850_register_backlight(&da850evm_backlight,
&da850evm_backlight_data);
#endif
ret = platform_device_register(&da850evm_backlight);
if (ret)
pr_warning("da850_evm_init:"
" backlight device registration"
" failed: %d\n", ret);
}
if (HAS_ECAP_CAP) {
if (HAS_MCASP)
pr_warning("da850_evm_init:"
"ecap module 1 cannot be used "
"since it shares pins with McASP\n");
else {
ret = davinci_cfg_reg(DA850_ECAP1_APWM1);
if (ret)
pr_warning("da850_evm_init:ecap mux failed:%d\n"
, ret);
else {
ret = da850_register_ecap_cap(1);
if (ret)
pr_warning("da850_evm_init"
"eCAP registration failed: %d\n", ret);
}
}
}
da850_evm_tl_leds_init();
#if 1
/* TL138-EVM as it requires the GP0[8] pin at low for experiment box. */
ret = davinci_cfg_reg(DA850_GPIO0_8);
if (ret)
pr_warning("da850_evm_init:GPIO(0,8) mux setup failed\n");
ret = gpio_request(GPIO_TO_PIN(0, 8), "gpio0_8");
if (ret)
pr_warning("Fail to request gpio0_8 PIN.\n");
gpio_direction_output(GPIO_TO_PIN(0, 8), 0);
/* TL138-EVM as it requires the GP0[9] pin at low for experiment box. */
ret = davinci_cfg_reg(DA850_GPIO0_9);
if (ret)
pr_warning("da850_evm_init:GPIO(0,9) mux setup failed\n");
ret = gpio_request(GPIO_TO_PIN(0, 9), "gpio0_9");
if (ret)
pr_warning("Fail to request gpio0_9 PIN.\n");
gpio_direction_output(GPIO_TO_PIN(0, 9), 0);
#endif
#if 0
da850_evm_tl_keys_init();
#endif
#if defined(CONFIG_SERIAL_8250_EXTENDED)
da850_evm_setup_tl16754();
#endif
}