FreeBSDのサウンドドライバ始動編

ちょっと思うところあってサウンドドライバーをいじっています。

目標はサウンド再生です。

公式のドキュメントはここにありました。

https://docs.freebsd.org/en/books/arch-handbook/sound/

ハードはロシアの友人にもらった[Onion Omega](https://qiita.com/yamori813/items/db62736cb88bcee9882d)(AtherosのAR9331)をターゲットにしてます。

このSOCはI2SとSPDIF-outのサポートがあります。I2Sは4本の信号線が必要で、SPDIFは1本ですんでお手軽です。SPDIFはGPIO 23に出ています。

SPDIFは4本分の信号を一本で送っているのと、属性情報を送っていたりするのでI2Sより処理は複雑になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/c02079f0-377b-dcbc-1219-33e5d27d5020.png)

Onion Omegaではピンソケットに出ています。

![oni.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/5e5b5d4f-fdfd-a18e-b199-e04cc669d649.png)

I2SはGPIO6,7,8,11かGPIO18,19,20,21で使えますが、GPIO18-の方はピンソケットにすべて出ているようです。

なぜかAR9331のデーターシートはいろいろ抜けています。AR7242やAR9344にあるAUDIO_PLL_CONFIGの記載がありません。
AR9344のデーターシートを参考にしたほうがよいです。ただ微妙に仕様が変わっているので、9331の方も確認が必要です。
AtherosのSOCは24KになったAR71xx以降SOCすべてでI2Sのサポートがあります。AR71xx->AR72xx->AR933x->AR934xのような順番でリリースされています。AR9344にはPINを動的にアサインする機能が追加されているのとPLL周りが若干変わっているようです。

どうもAR933XでPLLまわりをいじったのですが、なんらか問題があったのでAR934Xでは元に戻して拡張したような感じです。

このため全体をサポートするためには大きく分けるとAR71xx,AR72xxとAR933xとAR934x用のコードが必要になると考えられます。

ざっくりながめてみるとI2SのレジスタとDMAの処理をするMailboxのレジスターを制御する必要があるようです。

作る部分は緑のところです。

![freebsd_pcm.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/83fbee38-5db9-2933-7731-402654b500ac.png)

FreeBSDのAtherosのコードはhintsベースの作り込みです。FDTではありません。

通常サウンドの出力にはダブルバッファの仕組みを使い、二つともバッファを埋めてスタートし、片方のバッファが空になった割り込みで再度バッファを埋めを繰り返します。

FreeBSDのサウンドドライバーではpcm_addchan()から始まり、登録されたクラスのchannel_initが呼びされます。

そこでsndbuf_setup()でDMAするバッファを引き渡します。バッファは内部で2つに分けられます。

ドライバ側でも半分で処理するようにして、半分空になったら割り込みが上がるようにします。

半分空になりDMAの割り込みでchn_intr()するとバッファが埋められるようです。chn_intr()からchannel_getptrの関数が呼ばれてバッファを指定されるようです。

しかしKPIにも関わらず関数名に一貫性がなく分かりにくいです。

AR9331のI2SのDMAはMailbox(MBOX)と呼ばれていて、Ethernetと同じようにディスクリプタでバッファを指定してそのディスクリプタをチェインしておいて処理させます。ディスクリプタのバッファのポインターは仮想アドレスではなく物理アドレスを使用する必要があります。もちろんディスクリプタ自体も物理アドレスで設定します。

キャッシュの処理は割り込みが上がったときにディスクリプタのキャッシュを捨てて、OWNフラグを読む必要があることと、バッファを埋めたときにバッファとディスクリプタをメモリに吐く必要があります。

FreeBSDのソースでsys/mips/ingenic/jz4780_aic.cやheadの方にあるgonzoさんのsys/dev/sound/fdtのコードなどが参考になります。

ディスクリプタにはSPDIFに乗せる付加情報(VUC)のデータも設定できます。I2Sの場合は必要ありません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/37df9b38-1951-1d4a-41a2-5192a67fa0f4.png)

バッファのsizeが12Bitしかないので、4095以下でサンプル2,チャンネル2にバウンダリを合わせると4092が最大長になる。これだとダブルバッファではちょっと厳しい気がする。

SPDIFは192フレームで1ブロックで、2ブロックで3Kバイトになるので、このサイズが適当と思われる。48Kサンプリングで8msになる。

再生がRXで録音がTXになるようです。勘違いしそうですね。mailboxから見て受信して再生という事でRXなのかもしれません。

AR9344のデーターシートですが誤植があります。AR7242の誤植がそのままになっているようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/97788609-c90e-751d-4478-068099c3fd7e.png)

いろいろ調べてみたところI2Sは24K初期のAR72xxシリーズでもサポートがあり、I2Sのエンジンはほぼ同じもののようです。ただPLLの仕様が変わっていて設定項目が違います。またAR9331の後の製品のAR9344でもPLLの仕様が変わっています。なぜかAR9344とAR7242は似ているのですが、AR9331はかなり違うように見えます。

探してみたらLinux用のコードが見つかりました。Qualcommに買収後にQualcommが出しだコードのようで"Dual BSD/GPL"ライセンスのようなので参考にしても大丈夫そうです。sys/mipsが消えるのでHeadに入れることはできないので、どうでもよいのですが。(私はBSDライセンスの原理主義者ではありません)

https://github.com/franzflasch/ar9331-i2s-alsa

これ以外にath79-i2s-pll.cが必要です。

別のコードもありました。こちらは買収される前のコードだと思われます。AR934xにも対応したコードになっています。

https://github.com/luotao717/arsdk/tree/9f9004157afcd26b915125576a815f6b3e0cd715/linux/drivers/i2s

こちらもAtherosから出たもののようです。

こちらはちょっと新しいようで、いろいろ書き換えられてます。

https://github.com/KHATEEBNSIT/cpe/tree/47add3b05f818cedbbca379d93ed1e128e3eac91/target/linux/atheros/wp838/wp838_QCA10.1.436/files/drivers/i2s

OMRONにいた頃にLUNA 88Kにカノープス社のCバスカード サウンドマスターを入れてCDクオリティーのサウンドの処理システムを作らせてもらいました。この経験がほんとうに役に立っています。