From: Eric van Tassell <evt@evtM17x.(none)>
Since my first attempt at doing this by analogy to what's already in powerdebug(tree of sysfs files) was rejected because reviewers didn't want to add a bunch more OMAP specific files to sysfs, I rewrote things in userland.
There are a few basic chunks to the changes:
1) Add code to parse a CSV-like config file that defines a heirarchy of whatever form you want where the leaves are fields in mmio registers. Include decoders for the field values something easy to read (ex: "off" instead of 0)
2) A code to build a tree that the powerdebug framework walks from a CSV config file
3) A small bit of code to read the mmio regs via /dev/mem
4) One example config file each for Power & Voltage Domains.
It's all tested on OMAP4430(panda) but the config file mechanism is completely general.
Eric van Tassell (7): - add config files to define selected power domain and voltage domain registers for OMAP4430 add delimi.* to parse config files with clone of strchrnul
- add support for reading memory mapped I/O registers via /dev/mem
- add support to display fields of memory mapped I/O registers with optional value decoding as defined by config files
- largest commit of this series. Provide an instance of the tree abstraction used by powerdebug core that is built by parsing a config file instead of walking a debugfs tree as, for example, the sensor functionality does
- add display options for Voltage and Power domains - enable extended display function call
- add options for power and voltage domains - call tree_mgr_new to create the objects that implement them
- cleanup
Android.mk | 4 +- Makefile | 4 +- delimi.c | 106 +++++++++++++++++++ delimi.h | 30 ++++++ dirtree.c | 149 +++++++++++++++++++++++++++ dirtree.h | 22 ++++ display.c | 30 +++++- display.h | 4 +- mainloop.c | 2 + mmioreg.c | 77 ++++++++++++++ mmioreg.h | 27 +++++ powerdebug.c | 56 +++++++++-- pwrdm.regdefs.omap4 | 33 ++++++ regfield.c | 279 +++++++++++++++++++++++++++++++++++++++++++++++++++ regfield.h | 52 ++++++++++ tree.c | 28 ++++++ tree.h | 11 +- tree_mgr.c | 203 +++++++++++++++++++++++++++++++++++++ tree_mgr.h | 25 +++++ utils.c | 69 +++++++++++++ utils.h | 15 ++- vdd.regdefs.omap4 | 68 +++++++++++++ 22 files changed, 1275 insertions(+), 19 deletions(-) create mode 100644 delimi.c create mode 100644 delimi.h create mode 100644 dirtree.c create mode 100644 dirtree.h create mode 100644 mmioreg.c create mode 100644 mmioreg.h create mode 100644 pwrdm.regdefs.omap4 create mode 100644 regfield.c create mode 100644 regfield.h create mode 100644 tree_mgr.c create mode 100644 tree_mgr.h create mode 100644 vdd.regdefs.omap4
From: Eric van Tassell <evt@evtM17x.(none)>
--- Android.mk | 4 +- Makefile | 2 +- delimi.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++ delimi.h | 30 +++++++++++++++ pwrdm.regdefs.omap4 | 33 ++++++++++++++++ utils.c | 12 ++++++ utils.h | 11 +++++- vdd.regdefs.omap4 | 68 +++++++++++++++++++++++++++++++++ 8 files changed, 262 insertions(+), 4 deletions(-) create mode 100644 delimi.c create mode 100644 delimi.h create mode 100644 pwrdm.regdefs.omap4 create mode 100644 vdd.regdefs.omap4
diff --git a/Android.mk b/Android.mk index e062c1c..f448d48 100644 --- a/Android.mk +++ b/Android.mk @@ -28,7 +28,7 @@ LOCAL_C_INCLUDES += external/stlport/stlport/ \ external/ncurses/include/ncurses
LOCAL_SRC_FILES += \ - powerdebug.c sensor.c clocks.c regulator.c \ - display.c tree.c utils.c mainloop.c + powerdebug.c sensor.c clocks.c regulator.c gpio.c \ + display.c tree.c utils.c mainloop.c delimi.c
include $(BUILD_EXECUTABLE) diff --git a/Makefile b/Makefile index 2da9d67..5007972 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ CFLAGS?=-O1 -g -Wall -Wshadow CC?=gcc
OBJS = powerdebug.o sensor.o clocks.o regulator.o gpio.o \ - display.o tree.o utils.o mainloop.o + display.o tree.o utils.o mainloop.o delimi.o
default: powerdebug
diff --git a/delimi.c b/delimi.c new file mode 100644 index 0000000..8c7dbee --- /dev/null +++ b/delimi.c @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright (C) 2012, Linaro Limited. + * + * This file is part of PowerDebug. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eric van Tassell + * - initial API and implementation + ******************************************************************************/ + +#define _GNU_SOURCE +#include <stdio.h> +#undef _GNU_SOURCE +#include <sys/types.h> +#include <stdbool.h> +#include <dirent.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <fcntl.h> +#include <sys/mman.h> +#include "display.h" +#include "utils.h" +#include "delimi.h" + +struct delim_iterator *delimi_new(char *buf, char delim) +{ + char *p; + struct delim_iterator *delimi; + + delimi = (struct delim_iterator *) calloc(1, sizeof(struct delim_iterator)); + if (!delimi) + return NULL; + + delimi->str = delimi->val = calloc(1, strlen(buf)); + delimi->delim = delim; + + for (p = delimi->str; *buf; buf++) { + /* skip blanks & newlines */ + if (isblank(*buf) || (*buf == '\n')) + continue; + *p++ = *buf; + } + delimi->val_end = strchrnul(delimi->val, delimi->delim); + delimi->val_end--; + return delimi; +} + +void delimi_free(struct delim_iterator *delimi) +{ + if (!delimi) + return; + if (delimi->str) + free(delimi->str); + free(delimi); +} + +void delimi_next(struct delim_iterator *delimi) +{ + if (*(delimi->val_end + 1) == '\0') { + /* we saw delimi->val_end = "last-value\0" */ + delimi->val = delimi->val_end = delimi->val_end + 1; + } else { + /* saw "x,value1,value2,..." */ + delimi->val = delimi->val_end + 2; + delimi->val_end = strchrnul(delimi->val, delimi->delim); + if (*(delimi->val_end) == delimi->delim) + delimi->val_end--; + } +} + +int delimi_empty(struct delim_iterator *delimi) +{ + return (delimi->val == delimi->val_end); +} + +#ifdef DEBUG_PARSE +void delimi_show(struct delim_iterator *delimi) +{ + printf("%s:\n\tstr = %s\n\tval = %s\n\tval_end = %s\n\tempty = %s\n", + __func__, + delimi->str, + delimi->val, + delimi->val_end, + delimi_empty(delimi) ? "true" : "false"); +} +#endif /* DEBUG_PARSE */ + +/* allocate space for and get current value */ +char *delimi_aget_val(struct delim_iterator *delimi) +{ + char *tmp; + + if (!delimi) + BAIL_OUT(("NULL struct delim_iterator *")); + + tmp = calloc(1, delimi->val_end - delimi->val + 2); + memcpy(tmp, delimi->val, delimi->val_end - delimi->val + 1); + return tmp; +} + diff --git a/delimi.h b/delimi.h new file mode 100644 index 0000000..f000097 --- /dev/null +++ b/delimi.h @@ -0,0 +1,30 @@ +/****************************************************************************** + * Copyright (C) 2012, Linaro Limited. + * + * This file is part of PowerDebug. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eric van Tassell + * - initial API and implementation + *****************************************************************************/ +struct delim_iterator { + char *str; + char *val; + char *val_end; + char delim; +}; + +/* prototypes for exported functions */ +void delimi_next(struct delim_iterator *delimi); +int delimi_empty(struct delim_iterator *delimi); +char *delimi_aget_val(struct delim_iterator *delimi); +#ifdef DEBUG_PARSE +void delimi_show(struct delim_iterator *delimi); +#endif +struct delim_iterator *delimi_new(char *buf, char delim); +void delimi_free(struct delim_iterator *delimi); diff --git a/pwrdm.regdefs.omap4 b/pwrdm.regdefs.omap4 new file mode 100644 index 0000000..30e85b7 --- /dev/null +++ b/pwrdm.regdefs.omap4 @@ -0,0 +1,33 @@ +# +# see the README for information on the format of this file +# this is just a sample, much more could be added +# +decoder, boolean, false, true +decoder, logicst, off, on +decoder, retst, retention registers, whole logic +decoder, statest, off, retention, on-inactive, on-active +push, MPU_PD +push, PWRSTCTL +field, lowpowerstatechange, 0x4A306300, 4, 1, boolean +field, logicretstate, 0x4A306300, 2, 1, retst +field, powerstate, 0x4A306300, 0, 3, statest +pop +push, PWRST +field, powerstate, 0x4A306304, 0, 3, statest +pop +pop +push, ABE_PD +push, PWRSTCTL +field, powerstate, 0x4A306500, 0, 3, statest +pop +pop +push, IVAHD_PD +push, PWRSTCTL +field, powerstate, 0x4A306F00, 0, 3, statest +pop +pop +push, EMU_PD +push, PWRSTCTL +field, powerstate, 0x4A307900, 0, 3, statest +pop +pop diff --git a/utils.c b/utils.c index e47c58e..0e95f05 100644 --- a/utils.c +++ b/utils.c @@ -53,3 +53,15 @@ out_free: free(rpath); return ret; } + +/* bionic lacks strchrnul */ +char *strchrnul(char *str, char delim) +{ + char *tmp; + + tmp = strchr(str, delim); + + if (tmp == NULL) + tmp = str + strlen(str) - 1; + return tmp; +} diff --git a/utils.h b/utils.h index d4ac65a..c5cec51 100644 --- a/utils.h +++ b/utils.h @@ -15,8 +15,17 @@ #ifndef __UTILS_H #define __UTILS_H
+#define BAIL_OUT(x) \ + { \ + printf x; \ + printf("%s@%d:BAILING OUT HERE:\n", __func__, __LINE__); \ + exit(0); \ +} +#undef DEBUG_PARSE + +/* prototypes */ extern int file_read_value(const char *path, const char *name, const char *format, void *value);
- +char *strchrnul(char *str, char delim); #endif diff --git a/vdd.regdefs.omap4 b/vdd.regdefs.omap4 new file mode 100644 index 0000000..8b3c3e6 --- /dev/null +++ b/vdd.regdefs.omap4 @@ -0,0 +1,68 @@ +# +# see the README for information on the format of this file +# this is just a sample, much more could be added +# +decoder, boolean, false, true +decoder, initvdd, reset, write_to_voltage_processor +decoder, forceupd, reset, write_to_SMPS +# +push, VDD_CORE_L +# +push, CONFIG +field, INITVOLTAGE, 0x4A307B40, 8, 0xff +field, TIMEOUTEN, 0x4A307B40, 3, 1, boolean +field, INITVDD, 0x4A307B40, 2, 1, initvdd +field, FORCEUPD ,0x4A307B40, 1, 1, forceupd +field, VPENABLE,0x4A307B40, 0, 1, boolean +# +pop +push, STATUS +field, VPINIDLE,0x4A307B44, 0, 1 +# +pop +push, VOLTAGE +field, VPVOLTAGE,0x4A307B4C, 0, 0xff +# +pop +pop +push, VDD_MPU_L +# +push, CONFIG +field, INITVOLTAGE, 0x4A307B58, 8, 0xff +field, TIMEOUTEN, 0x4A307B58, 3, 1, boolean +field, INITVDD, 0x4A307B58, 2, 1, initvdd +field, FORCEUPD ,0x4A307B58, 1, 1, forceupd +field, VPENABLE,0x4A307B58, 0, 1, boolean +# +pop +push, STATUS +field, VPINIDLE,0x4A307B5C, 0, 1 +# +pop +push, VOLTAGE +field, VPVOLTAGE,0x4A307B64, 0, 0xff +# +pop +pop +push, VDD_IVA_L +# +push, CONFIG +field, INITVOLTAGE, 0x4A307B70, 8, 0xff +field, TIMEOUTEN, 0x4A307B70, 3, 1, boolean +field, INITVDD, 0x4A307B70, 2, 1, initvdd +field, FORCEUPD ,0x4A307B70, 1, 1, forceupd +field, VPENABLE,0x4A307B70, 0, 1, boolean +# +pop +push, STATUS +field, VPINIDLE,0x4A307B74, 0, 1 +# +pop +push, VOLTAGE +field, VPVOLTAGE,0x4A307B7C, 0, 0xff +pop +pop +# +push, misc +push, PRM_VC_CFG_CHANNEL +field, [31:0], 0x4a307BA4, 0, 0xffffffff
From: Eric van Tassell <evt@evtM17x.(none)>
--- Android.mk | 2 +- Makefile | 2 +- mmioreg.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ mmioreg.h | 26 +++++++++++++++++++++ 4 files changed, 104 insertions(+), 2 deletions(-) create mode 100644 mmioreg.c create mode 100644 mmioreg.h
diff --git a/Android.mk b/Android.mk index f448d48..c6ec0d7 100644 --- a/Android.mk +++ b/Android.mk @@ -29,6 +29,6 @@ LOCAL_C_INCLUDES += external/stlport/stlport/ \
LOCAL_SRC_FILES += \ powerdebug.c sensor.c clocks.c regulator.c gpio.c \ - display.c tree.c utils.c mainloop.c delimi.c + display.c tree.c utils.c mainloop.c delimi.c mmioreg.c
include $(BUILD_EXECUTABLE) diff --git a/Makefile b/Makefile index 5007972..71537c9 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ CFLAGS?=-O1 -g -Wall -Wshadow CC?=gcc
OBJS = powerdebug.o sensor.o clocks.o regulator.o gpio.o \ - display.o tree.o utils.o mainloop.o delimi.o + display.o tree.o utils.o mainloop.o delimi.o mmioreg.o
default: powerdebug
diff --git a/mmioreg.c b/mmioreg.c new file mode 100644 index 0000000..6dab4f6 --- /dev/null +++ b/mmioreg.c @@ -0,0 +1,76 @@ +/****************************************************************************** + * Copyright (C) 2012, Linaro Limited. + * + * This file is part of PowerDebug. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eric van Tassell + * - initial API and implementation + *****************************************************************************/ + +#define _GNU_SOURCE +#include <stdio.h> +#undef _GNU_SOURCE +#include <sys/types.h> +#include <stdbool.h> +#include <dirent.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <fcntl.h> +#include <sys/mman.h> +#include "utils.h" +#include "delimi.h" +#include "mmioreg.h" + +struct memobj devmem = { + .path = "/dev/mem", + .fd = -1, + .map_base = NULL, + .last_map_req = 0, + .map_size = 4096, + .map_mask = 4096 - 1 +}; + +void memobj_open(struct memobj *m) +{ + m->fd = open("/dev/mem", O_RDWR | O_SYNC); + if (m->fd == -1) + BAIL_OUT(("%s: failed to open %s\n", __func__, m->path)); +} + +uint32_t memobj_readu32(struct memobj *m, uint32_t addr) +{ + uint32_t ret; + + if (m->fd == -1) + memobj_open(m); + + if (m->last_map_req != addr) { + if (m->map_base != NULL) + munmap(m->map_base, m->map_size); + m->map_base = mmap(0, + m->map_size, + PROT_READ|PROT_WRITE, MAP_SHARED, + m->fd, + addr & ~m->map_mask); + if (m->map_base == (void *)-1) + BAIL_OUT(("could not map system memory")); + m->last_map_req = addr; + } + ret = *((uint32_t *)(((uint32_t)m->map_base) + (addr & m->map_mask))); + return ret; +} + +static void memobj_close(struct memobj *m) +{ + close(m->fd); + m->map_base = NULL; + m->last_map_req = 0; +} + diff --git a/mmioreg.h b/mmioreg.h new file mode 100644 index 0000000..900b1fd --- /dev/null +++ b/mmioreg.h @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (C) 2012, Linaro Limited. + * + * This file is part of PowerDebug. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eric van Tassell + * - initial API and implementation + ******************************************************************************/ + +struct memobj { + char *path; + int fd; + void *map_base; + uint32_t last_map_req; + unsigned long map_size; + unsigned long map_mask; +}; + +/* prototypes */ +uint32_t memobj_readu32(struct memobj *m, uint32_t addr);
From: Eric van Tassell <evt@evtM17x.(none)>
--- Android.mk | 2 +- Makefile | 2 +- mainloop.c | 2 + mmioreg.c | 43 +++++----- mmioreg.h | 3 +- regfield.c | 279 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ regfield.h | 52 +++++++++++ utils.h | 1 + 8 files changed, 360 insertions(+), 24 deletions(-) create mode 100644 regfield.c create mode 100644 regfield.h
diff --git a/Android.mk b/Android.mk index c6ec0d7..7bf67dc 100644 --- a/Android.mk +++ b/Android.mk @@ -28,7 +28,7 @@ LOCAL_C_INCLUDES += external/stlport/stlport/ \ external/ncurses/include/ncurses
LOCAL_SRC_FILES += \ - powerdebug.c sensor.c clocks.c regulator.c gpio.c \ + powerdebug.c sensor.c clocks.c regulator.c gpio.c regfield.c\ display.c tree.c utils.c mainloop.c delimi.c mmioreg.c
include $(BUILD_EXECUTABLE) diff --git a/Makefile b/Makefile index 71537c9..e7e3f20 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ MANDIR=/usr/share/man/man8 CFLAGS?=-O1 -g -Wall -Wshadow CC?=gcc
-OBJS = powerdebug.o sensor.o clocks.o regulator.o gpio.o \ +OBJS = powerdebug.o sensor.o clocks.o regulator.o gpio.o regfield.o\ display.o tree.o utils.o mainloop.o delimi.o mmioreg.o
default: powerdebug diff --git a/mainloop.c b/mainloop.c index 02dda98..57fc4e7 100644 --- a/mainloop.c +++ b/mainloop.c @@ -18,6 +18,7 @@ #include <unistd.h> #include <sys/epoll.h> #include "mainloop.h" +#include "mmioreg.h"
static int epfd = -1; static unsigned short nrhandler; @@ -118,5 +119,6 @@ int mainloop_init(void)
void mainloop_fini(void) { + memobj_close(); close(epfd); } diff --git a/mmioreg.c b/mmioreg.c index 6dab4f6..54ce24e 100644 --- a/mmioreg.c +++ b/mmioreg.c @@ -37,40 +37,41 @@ struct memobj devmem = { .map_mask = 4096 - 1 };
-void memobj_open(struct memobj *m) +static void memobj_open(void) { - m->fd = open("/dev/mem", O_RDWR | O_SYNC); - if (m->fd == -1) - BAIL_OUT(("%s: failed to open %s\n", __func__, m->path)); + devmem.fd = open("/dev/mem", O_RDWR | O_SYNC); + if (devmem.fd == -1) + BAIL_OUT(("%s: failed to open %s\n", __func__, devmem.path)); }
-uint32_t memobj_readu32(struct memobj *m, uint32_t addr) +uint32_t memobj_readu32(uint32_t addr) { uint32_t ret;
- if (m->fd == -1) - memobj_open(m); + if (devmem.fd == -1) + memobj_open();
- if (m->last_map_req != addr) { - if (m->map_base != NULL) - munmap(m->map_base, m->map_size); - m->map_base = mmap(0, - m->map_size, + if (devmem.last_map_req != addr) { + if (devmem.map_base != NULL) + munmap(devmem.map_base, devmem.map_size); + devmem.map_base = mmap(0, + devmem.map_size, PROT_READ|PROT_WRITE, MAP_SHARED, - m->fd, - addr & ~m->map_mask); - if (m->map_base == (void *)-1) + devmem.fd, + addr & ~devmem.map_mask); + if (devmem.map_base == (void *)-1) BAIL_OUT(("could not map system memory")); - m->last_map_req = addr; + devmem.last_map_req = addr; } - ret = *((uint32_t *)(((uint32_t)m->map_base) + (addr & m->map_mask))); + ret = *((uint32_t *) + (((uint32_t)devmem.map_base) + (addr & devmem.map_mask))); return ret; }
-static void memobj_close(struct memobj *m) +void memobj_close(void) { - close(m->fd); - m->map_base = NULL; - m->last_map_req = 0; + close(devmem.fd); + devmem.map_base = NULL; + devmem.last_map_req = 0; }
diff --git a/mmioreg.h b/mmioreg.h index 900b1fd..1757b10 100644 --- a/mmioreg.h +++ b/mmioreg.h @@ -23,4 +23,5 @@ struct memobj { };
/* prototypes */ -uint32_t memobj_readu32(struct memobj *m, uint32_t addr); +uint32_t memobj_readu32(uint32_t addr); +void memobj_close(void); diff --git a/regfield.c b/regfield.c new file mode 100644 index 0000000..2e7e31c --- /dev/null +++ b/regfield.c @@ -0,0 +1,279 @@ +/******************************************************************************* + * Copyright (C) 2012, Linaro Limited. + * + * This file is part of PowerDebug. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eric van Tassell + * - initial API and implementation + ******************************************************************************/ + +#define _GNU_SOURCE +#include <stdio.h> +#undef _GNU_SOURCE +#include <sys/types.h> +#include <stdbool.h> +#include <dirent.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <fcntl.h> +#include <sys/mman.h> +#include "utils.h" +#include "delimi.h" +#include "regfield.h" +#include "mmioreg.h" + +static struct decoder *decoder_new(char *name) +{ + struct decoder *d = (struct decoder *)calloc(1, sizeof(struct decoder)); + + if (!d) + return NULL; + + d->name = name; + d->values = NULL; + d->num_values = 0; + + return d; +} + +#ifdef DEBUG_PARSE +static void decoder_show(struct decoder *d) +{ + int i; + + if (!d) + return; + printf("decoder: %s\n", d->name); + for (i = 0; i < d->num_values; i++) + printf("\t%d: %s\n", i, d->values[i]); +} +#endif /* DEBUG_PARSE */ + +static void decoder_free(struct decoder *d) +{ + int i; + + if (!d) + return; + if (d->name) + free(d->name); + + for (i = 0; i < d->num_values; i++) { + if (d->values[i]) + free(d->values[i]); + } + free(d); +} + +static int decoder_add_value(struct decoder *d, char *value) +{ + char **tmp; + + tmp = realloc(d->values, (d->num_values + 1) * sizeof(char *)); + + if (tmp == NULL) + return 0; + + d->values = tmp; + d->values[d->num_values] = value; + d->num_values++; + return 1; +} + +static struct field_def *field_new(char *name) +{ + struct field_def *f + = (struct field_def *)calloc(1, sizeof(struct field_def)); + + if (!f) + return NULL; + + f->name = name; + return f; +} + +static void field_show(struct field_def *f) +{ + if (!f) + return; + printf("%s\n", __func__); + printf("\t%s\n", f->name); + printf("\t0x%x\n", f->address); + printf("\t0x%x\n", f->shift); + printf("\t0x%x\n", f->mask); + printf("--------- decoder ---------\n"); +#ifdef DEBUG_PARSE + decoder_show(f->decoder); +#endif +} + +struct decoder_ctl decoder_ctl; + +char *field_decode(struct field_def *f) +{ + if (!f) + BAIL_OUT(("null field")); + + if (f->value >= f->decoder->num_values) + return "out of range"; + + return f->decoder->values[f->value]; +} + +void field_read(struct field_def *f) +{ + f->value = memobj_readu32(f->address); + f->value = (f->value >> f->shift) & f->mask; +} + +#ifdef DEBUG_PARSE +static void decoder_ctl_show(struct decoder_ctl *dc) +{ + int i; + + for (i = 0; i < dc->num_decoders; i++) +#ifdef DEBUG_PARSE + decoder_show(dc->decoders[i]); +#endif +} +#endif /* DEBUG_PARSE */ + +static struct decoder *decoder_ctl_lookup_decoder(struct decoder_ctl *dc, + char *name) +{ + int i; + + if (!name) + return NULL; + + for (i = 0; i < dc->num_decoders; i++) { + if (!strncmp(dc->decoders[i]->name, name, strlen(name))) + return dc->decoders[i]; + } + return NULL; +} + +static void decoder_ctl_free(struct decoder_ctl *dc) +{ + int i; + + for (i = 0; i < dc->num_decoders; i++) + decoder_free(dc->decoders[i]); + free(dc->decoders); +} + +static int decoder_ctl_add_decoder(struct decoder_ctl *dc, struct decoder *d) +{ + + struct decoder **tmp; + + tmp = realloc(dc->decoders, + (dc->num_decoders + 1) * sizeof(struct decoder *)); + if (tmp == NULL) + return 0; + dc->decoders = tmp; + dc->decoders[dc->num_decoders] = d; + dc->num_decoders++; + return 1; +} + +void *parse_decoder(struct delim_iterator *delimi, char **name) +{ + struct decoder *decoder; + /* skip the first word, we already know it's "decoder" */ + delimi_next(delimi); + + decoder = decoder_new(delimi_aget_val(delimi)); + delimi_next(delimi); + if (decoder == NULL) + return NULL; + + /* + * we're relaxed about errors in processing decoders, + * if we can't decode -> just report raw value + */ + while (!delimi_empty(delimi)) { + if (!decoder_add_value(decoder, delimi_aget_val(delimi))) { + decoder_free(decoder); + return NULL; + } + delimi_next(delimi); + } + + if (!decoder_ctl_add_decoder(&decoder_ctl, decoder)) { + decoder_ctl_free(&decoder_ctl); + return NULL; + } + return NULL; +} + +void *parse_field(struct delim_iterator *delimi, char **name) +{ + char *verb, *fldname, *decoder_name; + struct field_def *f; + unsigned int address; + int shift, mask; + char *tmp; + + /* skip the first word, we already know it's "field" */ + delimi_next(delimi); + + f = field_new(delimi_aget_val(delimi)); + delimi_next(delimi); + + tmp = delimi_aget_val(delimi); + if (!tmp) + return NULL; + + sscanf(tmp, "%x", &f->address); + free(tmp); + delimi_next(delimi); + + tmp = delimi_aget_val(delimi); + if (!tmp) + return NULL; + + sscanf(tmp, "%x", &f->shift); + free(tmp); + delimi_next(delimi); + + tmp = delimi_aget_val(delimi); + if (!tmp) + return NULL; + + sscanf(tmp, "%x", &f->mask); + free(tmp); + delimi_next(delimi); + + tmp = delimi_aget_val(delimi); /* decoder is optional */ + if (strlen(tmp) != 0) + f->decoder = decoder_ctl_lookup_decoder(&decoder_ctl, tmp); + free(tmp); + *name = f->name; + + return f; +} + +static struct parser_descriptor parser_descriptors[2] = { + { + .verb = "field", + .parser = parse_field, + }, + { + .verb = "decoder", + .parser = parse_decoder, + }, +}; + + +struct parser_ctl regfield_parsers = { + .num_parsers = NUM_ELTS(parser_descriptors, struct parser_descriptor), + .descriptors = parser_descriptors +}; diff --git a/regfield.h b/regfield.h new file mode 100644 index 0000000..4fa6e8a --- /dev/null +++ b/regfield.h @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (C) 2012, Linaro Limited. + * + * This file is part of PowerDebug. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eric van Tassell + * - initial API and implementation + ******************************************************************************/ +struct parser_descriptor { + char *verb; + void *(*parser)(struct delim_iterator *delimi, char **); +}; + +struct parser_ctl { + int num_parsers; + struct parser_descriptor *descriptors; +}; + +struct decoder { + char *name; + char **values; + unsigned char num_values; +}; + +struct decoder_ctl { + struct decoder **decoders; + unsigned char num_decoders; +}; + +struct field_def { + char *name; + unsigned int address; + unsigned int shift; + unsigned int mask; + struct decoder *decoder; + uint32_t value; +}; + +/* shared data */ +extern struct parser_ctl regfield_parsers; + +/* prototypes */ +char *field_decode(struct field_def *f); +void field_read(struct field_def *f); +void *parse_field(struct delim_iterator *delimi, char **name); +void *parse_decoder(struct delim_iterator *delimi, char **name); diff --git a/utils.h b/utils.h index c5cec51..581e20d 100644 --- a/utils.h +++ b/utils.h @@ -23,6 +23,7 @@ } #undef DEBUG_PARSE
+#define NUM_ELTS(vbl, type) (sizeof(vbl) / sizeof(type)) /* prototypes */ extern int file_read_value(const char *path, const char *name, const char *format, void *value);
From: Eric van Tassell <evt@evtM17x.(none)>
--- Android.mk | 4 +- Makefile | 4 +- dirtree.c | 149 ++++++++++++++++++++++++++++++++++++++++++++ dirtree.h | 22 +++++++ display.c | 12 ++++ display.h | 4 +- powerdebug.c | 1 + tree.c | 28 +++++++++ tree.h | 11 +++- tree_mgr.c | 197 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ tree_mgr.h | 25 ++++++++ utils.c | 58 +++++++++++++++++ utils.h | 3 + 13 files changed, 511 insertions(+), 7 deletions(-) create mode 100644 dirtree.c create mode 100644 dirtree.h create mode 100644 tree_mgr.c create mode 100644 tree_mgr.h
diff --git a/Android.mk b/Android.mk index 7bf67dc..d67317f 100644 --- a/Android.mk +++ b/Android.mk @@ -28,7 +28,7 @@ LOCAL_C_INCLUDES += external/stlport/stlport/ \ external/ncurses/include/ncurses
LOCAL_SRC_FILES += \ - powerdebug.c sensor.c clocks.c regulator.c gpio.c regfield.c\ - display.c tree.c utils.c mainloop.c delimi.c mmioreg.c + powerdebug.c sensor.c clocks.c regulator.c gpio.c regfield.c dirtree.c \ + display.c tree.c utils.c mainloop.c delimi.c mmioreg.c tree_mgr.c
include $(BUILD_EXECUTABLE) diff --git a/Makefile b/Makefile index e7e3f20..b04749e 100644 --- a/Makefile +++ b/Makefile @@ -4,8 +4,8 @@ MANDIR=/usr/share/man/man8 CFLAGS?=-O1 -g -Wall -Wshadow CC?=gcc
-OBJS = powerdebug.o sensor.o clocks.o regulator.o gpio.o regfield.o\ - display.o tree.o utils.o mainloop.o delimi.o mmioreg.o +OBJS = powerdebug.o sensor.o clocks.o regulator.o gpio.o regfield.o dirtree.o \ + display.o tree.o utils.o mainloop.o delimi.o mmioreg.o tree_mgr.o
default: powerdebug
diff --git a/dirtree.c b/dirtree.c new file mode 100644 index 0000000..a630f14 --- /dev/null +++ b/dirtree.c @@ -0,0 +1,149 @@ +/******************************************************************************* + * Copyright (C) 2012, Linaro Limited. + * + * This file is part of PowerDebug. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eric van Tassell + * - initial API and implementation + ******************************************************************************/ + +#define _GNU_SOURCE +#include <stdio.h> +#undef _GNU_SOURCE +#include <sys/types.h> +#include <stdbool.h> +#include <dirent.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <fcntl.h> +#include <sys/mman.h> +#include "display.h" +#include "tree.h" +#include "utils.h" +#include "delimi.h" +#include "dirtree.h" +#include "regfield.h" + +/* + * This function takes the path to a config file that defines the heirarchy + * of memory mapped registers. ex: root -> power-domain -> register -> field + * + * This approach is taken to avoid creating tons of architecture specific + * debugfs files + * + * @tree : a path to the topmost directory path + * Returns a tree structure corresponding to the root node of the + * directory tree representation on success, NULL otherwise + */ +struct tree *tree_load_file(const char *cfg_file_path) +{ + struct tree *tree; + struct tree *node_stack[MAX_TREE_DEPTH]; + struct tree *node; + int sp = 0; + FILE *fp; + char buf[MAX_LINE_LENGTH]; + char *cfg_field; + char new_path[MAX_LINE_LENGTH]; + struct tree *(*alloc)(const char *path, int depth); + void (*add_child)(struct tree *parent, struct tree *child); + struct delim_iterator *delimi; + struct parser_ctl *parser_ctl = ®field_parsers; + + get_tree_cbs(&alloc, &add_child); + if ((alloc == NULL) || (add_child == NULL)) + BAIL_OUT(("cannnot determine alloc or add_child callbacks")); + + memset(node_stack, 0, sizeof(node_stack)); + + tree = alloc("/", sp); + if (!tree) + return NULL; + + node_stack[sp] = tree; + + fp = fopen(cfg_file_path, "r"); + if (!fp) + BAIL_OUT(("Cannot open config file: %s\n", cfg_file_path)); + + memset(buf, 0, sizeof(buf)); + + while (fgets(buf, sizeof(buf), fp)) { + if (*buf == '#') + continue; + delimi = delimi_new(buf, ','); + if (delimi == NULL) + BAIL_OUT(("NULL delim_iterator_t *")); + + if (!strncmp(buf, "push", strlen("push"))) { + char path[MAX_LINE_LENGTH]; + + if (sp == MAX_TREE_DEPTH - 1) { + printf("push - max tree depth reached\n"); + exit(0); + } + + memset(path, 0, sizeof(path)); + sscanf(buf, "push, %s\n", path); + if (sp == 0) + sprintf(new_path, "%s%s", + node_stack[sp]->path, + path); + else + sprintf(new_path, + "%s/%s", + node_stack[sp]->path, + path); + + sp++; + node_stack[sp] = alloc(new_path, sp); + add_child(node_stack[sp - 1], node_stack[sp]); + } else if (!strncmp(buf, "pop", strlen("pop"))) { + if (sp == 0) { + printf("illegal - cant pop the root node\n"); + exit(0); + } + sp--; + } else { + int i; + int parser_found = 0; + + for (i = 0; i < parser_ctl->num_parsers; i++) { + struct parser_descriptor *pd; + + pd = &(parser_ctl->descriptors[i]); + if (!strncmp(buf, pd->verb, strlen(pd->verb))) { + void *pvdata; + char *name; + + parser_found = 1; + pvdata = (pd->parser)(delimi, &name); + if (pvdata) { + sprintf(new_path, "%s/%s", + node_stack[sp]->path, + name); + node = alloc(new_path, sp + 1); + if (!node) + BAIL_OUT(("NULL node")); + + node->private = pvdata; + add_child(node_stack[sp], node); + } + break; + } + } + if (!parser_found) + BAIL_OUT(("illegal config line:%s\n", buf)); + } + delimi_free(delimi); + memset(buf, 0, sizeof(buf)); + } + return tree; +} diff --git a/dirtree.h b/dirtree.h new file mode 100644 index 0000000..57abb98 --- /dev/null +++ b/dirtree.h @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (C) 2012, Linaro Limited. + * + * This file is part of PowerDebug. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eric van Tassell + * - initial API and implementation + ******************************************************************************/ + +#define MAX_TREE_DEPTH 8 +#define MAX_LINE_LENGTH 255 + +typedef void (*p_parser)(struct delim_iterator *, char **); + +/* prototypes */ +struct tree *tree_load_file(const char *cfg_file_path); diff --git a/display.c b/display.c index f06387c..fcb4ec1 100644 --- a/display.c +++ b/display.c @@ -24,6 +24,7 @@ #include "mainloop.h" #include "regulator.h" #include "display.h" +#include "utils.h"
enum { PT_COLOR_DEFAULT = 1, PT_COLOR_HEADER_BAR, @@ -52,6 +53,7 @@ struct windata { WINDOW *pad; struct display_ops *ops; struct rowdata *rowdata; + void *pvdata; char *name; int nrdata; int scrolling; @@ -600,3 +602,13 @@ int display_register(int win, struct display_ops *ops)
return 0; } + +int display_register_ex(int win, struct display_ops *ops, void *v) +{ + if (display_register(win, ops)) + return -1; + + windata[win].pvdata = v; + printf("%s: win = %d, v = %p\n", __func__, win, v); + return 0; +} diff --git a/display.h b/display.h index 6362a48..d469a66 100644 --- a/display.h +++ b/display.h @@ -13,10 +13,9 @@ * - initial API and implementation *******************************************************************************/
-enum { CLOCK, REGULATOR, SENSOR, GPIO }; - struct display_ops { int (*display)(bool refresh); + int (*display_ex)(bool refresh, void *v); int (*select)(void); int (*find)(const char *); int (*selectf)(void); @@ -31,6 +30,7 @@ extern void *display_get_row_data(int window);
extern int display_init(int wdefault); extern int display_register(int win, struct display_ops *ops); +extern int display_register_ex(int win, struct display_ops *ops, void *v); extern int display_column_name(const char *line);
#define NAME_MAX 255 diff --git a/powerdebug.c b/powerdebug.c index cc9e871..0f15b38 100644 --- a/powerdebug.c +++ b/powerdebug.c @@ -27,6 +27,7 @@ #include "gpio.h" #include "mainloop.h" #include "powerdebug.h" +#include "utils.h"
void usage(void) { diff --git a/tree.c b/tree.c index d331c60..d4ada79 100644 --- a/tree.c +++ b/tree.c @@ -229,6 +229,34 @@ int tree_for_each(struct tree *tree, tree_cb_t cb, void *data) }
/* + * provide callbacks to allow external tree composers to be built without + * polluting this file with application specific code + */ +void get_tree_cbs(struct tree *(**alloc)(const char *path, int depth), + void (**add_child)(struct tree *parent, struct tree *child)) +{ + if ((alloc == NULL) || (add_child == NULL)) + return; + *alloc = tree_alloc; + *add_child = tree_add_child; +} + +/* same as above but pass an integer to each cb */ +int tree_for_each_ex(struct tree *tree, tree_cb_ex_t cb, void *data, int ix) +{ + if (!tree) + return 0; + + if (cb(tree, data, ix)) + return -1; + + if (tree_for_each_ex(tree->child, cb, data, ix)) + return -1; + + return tree_for_each_ex(tree->next, cb, data, ix); +} + +/* * This function will go over the tree passed as parameter at the reverse * order and will call the callback passed as parameter for each. * @tree : the lower node where we begin to browse the tree at the reverse diff --git a/tree.h b/tree.h index 5c1c697..9a6649c 100644 --- a/tree.h +++ b/tree.h @@ -11,7 +11,7 @@ * Author: * Daniel Lezcano daniel.lezcano@linaro.org * - *******************************************************************************/ + ******************************************************************************/
/* * Structure describing a node of the clock tree @@ -40,6 +40,7 @@ struct tree { typedef int (*tree_cb_t)(struct tree *t, void *data);
typedef int (*tree_filter_t)(const char *name); +typedef int (*tree_cb_ex_t)(struct tree *t, void *data, int ix);
extern struct tree *tree_load(const char *path, tree_filter_t filter, bool follow);
@@ -47,8 +48,16 @@ extern struct tree *tree_find(struct tree *tree, const char *name);
extern int tree_for_each(struct tree *tree, tree_cb_t cb, void *data);
+extern int tree_for_each_ex(struct tree *tree, + tree_cb_ex_t cb, + void *data, + int ix); + extern int tree_for_each_reverse(struct tree *tree, tree_cb_t cb, void *data);
extern int tree_for_each_parent(struct tree *tree, tree_cb_t cb, void *data);
extern int tree_finds(struct tree *tree, const char *name, struct tree ***ptr); + +void get_tree_cbs(struct tree *(**alloc)(const char *path, int depth), + void (**add_child)(struct tree *parent, struct tree *child)); diff --git a/tree_mgr.c b/tree_mgr.c new file mode 100644 index 0000000..9588a2a --- /dev/null +++ b/tree_mgr.c @@ -0,0 +1,197 @@ +/******************************************************************************* + * Copyright (C) 2012, Linaro Limited. + * + * This file is part of PowerDebug. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eric van Tassell + * - initial API and implementation + ******************************************************************************/ + +#define _GNU_SOURCE +#include <stdio.h> +#undef _GNU_SOURCE +#include <sys/types.h> +#include <stdbool.h> +#include <dirent.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <fcntl.h> +#include <sys/mman.h> +#include "display.h" +#include "tree_mgr.h" +#include "tree.h" +#include "utils.h" +#include "delimi.h" +#include "dirtree.h" +#include "regfield.h" + +static int tree_mgr_dump_cb(struct tree *t, void *data) +{ + int i; + if (t->depth == 0) + return 0; + + for (i = 1; i < t->depth; i++) + printf("\t"); + printf("%s\n", t->name); + if (t->private) { + struct field_def *f = (struct field_def *) t->private; + + for (i = 1; i < t->depth; i++) + printf("\t"); + if (f->decoder) + printf("\t0x%x(%s)\n", f->value, field_decode(f)); + else + printf("\t0x%x\n", f->value); + } + return 0; +} + +int tree_mgr_dump(struct tree_mgr *t) +{ + printf("%s", t->dump_header); + + return tree_for_each(t->tree, tree_mgr_dump_cb, NULL); +} + +static int tree_mgr_read_cb(struct tree *t, void *data) +{ + if (!t) + BAIL_OUT(("bad tree")); + + field_read((struct field_def *) t->private); + return 0; +} + +static int tree_mgr_fill_cb(struct tree *t, void *data) +{ + if (t->private) + return tree_mgr_read_cb(t, data); + else + return 0; +} + +#ifdef DEBUG_PARSE +static int tree_mgr_dump_debug_cb(struct tree *t, void *data) +{ + printf("%s: name = %s, depth = %d, private = %p, path = %s\n", + __func__, + t->name, + t->depth, + t->private, + t->path); + return 0; +} +#endif /* DEBUG_PARSE */ + +static int tree_mgr_fill_tree(struct tree_mgr *t) +{ + return tree_for_each(t->tree, tree_mgr_fill_cb, NULL); +} + +#ifdef DEBUG_PARSE +static int tree_mgr_debug_dump_tree(struct tree *t) +{ + return tree_for_each(t, tree_mgr_dump_debug_cb, NULL); +} +#endif /* DEBUG_PARSE */ + +static int tree_mgr_display_cb(struct tree *t, void *data, int ix) +{ + int *line = data; + char *buf; + int i; + struct field_def *f = (struct field_def *) t->private; + + if (t == NULL) + BAIL_OUT(("bad tree")); + if (t->private == NULL) + return 0; /* only display register fields */ + + if (f->decoder) + asprintf(&buf, "%25s %-8x(%s)", + t->path, f->value, field_decode(f)); + else + asprintf(&buf, "%25s %-8x", t->path, f->value); + display_print_line(ix, *line, buf, 1, t); + + (*line)++; + + return 0; +} + +static int tree_mgr_print_header(void) +{ + char *buf; + int ret; + + if (asprintf(&buf, "%-36s%s", "Name", "Value") < 0) + return -1; + + ret = display_column_name(buf); + + free(buf); + + return ret; +} + +static int tree_mgr_display(bool refresh, void *v) +{ + int ret, line = 0; + struct tree_mgr *tm = (struct tree_mgr *) v; + struct tree *t; + + if (!tm) + BAIL_OUT(("bad tree_mgr")); + t = tm->tree; + if (!t) + BAIL_OUT(("bad tree")); + + display_reset_cursor(tm->ix); + + tree_mgr_print_header(); + + ret = tree_for_each_ex(t, tree_mgr_display_cb, &line, tm->ix); + + display_refresh_pad(tm->ix); + + return ret; +} + +static struct display_ops tree_mgr_ops = { + .display_ex = tree_mgr_display, +}; + +struct tree_mgr *tree_mgr_new(int ix, char *hdr_str) +{ + struct tree_mgr *t = calloc(1, sizeof(struct tree_mgr)); + + if (!t) + BAIL_OUT(("failed to allocated struct tree_mgr")); + + t->tree = tree_load_file(get_cfg_file(ix)); + t->dump_header = hdr_str; + t->ix = ix; + +#ifdef DEBUG_PARSE + tree_mgr_debug_dump_tree(t->tree); +#endif /* DEBUG_PARSE */ + + if (!t->tree) + BAIL_OUT(("failed to allocate tree")); + + if (tree_mgr_fill_tree(t)) + return NULL; + + if (display_register_ex(ix, &tree_mgr_ops, (void *)t)) + BAIL_OUT(("display_register_ex failed")); + return t; +} + diff --git a/tree_mgr.h b/tree_mgr.h new file mode 100644 index 0000000..d692e1f --- /dev/null +++ b/tree_mgr.h @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (C) 2012, Linaro Limited. + * + * This file is part of PowerDebug. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eric van Tassell + * - initial API and implementation + ******************************************************************************/ + + +struct tree_mgr { + int ix; + struct tree *tree; + char *dump_header; +}; + +/* prototypes */ +struct tree_mgr *tree_mgr_new(int ix, char *hdr_str); +extern int tree_mgr_dump(struct tree_mgr *t); diff --git a/utils.c b/utils.c index 0e95f05..35a61a5 100644 --- a/utils.c +++ b/utils.c @@ -11,12 +11,17 @@ * Contributors: * Daniel Lezcano daniel.lezcano@linaro.org (IBM Corporation) * - initial API and implementation + * Eric van Tassell + * - minor additions *******************************************************************************/
#define _GNU_SOURCE #include <stdio.h> #undef _GNU_SOURCE #include <stdlib.h> +#include "utils.h" +#include "delimi.h" +#include "regfield.h"
/* * This functions is a helper to read a specific file content and store @@ -65,3 +70,56 @@ char *strchrnul(char *str, char delim) tmp = str + strlen(str) - 1; return tmp; } + +static char *get_omap4_config_file(int ix) +{ + switch (ix) { + case PWRDM: + return"pwrdm.regdefs.omap4"; + case VDD: + return"vdd.regdefs.omap4"; + default: + return NULL; + } +} + +static int is_omap4(void) +{ + uint32_t omap4_ids[] = { + 0x0B85202F, /* OMAP4430 ES1.0 */ + 0x1B85202F, /* OMAP4430 ES2.0 */ + 0x3B95C02F, /* OMAP4430 ES2.1 */ + 0x4B95C02F, /* OMAP4430 ES2.2 */ + 0x6B95C02F /* OMAP4430 ES2.3 */ + }; + + struct field_def omap4_id_code = { + .name = "ID_CODE", + .address = 0x4A002204, + .shift = 0, + .mask = 0xffffffff + }; + + uint32_t i; + + field_read(&omap4_id_code); + + for (i = 0; i < sizeof(omap4_ids) / sizeof(uint32_t); i++) { + if (omap4_ids[i] == omap4_id_code.value) + return 1; + } + return 0; +} + +char *get_cfg_file(int ix) +{ + char *ret = NULL; + + if (is_omap4()) + ret = get_omap4_config_file(ix); + else + BAIL_OUT(("unknown SOC, cannot determine config file")); + + printf("%s: ret = %s\n", __func__, ret); + return ret; +} diff --git a/utils.h b/utils.h index 581e20d..d4b7ece 100644 --- a/utils.h +++ b/utils.h @@ -15,6 +15,8 @@ #ifndef __UTILS_H #define __UTILS_H
+enum { CLOCK, REGULATOR, SENSOR, PWRDM, VDD, GPIO}; + #define BAIL_OUT(x) \ { \ printf x; \ @@ -29,4 +31,5 @@ extern int file_read_value(const char *path, const char *name, const char *format, void *value);
char *strchrnul(char *str, char delim); +char *get_cfg_file(int ix); #endif
From: Eric van Tassell <evt@evtM17x.(none)>
--- display.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/display.c b/display.c index fcb4ec1..c97b45d 100644 --- a/display.c +++ b/display.c @@ -65,6 +65,8 @@ struct windata windata[] = { [CLOCK] = { .name = "Clocks" }, [REGULATOR] = { .name = "Regulators" }, [SENSOR] = { .name = "Sensors" }, + [PWRDM] = { .name = "Pwrdms" }, + [VDD] = { .name = "Voltages" }, [GPIO] = { .name = "Gpio" }, };
@@ -116,12 +118,24 @@ static int display_show_footer(int win, char *string)
static int display_refresh(int win, bool read) { + struct display_ops *ops; /* we are trying to refresh a window which is not showed */ if (win != current_win) return 0;
- if (windata[win].ops && windata[win].ops->display) - return windata[win].ops->display(read); + ops = windata[win].ops; + + if (ops) { + if (ops->display) + return ops->display(read); + else + if (ops->display_ex) { + return ops->display_ex(read, + windata[win].pvdata); + } + else + return -1; + }
if (werase(main_win)) return -1; @@ -599,6 +613,7 @@ int display_register(int win, struct display_ops *ops) return -1;
windata[win].ops = ops; + windata[win].pvdata = NULL;
return 0; }
From: Eric van Tassell <evt@evtM17x.(none)>
--- powerdebug.c | 53 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 8 deletions(-)
diff --git a/powerdebug.c b/powerdebug.c index 0f15b38..6fe4b19 100644 --- a/powerdebug.c +++ b/powerdebug.c @@ -28,6 +28,10 @@ #include "mainloop.h" #include "powerdebug.h" #include "utils.h" +#include "tree_mgr.h" + +struct tree_mgr *pwrdm; +struct tree_mgr *vdd;
void usage(void) { @@ -38,6 +42,8 @@ void usage(void) printf("powerdebug [ -r | -s | -c ]\n"); printf(" -r, --regulator Show regulator information\n"); printf(" -s, --sensor Show sensor information\n"); + printf(" -P, --pwrdm Show power domain information\n"); + printf(" -V, --vdd Show voltage domain information\n"); printf(" -c, --clock Show clock information\n"); printf(" -p, --findparents Show all parents for a particular" " clock\n"); @@ -45,7 +51,7 @@ void usage(void) printf(" -d, --dump Dump information once (no refresh)\n"); printf(" -v, --verbose Verbose mode (use with -r and/or" " -s)\n"); - printf(" -V, --version Show Version\n"); + printf(" -i, --version Show Version\n"); printf(" -h, --help Help\n"); }
@@ -58,13 +64,15 @@ void version() * Options: * -r, --regulator : regulators * -s, --sensor : sensors + * -P, --pwrdm : pwrdm + * -V, --vdd : vdd * -c, --clock : clocks * -g, --gpio : gpios * -p, --findparents : clockname whose parents have to be found * -t, --time : ticktime * -d, --dump : dump * -v, --verbose : verbose - * -V, --version : version + * -i, --version : version * -h, --help : help * no option / default : show usage! */ @@ -72,13 +80,15 @@ void version() static struct option long_options[] = { { "regulator", 0, 0, 'r' }, { "sensor", 0, 0, 's' }, + { "pwrdm", 0, 0, 'P' }, + { "vdd", 0, 0, 'V' }, { "clock", 0, 0, 'c' }, { "gpio", 0, 0, 'g' }, { "findparents", 1, 0, 'p' }, { "time", 1, 0, 't' }, { "dump", 0, 0, 'd' }, { "verbose", 0, 0, 'v' }, - { "version", 0, 0, 'V' }, + { "version", 0, 0, 'i' }, { "help", 0, 0, 'h' }, { 0, 0, 0, 0 } }; @@ -87,6 +97,8 @@ struct powerdebug_options { bool verbose; bool regulators; bool sensors; + bool pwrdms; + bool vdds; bool clocks; bool gpios; bool dump; @@ -106,7 +118,7 @@ int getoptions(int argc, char *argv[], struct powerdebug_options *options) while (1) { int optindex = 0;
- c = getopt_long(argc, argv, "rscgp:t:dvVh", + c = getopt_long(argc, argv, "rsPcgp:t:dvVhi", long_options, &optindex); if (c == -1) break; @@ -120,6 +132,13 @@ int getoptions(int argc, char *argv[], struct powerdebug_options *options) options->sensors = true; options->selectedwindow = SENSOR; break; + case 'P': + options->pwrdms = true; + options->selectedwindow = PWRDM; + case 'V': + options->vdds = true; + options->selectedwindow = VDD; + break; case 'c': options->clocks = true; options->selectedwindow = CLOCK; @@ -146,7 +165,7 @@ int getoptions(int argc, char *argv[], struct powerdebug_options *options) case 'v': options->verbose = true; break; - case 'V': + case 'i': version(); break; case '?': @@ -159,9 +178,11 @@ int getoptions(int argc, char *argv[], struct powerdebug_options *options)
/* No system specified to be dump, let's default to all */ if (!options->regulators && !options->clocks && + !options->pwrdms && !options->vdds && !options->sensors && !options->gpios) - options->regulators = options->clocks = - options->sensors = options->gpios = true; + options->regulators = options->clocks = options->sensors + = options->pwrdms = options->vdds = options->gpios + = true;
if (options->selectedwindow == -1) options->selectedwindow = CLOCK; @@ -180,6 +201,12 @@ static int powerdebug_dump(struct powerdebug_options *options) if (options->sensors) sensor_dump();
+ if (options->pwrdms) + tree_mgr_dump(pwrdm); + + if (options->vdds) + tree_mgr_dump(vdd); + if (options->gpios) gpio_dump();
@@ -247,12 +274,22 @@ int main(int argc, char **argv) printf("failed to initialize sensors\n"); options->sensors = false; } + pwrdm = tree_mgr_new(PWRDM, "\nPower Domain Information:\n*******\n\n"); + if (!pwrdm) { + printf("failed to initialize pwrdms\n"); + options->pwrdms = false; + } + + vdd = tree_mgr_new(VDD, "\nVoltage Domain Information:\n*********\n\n"); + if (!vdd) { + printf("failed to initialize vdds\n"); + options->vdds = false; + }
if (gpio_init()) { printf("failed to initialize gpios\n"); options->gpios = false; } - ret = options->dump ? powerdebug_dump(options) : powerdebug_display(options);
From: Eric van Tassell <evt@evtM17x.(none)>
--- display.c | 1 - powerdebug.c | 6 +++--- tree_mgr.c | 6 ++++++ utils.c | 1 - 4 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/display.c b/display.c index c97b45d..2872ed5 100644 --- a/display.c +++ b/display.c @@ -624,6 +624,5 @@ int display_register_ex(int win, struct display_ops *ops, void *v) return -1;
windata[win].pvdata = v; - printf("%s: win = %d, v = %p\n", __func__, win, v); return 0; } diff --git a/powerdebug.c b/powerdebug.c index 6fe4b19..d292106 100644 --- a/powerdebug.c +++ b/powerdebug.c @@ -135,6 +135,7 @@ int getoptions(int argc, char *argv[], struct powerdebug_options *options) case 'P': options->pwrdms = true; options->selectedwindow = PWRDM; + break; case 'V': options->vdds = true; options->selectedwindow = VDD; @@ -183,7 +184,6 @@ int getoptions(int argc, char *argv[], struct powerdebug_options *options) options->regulators = options->clocks = options->sensors = options->pwrdms = options->vdds = options->gpios = true; - if (options->selectedwindow == -1) options->selectedwindow = CLOCK;
@@ -274,13 +274,13 @@ int main(int argc, char **argv) printf("failed to initialize sensors\n"); options->sensors = false; } - pwrdm = tree_mgr_new(PWRDM, "\nPower Domain Information:\n*******\n\n"); + pwrdm = tree_mgr_new(PWRDM, "Power Domain Information:"); if (!pwrdm) { printf("failed to initialize pwrdms\n"); options->pwrdms = false; }
- vdd = tree_mgr_new(VDD, "\nVoltage Domain Information:\n*********\n\n"); + vdd = tree_mgr_new(VDD, "Voltage Domain Information:"); if (!vdd) { printf("failed to initialize vdds\n"); options->vdds = false; diff --git a/tree_mgr.c b/tree_mgr.c index 9588a2a..be8e682 100644 --- a/tree_mgr.c +++ b/tree_mgr.c @@ -31,6 +31,7 @@ #include "delimi.h" #include "dirtree.h" #include "regfield.h" +#define MIN(a, b) ((a) < (b) ? (a) : (b))
static int tree_mgr_dump_cb(struct tree *t, void *data) { @@ -56,8 +57,13 @@ static int tree_mgr_dump_cb(struct tree *t, void *data)
int tree_mgr_dump(struct tree_mgr *t) { + char buf[80]; printf("%s", t->dump_header);
+ memset(buf, 0, 80); + memset(buf, '*', MIN(80, strlen(t->dump_header))); + printf("\n%s\n\n", buf); + return tree_for_each(t->tree, tree_mgr_dump_cb, NULL); }
diff --git a/utils.c b/utils.c index 35a61a5..8321603 100644 --- a/utils.c +++ b/utils.c @@ -120,6 +120,5 @@ char *get_cfg_file(int ix) else BAIL_OUT(("unknown SOC, cannot determine config file"));
- printf("%s: ret = %s\n", __func__, ret); return ret; }