[PATCH v2 1/3] mach-snapdragon: Add generic SMEM cache infrastructure
Simon Glass
sjg at chromium.org
Tue Feb 10 13:49:46 CET 2026
Hi Aswin,
On Thu, 29 Jan 2026 at 11:48, Aswin Murugan
<aswin.murugan at oss.qualcomm.com> wrote:
>
> Add cached access functions for commonly used SMEM data to reduce
> redundant SMEM lookups across the boot process.
What is SMEM? Could you add some mention of this in doc/board/qualcomm/ ?
>
> This patch introduces three generic caching functions:
> - qcom_get_smem_device(): Cached SMEM device access
> - qcom_get_socinfo(): Cached socinfo structure access
> - qcom_get_ram_partitions(): Cached RAM partition table access
>
> The implementation includes new header files for data structures:
> - include/soc/qcom/socinfo.h: Added socinfo header from Linux [1]
> Provides socinfo structure definitions for SoC identification
> and hardware parameters
> - arch/arm/mach-snapdragon/rampart.h: Provides RAM partition table
> structures for memory layout information
>
> The caching mechanism initializes SMEM data on first access and
> returns cached pointers on subsequent calls, avoiding expensive
> SMEM lookups during boot. This infrastructure is designed to be
> reusable by other Qualcomm-specific features that require hardware
> information from SMEM.
>
> The functions provide a clean API for accessing:
> - SoC information (chip ID, version, platform details)
> - RAM partition layout for memory size calculations
> - Hardware parameters needed for device-specific configurations
>
> [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/linux/soc/qcom/socinfo.h?id=7dcc1dfaa3d1cd3aafed2beb7086ed34fdb22303
>
> Signed-off-by: Aswin Murugan <aswin.murugan at oss.qualcomm.com>
> ---
> arch/arm/mach-snapdragon/board.c | 92 +++++++++++
> arch/arm/mach-snapdragon/qcom-priv.h | 10 ++
> arch/arm/mach-snapdragon/rampart.h | 236 +++++++++++++++++++++++++++
> include/soc/qcom/socinfo.h | 114 +++++++++++++
> 4 files changed, 452 insertions(+)
> create mode 100644 arch/arm/mach-snapdragon/rampart.h
> create mode 100644 include/soc/qcom/socinfo.h
>
> diff --git a/arch/arm/mach-snapdragon/board.c b/arch/arm/mach-snapdragon/board.c
> index 5fb3240acc5..cbe2aaeba6e 100644
> --- a/arch/arm/mach-snapdragon/board.c
> +++ b/arch/arm/mach-snapdragon/board.c
> @@ -30,6 +30,7 @@
> #include <malloc.h>
> #include <fdt_support.h>
> #include <usb.h>
> +#include <smem.h>
> #include <sort.h>
> #include <time.h>
header order
https://docs.u-boot.org/en/latest/develop/codingstyle.html#include-files
>
> @@ -39,6 +40,13 @@ DECLARE_GLOBAL_DATA_PTR;
>
> enum qcom_boot_source qcom_boot_source __section(".data") = 0;
>
> +/* SMEM cache structure */
> +static struct {
> + struct udevice *smem_dev;
> + struct socinfo *soc_info;
> + struct usable_ram_partition_table *ram_partition_table;
how about 'ram_part' as the name, since it is shorter? Please comment
the struct too.
> +} smem_cache;
> +
> static struct mm_region rbx_mem_map[CONFIG_NR_DRAM_BANKS + 2] = { { 0 } };
This should already be zero. Can you move this to device-private data?
Then it can be allocated/freed by driver model.
Perhaps you could just have smem_dev as a variable with the other two
fields (from the above struct) kept in driver-private data?
>
> struct mm_region *mem_map = rbx_mem_map;
> @@ -749,3 +757,87 @@ void enable_caches(void)
> }
> dcache_enable();
> }
> +
> +/**
> + * qcom_get_smem_device() - Get cached SMEM device
> + *
> + * This function provides cached access to the SMEM device.
> + * On first call, it initializes the SMEM device.
> + * Subsequent calls return the cached pointer.
> + *
> + * Return: Pointer to SMEM device on success, NULL on failure
> + */
> +struct udevice *qcom_get_smem_device(void)
> +{
> + if (smem_cache.smem_dev)
> + return smem_cache.smem_dev;
> +
> + if (uclass_get_device(UCLASS_SMEM, 0, &smem_cache.smem_dev)) {
If there is only ever one, then uclass_first_device_err()
> + log_err("Failed to get SMEM device\n");
> + return NULL;
> + }
> +
> + return smem_cache.smem_dev;
> +}
> +
> +/**
> + * qcom_get_socinfo() - Get cached socinfo from SMEM
> + *
> + * This function provides cached access to the socinfo structure from SMEM.
> + * On first call, it initializes the SMEM device and retrieves the socinfo.
> + * Subsequent calls return the cached pointer.
> + *
> + * Return: Pointer to socinfo structure on success, NULL on failure
> + */
> +struct socinfo *qcom_get_socinfo(void)
> +{
> + size_t size;
> + struct udevice *dev;
> +
> + if (smem_cache.soc_info)
> + return smem_cache.soc_info;
> +
> + dev = qcom_get_smem_device();
> + if (!dev)
> + return NULL;
> +
> + smem_cache.soc_info = smem_get(dev, 0, SMEM_HW_SW_BUILD_ID, &size);
> + if (!smem_cache.soc_info) {
> + log_err("Failed to get socinfo from SMEM\n");
> + return NULL;
> + }
> +
> + return smem_cache.soc_info;
> +}
> +
> +/**
> + * qcom_get_ram_partitions() - Get cached RAM partition table from SMEM
> + *
> + * This function provides cached access to the RAM partition table from SMEM.
> + * On first call, it retrieves the partition table from SMEM.
> + * Subsequent calls return the cached pointer.
> + *
> + * Return: Pointer to RAM partition table on success, NULL on failure
> + */
> +struct usable_ram_partition_table *qcom_get_ram_partitions(void)
> +{
> + size_t size;
> + struct udevice *dev;
> +
> + if (smem_cache.ram_partition_table)
> + return smem_cache.ram_partition_table;
> +
> + dev = qcom_get_smem_device();
> + if (!dev)
> + return NULL;
> +
> + smem_cache.ram_partition_table = smem_get(dev, 0,
> + SMEM_USABLE_RAM_PARTITION_TABLE,
> + &size);
> + if (!smem_cache.ram_partition_table) {
> + log_err("Failed to get RAM partition table from SMEM\n");
> + return NULL;
> + }
> +
> + return smem_cache.ram_partition_table;
> +}
> diff --git a/arch/arm/mach-snapdragon/qcom-priv.h b/arch/arm/mach-snapdragon/qcom-priv.h
> index b8bf574e8bb..ca1363514ae 100644
> --- a/arch/arm/mach-snapdragon/qcom-priv.h
> +++ b/arch/arm/mach-snapdragon/qcom-priv.h
> @@ -3,6 +3,9 @@
> #ifndef __QCOM_PRIV_H__
> #define __QCOM_PRIV_H__
>
> +#include <soc/qcom/socinfo.h>
> +#include "rampart.h"
> +
> /**
> * enum qcom_boot_source - Track where we got loaded from.
> * Used for capsule update logic.
> @@ -17,6 +20,13 @@ enum qcom_boot_source {
>
> extern enum qcom_boot_source qcom_boot_source;
>
> +/*
> + * SMEM Cache API - Provides cached access to SMEM data structures
> + */
> +struct udevice *qcom_get_smem_device(void);
> +struct socinfo *qcom_get_socinfo(void);
> +struct usable_ram_partition_table *qcom_get_ram_partitions(void);
comments
> +
> #if IS_ENABLED(CONFIG_EFI_HAVE_CAPSULE_SUPPORT)
> void qcom_configure_capsule_updates(void);
> #else
> diff --git a/arch/arm/mach-snapdragon/rampart.h b/arch/arm/mach-snapdragon/rampart.h
> new file mode 100644
> index 00000000000..cfddaca0d5f
> --- /dev/null
> +++ b/arch/arm/mach-snapdragon/rampart.h
> @@ -0,0 +1,236 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * RAM partition table definitions
> + *
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + *
> + */
> +
> +#define SMEM_USABLE_RAM_PARTITION_TABLE 402
> +
> +#define RAM_PARTITION_H_MAJOR 03
> +#define RAM_PARTITION_H_MINOR 00
> +
> +typedef u8 uint8;
> +typedef u32 uint32;
> +typedef u64 uint64;
We already have these definitions - see asm-generic/int-ll64.h
> +
> +/**
> + * Total length of zero filled name string. This is not a C
> + * string, as it can occupy the total number of bytes, and if
> + * it does, it does not require a zero terminator. It cannot
> + * be manipulated with standard string handling library functions.
> + */
> +#define RAM_PART_NAME_LENGTH 16
> +
> +/**
> + * Number of RAM partition entries which are usable by APPS.
> + */
> +#define RAM_NUM_PART_ENTRIES 32
> +
> +/**
> + * @name: Magic numbers
> + * Used in identifying valid RAM partition table.
> + */
> +#define RAM_PART_MAGIC1 0x9DA5E0A8
> +#define RAM_PART_MAGIC2 0xAF9EC4E2
lower-case hex (please fix throughout0
> +
> +/**
> + * Must increment this version number whenever RAM structure of
> + * RAM partition table changes.
> + */
> +#define RAM_PARTITION_VERSION 0x3
> +
> +/**
> + * Value which indicates the partition can grow to fill the
> + * rest of RAM. Must only be used on the last partition.
> + */
> +#define RAM_PARTITION_GROW 0xFFFFFFFF
> +
> +/**
> + * RAM partition API return types.
> + */
> +enum ram_partition_return_type {
> + RAM_PART_SUCCESS = 0, /* Successful return from API */
> + RAM_PART_NULL_PTR_ERR, /* Partition table/entry null pointer */
> + RAM_PART_OUT_OF_BOUND_PTR_ERR, /* Partition table pointer is not in SMEM */
> + RAM_PART_TABLE_EMPTY_ERR, /* Trying to delete entry from empty table */
> + RAM_PART_TABLE_FULL_ERR, /* Trying to add entry to full table */
> + RAM_PART_CATEGORY_NOT_EXIST_ERR, /* Partition doesn't belong to any memory category */
> + RAM_PART_OTHER_ERR, /* Unknown error */
> + RAM_PART_RETURN_MAX_SIZE = 0x7FFFFFFF
> +};
> +
> +/**
> + * RAM partition attributes.
> + */
> +enum ram_partition_attribute_t {
> + RAM_PARTITION_DEFAULT_ATTRB = ~0, /* No specific attribute definition */
> + RAM_PARTITION_READ_ONLY = 0, /* Read-only RAM partition */
> + RAM_PARTITION_READWRITE, /* Read/write RAM partition */
> + RAM_PARTITION_ATTRIBUTE_MAX_SIZE = 0x7FFFFFFF
> +};
> +
> +/**
> + * RAM partition categories.
> + */
> +enum ram_partition_category_t {
> + RAM_PARTITION_DEFAULT_CATEGORY = ~0, /* No specific category definition */
> + RAM_PARTITION_IRAM = 4, /* IRAM RAM partition */
> + RAM_PARTITION_IMEM = 5, /* IMEM RAM partition */
> + RAM_PARTITION_SDRAM = 14, /* SDRAM type without specific bus information**/
> + RAM_PARTITION_CATEGORY_MAX_SIZE = 0x7FFFFFFF
> +};
> +
> +/**
> + * RAM Partition domains.
> + * @note: For shared RAM partition, domain value would be 0b11:\n
> + * RAM_PARTITION_APPS_DOMAIN | RAM_PARTITION_MODEM_DOMAIN.
> + */
> +enum ram_partition_domain_t {
> + RAM_PARTITION_DEFAULT_DOMAIN = 0, /* 0b00: No specific domain definition */
> + RAM_PARTITION_APPS_DOMAIN = 1, /* 0b01: APPS RAM partition */
> + RAM_PARTITION_MODEM_DOMAIN = 2, /* 0b10: MODEM RAM partition */
> + RAM_PARTITION_DOMAIN_MAX_SIZE = 0x7FFFFFFF
> +};
> +
> +/**
> + * RAM Partition types.
> + * @note: The RAM_PARTITION_SYS_MEMORY type represents DDR rams that are attached
> + * to the current system.
> + */
> +enum ram_partition_type_t {
> + RAM_PARTITION_SYS_MEMORY = 1, /* system memory */
> + RAM_PARTITION_BOOT_REGION_MEMORY1, /* boot loader memory 1 */
> + RAM_PARTITION_BOOT_REGION_MEMORY2, /* boot loader memory 2, reserved */
> + RAM_PARTITION_APPSBL_MEMORY, /* apps boot loader memory */
> + RAM_PARTITION_APPS_MEMORY, /* apps usage memory */
> + RAM_PARTITION_TOOLS_FV_MEMORY, /* tools usage memory */
> + RAM_PARTITION_QUANTUM_FV_MEMORY, /* quantum usage memory */
> + RAM_PARTITION_QUEST_FV_MEMORY, /* quest usage memory */
> + RAM_PARTITION_TYPE_MAX_SIZE = 0x7FFFFFFF
> +};
> +
> +/**
> + * @brief: Holds information for an entry in the RAM partition table.
> + */
> +struct ram_partition_entry {
> + char name[RAM_PART_NAME_LENGTH]; /* Partition name, unused for now */
> + uint64 start_address; /* Partition start address in RAM */
> + uint64 length; /* Partition length in RAM in Bytes */
> + uint32 partition_attribute; /* Partition attribute */
> + uint32 partition_category; /* Partition category */
> + uint32 partition_domain; /* Partition domain */
> + uint32 partition_type; /* Partition type */
> + uint32 num_partitions; /* Number of partitions on device */
> + uint32 hw_info; /* hw information such as type and frequency */
> + uint8 highest_bank_bit; /* Highest bit corresponding to a bank */
> + uint8 reserve0; /* Reserved for future use */
> + uint8 reserve1; /* Reserved for future use */
> + uint8 reserve2; /* Reserved for future use */
> + uint32 min_pasr_size; /* Minimum PASR size in MB */
> + uint64 available_length; /* Available Partition length in RAM in Bytes */
> +};
> +
> +/**
> + * @brief: Defines the RAM partition table structure
> + * @note: No matter how you change the structure, do not change the placement of the
> + * first four elements so that future compatibility will always be guaranteed
> + * at least for the identifiers.
> + *
> + * @note: The other portion of the structure may be changed as necessary to accommodate
> + * new features. Be sure to increment version number if you change it.
> + */
> +struct usable_ram_partition_table {
> + uint32 magic1; /* Magic number to identify valid RAM partition table */
> + uint32 magic2; /* Magic number to identify valid RAM partition table */
> + uint32 version; /* Version number to track structure definition changes */
> + uint32 reserved1; /* Reserved for future use */
> +
> + uint32 num_partitions; /* Number of RAM partition table entries */
> +
> + uint32 reserved2; /* Added for 8 bytes alignment of header */
> +
> + /* RAM partition table entries */
> + struct ram_partition_entry ram_part_entry[RAM_NUM_PART_ENTRIES];
> +};
> +
> +/**
> + * Version 1 structure 32 Bit
> + * @brief: Holds information for an entry in the RAM partition table.
> + */
> +struct ram_partition_entry_v1 {
> + char name[RAM_PART_NAME_LENGTH]; /* Partition name, unused for now */
> + uint64 start_address; /* Partition start address in RAM */
> + uint64 length; /* Partition length in RAM in Bytes */
> + uint32 partition_attribute; /* Partition attribute */
> + uint32 partition_category; /* Partition category */
> + uint32 partition_domain; /* Partition domain */
> + uint32 partition_type; /* Partition type */
> + uint32 num_partitions; /* Number of partitions on device */
> + uint32 hw_info; /* hw information such as type and frequency */
> + uint32 reserved4; /* Reserved for future use */
> + uint32 reserved5; /* Reserved for future use */
> +};
> +
> +/**
> + * @brief: Defines the RAM partition table structure
> + * @note: No matter how you change the structure, do not change the placement of the
> + * first four elements so that future compatibility will always be guaranteed
> + * at least for the identifiers.
> + *
> + * @note: The other portion of the structure may be changed as necessary to accommodate
> + * new features. Be sure to increment version number if you change it.
> + */
> +struct usable_ram_partition_table_v1 {
> + uint32 magic1; /* Magic number to identify valid RAM partition table */
> + uint32 magic2; /* Magic number to identify valid RAM partition table */
> + uint32 version; /* Version number to track structure definition changes */
> + uint32 reserved1; /* Reserved for future use */
> +
> + uint32 num_partitions; /* Number of RAM partition table entries */
> +
> + uint32 reserved2; /* Added for 8 bytes alignment of header */
> +
> + /* RAM partition table entries */
> + struct ram_partition_entry_v1 ram_part_entry_v1[RAM_NUM_PART_ENTRIES];
> +};
> +
> +/**
> + * Version 0 structure 32 Bit
> + * @brief: Holds information for an entry in the RAM partition table.
> + */
> +struct ram_partition_entry_v0 {
> + char name[RAM_PART_NAME_LENGTH]; /* Partition name, unused for now */
> + uint32 start_address; /* Partition start address in RAM */
> + uint32 length; /* Partition length in RAM in Bytes */
> + uint32 partition_attribute; /* Partition attribute */
> + uint32 partition_category; /* Partition category */
> + uint32 partition_domain; /* Partition domain */
> + uint32 partition_type; /* Partition type */
> + uint32 num_partitions; /* Number of partitions on device */
> + uint32 reserved3; /* Reserved for future use */
> + uint32 reserved4; /* Reserved for future use */
> + uint32 reserved5; /* Reserved for future use */
> +};
> +
> +/**
> + * @brief: Defines the RAM partition table structure
> + * @note: No matter how you change the structure, do not change the placement of the
> + * first four elements so that future compatibility will always be guaranteed
> + * at least for the identifiers.
> + *
> + * @note: The other portion of the structure may be changed as necessary to accommodate
> + * new features. Be sure to increment version number if you change it.
> + */
Is this actually kerneldoc? We don't normally use @brief etc.
> +struct usable_ram_partition_table_v0 {
> + uint32 magic1; /* Magic number to identify valid RAM partition table */
> + uint32 magic2; /* Magic number to identify valid RAM partition table */
> + uint32 version; /* Version number to track structure definition changes */
> + uint32 reserved1; /* Reserved for future use */
> +
> + uint32 num_partitions; /* Number of RAM partition table entries */
> +
> + /* RAM partition table entries */
> + struct ram_partition_entry_v0 ram_part_entry_v0[RAM_NUM_PART_ENTRIES];
very long identifiers!
> +};
> diff --git a/include/soc/qcom/socinfo.h b/include/soc/qcom/socinfo.h
> new file mode 100644
> index 00000000000..1bb6e200e1f
> --- /dev/null
> +++ b/include/soc/qcom/socinfo.h
> @@ -0,0 +1,114 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + */
> +
> +#ifndef __QCOM_SOCINFO_H__
> +#define __QCOM_SOCINFO_H__
> +
> +#include <linux/types.h>
> +
> +/*
> + * SMEM item id, used to acquire handles to respective
> + * SMEM region.
> + */
> +#define SMEM_HW_SW_BUILD_ID 137
> +
> +#define SMEM_SOCINFO_BUILD_ID_LENGTH 32
> +#define SMEM_SOCINFO_CHIP_ID_LENGTH 32
> +
> +/*
> + * SoC version type with major number in the upper 16 bits and minor
> + * number in the lower 16 bits.
> + */
> +#define SOCINFO_MAJOR(ver) (((ver) >> 16) & 0xffff)
> +#define SOCINFO_MINOR(ver) ((ver) & 0xffff)
> +#define SOCINFO_VERSION(maj, min) ((((maj) & 0xffff) << 16) | ((min) & 0xffff))
> +
> +/* Socinfo SMEM item structure */
> +struct socinfo {
> + __le32 fmt;
> + __le32 id;
> + __le32 ver;
> + char build_id[SMEM_SOCINFO_BUILD_ID_LENGTH];
> + /* Version 2 */
> + __le32 raw_id;
> + __le32 raw_ver;
> + /* Version 3 */
> + __le32 hw_plat;
> + /* Version 4 */
> + __le32 plat_ver;
> + /* Version 5 */
> + __le32 accessory_chip;
> + /* Version 6 */
> + __le32 hw_plat_subtype;
> + /* Version 7 */
> + __le32 pmic_model;
> + __le32 pmic_die_rev;
> + /* Version 8 */
> + __le32 pmic_model_1;
> + __le32 pmic_die_rev_1;
> + __le32 pmic_model_2;
> + __le32 pmic_die_rev_2;
> + /* Version 9 */
> + __le32 foundry_id;
> + /* Version 10 */
> + __le32 serial_num;
> + /* Version 11 */
> + __le32 num_pmics;
> + __le32 pmic_array_offset;
> + /* Version 12 */
> + __le32 chip_family;
> + __le32 raw_device_family;
> + __le32 raw_device_num;
> + /* Version 13 */
> + __le32 nproduct_id;
> + char chip_id[SMEM_SOCINFO_CHIP_ID_LENGTH];
> + /* Version 14 */
> + __le32 num_clusters;
> + __le32 ncluster_array_offset;
> + __le32 num_subset_parts;
> + __le32 nsubset_parts_array_offset;
> + /* Version 15 */
> + __le32 nmodem_supported;
> + /* Version 16 */
> + __le32 feature_code;
> + __le32 pcode;
> + __le32 npartnamemap_offset;
> + __le32 nnum_partname_mapping;
> + /* Version 17 */
> + __le32 oem_variant;
> + /* Version 18 */
> + __le32 num_kvps;
> + __le32 kvps_offset;
> + /* Version 19 */
> + __le32 num_func_clusters;
> + __le32 boot_cluster;
> + __le32 boot_core;
> +};
> +
> +/* Internal feature codes */
> +enum qcom_socinfo_feature_code {
> + /* External feature codes */
> + SOCINFO_FC_UNKNOWN = 0x0,
> + SOCINFO_FC_AA,
> + SOCINFO_FC_AB,
> + SOCINFO_FC_AC,
> + SOCINFO_FC_AD,
> + SOCINFO_FC_AE,
> + SOCINFO_FC_AF,
> + SOCINFO_FC_AG,
> + SOCINFO_FC_AH,
> +};
Do these values have any meaning, or are they documented somewhere?
> +
> +/* Internal feature codes */
> +/* Valid values: 0 <= n <= 0xf */
> +#define SOCINFO_FC_Yn(n) (0xf1 + (n))
> +#define SOCINFO_FC_INT_MAX SOCINFO_FC_Yn(0xf)
> +
> +/* Product codes */
> +#define SOCINFO_PC_UNKNOWN 0
> +#define SOCINFO_PCn(n) ((n) + 1)
> +#define SOCINFO_PC_RESERVE (BIT(31) - 1)
> +
> +#endif
> --
> 2.34.1
>
Regards,
Simon
More information about the U-Boot
mailing list