1. 程式人生 > >Linux啟動過程分析(十一)-----customize_machine(註冊開發板相關硬體資訊)

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
}