162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2022-2023, Ventana Micro Systems Inc 462306a36Sopenharmony_ci * Author: Sunil V L <sunilvl@ventanamicro.com> 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#define pr_fmt(fmt) "ACPI: RHCT: " fmt 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/acpi.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_cistatic struct acpi_table_header *acpi_get_rhct(void) 1362306a36Sopenharmony_ci{ 1462306a36Sopenharmony_ci static struct acpi_table_header *rhct; 1562306a36Sopenharmony_ci acpi_status status; 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci /* 1862306a36Sopenharmony_ci * RHCT will be used at runtime on every CPU, so we 1962306a36Sopenharmony_ci * don't need to call acpi_put_table() to release the table mapping. 2062306a36Sopenharmony_ci */ 2162306a36Sopenharmony_ci if (!rhct) { 2262306a36Sopenharmony_ci status = acpi_get_table(ACPI_SIG_RHCT, 0, &rhct); 2362306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 2462306a36Sopenharmony_ci pr_warn_once("No RHCT table found\n"); 2562306a36Sopenharmony_ci return NULL; 2662306a36Sopenharmony_ci } 2762306a36Sopenharmony_ci } 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci return rhct; 3062306a36Sopenharmony_ci} 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/* 3362306a36Sopenharmony_ci * During early boot, the caller should call acpi_get_table() and pass its pointer to 3462306a36Sopenharmony_ci * these functions(and free up later). At run time, since this table can be used 3562306a36Sopenharmony_ci * multiple times, NULL may be passed in order to use the cached table. 3662306a36Sopenharmony_ci */ 3762306a36Sopenharmony_ciint acpi_get_riscv_isa(struct acpi_table_header *table, unsigned int cpu, const char **isa) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci struct acpi_rhct_node_header *node, *ref_node, *end; 4062306a36Sopenharmony_ci u32 size_hdr = sizeof(struct acpi_rhct_node_header); 4162306a36Sopenharmony_ci u32 size_hartinfo = sizeof(struct acpi_rhct_hart_info); 4262306a36Sopenharmony_ci struct acpi_rhct_hart_info *hart_info; 4362306a36Sopenharmony_ci struct acpi_rhct_isa_string *isa_node; 4462306a36Sopenharmony_ci struct acpi_table_rhct *rhct; 4562306a36Sopenharmony_ci u32 *hart_info_node_offset; 4662306a36Sopenharmony_ci u32 acpi_cpu_id = get_acpi_id_for_cpu(cpu); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci BUG_ON(acpi_disabled); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci if (!table) { 5162306a36Sopenharmony_ci rhct = (struct acpi_table_rhct *)acpi_get_rhct(); 5262306a36Sopenharmony_ci if (!rhct) 5362306a36Sopenharmony_ci return -ENOENT; 5462306a36Sopenharmony_ci } else { 5562306a36Sopenharmony_ci rhct = (struct acpi_table_rhct *)table; 5662306a36Sopenharmony_ci } 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci end = ACPI_ADD_PTR(struct acpi_rhct_node_header, rhct, rhct->header.length); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci for (node = ACPI_ADD_PTR(struct acpi_rhct_node_header, rhct, rhct->node_offset); 6162306a36Sopenharmony_ci node < end; 6262306a36Sopenharmony_ci node = ACPI_ADD_PTR(struct acpi_rhct_node_header, node, node->length)) { 6362306a36Sopenharmony_ci if (node->type == ACPI_RHCT_NODE_TYPE_HART_INFO) { 6462306a36Sopenharmony_ci hart_info = ACPI_ADD_PTR(struct acpi_rhct_hart_info, node, size_hdr); 6562306a36Sopenharmony_ci hart_info_node_offset = ACPI_ADD_PTR(u32, hart_info, size_hartinfo); 6662306a36Sopenharmony_ci if (acpi_cpu_id != hart_info->uid) 6762306a36Sopenharmony_ci continue; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci for (int i = 0; i < hart_info->num_offsets; i++) { 7062306a36Sopenharmony_ci ref_node = ACPI_ADD_PTR(struct acpi_rhct_node_header, 7162306a36Sopenharmony_ci rhct, hart_info_node_offset[i]); 7262306a36Sopenharmony_ci if (ref_node->type == ACPI_RHCT_NODE_TYPE_ISA_STRING) { 7362306a36Sopenharmony_ci isa_node = ACPI_ADD_PTR(struct acpi_rhct_isa_string, 7462306a36Sopenharmony_ci ref_node, size_hdr); 7562306a36Sopenharmony_ci *isa = isa_node->isa; 7662306a36Sopenharmony_ci return 0; 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci } 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci } 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci return -1; 8362306a36Sopenharmony_ci} 84