• 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 添加如下内容:

    1. /include/ "system-conf.dtsi"
    2. / {
    3. reserved-memory {
    4. #address-cells = <1>;
    5. #size-cells = <1>;
    6. ranges;
    7. reserved: buffer@0x18000000 { //512-384 = 128M, 长度 120M
    8. no-map;
    9. reg = <0x18000000 0x07800000>;
    10. };
    11. };
    12. reserved-driver@0 {
    13. compatible = "xlnx,reserved-memory";
    14. memory-region = <&reserved>;
    15. };
    16. dbox_ipc_dev_instance: dbox_ipc_dev@0 { //112M
    17. compatible = "dbox,dbox-ipc-dev";
    18. reg = <0x18000000 0x07000000>;
    19. ipi12 = <12>;
    20. ipi13 = <13>;
    21. };
    22. usb_phy0:usb_phy0{
    23. compatible = "ulpi-phy";
    24. #phy-cells = <0>;
    25. reg = <0xe0002000 0x1000>;
    26. view-port = <0x170>;
    27. drv-vbus;
    28. };
    29. };
    30. &axi_ethernet_0{
    31. local-mac-address = [B4 A9 FC 80 0A 54];
    32. phy-handle = <&phy1>;
    33. xlnx,has-mdio = <0x1>;
    34. phy-mode = "mii";
    35. mdio{
    36. #address-cells = <1>;
    37. #size-cells = <0>;
    38. phy1:phy@1{
    39. compatible = "realtek,rtl8201","ethernet-phy-id001c.c816";
    40. device_type = "ethernet-phy";
    41. reg = <0>;
    42. };
    43. };
    44. };
    45. &usb0{
    46. dr_mode = "host";
    47. usb-phy = <&usb_phy0>;
    48. };

    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 ,内容如下:

    1. /* dbox-ipc-dev.c - The simplest kernel module.
    2. * Copyright (C) 2013 - 2016 Xilinx, Inc
    3. *
    4. * This program is free software; you can redistribute it and/or modify
    5. * it under the terms of the GNU General Public License as published by
    6. * the Free Software Foundation; either version 2 of the License, or
    7. * (at your option) any later version.
    8. * This program is distributed in the hope that it will be useful,
    9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
    10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    11. * GNU General Public License for more details.
    12. *
    13. * You should have received a copy of the GNU General Public License along
    14. * with this program. If not, see .
    15. */
    16. #include
    17. #include
    18. #include
    19. #include
    20. #include
    21. #include
    22. #include
    23. #include
    24. #include
    25. #include
    26. #include
    27. #include
    28. #include
    29. #include
    30. #include <../../arch/arm/mach-zynq/common.h>
    31. #include
    32. //extern int zynq_cpun_stop(int cpu);
    33. /* Standard module information, edit as appropriate */
    34. MODULE_LICENSE("GPL");
    35. MODULE_AUTHOR
    36. ("Xilinx Inc.");
    37. MODULE_DESCRIPTION
    38. ("dbox-ipc-dev - loadable module template generated by petalinux-create -t modules");
    39. #define DRIVER_NAME "dbox-ipc-dev"
    40. #define DRIVER_NUM 1
    41. /* Simple example of how to receive command line parameters to your module.
    42. Delete if you don't need them */
    43. unsigned myint = 0xdeadbeef;
    44. char *mystr = "default";
    45. module_param(myint, int, S_IRUGO);
    46. module_param(mystr, charp, S_IRUGO);
    47. #define StarCpu1 0x10000000
    48. #define StopCpu1 0x20000000
    49. #define KickCpu1 0x30000000
    50. struct dbox_ipc_dev_local {
    51. int irq;
    52. int cpu0_to_cpu1_ipi;
    53. int cpu1_to_cpu0_ipi;
    54. unsigned long mem_start;
    55. unsigned long mem_end;
    56. void __iomem *base_addr;
    57. };
    58. struct dbox_ipc_dev
    59. {
    60. dev_t devid; /* 设备号 */
    61. struct cdev chdev; /* cdev 结构体 */
    62. struct class *class; /* 类 */
    63. struct device *device; /* 设备 */
    64. struct dbox_ipc_dev_local *param;
    65. struct fasync_struct *async_queue;
    66. };
    67. static struct dbox_ipc_dev dbox_ipc_dev_;
    68. static int dbox_ipc_dev_open(struct inode *inode, struct file *filp)
    69. {
    70. //cpu_up(1);
    71. //printk("dbox_ipc_dev Dev: open success \r\n");
    72. return 0;
    73. }
    74. static ssize_t dbox_ipc_dev_write(struct file *filp, const char __user *buf,size_t cnt, loff_t *offt)
    75. {
    76. int ret;
    77. ret = copy_from_user((unsigned char*)(dbox_ipc_dev_.param->base_addr + (*offt)), buf, cnt);
    78. if(0 > ret)
    79. {
    80. printk(KERN_ERR "dbox_ipc_dev_ Dev: Failed to copy data from user space \r\n");
    81. return -EFAULT;
    82. }
    83. //printk("dbox_ipc_dev_ Dev: write add: %08X cnt: %d\r\n",(unsigned int)(dbox_ipc_dev_.param->base_addr + (*offt)),cnt);
    84. *offt = *offt + cnt;
    85. return cnt;
    86. }
    87. static ssize_t dbox_ipc_dev_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
    88. {
    89. int ret = 0;
    90. ret = copy_to_user(buf, (unsigned char*)(dbox_ipc_dev_.param->base_addr + (*offt)) , cnt);
    91. if(ret < 0)
    92. {
    93. printk(KERN_ERR "dbox_ipc_dev_ Dev: Failed to copy data to user space \r\n");
    94. }
    95. *offt = *offt + cnt;
    96. return cnt;
    97. }
    98. static long dbox_ipc_dev_ioctl(struct file *filp,unsigned int cmd, unsigned long arg)
    99. {
    100. int ret = 0;
    101. //printk("cmd %d \n" ,cmd);
    102. switch(cmd)
    103. {
    104. case StarCpu1:
    105. ret = cpu_down(1);
    106. if (ret && (ret != -EBUSY))
    107. {
    108. printk("!! Can't release cpu1 %d\n",ret);
    109. return ret;
    110. }
    111. //zynq_cpun_stop(1);
    112. zynq_cpun_start((u32)dbox_ipc_dev_.param->mem_start, 1);
    113. //printk("StarCpu1\n");
    114. break;
    115. case StopCpu1:
    116. ret = cpu_up(1);
    117. if (ret)
    118. {
    119. printk("!! Can't power on cpu1 %d\n", ret);
    120. }
    121. //printk("StopCpu1\n");
    122. break;
    123. case KickCpu1:
    124. gic_raise_softirq(cpumask_of(1), dbox_ipc_dev_.param->cpu0_to_cpu1_ipi);
    125. //printk("KickCpu %d %d \n",1,dbox_ipc_dev_.param->cpu0_to_cpu1_ipi);
    126. break;
    127. }
    128. return 0;
    129. }
    130. /*********************************************************************
    131. *
    132. *
    133. *
    134. **********************************************************************/
    135. loff_t dbox_ipc_dev_llseek(struct file *filp, loff_t off, int whence)
    136. {
    137. loff_t newpos;
    138. switch(whence)
    139. {
    140. case 0: /* SEEK_SET */
    141. newpos = off;
    142. break;
    143. case 1: /* SEEK_CUR */
    144. newpos = filp->f_pos + off;
    145. break;
    146. case 2: /* SEEK_END */
    147. if(whence>0)
    148. newpos = (dbox_ipc_dev_.param->mem_end - dbox_ipc_dev_.param->mem_start);
    149. else
    150. newpos = (dbox_ipc_dev_.param->mem_end - dbox_ipc_dev_.param->mem_start)+ whence;
    151. break;
    152. default: /* can't happen */
    153. return -EINVAL;
    154. }
    155. if (newpos < 0)
    156. return -EINVAL;
    157. filp->f_pos = newpos;
    158. return newpos;
    159. }
    160. /*********************************************************************
    161. *
    162. *
    163. *
    164. **********************************************************************/
    165. static int dbox_ipc_dev_fasync(int fd, struct file *filp, int on)
    166. {
    167. return fasync_helper(fd, filp, on, &dbox_ipc_dev_.async_queue);
    168. }
    169. /*********************************************************************
    170. *
    171. *
    172. *
    173. **********************************************************************/
    174. static int dbox_ipc_dev_fasync_release(struct inode *inode, struct file *filp)
    175. {
    176. return dbox_ipc_dev_fasync(-1, filp, 0);
    177. }
    178. /*********************************************************************
    179. *
    180. *
    181. *
    182. **********************************************************************/
    183. static struct file_operations dbox_ipc_dev_fops =
    184. {
    185. .owner = THIS_MODULE,
    186. .open = dbox_ipc_dev_open,
    187. .write = dbox_ipc_dev_write,
    188. .read = dbox_ipc_dev_read,
    189. .unlocked_ioctl = dbox_ipc_dev_ioctl,
    190. .llseek = dbox_ipc_dev_llseek,
    191. .fasync = dbox_ipc_dev_fasync,
    192. .release = dbox_ipc_dev_fasync_release,
    193. };
    194. /*********************************************************************
    195. *
    196. *
    197. *
    198. **********************************************************************/
    199. static int dbox_ipc_dev_param_init(struct dbox_ipc_dev_local *nd)
    200. {
    201. dbox_ipc_dev_.param = nd;
    202. cpu_down(1);
    203. return 0;
    204. }
    205. /*********************************************************************
    206. *
    207. *IPI 中断通知Linux CPU0 有信息要处理
    208. *
    209. **********************************************************************/
    210. static void cpu1_to_cpu0_ipi_kick(void)
    211. {
    212. //printk("[dbox]-->>ipi %d \n",dbox_ipc_dev_.param->cpu1_to_cpu0_ipi);
    213. if(dbox_ipc_dev_.async_queue)
    214. {
    215. //printk("ipi %d kick SIGIO \n",dbox_ipc_dev_.param->cpu1_to_cpu0_ipi);
    216. kill_fasync(&dbox_ipc_dev_.async_queue, SIGIO, POLL_IN);
    217. }
    218. else
    219. {
    220. //printk("ipi %d kick but async_queue is null \n",dbox_ipc_dev_.param->cpu1_to_cpu0_ipi);
    221. }
    222. }
    223. static irqreturn_t dbox_ipc_dev_irq(int irq, void *lp)
    224. {
    225. printk("dbox-ipc-dev interrupt\n");
    226. return IRQ_HANDLED;
    227. }
    228. static int dbox_ipc_dev_probe(struct platform_device *pdev)
    229. {
    230. struct resource *r_irq; /* Interrupt resources */
    231. struct resource *r_mem; /* IO mem resources */
    232. struct device *dev = &pdev->dev;
    233. struct dbox_ipc_dev_local *lp = NULL;
    234. int rc = 0;
    235. dev_info(dev, "Device Tree Probing\n");
    236. printk("---->>>>>dbox ipc dev Device Tree Probing\n");
    237. /* Get iospace for the device */
    238. r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    239. if (!r_mem) {
    240. dev_err(dev, "invalid address\n");
    241. return -ENODEV;
    242. }
    243. lp = (struct dbox_ipc_dev_local *) kmalloc(sizeof(struct dbox_ipc_dev_local), GFP_KERNEL);
    244. if (!lp) {
    245. dev_err(dev, "Cound not allocate dbox-ipc-dev device\n");
    246. return -ENOMEM;
    247. }
    248. dev_set_drvdata(dev, lp);
    249. lp->mem_start = r_mem->start;
    250. lp->mem_end = r_mem->end;
    251. if (!request_mem_region(lp->mem_start,
    252. lp->mem_end - lp->mem_start + 1,
    253. DRIVER_NAME)) {
    254. dev_err(dev, "Couldn't lock memory region at %p\n",
    255. (void *)lp->mem_start);
    256. rc = -EBUSY;
    257. goto error1;
    258. }
    259. lp->base_addr = ioremap(lp->mem_start, lp->mem_end - lp->mem_start + 1);
    260. if (!lp->base_addr) {
    261. dev_err(dev, "dbox-ipc-dev: Could not allocate iomem\n");
    262. rc = -EIO;
    263. goto error2;
    264. }
    265. lp->cpu0_to_cpu1_ipi = 12;
    266. lp->cpu1_to_cpu0_ipi = 13;//默认值
    267. /* Read ipi12 ipi number 用于 ucos 通知 linux */
    268. rc = of_property_read_u32(pdev->dev.of_node, "ipi12",&lp->cpu1_to_cpu0_ipi);
    269. if (rc < 0)
    270. {
    271. dev_err(&pdev->dev, "unable to read property ipi 12");
    272. goto error3;
    273. }
    274. rc = set_ipi_handler(lp->cpu1_to_cpu0_ipi, cpu1_to_cpu0_ipi_kick,"cpu 1 kick cpu0");
    275. if (rc)
    276. {
    277. dev_err(&pdev->dev, "IPI 12 handler already registered\n");
    278. goto error3;
    279. }
    280. /* Read ipi13 ipi number 用于 linux 通知 ucos */
    281. rc = of_property_read_u32(pdev->dev.of_node, "ipi13",&lp->cpu0_to_cpu1_ipi);
    282. if (rc < 0)
    283. {
    284. dev_err(&pdev->dev, "unable to read property ipi 13");
    285. goto error3;
    286. }
    287. printk("dbox_ipc_dev_device at 0x%08x mapped to 0x%08x len= %08X , ipi= %d\n",
    288. (unsigned int __force)lp->mem_start,
    289. (unsigned int __force)lp->base_addr,
    290. (unsigned int __force)(lp->mem_end - lp->mem_start+1),
    291. lp->cpu0_to_cpu1_ipi);
    292. dbox_ipc_dev_param_init(lp);
    293. rc = alloc_chrdev_region(&dbox_ipc_dev_.devid, 0, DRIVER_NUM, DRIVER_NAME);
    294. if(rc)
    295. {
    296. dev_err(&pdev->dev, "unable to alloc_chrdev_region ");
    297. }
    298. dbox_ipc_dev_.chdev.owner = THIS_MODULE;
    299. cdev_init(&dbox_ipc_dev_.chdev, &dbox_ipc_dev_fops);
    300. rc = cdev_add(&dbox_ipc_dev_.chdev, dbox_ipc_dev_.devid, 1);
    301. if(rc)
    302. {
    303. dev_err(&pdev->dev, "unable to cdev_add ");
    304. }
    305. dbox_ipc_dev_.class = class_create(THIS_MODULE, DRIVER_NAME);
    306. if (IS_ERR(dbox_ipc_dev_.class))
    307. {
    308. dev_err(&pdev->dev, "unable to class_create ");
    309. }
    310. dbox_ipc_dev_.device = device_create(dbox_ipc_dev_.class, &pdev->dev,dbox_ipc_dev_.devid, NULL, DRIVER_NAME);
    311. if (IS_ERR(dbox_ipc_dev_.device))
    312. {
    313. dev_err(&pdev->dev, "unable to device_create ");
    314. }
    315. return 0;
    316. error3:
    317. clear_ipi_handler(lp->cpu0_to_cpu1_ipi);
    318. error2:
    319. release_mem_region(lp->mem_start, lp->mem_end - lp->mem_start + 1);
    320. error1:
    321. kfree(lp);
    322. dev_set_drvdata(dev, NULL);
    323. return rc;
    324. }
    325. static int dbox_ipc_dev_remove(struct platform_device *pdev)
    326. {
    327. struct device *dev = &pdev->dev;
    328. struct dbox_ipc_dev_local *lp = dev_get_drvdata(dev);
    329. device_destroy(dbox_ipc_dev_.class, dbox_ipc_dev_.devid);
    330. class_destroy(dbox_ipc_dev_.class);
    331. cdev_del(&dbox_ipc_dev_.chdev);
    332. unregister_chrdev_region(dbox_ipc_dev_.devid, DRIVER_NUM);
    333. clear_ipi_handler(lp->cpu0_to_cpu1_ipi);
    334. iounmap(lp->base_addr);
    335. release_mem_region(lp->mem_start, lp->mem_end - lp->mem_start + 1);
    336. kfree(lp);
    337. dev_set_drvdata(dev, NULL);
    338. return 0;
    339. }
    340. static struct of_device_id dbox_ipc_dev_of_match[] = {
    341. { .compatible = "dbox,dbox-ipc-dev", },
    342. { /* end of list */ },
    343. };
    344. MODULE_DEVICE_TABLE(of, dbox_ipc_dev_of_match);
    345. static struct platform_driver dbox_ipc_dev_driver = {
    346. .driver = {
    347. .name = DRIVER_NAME,
    348. .owner = THIS_MODULE,
    349. .of_match_table = dbox_ipc_dev_of_match,
    350. },
    351. .probe = dbox_ipc_dev_probe,
    352. .remove = dbox_ipc_dev_remove,
    353. };
    354. static int __init dbox_ipc_dev_init(void)
    355. {
    356. printk("<1>Hello module world.\n");
    357. printk("<1>Module parameters were (0x%08x) and \"%s\"\n", myint,
    358. mystr);
    359. return platform_driver_register(&dbox_ipc_dev_driver);
    360. }
    361. static void __exit dbox_ipc_dev_exit(void)
    362. {
    363. platform_driver_unregister(&dbox_ipc_dev_driver);
    364. printk(KERN_ALERT "Goodbye module world.\n");
    365. }
    366. module_init(dbox_ipc_dev_init);
    367. 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“ 则表明驱动运行正常

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

  • 相关阅读:
    C语言300行代码实现扫雷(可展开+可标记+可更改困难级别+内附图形界面版本)
    认识京东联盟API,获取APPkey和APPsecret|直接调用KEY方式
    java基于Android studio的家政服务系统
    idea热部署Jrebel插件和自动手动三种方式实现
    JVM-虚拟机的故障处理与调优案例分析
    Flink 写入Apache Arrow
    韩国程序员面试考什么?
    Redis变慢怎么办?
    [原创]dotnet 命令行工具解决方案 PomeloCli
    Vue2 | Vant uploader实现上传文件和图片
  • 原文地址:https://blog.csdn.net/mengqingbin5219/article/details/126480517