diff options
Diffstat (limited to 'hardinfo/dt_util.c')
-rw-r--r-- | hardinfo/dt_util.c | 127 |
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; |