Lemans spinor bringup - #132
vandhiadevan wants to merge 13 commits into
Conversation
| obj-$(CONFIG_PIC32_SPI) += pic32_spi.o | ||
| obj-$(CONFIG_PL022_SPI) += pl022_spi.o | ||
| obj-$(CONFIG_SPI_QUP) += spi-qup.o | ||
| obj-$(CONFIG_SPI_GENI_QCOM) += qcom_geni_spi.o |
There was a problem hiding this comment.
Please have this in sorted order. Lines 70 & 71 should be swapped
| #define SE_DMA_RX_PTR_L 0xd30 | ||
| #define SE_DMA_RX_PTR_H 0xd34 | ||
| #define SE_DMA_RX_ATTR 0xd38 | ||
| #define SE_DMA_RX_LEN 0xd3c |
There was a problem hiding this comment.
The defines are sorted by offset, please insert the new ones appropriately
There was a problem hiding this comment.
Addressed in the latest update
| hw_major = GENI_SE_VERSION_MAJOR(hw_version); | ||
| hw_minor = GENI_SE_VERSION_MINOR(hw_version); | ||
|
|
||
| if ((hw_major == 3 && hw_minor >= 10) || hw_major > 3) | ||
| rx_fifo_depth_mask = RX_FIFO_DEPTH_MSK_256_BYTES; | ||
| else | ||
| rx_fifo_depth_mask = RX_FIFO_DEPTH_MSK; | ||
|
|
||
| reg_value = readl_relaxed(rsc->base + SE_HW_PARAM_1); | ||
| mask = (reg_value & rx_fifo_depth_mask) >> RX_FIFO_DEPTH_SHFT; |
There was a problem hiding this comment.
Why isn't geni_se_fifo_depth_mask() (added in previous patch) being used.
There was a problem hiding this comment.
Addressed in the latest update
| #define SPI_NOR_MAX_ADDR_WIDTH 4 | ||
|
|
||
| struct mtd_info; | ||
|
|
There was a problem hiding this comment.
IIRC, for declaring pointers you don't need this
There was a problem hiding this comment.
Addressed in the latest update
| struct spi_flash_blk_plat { | ||
| struct mtd_info *mtd; | ||
| }; | ||
|
|
There was a problem hiding this comment.
Why can't it use mtd_info pointer itself?
There was a problem hiding this comment.
Addressed in the latest update
05166fd to
79619b3
Compare
| /* Find out the parent device uclass */ | ||
| if (device_get_uclass_id(dev->parent) != uclass_id) { | ||
| if (device_get_uclass_id(dev->parent) != uclass_id && | ||
| desc->uclass_id != uclass_id) { |
There was a problem hiding this comment.
Not sure if community will accept this. spi-nor is not considered a block device and this tries to show spi-nor as block.
| { | ||
| if (block_device_override >= 0) | ||
| return block_device_override; | ||
|
|
||
| return config_opt_enabled(CONFIG_FASTBOOT_FLASH_BLOCK, | ||
| CONFIG_FASTBOOT_FLASH_BLOCK_DEVICE_ID, -1); | ||
| } |
There was a problem hiding this comment.
Is the config_opt_enabled check needed? This file is compiled only if CONFIG_FASTBOOT_FLASH_BLOCK is enabled. Please see Makefile. Am I missing something? If that check is not needed, wouldn't return CONFIG_FASTBOOT_FLASH_BLOCK_DEVICE_ID alone suffice?
| { | ||
| if (block_interface_override[0]) | ||
| return block_interface_override; | ||
|
|
||
| return config_opt_enabled(CONFIG_FASTBOOT_FLASH_BLOCK, | ||
| CONFIG_FASTBOOT_FLASH_BLOCK_INTERFACE_NAME, NULL); | ||
| } |
There was a problem hiding this comment.
Is the config_opt_enabled check needed? This file is compiled only if CONFIG_FASTBOOT_FLASH_BLOCK is enabled. Please see Makefile. Am I missing something? If that check is not needed, wouldn't return CONFIG_FASTBOOT_FLASH_BLOCK_INTERFACE_NAME alone suffice?
| */ | ||
| static void __maybe_unused oem_set_block_target(char *cmd_parameter, char *response) | ||
| { | ||
| char interface[16] = { 0 }; |
There was a problem hiding this comment.
This 16 and the 16 in static char block_interface_override[16]; should have a common macro
| fastboot_fail("interface name too long", response); | ||
| return; | ||
| } | ||
| memcpy(interface, cmd_parameter, len); |
There was a problem hiding this comment.
This memcpy and strlcpy at 635 is not needed. Can terminate with cmd_parameter[len] = 0;. And invoke fastboot_block_set_target(cmd_parameter, device);
With that the interface local variable and the hardcoded number 16 can be dropped.
| &tlmm { | ||
| bootph-all; /* Make TLMM GPIO controller available in SPL */ | ||
|
|
||
| qup_spi21_default: qup-spi21-state { |
There was a problem hiding this comment.
Community expects these to be in Linux DTS itself. They may not accept. Community goal is to discard the override DT itself and handle stuff minimally using dt fixup
| /delete-property/ dma-names; | ||
| status = "okay"; | ||
|
|
||
| flash@0 { |
There was a problem hiding this comment.
Community expects these to be in Linux DTS itself. They may not accept. Community goal is to discard the override DT itself and handle stuff minimally using dt fixup
| } | ||
|
|
||
| /* Update the partition table entries*/ | ||
| desc->part_type = PART_TYPE_UNKNOWN; |
There was a problem hiding this comment.
This negates the caching effect for everyone. Should it be qualified with something like
if (desc->part_type == PART_TYPE_MTD && desc->uclass_id == UCLASS_SPI_FLASH (or) UCLASS_SPI)
load_se_firmware() derives the RX_RFR_WATERMARK value from
QUPV3_SE_HW_PARAM_1 using RX_FIFO_WIDTH_BIT/RX_FIFO_WIDTH_MASK, which
decode the RX FIFO element width (bits per FIFO word), not its depth
(number of entries). The watermark register expects a depth-based
threshold, so this produces an incorrect watermark value and, on QUP
HW versions >= 3.10 where the depth field widened to 8 bits for
256-byte-deep FIFOs, an inconsistent one depending on core revision.
This mirrors geni_i2c_get_tx_fifo_depth() in drivers/i2c/geni_i2c.c,
which already reads SE_HW_PARAM_0 with the HW-version-gated
TX_FIFO_DEPTH_MSK/TX_FIFO_DEPTH_MSK_256_BYTES masks for the same
reason on the TX side.
The same depth-vs-width distinction, and the HW-version gating for
QUP HW >= 3.10, was introduced upstream in Linux by commit
fe8aa1ba0783 ("soc: qcom: geni-se: Update Tx and Rx fifo depth based
on QUP HW version"). The Linux driver this file's firmware-loading
sequence was ported from, added by commit d4bf06592ad6 ("soc: qcom:
geni-se: Add support to load QUP SE Firmware via Linux subsystem"),
computes the RX_RFR_WATERMARK value via geni_se_get_rx_fifo_depth()
which applies that same depth mask -- confirming this is a porting
bug rather than an intentional difference.
Add geni_se_fifo_depth_mask() to the shared include/soc/qcom/geni-se.h
to pick the correct depth mask for a given QUP HW version.
Signed-off-by: Vandhiadevan Karunamoorthy <vandhiadevan.karunamoorthy@oss.qualcomm.com>
Add a DM_SPI driver for the SPI-protocol personality of the Qualcomm GENI Serial Engine, found inside a QUPv3 wrapper on Qualcomm SoCs such as SDM845, SM8250 and SA8775P. The Serial Engine is shared across UART/I2C/SPI protocols and needs firmware for the desired protocol loaded into it before use, via the existing qcom_geni_load_firmware() helper. The driver supports both the CPU-driven FIFO transfer path and the Serial Engine's own DMA engine (SE-DMA). Whether FIFO mode is usable is read back from hardware (GENI_IF_DISABLE_RO); SE-DMA is always available. The driver picks FIFO for small transfers when FIFO is available, and SE-DMA otherwise, matching the mode-selection logic of the equivalent Linux driver. Add the SE-DMA register offsets needed by the new driver to the shared include/soc/qcom/geni-se.h, and wire up the new driver's Kconfig entry and Makefile rule. The driver's TX fifo depth calculation reuses geni_se_fifo_depth_mask(), added to the same header by the preceding fix. Signed-off-by: Vandhiadevan Karunamoorthy <vandhiadevan.karunamoorthy@oss.qualcomm.com>
mtd_blk_probe() never initializes bdesc->lba, so every MTD block device reports a block count of zero regardless of the underlying MTD device's actual size. This makes MTD block devices unusable for partition table (GPT/MBR) scanning, since partition code relies on lba to know the device's extent. Set lba from the MTD device's size and the block descriptor's blksz, mirroring how other block drivers populate this field during probe. Signed-off-by: Vandhiadevan Karunamoorthy <vandhiadevan.karunamoorthy@oss.qualcomm.com>
79619b3 to
6dd46ef
Compare
Bind the SPI-NOR jedec_spi_nor device into the MTD block subsystem from a new jedec_spi_nor_bind() .bind() hook, matching the spinand_bind()/mmc_bind() precedent of creating blk children once at bind time rather than on every probe. Set the block descriptor's logical block size, log2blksz, and lba from a new CONFIG_MTD_BLOCK_SIZE Kconfig value (default 4 KB) instead of a DT property, matching the sector size GPT images are generated with. No changes to mtd_bind()'s signature or behavior for existing callers. .bind() runs exactly once per device lifetime, so the mtdblock child is created unconditionally there. Probe-time only looks the child up via blk_find_from_parent() to refresh the mtd_info pointer and block geometry (blksz, log2blksz, lba, part_type), which must still happen on every probe since flash->mtd is only valid after spi_nor_scan() succeeds. If the lookup fails, that is a real error (the child failed to bind), reported via dev_err() and unwound through the existing err_read_id path, which is a generic post-spi_claim_bus() cleanup and not specific to ID-read failures. Wrap the block in a preprocessor '#if CONFIG_IS_ENABLED(MTD_BLOCK)' guard instead of a runtime check, since CONFIG_MTD_BLOCK_SIZE is only emitted to autoconf.h when MTD_BLOCK is enabled; referencing it unconditionally fails to build with MTD_BLOCK disabled. Signed-off-by: Vandhiadevan Karunamoorthy <vandhiadevan.karunamoorthy@oss.qualcomm.com>
For uclass_id == UCLASS_MTD, resolve blk_get_devnum_by_uclass_idname() via blk_get_devnum_by_uclass_id(UCLASS_MTD, devnum), matching on the block descriptor's own uclass_id rather than its parent device's uclass. SPI-NOR backed mtdblock/ubiblock devices are parented by a UCLASS_SPI_FLASH device, so the generic parent-uclass matching loop never finds them; SPI-NAND and parallel NOR are unaffected since their MTD block devices are parented directly by a UCLASS_MTD device.
Add fastboot_block_set_target() so an OEM command can point the generic block fastboot backend at a different interface/device at runtime, without requiring a rebuild. Falls back to the existing build-time CONFIG_FASTBOOT_FLASH_BLOCK_INTERFACE_NAME/ CONFIG_FASTBOOT_FLASH_BLOCK_DEVICE_ID defaults when no override is set. Expose this to fastboot clients via a new "oem set-block-target <interface> [device]" command, gated behind CONFIG_FASTBOOT_CMD_OEM_SET_BLOCK_TARGET (depends on CONFIG_FASTBOOT_FLASH_BLOCK). This is needed to target storage devices, such as SPI-NOR exposed through the MTD block uclass, that aren't known until runtime or that coexist with another default block interface on the same board. Signed-off-by: Vandhiadevan Karunamoorthy <vandhiadevan.karunamoorthy@oss.qualcomm.com>
Add an "oem spi-nor-init" fastboot command that removes the default SPI flash device and reprobes it, mirroring the remove+re-probe pattern already used by fastboot_spi_flash_probe() in fb_spi_flash.c. This lets the driver's own probe() perform any bring-up it needs (e.g. loading firmware). Some SoCs load SPI-NOR firmware from storage in a single bulk pass at boot, before a bare reprobe of the SPI flash device is enough to pick it up (e.g. if the firmware source wasn't available yet at that point). To let such platforms redo that one-time, driver-external step here without hardcoding any vendor-specific call into generic fastboot code, add a weak fastboot_oem_spi_nor_reinit() hook that is called between the removal and the reprobe. The default implementation is a no-op; SoC-specific code may override it. This is useful on boards where the SPI flash device is not usable until fastboot has flashed something it depends on, such as firmware or configuration data. It is intended to be used together with "oem set-block-target" once the device has been brought up. Signed-off-by: Vandhiadevan Karunamoorthy <vandhiadevan.karunamoorthy@oss.qualcomm.com>
qcom_geni_fw_initialise() runs once, at EVT_LAST_STAGE_INIT, and reads GENI SE firmware from a dedicated storage partition into memory for its children to pick up during their own probe(). If that partition does not exist yet at that point (e.g. first boot, before fastboot has flashed it), it finds nothing to load and does not retry later. A later bare SPI-NOR reprobe cannot recover from that on its own, since the SPI driver's probe() only re-reads firmware already cached by qcom_geni_fw_initialise(); it does not re-read storage itself. Override the fastboot_oem_spi_nor_reinit() hook to re-run qcom_geni_fw_initialise(), so that "fastboot oem spi-nor-init" can pick up firmware that has been flashed since boot before reprobing the SPI-NOR device. Signed-off-by: Vandhiadevan Karunamoorthy <vandhiadevan.karunamoorthy@oss.qualcomm.com>
Add the clock RCG, gate bit definitions, and frequency table needed to enable and configure the SE0 (SPI) serial engine clock on QUPv3 wrapper 3, GCC_QUPV3_WRAP3_S0_CLK. This is required to bring up the GENI SPI controller on QUPv3 wrapper 3, e.g. for SPI-NOR flash attached to that wrapper. Also add the wrapper's M-AHB/S-AHB clock gates and the QSPI/AGGRE-NOC gates that must be enabled alongside the SE0 clock. Signed-off-by: Vandhiadevan Karunamoorthy <vandhiadevan.karunamoorthy@oss.qualcomm.com>
Wire up the QUPv3 wrapper 3 / SPI21 GENI SPI controller and its clock/pinctrl dependencies so the SPI-NOR flash on the LeMans EVK can be probed in U-Boot proper. Mark GCC, RPMH clock controller, Apps RSC, TLMM and QUPv3 wrapper 3 as bootph-all so they remain bound prior to relocation, add the SPI21 pinctrl state, set the SE0 clock to 48 MHz via assigned-clocks on GCC, and drop the power-domain/DMA properties on SPI21 that are not usable prior to relocation. Add a jedec,spi-nor flash child node and an spi0 alias for the SPI-NOR flash. Signed-off-by: Vandhiadevan Karunamoorthy <vandhiadevan.karunamoorthy@oss.qualcomm.com>
Turn on the GENI/QUPv3 wrapper-3 SPI-NOR stack and the fastboot
runtime block-target override that this branch already implements,
using the existing qcom_lemans_snagboot_defconfig rather than adding
a new one:
- CONFIG_OF_UPSTREAM plus CONFIG_QCOM_COMMAND_DB for RPMH clock
resource lookups
- CONFIG_IOMMU / CONFIG_QCOM_HYP_SMMU so the QUP3 GENI SE-DMA stream
is routed through the hypervisor-backed SMMU instead of silently
faulting
- DM_SPI / SPI_GENI_QCOM, DM_SPI_FLASH / SPI_FLASH_MTD and the MTD
block layer for SPI-NOR on QUPv3 wrapper 3, SE0
- the broader SPI-NOR vendor set from drivers/mtd/spi/Kconfig
(Atmel, Dosilicon, EON, GigaDevice, ISSI, Macronix, Puya, Silicon
Kaiser, Spansion, STMicro, SST, Winbond, XMC, XTX, ZBIT), instead
of Macronix alone
- FASTBOOT_CMD_OEM_SET_BLOCK_TARGET / FASTBOOT_CMD_OEM_SPI_NOR_INIT
so fastboot can switch its block backend from the snagboot
default ("scsi") to "mtd" at runtime, once SPI-NOR has probed
Validated with a full build for lemans-evk (qcom_lemans_snagboot_defconfig),
confirming qcom_geni_spi.o, sf_probe.o, mtdblock.o and fb_block.o all
compile and link into u-boot.bin.
Signed-off-by: Vandhiadevan Karunamoorthy <vandhiadevan.karunamoorthy@oss.qualcomm.com>
…are() qcom_geni_load_firmware() unconditionally dereferences the firmware blob pointer cached in the GENI wrapper's private data (dev_get_priv(dev->parent)) without checking it for NULL. qcom_geni_fw_initialise() only populates that private data when it successfully locates and reads the dedicated QUP firmware partition at EVT_LAST_STAGE_INIT. If no such partition exists yet - e.g. a board with no MMC/UFS storage and an unprovisioned SPI-NOR, before any image has been flashed - it prints "QUP firmware partition not found" and returns without ever setting the wrapper's private data, leaving it NULL. Any later probe of a GENI peripheral (SPI/I2C/UART) whose firmware is not yet loaded on that hardware instance then calls qcom_geni_load_firmware(), which dereferences the NULL pointer and crashes with a synchronous abort/data abort. Add a NULL check and fail gracefully with -ENOENT, matching how the SPI caller already handles a nonzero return from this function. Signed-off-by: Vandhiadevan Karunamoorthy <vandhiadevan.karunamoorthy@oss.qualcomm.com>
write_mbr_and_gpt_partitions() calls part_init() after writing the GPT to re-detect the partition table, but part_init() takes a fast path when desc->part_type is already cached: it only re-validates the existing driver's test() instead of re-scanning all partition drivers. On SPI-NOR/MTD block devices, part_type is cached as PART_TYPE_MTD from the initial probe, since the MTD partition driver's test() unconditionally matches. When fastboot subsequently writes a GPT to SPI-NOR (e.g. via 'gpt write'), the post-write part_init() call keeps reusing the stale MTD type instead of detecting EFI, so 'part list mtd 0' reports "Partition Type: MTD" with no partitions until an unrelated full reprobe (e.g. 'sf probe') resets part_type and forces a re-scan. Reset part_type to PART_TYPE_UNKNOWN before the post-write part_init() call so it always performs a full re-scan and correctly detects EFI immediately. Signed-off-by: Vandhiadevan Karunamoorthy <vandhiadevan.karunamoorthy@oss.qualcomm.com>
6dd46ef to
2dc4dbb
Compare
Title: arm64: lemans: Enable SPI-NOR flash support and fastboot GPT flashing
Summary
depth vs width bug, and add SA8775p QUPv3-wrapper-3 SPI clock support.
blk_desc lba fix, plat data struct) and allow blk uclass lookup by a
device's own uclass_id.
and geni firmware reinit support, to flash SPI-NOR over fastboot.
clocks, jedec,spi-nor flash node, spi0 alias) and enable it in the
snagboot defconfig.
partition-type re-detection after a fastboot GPT write to SPI-NOR
(previously showed "Partition Type: MTD" until a manual
sf probe).Test plan
qcom_lemans_snagboot_defconfig (SWIV + qtestsign tz flow).
part list mtd 0reports
Partition Type: EFIwith partitions visible immediatelyafter GPT write (no
sf probeworkaround needed).clock-driver changes.