Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion arch/arm/dts/lemans-evk-u-boot.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
};

&gcc {
bootph-all; /* Enable GCC for SPL */
bootph-all;
};

/* RPMH clock controller - required by GCC */
Expand All @@ -56,6 +56,13 @@

&tlmm {
bootph-all; /* Make TLMM GPIO controller available in SPL */

qup_spi21_default: qup-spi21-state {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

pins = "gpio13", "gpio14", "gpio15", "gpio16";
function = "sail_top";
drive-strength = <2>;
bias-disable;
};
};

/* Enter Qualcomm EDL/download mode via "reset -edl". */
Expand All @@ -64,3 +71,26 @@
mode-edl = <0x80000000 0x00000001>;
};
};

&{/aliases} {
spi0 = &spi21;
};

&qupv3_id_3 {
bootph-all;
status = "okay";
};

&spi21 {
assigned-clocks = <&gcc GCC_QUPV3_WRAP3_S0_CLK>;
assigned-clock-rates = <48000000>;
status = "okay";

flash@0 {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

compatible = "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <48000000>;
spi-tx-bus-width = <1>;
spi-rx-bus-width = <1>;
};
};
52 changes: 51 additions & 1 deletion configs/qcom_lemans_snagboot_defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,54 @@ CONFIG_FASTBOOT_BUF_ADDR=0xdb300000
CONFIG_DEFAULT_DEVICE_TREE="qcom/lemans-evk"

# Timer frequency for Lemans platform
CONFIG_COUNTER_FREQUENCY=19200000
CONFIG_COUNTER_FREQUENCY=19200000

# Use upstream DTS
CONFIG_OF_UPSTREAM=y

# CMD_DB required for RPMH clock resource lookups (used by SMMU/RPMH setup below)
CONFIG_QCOM_COMMAND_DB=y

# SMMU: the QUP3 GENI SE-DMA stream needs the Qualcomm hypervisor-backed SMMU
# enabled or DMA silently faults instead of landing in DRAM.
CONFIG_IOMMU=y
CONFIG_QCOM_HYP_SMMU=y

# SPI-NOR on QUPV3 wrapper 3, SE0
CONFIG_SPI=y
CONFIG_DM_SPI=y
CONFIG_SPI_GENI_QCOM=y
CONFIG_MTD=y
CONFIG_DM_MTD=y
CONFIG_CMD_MTD=y
CONFIG_MTD_BLOCK=y
CONFIG_DM_SPI_FLASH=y
CONFIG_SPI_FLASH_MTD=y
CONFIG_SPI_FLASH_SFDP_SUPPORT=y
CONFIG_SF_DEFAULT_BUS=0
CONFIG_SF_DEFAULT_CS=0
CONFIG_SF_DEFAULT_SPEED=48000000
CONFIG_SF_DEFAULT_MODE=0
CONFIG_CMD_SF_TEST=y

# SPI-NOR flash vendors
CONFIG_SPI_FLASH_ATMEL=y
CONFIG_SPI_FLASH_DOSILICON=y
CONFIG_SPI_FLASH_EON=y
CONFIG_SPI_FLASH_GIGADEVICE=y
CONFIG_SPI_FLASH_ISSI=y
CONFIG_SPI_FLASH_MACRONIX=y
CONFIG_SPI_FLASH_PUYA=y
CONFIG_SPI_FLASH_SILICONKAISER=y
CONFIG_SPI_FLASH_SPANSION=y
CONFIG_SPI_FLASH_STMICRO=y
CONFIG_SPI_FLASH_SST=y
CONFIG_SPI_FLASH_WINBOND=y
CONFIG_SPI_FLASH_XMC=y
CONFIG_SPI_FLASH_XTX=y
CONFIG_SPI_FLASH_ZBIT=y

