/* * Copyright (c) 2024, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #define NI_CHILD_NODE_COUNT 4 #define NI_CHILD_POINTERS_START 8 #define NI_PMU_SECURE_CTRL 0x100 #define NI_PMU_SECURE_EVENT_OBSERVATION 0x108 #define NI_PMU_DEBUG_ENABLE 0x110 #define NI_COMP_NUM_SUBFEATURES 0x100 #define NI_COMP_SUBFEATURE_TYPE_START 0x108 #define NI_COMP_SUBFEATURE_SECURE_CTRL_START 0x308 #define SECURE_OVERRIDE_DEFAULT BIT(0) #define SECURE_EVENT_ENABLE BIT(2) #define NA_EVENT_ENABLE BIT(3) #define PMU_ENABLE BIT(0) #define NI_NODE_MASK 0x0000ffff #define NI_NODE_TYPE(node_info) (node_info & NI_NODE_MASK) #define NI_CHILD_POINTER(i) (NI_CHILD_POINTERS_START + (i * 4)) #define NI_COMP_SUBFEATURE_TYPE(i) (NI_COMP_SUBFEATURE_TYPE_START + (i * 8)) #define NI_COMP_SUBFEATURE_SECURE_CTRL(i) (NI_COMP_SUBFEATURE_SECURE_CTRL_START + (i * 8)) #define NI_PERIPHERAL_ID0 0xfe0 #define NI_PIDR0_PART_MASK 0xff #define NI_PERIPHERAL_ID1 0xfe4 #define NI_PIDR1_PART_MASK 0xf #define NI_PIDR1_PART_SHIFT 8 enum ni_part { NI_700 = 0x43b, NI_710AE = 0x43d, NI_TOWER = 0x43f, }; enum ni_node_type { NI_INVALID_NODE = 0, NI_VOLTAGE_DOMAIN = 1, NI_POWER_DOMAIN = 2, NI_CLOCK_DOMAIN = 3, NI_ASNI = 4, NI_AMNI = 5, NI_PMU = 6, NI_HSNI = 7, NI_HMNI = 8, NI_PMNI = 9, NI_CMNI = 14, NI_CFGNI = 15 }; enum ni_subfeature_type { NI_SUBFEATURE_APU = 0, NI_SUBFEATURE_ADDR_MAP = 1, NI_SUBFEATURE_FCU = 2, NI_SUBFEATURE_IDM = 3 }; static void ni_enable_pmu(uintptr_t pmu_addr) { mmio_setbits_32(pmu_addr + NI_PMU_DEBUG_ENABLE, PMU_ENABLE); } static void ni_enable_fcu_ns_access(uintptr_t comp_addr) { uint32_t subfeature_type; uint32_t subfeature_count; uint32_t subfeature_secure_ctrl; subfeature_count = mmio_read_32(comp_addr + NI_COMP_NUM_SUBFEATURES); for (uint32_t i = 0U; i < subfeature_count; i++) { subfeature_type = NI_NODE_TYPE(mmio_read_32(comp_addr + NI_COMP_SUBFEATURE_TYPE(i))); if (subfeature_type == NI_SUBFEATURE_FCU) { subfeature_secure_ctrl = comp_addr + NI_COMP_SUBFEATURE_SECURE_CTRL(i); mmio_setbits_32(subfeature_secure_ctrl, SECURE_OVERRIDE_DEFAULT); } } } static void ni_enable_pmu_ns_access(uintptr_t comp_addr) { mmio_setbits_32(comp_addr + NI_PMU_SECURE_CTRL, SECURE_OVERRIDE_DEFAULT); mmio_setbits_32(comp_addr + NI_PMU_SECURE_EVENT_OBSERVATION, SECURE_EVENT_ENABLE | NA_EVENT_ENABLE); } static void ni_setup_component(uintptr_t comp_addr) { uint32_t node_info; node_info = mmio_read_32(comp_addr); switch (NI_NODE_TYPE(node_info)) { case NI_ASNI: case NI_AMNI: case NI_HSNI: case NI_HMNI: case NI_PMNI: ni_enable_fcu_ns_access(comp_addr); break; case NI_PMU: ni_enable_pmu_ns_access(comp_addr); ni_enable_pmu(comp_addr); break; default: return; } } int plat_arm_ni_setup(uintptr_t global_cfg) { uintptr_t vd_addr; uintptr_t pd_addr; uintptr_t cd_addr; uintptr_t comp_addr; uint32_t vd_count; uint32_t pd_count; uint32_t cd_count; uint32_t comp_count; uint32_t part; uint32_t reg; reg = mmio_read_32(global_cfg + NI_PERIPHERAL_ID0); part = reg & NI_PIDR0_PART_MASK; reg = mmio_read_32(global_cfg + NI_PERIPHERAL_ID1); part |= ((reg & NI_PIDR1_PART_MASK) << NI_PIDR1_PART_SHIFT); if (part != NI_TOWER) { ERROR("0x%x is not supported\n", part); return -EINVAL; } vd_count = mmio_read_32(global_cfg + NI_CHILD_NODE_COUNT); for (uint32_t i = 0U; i < vd_count; i++) { vd_addr = global_cfg + mmio_read_32(global_cfg + NI_CHILD_POINTER(i)); pd_count = mmio_read_32(vd_addr + NI_CHILD_NODE_COUNT); for (uint32_t j = 0U; j < pd_count; j++) { pd_addr = global_cfg + mmio_read_32(vd_addr + NI_CHILD_POINTER(j)); cd_count = mmio_read_32(pd_addr + NI_CHILD_NODE_COUNT); for (uint32_t k = 0U; k < cd_count; k++) { cd_addr = global_cfg + mmio_read_32(pd_addr + NI_CHILD_POINTER(k)); comp_count = mmio_read_32(cd_addr + NI_CHILD_NODE_COUNT); for (uint32_t l = 0U; l < comp_count; l++) { comp_addr = global_cfg + mmio_read_32(cd_addr + NI_CHILD_POINTER(l)); ni_setup_component(comp_addr); } } } } return 0; }