在 Zynq UltraScale+ MPSoC 平台下, 建立一個driver, 令 PS(linux kernel) 可以透過 zynqmp_dma DMA controller driver 把 memory 中的資料搬到 PL 中.
使用 dma_proxy(https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18842418/Linux+DMA+From+User+Space) 來修改, 但 dma_proxy 是用 Slave DMA 來做傳送.
1. 如何 match 到 Async TX DMA(zynqmp_dma.c)?
是直接使用 dma_request_slave_channel ?
還是要使用 of_dma_request_slave_channel + dma_request_channel
2. dmaengine_prep_dma_memcpy 所需要用到的 des_addr, src_addr
2.1. des_addr - 在linux driver 中, 把 PL 的位置用 mmap 的方式, mapping 到 PS 的 physical 位置.
如何 mapping 到PS 的 physical 位置?
dma_map_single ?
platform_get_resource + devm_ioremap_resource? devm_ioremap_resource 回傳的 addr 當作 des addr ? 追樣的 __iomem 可以當作 dma_addr_t ?
2.2. src_addr - 使用 dmam_alloc_coherent 去 allocate 出一塊 non-cached dma buffer 來使用.
3. 當 read / write 時, 只需要把 des 與 src 的位置交換即可?
if (pchannel_p->direction == DMA_MEM_TO_DEV) // write
chan_desc = dmaengine_prep_dma_memcpy(pchannel_p->channel_p, dma_dst + offset, pchannel_p->dma_handle, interface_p->length, flags);
else // read
chan_desc = dmaengine_prep_dma_memcpy(pchannel_p->channel_p, pchannel_p->dma_handle, dma_dst + offset, interface_p->length, flags);
4. dtsi 如下:
fpd_dma_chan1
fpd_dma_chan1: dma@fd500000 {
#dma-cells = <1>;
status = "okay";
compatible = "xlnx,zynqmp-dma-1.0";
reg = <0x0 0xfd500000 0x0 0x1000>;
interrupt-parent = <0x4>;
interrupts = <0x0 0x7c 0x4>;
clock-names = "clk_main", "clk_apb";
xlnx,bus-width = <0x80>;
#stream-id-cells = <0x1>;
iommus = <0x9 0x14e8>;
power-domains = <0xa>;
clocks = <0x3 0x13 0x3 0x1f>;
};
dma_proxy_0: dma_proxy@a0000000 {
compatible ="xlnx,dma_proxy";
dmas =
&fpd_dma_chan1 1>;
dma-names = "dma_proxy_tx", "dma_proxy_rx";
reg = <0x0 0xa0000000 0x0 0x1000>;
interrupts = <0 131 4>;
};