Camera 内存相关知识,真的绕不开dma相关接口。这里自我总结一下。
下面只是个人的理解,方便自己以后修正:
一般isp内部会有单向的dma,也就是摄像头数据搬运到ddr,dma一般需求连续物理内存,那么dma api会提供内存分配,映射的接口。我们可以把它看做一个框架接口,具体实现这些接口对上不用关心。对下就可以有多种实现,比如cma,单个设备预留内存,iommu指向的总线内存,以及早期用到的ion内存。Dma api 对下也提供了相关接口用于实现不同种类的操作函数。

1.简单说明几种内存地址
Pa: 物理地址,真实存在的内存,对于硬件设备的寄存器等资源,kernel是按照物理地址来管理。
Va:虚拟地址 ,人为虚拟出来的,既然是虚拟的,那么总要对应到物理地址,页码表就是用来翻译从虚拟地址到物理地址。
Iova:总线地址 ,除了cpu有页码表,设备也有页码表,那么这个内存管理单元就是iommu。那么从虚拟地址要经过cpu的译码表,再到iommu的译码表,才能转换成物理地址。
2.要想使用dma api,都要包含<linux/dma-mapping.h>文件
里面定义和声明了一些对外接口函数。dma_map_ops是对下具体内存模块需要实现的相关函数。里面的dma_addr_t地址,在启用iommu的时候,对应为iova,如果没有iommu,那就是物理地址。
对于部分dma设备地址线的原因,只能访问系统的低位内存,也就是dma寻址限制,要调用下面函数,设置mask
dma_set_coherent_mask
dma api适用于各种架构,对于驱动开发工程师来说,只需要调用dma_map_xxx,而不用调用个总线pci_map_xxx,或者platfrom_map_xxx
3. Dma一致性映射特点
是持续使用的dma buffer,所以一般是在初始化的时候map,在设备退出的时候ummap。
一般使用的时候是noncache,这样不要考虑cache的影响,cpu和dma控制器都可以看到dmabuffer的更新
Dma流式映射
需要传输的时候才map,传输完成就ummap。
所以camera是一致性映射,因为buffer是要连续的接受数据。
4. 主要api函数
cpu_addr = dma_alloc_coherent(dev, size, &dma_handle, gfp);
这个是最常用的分配和映射大段内存的接口,返回dma_handle返回总线地址,cpu_addr是虚拟地址,gfp是内存分配的flag
当然与之对应的是dma_free_coherent

我们videobuffer模块,使用的就是dma_alloc_coherent去分配dam buffer。
dma_handle = dma_map_single(dev, addr, size, direction);
这个是流式dma映射函数,让dma引擎直接在上层传下来的内存里做事。
比如一段内存,开始并不知道要往dma走,所以没用dma分配连续内存,如果这段内存要给dma用,就要调用这个函数,或者dma_map_sg,取决于dma是否支持这种模式,由于这段内存很可能是cache,在调用的时候这个函数会执行之后要执行dma_sync_single_for_cpu 这个是调用cache的flush函数。参数最后是制定方向。主要是这几个
DMA_BIDIRECTIONAL
DMA_TO_DEVICE
DMA_FROM_DEVICE
DMA_NONE

正常看完这些接口,发现实际都是操作内存的,实际没有dma控制器的相关操作。 接下来看dma engine,就是说的这些。
要说这些先得说下dma的一些概念。
1.Channel
Dma 一般有多个channel,传输数据可以选择不同的channel, 这些硬件channel看似可以同时搬运,但因为总线的访问机制,不可能做到同时,实际上内部有仲裁机制。对于使用者而言,无关乎这些,可以认为是同时的。另外除了硬件channel,软件也可以虚拟出channel来, 用软件管理这些channel。对于上层来说,操作都是一样的.
2.Request line
早先看到datasheet
有点不解,只是给出一样表说是Request Mapping Table。
其实dma并不是所有的设备都可以使用(以前我傻b以为是这样),实际每个dma只有专门的几个模块可以使用,具体多少个模块,跟控制器内部连线有关。这个连线称为Request line,让然具体连了多少线,怎么连的我没具体去了解。用于dma和外设通信,是否有数据,fifo是否空闲等等,可以决定是否传输。所以上图应该描述的是外设线为高时候,表明当前设备可以传输。
每个设备都对应一个Request line,但通道数可以小于或者等于连接的外设总数,因为并不是所有外设都需要同时传输。
3.传输参数
传输大小:这个很好理解,一次dma传输总数据大小,为transfer size
传输宽度:在某些场景需要固定每次传输大小,比如声卡16bit采样,每次传输宽度为16bit。这个是transfer width
触发传输大小:当dma用于memory之间的传输的时候。Dma如果一个个搬运也很暂用总线时间,dma可以内部申请buffer,然后buffer填充到一定程度后,来一次dma传输。buffer的大小可以称为burst size
4.主要api接口
 include/linux/dmaengine.h
里面包含实现的主要接口函数以及结构体
dma_device
dma_chan
这两个结构体是驱动主要实现的部分。里面有相关的设备函数。
int dma_async_device_register(struct dma_device *device);
注册函数,在probe中调用,rk代码在kernel\drivers\dma pl330.c
drivers/dma/dmaengine.h
里面包含了几个cookie的接口
static inline void dma_cookie_init(struct dma_chan *chan)
static inline dma_cookie_t dma_cookie_assign(struct dma_async_tx_descriptor *tx)
static inline void dma_cookie_complete(struct dma_async_tx_descriptor *tx)
static inline enum dma_status dma_cookie_status(struct dma_chan *chan,
dma_cookie_t cookie, struct dma_tx_state *state)
static inline void dma_set_residue(struct dma_tx_state *state, u32 residue)
cookie有关的辅助接口,看函数其实是个标志

更多推荐

camera内存之---dma_api简述(4)