soc/qualcomm/common: Add CMD-DB driver support

Introduce CMD-DB driver to enable reading command database entries,
querying SoC resource data, and providing helper functions required
by AOP and other subsystems.

Test=Create an image.serial.bin and ensure it boots on X1P42100.

Change-Id: I3788bf7c97cc1133ae4893f4fdeaf36882e71276
Signed-off-by: Swathi Tamilselvan <tswathi@qualcomm.corp-partner.google.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/90465
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Subrata Banik <subratabanik@google.com>
This commit is contained in:
Swathi Tamilselvan 2025-12-10 16:12:53 +05:30 committed by Matt DeVillier
commit 01bc527afa
3 changed files with 339 additions and 0 deletions

View file

@ -0,0 +1,247 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <console/console.h>
#include <device/mmio.h>
#include <string.h>
#include <soc/cmd_db.h>
#include <types.h>
#include <string.h>
#include <endian.h>
/**
* struct entry_header: header for each entry in cmd_db
*
* @id: resource's identifier
* @priority: unused
* @addr: the address of the resource
* @len: length of the data
* @offset: offset from :@data_offset, start of the data
*/
struct entry_header {
u8 id[8];
u32 priority[NUM_PRIORITY];
u32 addr;
u16 len;
u16 offset;
} __packed;
/**
* struct rsc_hdr: resource header information
*
* @slv_id: id for the resource
* @header_offset: entry's header at offset from the end of the cmd_db_header
* @data_offset: entry's data at offset from the end of the cmd_db_header
* @cnt: number of entries for HW type
* @version: MSB is major, LSB is minor
* @reserved: reserved for future use.
*/
struct rsc_hdr {
u16 slv_id;
u16 header_offset;
u16 data_offset;
u16 cnt;
u16 version;
u16 reserved[3];
} __packed;
/**
* struct cmd_db_header: The DB header information
*
* @version: The cmd db version
* @magic: constant expected in the database
* @header: array of resources
* @checksum: checksum for the header. Unused.
* @reserved: reserved memory
* @data: driver specific data
*/
struct cmd_db_header {
u32 version;
u8 magic[4];
struct rsc_hdr header[MAX_SLV_ID];
u32 checksum;
u32 reserved;
u8 data[];
} __packed;
/**
* DOC: Description of the Command DB database.
*
* At the start of the command DB memory is the cmd_db_header structure.
* The cmd_db_header holds the version, checksum, magic key as well as an
* array for header for each slave (depicted by the rsc_header). Each h/w
* based accelerator is a 'slave' (shared resource) and has slave id indicating
* the type of accelerator. The rsc_header is the header for such individual
* slaves of a given type. The entries for each of these slaves begin at the
* rsc_hdr.header_offset. In addition each slave could have auxiliary data
* that may be needed by the driver. The data for the slave starts at the
* entry_header.offset to the location pointed to by the rsc_hdr.data_offset.
*
* Drivers have a stringified key to a slave/resource. They can query the slave
* information and get the slave id and the auxiliary data and the length of the
* data. Using this information, they can format the request to be sent to the
* h/w accelerator and request a resource state.
*/
static const u8 CMD_DB_MAGIC[] = { 0xdb, 0x30, 0x03, 0x0c };
static struct cmd_db_header *cmd_db_header;
static bool cmd_db_magic_matches(const struct cmd_db_header *header)
{
return memcmp(header->magic, CMD_DB_MAGIC, sizeof(CMD_DB_MAGIC)) == 0;
}
static inline const void *rsc_to_entry_header(const struct rsc_hdr *hdr)
{
u16 offset = hdr->header_offset;
return cmd_db_header->data + offset;
}
static inline void *rsc_offset(const struct rsc_hdr *hdr,
const struct entry_header *ent)
{
u16 offset = hdr->data_offset;
u16 loffset = ent->offset;
return cmd_db_header->data + offset + loffset;
}
enum cb_err cmd_db_ready(void)
{
if (cmd_db_header == NULL)
return CB_ERR;
else if (!cmd_db_magic_matches(cmd_db_header))
return CB_ERR;
return CB_SUCCESS;
}
static enum cb_err cmd_db_get_header(const char *id,
const struct entry_header **eh,
const struct rsc_hdr **rh)
{
const struct rsc_hdr *rsc_hdr;
const struct entry_header *ent;
enum cb_err ret;
int i, j;
u8 query[sizeof(ent->id)];
size_t id_len;
ret = cmd_db_ready();
if (ret != CB_SUCCESS)
return ret;
memset(query, 0, sizeof(query));
id_len = strlen(id);
if (id_len > sizeof(query))
id_len = sizeof(query);
memcpy(query, id, id_len);
for (i = 0; i < MAX_SLV_ID; i++) {
rsc_hdr = &cmd_db_header->header[i];
if (!rsc_hdr->slv_id)
break;
ent = rsc_to_entry_header(rsc_hdr);
for (j = 0; j < rsc_hdr->cnt; j++, ent++) {
if (memcmp(ent->id, query, sizeof(ent->id)) == 0) {
if (eh)
*eh = ent;
if (rh)
*rh = rsc_hdr;
return CB_SUCCESS;
}
}
}
return CB_ERR;
}
u32 cmd_db_read_addr(const char *id)
{
enum cb_err ret;
const struct entry_header *ent;
ret = cmd_db_get_header(id, &ent, NULL);
if (ret != CB_SUCCESS)
return 0;
return ent->addr;
}
const void *cmd_db_read_aux_data(const char *id, size_t *len)
{
enum cb_err ret;
const struct entry_header *ent;
const struct rsc_hdr *rsc_hdr;
ret = cmd_db_get_header(id, &ent, &rsc_hdr);
if (ret != CB_SUCCESS)
return NULL;
if (len)
*len = ent->len;
return rsc_offset(rsc_hdr, ent);
}
bool cmd_db_match_resource_addr(u32 addr1, u32 addr2)
{
if (addr1 == addr2)
return true;
else if (SLAVE_ID(addr1) == CMD_DB_HW_VRM &&
VRM_ADDR(addr1) == VRM_ADDR(addr2))
return true;
return false;
}
enum cmd_db_hw_type cmd_db_read_slave_id(const char *id)
{
enum cb_err ret;
const struct entry_header *ent;
u32 addr;
ret = cmd_db_get_header(id, &ent, NULL);
if (ret != CB_SUCCESS)
return CMD_DB_HW_INVALID;
addr = ent->addr;
return (addr >> SLAVE_ID_SHIFT) & SLAVE_ID_MASK;
}
bool cmd_db_is_standalone(void)
{
enum cb_err ret = cmd_db_ready();
u32 standalone;
if (ret != CB_SUCCESS)
return false;
standalone = cmd_db_header->reserved & CMD_DB_STANDALONE_MASK;
return standalone != 0;
}
enum cb_err cmd_db_init(uintptr_t base, size_t size)
{
if (base == 0 || size == 0) {
printk(BIOS_ERR, "CMD_DB: Invalid base address or size\n");
return CB_ERR;
}
/* Map the command DB memory region */
cmd_db_header = (struct cmd_db_header *)base;
if (!cmd_db_magic_matches(cmd_db_header)) {
printk(BIOS_ERR, "CMD_DB: Invalid Command DB Magic\n");
cmd_db_header = NULL;
return CB_ERR;
}
printk(BIOS_DEBUG, "CMD_DB: Initialized at 0x%lx, size: 0x%zx\n",
base, size);
if (cmd_db_is_standalone())
printk(BIOS_DEBUG, "CMD_DB: Running in standalone mode\n");
return CB_SUCCESS;
}

