Hi Aswin,

On Thu, 29 Jan 2026 at 11:48, Aswin Murugan
<[email protected]> 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 <[email protected]>
> ---
>  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

Reply via email to