ZYNQ7020--动态加载CPU1程序<1>

配合食用“ZYNQ7020--AMP下裸机程序开发 <2>

1.实验目标

        CPU0运行petalinux,CPU1运行裸机程序。CPU0启动后,可动态加载CPU1程序。

        测试:通过分别加载两个程序来验证是否成功。

        CPU1共有两个程序:一个控制两路LED灯闪烁,另一个控制两路LED按照0-1-2-3二进制显示。

2.硬件配置

  • 串口0
  • 网口
  • SD0
  • AXI-GPIO

详细配置过程参照《Z7-Lite 系列教程 之 Linux 系统篇》第5章和第9章。

工程文件编译后,导出硬件描述文件至SDK。

3.PetaLinux端配置

创建工程

petalinux-create --type project --template zynq --name ampgpio  

 指定工作目录

petalinux-config --get-hw-description=.  

3.1 工程配置

主菜单 ---> DTG Settings ---> Kernel Bootargs,取消 generate boot args automatically,手动填入如下信息:

console=ttyPS0,115200 earlyprintk maxcpus=1

 保存退出

3.2 内核配置

主要用于自动初始化下axi-gpio相关内容,配置内核。

petalinux-config -c kernel                          

等待弹窗,此处无需修改配置,直接保存,退出即可。

 3.3 修改设备树

路径:工程目录 ---> 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的第二个参数。

3.4 添加驱动

参考教程:使用petalinux写驱动_沐唐的博客-CSDN博客_petalinux编译驱动

3.4.1 创建驱动工程

petalinux-create -t modules --name dbox-ipc-dev

使用如下指令时 无需3.4.3

petalinux-create -t modules --name dbox-ipc-dev --enable

3.4.2 修改.c文件

路径:执行上边指令后,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 <http://www.gnu.org/licenses/>.

*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/uaccess.h> 
#include <linux/cdev.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>

#include <linux/of_irq.h>
#include <linux/fs.h>
#include <linux/fcntl.h> 
#include <../../arch/arm/mach-zynq/common.h>
#include <linux/irqchip/arm-gic.h> 

//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);

3.4.3 将驱动添加到内核

petalinux-config -c rootfs

界面选择 modules ---> ,使能 dbox-ipc-dev,保存。

 3.4.4 编译

petalinux-build

3.4.5 打包

petalinux-package --boot --fsbl ./images/linux/zynq_fsbl.elf --fpga ./images/linux/system.bit --uboot --force

将 images/linux 下的,BOOT.bin 和 image.ub 拷贝至SD卡。

 3.4.6 驱动验证

登录系统,找到 ”/dev/dbox-ipc-dev“ 则表明驱动运行正常

ls /dev/db*				 //看到 dbox-ipc-dev 则表明成功
cat /proc/cpuinfo		 //看到一个cpu则 表明运行成功

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值