View file

@ -0,0 +1,91 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef __SOC_QUALCOMM_CMD_DB_H__
#define __SOC_QUALCOMM_CMD_DB_H__
#include <types.h>
#define NUM_PRIORITY 2
#define MAX_SLV_ID 8
#define SLAVE_ID_MASK 0x7
#define SLAVE_ID_SHIFT 16
#define CMD_DB_STANDALONE_MASK BIT(0)
#define SLAVE_ID(addr) (((addr) >> 16) & 0xF)
#define VRM_ADDR(addr) (((addr) >> 4) & 0xFFFF)
enum cmd_db_hw_type {
CMD_DB_HW_INVALID = 0,
CMD_DB_HW_MIN = 3,
CMD_DB_HW_ARC = CMD_DB_HW_MIN,
CMD_DB_HW_VRM = 4,
CMD_DB_HW_BCM = 5,
CMD_DB_HW_MAX = CMD_DB_HW_BCM,
CMD_DB_HW_ALL = 0xff,
};
/**
* cmd_db_ready - Indicates if command DB is available
*
* Return: CB_SUCCESS on success, CB_ERR otherwise
*/
enum cb_err cmd_db_ready(void);
/**
* cmd_db_read_addr() - Query command db for resource id address.
*
* @id: resource id to query for address
*
* Return: resource address on success, 0 on error
*
* This is used to retrieve resource address based on resource id.
*/
u32 cmd_db_read_addr(const char *id);
/**
* cmd_db_read_aux_data() - Query command db for aux data.
*
* @id: Resource to retrieve AUX Data on
* @len: size of data buffer returned
*
* Return: pointer to data on success, NULL otherwise
*/
const void *cmd_db_read_aux_data(const char *id, size_t *len);
/**
* cmd_db_match_resource_addr() - Compare if both Resource addresses are same
*
* @addr1: Resource address to compare
* @addr2: Resource address to compare
*
* Return: true if two addresses refer to the same resource, false otherwise
*/
bool cmd_db_match_resource_addr(u32 addr1, u32 addr2);
/**
* cmd_db_read_slave_id - Get the slave ID for a given resource address
*
* @id: Resource id to query the DB for version
*
* Return: cmd_db_hw_type enum on success, CMD_DB_HW_INVALID on error
*/
enum cmd_db_hw_type cmd_db_read_slave_id(const char *id);
/**
* cmd_db_is_standalone - Check if command DB is in standalone mode
*
* Return: true if standalone, false otherwise
*/
bool cmd_db_is_standalone(void);
/**
* cmd_db_init - Initialize the command DB
*
* @base: Physical base address of the command DB memory region
* @size: Size of the command DB memory region
*
* Return: CB_SUCCESS on success, CB_ERR otherwise
*/
enum cb_err cmd_db_init(uintptr_t base, size_t size);
#endif /* __SOC_QUALCOMM_CMD_DB_H__ */

View file

@ -52,6 +52,7 @@ ramstage-$(CONFIG_PCI) += ../common/pcie_common.c
ramstage-y += ../common/spmi.c
ramstage-$(CONFIG_PCI) += pcie.c
ramstage-y += cpucp_load_reset.c
ramstage-y += ../common/cmd_db.c
################################################################################