# Fastboot: switch the block backend from the snagboot default ("scsi") to
# "mtd" at runtime, once SPI-NOR has been probed
CONFIG_FASTBOOT_CMD_OEM_SET_BLOCK_TARGET=y
CONFIG_FASTBOOT_CMD_OEM_SPI_NOR_INIT=y
3 changes: 3 additions & 0 deletions disk/part_efi.c
Original file line number Diff line number Diff line change
Expand Up @@ -975,6 +975,9 @@ int write_mbr_and_gpt_partitions(struct blk_desc *desc, void *buf)
return 1;
}

if (desc->part_type == PART_TYPE_MTD)
desc->part_type = PART_TYPE_UNKNOWN;

/* Update the partition table entries*/
part_init(desc);

Expand Down
3 changes: 3 additions & 0 deletions drivers/block/blk-uclass.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,9 @@ struct blk_desc *blk_get_devnum_by_uclass_idname(const char *uclass_idname, int
return NULL;
}

if (uclass_id == UCLASS_MTD)
return blk_get_devnum_by_uclass_id(UCLASS_MTD, devnum);

ret = uclass_get(UCLASS_BLK, &uc);
if (ret)
return NULL;
Expand Down
35 changes: 35 additions & 0 deletions drivers/clk/qcom/clock-sa8775p.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#define UFS_PHY_UNIPRO_CORE_CLK_CMD_RCGR 0x8308c

#define SDCC1_APPS_CLK_CMD_RCGR 0x20014
#define QUPV3_WRAP3_S0_CLK_CMD_RCGR 0xc4154

#define APCS_GPLL9_STATUS 0x9000
#define APCS_GPLLX_ENA_REG 0x4b028
Expand Down Expand Up @@ -53,6 +54,26 @@
#define GCC_QUPV3_WRAP2_S6_CLK_ENA_BIT BIT(29)

#define GCC_QUPV3_WRAP3_S0_CLK_ENA_BIT BIT(25)
#define GCC_QUPV3_WRAP_3_M_AHB_ENA_BIT BIT(27)
#define GCC_QUPV3_WRAP_3_S_AHB_ENA_BIT BIT(20)
#define GCC_QUPV3_WRAP3_QSPI_ENA_BIT BIT(26)
#define GCC_AGGRE_NOC_QUPV3_AXI_ENA_BIT BIT(28)

/* QUP Wrapper 3 SE0 (SPI) clock frequency table */
static const struct freq_tbl ftbl_gcc_qupv3_wrap3_s0_clk_src[] = {
F(7372800, CFG_CLK_SRC_GPLL0_EVEN, 1, 384, 15625),
F(14745600, CFG_CLK_SRC_GPLL0_EVEN, 1, 768, 15625),
F(19200000, CFG_CLK_SRC_CXO, 1, 0, 0),
F(29491200, CFG_CLK_SRC_GPLL0_EVEN, 1, 1536, 15625),
F(32000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 8, 75),
F(48000000, CFG_CLK_SRC_GPLL0, 2, 4, 25),
F(64000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 16, 75),
F(75000000, CFG_CLK_SRC_GPLL0_EVEN, 4, 0, 0),
F(80000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 4, 15),
F(96000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 8, 25),
F(100000000, CFG_CLK_SRC_GPLL0, 6, 0, 0),
{ }
};

