fconf_amu_getter.c 3.0 KB

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