2018/05/09 10:49 zhoulinhua@2018-05-10
一、系统分区
name address size
bootstrap 0x0 64k
u-boot 0x10000 640k
env 0xb0000 192k
dtb 0xe0000 128k
uImage 0x100000 4M
rootfs 0x500000 -
spi0的设备树如下:at91sam9x5ek.dtsi
spi0: spi@f0000000 {
status = "okay"; /* conflict with mmc1 */
cs-gpios = <&pioA 14 0>, <0>, <0>, <0>;
m25p80@0 {
compatible = "jedec,spi-nor";
spi-max-frequency = <50000000>;
reg = <0>;
#address-cells = <1>;
#size-cells = <1>;
partition@bootstrap {
label = "bootstrap";
reg = <0x0 0x10000>;
};
partition@uboot {
label = "uboot";
reg = <0x10000 0xA0000>;
};
partition@env {
label = "env";
reg = <0xb0000 0x30000>;
};
partition@dtb {
label = "dtb";
reg = <0xE0000 0x20000>;
};
partition@kernel {
label = "kernel";
reg = <0x100000 0x400000>;
};
partition@rootfs {
label = "rootfs";
reg = <0x500000 0xb00000>;
};
};
注意:
分区大小必须是erase sectors size的整数倍
说明:对于不支持设备树的系统u-boot通过machid传递到linux内核进行驱动匹配,支持设备树的系统通过解析dtb进行驱动匹配。dtb必须烧写到flash的指定位置,然后加载到内存空间进行执行。不支持设备树的系统中如果没有传递正确的machid内核启动不来,同样的支持设备树的系统必须在指定位置烧录dtb,不然内核也不能正常启动;
二、u-boot调试
1启动配置
u-boot-at91\include\configs\at91sam9x5ek.h
1)配置bootm
#define CONFIG_BOOTCOMMAND "sf probe 0; " \
"sf read 0x22000000 0x100000 0x400000; " \
"sf read 0x21000000 0xE0000 0x20000; " \
"bootm 0x22000000 - 0x21000000"
sf read 0x22000000 0x100000 0x400000;
从flash的0x100000位置读取0x400000(4M)到内存0x22000000处;内核加载
sf read 0x21000000 0xE0000 0x20000
从flash的0xE0000位置读取0x10000(64k)到内存0x21000000处;设备树加载
bootm 0x22000000 - 0x21000000
设置内核内存加载地址为:0x22000000
设置生成树内存加载地址为:0x21000000
2)配置bootargs
#define CONFIG_BOOTARGS \
"console=ttyS0,115200 earlyprintk " \
"root=/dev/mtdblock5 init=/linuxrc rootfstype=jffs2 rw"
3)配置spi flash参数
修改头文件u-boot-at91/include/configs/at91sam9x5ek.h
/*
#define CONFIG_ENV_OFFSET 0x5000
#define CONFIG_ENV_SIZE 0x3000
#define CONFIG_ENV_SECT_SIZE 0x1000
*/
#define CONFIG_ENV_OFFSET 0xb0000
#define CONFIG_ENV_SIZE 0x30000
#define CONFIG_ENV_SECT_SIZE 0x10000
2.u-boot增加n25128a SPI_FLASH支持;
Device Drivers --->
SPI Flash Support --->
[*] STMicro SPI flash support
备注:调试上述步骤之后u-boot已经能正常启动内核;
3.Uboot网口驱动调试
1)驱动分析:
board_r.c
board_init_r();
init_sequence_r[ ]={
initr_net;
};
initr_net() :
static int initr_net(void)
{
puts("Net: ");
eth_initialize();
/*zhoulinhua@2018-08-15,init bcm53262 spi control interface*/
spi_bcm53262_probe(1, 0,30000000,3);
#if defined(CONFIG_RESET_PHY_R)
debug("Reset Ethernet PHY\n");
reset_phy();
#endif
return 0;
}
eth-uclass.c
int eth_initialize();
2)device driver mode
uclass_driver:
UCLASS_DRIVER(eth) = {
.name = "eth",
.id = UCLASS_ETH,
.post_bind = eth_post_bind,
.pre_unbind = eth_pre_unbind,
.post_probe = eth_post_probe,
.pre_remove = eth_pre_remove,
.priv_auto_alloc_size = sizeof(struct eth_uclass_priv),
.per_device_auto_alloc_size = sizeof(struct eth_device_priv),
.flags = DM_UC_FLAG_SEQ_ALIAS,
};
定义eth的dts节点:
macb0: ethernet@f802c000 {
compatible = "cdns,at91sam9260-macb", "cdns,macb";
reg = <0xf802c000 0x100>;
interrupts = <24 IRQ_TYPE_LEVEL_HIGH 3>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_macb0_rmii>;
clocks = <&macb0_clk>, <&macb0_clk>;
clock-names = "hclk", "pclk";
status = "disabled";
};
定义设备驱动:
U_BOOT_DRIVER(eth_macb) = {
.name = "eth_macb",
.id = UCLASS_ETH,
.of_match = macb_eth_ids,
.ofdata_to_platdata = macb_eth_ofdata_to_platdata,
.probe = macb_eth_probe,
.remove = macb_eth_remove,
.ops = &macb_eth_ops,
.priv_auto_alloc_size = sizeof(struct macb_device),
.platdata_auto_alloc_size = sizeof(struct eth_pdata),
};
static const struct udevice_id macb_eth_ids[] = {
{ .compatible = "cdns,macb" },
{ .compatible = "cdns,at91sam9260-macb" },
{ .compatible = "atmel,sama5d2-gem" },
{ .compatible = "atmel,sama5d3-gem" },
{ .compatible = "atmel,sama5d4-gem" },
{ }
};
lists_bind_fdt();
ret = driver_check_compatible(blob, offset, entry->of_match, &id);
static int eth_post_probe(struct udevice *dev)
3)BCM53262 SPI管理控制驱动
三、内核调试
1.设备驱动加载过程
1)unflatten_device_tree()函数:device加载通过解析设备树
a.函数调用:start_kernel() --> setup_arch() --> unflatten_device_tree()
b.在执行完unflatten_device_tree()后,DTS节点信息被解析出来,保存到of_allnodes链表中of_allnodes会在后面被用到。
2)of_platform_populate()函数:将device转化为platform device
a.函数调用:start_kernel->rest_init->kernel_init->kernel_init_freeable->do_basic_setup->do_initcalls: arch_initcall(customize_machine)-->customize_machine()-->{init_machine():callback:at91rm9200_dt_device_init()} 或者调用of_platform_default_populate()-->of_platform_populate()
b.解析device转化为platform device(平台总线设备驱动模型的设备)dts中需要加载为device的device node转为platform device,而这个过程是交给(platform.c)of_platform_populate()来完成的。
3)of_platform_populate()功能:
a.根据所选择的device node根节点,来递归式的遍历从root node开始以下的所有device node
b.将device node转变为一个platform_device并将其作为device 通过device_add到内核
c.可以判断哪些device node是需要转为device到内核的。
d. 如果传入的root=NULL,则表明从dts的\节点开始逐一的递归处理,否则根据所选择的device node作为root,做递归处理。
e. struct of_device_id *matches,该match table重点是后续节点递归处理时,需要和该table mach后才可以继续递归处理。
DTB解析过程:
of_platform_populate()-->of_platform_bus_create()-->of_platform_device_create_pdata()-->of_device_alloc()
2.内核支持增加SPI_FLASH支持;spi-atmel.c(spi bus driver)、spi.c(spi nor chip)
platform_macth-->atmel_spi_probe()-->devm_spi_register_master()-->spi_register_master()
在linux启动后,会解析这个dts文件,当进行spi master driver注册时,会进行of_match,之后就调用master driver下的atmel_spi_probe函数
atmel_spi_probe函数中会调用devm_spi_register_master然后调用spi_register_master函数.我们知道有spi master只是有总线的驱动了,那一定还有spi相关的device,没错,spi device就是在spi_register_master中来完成的,我们也可以通过上面的spi master 的dts代码看到,在这个spi bus 下只挂了一个spi nor flash.在spi_register_master中会对master下所挂的spi nor device进行add:
device: of_register_spi_devices(master)-->of_register_spi_device()
driver: atmel_spi_probe-->dev_spi_register_master-->spi_register_master
ARCH:
After this framework, the layer is like: MTD
------------------------ SPI NOR framework spi-nor.c
------------------------ m25p80 ,m25p80.c
------------------------ SPI bus driver spi.c
------------------------ SPI NOR chip spi-atmel.c
说明:
This framework just adds a new layer between the MTD and the SPI bus driver. With this new layer, the SPI NOR controller driver does not depend on the m25p80 code anymore.
四、修改MTD支持spi-nor
1.修改MTD支持spi-nor
cd linux-at91
make menuconfig
1)添加MTD对SPI-NOR的支持
File systems --->
---Device Drivers --->
<*> Memory Technology Device (MTD) support --->
<*> SPI-NOR device support --->
--- SPI-NOR device support
[*] Use small 4096 B erase sectors
注意:在选择SPI-NOR device support之后 [*] Use small 4096 B erase sectors会默认勾选了,这里要去掉不然挂载jffs2根文件系统会出错;导致根文件系统无法挂载;
修改之后的配置如下:
File systems --->
---Device Drivers --->
<*> Memory Technology Device (MTD) support --->
<*> SPI-NOR device support --->
--- SPI-NOR device support
< > Mediatek MT81xx SPI NOR flash controller
[ ] Use small 4096 B erase sectors
2)选择SPI-NOR Flash chips
---Device Drivers --->
<*> Memory Technology Device (MTD) support --->
Self-contained MTD device drivers --->
<*> Support most SPI Flash chips (AT26DF, M25P, W25X, ...)
2.增加is25lp128 Flash支持
spi-nor.c
static const struct flash_info spi_nor_ids[] = {
/*zhoulinhua@2018-06-15,spi flash support for ISSI*/
{ "is25lp128", INFO(0x9d6018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) },
}
五、增加内核对jffs文件系统的支持
1.增加内核对文件系统的支持
在内核目录下执行:output/build/linux-linux4sam_5.7
make menuconfig
File systems --->
--- Miscellaneous filesystems
<*> Journalling Flash File System v2 (JFFS2) support
六、制作jffs2根文件系统
制作工具以及命令如下:
/workspace/at91/buildroot-at91/output/host/sbin/mkfs.jffs2 -e 0x10000 -l -d /workspace/at91/buildroot-at91/output/target -o /workspace/at91/buildroot-at91/output/images/rootfs.jffs2
你可以自己创建文件,然后下载busybox进行创建,这里我在buildroot中创建jffs2根文件系统;