本章所涉及的函数如下:
1 static init_fnc_t init_sequence_f[] = { 2 arch_cpu_init, /* CPU相关初始化,若没有,则返回0即可 */ 3 initf_dm, /* 初始化驱动模型 */ 4 mark_bootstage, /* need timer, go after init dm */ 5 board_early_init_f, /* 初始化UART_IOMUX */ 6 timer_init, /* 初始化定时器 */ 7 board_postclk_init, /* Set VDDSOC to 1.175V */ 8 serial_init, /* 启动UART */ 9 init_func_i2c, /* 初始化I2C */ 10 11 setup_reloc, /* 代码重定位 */ 12 NULL, 13 };
arch_cpu_init() -> init_aips() /* 初始化Arm IP Bus,设置主机访问权限和优先级 */ -> writel(0x77777777, &aips1->mprot0); /* *0x0207C000 = 0x77777777,AIPSTZ1_MPR指定16个4bit,共8byte */ -> writel(0x77777777, &aips1->mprot1); /* *0x0207C004 = 0x77777777,上一行代码只写了4byte */ -> writel(0x00000000, &aips1->opacr0); /* *0x0207C040 = 0x00000000,AIPSTZ1_OPACR */ -> clear_mmdc_ch_mask() /* 清除MMDC通道屏蔽 */ -> reg = readl(&mxc_ccm->ccdr) & ~(1 << 16); -> writel(reg, &mxc_ccm->ccdr); /* 0x020C4004的bit[16] = 0,CCM_CCDR->MMDC_CH1_MASK */ -> init_bandgap() /* 让使用带隙的输出获得最佳的模拟块噪声性能 */ -> struct anatop_regs *anatop = 0x020C8000; -> struct fuse_bank1_regs *fuse = bank->fuse_regs; /* 0x021BC480 */ -> writel(0x8, &anatop->ana_misc0_set); /* *0x020C8154 = 0x8,CCM_ANALOG_MISC0_SET->REFTOP_SELFBIASOFF */ -> val = (readl(&fuse->mem0) >> 8) & 0x7; /* 0x021BC480的bit[10:8] */ -> writel(val << 4, &anatop->ana_misc0_set); /* 0x020C8154的bit[ 6:4],CCM_ANALOG_MISC0_SET->REFTOP_VBGADJ */ -> writel(readl(0x020B0000) | 0x3, 0x020B0000); /* 0x020B0000的bit[ 1:0] = 0b11 */ -> imx_set_wdog_powerdown(false); /* 关闭看门狗 */ -> writew(0, &wdog1->wmcr); /* *0x020BC008 = 0,WDOG1_WMCR */ -> writew(0, &wdog2->wmcr); /* *0x020C0008 = 0 */ -> writew(0, &wdog3->wmcr); /* *0x021E4008 = 0 */ -> init_src() /* 强制热复位源产生冷复位,以实现更可靠的重启 */ -> val = readl(&src_regs->scr) & ~(1 << 0); -> writel(val, &src_regs->scr); /* 0x020D8000的bit[0] = 0,SRC_SCR->warm_reset_enable */
在介绍此函数之前,我们需要先了解u-boot的驱动模型
驱动模型是u-boot为了提供统一框架和提升代码通用性所推出的模型,其架构如下图所示:

图中的root是一个虚拟设备,主要为其他设备提供挂载点,它会在initf_dm()函数中完成初始化
模型中主要涉及以下四个结构体
1. udevice:用于描述一个设备,由u-boot动态生成,类似于内核中的device
2. driver:设备对应的驱动,需要静态定义,类似于内核中的driver
3. uclass:共用同一个驱动的设备群组,由u-boot动态生成,并为上层调用提供统一接口
4. uclass_driver:uclass对应的驱动,需要静态定义,主要用于绑定uclass和udevice
上述四个结构体所构成的结构如下图所示:

root的driver和uclass_driver的静态定义如下:
1 /* This is the root driver - all drivers are children of this */ 2 struct driver _u_boot_list_2_driver_2_root_driver __aligned(4) 3 __attribute__((unused, section(".u_boot_list_2_driver_2_root_driver"))) = 4 { 5 .name = "root_driver", 6 .id = UCLASS_ROOT, 7 .priv_auto_alloc_size = sizeof(struct root_priv), 8 } 9 10 /* This is the root uclass */ 11 struct uclass_driver _u_boot_list_2_uclass_2_root __aligned(4) 12 __attribute__((unused, section(".u_boot_list_2_uclass_2_root"))) = 13 { 14 .name = "root", 15 .id = UCLASS_ROOT, 16 }
initf_dm()函数的执行过程可分为如下四部分:
1. 准备操作,如设置uclass和udevice存放的地址
initf_dm() -> ret = dm_init_and_scan(true); -> ret = dm_init(); -> INIT_LIST_HEAD(&(((gd_t *)gd)->uclass_root)); /* uclass链表存放在gd->uclass_root中 */ -> device_bind_by_name(NULL, 0, &info, &((gd_t*)gd->dm_root)); /* root的udevice存放在gd->dm_root中 */ -> struct driver *drv = lists_driver_lookup_name("root_driver"); /* 查找名为"root_driver"的driver */ -> struct driver *drv = ll_entry_start(struct driver, driver); /* driver起始地址:.u_boot_list_2_driver_1 */ -> ll_entry_end(struct driver, driver); /* driver结束地址:.u_boot_list_2_driver_3 */ -> return entry; /* 匹配"root_driver"和driver->name,成功则返回driver */
2. 设置root uclass
device_bind_by_name(NULL, 0, &info, &((gd_t*)gd->dm_root)); -> return device_bind(NULL, drv, "root_driver" (void *)info->platdata, -1, (gd_t *)gd->dm_root); -> ret = uclass_get(drv->id, &uc); -> return uclass_add(drv->id, uc); /* 构造一个新的uclass */ -> struct uclass_driver *uc_drv = lists_uclass_lookup(drv->id); -> uclass = ll_entry_start(struct uclass_driver, uclass); /* uclass_driver起始地址:.u_boot_list_2_uclass_1 */ -> return entry; /* 匹配driver->uclass_id和uclass_driver->uclass_id */ -> uc->uc_drv = uc_drv; /* uclass的uc_drv指向uclass_driver */ -> INIT_LIST_HEAD(&uc->sibling_node); -> INIT_LIST_HEAD(&uc->dev_head); -> list_add(&uc->sibling_node, &((gd_t *)gd->uclass_root)); /* 将uclass的sibling_node存放到gd->uclass_root链表中 */ -> ret = uc_drv->init(uc); /* 调用uclass_driver的init函数,此处为空 */
3. 设置root udevice
device_bind_by_name(NULL, 0, &info, &((gd_t*)gd->dm_root)); -> return device_bind(NULL, drv, "root_driver" (void *)info->platdata, -1, (gd_t *)gd->dm_root); -> dev = calloc(1, sizeof(struct udevice)); /* 构造一个新的udevice */ -> INIT_LIST_HEAD(&dev->sibling_node); -> INIT_LIST_HEAD(&dev->uclass_node); -> INIT_LIST_HEAD(&dev->devres_head); -> dev->name = name; /* "root_driver" */ -> dev->driver = drv; /* 设置udevice的driver */ -> dev->uclass = uc; /* 设置udevuce所属的uclass */ -> ret = uclass_bind_device(dev); -> list_add_tail(&dev->uclass_node, &uc->dev_head); /* 将udevice的uclass_node存放到uclass的dev_head链表中 */ -> *((gd_t *)gd->dm_root) = dev; /* 将udevice的数据存放至gd->dm_root中 */
设置完成后的关系如下图:

4. 设置其他外设的uclass和udevice
ret = dm_init_and_scan(true); -> ret = dm_init(); -> ret = device_probe((gd_t *)gd->dm_root); -> drv = dev->driver; -> ret = uclass_pre_probe_device(dev); -> struct uclass_driver *uc_drv = dev->uclass->uc_drv; -> ret = uc_drv->pre_probe(dev); /* uclass_driver->pre_probe(dev) */ -> ret = drv->probe(dev); /* driver->probe(dev) */ -> ret = uclass_post_probe_device(dev); -> uc_drv->post_probe(dev); /* uclass_driver->post_probe(dev) */ -> ret = dm_scan_platdata(true); -> ret = lists_bind_drivers((gd_t *)gd->dm_root, true); -> ret = device_bind_by_name(NULL, true, &info, &dev); /* 通过driver_info->name设置其他uclass和udevice */ -> ret = dm_scan_other(true); /* 空函数 */
根据以上四部分代码,可以确定initf_dm()函数所做的事情有:
1. 根据设备名查到到对应的driver
2. 匹配位于.u_boot_list_2_driver_[1-3]段中的driver id和位于.u_boot_list_2_uclass_[1-3]段中的uclass_driver id
3. 初始化uclass链表,root uclass为链表头
4. 创建设备对应的udevice,root udevice并存放在gd->dm_root中
5. 调用uclass_driver和driver的probe()函数
6. 调用device_bind_by_name()函数重复第1-4点(没有第5点)
u-boot.map中 .u_boot_list_2_driver_[1-3]段 和 .u_boot_list_2_uclass_[1-3]段 定义如下:
1 .u_boot_list_2_driver_1 2 0x87860c54 0x0 drivers/built-in.o 3 .u_boot_list_2_driver_2_imx_thermal 4 0x87860c54 0x44 drivers/built-in.o 5 0x87860c54 _u_boot_list_2_driver_2_imx_thermal 6 .u_boot_list_2_driver_2_root_driver 7 0x87860c98 0x44 drivers/built-in.o 8 0x87860c98 _u_boot_list_2_driver_2_root_driver 9 .u_boot_list_2_driver_3 10 0x87860cdc 0x0 drivers/built-in.o 11 12 .u_boot_list_2_uclass_1 13 0x87860da4 0x0 drivers/built-in.o 14 .u_boot_list_2_uclass_2_disk 15 0x87860da4 0x48 drivers/built-in.o 16 0x87860da4 _u_boot_list_2_uclass_2_disk 17 .u_boot_list_2_uclass_2_root 18 0x87860dec 0x48 drivers/built-in.o 19 0x87860dec _u_boot_list_2_uclass_2_root 20 .u_boot_list_2_uclass_2_thermal 21 0x87860e34 0x48 drivers/built-in.o 22 0x87860e34 _u_boot_list_2_uclass_2_thermal 23 .u_boot_list_2_uclass_3 24 0x87860e7c 0x0 drivers/built-in.o 25 0x87860e7c . = ALIGN (0x4)
其中,imx_thermal的driver和uclass_driver定义如下:
1 UCLASS_DRIVER(thermal) = { 2 .id = UCLASS_THERMAL, 3 .name = "thermal", 4 }; 5 6 U_BOOT_DRIVER(imx_thermal) = { 7 .name = "imx_thermal", 8 .id = UCLASS_THERMAL, 9 .ops = &imx_thermal_ops, 10 .probe = imx_thermal_probe, 11 .priv_auto_alloc_size = sizeof(struct thermal_data), 12 .flags = DM_FLAG_PRE_RELOC, 13 };
mark_bootstage() -> bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_F, "board_init_f"); -> bootstage_add_record(id, name, 0, timer_get_boot_us()); -> struct bootstage_record *rec = &record[id]; /* 1 */ -> rec->time_us = timer_get_boot_us(); -> rec->name = "board_init_f"; -> rec->flags = 0; -> rec->id = BOOTSTAGE_ID_START_UBOOT_F; -> show_boot_progress(flags & BOOTSTAGEF_ERROR ? -id : id); /* 空函数 */
board_early_init_f() /* 一般用于初始化时钟树并设置GPIO功能 */ -> setup_iomux_uart(); -> imx_iomux_v3_setup_multiple_pads(uart1_pads, ARRAY_SIZE(uart1_pads)); -> imx_iomux_v3_setup_pad(*p); -> u32 mux_ctrl_ofs = (pad & 0xfff); /* mux_ctrl_ofs及其其他变量都可以与IOMUX_PAD()对应 */ -> u32 lpsr = (pad & MUX_MODE_LPSR) >> MUX_MODE_SHIFT; /* lpsr = 0 */ -> __raw_writel(mux_mode, base + mux_ctrl_ofs); /* base = 0x020E0000 */ -> __raw_writel(sel_input, base + sel_input_ofs); -> __raw_writel(pad_ctrl, base + pad_ctrl_ofs);
其中主要变量定义或结果如下:
1 static iomux_v3_cfg_t const uart1_pads[] = { 2 /* IOMUX_PAD(0x0310, 0x0084, 0, 0x0000, 0, 0) = 0x0084 | (0x0310 << 12) = 0x00310084 */ 3 /* UART_PAD_CTRL = (1 << 12 | 1 << 13 | 2 << 14 | 2 << 6 | 6 << 3 | 1 << 0 | 1 << 16) = 0x0001b0b1 4 * MUX_PAD_CTRL(UART_PAD_CTRL) = 0x0001b0b1 << 42 5 */ 6 /* 0x00310084 | (0x0001b0b1 << 42) */ 7 MX6_PAD_UART1_TX_DATA__UART1_DCE_TX | MUX_PAD_CTRL(UART_PAD_CTRL), 8 MX6_PAD_UART1_RX_DATA__UART1_DCE_RX | MUX_PAD_CTRL(UART_PAD_CTRL), 9 }; 10 11 /* MX6_PAD_UART1_TX_DATA */ 12 /* IOMUX_PAD(pad_ctrl_ofs, mux_ctrl_ofs, mux_mode, sel_input_ofs, sel_input, pad_ctrl) 13 * IOMUX_PAD(0x0310, 0x0084, 0, 0x0000, 0, 0) 14 * = 0x0084 | (0x0310 << 12) = 0x00310084 15 */ 16 /* mux_ctrl_ofs = pad & 0xfff = 0x084 17 * mux_mode = (pad & (0x3f << 36)) >> 36 = 0 18 * sel_input_ofs = (pad & (0xfff << 24)) >> 24 = 0 19 * sel_input = (pad & (0xf << 60)) >> 60 = 0 20 * pad_ctrl_ofs = (pad & (0xfff << 12)) >> 12 = 0x310 21 * pad_ctrl = (pad & (0x3ffff << 42)) >> 42 = 0 22 */ 23 u32 mux_ctrl_ofs = (pad & MUX_CTRL_OFS_MASK) >> MUX_CTRL_OFS_SHIFT; 24 u32 mux_mode = (pad & MUX_MODE_MASK) >> MUX_MODE_SHIFT; 25 u32 sel_input_ofs = (pad & MUX_SEL_INPUT_OFS_MASK) >> MUX_SEL_INPUT_OFS_SHIFT; 26 u32 sel_input = (pad & MUX_SEL_INPUT_MASK) >> MUX_SEL_INPUT_SHIFT; 27 u32 pad_ctrl_ofs = (pad & MUX_PAD_CTRL_OFS_MASK) >> MUX_PAD_CTRL_OFS_SHIFT; 28 u32 pad_ctrl = (pad & MUX_PAD_CTRL_MASK) >> MUX_PAD_CTRL_SHIFT; 29 30 /* lpsr = (pad & (0x20 << 36)) >> 36 = 0,取第41位后右移36位 */ 31 u32 lpsr = (pad & MUX_MODE_LPSR) >> MUX_MODE_SHIFT;
timer_init() -> static struct mxc_gpt *cur_gpt = (struct mxc_gpt *)GPT1_BASE_ADDR; /* GPT1_BASE_ADDR = 0x02098000 */ -> __raw_writel(GPTCR_SWR, &cur_gpt->control); /* *0x02098000 = 1 << 15 */ -> __raw_writel(0, &cur_gpt->control); /* 循环100次写0 */ -> i = __raw_readl(&cur_gpt->control); -> i &= ~GPTCR_CLKSOURCE_MASK; /* 7 << 6 */ -> i |= GPTCR_CLKSOURCE_OSC | GPTCR_TEN | GPTCR_24MEN; /* 5 << 6 | 1 << 0 | 1 << 10 */ -> __raw_writel((7 << GPTPR_PRESCALER24M_SHIFT), &cur_gpt->prescaler); /* *0x02098004 = 7 << 12 */ -> __raw_writel(i, &cur_gpt->control);
serial_init() -> return get_current()->start(); -> struct serial_device *dev = default_serial_console(); -> return &mxc_serial_drv; -> mxc_serial_drv.start = mxc_serial_init, -> UART寄存器设置
UART寄存器设置如下:
1 static int mxc_serial_init(void) 2 { 3 __REG(UART_PHYS + UCR1) = 0x0; /* *0x02020080 = 0 */ 4 __REG(UART_PHYS + UCR2) = 0x0; /* *0x02020084 = 0 */ 5 6 while (!(__REG(UART_PHYS + UCR2) & UCR2_SRST)); /* !(*0x02020084 & 1) */ 7 8 __REG(UART_PHYS + UCR3) = 0x0704 | UCR3_ADNIMP; /* *0x02020088 = 0x784 */ 9 __REG(UART_PHYS + UCR4) = 0x8000; /* *0x02020084 = 0x8000 */ 10 __REG(UART_PHYS + UESC) = 0x002b; /* *0x0202008c = 0x002b */ 11 __REG(UART_PHYS + UTIM) = 0x0; /* *0x020200a0 = 0 */ 12 13 __REG(UART_PHYS + UTS) = 0x0; /* *0x020200b4 = 0 */ 14 15 serial_setbrg(); /* 1. 获取uart时钟 */ 16 /* 2. *0x02020090 = (4 << 7) | (2 << 10) | 1 */ 17 /* 3. *0x020200a4 = 0xf */ 18 /* 4. *0x020200a8 = clk / (2 * 115200); */ 19 /* *0x02020084 = (1 << 5) | (1 << 14) | (1 << 1) | (1 << 2) | 1 */ 20 __REG(UART_PHYS + UCR2) = UCR2_WS | UCR2_IRTS | UCR2_RXEN | UCR2_TXEN | UCR2_SRST; 21 /* *0x02020080 = 1 */ 22 __REG(UART_PHYS + UCR1) = UCR1_UARTEN; 23 24 return 0; 25 }
init_func_i2c() -> i2c_init_all(); -> i2c_init_board(); /* 空函数 */ -> i2c_set_bus_num(CONFIG_SYS_SPD_BUS_NUM); /* CONFIG_SYS_SPD_BUS_NUM = 0 */ -> max = ll_entry_count(struct i2c_adapter, i2c); /* .u_boot_list_2_i2c_1到.u_boot_list_2_i2c_3 */ -> gd->cur_i2c_bus = bus; /* gd->cur_i2c_bus = 0 */ -> i2c_init_bus(bus, I2C_ADAP->speed, I2C_ADAP->slaveaddr); /* I2C_ADAP = i2c_get_adapter(0):后面的_u_boot_list_2_i2c_mxc0 */ -> I2C_ADAP->init(I2C_ADAP, speed, slaveaddr); /* drivers/i2c/mxc_i2c.c */ -> mxc_i2c_init(_u_boot_list_2_i2c_mxc0, CONFIG_SYS_MXC_I2C1_SPEED, CONFIG_SYS_MXC_I2C1_SLAVE) -> bus_i2c_init(adap->hwadapnr, speed, slaveaddr, NULL, NULL); /* 0, 100000, 0, */ -> ret = enable_i2c_clk(1, 0); -> mask = 3 << (6 + (0 << 1)); -> reg = __raw_readl(&imx_ccm->CCGR2); /* reg = 0xffffffff */ -> reg |= mask; /* CCM->CCGR2 |= 3 << 6 */ -> __raw_writel(reg, &imx_ccm->CCGR2); -> bus_i2c_set_bus_speed(&mxc_i2c_buses[0], 100000); -> u8 clk_idx = i2c_imx_get_clk(i2c_bus, 100000); -> i2c_clk_rate = mxc_get_clock(MXC_I2C_CLK); /* i2c_clk_rate = 66000000 */ -> div = (i2c_clk_rate + 100000 - 1) / 100000; /* div = 660 */ -> for (clk_div = 0; i2c_clk_div[clk_div][0] < div; clk_div++) ; /* clk_div = 36 */ -> u8 idx = i2c_clk_div[clk_idx][1]; /* { 768, 0x39 } */ -> writeb(idx, base + (IFDR << 2)); /* *(0x21a0000 + (1 << 2)) = 0x39 */ -> writeb(I2CR_IDIS, base + (I2CR << 2)); /* *(0x21a0000 + (2 << 2)) = (0 << 7) */ -> writeb(0, base + (I2SR << 2)); /* *(0x21a0000 + (3 << 2)) = 0 */
在读者跟随上面的调用过程自己探索时,可能会发现u-boot并没有直接定义struct i2c_adapter _u_boot_list_2_i2c_mxc0
它在u-boot中是通过宏定义间接定义的,如下:
1 include/i2c.h 2 #define U_BOOT_I2C_ADAP_COMPLETE(_name, _init, _probe, _read, _write, 3 _set_speed, _speed, _slaveaddr, _hwadapnr) 4 ll_entry_declare(struct i2c_adapter, _name, i2c) = 5 U_BOOT_I2C_MKENT_COMPLETE(_init, _probe, _read, _write, 6 _set_speed, _speed, _slaveaddr, _hwadapnr, _name); 7 8 include/linker_lists.h 9 #define ll_entry_declare(_type, _name, _list) 10 _type _u_boot_list_2_##_list##_2_##_name __aligned(4) 11 __attribute__((unused, 12 section(".u_boot_list_2_"#_list"_2_"#_name))) 13 14 include/i2c.h 15 #define U_BOOT_I2C_MKENT_COMPLETE(_init, _probe, _read, _write, 16 _set_speed, _speed, _slaveaddr, _hwadapnr, _name) 17 { 18 .init = _init, 19 .probe = _probe, 20 .read = _read, 21 .write = _write, 22 .set_bus_speed = _set_speed, 23 .speed = _speed, 24 .slaveaddr = _slaveaddr, 25 .init_done = 0, 26 .hwadapnr = _hwadapnr, 27 .name = #_name 28 }; 29 30 drivers/i2c/mxc_i2c.c 31 U_BOOT_I2C_ADAP_COMPLETE(mxc0, mxc_i2c_init, mxc_i2c_probe, 32 mxc_i2c_read, mxc_i2c_write, 33 mxc_i2c_set_bus_speed, 34 CONFIG_SYS_MXC_I2C1_SPEED/* 100000 */, 35 CONFIG_SYS_MXC_I2C1_SLAVE/* 0 */, 0) 36 37 变成 38 struct i2c_adapter _u_boot_list_2_i2c_mxc0 __aligned(4) 39 __attribute__((unused, section(".u_boot_list_2_i2c_2_mxc0))) = 40 { 41 .init = mxc_i2c_init, 42 .probe = mxc_i2c_probe, 43 .read = mxc_i2c_read, 44 .write = mxc_i2c_write, 45 .set_bus_speed = mxc_i2c_set_bus_speed, 46 .speed = CONFIG_SYS_MXC_I2C1_SPEED, /* 100000 */ 47 .slaveaddr = CONFIG_SYS_MXC_I2C1_SLAVE, /* 0 */ 48 .init_done = 0, 49 .hwadapnr = 0, 50 .name = "mxc0" 51 };
setup_reloc() /* 拷贝gd结构体至new_gd地址 */ -> memcpy(gd->new_gd, (char *)gd, sizeof(gd_t));
3、init_sequence_f[]中驱动模型和外设相关初始化
原文:https://www.cnblogs.com/Lioker/p/13218865.html