xilinx vdma能够workstation 配置直通成直通吗

Xilinx Zynq使用HLS实现OpenCV的开发流程
> Xilinx Zynq使用HLS实现OpenCV的开发流程
Xilinx Zynq使用HLS实现OpenCV的开发流程
  摘要:首先介绍中图像类型和函数处理方法,之后通过设计实例描述在中调用库函数实现图像处理的几个基本步骤,阐述从设计到RTL转换综合的开发流程。本文引用地址:
  关键词:;;;OpenCV;Zynq&AP&SOC
  开源计算机视觉&(OpenCV)&被广泛用于开发计算机视觉应用,它包含2500多个优化的视频函数的函数库并且专门针对台式机和GPU进行优化。Xilinx&高层次综合工具能够使用C/C++&编写的代码直接创建RTL硬件,显著提高设计生产力,同时,Xilinx&Zynq全SOC系列器件嵌入双核ARM&Cortex-A9将软件能力与FPGA的硬件可编程能力实现完美结合,以低功耗和低成本等系统优势实现单芯片无以伦比的系统性能、灵活性、可扩展性,加速图形处理产品设计上市时间。OpenCV拥有成千上万的用户,而且OpenCV的设计无需修改即可在&Zynq器件的ARM处理器上运行,但是利用OpenCV实现的高清处理经常受外部存储器的限制,尤其是存储带宽会成为性能瓶颈,存储访问也限制了功耗效率。使用Xilinx公司的VivadoHLS高级语言综合工具,可以轻松实现OpenCV&C++视频处理设计到RTL代码的转换,输出Zynq的硬件加速器或者直接在FPGA上实现实时硬件视频处理功能。同时,Xiinx公司的Zynq&All-programmable&SoC是实现嵌入式计算机视觉应用的好方法,解决了在单一处理器上实现视频处理性能低功耗高的限制,Zynq高性能可编程逻辑和嵌入式ARM内核,是一款性能功耗最优化的图像处理集成式解决方案。
  1&OpenCV中图像IplImage,&CvMat,&Mat&类型的关系和VivadoHLS中图像hls::Mat类型
  OpenCV中常见的与图像操作有关的数据容器有Mat,cvMat和IplImage,这三种类型都可以代表和显示图像,但是,Mat类型侧重于计算,数学性较高。而CvMat和IplImage类型更侧重于&图像&,OpenCV对其中的图像操作(缩放、单通道提取、图像阈值操作等)进行了优化。
  1.1&OpenCV中的Mat矩阵类型
  在OpenCV中,Mat是一个多维的密集数据数组。可以用来处理向量和矩阵、图像、直方图等等常见的多维数据。
  Mat类型较CvMat与IplImage类型来说,有更强的矩阵运算能力,支持常见的矩阵运算。在计算密集型的应用当中,将CvMat与IplImage类型转化为Mat类型将大大减少计算时间花费。
  1.2&OpenCV中的CvMat与IplImage类型
  在openCV中,CvMat和IplImage类型更侧重于&图像&,尤其是对其中的图像操作进行一定程度的优化。OpenCV没有向量(vector)的数据结构,但当我们要表示向量时,需要用矩阵数据表示。但是,CvMat更抽象,它的元素数据类型并不仅限于基础数据类型,而且可以是任意的预定义数据类型,比如RGB或者别的多通道数据。、
  在OpenCV类型关系上,我们可以说IplImage类型继承自CvMat类型,当然还包括其他的变量将之解析成图像数据。IplImage类型较之CvMat多了很多参数,比如depth和nChannels。IplImage对图像的另一种优化是变量origin原点,为了弥补这一点,OpenCV允许用户定义自己的原点设置。
  1.3&VivadoHLS中图像数据类型hls::Mat&&
  VivadoHLS视频处理函数库使用hls::Mat&&数据类型,这种类型用于模型化视频像素流处理,实质等同于hls::steam&&流的类型,而不是OpenCV中在外部memory中存储的matrix矩阵类型。因此,在用vivadoHLS实现OpenCV的设计中,需要将输入和输出HLS可综合的视频设计接口,修改为Video&stream接口,也就是采用HLS提供的video接口可综合函数,实现AXI4&video&stream到VivadoHLS中hls::Mat&&类型的转换。
  2&使用VivadoHLS实现OpenCV到RTL代码转换的流程
  2.1&OpenCV设计中的权衡
  OpenCV图像处理是基于存储器帧缓存而构建的,它总是假设视频frame数据存放在外部DDR&存储器中,因此,OpenCV对于访问局部图像性能较差,因为处理器的小容量高速缓存性能不足以完成这个任务。而且出于性能考虑,基于OpenCV设计的架构比较复杂,功耗更高。在对分辨率或帧速率要求低,或者在更大的图像中对需要的特征或区域进行处理是,OpenCV似乎足以满足很多应用的要求,但对于高分辨率高帧率实时处理的场景下,OpenCV很难满足高性能和低功耗的需求。
  基于视频流的架构能提供高性能和低功耗,链条化的图像处理函数减少了外部存储器访问,针对视频优化的行缓存和窗口缓存比处理器高速缓存更简单高效,更易于使用VivadoHLS&在FPGA部件中采用数据流优化来实现。
  VivadoHLS对OpenCV的支持,不是指可以将OpenCV的函数库直接综合成RTL代码,而是需要将代码转换为可综合的代码,这些可综合的视频库称为HLS视频库,由VivadoHLS提供。
  OpenCV函数不能直接通过HLS进行综合,因为OpenCV函数一般都包含动态的内存分配、浮点以及假设图像在外部存储器中存放或者修改。
  VivadoHLS视频库用于替换很多基本的&OpenCV函数,它与OpenCV具有相似的接口和算法,主要针对在FPGA架构中实现的图像处理函数,包含了专门面向FPGA的优化,比如定点运算而非浮点运算(不必精确到比特位),片上的行缓存(line&buffer)和窗口缓存(window&buffer)。图2.1展示了在Xilinx&Zynq&AP&SOC器件上实现视频处理的系统结构。
  图2.1&Zynq视频处理系统结构
  2.2&在FPGA/Zynq开发中使用VivadoHLS实现OpenCV的设计流程
  设计开发流程主要有如图2.2三个步骤。
  1.&在计算机上开发OpenCV应用,由于是开源的设计,采用C++的编译器对其进行编译,仿真和debug,最后产生可执行文件。这些设计无需修改即可在&ARM内核上运行OpenCV应用。
  2.&使用I/O函数抽取FPGA实现的部分,并且使用可综合的VivadoHLS&Video库函数代码代替OpenCV函数的调用。
  3.&运行HLS生成RTL代码,在VivadoHLS工程中启动co-sim,HLS工具自动重用OpenCV的测试激励验证产生的RTL代码。在Xilinx的ISE或者Vivado开发环境中做RTL的集成和SoC/FPGA实现。
  图2.2&在FPGA/Zynq设计中使用OpenCV的开发流程
  2.2.1&VivadoHLS视频库函数
  HLS视频库是包含在hls命名空间内的C++代码。#include&&hls_video.h&
  HLS视频库与OpenCV等具有相似的接口和等效的行为,例如:
  OpenCV库:cvScale(src,&dst,&scale,&shift);
  HLS视频库:hls::Scale&...&(src,&dst,&scale,&shift);
  HLS视频库的一些构造函数具有类似的或替代性的模板参数,例如:
  OpenCV库:cv::Mat&mat(rows,&cols,&CV_8UC3);
  HLS视频库:hls::Mat&mat(rows,&cols);
  ROWS和COLS指定处理的最大图像尺寸。
  表1&VivadoHLS视频处理函数库
  2.2.2&VivadHLS实现OpenCV设计的局限性
  首先,必须用HLS视频库函数代替OpenCV调用。
  其次,不支持OpenCV通过指针访问帧缓存,可以在HLS中使用VDMA和&AXI&Stream&adpater函数代替。
  再者,不支持OpenCV的随机访问。HLS对于读取超过一次的数据必须进行复制,更多的例子可以参见见hls::Duplicate()函数。
  最后,不支持OpenCVS的In-place更新,比如&cvRectangle&(img,&point1,&point2)。
  下表2列举了OpenCV中随机访问一帧图像处理对应HLS视频库的实现方法。
  表2&OpenCV和HLS中对一帧图像像素访问对应方法
  2.3&用HLS实现OpenCV应用的实例(快速角点滤波器image_filter)
  我们通过快速角点的例子,说明通常用VivadoHLS实现OpenCV的流程。首先,开发基于OpenCV的快速角点算法设计,并使用基于OpenCV的测试激励仿真验证这个算法。接着,建立基于视频数据流链的OpenCV处理算法,改写前面OpenCV的通常设计,这样的改写是为了与HLS视频库处理机制相同,方便后面步骤的函数替换。最后,将改写的OpenCV设计中的函数,替换为HLS提供的相应功能的视频函数,并使用VivadoHLS综合,在Xilinx开发环境下在FPGA可编程逻辑或作为Zynq&SOC硬件加速器实现。当然,这些可综合代码也可在处理器或ARM上运行。
  2.3.1&设计基于OpenCV的视频滤波器设计和测试激励
  在这个例子中,首先设计开发完全调用OpenCV库函数的快速角点滤波器设计opencv_image_filter.cpp和这个滤波器的测试激励(不在本例中展示),测试激励用于仿真验证opencv_image_filter算法功能。OpenCV算法实现的设计代码如下:
  void&opencv_image_filter(IplImage*&src,&IplImage*&dst)
  IplImage*&gray&=&cvCreateImage(&cvGetSize(src),&8,&1&);
  cv::Mat&gray_mat(gray,0);
  cvCvtColor(src,&gray,&CV_BGR2GRAY&);
  cv::FAST(&gray_mat,&keypoints,&20,&true);
  cvCopy(&src,dst);
  for&(inti=0;i
  cvRectangle(dst,&cvPoint(keypoints[i].pt.x-1,keypoints[i].pt.y-1),
  cvPoint(keypoints[i].pt.x+1,keypoints[i].pt.y+1),&cvScalar(255,0,0),CV_FILLED);
  cvReleaseImage(&&gray&);
  例子2.3.1&通常的OpenCV视频处理代码opencv_image_filter.cpp
  上面的例子是直接调用OpenCV在处理器上软件应用实现的例子,可以看到在算法设计中直接调用opencV库函数,测试激励读入图像,经过滤波器处理输出的图像保存分析。可以看到,算法的处理基于IPIimage类型,输入和输出图像都使用此类型。
  2.3.2&使用IO函数和Vivado&HLS视频库替换OpenCV函数库
  需要特别说明的是,Xilinx公司通常使用的视频处理模块是基于AXI4&streaming协议进行不同模式见像素数据的交互,也就是我们所说的AXI4&video接口协议格式。为了和Xilinx视频库接口协议统一,VivadoHLS提供了视频接口函数库,用于从OpenCV程序中抽取需要进行RTL综合转换的顶层函数,并把这些可综合的代码和OpenCV不可综合转换的代码进行隔离。然后,对需要综合转换为RTL代码的OpenCV函数,用Xilinx&VivadoHLS提供相应功能的可综合video函数进行替换。最后在C/C++编译环境下仿真验证OpenCV代码和替换video函数后功能的一致性,并在VivadoHLS开发环境中做代码综合和产生RTL代码的co-sim混合仿真验证。
  VivadoHLS可综合的视频接口函数:
  Hls::AXIvideo2Mat&转换AXI4&video&stream到hls::Mat表示格式
  Hls::Mat2AXIvideo&转换hls::Mat数据格式到AXI4&video&stream
  首先,我们对2.3.1中OpenCV的设计进行改写,改写的代码还是完全基于OpenCV的函数,目的是为了对视频的处理机制基于视频流的方式,与VivadoHLS视频库提供函数的处理机制一致。
  其次,使用Vivado&HLS视频库替代标准OpenCV函数,并使用可综合的视频接口函数,采用video&stream的方式交互视频数据。用于FPGA的硬件可综合模块由VivadoHLS视频库函数与接口组成,我们用hls命名空间中的相似函数代替OpenCV函数,增加接口函数构建AXI4&stream类型的接口。
  void&image_filter(AXI_STREAM&&input,&AXI_STREAM&&output,&int&rows,&int&cols)
  hls::Mat&_src(rows,cols);
  hls::Mat&_dst(rows,cols);
  hls::AXIvideo2Mat(input,&_src);
  hls::Mat&src0(rows,cols);
  hls::Mat&src1(rows,cols);
  hls::Mat&mask(rows,cols);
  hls::Matdmask(rows,cols);
  hls::Scalar&3,unsigned&char&&color(255,0,0);
  hls::Duplicate(_src,src0,src1);
  hls::Mat&gray(rows,cols);
  hls::CvtColor(src0,gray);
  hls::FASTX(gray,mask,20,true);
  hls::Dilate(mask,dmask);
  hls::PaintMask(src1,dmask,_dst,color);
  hls::Mat2AXIvideo(_dst,&output);
  例子2.3.2&采用VivadoHLS视频库替换后可综合的设计opencv_image_filter.cpp
  最后,在vivadoHLS开发环境下综合例子2.3.2.2的设计,产生RTL代码并重用OpenCV的测试激励验证RTL代码功能。
  3&VHLS实现OpenCV设计流程总结
  OpenCV函数可实现计算机视觉算法的快速原型设计,并使用VivadoHLS工具转换为RTL代码,在FPGA可编程逻辑上或者Zynq&SoC逻辑上作为硬件加速器,实现高分辨率高帧率的实时视频处理。计算机视觉应用与生俱来的异构特性,使其需要软硬件相结合的实现方案,采用Vivado&HLS视频库能加快OpenCV函数向FPGA或Zynq&SOC全可编程架构的映射。
  参考文献:
  [1]Vivado&Design&Suite&User&Guide:&High-LevelSynthesis(UG902).
  [2]Accelerating&OpenCV&applications&with&Zynq&using&VivadoHLS&video&libraries(XAPP1167)
  [3]Bradski&G,Kaebler&&A.Learning&OpenCV&.ISBN&978-7-302-20993-5
  [4]Implementing&Memory&structure&for&video&processing&in&the&vivadoHLStool(XAPP793)
  [5]&Rafael&C.Gonzalez,Richard&E.Wood&&Digital&Image&Processing,&Third&Edition&ISBN&978-7-121-11008-5
滤波器相关文章:
滤波器相关文章:
c++相关文章:
cvt相关文章:
分享给小伙伴们:
我来说两句……
最新技术贴
微信公众号二
微信公众号一君,已阅读到文档的结尾了呢~~
基于Zynq 的图形生成电路设计与实现
扫扫二维码,随身浏览文档
手机或平板扫扫即可继续访问
基于Zynq 的图形生成电路设计与实现
举报该文档为侵权文档。
举报该文档含有违规或不良信息。
反馈该文档无法正常浏览。
举报该文档为重复文档。
推荐理由:
将文档分享至:
分享完整地址
文档地址:
粘贴到BBS或博客
flash地址:
支持嵌入FLASH地址的网站使用
html代码:
&embed src='/DocinViewer--144.swf' width='100%' height='600' type=application/x-shockwave-flash ALLOWFULLSCREEN='true' ALLOWSCRIPTACCESS='always'&&/embed&
450px*300px480px*400px650px*490px
支持嵌入HTML代码的网站使用
您的内容已经提交成功
您所提交的内容需要审核后才能发布,请您等待!
3秒自动关闭窗口[PATCH 3/7] dmaengine: xilinx_vdma: Add Support for Xilinx AXI Direct Memory Access Engine
[][][][][][]
Subject: [PATCH 3/7] dmaengine: xilinx_vdma: Add Support for Xilinx AXI Direct Memory Access Engine
From: Kedareswara rao Appana &&
Date: Tue, 15 Mar :08 +0530
In-reply-to: &&
This patch adds support for the AXI Direct Memory Access (AXI DMA)
core, which is a soft Xilinx IP core that provides high-
bandwidth direct memory access between memory and AXI4-Stream
type target peripherals.
Signed-off-by: Kedareswara rao Appana &appanad@xxxxxxxxxx&
drivers/dma/xilinx/xilinx_vdma.c | 385 ++++++++++++++++++++++++++++++++++-----
1 file changed, 341 insertions(+), 44 deletions(-)
diff --git a/drivers/dma/xilinx/xilinx_vdma.c b/drivers/dma/xilinx/xilinx_vdma.c
index f682bef..644
--- a/drivers/dma/xilinx/xilinx_vdma.c
+++ b/drivers/dma/xilinx/xilinx_vdma.c
@@ -16,6 +16,12 @@
* video device (S2MM). Initialization, status, interrupt and management
* registers are accessed through an AXI4-Lite slave interface.
The AXI DMA, is a soft IP, which provides high-bandwidth Direct Memory
Access between memory and AXI4-Stream-type target peripherals. It can be
configured to have one channel or two channels and if configured as two
channels, one is to transmit data from memory to a device and another is
to receive from a device.
* 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
@@ -140,6 +146,20 @@
#define XILINX_VDMA_LOOP_COUNT
#define AXIVDMA_SUPPORT
+#define AXIDMA_SUPPORT
+/* AXI DMA Specific Registers/Offsets */
+#define XILINX_DMA_REG_SRCDSTADDR 0x18
+#define XILINX_DMA_REG_DSTADDR
+#define XILINX_DMA_REG_BTT
+#define XILINX_DMA_MAX_TRANS_LEN GENMASK(22, 0)
+#define XILINX_DMA_CR_COALESCE_MAX GENMASK(23, 16)
+#define XILINX_DMA_CR_COALESCE_SHIFT 16
+#define XILINX_DMA_BD_SOP
+#define XILINX_DMA_BD_EOP
+#define XILINX_DMA_COALESCE_MAX
+#define XILINX_DMA_NUM_APP_WORDS 5
* struct xilinx_vdma_desc_hw - Hardware Descriptor
@@ -147,19 +167,23 @@
* @pad1: Reserved @0x04
* @buf_addr: Buffer address @0x08
* @pad2: Reserved @0x0C
- * @vsize: Vertical Size @0x10
+ * @dstaddr_vsize: Vertical Size @0x10
* @hsize: Horizontal Size @0x14
- * @stride: Number of bytes between the first
+ * @control_stride: Number of bytes between the first
pixels of each horizontal line @0x18
+ * @status: Status field @0x1C
+ * @app: APP Fields @0x20 - 0x30
struct xilinx_vdma_desc_hw {
+ u32 dstaddr_
+ u32 control_
+ u32 app[XILINX_DMA_NUM_APP_WORDS];
} __aligned(64);
@@ -209,6 +233,9 @@ struct xilinx_vdma_tx_descriptor {
* @config: Device configuration info
* @flush_on_fsync: Flush on Frame sync
* @desc_pendingcount: Descriptor pending count
+ * @residue: Residue for AXI DMA
+ * @seg_v: Statically allocated segments base
+ * @start_transfer: Differentiate b/w DMA IP's transfer
struct xilinx_vdma_chan {
struct xilinx_vdma_device *
@@ -232,6 +259,9 @@ struct xilinx_vdma_chan {
struct xilinx_vdma_
bool flush_on_
+ struct xilinx_vdma_tx_segment *seg_v;
(*start_transfer)(struct xilinx_vdma_chan *chan);
@@ -436,6 +466,7 @@ static void xilinx_vdma_free_chan_resources(struct dma_chan *dchan)
dev_dbg(chan-&dev, &Free all channel resources.\n&);
xilinx_vdma_free_descriptors(chan);
+ xilinx_vdma_free_tx_segment(chan, chan-&seg_v);
dma_pool_destroy(chan-&desc_pool);
chan-&desc_pool = NULL;
@@ -515,7 +546,12 @@ static int xilinx_vdma_alloc_chan_resources(struct dma_chan *dchan)
return -ENOMEM;
+ chan-&seg_v = xilinx_vdma_alloc_tx_segment(chan);
dma_cookie_init(dchan);
+ /* Enable interrupts */
+ vdma_ctrl_set(chan, XILINX_VDMA_REG_DMACR,
XILINX_VDMA_DMAXR_ALL_IRQ_MASK);
@@ -531,7 +567,37 @@ static enum dma_status xilinx_vdma_tx_status(struct dma_chan *dchan,
dma_cookie_t cookie,
struct dma_tx_state *txstate)
- return dma_cookie_status(dchan, cookie, txstate);
+ struct xilinx_vdma_chan *chan = to_xilinx_chan(dchan);
+ struct xilinx_vdma_tx_descriptor *
+ struct xilinx_vdma_tx_segment *
+ struct xilinx_vdma_desc_hw *
+ enum dma_
+ u32 residue = 0;
+ ret = dma_cookie_status(dchan, cookie, txstate);
+ if (ret == DMA_COMPLETE || !txstate)
+ if (chan-&xdev-&quirks & AXIDMA_SUPPORT) {
desc = list_last_entry(&chan-&active_list,
struct xilinx_vdma_tx_descriptor, node);
spin_lock_irqsave(&chan-&lock, flags);
if (chan-&has_sg) {
list_for_each_entry(segment, &desc-&segments, node) {
hw = &segment-&
residue += (hw-&control_stride - hw-&status) &
XILINX_DMA_MAX_TRANS_LEN;
spin_unlock_irqrestore(&chan-&lock, flags);
chan-&residue =
dma_set_residue(txstate, chan-&residue);
@@ -713,8 +779,9 @@ static void xilinx_vdma_start_transfer(struct xilinx_vdma_chan *chan)
/* HW expects these parameters to be same for one transaction */
vdma_desc_write(chan, XILINX_VDMA_REG_HSIZE, last-&hw.hsize);
vdma_desc_write(chan, XILINX_VDMA_REG_FRMDLY_STRIDE,
last-&hw.stride);
vdma_desc_write(chan, XILINX_VDMA_REG_VSIZE, last-&hw.vsize);
last-&hw.control_stride);
vdma_desc_write(chan, XILINX_VDMA_REG_VSIZE,
last-&hw.dstaddr_vsize);
list_splice_tail_init(&chan-&pending_list, &chan-&active_list);
@@ -736,6 +803,105 @@ static void xilinx_vdma_issue_pending(struct dma_chan *dchan)
+ * xilinx_dma_start_transfer - Starts DMA transfer
+ * @chan: Driver specific channel struct pointer
+static void xilinx_dma_start_transfer(struct xilinx_vdma_chan *chan)
+ struct xilinx_vdma_tx_descriptor *head_desc, *tail_
+ struct xilinx_vdma_tx_segment *tail_segment, *old_head, *new_
+ /* This function was invoked with lock held */
+ if (chan-&err)
+ if (list_empty(&chan-&pending_list))
+ head_desc = list_first_entry(&chan-&pending_list,
struct xilinx_vdma_tx_descriptor, node);
+ tail_desc = list_last_entry(&chan-&pending_list,
struct xilinx_vdma_tx_descriptor, node);
+ tail_segment = list_last_entry(&tail_desc-&segments,
struct xilinx_vdma_tx_segment, node);
+ old_head = list_first_entry(&head_desc-&segments,
struct xilinx_vdma_tx_segment, node);
+ new_head = chan-&seg_v;
+ /* Copy Buffer Descriptor fields. */
+ new_head-&hw = old_head-&
+ /* Swap and save new reserve */
+ list_replace_init(&old_head-&node, &new_head-&node);
+ chan-&seg_v = old_
+ tail_segment-&hw.next_desc = chan-&seg_v-&
+ head_desc-&async_tx.phys = new_head-&
+ /* If it is SG mode and hardware is busy, cannot submit */
+ if (chan-&has_sg && xilinx_vdma_is_running(chan) &&
!xilinx_vdma_is_idle(chan)) {
dev_dbg(chan-&dev, &DMA controller still busy\n&);
+ reg = vdma_ctrl_read(chan, XILINX_VDMA_REG_DMACR);
+ if (chan-&desc_pendingcount &= XILINX_DMA_COALESCE_MAX) {
reg &= ~XILINX_DMA_CR_COALESCE_MAX;
reg |= chan-&desc_pendingcount &&
XILINX_DMA_CR_COALESCE_SHIFT;
vdma_ctrl_write(chan, XILINX_VDMA_REG_DMACR, reg);
+ if (chan-&has_sg)
vdma_ctrl_write(chan, XILINX_VDMA_REG_CURDESC,
head_desc-&async_tx.phys);
+ xilinx_vdma_start(chan);
+ if (chan-&err)
+ /* Start the transfer */
+ if (chan-&has_sg) {
vdma_ctrl_write(chan, XILINX_VDMA_REG_TAILDESC,
tail_segment-&phys);
+ } else {
struct xilinx_vdma_tx_segment *
struct xilinx_vdma_desc_hw *
segment = list_first_entry(&head_desc-&segments,
struct xilinx_vdma_tx_segment, node);
hw = &segment-&
vdma_ctrl_write(chan, XILINX_DMA_REG_SRCDSTADDR, hw-&buf_addr);
/* Start the transfer */
vdma_ctrl_write(chan, XILINX_DMA_REG_BTT,
hw-&control_stride & XILINX_DMA_MAX_TRANS_LEN);
+ list_splice_tail_init(&chan-&pending_list, &chan-&active_list);
+ chan-&desc_pendingcount = 0;
+ * xilinx_dma_issue_pending - Issue pending transactions
+ * @dchan: DMA channel
+static void xilinx_dma_issue_pending(struct dma_chan *dchan)
+ struct xilinx_vdma_chan *chan = to_xilinx_chan(dchan);
+ spin_lock_irqsave(&chan-&lock, flags);
+ xilinx_dma_start_transfer(chan);
+ spin_unlock_irqrestore(&chan-&lock, flags);
* xilinx_vdma_complete_descriptor - Mark the active descriptor as complete
* @chan : xilinx DMA channel
@@ -841,15 +1007,12 @@ static irqreturn_t xilinx_vdma_irq_handler(int irq, void *data)
vdma_ctrl_write(chan, XILINX_VDMA_REG_DMASR,
errors & XILINX_VDMA_DMASR_ERR_RECOVER_MASK);
if (!chan-&flush_on_fsync ||
(errors & ~XILINX_VDMA_DMASR_ERR_RECOVER_MASK)) {
dev_err(chan-&dev,
&Channel %p has errors %x, cdr %x tdr %x\n&,
chan, errors,
vdma_ctrl_read(chan, XILINX_VDMA_REG_CURDESC),
vdma_ctrl_read(chan, XILINX_VDMA_REG_TAILDESC));
chan-&err =
dev_err(chan-&dev,
&Channel %p has errors %x, cdr %x tdr %x\n&,
chan, errors,
vdma_ctrl_read(chan, XILINX_VDMA_REG_CURDESC),
vdma_ctrl_read(chan, XILINX_VDMA_REG_TAILDESC));
chan-&err =
if (status & XILINX_VDMA_DMASR_DLY_CNT_IRQ) {
@@ -863,7 +1026,7 @@ static irqreturn_t xilinx_vdma_irq_handler(int irq, void *data)
if (status & XILINX_VDMA_DMASR_FRM_CNT_IRQ) {
spin_lock(&chan-&lock);
xilinx_vdma_complete_descriptor(chan);
xilinx_vdma_start_transfer(chan);
chan-&start_transfer(chan);
spin_unlock(&chan-&lock);
@@ -903,7 +1066,8 @@ append:
list_add_tail(&desc-&node, &chan-&pending_list);
chan-&desc_pendingcount++;
- if (unlikely(chan-&desc_pendingcount & chan-&num_frms)) {
+ if ((unlikely(chan-&desc_pendingcount & chan-&num_frms)) &&
(chan-&xdev-&quirks & AXIVDMA_SUPPORT)) {
dev_dbg(chan-&dev, &desc pendingcount is too high\n&);
chan-&desc_pendingcount = chan-&num_
@@ -989,11 +1153,11 @@ xilinx_vdma_dma_prep_interleaved(struct dma_chan *dchan,
/* Fill in the hardware descriptor */
hw = &segment-&
- hw-&vsize = xt-&
+ hw-&dstaddr_vsize = xt-&
hw-&hsize = xt-&sgl[0].
- hw-&stride = (xt-&sgl[0].icg + xt-&sgl[0].size) &&
+ hw-&control_stride = (xt-&sgl[0].icg + xt-&sgl[0].size) &&
XILINX_VDMA_FRMDLY_STRIDE_STRIDE_SHIFT;
- hw-&stride |= chan-&config.frm_dly &&
+ hw-&control_stride |= chan-&config.frm_dly &&
XILINX_VDMA_FRMDLY_STRIDE_FRMDLY_SHIFT;
if (xt-&dir != DMA_MEM_TO_DEV)
@@ -83,108 @@ error:
+ * xilinx_dma_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction
+ * @dchan: DMA channel
+ * @sgl: scatterlist to transfer to/from
+ * @sg_len: number of entries in @scatterlist
+ * @direction: DMA direction
+ * @flags: transfer ack flags
+ * @context: APP words of the descriptor
+ * Return: Async transaction descriptor on success and NULL on failure
+static struct dma_async_tx_descriptor *xilinx_dma_prep_slave_sg(
+ struct dma_chan *dchan, struct scatterlist *sgl, unsigned int sg_len,
+ enum dma_transfer_direction direction, unsigned long flags,
+ void *context)
+ struct xilinx_vdma_chan *chan = to_xilinx_chan(dchan);
+ struct xilinx_vdma_tx_descriptor *
+ struct xilinx_vdma_tx_segment *segment = NULL, *prev = NULL;
+ u32 *app_w = (u32 *)
+ struct scatterlist *
+ size_t copy, sg_
+ if (!is_slave_direction(direction))
return NULL;
+ /* Allocate a transaction descriptor. */
+ desc = xilinx_vdma_alloc_tx_descriptor(chan);
+ if (!desc)
return NULL;
+ dma_async_tx_descriptor_init(&desc-&async_tx, &chan-&common);
+ desc-&async_tx.tx_submit = xilinx_vdma_tx_
+ /* Build transactions using information in the scatter gather list */
+ for_each_sg(sgl, sg, sg_len, i) {
sg_used = 0;
/* Loop until the entire scatterlist entry is used */
while (sg_used & sg_dma_len(sg)) {
struct xilinx_vdma_desc_hw *
/* Get a free segment */
segment = xilinx_vdma_alloc_tx_segment(chan);
if (!segment)
* Calculate the maximum number of bytes to transfer,
* making sure it is less than the hw limit
copy = min_t(size_t, sg_dma_len(sg) - sg_used,
XILINX_DMA_MAX_TRANS_LEN);
hw = &segment-&
/* Fill in the descriptor */
hw-&buf_addr = sg_dma_address(sg) + sg_
hw-&control_stride =
if (chan-&direction == DMA_MEM_TO_DEV) {
if (app_w)
memcpy(hw-&app, app_w, sizeof(u32) *
XILINX_DMA_NUM_APP_WORDS);
prev-&hw.next_desc = segment-&
sg_used +=
* Insert the segment into the descriptor segments
list_add_tail(&segment-&node, &desc-&segments);
+ segment = list_first_entry(&desc-&segments,
struct xilinx_vdma_tx_segment, node);
+ desc-&async_tx.phys = segment-&
+ prev-&hw.next_desc = segment-&
+ /* For the last DMA_MEM_TO_DEV transfer, set EOP */
+ if (chan-&direction == DMA_MEM_TO_DEV) {
segment-&hw.control_stride |= XILINX_DMA_BD_SOP;
segment = list_last_entry(&desc-&segments,
struct xilinx_vdma_tx_segment,
segment-&hw.control_stride |= XILINX_DMA_BD_EOP;
+ return &desc-&async_
+ xilinx_vdma_free_tx_descriptor(chan, desc);
+ return NULL;
* xilinx_vdma_terminate_all - Halt the channel and free descriptors
* @chan: Driver specific VDMA Channel pointer
@@ -45,36 @@ static int xilinx_vdma_chan_probe(struct xilinx_vdma_device *xdev,
chan-&id = 0;
chan-&ctrl_offset = XILINX_VDMA_MM2S_CTRL_OFFSET;
chan-&desc_offset = XILINX_VDMA_MM2S_DESC_OFFSET;
if (xdev-&quirks & AXIVDMA_SUPPORT) {
chan-&desc_offset = XILINX_VDMA_MM2S_DESC_OFFSET;
if (xdev-&flush_on_fsync == XILINX_VDMA_FLUSH_BOTH ||
xdev-&flush_on_fsync == XILINX_VDMA_FLUSH_MM2S)
chan-&flush_on_fsync =
if (xdev-&flush_on_fsync == XILINX_VDMA_FLUSH_BOTH ||
xdev-&flush_on_fsync == XILINX_VDMA_FLUSH_MM2S)
chan-&flush_on_fsync =
} else if (of_device_is_compatible(node,
&xlnx,axi-vdma-s2mm-channel&)) {
chan-&direction = DMA_DEV_TO_MEM;
chan-&id = 1;
chan-&ctrl_offset = XILINX_VDMA_S2MM_CTRL_OFFSET;
chan-&desc_offset = XILINX_VDMA_S2MM_DESC_OFFSET;
if (xdev-&quirks & AXIVDMA_SUPPORT) {
chan-&desc_offset = XILINX_VDMA_S2MM_DESC_OFFSET;
if (xdev-&flush_on_fsync == XILINX_VDMA_FLUSH_BOTH ||
xdev-&flush_on_fsync == XILINX_VDMA_FLUSH_S2MM)
chan-&flush_on_fsync =
if (xdev-&flush_on_fsync == XILINX_VDMA_FLUSH_BOTH ||
xdev-&flush_on_fsync == XILINX_VDMA_FLUSH_S2MM)
chan-&flush_on_fsync =
dev_err(xdev-&dev, &Invalid channel compatible node\n&);
return -EINVAL;
+ if (xdev-&quirks & AXIVDMA_SUPPORT)
chan-&start_transfer = xilinx_vdma_start_
chan-&start_transfer = xilinx_dma_start_
/* Request the interrupt */
chan-&irq = irq_of_parse_and_map(node, 0);
err = request_irq(chan-&irq, xilinx_vdma_irq_handler, IRQF_SHARED,
@@ -30,13 @@ static const struct xdma_platform_data xvdma_def = {
.quirks = AXIVDMA_SUPPORT,
+static const struct xdma_platform_data xdma_def = {
+ .quirks = AXIDMA_SUPPORT,
static const struct of_device_id xilinx_vdma_of_ids[] = {
{ .compatible = &xlnx,axi-vdma-1.00.a&, .data = &xvdma_def},
+ { .compatible = &xlnx,axi-dma-1.00.a&, .data = &xdma_def},
MODULE_DEVICE_TABLE(of, xilinx_vdma_of_ids);
@@ -80,22 @@ static int xilinx_vdma_probe(struct platform_device *pdev)
/* Retrieve the DMA engine properties from the device tree */
xdev-&has_sg = of_property_read_bool(node, &xlnx,include-sg&);
- err = of_property_read_u32(node, &xlnx,num-fstores&, &num_frames);
- if (err & 0) {
dev_err(xdev-&dev, &missing xlnx,num-fstores property\n&);
+ if ((xdev-&quirks & AXIVDMA_SUPPORT)) {
- err = of_property_read_u32(node, &xlnx,flush-fsync&,
&xdev-&flush_on_fsync);
- if (err & 0)
dev_warn(xdev-&dev, &missing xlnx,flush-fsync property\n&);
err = of_property_read_u32(node, &xlnx,num-fstores&,
&num_frames);
if (err & 0) {
dev_err(xdev-&dev,
&missing xlnx,num-fstores property\n&);
err = of_property_read_u32(node, &xlnx,flush-fsync&,
&xdev-&flush_on_fsync);
if (err & 0)
dev_warn(xdev-&dev,
&missing xlnx,flush-fsync property\n&);
/* Initialize the DMA engine */
xdev-&common.dev = &pdev-&
@@ -08,20 @@ static int xilinx_vdma_probe(struct platform_device *pdev)
xilinx_vdma_alloc_chan_
xdev-&common.device_free_chan_resources =
xilinx_vdma_free_chan_
- xdev-&common.device_prep_interleaved_dma =
xilinx_vdma_dma_prep_
xdev-&common.device_terminate_all = xilinx_vdma_terminate_
xdev-&common.device_tx_status = xilinx_vdma_tx_
- xdev-&common.device_issue_pending = xilinx_vdma_issue_
+ if (xdev-&quirks & AXIVDMA_SUPPORT) {
xdev-&common.device_issue_pending = xilinx_vdma_issue_
xdev-&common.device_prep_interleaved_dma =
xilinx_vdma_dma_prep_
+ } else {
xdev-&common.device_prep_slave_sg = xilinx_dma_prep_slave_
xdev-&common.device_issue_pending = xilinx_dma_issue_
xdev-&common.directions = BIT(DMA_DEV_TO_MEM) |
BIT(DMA_MEM_TO_DEV);
xdev-&common.residue_granularity =
DMA_RESIDUE_GRANULARITY_SEGMENT;
platform_set_drvdata(pdev, xdev);
@@ -32,11 @@ static int xilinx_vdma_probe(struct platform_device *pdev)
- for (i = 0; i & XILINX_VDMA_MAX_CHANS_PER_DEVICE; i++)
if (xdev-&chan[i])
xdev-&chan[i]-&num_frms = num_
+ if (xdev-&quirks & AXIVDMA_SUPPORT) {
for (i = 0; i & XILINX_VDMA_MAX_CHANS_PER_DEVICE; i++)
if (xdev-&chan[i])
xdev-&chan[i]-&num_frms = num_
/* Register the DMA engine with the core */
dma_async_device_register(&xdev-&common);
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@xxxxxxxxxxxxxxxxxxx
Follow-Ups:
From: Laurent Pinchart
References:
From: Kedareswara rao Appana
Prev by Date:
Next by Date:
Previous by thread:
Next by thread:
Index(es):}

我要回帖

更多关于 xilinx fpga配置方式 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信