0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Qua Station(RTD1295)をClaude CodeでUbuntu 26.04+mainline Linux 6.18導入記録(2)ハードウェア復活編

0
Last updated at Posted at 2026-09-21

(1)では、シリアルコンソール無しでrootfs起動不能の原因(tarがusrmergeのシンボリックリンクを破壊していた)を突き止めるまでを書きました。本編では、そこから実際のハードウェア(SATA・PCIe・Wi-Fi)を1つずつ復活させていく過程を扱います。

各デバイスの特定方法とドライバ入手元

本題に入る前に、各デバイスを「どうやって特定したか」「ドライバをどこから持ってきたか」を一覧にしておきます。同じSoC・似た機種で作業する人には、個別の詳細よりこちらの方が有用かもしれません。

デバイス 特定方法 ドライバ入手元
CPU(Cortex-A53 ×4) cat /proc/cpuinfo・nproc mainline標準
GMAC(内蔵Ethernet)※ 4.9のDTBにRealtek,r8168ノードあり symops/monarch-6.18に実装済み(r8169soc.c)
クロックゲート ベンダーBSPソースcgc.cの解析+4.9 DTBとのビット照合(前述) 新規実装(BSPをmainline流儀に移植)
SATA(AHCI) 0xdeadbeefの実測+clk_summaryでクロック状態を直接確認(前述) symops/monarch-6.18のahci_rtd1295.cに追記
misc GPIO 4.9 DTBのRealtek,usb-manager等の記述からLED/電源制御の対応を特定 mainlineに既存(gpio-rtd.c)、DTノード追加のみで対応
PCIe(Wi-Fiカード) lspciのVendor:Device ID(10ec:818b(RTL8192EE)/10ec:8812(RTL8812AE)) ホストドライバはafaerber/linuxの資産をベースに新規実装。Wi-Fi本体のドライバはLinuxカーネル標準のrtlwifi/rtl8192ee・rtl8821ae(既存)
Wi-Fiファームウェア dmesgのfirmware要求名 linux-firmware(ライセンス確認済み、後述)
Bluetooth(RTL8761ATV)※後日 HCI_Read_Local_Versionコマンドの応答(LMP Subversion=0x8761がそのままチップ型番) mainlineのbtrtlはUSB接続のみ対応。今回はUART接続のため4.9側のrtk_hciattachを暫定利用中。mainline化(serdev対応)は次回以降の課題
USB(dwc3/xHCI) lsusbで列挙確認 symops/monarch-6.18に実装済み
LED・ボタン(11個) 4.9 DTBのgpio-leds/gpio-keysノードとsysfs名の突き合わせ DT定義のみ、ドライバはmainline標準のleds-gpio/gpio-keys

※ GMACは端子が無いのに中身にチップは載っていました。試しに有効化したら動いてしまった話は後述します。※後日: Bluetoothの識別方法は、本編が扱う(1)(2)のセッション時点ではなく、その後の別セッションで確定した内容です。

やったこと(ハードウェア復活の流れ)

(1)のシリアルレス診断でrootfs問題を解決した後は、「1回のビルドにつき1機能だけ有効化し、そのたびに再起動して確認する」という手堅い方式で、ハードウェアを1つずつ復活させていきました。実機が本番稼働中のため、一気に全部盛り込んで失敗した時の切り分けコストを避ける狙いです。

段階 内容 結果
CPU maxcpus=1を外してCPU4個をフル活用 成功
GMAC※ 内蔵Ethernet有効化 成功(ただし後述の通り端子(RJ45)が無いので無効化に戻した)
GPIO misc GPIOコントローラ投入(PCIeの電源制御に必須の土台) 成功
LED/ボタン 物理LED11個のマッピング確定、ボタン極性修正 成功
クロックゲート RTD129x用クロックゲートドライバを新規実装(57ゲート) 成功
SATA クロック・リセット・電源GPIOの3点を追加 1TB SSDを無介入で認識
PCIe PCIeホストドライバを新規実装 Wi-Fi 2.4GHz/5GHzの両カードが同時リンクアップ

SATA: クロックゲート未開放によるポイズン値0xdeadbeef(実測で確定)

SATAを最初に有効化した際、起動が止まりレジスタから0xdeadbeefという値が読めました。これはクロック・リセットゲートが未開放のままレジスタを読んだ時に返る、Armコアでよく知られたポイズン値です。ここで「たぶんクロックだろう」で済ませず、実際にクロックの状態を読める手段を先に作って確認しました。

