summaryrefslogtreecommitdiff
path: root/hardinfo/dt_util.c
diff options
context:
space:
mode:
authorBurt P <pburt0@gmail.com>2018-09-28 20:43:41 -0500
committerLeandro A. F. Pereira <leandro@hardinfo.org>2018-10-22 19:45:03 -0700
commit61ffa17d01ef8668def03e15c33d1bd0dc9be93e (patch)
treee0f92bde2f13d5ae246f41d54678ed13ac1198cd /hardinfo/dt_util.c
parent7c3ba61e9e433bbad816833320c39cf5bb8afcd8 (diff)
devicetree: get opp-v2 freq range for gpu, if available
* opp-v2 = operating-points-v2, frequency scaling information from device tree that can be used for cpu, gpu, etc. * adds helper function to get the opp-v2 range of frequencies for a node, dtr_get_opp_range() in dt_util.c * adds a freq range in opp-v2 property for a node in dt * reports a gpu's max clock frequency if avaiable via opp-v2 Signed-off-by: Burt P <pburt0@gmail.com>
Diffstat (limited to 'hardinfo/dt_util.c')
-rw-r--r--hardinfo/dt_util.c127
1 files changed, 120 insertions, 7 deletions
diff --git a/hardinfo/dt_util.c b/hardinfo/dt_util.c
index b7b6073f..49d08f8b 100644
--- a/hardinfo/dt_util.c
+++ b/hardinfo/dt_util.c
@@ -52,6 +52,7 @@ static struct {
/* operating-points-v2: */
/* https://www.kernel.org/doc/Documentation/devicetree/bindings/opp/opp.txt */
+ { "operating-points-v2", DTP_PH_REF_OPP2 },
{ "opp-hz", DTP_UINT64 },
{ "opp-microvolt", DTP_UINT },
{ "opp-microvolt-L0", DTP_UINT }, /* opp-microvolt-<named>, but this kind of */
@@ -482,6 +483,21 @@ uint32_t dtr_get_prop_u32(dtr *s, dtr_obj *node, const char *name) {
return ret;
}
+uint64_t dtr_get_prop_u64(dtr *s, dtr_obj *node, const char *name) {
+ dtr_obj *prop;
+ char *ptmp;
+ uint64_t ret = 0;
+
+ ptmp = g_strdup_printf("%s/%s", (node == NULL) ? "" : node->path, name);
+ prop = dtr_obj_read(s, ptmp);
+ if (prop != NULL && prop->data != NULL) {
+ ret = be64toh(*prop->data_int64);
+ dtr_obj_free(prop);
+ }
+ g_free(ptmp);
+ return ret;
+}
+
int dtr_guess_type(dtr_obj *obj) {
char *tmp, *dash;
int i = 0, anc = 0, might_be_str = 1;
@@ -537,7 +553,7 @@ int dtr_guess_type(dtr_obj *obj) {
return DTP_UNK;
}
-char *dtr_elem_phref(dtr *s, dt_uint e, int show_path) {
+char *dtr_elem_phref(dtr *s, dt_uint e, int show_path, const char *extra) {
const char *ph_path, *al_label;
char *ret = NULL;
ph_path = dtr_phandle_lookup(s, be32toh(e));
@@ -546,12 +562,12 @@ char *dtr_elem_phref(dtr *s, dt_uint e, int show_path) {
al_label = dtr_symbol_lookup_by_path(s, ph_path);
if (al_label != NULL) {
if (show_path)
- ret = g_strdup_printf("&%s (%s)", al_label, ph_path);
+ ret = g_strdup_printf("&%s (%s) %s", al_label, ph_path, extra ? extra : "");
else
- ret = g_strdup_printf("&%s", al_label);
+ ret = g_strdup_printf("&%s %s", al_label, extra ? extra : "");
} else {
if (show_path)
- ret = g_strdup_printf("0x%x (%s)", be32toh(e), ph_path);
+ ret = g_strdup_printf("0x%x (%s) %s", be32toh(e), ph_path, extra ? extra : "");
}
}
if (ret == NULL)
@@ -559,6 +575,20 @@ char *dtr_elem_phref(dtr *s, dt_uint e, int show_path) {
return ret;
}
+char *dtr_elem_oppv2(dtr_obj* obj) {
+ char opp_str[512] = "";
+ dtr_obj *parent = dtr_get_parent_obj(obj);
+ if (parent) {
+ dt_opp_range *opp = dtr_get_opp_range(obj->dt, parent->path);
+ if (opp) {
+ snprintf(opp_str, 511, "[%d - %d %s]", opp->khz_min, opp->khz_max, _("kHz"));
+ free(opp);
+ }
+ dtr_obj_free(parent);
+ }
+ return dtr_elem_phref(obj->dt, *obj->data_int, 1, opp_str);
+}
+
char *dtr_elem_hex(dt_uint e) {
return g_strdup_printf("0x%x", be32toh(e) );
}
@@ -643,7 +673,7 @@ char *dtr_list_override(dtr_obj *obj) {
int l, consumed = 0;
src = obj->data_str;
while (consumed + 5 <= obj->length) {
- ph = dtr_elem_phref(obj->dt, *(dt_uint*)src, 1);
+ ph = dtr_elem_phref(obj->dt, *(dt_uint*)src, 1, NULL);
src += 4; consumed += 4;
l = strlen(src) + 1; /* consume the null */
str = dtr_list_str0(src, l);
@@ -682,7 +712,7 @@ char *dtr_list_phref(dtr_obj *obj, char *ext_cell_prop) {
ext_cells = 0;
else
ext_cells = dtr_get_phref_prop(obj->dt, be32toh(obj->data_int[i]), ext_cell_prop);
- ph = dtr_elem_phref(obj->dt, obj->data_int[i], 0); i++;
+ ph = dtr_elem_phref(obj->dt, obj->data_int[i], 0, NULL); i++;
if (ext_cells > count - i) ext_cells = count - i;
ext = dtr_list_hex((obj->data_int + i), ext_cells); i+=ext_cells;
ret = appf(ret, "<%s%s%s>",
@@ -814,7 +844,10 @@ char* dtr_str(dtr_obj *obj) {
ret = dtr_list_hex(obj->data, obj->length / 4);
break;
case DTP_PH_REF:
- ret = dtr_elem_phref(obj->dt, *obj->data_int, 1);
+ ret = dtr_elem_phref(obj->dt, *obj->data_int, 1, NULL);
+ break;
+ case DTP_PH_REF_OPP2:
+ ret = dtr_elem_oppv2(obj);
break;
case DTP_UINT:
ret = dtr_elem_uint(*obj->data_int);
@@ -895,6 +928,86 @@ int dtr_inh_find(dtr_obj *obj, char *qprop, int limit) {
return ret;
}
+dt_opp_range *dtr_get_opp_range(dtr *s, const char *name) {
+ dt_opp_range *ret = NULL;
+ dtr_obj *obj = NULL, *table_obj = NULL, *row_obj = NULL;
+ uint32_t opp_ph = 0;
+ const char *opp_table_path = NULL;
+ char *tab_compat = NULL, *tab_status = NULL;
+ const gchar *fn;
+ gchar *full_path;
+ GDir *dir;
+ uint64_t khz = 0;
+ uint32_t lns = 0;
+ char *row_status = NULL;
+
+ if (!s)
+ return NULL;
+
+ obj = dtr_obj_read(s, name);
+ if (!obj)
+ goto get_opp_finish;
+
+ opp_ph = dtr_get_prop_u32(s, obj, "operating-points-v2");
+ if (!opp_ph)
+ goto get_opp_finish;
+
+ opp_table_path = dtr_phandle_lookup(s, opp_ph);
+ if (!opp_table_path)
+ goto get_opp_finish;
+
+ table_obj = dtr_obj_read(s, opp_table_path);
+ if (!table_obj)
+ goto get_opp_finish;
+
+ tab_compat = dtr_get_prop_str(s, table_obj, "compatible");
+ tab_status = dtr_get_prop_str(s, table_obj, "status");
+
+ if (!tab_compat || strcmp(tab_compat, "operating-points-v2") != 0)
+ goto get_opp_finish;
+ if (tab_status && strcmp(tab_status, "disabled") == 0)
+ goto get_opp_finish;
+
+ ret = malloc(sizeof(dt_opp_range));
+ ret->phandle = opp_ph;
+ ret->khz_min = ret->khz_max = ret->clock_latency_ns = 0;
+
+ full_path = dtr_obj_full_path(table_obj);
+ dir = g_dir_open(full_path, 0 , NULL);
+ if (dir) {
+ while((fn = g_dir_read_name(dir)) != NULL) {
+ row_obj = dtr_get_prop_obj(s, table_obj, fn);
+ if (row_obj->type == DT_NODE) {
+ row_status = dtr_get_prop_str(s, row_obj, "status");
+ if (!row_status || strcmp(row_status, "disabled") != 0) {
+ khz = dtr_get_prop_u64(s, row_obj, "opp-hz");
+ khz /= 1000; /* 64b hz -> 32b khz */
+ lns = dtr_get_prop_u32(s, row_obj, "clock-latency-ns");
+ if (khz > ret->khz_max)
+ ret->khz_max = khz;
+ if (khz < ret->khz_min || ret->khz_min == 0)
+ ret->khz_min = khz;
+ ret->clock_latency_ns = lns;
+ }
+ }
+ free(row_status); row_status = NULL;
+ dtr_obj_free(row_obj);
+ row_obj = NULL;
+ }
+ g_dir_close(dir);
+ }
+ g_free(full_path);
+
+get_opp_finish:
+ dtr_obj_free(obj);
+ dtr_obj_free(table_obj);
+ free(tab_status);
+ free(tab_compat);
+ free(row_status);
+ return ret;
+}
+
+
void _dtr_read_aliases(dtr *s) {
gchar *dir_path;
GDir *dir;