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