/* UFS AXI clock frequency table */
static const struct freq_tbl ftbl_gcc_ufs_phy_axi_clk_src[] = {
Expand Down Expand Up @@ -147,6 +168,12 @@ static ulong sa8775p_set_rate(struct clk *clk, ulong rate)
clk_rcg_set_rate_mnd(priv->base, SDCC1_APPS_CLK_CMD_RCGR,
freq->pre_div, freq->m, freq->n, freq->src, 8);
return freq->freq;
case GCC_QUPV3_WRAP3_S0_CLK:
freq = qcom_find_freq(ftbl_gcc_qupv3_wrap3_s0_clk_src, rate);
clk_rcg_set_rate_mnd(priv->base, QUPV3_WRAP3_S0_CLK_CMD_RCGR,
freq->pre_div, freq->m, freq->n,
freq->src, 16);
return freq->freq;
default:
return 0;
}
Expand Down Expand Up @@ -189,7 +216,11 @@ static const struct gate_clk sa8775p_clks[] = {
GATE_CLK(GCC_QUPV3_WRAP2_S6_CLK, 0x4b018, GCC_QUPV3_WRAP2_S6_CLK_ENA_BIT),

/* QUP Wrapper 3 clocks */
GATE_CLK(GCC_QUPV3_WRAP_3_M_AHB_CLK, 0x4b000, GCC_QUPV3_WRAP_3_M_AHB_ENA_BIT),
GATE_CLK(GCC_QUPV3_WRAP_3_S_AHB_CLK, 0x4b000, GCC_QUPV3_WRAP_3_S_AHB_ENA_BIT),
GATE_CLK(GCC_QUPV3_WRAP3_S0_CLK, 0x4b000, GCC_QUPV3_WRAP3_S0_CLK_ENA_BIT),
GATE_CLK(GCC_QUPV3_WRAP3_QSPI_CLK, 0x4b000, GCC_QUPV3_WRAP3_QSPI_ENA_BIT),
GATE_CLK(GCC_AGGRE_NOC_QUPV3_AXI_CLK, 0x4b000, GCC_AGGRE_NOC_QUPV3_AXI_ENA_BIT),

/* UFS PHY clocks */
GATE_CLK_POLLED(GCC_UFS_PHY_AXI_CLK, 0x83018, BIT(0), 0x83018),
Expand Down Expand Up @@ -229,6 +260,10 @@ static int sa8775p_enable(struct clk *clk)
qcom_gate_clk_en(priv, GCC_USB3_PRIM_PHY_AUX_CLK);
qcom_gate_clk_en(priv, GCC_USB3_PRIM_PHY_COM_AUX_CLK);
break;
case GCC_QUPV3_WRAP3_S0_CLK:
qcom_gate_clk_en(priv, GCC_QUPV3_WRAP3_QSPI_CLK);
qcom_gate_clk_en(priv, GCC_AGGRE_NOC_QUPV3_AXI_CLK);
break;
}

return qcom_gate_clk_en(priv, clk->id);
Expand Down
22 changes: 22 additions & 0 deletions drivers/fastboot/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,28 @@ config FASTBOOT_FLASH_BLOCK_DEVICE_ID
Device identifiers are numbered starting from 0 and the most
common case is to use the first controller on the system.

config FASTBOOT_CMD_OEM_SET_BLOCK_TARGET
bool "Enable the 'oem set-block-target' command"
depends on FASTBOOT_FLASH_BLOCK
help
Add support for the "oem set-block-target" command from a client.
This allows switching the block interface (e.g. scsi, mtd) and
device number used by the fastboot "flash"/"erase" commands at
runtime, instead of relying solely on the
CONFIG_FASTBOOT_FLASH_BLOCK_INTERFACE_NAME /
CONFIG_FASTBOOT_FLASH_BLOCK_DEVICE_ID build-time defaults.

config FASTBOOT_CMD_OEM_SPI_NOR_INIT
bool "Enable the 'oem spi-nor-init' command"
depends on DM_SPI_FLASH
help
Add support for the "oem spi-nor-init" command from a client. This
removes and reprobes the default SPI-NOR device, letting its
driver's probe() handle any vendor-specific bring-up (e.g. firmware
load) it needs. Use together with "oem set-block-target" to bring up
SPI-NOR via fastboot on boards where SPI-NOR is not usable until
after fastboot has flashed something it depends on.

config FASTBOOT_GPT_NAME
string "Target name for updating GPT"
depends on (FASTBOOT_FLASH_MMC || FASTBOOT_FLASH_BLOCK) && EFI_PARTITION
Expand Down
75 changes: 64 additions & 11 deletions drivers/fastboot/fb_block.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,66 @@ static lbaint_t fb_block_sparse_reserve(struct sparse_storage *info,
return blkcnt;
}

/**
* block_interface_override - runtime-set block interface name, empty if unset
*/
static char block_interface_override[16];
/**
* block_device_override - runtime-set block device number, -1 if unset
*/
static int block_device_override = -1;

