rtwo: fix UFS bring-up and FIT boot_a chainload

Several stacked bugs were blocking boot_a resolution and kernel handoff,
found by working backwards from "could not resolve boot_a partition":

- clock-sm8550.c: add missing GCC_CFG_NOC_USB3_PRIM_AXI_CLK gate
  (offset 0x39088 bit 0, verified against upstream gcc-sm8550.c). Needed
  by the mainline USB DT nodes added to the vendor control-DTB (not
  tracked in this repo, see ~/pmos/uboot-chainload/vendor-dtb-from-
  boot_v14_dbg.dtb on the dev machine).

- bootcmd: boot_a is on `scsi 3`, not `scsi 0` -- Motorola splits UFS
  into multiple LUNs, with boot-critical A/B partitions (boot_a/b,
  dtbo_a/b, vbmeta_a/b) on a small 1.1 GB LUN separate from the ~236 GB
  "user" LUN. Confirmed via `part number scsi N boot_a` sweep on
  hardware.

- bootcmd: every setexpr call was missing the `$` before its operand
  variable names (`boot_a_size` instead of `$boot_a_size`, etc).
  setexpr always parses operands as hex via hextoul(), so the literal
  string "boot_a_size" was read as 0xb (stops at the first non-hex
  char), producing a nonsensical blksz and an integer-underflowed
  fit_blk_cnt. This silently produced garbage even before the UFS fixes
  below, since boot_a was never reached until now.

- bootcmd: `scsi read` doesn't take a device argument, it operates on
  the last device selected via `scsi dev`; add that before the read.

The UFS host controller (ufshc@1d84000) and its PHY were never binding
at all in U-Boot, independent of all of the above -- three separate
issues in the vendor control-DTB (not in this repo):
  1. Both nodes used `status = "ok"`, which fdtdec_get_is_enabled()
     treats as disabled (it only accepts "okay").
  2. The UFS PHY's compatible was the downstream
     "qcom,ufs-phy-qmp-v4-kalama", unrecognized by phy-qcom-qmp-ufs.c
     (needs "qcom,sm8550-qmp-ufs-phy").
  3. Both the host controller's and PHY's clocks lists referenced
     "qcom,kalama-rpmh-clk" (the root XO), which has no matching driver
     in this U-Boot tree -- clk_get_bulk()/clk_get_by_index() on it
     returned -ENODEV, aborting ufshcd_probe(). Removed the unused
     reference on the host controller and added a plain 19.2 MHz
     fixed-clock node for the PHY's ref_clk_src, which is the only
     actual consumer of it by index.

Confirmed on hardware (2026-09-17): boot_a resolves, the raw FIT read
from UFS succeeds, and bootm loads kernel+ramdisk+fdt with hash
verification OK and reaches "Starting kernel ...". The kernel itself
now resets very early after that -- separate, unrelated bring-up work,
not a U-Boot/chainload issue.