まず、ベンダーのBSPソース(bsp/linux/drivers/clk/realtek/cgc.c)をmainlineの流儀に移植する形で、RTD129x用クロックゲートドライバ(clk-rtd129x-gate.c)を新規実装しました。ビット割り当てが正しいかは、ビルドしたDTBと稼働中の4.9カーネルのDTB(/sys/firmware/fdtから取得済み)をレジスタアドレス単位で突き合わせて検証しています。

9800000c <-> clock-gate@c   32/32 全ビット一致
98000010 <-> clock-gate@10  32/32 全ビット一致
9800708c <-> clock-gate@8c  13/13 全ビット一致
総合判定: 完全一致

この段階ではまだどのクロックにもドライバをぶら下げず(consumer 0個)、clk_ignore_unusedを付けて安全に起動確認だけしました。起動後/sys/kernel/debug/clk/clk_summaryを見ると57個のゲートが登録され、実機の現在のクロック状態がそのまま読めます。

clk_en_sata_0          hw_enable=N   <- SATAのクロックが切れている
clk_en_sata_alive_0    hw_enable=N
clk_en_pcie0           hw_enable=N   <- PCIeも切れている
clk_en_pcie1           hw_enable=N
clk_en_i2c0            hw_enable=Y   <- I2Cのクロックは既に入っている

これで「SATAとPCIeのクロックが切れている」ことが推測ではなく実測で確定しました(逆にI2Cは既にクロックが入っており、当初の「クロック側が原因」という仮説はI2Cについては誤りだったことも同時に分かりました)。この上でクロック・リセット・電源制御GPIOの3点をまとめて有効化したところ、追加の個別対応なしで1TB SSDがそのまま認識されました。

PCIe: RTD1295特有の「ページ切り替えMMIO窓」

PCIeスロット自体は見え、config空間も読めるのに、Realtek製Wi-FiカードのレジスタアクセスだけInit MAC failedでTimeoutする問題がありました。

最初の実装では、afaerber/linuxの資産をベースにPCIeホストドライバ(pcie-rtd129x.c)を新規実装し、DT側にPCIeのMMIO領域として0xc0000000/0xc1000000(各16MB)を割り当てていました。これはPCIe config空間の列挙自体は正しく動くのですが、Wi-Fiカードの実際のレジスタ(BAR)はこのアドレスに配線されていませんでした。実機で直接読むと空振りします。

rdmem 0xc0000000 → ffffffff ffff63ff ffefdffb ...(ゴミ)
dmesg: rtl8192ee: Init MAC failed, rtl8821ae: Init MAC failed

ベンダーの独自ドライバ(slot1.cのrtk_pcie1_read/write)を読むと、実際のレジスタアクセスは固定アドレス0x9804f000にある4KBの「窓」経由で行われており、0xD04オフセットのTRANSレジスタに「今どのアドレス範囲を窓に見せるか」を書き込んでから読み書きする、という設計でした。試しにこの窓経由で読むと、正しい値が返ってきます。

REG_PCI_BASE 9804ecfc=9804f000  MASK 9804ed00=fffff000  TRANS 9804ed04=c0000000
rdmem 0x9804f000 → 51c0b2f3 14020012 00203023 ...(窓経由は本物のレジスタ)

つまりRTD1295は、PCIeデバイスのMMIO空間をCPUのアドレス空間に直接マッピングせず、この4KB窓を都度切り替えてアクセスする設計になっているとわかりました(さらにこの窓には0xc68/0xcecオフセットがコントローラ自身のレジスタと衝突するというハードウェア特有の癖もあり、ベンダードライバはこの2箇所だけマスクを2KBにずらして回避しています)。

これを踏まえ、ページ切り替え窓を読み書きする関数(rtd129x_pcie_mmio_read/write())を新規実装してPCIeホストドライバからEXPORT_SYMBOL_GPLで公開し、rtlwifiドライバ側の_rtl_pci_io_handler_init()(レジスタアクセスが必ずこの関数ポインタ経由になっている箇所)を、RTD129xの場合はこの窓経由の関数に差し替える形にしました。実機のメモリ読み書きツール(devmemベースの自作ツール)で窓の切り替え自体が正常に動くことも別途確認した上での実装です。

dmesg: rtlwifi: using RTD129x paged MMIO window
       Init MAC failed  ← 消滅

落とし穴: 偽ファームウェア

窓経由のアクセスに切り替えた後もchksum report failが出てWi-Fiが起動しませんでした。デバッグログで「Firmware SIZE 3165」という不自然に小さいサイズが出ていたためfileコマンドで正体を確認したところ、linux-firmwareのcgitの/plain/URLから取得していたファイルの中身がHTMLエラーページでした。取得したバイナリはサイズやfileの出力で必ず検証してから配置する、という教訓を得ました。

