mirror of
https://github.com/u-boot/u-boot.git
synced 2025-04-15 17:34:43 +00:00
acpi: acpi_table: Add IORT support
The SoC can implement acpi_fill_iort to update the IORT table. Add a helper function to fill out the NAMED_COMPONENT node. TEST=Run FWTS V24.03.00 on RPi4 and round no problems. Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com> Reviewed-by: Simon Glass <sjg@chromium.org> Cc: Simon Glass <sjg@chromium.org>
This commit is contained in:
parent
7f91bcac1e
commit
bf5d37662d
2 changed files with 426 additions and 0 deletions
|
@ -832,6 +832,117 @@ struct acpi_pptt_cache {
|
|||
u16 line_size;
|
||||
} __packed;
|
||||
|
||||
/** IORT - IO Remapping Table revision 6
|
||||
* Document number: ARM DEN 0049E.e, Sep 2022
|
||||
*/
|
||||
struct acpi_table_iort {
|
||||
struct acpi_table_header header;
|
||||
u32 node_count;
|
||||
u32 node_offset;
|
||||
u32 reserved;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* IORT subtables
|
||||
*/
|
||||
struct acpi_iort_node {
|
||||
u8 type;
|
||||
u16 length;
|
||||
u8 revision;
|
||||
u32 identifier;
|
||||
u32 mapping_count;
|
||||
u32 mapping_offset;
|
||||
char node_data[];
|
||||
} __packed;
|
||||
|
||||
/* Values for subtable Type above */
|
||||
enum acpi_iort_node_type {
|
||||
ACPI_IORT_NODE_ITS_GROUP = 0x00,
|
||||
ACPI_IORT_NODE_NAMED_COMPONENT = 0x01,
|
||||
ACPI_IORT_NODE_PCI_ROOT_COMPLEX = 0x02,
|
||||
ACPI_IORT_NODE_SMMU = 0x03,
|
||||
ACPI_IORT_NODE_SMMU_V3 = 0x04,
|
||||
ACPI_IORT_NODE_PMCG = 0x05,
|
||||
ACPI_IORT_NODE_RMR = 0x06,
|
||||
};
|
||||
|
||||
/* ITS Group revision 1 */
|
||||
struct acpi_iort_its_group {
|
||||
u32 its_count;
|
||||
u32 identifiers[]; /* GIC ITS identifier array */
|
||||
} __packed;
|
||||
|
||||
/* PCI root complex node revision 2 */
|
||||
struct acpi_iort_rc {
|
||||
u64 mem_access_properties;
|
||||
u32 ats_attributes;
|
||||
u32 pci_segment_number;
|
||||
u8 memory_address_size_limit;
|
||||
u8 reserved[3];
|
||||
} __packed;
|
||||
|
||||
/* SMMUv3 revision 5 */
|
||||
struct acpi_iort_smmu_v3 {
|
||||
u64 base_address; /* SMMUv3 base address */
|
||||
u32 flags;
|
||||
u32 reserved;
|
||||
u64 vatos_address;
|
||||
u32 model;
|
||||
u32 event_gsiv;
|
||||
u32 pri_gsiv;
|
||||
u32 gerr_gsiv;
|
||||
u32 sync_gsiv;
|
||||
u32 pxm;
|
||||
u32 id_mapping_index;
|
||||
} __packed;
|
||||
|
||||
/* Masks for Flags field above */
|
||||
#define ACPI_IORT_SMMU_V3_COHACC_OVERRIDE (1)
|
||||
#define ACPI_IORT_SMMU_V3_HTTU_OVERRIDE (3 << 1)
|
||||
#define ACPI_IORT_SMMU_V3_PXM_VALID (1 << 3)
|
||||
#define ACPI_IORT_SMMU_V3_DEVICEID_VALID (1 << 4)
|
||||
|
||||
struct acpi_iort_id_mapping {
|
||||
u32 input_base; /* Lowest value in input range */
|
||||
u32 id_count; /* Number of IDs */
|
||||
u32 output_base; /* Lowest value in output range */
|
||||
u32 output_reference; /* A reference to the output node */
|
||||
u32 flags;
|
||||
} __packed;
|
||||
|
||||
/* Masks for Flags field above for IORT subtable */
|
||||
#define ACPI_IORT_ID_SINGLE_MAPPING (1)
|
||||
|
||||
/* Named Component revision 4 */
|
||||
struct acpi_iort_named_component {
|
||||
u32 node_flags;
|
||||
u64 memory_properties; /* Memory access properties */
|
||||
u8 memory_address_limit; /* Memory address size limit */
|
||||
char device_name[]; /* Path of namespace object */
|
||||
} __packed;
|
||||
|
||||
/* Masks for Flags field above */
|
||||
#define ACPI_IORT_NC_STALL_SUPPORTED (1)
|
||||
#define ACPI_IORT_NC_PASID_BITS (31 << 1)
|
||||
|
||||
struct acpi_iort_root_complex {
|
||||
u64 memory_properties; /* Memory access properties */
|
||||
u32 ats_attribute;
|
||||
u32 pci_segment_number;
|
||||
u8 memory_address_limit;/* Memory address size limit */
|
||||
u16 pasid_capabilities; /* PASID Capabilities */
|
||||
u8 reserved; /* Reserved, must be zero */
|
||||
u32 flags; /* Flags */
|
||||
} __packed;
|
||||
|
||||
/* Masks for ats_attribute field above */
|
||||
#define ACPI_IORT_ATS_SUPPORTED (1) /* The root complex ATS support */
|
||||
#define ACPI_IORT_PRI_SUPPORTED (1 << 1) /* The root complex PRI support */
|
||||
#define ACPI_IORT_PASID_FWD_SUPPORTED (1 << 2) /* The root complex PASID forward support */
|
||||
|
||||
/* Masks for pasid_capabilities field above */
|
||||
#define ACPI_IORT_PASID_MAX_WIDTH (0x1F) /* Bits 0-4 */
|
||||
|
||||
/* Tables defined/reserved by ACPI and generated by U-Boot */
|
||||
enum acpi_tables {
|
||||
ACPITAB_BERT,
|
||||
|
@ -1000,6 +1111,108 @@ int acpi_fill_csrt(struct acpi_ctx *ctx);
|
|||
*/
|
||||
void acpi_fill_fadt(struct acpi_fadt *fadt);
|
||||
|
||||
/**
|
||||
* acpi_fill_iort() - Fill out the body of the IORT table
|
||||
*
|
||||
* Should be implemented in SoC specific code.
|
||||
*
|
||||
* @ctx: ACPI context to write to
|
||||
* @offset: Offset from the start of the IORT
|
||||
*/
|
||||
int acpi_fill_iort(struct acpi_ctx *ctx);
|
||||
|
||||
/**
|
||||
* acpi_iort_add_its_group() - Add ITS group node to IORT table
|
||||
*
|
||||
* Called by SoC specific code within acpi_fill_iort().
|
||||
*
|
||||
* @ctx: ACPI context to write to
|
||||
* @its_count: Elements in identifiers
|
||||
* @identifiers: The array of ITS identifiers. These IDs must match the value
|
||||
* used in the Multiple APIC Description Table (MADT) GIC ITS
|
||||
* structure for each relevant ITS unit.
|
||||
* @return Offset of table within parent
|
||||
*/
|
||||
int acpi_iort_add_its_group(struct acpi_ctx *ctx,
|
||||
const u32 its_count,
|
||||
const u32 *identifiers);
|
||||
|
||||
/**
|
||||
* acpi_iort_add_named_component() - Add named component to IORT table
|
||||
*
|
||||
* Called by SoC specific code within acpi_fill_iort().
|
||||
*
|
||||
* @ctx: ACPI context to write to
|
||||
* @node_flags: Node flags
|
||||
* @memory_properties: Memory properties
|
||||
* @memory_address_limit: Memory address limit
|
||||
* @device_name: ACPI device path
|
||||
* @return Offset of table within parent
|
||||
*/
|
||||
int acpi_iort_add_named_component(struct acpi_ctx *ctx,
|
||||
const u32 node_flags,
|
||||
const u64 memory_properties,
|
||||
const u8 memory_address_limit,
|
||||
const char *device_name);
|
||||
|
||||
/**
|
||||
* acpi_iort_add_rc() - Add PCI root complex node to IORT table
|
||||
*
|
||||
* Called by SoC specific code within acpi_fill_iort().
|
||||
*
|
||||
* @ctx: ACPI context to write to
|
||||
* @mem_access_properties: Memory access properties
|
||||
* @ats_attributes: Support for ATS and its ancillary feature
|
||||
* @pci_segment_number: The PCI segment number, as in MCFG
|
||||
* @memory_address_size_limit: The number of address bits, starting from LSB
|
||||
* @num_mappings: Number of elements in map
|
||||
* @map: ID mappings for this node
|
||||
* @return Offset of table within parent
|
||||
*/
|
||||
int acpi_iort_add_rc(struct acpi_ctx *ctx,
|
||||
const u64 mem_access_properties,
|
||||
const u32 ats_attributes,
|
||||
const u32 pci_segment_number,
|
||||
const u8 memory_address_size_limit,
|
||||
const int num_mappings,
|
||||
const struct acpi_iort_id_mapping *map);
|
||||
|
||||
/**
|
||||
* acpi_iort_add_smmu_v3() - Add PCI root complex node to IORT table
|
||||
*
|
||||
* Called by SoC specific code within acpi_fill_iort().
|
||||
*
|
||||
* @ctx: ACPI context to write to
|
||||
* @base_address: Base address of SMMU
|
||||
* @flags: SMMUv3 flags
|
||||
* @vatos_address: Optional, set to zero if not supported
|
||||
* @model: Model ID
|
||||
* @event_gsiv: GSIV of the Event interrupt if SPI based
|
||||
* @pri_gsiv: GSIV of the PRI interrupt if SPI based
|
||||
* @gerr_gsiv: GSIV of the GERR interrupt if GSIV based
|
||||
* @sync_gsiv: TGSIV of the Sync interrupt if GSIV based
|
||||
* @pxm: Proximity Domain
|
||||
* @id_mapping_index: If all the SMMU control interrupts are GSIV based,
|
||||
* this field is ignored. Index into the array of ID
|
||||
* mapping otherwise.
|
||||
* @num_mappings: Number of elements in map
|
||||
* @map: ID mappings for this node
|
||||
* @return Offset of table within parent
|
||||
*/
|
||||
int acpi_iort_add_smmu_v3(struct acpi_ctx *ctx,
|
||||
const u64 base_address,
|
||||
const u32 flags,
|
||||
const u64 vatos_address,
|
||||
const u32 model,
|
||||
const u32 event_gsiv,
|
||||
const u32 pri_gsiv,
|
||||
const u32 gerr_gsiv,
|
||||
const u32 sync_gsiv,
|
||||
const u32 pxm,
|
||||
const u32 id_mapping_index,
|
||||
const int num_mappings,
|
||||
const struct acpi_iort_id_mapping *map);
|
||||
|
||||
/**
|
||||
* acpi_fill_madt() - Fill out the body of the MADT
|
||||
*
|
||||
|
|
|
@ -520,3 +520,216 @@ static int acpi_write_spcr(struct acpi_ctx *ctx, const struct acpi_writer *entry
|
|||
}
|
||||
|
||||
ACPI_WRITER(5spcr, "SPCR", acpi_write_spcr, 0);
|
||||
|
||||
__weak int acpi_fill_iort(struct acpi_ctx *ctx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int acpi_iort_add_its_group(struct acpi_ctx *ctx,
|
||||
const u32 its_count,
|
||||
const u32 *identifiers)
|
||||
{
|
||||
struct acpi_iort_node *node;
|
||||
struct acpi_iort_its_group *group;
|
||||
int offset;
|
||||
|
||||
offset = ctx->current - ctx->tab_start;
|
||||
|
||||
node = ctx->current;
|
||||
memset(node, '\0', sizeof(struct acpi_iort_node));
|
||||
|
||||
node->type = ACPI_IORT_NODE_ITS_GROUP;
|
||||
node->revision = 1;
|
||||
|
||||
node->length = sizeof(struct acpi_iort_node);
|
||||
node->length += sizeof(struct acpi_iort_its_group);
|
||||
node->length += sizeof(u32) * its_count;
|
||||
|
||||
group = (struct acpi_iort_its_group *)node->node_data;
|
||||
group->its_count = its_count;
|
||||
memcpy(&group->identifiers, identifiers, sizeof(u32) * its_count);
|
||||
|
||||
ctx->current += node->length;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
int acpi_iort_add_named_component(struct acpi_ctx *ctx,
|
||||
const u32 node_flags,
|
||||
const u64 memory_properties,
|
||||
const u8 memory_address_limit,
|
||||
const char *device_name)
|
||||
{
|
||||
struct acpi_iort_node *node;
|
||||
struct acpi_iort_named_component *comp;
|
||||
int offset;
|
||||
|
||||
offset = ctx->current - ctx->tab_start;
|
||||
|
||||
node = ctx->current;
|
||||
memset(node, '\0', sizeof(struct acpi_iort_node));
|
||||
|
||||
node->type = ACPI_IORT_NODE_NAMED_COMPONENT;
|
||||
node->revision = 4;
|
||||
node->length = sizeof(struct acpi_iort_node);
|
||||
node->length += sizeof(struct acpi_iort_named_component);
|
||||
node->length += strlen(device_name) + 1;
|
||||
|
||||
comp = (struct acpi_iort_named_component *)node->node_data;
|
||||
|
||||
comp->node_flags = node_flags;
|
||||
comp->memory_properties = memory_properties;
|
||||
comp->memory_address_limit = memory_address_limit;
|
||||
memcpy(comp->device_name, device_name, strlen(device_name) + 1);
|
||||
|
||||
ctx->current += node->length;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
int acpi_iort_add_rc(struct acpi_ctx *ctx,
|
||||
const u64 mem_access_properties,
|
||||
const u32 ats_attributes,
|
||||
const u32 pci_segment_number,
|
||||
const u8 memory_address_size_limit,
|
||||
const int num_mappings,
|
||||
const struct acpi_iort_id_mapping *map)
|
||||
{
|
||||
struct acpi_iort_id_mapping *mapping;
|
||||
struct acpi_iort_node *node;
|
||||
struct acpi_iort_rc *rc;
|
||||
int offset;
|
||||
|
||||
offset = ctx->current - ctx->tab_start;
|
||||
|
||||
node = ctx->current;
|
||||
memset(node, '\0', sizeof(struct acpi_iort_node));
|
||||
|
||||
node->type = ACPI_IORT_NODE_PCI_ROOT_COMPLEX;
|
||||
node->revision = 2;
|
||||
|
||||
node->length = sizeof(struct acpi_iort_node);
|
||||
node->length += sizeof(struct acpi_iort_rc);
|
||||
node->length += sizeof(struct acpi_iort_id_mapping) * num_mappings;
|
||||
|
||||
rc = (struct acpi_iort_rc *)node->node_data;
|
||||
rc->mem_access_properties = mem_access_properties;
|
||||
rc->ats_attributes = ats_attributes;
|
||||
rc->pci_segment_number = pci_segment_number;
|
||||
rc->memory_address_size_limit = memory_address_size_limit;
|
||||
|
||||
mapping = (struct acpi_iort_id_mapping *)(rc + 1);
|
||||
for (int i = 0; i < num_mappings; i++) {
|
||||
memcpy(mapping, &map[i], sizeof(struct acpi_iort_id_mapping));
|
||||
mapping++;
|
||||
}
|
||||
|
||||
ctx->current += node->length;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
int acpi_iort_add_smmu_v3(struct acpi_ctx *ctx,
|
||||
const u64 base_address,
|
||||
const u32 flags,
|
||||
const u64 vatos_address,
|
||||
const u32 model,
|
||||
const u32 event_gsiv,
|
||||
const u32 pri_gsiv,
|
||||
const u32 gerr_gsiv,
|
||||
const u32 sync_gsiv,
|
||||
const u32 pxm,
|
||||
const u32 id_mapping_index,
|
||||
const int num_mappings,
|
||||
const struct acpi_iort_id_mapping *map)
|
||||
{
|
||||
struct acpi_iort_node *node;
|
||||
struct acpi_iort_smmu_v3 *smmu;
|
||||
struct acpi_iort_id_mapping *mapping;
|
||||
int offset;
|
||||
|
||||
offset = ctx->current - ctx->tab_start;
|
||||
|
||||
node = ctx->current;
|
||||
memset(node, '\0', sizeof(struct acpi_iort_node));
|
||||
|
||||
node->type = ACPI_IORT_NODE_SMMU_V3;
|
||||
node->revision = 5;
|
||||
node->mapping_count = num_mappings;
|
||||
node->mapping_offset = sizeof(struct acpi_iort_node) + sizeof(struct acpi_iort_smmu_v3);
|
||||
|
||||
node->length = sizeof(struct acpi_iort_node);
|
||||
node->length += sizeof(struct acpi_iort_smmu_v3);
|
||||
node->length += sizeof(struct acpi_iort_id_mapping) * num_mappings;
|
||||
|
||||
smmu = (struct acpi_iort_smmu_v3 *)node->node_data;
|
||||
|
||||
smmu->base_address = base_address;
|
||||
smmu->flags = flags;
|
||||
smmu->vatos_address = vatos_address;
|
||||
smmu->model = model;
|
||||
smmu->event_gsiv = event_gsiv;
|
||||
smmu->pri_gsiv = pri_gsiv;
|
||||
smmu->gerr_gsiv = gerr_gsiv;
|
||||
smmu->sync_gsiv = sync_gsiv;
|
||||
smmu->pxm = pxm;
|
||||
smmu->id_mapping_index = id_mapping_index;
|
||||
|
||||
mapping = (struct acpi_iort_id_mapping *)(smmu + 1);
|
||||
for (int i = 0; i < num_mappings; i++) {
|
||||
memcpy(mapping, &map[i], sizeof(struct acpi_iort_id_mapping));
|
||||
mapping++;
|
||||
}
|
||||
|
||||
ctx->current += node->length;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
static int acpi_write_iort(struct acpi_ctx *ctx, const struct acpi_writer *entry)
|
||||
{
|
||||
struct acpi_table_iort *iort;
|
||||
struct acpi_iort_node *node;
|
||||
u32 offset;
|
||||
int ret;
|
||||
|
||||
iort = ctx->current;
|
||||
ctx->tab_start = ctx->current;
|
||||
memset(iort, '\0', sizeof(struct acpi_table_iort));
|
||||
|
||||
acpi_fill_header(&iort->header, "IORT");
|
||||
iort->header.revision = 1;
|
||||
iort->header.creator_revision = 1;
|
||||
iort->header.length = sizeof(struct acpi_table_iort);
|
||||
iort->node_offset = sizeof(struct acpi_table_iort);
|
||||
|
||||
acpi_inc(ctx, sizeof(struct acpi_table_iort));
|
||||
|
||||
offset = sizeof(struct acpi_table_iort);
|
||||
ret = acpi_fill_iort(ctx);
|
||||
if (ret) {
|
||||
ctx->current = iort;
|
||||
return log_msg_ret("fill", ret);
|
||||
}
|
||||
|
||||
/* Count nodes filled in */
|
||||
for (node = (void *)iort + iort->node_offset;
|
||||
node->length > 0 && (void *)node < ctx->current;
|
||||
node = (void *)node + node->length)
|
||||
iort->node_count++;
|
||||
|
||||
/* (Re)calculate length and checksum */
|
||||
iort->header.length = ctx->current - (void *)iort;
|
||||
iort->header.checksum = table_compute_checksum((void *)iort, iort->header.length);
|
||||
log_debug("IORT at %p, length %x\n", iort, iort->header.length);
|
||||
|
||||
/* Drop the table if it is empty */
|
||||
if (iort->header.length == sizeof(struct acpi_table_iort))
|
||||
return log_msg_ret("fill", -ENOENT);
|
||||
acpi_add_table(ctx, iort);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ACPI_WRITER(5iort, "IORT", acpi_write_iort, 0);
|
||||
|
|
Loading…
Add table
Reference in a new issue