/**
* fb_block_interface() - Resolve the block interface name to use
*
* Returns the runtime override set via fastboot_block_set_target() if one
* is active, otherwise falls back to the build-time config default.
*/
static const char *fb_block_interface(void)
{
if (!IS_ENABLED(CONFIG_FASTBOOT_FLASH_BLOCK))
return NULL;

if (block_interface_override[0])
return block_interface_override;

return config_opt_enabled(CONFIG_FASTBOOT_FLASH_BLOCK,
CONFIG_FASTBOOT_FLASH_BLOCK_INTERFACE_NAME, NULL);
}
Comment on lines +144 to +153

@varada-qcom varada-qcom Sep 11, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?


/**
* fb_block_device() - Resolve the block device number to use
*
* Returns the runtime override set via fastboot_block_set_target() if one
* is active, otherwise falls back to the build-time config default.
*/
static int fb_block_device(void)
{
if (!IS_ENABLED(CONFIG_FASTBOOT_FLASH_BLOCK))
return -1;

if (block_device_override >= 0)
return block_device_override;

return config_opt_enabled(CONFIG_FASTBOOT_FLASH_BLOCK,
CONFIG_FASTBOOT_FLASH_BLOCK_DEVICE_ID, -1);
}
Comment on lines +162 to +171

@varada-qcom varada-qcom Sep 11, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?


int fastboot_block_set_target(const char *interface, int device)
{
if (interface) {
if (strlen(interface) >= sizeof(block_interface_override))
return -EINVAL;
strlcpy(block_interface_override, interface,
sizeof(block_interface_override));
}

if (device >= 0)
block_device_override = device;

return 0;
}

/**
* parse_device_partition() - Parse and validate device:partition format
* @part_name: Input string in format "N:partition" or "partition"
Expand All @@ -140,8 +200,7 @@ static int parse_device_partition(const char *part_name, int *device,
{
const char *colon_pos;

*device = config_opt_enabled(CONFIG_FASTBOOT_FLASH_BLOCK,
CONFIG_FASTBOOT_FLASH_BLOCK_DEVICE_ID, -1);
*device = fb_block_device();

/* Check for colon in partition name */
colon_pos = strchr(part_name, ':');
Expand Down Expand Up @@ -190,9 +249,7 @@ int fastboot_block_get_part_info(const char *part_name,
char *response)
{
int ret;
const char *interface = config_opt_enabled(CONFIG_FASTBOOT_FLASH_BLOCK,
CONFIG_FASTBOOT_FLASH_BLOCK_INTERFACE_NAME,
NULL);
const char *interface = fb_block_interface();
int device;
const char *partition_name;

Expand Down Expand Up @@ -385,9 +442,7 @@ void fastboot_block_flash_write(const char *part_name, void *download_buffer,
#if CONFIG_IS_ENABLED(EFI_PARTITION)
if (is_partition_table_name(part_name, CONFIG_FASTBOOT_GPT_NAME)) {
int device;
const char *interface = config_opt_enabled(CONFIG_FASTBOOT_FLASH_BLOCK,
CONFIG_FASTBOOT_FLASH_BLOCK_INTERFACE_NAME,
NULL);
const char *interface = fb_block_interface();

parse_device_partition(part_name, &device, NULL);
fastboot_flash_gpt_partition_table(interface, device,
Expand All @@ -399,9 +454,7 @@ void fastboot_block_flash_write(const char *part_name, void *download_buffer,
#if CONFIG_IS_ENABLED(DOS_PARTITION)
if (is_partition_table_name(part_name, CONFIG_FASTBOOT_MBR_NAME)) {
int device;
const char *interface = config_opt_enabled(CONFIG_FASTBOOT_FLASH_BLOCK,
CONFIG_FASTBOOT_FLASH_BLOCK_INTERFACE_NAME,
NULL);
const char *interface = fb_block_interface();

parse_device_partition(part_name, &device, NULL);
fastboot_flash_mbr_partition_table(interface, device,
Expand Down
Loading