U-Boot (aarch64) on Qemu を動作させたい (6)
現在は、仕事で触れている freescale の ls1046a Reference Design Board の U-Boot を Qemu で動作させるべく、仮想ボードを作成中。
CPU, RAM, UART と何とか整えてきて、i2c の調整を行っています。
U-Boot 2016.092.0+ga06b20925c (Oct 22 2017 - 21:04:46 +0900) SoC: LS1046AE Rev1.0 (0x87070010) Clock Configuration: CPU0( ):800 MHz CPU1( ):800 MHz CPU2( ):800 MHz CPU3( ):800 MHz Bus: 600 MHz DDR: 2100 MT/s FMAN: 800 MHz Reset Configuration Word (RCW): 00000000: 0c150010 0e000000 00000000 00000000 00000010: 11335559 40000012 60040000 c1000000 00000020: 00000000 00000000 00000000 00238800 00000030: 20124000 00003000 00000096 00000001 Model: LS1046A RDB Board Board: LS1046ARDB, boot from Invalid setting of SW5 CPLD: V0.0 PCBA: V0.0 SERDES Reference Clocks: SD1_CLK1 = 100.00MHZ, SD1_CLK2 = 100.00MHZ I2C: ready DRAM: wait_for_sr_state: failed sr=a1 cr=38 state=202 i2c_init_transfer: failed for chip 0x36 retry=0 wait_for_sr_state: failed sr=a1 cr=38 state=202 i2c_init_transfer: failed for chip 0x36 retry=1 wait_for_sr_state: failed sr=a1 cr=38 state=202 i2c_init_transfer: failed for chip 0x36 retry=2 i2c_init_transfer: give up i2c_regs=0x2180000 wait_for_sr_state: failed sr=a1 cr=38 state=202 i2c_init_transfer: failed for chip 0x51 retry=0 wait_for_sr_state: failed sr=a1 cr=38 state=202 i2c_init_transfer: failed for chip 0x51 retry=1 wait_for_sr_state: failed sr=a1 cr=38 state=202 i2c_init_transfer: failed for chip 0x51 retry=2 i2c_init_transfer: give up i2c_regs=0x2180000 DDR: failed to read SPD from address 81 Error: No valid SPD detected. 16 EiB (DDR not enabled) "Synchronous Abort" handler, esr 0x96000045 ELR: fff638e8 LR: ffefd214 x0 : 00000007ffe00000 x1 : 0000000000000000 x2 : 0000000000001000 x3 : 00000007ffe01000 x4 : 00000007ffe00000 x5 : 0000000000000000 x6 : 00000000000001e8 x7 : 0000000000000001 x8 : 0000000082070550 x9 : 000000007defb000 x10: 0000000000000403 x11: 0000000082059274 x12: 0000000000000002 x13: 0000000000000000 x14: 0000000000000000 x15: 0000000082003228 x16: 0000000000000000 x17: 0000000000000000 x18: 00000000ffdf8d70 x19: 00000007ffe00000 x20: 00000007ffe00000 x21: 0000000000000000 x22: 00000000fff89490 x23: 0000000000000000 x24: 0000000000000000 x25: 0000000000000000 x26: 0000000000000000 x27: 0000000000000000 x28: 0000000082001cd8 x29: 00000000ffdf6680 Resetting CPU ... resetting ... guts: Unknown register read: b0 guts: Unknown register write: b0 = 2
最終的には Abort してしまっているけど、原因がどこかは現時点では未調査。
タイムアウトの原因を GDB で追いかけると、 i2c_init_transfer_()
から tx_byte()
に入り、 I2DR にスレーブアドレスを書き込んだあとに、 I2SR_IIF ビット (割り込み) が立たないため、タイムアウトが発生していた。
Qemu 側も GDB で追いかけると、imx_i2c.c から i2c/core.c の i2c_start_transfer()
を呼び出したところで QTAILQ_FOREACH()
マクロの処理が行われていないため、 I2SR_IIF ビットを立てる処理が実施されていないことがわかった。
QTAILQ_FOREACH()
マクロは、 &bus->qbus.children.tqh_first
にデータがある場合に実行される処理で、タイムアウトの場合は NULL となっていたため、 bus->current_devs.lh_first
も空のままになり、下の QLIST_EMPTY で return 1 となっていた。
if (QLIST_EMPTY(&bus->current_devs)) { QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) { DeviceState *qdev = kid->child; I2CSlave *candidate = I2C_SLAVE(qdev); if ((candidate->address == address) || (bus->broadcast)) { node = g_malloc(sizeof(struct I2CNode)); node->elt = candidate; QLIST_INSERT_HEAD(&bus->current_devs, node, next); if (!bus->broadcast) { break; } } } bus_scanned = true; } if (QLIST_EMPTY(&bus->current_devs)) { return 1; }
bus->qbus.children.tqh_first
にデータが入る条件を調べると、 qdev_set_parent_bus()
が呼ばれた場合であることがわかった。
qdev_set_parent_bus()
は、システムバズに仮想デバイスをつなぐ場合に呼び出している処理で、特定のバスに仮想デバイスを接続する機能を持っている。
ということは、現在は i2c バスにデバイスが接続されていないから、スレーブアドレスの書き込みでタイムアウトになっている、ということ?
backtrace を確認すると、 DDR の SPD アクセスに使用していることがわかった。
DDR の情報が取得できないので、 Abort につながっているようだ。