Diagnostic bootmenu entries (12-14) are debugging aids kept for the
next round of hardware bring-up, along with the two `pause` statements
added to bootcmd around the SCSI read and bootm calls.
This commit is contained in:
2026-09-17 18:24:10 -03:00
parent 8e92d068c3
commit bc6a059bf8
2 changed files with 25 additions and 8 deletions
+23 -8
View File
@@ -22,14 +22,26 @@ serial_gadget=setenv stdin serial,button-kbd,usbacm; \
# then bail out to the boot menu instead (with a pause to read # then bail out to the boot menu instead (with a pause to read
# the error message) # the error message)
# #
# rtwo (Motorola Edge 40 Pro, SM8550): the ABL loads the FIT image # rtwo (Motorola Edge 40 Pro, SM8550): the FIT image (mainline Image +
# (mainline Image + dtb + initramfs) into the ramdisk slot of the # dtb + initramfs) is packed by pack-fixedoff.py at a FIXED FILE OFFSET
# Android boot.img. The ABL writes that address into # (0x18c000) inside boot_a -- same offset the ABL uses to load kernel/
# /chosen/linux,initrd-start of the fdt it hands us, and U-Boot saves # dtb, discovered via RE because this ABL does NOT follow the standard
# it as $prevbl_initrd_start_addr (CONFIG_SAVE_PREV_BL_INITRAMFS_START_ADDR). # Android boot.img formula. Confirmed in hardware (2026-09-17): trusting
# Try that first; only fall back to the phone menu if it fails. # $prevbl_initrd_start_addr (CONFIG_SAVE_PREV_BL_INITRAMFS_START_ADDR,
pmos_bootargs=earlycon console=ttyMSM0,115200n8 panic=5 pmos.debug-shell clk_ignore_unused pd_ignore_unused regulator_ignore_unused allow_mismatched_32bit_el0 pmos_boot_uuid=d4373976-057c-4cf3-a43d-00734001b405 pmos_root_uuid=09804032-85bb-4d57-95a5-00d1965fb10f pmos_rootfsopts=defaults # i.e. what the ABL claims via /chosen/linux,initrd-start) fails with
bootcmd=setenv bootargs $pmos_bootargs; echo pmOS: booting FIT at prevbl_initrd_start_addr=$prevbl_initrd_start_addr; bootm $prevbl_initrd_start_addr; echo pmOS: bootm failed; bootefi bootmgr; pause; run menucmd # "ERROR -91E: can't get kernel image!" (EPROTOTYPE, no FIT magic at
# that address) -- consistent with the ABL's fixed-offset loading not
# populating that property correctly either. So: read the FIT ourselves
# straight from boot_a at the known offset via the UFS/SCSI block layer
# (preboot already did `scsi scan`) into $ramdisk_addr_r (128 MiB
# scratch region board_late_init reserves, arch/arm/mach-snapdragon/
# board.c). Block size is derived at runtime (100663296 / blocks-in-
# partition) instead of assumed, since we don't know if this UFS LU
# reports 512B or 4096B logical blocks. Falls back to the old
# prevbl_initrd_start_addr attempt, then to the phone menu, if this
# fails -- see memoria rtwo-uboot-chainload-fit-raw-read.
pmos_bootargs=earlycon console=ttyMSM0,115200n8 console=tty0 ignore_loglevel panic=5 pmos.debug-shell clk_ignore_unused pd_ignore_unused regulator_ignore_unused allow_mismatched_32bit_el0 pmos_boot_uuid=d4373976-057c-4cf3-a43d-00734001b405 pmos_root_uuid=09804032-85bb-4d57-95a5-00d1965fb10f pmos_rootfsopts=defaults
bootcmd=setenv bootargs $pmos_bootargs; if part start scsi 3 boot_a boot_a_start && part size scsi 3 boot_a boot_a_size; then setexpr blksz 0x6000000 / $boot_a_size; setexpr fit_blk_off 0x18c000 / $blksz; setexpr fit_lba $boot_a_start + $fit_blk_off; setexpr fit_blk_cnt $boot_a_size - $fit_blk_off; echo pmOS: boot_a start=$boot_a_start size=$boot_a_size blksz=$blksz fit_lba=$fit_lba fit_cnt=$fit_blk_cnt; pause; scsi dev 3; if scsi read $ramdisk_addr_r $fit_lba $fit_blk_cnt; then echo pmOS: FIT read OK, about to bootm at $ramdisk_addr_r; pause; bootm $ramdisk_addr_r; echo pmOS: bootm on FIT returned control, this should not happen; pause; else echo pmOS: scsi read of FIT failed; pause; fi; else echo pmOS: could not resolve boot_a partition; fi; echo pmOS: raw boot_a read failed, trying prevbl_initrd_start_addr=$prevbl_initrd_start_addr; bootm $prevbl_initrd_start_addr; echo pmOS: bootm failed; bootefi bootmgr; pause; run menucmd
# When entering the menu (either from button press or failed boot) # When entering the menu (either from button press or failed boot)
# remap bootcmd so it will re-open the menu and we won't get stuck # remap bootcmd so it will re-open the menu and we won't get stuck
@@ -50,6 +62,9 @@ bootmenu_8=Dump environment=printenv; pause
bootmenu_9=Board info=bdinfo; pause bootmenu_9=Board info=bdinfo; pause
bootmenu_10=Dump bootargs=fdt addr $fdt_addr_r; fdt print /chosen bootargs; pause bootmenu_10=Dump bootargs=fdt addr $fdt_addr_r; fdt print /chosen bootargs; pause
bootmenu_11=Power off=poweroff bootmenu_11=Power off=poweroff
bootmenu_12=Diag SCSI boot_a=scsi scan; scsi info; pause; if part number scsi 0 boot_a i; then echo scsi0:part=$i; else echo scsi0:no-boot_a; fi; if part number scsi 1 boot_a i; then echo scsi1:part=$i; else echo scsi1:no-boot_a; fi; if part number scsi 2 boot_a i; then echo scsi2:part=$i; else echo scsi2:no-boot_a; fi; if part number scsi 3 boot_a i; then echo scsi3:part=$i; else echo scsi3:no-boot_a; fi; pause; if part number scsi 4 boot_a i; then echo scsi4:part=$i; else echo scsi4:no-boot_a; fi; if part number scsi 5 boot_a i; then echo scsi5:part=$i; else echo scsi5:no-boot_a; fi; if part number scsi 6 boot_a i; then echo scsi6:part=$i; else echo scsi6:no-boot_a; fi; if part number scsi 7 boot_a i; then echo scsi7:part=$i; else echo scsi7:no-boot_a; fi; pause
bootmenu_13=Diag USB gadget=dm uclass usb_gadget; pause; dm uclass usb; pause; dm uclass phy; pause
bootmenu_14=Diag UFS=dm uclass ufs; pause; dm uclass phy; pause; ufs init 0; echo ufs_init_ret=$?; pause
# Allow holding the volume down button while U-Boot loads to enter # Allow holding the volume down button while U-Boot loads to enter
# the boot menu # the boot menu
+2
View File
@@ -122,6 +122,7 @@ static const struct gate_clk sm8550_clks[] = {
GATE_CLK(GCC_AGGRE_UFS_PHY_AXI_CLK, 0x770e4, BIT(0)), GATE_CLK(GCC_AGGRE_UFS_PHY_AXI_CLK, 0x770e4, BIT(0)),
GATE_CLK(GCC_AGGRE_UFS_PHY_AXI_HW_CTL_CLK, 0x770e4, BIT(1)), GATE_CLK(GCC_AGGRE_UFS_PHY_AXI_HW_CTL_CLK, 0x770e4, BIT(1)),
GATE_CLK(GCC_AGGRE_USB3_PRIM_AXI_CLK, 0x3908c, BIT(0)), GATE_CLK(GCC_AGGRE_USB3_PRIM_AXI_CLK, 0x3908c, BIT(0)),
GATE_CLK(GCC_CFG_NOC_USB3_PRIM_AXI_CLK, 0x39088, BIT(0)),
GATE_CLK(GCC_CNOC_PCIE_SF_AXI_CLK, 0x52008, BIT(6)), GATE_CLK(GCC_CNOC_PCIE_SF_AXI_CLK, 0x52008, BIT(6)),
GATE_CLK(GCC_DDRSS_GPU_AXI_CLK, 0x71154, BIT(0)), GATE_CLK(GCC_DDRSS_GPU_AXI_CLK, 0x71154, BIT(0)),
GATE_CLK(GCC_DDRSS_PCIE_SF_QTB_CLK, 0x52000, BIT(19)), GATE_CLK(GCC_DDRSS_PCIE_SF_QTB_CLK, 0x52000, BIT(19)),
@@ -203,6 +204,7 @@ static int sm8550_enable(struct clk *clk)
struct msm_clk_priv *priv = dev_get_priv(clk->dev); struct msm_clk_priv *priv = dev_get_priv(clk->dev);
switch (clk->id) { switch (clk->id) {
case GCC_CFG_NOC_USB3_PRIM_AXI_CLK:
case GCC_AGGRE_USB3_PRIM_AXI_CLK: case GCC_AGGRE_USB3_PRIM_AXI_CLK:
qcom_gate_clk_en(priv, GCC_USB30_PRIM_MASTER_CLK); qcom_gate_clk_en(priv, GCC_USB30_PRIM_MASTER_CLK);
fallthrough; fallthrough;