ファームウェアの入手元とライセンス

正しいファームウェアは、開発用PC(x86_64 Ubuntu 26.04LTS、(1)の環境表参照)にlinux-firmwareパッケージ経由で既に入っていたrtl8192eefw.bin.zst(32286バイトに圧縮復元)を配置して解決しました。QuaStation実機用に取得したわけではなく、開発用PC自身のディストリが元々持っていたファイルを転用した形です。この機会に、配布・再配布してよいものか出典を確認しています。

RTL8192EE/RTL8812AE用のファームウェアはlinux-firmwareプロジェクトが配布元で、WHENCEファイルに以下のように明記されています。

Driver: rtl8192ee - Realtek 802.11n WLAN driver for RTL8192EE
File: rtlwifi/rtl8192eefw.bin (rtl8192eu_nic.binへのリンク)
Licence: Redistributable. See LICENCE.rtlwifi_firmware.txt for details.

Driver: rtl8821ae - Realtek 802.11n WLAN driver for RTL8812AE  (原文ママ。RTL8812AE自体は802.11ac対応)
File: rtlwifi/rtl8812aefw.bin
Licence: Redistributable. See LICENCE.rtlwifi_firmware.txt for details.

LICENCE.rtlwifi_firmware.txt(Realtek Semiconductor Corporation, 2010)を見ると、無改変のバイナリ形式での再配布は明示的に許可されています(著作権表示・免責事項の保持が条件、リバースエンジニアリングは禁止)。今回のように「正しい入手元から落とし直して配置する」使い方は問題ありません。

MSI割り込みでのカーネルパニック

MSI(Message Signaled Interrupts)を有効化した瞬間にパニックする問題も発生しました。カーネル内部のmsi_domain_update_chip_ops()は、親chipにirq_set_affinityが無い場合にmsi_domain_set_affinity()を自動的に差し込む仕様になっています(ここまでは正常動作)。原因は、その差し込まれたmsi_domain_set_affinity()が実行時に親chipのirq_set_affinity(実体はNULL)を呼び出そうとしてクラッシュしていたことでした。MSI_FLAG_NO_AFFINITYフラグを追加してパニックは解消しましたが、その後もWi-Fiスキャンが完了しない別の問題(割り込みが一度も発火しない、hwirqが異常値)が残ったため、今回は動作実績のあるINTx方式へロールバックしています。根本原因は次回への宿題です。

LED・ボタン: 物理的に光らせて確かめる

LEDとボタンは、データシートやDTBの記述だけでは正しいかどうか分かりません。実際に光らせて・押して確認しています。

LEDの物理同定: 4.9のDTBには12個のLED(2色LED5箇所分=10個、単色の制御線led_ctrl/led_ctrl1が2個の内訳)が定義されていましたが、6.18側は当初5個しか移植できていませんでした。1個ずつ点灯させて、実機の物理的な位置とラベルの対応を目視で確定させています。

位置 ラベル 緑 赤
前面中央 wifi_led misc 8 iso 7
前面右 hdd_led misc 6 misc 7
上部(COPYボタン脇) imp_led misc 5 misc 100
前面左? lte_led misc 19 misc 17
背面下 pwr_led iso 29 iso 30

このうちlte_ledの緑側(misc 19)はUSBポート電源と兼用のため意図的に除外し、12個中11個を最終的に登録しています(led_ctrl/led_ctrl1の2個は用途不明の制御線で、直接光るLEDではありません)。

面白い発見がありました。lte_ledを駆動しているGPIO(misc 19)がUSBポートの電源制御と兼用されていたことです。4.9側のソースを読むと分かる話で、もし気づかずこのGPIOをLED用に叩いていたら、USB接続の起動ディスクの電源を落としてブートディスクを見失うところでした。LEDとして使うのは保留にしています。

なおlte_ledだけは他のLEDと違い、点灯順序からの消去法で位置を推定したもので、ケースを閉じた外側から実際に視認できるかは未確認です(基板上には存在するが、外装からは見えない設計の可能性もあります)。

ボタンの極性: evtestで物理ボタンを押してもらい、生イベントを見ながら対応を確定させました。

Event: type 1 (EV_KEY), code 133 (KEY_COPY), value 0
Event: type 1 (EV_KEY), code 133 (KEY_COPY), value 1

DT上はGPIO_ACTIVE_HIGHと書かれていましたが、押した瞬間にvalue 0が出ていたため、実物はアクティブLOWと判明(極性が逆でした)。

