配合食用“ZYNQ7020--AMP下裸机程序开发 <2>”
CPU0运行petalinux,CPU1运行裸机程序。CPU0启动后,可动态加载CPU1程序。
测试:通过分别加载两个程序来验证是否成功。
CPU1共有两个程序:一个控制两路LED灯闪烁,另一个控制两路LED按照0-1-2-3二进制显示。
详细配置过程参照《Z7-Lite 系列教程 之 Linux 系统篇》第5章和第9章。
工程文件编译后,导出硬件描述文件至SDK。
创建工程
petalinux-create --type project --template zynq --name ampgpio
指定工作目录
petalinux-config --get-hw-description=.
主菜单 ---> DTG Settings ---> Kernel Bootargs,取消 generate boot args automatically,手动填入如下信息:
console=ttyPS0,115200 earlyprintk maxcpus=1
保存退出
主要用于自动初始化下axi-gpio相关内容,配置内核。
petalinux-config -c kernel
等待弹窗,此处无需修改配置,直接保存,退出即可。
路径:工程目录 ---> project-spec ---> meta-user ---> recipes-bsp ---> device-tree ---> files ---> system-user.dtsi 添加如下内容:
- /include/ "system-conf.dtsi"
- / {
- reserved-memory {
- #address-cells = <1>;
- #size-cells = <1>;
- ranges;
-
- reserved: buffer@0x18000000 { //512-384 = 128M, 长度 120M
- no-map;
- reg = <0x18000000 0x07800000>;
- };
- };
-
- reserved-driver@0 {
- compatible = "xlnx,reserved-memory";
- memory-region = <&reserved>;
- };
-
- dbox_ipc_dev_instance: dbox_ipc_dev@0 { //112M
- compatible = "dbox,dbox-ipc-dev";
- reg = <0x18000000 0x07000000>;
- ipi12 = <12>;
- ipi13 = <13>;
- };
-
- usb_phy0:usb_phy0{
- compatible = "ulpi-phy";
- #phy-cells = <0>;
- reg = <0xe0002000 0x1000>;
- view-port = <0x170>;
- drv-vbus;
- };
- };
-
- &axi_ethernet_0{
- local-mac-address = [B4 A9 FC 80 0A 54];
- phy-handle = <&phy1>;
- xlnx,has-mdio = <0x1>;
- phy-mode = "mii";
-
- mdio{
- #address-cells = <1>;
- #size-cells = <0>;
- phy1:phy@1{
- compatible = "realtek,rtl8201","ethernet-phy-id001c.c816";
- device_type = "ethernet-phy";
- reg = <0>;
- };
- };
- };
-
- &usb0{
- dr_mode = "host";
- usb-phy = <&usb_phy0>;
- };
reserved-memory 和 reserved-driver: 用于为CPU1保留内存,
dbox_ipcb_dev_instance:是基于xilinx官方remotporc AMP程序,网上的一个简化版,网址如下:
zynq7000 AMP双核IPC+SharedMem通信_Donce Jiang的博客-CSDN博客_zynq7000 双核通信
需要注意:
dbox_ipcb_dev_instance 里边的地址要和 reserved 地址保持一致,也可能要大于reserved。dbox_ipc_dev_instance中reg后边一个参数,应该是长度,这个值不能超过reserved中reg的第二个参数。
参考教程:使用petalinux写驱动_沐唐的博客-CSDN博客_petalinux编译驱动
petalinux-create -t modules --name dbox-ipc-dev
使用如下指令时 无需3.4.3
petalinux-create -t modules --name dbox-ipc-dev --enable
路径:执行上边指令后,INFO会显示路径
工程目录 ---> project-spec ---> meta-user ---> recipes-modules ---> dbox-ipc-dev ---> files ---> dbox-ipc-dev.c ,内容如下:
- /* dbox-ipc-dev.c - The simplest kernel module.
-
- * Copyright (C) 2013 - 2016 Xilinx, Inc
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program. If not, see
. -
- */
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- #include
- #include
- #include
- #include <../../arch/arm/mach-zynq/common.h>
- #include
-
- //extern int zynq_cpun_stop(int cpu);
-
- /* Standard module information, edit as appropriate */
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR
- ("Xilinx Inc.");
- MODULE_DESCRIPTION
- ("dbox-ipc-dev - loadable module template generated by petalinux-create -t modules");
-
- #define DRIVER_NAME "dbox-ipc-dev"
- #define DRIVER_NUM 1
-
- /* Simple example of how to receive command line parameters to your module.
- Delete if you don't need them */
- unsigned myint = 0xdeadbeef;
- char *mystr = "default";
- module_param(myint, int, S_IRUGO);
- module_param(mystr, charp, S_IRUGO);
- #define StarCpu1 0x10000000
- #define StopCpu1 0x20000000
- #define KickCpu1 0x30000000
- struct dbox_ipc_dev_local {
- int irq;
- int cpu0_to_cpu1_ipi;
- int cpu1_to_cpu0_ipi;
- unsigned long mem_start;
- unsigned long mem_end;
- void __iomem *base_addr;
- };
- struct dbox_ipc_dev
- {
- dev_t devid; /* 设备号 */
- struct cdev chdev; /* cdev 结构体 */
- struct class *class; /* 类 */
- struct device *device; /* 设备 */
- struct dbox_ipc_dev_local *param;
- struct fasync_struct *async_queue;
- };
- static struct dbox_ipc_dev dbox_ipc_dev_;
- static int dbox_ipc_dev_open(struct inode *inode, struct file *filp)
- {
- //cpu_up(1);
- //printk("dbox_ipc_dev Dev: open success \r\n");
-
- return 0;
- }
- static ssize_t dbox_ipc_dev_write(struct file *filp, const char __user *buf,size_t cnt, loff_t *offt)
- {
- int ret;
-
- ret = copy_from_user((unsigned char*)(dbox_ipc_dev_.param->base_addr + (*offt)), buf, cnt);
-
- if(0 > ret)
- {
- printk(KERN_ERR "dbox_ipc_dev_ Dev: Failed to copy data from user space \r\n");
- return -EFAULT;
- }
-
- //printk("dbox_ipc_dev_ Dev: write add: %08X cnt: %d\r\n",(unsigned int)(dbox_ipc_dev_.param->base_addr + (*offt)),cnt);
-
- *offt = *offt + cnt;
-
- return cnt;
- }
- static ssize_t dbox_ipc_dev_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
- {
- int ret = 0;
-
- ret = copy_to_user(buf, (unsigned char*)(dbox_ipc_dev_.param->base_addr + (*offt)) , cnt);
-
- if(ret < 0)
- {
- printk(KERN_ERR "dbox_ipc_dev_ Dev: Failed to copy data to user space \r\n");
- }
-
- *offt = *offt + cnt;
-
- return cnt;
- }
- static long dbox_ipc_dev_ioctl(struct file *filp,unsigned int cmd, unsigned long arg)
- {
- int ret = 0;
- //printk("cmd %d \n" ,cmd);
- switch(cmd)
- {
- case StarCpu1:
- ret = cpu_down(1);
- if (ret && (ret != -EBUSY))
- {
- printk("!! Can't release cpu1 %d\n",ret);
- return ret;
- }
- //zynq_cpun_stop(1);
- zynq_cpun_start((u32)dbox_ipc_dev_.param->mem_start, 1);
- //printk("StarCpu1\n");
- break;
- case StopCpu1:
- ret = cpu_up(1);
- if (ret)
- {
- printk("!! Can't power on cpu1 %d\n", ret);
- }
- //printk("StopCpu1\n");
- break;
- case KickCpu1:
- gic_raise_softirq(cpumask_of(1), dbox_ipc_dev_.param->cpu0_to_cpu1_ipi);
- //printk("KickCpu %d %d \n",1,dbox_ipc_dev_.param->cpu0_to_cpu1_ipi);
- break;
- }
- return 0;
- }
- /*********************************************************************
- *
- *
- *
- **********************************************************************/
- loff_t dbox_ipc_dev_llseek(struct file *filp, loff_t off, int whence)
- {
- loff_t newpos;
- switch(whence)
- {
- case 0: /* SEEK_SET */
- newpos = off;
- break;
- case 1: /* SEEK_CUR */
- newpos = filp->f_pos + off;
- break;
- case 2: /* SEEK_END */
- if(whence>0)
- newpos = (dbox_ipc_dev_.param->mem_end - dbox_ipc_dev_.param->mem_start);
- else
- newpos = (dbox_ipc_dev_.param->mem_end - dbox_ipc_dev_.param->mem_start)+ whence;
- break;
- default: /* can't happen */
- return -EINVAL;
- }
-
- if (newpos < 0)
- return -EINVAL;
-
- filp->f_pos = newpos;
-
- return newpos;
- }
- /*********************************************************************
- *
- *
- *
- **********************************************************************/
- static int dbox_ipc_dev_fasync(int fd, struct file *filp, int on)
- {
- return fasync_helper(fd, filp, on, &dbox_ipc_dev_.async_queue);
- }
- /*********************************************************************
- *
- *
- *
- **********************************************************************/
- static int dbox_ipc_dev_fasync_release(struct inode *inode, struct file *filp)
- {
- return dbox_ipc_dev_fasync(-1, filp, 0);
- }
- /*********************************************************************
- *
- *
- *
- **********************************************************************/
- static struct file_operations dbox_ipc_dev_fops =
- {
- .owner = THIS_MODULE,
- .open = dbox_ipc_dev_open,
- .write = dbox_ipc_dev_write,
- .read = dbox_ipc_dev_read,
- .unlocked_ioctl = dbox_ipc_dev_ioctl,
- .llseek = dbox_ipc_dev_llseek,
- .fasync = dbox_ipc_dev_fasync,
- .release = dbox_ipc_dev_fasync_release,
- };
- /*********************************************************************
- *
- *
- *
- **********************************************************************/
- static int dbox_ipc_dev_param_init(struct dbox_ipc_dev_local *nd)
- {
- dbox_ipc_dev_.param = nd;
- cpu_down(1);
- return 0;
- }
- /*********************************************************************
- *
- *IPI 中断通知Linux CPU0 有信息要处理
- *
- **********************************************************************/
- static void cpu1_to_cpu0_ipi_kick(void)
- {
- //printk("[dbox]-->>ipi %d \n",dbox_ipc_dev_.param->cpu1_to_cpu0_ipi);
- if(dbox_ipc_dev_.async_queue)
- {
- //printk("ipi %d kick SIGIO \n",dbox_ipc_dev_.param->cpu1_to_cpu0_ipi);
- kill_fasync(&dbox_ipc_dev_.async_queue, SIGIO, POLL_IN);
- }
- else
- {
- //printk("ipi %d kick but async_queue is null \n",dbox_ipc_dev_.param->cpu1_to_cpu0_ipi);
- }
- }
-
- static irqreturn_t dbox_ipc_dev_irq(int irq, void *lp)
- {
- printk("dbox-ipc-dev interrupt\n");
- return IRQ_HANDLED;
- }
-
- static int dbox_ipc_dev_probe(struct platform_device *pdev)
- {
- struct resource *r_irq; /* Interrupt resources */
- struct resource *r_mem; /* IO mem resources */
- struct device *dev = &pdev->dev;
- struct dbox_ipc_dev_local *lp = NULL;
-
- int rc = 0;
- dev_info(dev, "Device Tree Probing\n");
- printk("---->>>>>dbox ipc dev Device Tree Probing\n");
- /* Get iospace for the device */
- r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!r_mem) {
- dev_err(dev, "invalid address\n");
- return -ENODEV;
- }
- lp = (struct dbox_ipc_dev_local *) kmalloc(sizeof(struct dbox_ipc_dev_local), GFP_KERNEL);
- if (!lp) {
- dev_err(dev, "Cound not allocate dbox-ipc-dev device\n");
- return -ENOMEM;
- }
- dev_set_drvdata(dev, lp);
- lp->mem_start = r_mem->start;
- lp->mem_end = r_mem->end;
-
- if (!request_mem_region(lp->mem_start,
- lp->mem_end - lp->mem_start + 1,
- DRIVER_NAME)) {
- dev_err(dev, "Couldn't lock memory region at %p\n",
- (void *)lp->mem_start);
- rc = -EBUSY;
- goto error1;
- }
-
- lp->base_addr = ioremap(lp->mem_start, lp->mem_end - lp->mem_start + 1);
- if (!lp->base_addr) {
- dev_err(dev, "dbox-ipc-dev: Could not allocate iomem\n");
- rc = -EIO;
- goto error2;
- }
-
- lp->cpu0_to_cpu1_ipi = 12;
- lp->cpu1_to_cpu0_ipi = 13;//默认值
-
- /* Read ipi12 ipi number 用于 ucos 通知 linux */
- rc = of_property_read_u32(pdev->dev.of_node, "ipi12",&lp->cpu1_to_cpu0_ipi);
- if (rc < 0)
- {
- dev_err(&pdev->dev, "unable to read property ipi 12");
- goto error3;
- }
- rc = set_ipi_handler(lp->cpu1_to_cpu0_ipi, cpu1_to_cpu0_ipi_kick,"cpu 1 kick cpu0");
- if (rc)
- {
- dev_err(&pdev->dev, "IPI 12 handler already registered\n");
- goto error3;
- }
- /* Read ipi13 ipi number 用于 linux 通知 ucos */
- rc = of_property_read_u32(pdev->dev.of_node, "ipi13",&lp->cpu0_to_cpu1_ipi);
- if (rc < 0)
- {
- dev_err(&pdev->dev, "unable to read property ipi 13");
- goto error3;
- }
- printk("dbox_ipc_dev_device at 0x%08x mapped to 0x%08x len= %08X , ipi= %d\n",
- (unsigned int __force)lp->mem_start,
- (unsigned int __force)lp->base_addr,
- (unsigned int __force)(lp->mem_end - lp->mem_start+1),
- lp->cpu0_to_cpu1_ipi);
-
- dbox_ipc_dev_param_init(lp);
-
- rc = alloc_chrdev_region(&dbox_ipc_dev_.devid, 0, DRIVER_NUM, DRIVER_NAME);
- if(rc)
- {
- dev_err(&pdev->dev, "unable to alloc_chrdev_region ");
- }
-
- dbox_ipc_dev_.chdev.owner = THIS_MODULE;
- cdev_init(&dbox_ipc_dev_.chdev, &dbox_ipc_dev_fops);
-
- rc = cdev_add(&dbox_ipc_dev_.chdev, dbox_ipc_dev_.devid, 1);
- if(rc)
- {
- dev_err(&pdev->dev, "unable to cdev_add ");
- }
-
- dbox_ipc_dev_.class = class_create(THIS_MODULE, DRIVER_NAME);
- if (IS_ERR(dbox_ipc_dev_.class))
- {
- dev_err(&pdev->dev, "unable to class_create ");
- }
-
- dbox_ipc_dev_.device = device_create(dbox_ipc_dev_.class, &pdev->dev,dbox_ipc_dev_.devid, NULL, DRIVER_NAME);
- if (IS_ERR(dbox_ipc_dev_.device))
- {
- dev_err(&pdev->dev, "unable to device_create ");
- }
-
- return 0;
- error3:
- clear_ipi_handler(lp->cpu0_to_cpu1_ipi);
- error2:
- release_mem_region(lp->mem_start, lp->mem_end - lp->mem_start + 1);
- error1:
- kfree(lp);
- dev_set_drvdata(dev, NULL);
- return rc;
- }
-
- static int dbox_ipc_dev_remove(struct platform_device *pdev)
- {
- struct device *dev = &pdev->dev;
- struct dbox_ipc_dev_local *lp = dev_get_drvdata(dev);
-
- device_destroy(dbox_ipc_dev_.class, dbox_ipc_dev_.devid);
- class_destroy(dbox_ipc_dev_.class);
- cdev_del(&dbox_ipc_dev_.chdev);
- unregister_chrdev_region(dbox_ipc_dev_.devid, DRIVER_NUM);
- clear_ipi_handler(lp->cpu0_to_cpu1_ipi);
- iounmap(lp->base_addr);
- release_mem_region(lp->mem_start, lp->mem_end - lp->mem_start + 1);
- kfree(lp);
- dev_set_drvdata(dev, NULL);
- return 0;
- }
-
- static struct of_device_id dbox_ipc_dev_of_match[] = {
- { .compatible = "dbox,dbox-ipc-dev", },
- { /* end of list */ },
- };
- MODULE_DEVICE_TABLE(of, dbox_ipc_dev_of_match);
-
- static struct platform_driver dbox_ipc_dev_driver = {
- .driver = {
- .name = DRIVER_NAME,
- .owner = THIS_MODULE,
- .of_match_table = dbox_ipc_dev_of_match,
- },
- .probe = dbox_ipc_dev_probe,
- .remove = dbox_ipc_dev_remove,
- };
-
- static int __init dbox_ipc_dev_init(void)
- {
- printk("<1>Hello module world.\n");
- printk("<1>Module parameters were (0x%08x) and \"%s\"\n", myint,
- mystr);
-
- return platform_driver_register(&dbox_ipc_dev_driver);
- }
-
- static void __exit dbox_ipc_dev_exit(void)
- {
- platform_driver_unregister(&dbox_ipc_dev_driver);
- printk(KERN_ALERT "Goodbye module world.\n");
- }
-
- module_init(dbox_ipc_dev_init);
- module_exit(dbox_ipc_dev_exit);
petalinux-config -c rootfs
界面选择 modules ---> ,使能 dbox-ipc-dev,保存。
petalinux-build
petalinux-package --boot --fsbl ./images/linux/zynq_fsbl.elf --fpga ./images/linux/system.bit --uboot --force
将 images/linux 下的,BOOT.bin 和 image.ub 拷贝至SD卡。
登录系统,找到 ”/dev/dbox-ipc-dev“ 则表明驱动运行正常
- ls /dev/db* //看到 dbox-ipc-dev 则表明成功
- cat /proc/cpuinfo //看到一个cpu则 表明运行成功