2017-02-23 37 views
2

Zynq PLのカスタムI2SコントローラにPCMストリームを転送するために、Zynq-7000ベースのプラットフォームでDMAエンジンを使用しようとしています。私のI2Sコントローラは外部アンプとインターフェースします。私は、AXI-DMAコントローラを通してDMAを使いたいです。これは現在私のデータパスです:ザイリンクスのZynqベースのプラットフォームでAXI-DMA IPを使用するPCM DMAエンジン

axi_dma_path 私はZynq PSでLinux 4.10カーネルを使用しています。私はLinuxのASoCサブシステムを使ってpcmストリームを生成し、私の外部オーディオアンプを制御しています。私はZynqに512MBのDDR RAMを接続しています。このRAMのセクションを使用して、私のDMAエンジンを実行したいと思います。私のI2Sコントローラは、AXI-Liteコントロールインターフェイスで動作し、オーディオストリーミングにはAXI4-Streamインターフェイスを使用します。このIPはテスト済みであり、これらのインターフェイスでうまく動作すると見なすことができます。

以前は、Zynq PSでPL330を使用してDMAエンジンを駆動しました。私のI2SコントローラにはFIFOが内蔵されていましたが、AXI-Liteのレジスタ空間であるため、すべてのDMA転送はAXI-Liteインターフェイスを経由しました。

struct axi_i2s { 
    struct snd_dmaengine_dai_dma_data playback_dma_data; 
    struct snd_dmaengine_dai_dma_data capture_dma_data; 
}; 

static int axi_i2s_dai_probe(struct snd_soc_dai *dai) 
{ 
    struct axi_i2s *i2s = snd_soc_dai_get_drvdata(dai); 

    snd_soc_dai_init_dma_data(dai, &i2s->playback_dma_data, 
     &i2s->capture_dma_data); 

    return 0; 
} 

static struct snd_soc_dai_driver axi_i2s_dai = { 
    .probe = axi_i2s_dai_probe, 
    .playback = { 
     .channels_min = 1, 
     .channels_max = 8, 
     .rates = I2S_RATES, 
     .formats = SNDRV_PCM_FMTBIT_S16_LE | 
       SNDRV_PCM_FMTBIT_S24_LE | 
       SNDRV_PCM_FMTBIT_S32_LE, 
    }, 
}; 

static int axi_i2s_probe(struct platform_device *pdev) 
{ 
    axi_i2s *i2s; 

    i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL); 
    if (!i2s) 
     return -ENOMEM; 

    platform_set_drvdata(pdev, i2s); 

    i2s->playback_dma_data.addr = I2S_BASE_ADDRESS + TX_FIFO_OFFSET; 
    i2s->playback_dma_data.addr_width = 4; 
    i2s->playback_dma_data.maxburst = 1; 

    i2s->capture_dma_data.addr = I2S_BASE_ADDRESS + RX_FIFO_OFFSET; 
    i2s->capture_dma_data.addr_width = 4; 
    i2s->capture_dma_data.maxburst = 1; 

    devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); 

    return 0; 
} 

Devicetree:

dmac_s: [email protected] { 
    compatible = "arm,pl330", "arm,primecell"; 
    reg = <0xf8003000 0x1000>; 
    interrupt-parent = <&intc>; 
    interrupt-names = "abort", "dma0", "dma1", "dma2", "dma3", 
     "dma4", "dma5", "dma6", "dma7"; 
    interrupts = <0 13 4>, 
     <0 14 4>, <0 15 4>, 
     <0 16 4>, <0 17 4>, 
     <0 40 4>, <0 41 4>, 
     <0 42 4>, <0 43 4>; 
    #dma-cells = <1>; 
    #dma-channels = <8>; 
    #dma-requests = <4>; 
    clocks = <&clkc 27>; 
    clock-names = "apb_pclk"; 
}; 

[email protected] { 
    #sound-dai-cells = <1>; 
    compatible = "my,driver"; 
    reg = <0x43C00000 0x10000>; 
    clocks = <&clkc 15>; 
    clock-names = "axi"; 
    dmas = <&dmac_s 0>, <&dmac_s 1>; 
    dma-names = "tx", "rx"; 
    xlnx,dma-type = <0x1>; 
}; 

