Zynq-Linux移植学习笔记之14-RapidIO驱动开发


在对zynq进行linux驱动开发时,除了需要针对zynq内ARM自带的控制器适配驱动外,还需要对zynq PL部分的IP核进行驱动开发。对于ARM来说,zynq PL部分的IP核就是一段地址空间,这段地址空间包含了该IP的一系列寄存器,ARM操作该IP核的寄存器也就是操作这段地址空间,而PL部分IP的驱动也就是对IP寄存器的操作。

 

1、  硬件设计

在vivado内进行设计时,RapidIO IP核通过AXI总线与ARM相连,地址空间区域如图:


从0x40000000-0x7FFFFFFF均为RapidIO IP的地址空间,注意这里的地址是物理地址,在zynq的裸程序中,可以通过xil_out32()或xil_in32()等函数直接操纵该地址的值,也即对RapidIO IP核寄存器的读写操作。

补充一点,考虑到RapidIO IP使用的一致性以及预防配置出错,硬件设计时已经将RapidIO IP寄存器进行了正确配置,这一部分是在硬件FPGA编程时实现的,软件部分并不需要从头开始配置RapidIO IP核。因此,对RapidIO IP驱动的开发也只需要实现对寄存器的读、写这两个函数即可。

 

2、  devicetree设计

由于RapidIO IP核位于PL部分,需要在devicetree中增加相应内容,如下:

amba_pl {
                   #address-cells= <0x1>;
                   #size-cells= <0x1>;
                   compatible= "simple-bus";
                   ranges;
                   srio_axi_config@40000000{
                            compatible= "xlnx,xps-rio-1.00.a";
                            reg= <0x40000000 0x40000000>;
                   };
};


Amba_pl对应PL部分的amba,devicetree中原有的amba对应PS部分,两个位于同一层。

 

3、  驱动设计

RapidIO IP核驱动实现对物理地址0x40000000到0x7fffffff的读、写操作,可以参考xilinxPL部分CAN IP核的驱动代码。实现过程需要注意地址的虚实转换,0x40000000开始的这一段地址是物理地址,需要将这段地址进行映射,确保CPU访问的地址经过MMU转换后确实对应这一地址。

 

 

/*
 * rio-xiic.c
 * Copyright (c) 2002-2007 Xilinx Inc.
 * Copyright (c) 2009-2010 Intel Corporation
 *
 */
/* Supports:
 * Xilinx RapidIO
 */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/wait.h>
#include <linux/i2c-xiic.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/of.h>

#define DRIVER_NAME "xiic-rio"

#define SRIO_ZYNQ_BASEADDR	0x40000000
#define SRIO_ZYNQ_NODE_BASEADDR	0x10100
#define SRIO_ZYNQ_MAX_HOPCOUNT	13

struct xiic_rio {
	struct mutex	lock;
	u8	*data;
};

/* We need global varriable for maped address */
static void __iomem* _rio_base = NULL;

static inline void rio_setreg32(unsigned int addrBase,unsigned int addrOffset,unsigned int value)
{
	iowrite32(value, addrBase + addrOffset);
}

static inline int rio_getreg32(unsigned int addrBase,unsigned int addrOffset)
{
	unsigned int reg_addr;
	reg_addr=addrBase+addrOffset;
	return ioread32(reg_addr);
}


static ssize_t hlMaintWrite(unsigned int dstId,unsigned short hopcount, unsigned int offset, unsigned int writedata)
{
	unsigned int reg_addr;
	if( hopcount > SRIO_ZYNQ_MAX_HOPCOUNT )
	{
		printk("!!!error, hopcount = %d,  > %d\n",hopcount,SRIO_ZYNQ_MAX_HOPCOUNT);
		return -1;
	}
	
	rio_setreg32((unsigned int)_rio_base,SRIO_ZYNQ_NODE_BASEADDR,dstId);	
	reg_addr = (((hopcount+1)<<24)|offset);
	rio_setreg32((unsigned int)_rio_base,reg_addr,writedata);		
	
	return 0;  
}

static ssize_t hlMaintRead(unsigned int dstId,unsigned short hopcount, unsigned int offset, void *mrdataAdr)
{	
	unsigned int reg_addr;
	if( hopcount > SRIO_ZYNQ_MAX_HOPCOUNT )
	{
		printk("!!!error, hopcount = %d,  > %d\n",hopcount,SRIO_ZYNQ_MAX_HOPCOUNT);
		return -1;
	}
	
	rio_setreg32((unsigned int)_rio_base,SRIO_ZYNQ_NODE_BASEADDR,dstId);	
	reg_addr = (((hopcount+1)<<24)|offset);

	mrdataAdr = rio_getreg32((unsigned int)_rio_base,reg_addr);
	
	printk("M_SRIO_MAINT_REG_READ: hopcount = %d, offset = 0x%x, value = 0x%x\n",hopcount,offset,mrdataAdr);
	return 0;  
}


static SIMPLE_DEV_PM_OPS(xiic_rio_pm_ops, hlMaintRead,hlMaintWrite);

static int xiic_rio_probe(struct platform_device *pdev)
{
	struct xiic_rio *rio;
	struct resource *res;
	unsigned int mtRdata=0;

	rio = kzalloc(sizeof(struct xiic_rio), GFP_KERNEL);
	if (!rio)
		return -ENOMEM;

	/* Get Mapped address */
	_rio_base = ioremap_nocache(SRIO_ZYNQ_BASEADDR, 0xe000000); 
	if (!_rio_base)
		return -ENOMEM;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	platform_set_drvdata(pdev, rio);

	hlMaintRead(0xFF,0, 0, mtRdata);
	return 0;
}

static int xiic_rio_remove(struct platform_device *pdev)
{
	struct xiic_rio *rio = platform_get_drvdata(pdev);

	kfree(rio);
	return 0;
}