4.9側のソースにはCOPYボタンとは別に、専用のPOWERボタン用GPIO(iso 8)が定義されていました。ただしこちらは6.18のDTSではコメントアウトされたままで、物理的な所在や極性の確証も取れていませんでした。一方でCOPYボタンは実際に押してevtestで挙動を確認済み・アクセスもしやすい場所にあります。そこで、確証の薄い専用POWERボタンを掘り下げるより、動作確認済みのCOPYボタンにKEY_POWERを割り当てる方針に切り替えました。実機の刻印は「COPY」のままですが、機能としては電源ボタンとして使える状態にしています。

起動インジケータと、自分自身への濡れ衣: 「起動中は赤、Ubuntu起動が終わったら緑」という表示を実装した際、pwr_led_gのLEDがDT側でdefault-state="off"を指定しているのに反映されない、という現象に遭遇しました。最初はカーネルのgpio-leds実装を疑いましたが、真犯人は**(1)のシリアルレス診断で作った内蔵initramfsの生存確認スクリプト**でした。

# ~/work/quastation-mainline-survey/qua-initramfs/init の残骸
for l in /sys/class/leds/pwr_led_g /sys/class/leds/led_ctrl1; do
  [ -d $l ] && { echo none > $l/trigger; echo 255 > $l/brightness; }; done

診断中に「initramfsがちゃんと動いているか」を目視確認するために書いたこのコードが、rootfsマウント前に毎回実行され続け、pwr_led_gのトリガ指定を問答無用で上書きしていました。カーネル側の設定は最初から正しかった、という結論です。この教訓から、/sysへの書き込み元を疑うときはrootfsだけでなくCONFIG_INITRAMFS_SOURCEで焼き込んだ内容も見るようにしています。修正後は、パニック発生を示す専用LED(panic-indicatorプロパティが必要で、トリガ指定だけでは反応しないという癖あり)も含めて意図通り動作しています。

仕上げ: MACアドレス固定と5GHz常用化

再起動のたびにWi-FiのMACアドレスがランダム化されるのを固定し、5GHz(RTL8812AE)を優先経路、2.4GHz(RTL8192EE)をフォールバックに設定しました。

wlan0(2.4GHz)  metric 600(フォールバック)
wlan1(5GHz)    metric 100(既定ルート)
default via 192.168.1.1 dev wlan1

systemdの.linkファイルによるMACAddress=指定はudevadm test-builtinではマッチするのに実機では反映されず、原因は未特定のままです。代わりにwpa_supplicant@.service.dのExecStartPreで直接ip link set <dev> address ...する方式に切り替えたところ、こちらは確実に効きました。再起動を跨いで両方の動作を確認済みです。

細かいけど地味に手間取った話

大きな山だけでなく、地味に足を取られた話も書いておきます。同じ作業をする人には案外こっちの方が役に立つかもしれません。

  • USBポートの電源GPIOという誤った仮説: 一部のUSBポートにハブが認識されない事象があり、「ベンダーの4.9系ドライバはポートごとにVBUS電源をGPIOで制御している」という記述を根拠に、GPIOを出力Highにする実装まで作りました。しかし実機で確認するとそのGPIOは既にU-Boot側でHighにされており、電源の問題ではありませんでした(仮説は棄却)。真因は単純で、USBハブを挿すポート(USB2用の黒ポートではなくUSB3用の青ポート)を変えたら通っただけでした。それらしい理由を見つけても、まず実機で状態を読んでから実装するべきだった、という反省点です
  • BOOTパーティションが満杯で配置に失敗: FAT32・99MBのBOOTパーティションに、試行錯誤のたびに作った中間ビルド(uImage.run28b/c/d等)を消さずに溜め込んでいたら、cpが容量不足で失敗するようになりました。純正のカーネルイメージと直前の安定版だけ残して他を削除し、58%まで回復させています
  • git commit -mがバッククォートで壊れる: コミットメッセージにコードの引用(バッククォート囲み)を入れたところ、シェルのコマンド置換として解釈されてコミットに失敗しました。以後はgit commit -F <ファイル>でメッセージをファイル経由で渡す方式に切り替えています
  • ※有線LANの端子(RJ45)は無いが、中身にはチップが載っていた: 実機に有線LANの端子は無いのですが、4.9のDTBを見るとRealtek,r8168ノードがあり、GMACのチップ自体は基板に載っていることに気づきました。試しにドライバをmainlineへ有効化してみたところ、r8169 Gigabit Ethernet driverが正常にロードされeth0として認識され、あっさり動いてしまいました。ただし端子が無いので繋ぎようがありません(w)。使い道が無いので、この機能は無効に戻しています。ドライバが動く=実際に使えるハードウェアがある、とは限らない好例です

