1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2021, Arm Limited. All rights reserved. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <stddef.h> 8*91f16700Schasinglulu #include <stdint.h> 9*91f16700Schasinglulu 10*91f16700Schasinglulu #include <common/debug.h> 11*91f16700Schasinglulu #include <common/fdt_wrappers.h> 12*91f16700Schasinglulu #include <lib/fconf/fconf.h> 13*91f16700Schasinglulu #include <lib/fconf/fconf_amu_getter.h> 14*91f16700Schasinglulu #include <libfdt.h> 15*91f16700Schasinglulu 16*91f16700Schasinglulu #include <plat/common/platform.h> 17*91f16700Schasinglulu 18*91f16700Schasinglulu struct fconf_amu_config fconf_amu_config; 19*91f16700Schasinglulu static struct amu_topology fconf_amu_topology_; 20*91f16700Schasinglulu 21*91f16700Schasinglulu /* 22*91f16700Schasinglulu * Populate the core-specific AMU structure with information retrieved from a 23*91f16700Schasinglulu * device tree. 24*91f16700Schasinglulu * 25*91f16700Schasinglulu * Returns `0` on success, or a negative integer representing an error code. 26*91f16700Schasinglulu */ 27*91f16700Schasinglulu static int fconf_populate_amu_cpu_amu(const void *fdt, int parent, 28*91f16700Schasinglulu struct amu_core *amu) 29*91f16700Schasinglulu { 30*91f16700Schasinglulu int ret = 0; 31*91f16700Schasinglulu int node = 0; 32*91f16700Schasinglulu 33*91f16700Schasinglulu fdt_for_each_subnode(node, fdt, parent) { 34*91f16700Schasinglulu const char *name; 35*91f16700Schasinglulu const char *value; 36*91f16700Schasinglulu int len; 37*91f16700Schasinglulu 38*91f16700Schasinglulu uintptr_t idx = 0U; 39*91f16700Schasinglulu 40*91f16700Schasinglulu name = fdt_get_name(fdt, node, &len); 41*91f16700Schasinglulu if (strncmp(name, "counter@", 8) != 0) { 42*91f16700Schasinglulu continue; 43*91f16700Schasinglulu } 44*91f16700Schasinglulu 45*91f16700Schasinglulu ret = fdt_get_reg_props_by_index(fdt, node, 0, &idx, NULL); 46*91f16700Schasinglulu if (ret < 0) { 47*91f16700Schasinglulu break; 48*91f16700Schasinglulu } 49*91f16700Schasinglulu 50*91f16700Schasinglulu value = fdt_getprop(fdt, node, "enable-at-el3", &len); 51*91f16700Schasinglulu if ((value == NULL) && (len != -FDT_ERR_NOTFOUND)) { 52*91f16700Schasinglulu break; 53*91f16700Schasinglulu } 54*91f16700Schasinglulu 55*91f16700Schasinglulu if (len != -FDT_ERR_NOTFOUND) { 56*91f16700Schasinglulu amu->enable |= (1 << idx); 57*91f16700Schasinglulu } 58*91f16700Schasinglulu } 59*91f16700Schasinglulu 60*91f16700Schasinglulu if ((node < 0) && (node != -FDT_ERR_NOTFOUND)) { 61*91f16700Schasinglulu return node; 62*91f16700Schasinglulu } 63*91f16700Schasinglulu 64*91f16700Schasinglulu return ret; 65*91f16700Schasinglulu } 66*91f16700Schasinglulu 67*91f16700Schasinglulu /* 68*91f16700Schasinglulu * Within a `cpu` node, attempt to dereference the `amu` property, and populate 69*91f16700Schasinglulu * the AMU information for the core. 70*91f16700Schasinglulu * 71*91f16700Schasinglulu * Returns `0` on success, or a negative integer representing an error code. 72*91f16700Schasinglulu */ 73*91f16700Schasinglulu static int fconf_populate_amu_cpu(const void *fdt, int node, uintptr_t mpidr) 74*91f16700Schasinglulu { 75*91f16700Schasinglulu int ret; 76*91f16700Schasinglulu int idx; 77*91f16700Schasinglulu 78*91f16700Schasinglulu uint32_t amu_phandle; 79*91f16700Schasinglulu struct amu_core *amu; 80*91f16700Schasinglulu 81*91f16700Schasinglulu ret = fdt_read_uint32(fdt, node, "amu", &amu_phandle); 82*91f16700Schasinglulu if (ret < 0) { 83*91f16700Schasinglulu if (ret == -FDT_ERR_NOTFOUND) { 84*91f16700Schasinglulu ret = 0; 85*91f16700Schasinglulu } 86*91f16700Schasinglulu 87*91f16700Schasinglulu return ret; 88*91f16700Schasinglulu } 89*91f16700Schasinglulu 90*91f16700Schasinglulu node = fdt_node_offset_by_phandle(fdt, amu_phandle); 91*91f16700Schasinglulu if (node < 0) { 92*91f16700Schasinglulu return node; 93*91f16700Schasinglulu } 94*91f16700Schasinglulu 95*91f16700Schasinglulu idx = plat_core_pos_by_mpidr(mpidr); 96*91f16700Schasinglulu if (idx < 0) { 97*91f16700Schasinglulu return -FDT_ERR_BADVALUE; 98*91f16700Schasinglulu } 99*91f16700Schasinglulu 100*91f16700Schasinglulu amu = &fconf_amu_topology_.cores[idx]; 101*91f16700Schasinglulu 102*91f16700Schasinglulu return fconf_populate_amu_cpu_amu(fdt, node, amu); 103*91f16700Schasinglulu } 104*91f16700Schasinglulu 105*91f16700Schasinglulu /* 106*91f16700Schasinglulu * Populates the global `amu_topology` structure based on what's described by 107*91f16700Schasinglulu * the hardware configuration device tree blob. 108*91f16700Schasinglulu * 109*91f16700Schasinglulu * The device tree is expected to provide an `amu` property for each `cpu` node, 110*91f16700Schasinglulu * like so: 111*91f16700Schasinglulu * 112*91f16700Schasinglulu * cpu@0 { 113*91f16700Schasinglulu * amu = <&cpu0_amu>; 114*91f16700Schasinglulu * }; 115*91f16700Schasinglulu * 116*91f16700Schasinglulu * amus { 117*91f16700Schasinglulu * cpu0_amu: amu-0 { 118*91f16700Schasinglulu * counters { 119*91f16700Schasinglulu * #address-cells = <2>; 120*91f16700Schasinglulu * #size-cells = <0>; 121*91f16700Schasinglulu * 122*91f16700Schasinglulu * counter@x,y { 123*91f16700Schasinglulu * reg = <x y>; // Group x, counter y 124*91f16700Schasinglulu * }; 125*91f16700Schasinglulu * }; 126*91f16700Schasinglulu * }; 127*91f16700Schasinglulu * }; 128*91f16700Schasinglulu */ 129*91f16700Schasinglulu static int fconf_populate_amu(uintptr_t config) 130*91f16700Schasinglulu { 131*91f16700Schasinglulu int ret = fdtw_for_each_cpu( 132*91f16700Schasinglulu (const void *)config, fconf_populate_amu_cpu); 133*91f16700Schasinglulu if (ret == 0) { 134*91f16700Schasinglulu fconf_amu_config.topology = &fconf_amu_topology_; 135*91f16700Schasinglulu } else { 136*91f16700Schasinglulu ERROR("FCONF: failed to parse AMU information: %d\n", ret); 137*91f16700Schasinglulu } 138*91f16700Schasinglulu 139*91f16700Schasinglulu return ret; 140*91f16700Schasinglulu } 141*91f16700Schasinglulu 142*91f16700Schasinglulu FCONF_REGISTER_POPULATOR(HW_CONFIG, amu, fconf_populate_amu); 143