zynq ps linux 学习笔记一
zynq ps启动流程
boot rom芯片自带的,无法更改,fsbl(first stage boot loader),zynq启动第一阶段的加载程序,经过了fsbl这一阶段,后面系统才能够运行裸奔程序或者是引导操作系统的u-boot,它进行了一些时钟、ddr等模块的初始化,他是vivado中配置zynq芯片时生成的。硬件的bootrom内部也有一个自带的fsbl,如果是jtag调试的话,bootrom会自动使用这个默认的fsbl。然后是uboot启动,这个我没有做过任何更改,一般是使用固定的config文件,例如zedboard的。uboot会给内核传参,修改内核的bootargs属性,设备树也可以给内核传入bootargs属性。uboot在传入bootargs时会检查以哪种文件系统启动,默认的是ramdisk,用内存来模拟硬盘的文件系统,不过我们使用的是SD卡的第二个分区,即需要更改uboot传入的参数,然后这个参数会自动由uboot写入到外部的flash中,然后再次启动时不做更改则会自动传入这些参数。其中fsbl和fpga的代码即bit文件以及uboot编译生成后的uboot.elf,这三个文件会一起编译生成BOOT.bin文件。
zynq 网卡驱动
zynq在使用网卡时遇到过bug,至今尚未解决。zynq在uboot和kernel两个地方都会配置网卡驱动。在uboot中会配置phy寄存器、检查设备以及配置mac地址等。在linux内核中,调用macb_probe,注册phy和mdio驱动等。
zynq gpio
zynq7020的gpio分为了54个MIO和192个EMIO(64个输入和128个输出),其中MIO是ps这边的,而EMIO是pl这边的,不过EMIO内部和ps端相连,而MIO是能直接拉出到外部引脚上。GPIO控制器基址0xE000A000,设备树描述如下:
gpio0: gpio@e000a000 {
compatible = "xlnx,zynq-gpio-1.0";
#gpio-cells = <2>;
clocks = <&clkc 42>;
gpio-controller;
interrupt-parent = <&intc>;
interrupts = <0 20 4>;
reg = <0xe000a000 0x1000>;
};
进入到/sys/class/gpio目录下可以看到只有一个gpiochip906,代表它的第一个gpio是从906开始的,前面54个为MIO,如果要操作EMIO的第一个引脚,则文件描述符计算为:906+54=960
zynq gpio中断
zynq的gic控制器结构如图所示:
CPU0和1分别代表两个arm-A9的和。如上所示,GIC控制器的中断主要有三种:
- SPI:共享外设中断,它发出的中断能给所有处理器,由各种IO和存储器的控制器产生
- PPI:私有外设中断,它发出的中断只给固定某个处理器,中断来源于PL全局定时器、专用定时器等
- SGI:软件中断,用于CPU核之间的通讯中断
具体的中断来源接口如下所示:
SGI中断
CPU0和1都能产生SGI中断,只需要操作ICDSGIR寄存器写入指定中断号就可以了,并且可以指定目标CPU,让自己或者另外的CPU接收到该中断。所有的SGI中断都是边沿触发且不能更改的
PPI中断
从上表可以看到,中断号1 6-16保留,而27-31代表了5个私有外设中断
SPI中断
中断号32位以上的为SPI中断。
中断号
gic中断控制器设备树描述如下:
intc: interrupt-controller@f8f01000 {
compatible = "arm,cortex-a9-gic";
#interrupt-cells = <3>;
interrupt-controller;
reg = <0xF8F01000 0x1000>,
<0xF8F00100 0x100>;
};
对于#interrupt-cells = <3>,很多处理器设备树都是3,如何指定一个中断:
- 指定它的类别,SPI、PPI还是SGI
- 指定是具体的哪一个中断
- 指定触发类型,电平触发还是边沿触发
所以GIC控制器的一个中断常常需要用三个cell来表示,第一个指定类别,第二个指定中断号,第三个指定中断触发方式。在vivado中选择pl和ps之间的通讯方式,编译生成的设备树如下:
irq: irq@0{
compatible = "hello,irq0";
interrupt-parent = <&intc>;
interrupts = <0 29 2>, <0 30 2>, <0 31 2>, <0 32 2>;
};
第一个0则代表了SPI方式,29则代表了spi中的第29组中断,它的实际中断号是29+32=61。