現在の到達点

  • USB起動(本番SSD無傷)でUbuntu 26.04 + Linux 6.18.52が動作中
  • SATA完全復活。1TB SSDを無介入で認識
  • PCIeホスト新規実装成功。Wi-Fi 2.4GHz(RTL8192EE)/5GHz(RTL8812AE)が同時にリンクアップし、インターネット疎通も確認済み
  • MACアドレス固定・5GHz優先経路化を再起動を跨いで確認済み
  • 物理LED11個の配置確定、ボタン極性修正、起動状況インジケータも実装済み
  • COPYボタンにKEY_POWERを割り当てたので、本体のCOPYボタン長押しで電源を切る設定も可能だと思われる(設定自体は入れているが、実際に長押しして確認するところまではまだやっていない)

Bluetoothについては、(1)・(2)のセッション時点では「チップ不明・調査保留」でしたが、その後の別作業でRTL8761ATVと判明し起動にも成功しています。

残課題

  1. MSI割り込みが発火しない根本原因の解明
  2. systemdの.linkファイルによるMACアドレス固定が実機では効かなかった原因の特定(回避策は前述の「仕上げ: MACアドレス固定と5GHz常用化」に記載)
  3. 最終ゴール本体: SSDへのパーティション作成とSSDからの起動(次回)
  4. 有線LAN(USB接続の外付けアダプタ)を外し、完全無線のみでの運用への移行

マルチエージェント構成について少しだけ

実装作業のほぼすべてをClaude Codeが担当していますが、作業の難易度に応じてモデルを使い分けています。

  • 大改修(クロックゲートドライバやPCIeホストドライバの新規実装など): Fable 5.1
  • 簡単な作業(DTのステータスを1行変えて再起動確認する等): Sonnet 5
  • その中間(SATAのポイズン値の原因裏付け、LEDトリガが効かない原因の切り分けなど): Opus 5

実装するモデルとレビューするモデルを分けることで、「実装した本人が見落としを追認してしまう」リスクを減らす狙いもあります。

さらに、これとは逆方向の仕組みも併用しています。通常のサブエージェントは「上位モデルが下位モデルに作業を振る」トップダウン型ですが、今回はそれに加えて下位モデルが自分で判断に迷った時に、自分から上位モデルへ相談を投げるボトムアップ型の相談機構も使いました。SATAのポイズン値の原因裏付けや今回の記事の査読自体がこのパターンで、実装や執筆を担当したモデルが「これで合っているか」を上位モデルに確認してから先に進む、という使い方をしています。今回はこの構成のおかげで原因特定が早まった場面がいくつかありました。

おわりに

「載っているハードウェアは全部使える状態にしたい」というのが今回の一番の動機でした。クロックゲート・PCIeという、ベンダーの独自カーネルでしか動いていなかった部分をmainline Linuxの流儀で一つずつ叩き起こしていく作業は地味ですが手応えがありました。次回は本番SSDへの実装に進みます。

ビルド成果物の公開

同じ機種で試したい方向けに、ここまでの全修正(SSD移行・SATA/PCIe/Wi-Fi/LED・USB2.0/PCIe診断ログ対応)を含む最終版のカーネルソース・Image・DTBをGitHubで公開しました。ソースは(2)で触れた通りGPL-2.0の派生物としてsymops/monarch-6.18をフォークする形で公開し、コンパイル済みのバイナリもReleaseとして添付しています。rootfs側については公開していませんが、公開の基準を満たせる状態になればこちらも公開しようと考えています。それまでは(1)(3)に書いた手順(公式Ubuntu Baseからの構築)で各自作成していただければと思います。

公開ファイルのハッシュ値(実機の稼働中BOOTパーティションから直接取得した、現在動いているビルドそのものです):

30f74fe861f129ce4b8cf7e25dc6fd33ea5d22cd0738a436256f20c38583c19b  uImage (17,166,848 bytes)
e0a71d92fd98f5fcaa2b331e8e94b4b24d23dfe038b4150c27df56e8ce88984f  QuaStation.dtb (33,639 bytes)

Releaseに添付したファイルのハッシュと一致することを確認しています。

参考文献(シリーズ共通)

今回の移植は先人の資産の上に成り立っています。ベースにしたもの・参照したものを、実機(Qua Station)に近い国内発の情報源、同じSoCの海外コミュニティ情報源、および各種公式ドキュメントに分けて挙げます。

国内(Qua Station実機ベース)

海外(同じRTD1295系SoCのコミュニティ資産)

Wi-Fiファームウェアのライセンス

Bluetooth / D-Bus

ファイルシステム復旧(e2fsprogs)

シリーズ目次

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?