新規設定

:私は単純にそうように、このFIFOアドレスにDMAエンジンを指摘

/* AXI DMA */ 
axi_dma_0: [email protected] { 
    compatible = "xlnx,axi-dma-1.00.a"; 
    #dma-cells = <1>; 
    reg = < 0x40400000 0x10000 >; 
    xlnx,addrwidth = <0x20>; 
    clocks = <&clkc 15>, <&clkc 15>, <&clkc 15>, <&clkc 15>; 
    clock-names = "s_axi_lite_aclk", "m_axi_sg_aclk", "m_axi_mm2s_aclk", "m_axi_s2mm_aclk"; 
    interrupt-parent = <&intc>; 
    interrupts = < 0 33 4 0 34 4>; 
    dma-ranges = <0x00000000 0x00000000 0x20000000>; 
    //xlnx,include-sg ; 
    [email protected] { 
     compatible = "xlnx,axi-dma-mm2s-channel"; 
     dma-channels = <0x1>; 
     interrupts = < 0 33 4 >; 
     xlnx,datawidth = <0x20>; 
     xlnx,device-id = <0x0>; 
     //xlnx,include-dre ; 
    } ; 
    [email protected] { 
     compatible = "xlnx,axi-dma-s2mm-channel"; 
     dma-channels = <0x1>; 
     interrupts = < 0 34 4 >; 
     xlnx,datawidth = <0x20>; 
     xlnx,device-id = <0x0>; 
     //xlnx,include-dre ; 
    } ; 
}; 

/* New stream version */ 
[email protected] { 
    #sound-dai-cells = <1>; 
    compatible = "my,driver"; 
    reg = <0x43C10000 0x10000>; 
    clocks = <&clkc 15>; 
    clock-names = "axi"; 
    dmas = <&axi_dma_0 0 
     &axi_dma_0 1>; 
    dma-names = "axidma0", "axidma1"; 
    xlnx,dma-type = <0x1>; 
}; 

明らかに、いくつかの詳細が省略されているが、これらを関連ビットです。

ここでは、PL330の代わりにAXI-DMA IPを使用してこのドライバをDMAに変更する方法を理解できません。 DMA転送はFIFOなしの別のメモリ領域で行われるため、AXI-DMAメモリに書き込むためにsnd_dmaengine_dai_dma_data構造体を設定するにはどうすればよいですか?具体的に、このセクション:

i2s->playback_dma_data.addr = I2S_BASE_ADDRESS + TX_FIFO_OFFSET; 
i2s->playback_dma_data.addr_width = 4; 
i2s->playback_dma_data.maxburst = 1; 

i2s->capture_dma_data.addr = I2S_BASE_ADDRESS + RX_FIFO_OFFSET; 
i2s->capture_dma_data.addr_width = 4; 
i2s->capture_dma_data.maxburst = 1; 

AXI-DMA IPは、私のDDRのすべての512メガバイトへのアクセスを持っていますが、カーネルは私のDMA転送のためにメモリを割り当てますどこ私は知りません。

答えて

0

DMAバッファとして使用されるメモリを割り当てるには、Linuxカーネルドライバが必要です。大きな連続バッファが必要な場合は、LinuxカーネルでCMAを有効にする必要があります。あなたのドライバでは、kmallocを使ってメモリを割り当てることができます。

カーネルドライバのリファレンスとして、udmabuf(https://github.com/ikwzm/udmabuf)を使用することをお勧めします。

udmabufは/ sys/class/udmabufのデバイスとして表示され、DMAバッファの物理アドレスはユーザー空間で読み取ることができます。このアドレスをデータをプッシュするターゲット領域としてAXI DMAバッファに渡します。 Zynq上のLinuxでのDMAの

さらに詳しい情報:https://forums.xilinx.com/xlnx/attachments/xlnx/ELINUX/10658/1/drivers-session4-dma-4public.pdf

EDIT: あなたがここに https://forums.xilinx.com/xlnx/attachments/xlnx/ELINUX/10658/2/axidma.c.golden

をAXI DMAための例のLinuxドライバを見つけることができます
関連する問題