static const struct of_device_id xiic_of_match[] = {
	{ .compatible = "xlnx,xps-rio-1.00.a", },
	{},
};
MODULE_DEVICE_TABLE(of, xiic_of_match);

static struct platform_driver xiic_rio_driver = {
	.probe   = xiic_rio_probe,
	.remove  = xiic_rio_remove,
	.driver  = {
		.name = DRIVER_NAME,
		.of_match_table = of_match_ptr(xiic_of_match),
		.pm = &xiic_rio_pm_ops,
	},
};

module_platform_driver(xiic_rio_driver);

MODULE_AUTHOR("info@mocean-labs.com");
MODULE_DESCRIPTION("Xilinx Rio IP Core driver");
MODULE_LICENSE("GPL v2");

 

上面代码中ioremap实现的就是物理地址的映射,该函数的第二个参数为映射的大小,由于模块上DDR只有1G,所以实际最大的映射空间只有224M,能访问IP核的实际地址空间为0x40000000-0x4e000000。驱动中实现读写两个函数,对zynq FPGA地址的访问可以直接调用ioread32()、iowrite32(),这两个函数和xil_out32()、xil_in32()相对应。

完成驱动后修改Kconfig文件和Makefile文件,加入驱动选项,这里是合在了I2C总线驱动里面:



 

4、  测试

对该驱动的测试主要是通过调用读函数访问地址空间,判断返回值是否符合预期。由于RapidIO IP核能够访问到CPS 1848,可以通过判断返回值是否是1848的device ID加以验证。

在probe中调用函数hlMaintRead(0xFF,0, 0, mtRdata),返回值如下:


Value和1848 datasheet中的一致,验证通过。


 

5、  总结

在对zynq PL部分IP核的驱动开发过程中需要注意地址转换问题,下面两种异常都是属于地址问题



这种异常是映射空间不够大,对应于ioremap第二个参数



  • 2
    点赞
  • 69
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
### 回答1: "Zynq-Linux移植学习笔记"是一篇关于在Zynq SoC平台上移植Linux操作系统的学习笔记。该笔记主要介绍了如何在Zynq平台上搭建交叉编译环境、编译内核、制作根文件系统以及启动Linux系统等方面的知识。通过学习这篇笔记,读者可以了解到如何将Linux操作系统移植Zynq平台上,并且可以通过实践来深入理解相关的知识和技 ### 回答2: Zynq Linux移植是搭建Zynq硬件平台和在该平台上运行Linux系统的过程。它包括了硬件的设计和软件的开发,这有助于实现在Zynq平台上开发Linux应用程序的目标。 首先,进行Zynq Linux移植前需要研究设备的结构和硬件构造。zynq硬件平台包含两个主要组成部分:PS和PL。PS负责处理器系统和外设的管理和控制,PL则是可编程逻辑,支持FPGA逻辑的定制化,同时也支持外设的实现。在移植时,需要设计PS的硬件架构和软件驱动程序,同时也需要配置PL。一般情况下,需要进行如(Xilinx SDK)和(Petalinux)等的软件开发环境安装和配置。 接下来,进行Linux系统的移植。这部分工作需要了解Linux内核的结构、功能和特性,然后根据硬件架构,对Linux系统进行调整和定制,构建出适合硬件平台的Linux系统。这个过程需要进行的工作包括:解编译适合SOC的内核、制定设备树、调整内核参数等。 最后,这些工作完成后,就可以在Zynq平台上编译和运行Linux应用程序了。开发者可以尝试通过开发板上的GPIO、I2C、SPI或UART等接口,学习Linux的设备驱动程序、网络编程、文件系统管理等知识点。可逐步学习如何掌握Linux的shell、打包工具、交叉编译工具等。 总结来说,Zynq Linux移植工作是基础的硬件构造、嵌入式软件和Linux知识的综合应用,需要开发者有至少三方面的技能。需要熟练编写硬件设计,熟练掌握Linux内核编程以及Linux系统软件的维护和管理。这些技能的应用能力对于移植Zynq平台Linux系统和应用程序的开发工程师来说是非常必要的。 ### 回答3: 随着嵌入式系统的广泛应用,zynq-linux移植成为了嵌入式开发的一个重要研究课题。zynq-linux移植涉及到许多方面的知识,在学习过程中需要注意以下几点: 一、zynq-linux移植前需要了解的基础知识 在开始进行zynq-linux移植之前,需要对Linux系统、ARM技术、FPGA开发、C语言等基础知识有一定的了解。同时需要熟悉zynq系列的基本架构和应用场景。 二、zynq-linux移植必要的步骤 zynq-linux移植的过程主要分为以下几个步骤:首先是确定硬件平台和环境搭建;其次是进行内核编译和配置;然后是uboot编译和烧录;最后是Linux文件系统的制作和烧录。在整个移植过程中,需要注意各个步骤的顺序和详细操作,确保每一步都正确完成。 三、zynq-linux移植中可能会遇到的问题 在zynq-linux移植过程中,可能会遇到各种问题,例如硬件平台的兼容性、内核配置的错误、uboot烧录问题、文件系统制作出错等。在遇到这些问题时,需要耐心地进行排查和解决,同时也可以借助搜索引擎和社区的技术支持。 四、zynq-linux移植之后的应用与拓展 zynq-linux移植成功之后,可以将其应用于各种嵌入式系统中,例如网络设备、智能家居、工业控制等领域。同时,还可以进行拓展和优化,例如添加各种驱动程序、优化系统性能等。 总之,在进行zynq-linux移植学习和实践中,需要认真学习基础知识,仔细操作每个步骤,及时排查并解决问题,并在成功移植之后持续进行应用与拓展。
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值