Add cached access functions for commonly used SMEM data to reduce redundant SMEM lookups across the boot process.
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> @@ -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; +} smem_cache; + static struct mm_region rbx_mem_map[CONFIG_NR_DRAM_BANKS + 2] = { { 0 } }; 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)) { + 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); + #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; + +/** + * 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 + +/** + * 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. + */ +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]; +}; 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, +}; + +/* 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

