From e1e5e67f8941791cbd0e6604c8897d73090bb268 Mon Sep 17 00:00:00 2001 From: Eric van Tassell Date: Mon, 16 Apr 2012 19:11:21 -0500 Subject: [PATCH] add power domain and voltage domain support --- Android.mk | 5 +- Makefile | 8 +- README | 20 +++- clocks.c | 1 - delimi.c | 105 +++++++++++++++++++ delimi.h | 31 ++++++ dirtree.c | 146 ++++++++++++++++++++++++++ dirtree.h | 19 ++++ display.c | 38 +++++-- display.h | 4 +- gpio.c | 2 - mmioreg.c | 72 +++++++++++++ mmioreg.h | 26 +++++ powerdebug.c | 52 ++++++++-- powerdebug.h | 1 + pwrdm.regdefs.omap4 | 33 ++++++ regfield.c | 285 +++++++++++++++++++++++++++++++++++++++++++++++++++ regfield.h | 53 ++++++++++ regulator.c | 3 +- sensor.c | 3 +- sensor.h | 2 +- tree.c | 28 +++++ tree.h | 8 ++ tree_mgr.c | 193 ++++++++++++++++++++++++++++++++++ tree_mgr.h | 25 +++++ utils.c | 69 +++++++++++++ utils.h | 19 +++- vdd.regdefs.omap4 | 68 ++++++++++++ 28 files changed, 1287 insertions(+), 32 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 diff --git a/Android.mk b/Android.mk index e062c1c..8600787 100644 --- a/Android.mk +++ b/Android.mk @@ -28,7 +28,8 @@ 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 + gpio.c powerdebug.c sensor.c clocks.c regulator.c \ + display.c tree.c utils.c mainloop.c tree_mgr.c delimi.c \ + dirtree.c mmioreg.c regfield.c include $(BUILD_EXECUTABLE) diff --git a/Makefile b/Makefile index 2da9d67..1a3875a 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,11 @@ BINDIR=/usr/sbin MANDIR=/usr/share/man/man8 -CFLAGS?=-O1 -g -Wall -Wshadow -CC?=gcc +CFLAGS=-O1 -g -Wall -Wshadow -I /home/evt/wrk/linaro/android.panda.tilt.255/prebuilt/linux-x86/toolchain/i686-linux-glibc2.7-4.4.3/sysroot -I /usr/include -I spankme +CC?="$TARGET_TOOLS_PREFIX"gcc -OBJS = powerdebug.o sensor.o clocks.o regulator.o gpio.o \ - display.o tree.o utils.o mainloop.o +OBJS = gpio.o powerdebug.o sensor.o clocks.o regulator.o display.o tree.o utils.o mainloop.o +OBJS += delimi.o dirtree.o mmioreg.o regfield.o tree_mgr.o default: powerdebug diff --git a/README b/README index fa997f6..ebe052f 100644 --- a/README +++ b/README @@ -7,4 +7,22 @@ information. Current version only displays regulator information and clock tree from debugfs. Support will be added for sensors later. - -- Amit Arora Fri, 08 Sep 2010 +configuration files for power and voltage domains: +-------------------------------------------------- + ++ each non comment line begins with one of {decoder, push, pop, field} + ++ fields are separated by commas and whitespace + ++ decoder lines have a name and a list of values. As an example: + decoder, 7dwarves, sleepy, sneezy, doc, happy, bashful, dopey, grumpy + + the name of the decoder is "7dwarves" + + a value of 2 in a field specifying this decoder would decode to "doc" + ++ push lines have a "path" and exist so you can group registers in a heirarchy + ++ pop is the inverse of push(duh) + ++ fields have name, address-in-hex, shift, mask, and optionally a decoder diff --git a/clocks.c b/clocks.c index 2611a0d..c96125a 100644 --- a/clocks.c +++ b/clocks.c @@ -30,7 +30,6 @@ #include #include -#include "powerdebug.h" #include "display.h" #include "clocks.h" #include "tree.h" diff --git a/delimi.c b/delimi.c new file mode 100644 index 0000000..060280b --- /dev/null +++ b/delimi.c @@ -0,0 +1,105 @@ +/******************************************************************************* + * 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 +#undef _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include "display.h" +#include "utils.h" +#include "delimi.h" + +delim_iterator_t *delimi_new(char *buf, char delim) +{ + char *p; + delim_iterator_t *delimi; + + delimi = (delim_iterator_t *) calloc(1, sizeof(delim_iterator_t)); + 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(delim_iterator_t *delimi) +{ + if (!delimi) + return; + if (delimi->str) + free(delimi->str); + free(delimi); +} + +void delimi_next(delim_iterator_t *delimi) +{ + if (*(delimi->val_end + 1) == '\0') { + delimi->val = delimi->val_end = delimi->val_end + 1; // we saw delimi->val_end = "last-value\0" + } + else { + delimi->val = delimi->val_end + 2; // saw "x,value1,value2,..." + delimi->val_end = strchrnul(delimi->val, delimi->delim); + if (*(delimi->val_end) == delimi->delim) + delimi->val_end--; + } +} + +int delimi_empty(delim_iterator_t *delimi) +{ + return (delimi->val == delimi->val_end); +} + +#ifdef DEBUG_PARSE +void delimi_show(delim_iterator_t *delimi) +{ + printf("%s:\n\tstr = %s\n\tval = %s\n\tval_end = %s\n\tempty = %s\n", + __FUNCTION__, + 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(delim_iterator_t *delimi) +{ + char *tmp; + + if (!delimi) + BAIL_OUT(("NULL delim_iterator_t *")); + + 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..0c92c49 --- /dev/null +++ b/delimi.h @@ -0,0 +1,31 @@ +/******************************************************************************* + * 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 + *******************************************************************************/ + +typedef struct delim_iterator { + char *str; + char *val; + char *val_end; + char delim; +} delim_iterator_t; + +// prototypes for exported functions +void delimi_next(delim_iterator_t *delimi); +int delimi_empty(delim_iterator_t *delimi); +char *delimi_aget_val(delim_iterator_t *delimi); +#ifdef DEBUG_PARSE +void delimi_show(delim_iterator_t *delimi); +#endif +delim_iterator_t *delimi_new(char *buf, char delim); +void delimi_free(delim_iterator_t *delimi); diff --git a/dirtree.c b/dirtree.c new file mode 100644 index 0000000..42eef8d --- /dev/null +++ b/dirtree.c @@ -0,0 +1,146 @@ +/******************************************************************************* + * 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 +#undef _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#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); + delim_iterator_t *delimi; + parser_ctl_t *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 *")); + + //printf("%s:%s", __FUNCTION__, buf); + + if (!strncmp(buf, "push", strlen("push"))) { + char path[MAX_LINE_LENGTH]; + + if (sp == MAX_TREE_DEPTH -1) { + printf("illegal 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); + //printf("\t+++ push:%s\n", new_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 pop - cant pop the root node\n"); + exit(0); + } + sp--; + //printf("\t+++ pop:%s\n", node_stack[sp]->path); + } + else { + int i; + int parser_found = 0; + + for (i = 0; i < parser_ctl->num_parsers; i++) { + if (!strncmp(buf, + parser_ctl->descriptors[i].verb, + strlen(parser_ctl->descriptors[i].verb))) { + void *pvdata; + char *name; + + parser_found = 1; + pvdata = (parser_ctl->descriptors[i].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(("failed to allocate node")); + + node->private = pvdata; + add_child(node_stack[sp], node); + } + break; + } + } + if (!parser_found) + BAIL_OUT(("ERROR: 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..59a4eb7 --- /dev/null +++ b/dirtree.h @@ -0,0 +1,19 @@ +/******************************************************************************* + * 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 + *******************************************************************************/ + +typedef void (*p_parser)(delim_iterator_t *, char **); + +// prototypes +struct tree *tree_load_file(const char *cfg_file_path); diff --git a/display.c b/display.c index f06387c..0d23449 100644 --- a/display.c +++ b/display.c @@ -20,6 +20,7 @@ #include #include #include +#include "utils.h" #include "powerdebug.h" #include "mainloop.h" #include "regulator.h" @@ -51,7 +52,9 @@ struct rowdata { struct windata { WINDOW *pad; struct display_ops *ops; + struct display_ops_ex *ops_ex; struct rowdata *rowdata; + void *pvdata; char *name; int nrdata; int scrolling; @@ -63,6 +66,8 @@ struct windata windata[] = { [CLOCK] = { .name = "Clocks" }, [REGULATOR] = { .name = "Regulators" }, [SENSOR] = { .name = "Sensors" }, + [PWRDM] = { .name = "Pwrdms" }, + [VDD] = { .name = "Voltages" }, [GPIO] = { .name = "Gpio" }, }; @@ -84,7 +89,7 @@ static int display_show_header(int win) mvwprintw(header_win, 0, curr_pointer, "PowerDebug %s", VERSION); curr_pointer += 20; - for (i = 0; i < array_size; i++) { + for (i = 0; (size_t)i < array_size; i++) { if (win == i) wattron(header_win, A_REVERSE); else @@ -118,8 +123,16 @@ static int display_refresh(int win, bool read) if (win != current_win) return 0; - if (windata[win].ops && windata[win].ops->display) - return windata[win].ops->display(read); + if (windata[win].ops) { + if (windata[win].ops->display) + return windata[win].ops->display(read); + else + if (windata[win].ops->display_ex) { + return windata[win].ops->display_ex(read, windata[win].pvdata); + } + else + return -1; + } if (werase(main_win)) return -1; @@ -533,7 +546,7 @@ int display_init(int wdefault) cbreak(); curs_set(0); nonl(); - +/* FIXME: WHY DOES THIS BREAK ?????? if (init_pair(PT_COLOR_DEFAULT, COLOR_WHITE, COLOR_BLACK) || init_pair(PT_COLOR_ERROR, COLOR_BLACK, COLOR_RED) || init_pair(PT_COLOR_HEADER_BAR, COLOR_WHITE, COLOR_BLACK) || @@ -543,13 +556,13 @@ int display_init(int wdefault) init_pair(PT_COLOR_BLUE, COLOR_WHITE, COLOR_BLUE) || init_pair(PT_COLOR_RED, COLOR_WHITE, COLOR_RED)) return -1; - +*/ if (atexit(display_fini)) return -1; getmaxyx(stdscr, maxy, maxx); - for (i = 0; i < array_size; i++) { + for (i = 0; (size_t)i < array_size; i++) { main_win = subwin(stdscr, maxy - 2, maxx, 1, 0); if (!main_win) @@ -593,10 +606,21 @@ int display_register(int win, struct display_ops *ops) { size_t array_size = sizeof(windata) / sizeof(windata[0]); - if (win < 0 || win >= array_size) + if (win < 0 || (size_t)win >= array_size) return -1; windata[win].ops = ops; + windata[win].pvdata = NULL; + + 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", __FUNCTION__, 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/gpio.c b/gpio.c index f7d2a10..586d621 100644 --- a/gpio.c +++ b/gpio.c @@ -25,8 +25,6 @@ #include #include #include - -#include "powerdebug.h" #include "display.h" #include "tree.h" #include "utils.h" diff --git a/mmioreg.c b/mmioreg.c new file mode 100644 index 0000000..6ce9b8e --- /dev/null +++ b/mmioreg.c @@ -0,0 +1,72 @@ +/******************************************************************************* + * 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 +#undef _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include "utils.h" +#include "delimi.h" +#include "mmioreg.h" + +memobj_t devmem = { + .path = "/dev/mem", + .fd = -1, + .map_base = NULL, + .last_map_req = 0, + .map_size = 4096, + .map_mask = 4096 - 1 +}; + +void memobj_open(memobj_t *m) +{ + if ((m->fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) + BAIL_OUT(("%s: failed to open %s\n", __FUNCTION__, m->path)); +} + +uint32_t memobj_readu32(memobj_t *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))); + //printf("%s:ret(0x%x) = 0x%x\n", __FUNCTION__, addr, ret); + return ret; +} + +static void memobj_close(memobj_t *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..e602be0 --- /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 + *******************************************************************************/ + +typedef struct memobj { + char *path; + int fd; + void *map_base; + uint32_t last_map_req; + unsigned long map_size; + unsigned long map_mask; +} memobj_t; + +//prototypes +uint32_t memobj_readu32(memobj_t *m, uint32_t addr); diff --git a/powerdebug.c b/powerdebug.c index cc9e871..dbc4fe1 100644 --- a/powerdebug.c +++ b/powerdebug.c @@ -20,14 +20,19 @@ #include #include #include +#include "utils.h" #include "regulator.h" #include "display.h" #include "clocks.h" #include "sensor.h" +#include "tree_mgr.h" #include "gpio.h" #include "mainloop.h" #include "powerdebug.h" +tree_mgr_t *pwrdm = NULL; +tree_mgr_t *vdd = NULL; + void usage(void) { printf("Usage: powerdebug [OPTIONS]\n"); @@ -37,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"); @@ -44,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"); } @@ -57,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! */ @@ -71,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 } }; @@ -86,6 +97,8 @@ struct powerdebug_options { bool verbose; bool regulators; bool sensors; + bool pwrdms; + bool vdds; bool clocks; bool gpios; bool dump; @@ -105,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; @@ -119,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; @@ -145,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 '?': @@ -158,9 +178,10 @@ 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->sensors = options->pwrdms = options->vdds =options->gpios = true; if (options->selectedwindow == -1) options->selectedwindow = CLOCK; @@ -179,6 +200,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,11 +274,22 @@ int main(int argc, char **argv) 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); diff --git a/powerdebug.h b/powerdebug.h index 09d3c1e..438f26c 100644 --- a/powerdebug.h +++ b/powerdebug.h @@ -14,3 +14,4 @@ *******************************************************************************/ #define VERSION "0.6.1" + 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/regfield.c b/regfield.c new file mode 100644 index 0000000..c098822 --- /dev/null +++ b/regfield.c @@ -0,0 +1,285 @@ +/******************************************************************************* + * 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 +#undef _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include "utils.h" +#include "delimi.h" +#include "regfield.h" +#include "mmioreg.h" + +static decoder_t *decoder_new(char *name) +{ + decoder_t *d = (decoder_t *)calloc(1, sizeof(decoder_t)); + + if (!d) + return NULL; + + d->name = name; + d->values = NULL; + d->num_values = 0; + + return d; +} + +#ifdef DEBUG_PARSE +static void decoder_show(decoder_t *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 // #if DEBUG_PARSE + +static void decoder_free(decoder_t *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(decoder_t *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 field_def_t *field_new(char *name) +{ + field_def_t *f = (field_def_t *)calloc(1, sizeof(field_def_t)); + + if (!f) + return NULL; + + f->name = name; + return f; +} + +static void field_show(field_def_t *f) +{ + if (!f) + return; + printf("%s\n", __FUNCTION__); + 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 +} + +decoder_ctl_t decoder_ctl; + +char *field_decode(field_def_t *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(field_def_t *f) +{ + extern memobj_t devmem; + + f->value = memobj_readu32(&devmem, f->address); + f->value = (f->value >> f->shift) & f->mask; +} + +#ifdef DEBUG_PARSE +static void decoder_ctl_show(decoder_ctl_t *dc) +{ + int i; + + for (i = 0; i < dc->num_decoders; i++) +#ifdef DEBUG_PARSE + decoder_show(dc->decoders[i]); +#endif +} +#endif // DEBUG_PARSE + +static decoder_t *decoder_ctl_lookup_decoder(decoder_ctl_t *dc, char *name) +{ + int i; + + if (!name) + return NULL; + + //printf("%s: name = %s(%p)<%d>\n", __FUNCTION__, name, name, strlen(name)); + + 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(decoder_ctl_t *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(decoder_ctl_t *dc, decoder_t *d) +{ + + decoder_t **tmp; + + tmp = realloc(dc->decoders, (dc->num_decoders + 1) * sizeof(decoder_t *)); + if (tmp == NULL) + return 0; + //printf("%s:adding decoder %s\n", __FUNCTION__, d->name); + dc->decoders = tmp; + dc->decoders[dc->num_decoders] = d; + dc->num_decoders++; + return 1; +} + +void *parse_decoder(delim_iterator_t *delimi, char **name) +{ + decoder_t *decoder; + + delimi_next(delimi); // skip the first word, we already know it's "decoder" + + 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(delim_iterator_t *delimi, char **name) +{ + char *verb, *fldname, *decoder_name; + field_def_t *f; + unsigned int address; + int shift, mask; + char *tmp; + + delimi_next(delimi);// skip the first word, we already know it's "field" + + 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 parser_descriptor_t parser_descriptors[2] = { + { + .verb = "field", + .parser = parse_field, + }, + { + .verb = "decoder", + .parser = parse_decoder, + }, +}; + + +parser_ctl_t regfield_parsers = { + .num_parsers = sizeof(parser_descriptors) / sizeof(parser_descriptor_t), + .descriptors = parser_descriptors +}; diff --git a/regfield.h b/regfield.h new file mode 100644 index 0000000..682173a --- /dev/null +++ b/regfield.h @@ -0,0 +1,53 @@ +/******************************************************************************* + * 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 + *******************************************************************************/ + +typedef struct parser_descriptor { + char *verb; + void *(*parser)(delim_iterator_t *delimi, char **); +} parser_descriptor_t; + +typedef struct parser_ctl { + int num_parsers; + parser_descriptor_t *descriptors; +} parser_ctl_t; + +typedef struct decoder { + char *name; + char **values; + unsigned char num_values; +} decoder_t; + +typedef struct decoder_ctl { + decoder_t **decoders; + unsigned char num_decoders; +} decoder_ctl_t; + +typedef struct { + char *name; + unsigned int address; + unsigned int shift; + unsigned int mask; + decoder_t *decoder; + uint32_t value; +} field_def_t; + +// shared daa +extern parser_ctl_t regfield_parsers; + +// prototypes +char *field_decode(field_def_t *f); +void field_read(field_def_t *f); +void *parse_field(delim_iterator_t *delimi, char **name); +void *parse_decoder(delim_iterator_t *delimi, char **name); diff --git a/regulator.c b/regulator.c index 55bd3e9..b1d5e87 100644 --- a/regulator.c +++ b/regulator.c @@ -19,6 +19,7 @@ #define SYSFS_REGULATOR "/sys/class/regulator" #define VALUE_MAX 16 +#define DO_TRACE_ME_GOOBER 0 #define _GNU_SOURCE #include @@ -29,7 +30,6 @@ #include #include #include "display.h" -#include "powerdebug.h" #include "tree.h" #include "utils.h" @@ -213,6 +213,7 @@ static int fill_regulator_cb(struct tree *t, void *data) { struct regulator_info *reg; + reg = regulator_alloc(); if (!reg) return -1; diff --git a/sensor.c b/sensor.c index bd8c354..989f371 100644 --- a/sensor.c +++ b/sensor.c @@ -21,10 +21,9 @@ #include #include #include - -#include "powerdebug.h" #include "display.h" #include "sensor.h" +#include "tree_mgr.h" #include "tree.h" #include "utils.h" diff --git a/sensor.h b/sensor.h index 0a069ce..d10b18a 100644 --- a/sensor.h +++ b/sensor.h @@ -13,5 +13,5 @@ * - initial API and implementation *******************************************************************************/ -extern int sensor_dump(void); +extern int sensor_dump(void); // FIXME_GOOBER extern int sensor_init(void); diff --git a/tree.c b/tree.c index d331c60..3a48e93 100644 --- a/tree.c +++ b/tree.c @@ -208,6 +208,19 @@ struct tree *tree_load(const char *path, tree_filter_t filter, bool follow) } /* + * 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; +} + +/* * This function will go over the tree passed as parameter and * will call the callback passed as parameter for each node. * @@ -228,6 +241,21 @@ int tree_for_each(struct tree *tree, tree_cb_t cb, void *data) return tree_for_each(tree->next, cb, data); } +/* 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. diff --git a/tree.h b/tree.h index 5c1c697..9efb92a 100644 --- a/tree.h +++ b/tree.h @@ -39,6 +39,8 @@ struct tree { typedef int (*tree_cb_t)(struct tree *t, void *data); +typedef int (*tree_cb_ex_t)(struct tree *t, void *data, int ix); + typedef int (*tree_filter_t)(const char *name); extern struct tree *tree_load(const char *path, tree_filter_t filter, bool follow); @@ -47,8 +49,14 @@ 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)); +#define MAX_TREE_DEPTH 8 +#define MAX_LINE_LENGTH 255 diff --git a/tree_mgr.c b/tree_mgr.c new file mode 100644 index 0000000..a7dd28a --- /dev/null +++ b/tree_mgr.c @@ -0,0 +1,193 @@ +/******************************************************************************* + * 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 +#undef _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#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) { + field_def_t *f = (field_def_t *) 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(tree_mgr_t *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((field_def_t *) t->private); + return 0; +} + +static int tree_mgr_fill_cb(struct tree *t, void *data) +{ + //printf("%s: name = %s, depth = %d\n", __FUNCTION__, t->name, t->depth); + 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", __FUNCTION__, t->name, t->depth, t->private, t->path); + return 0; +} +#endif // DEBUG_PARSE + +static int tree_mgr_fill_tree(tree_mgr_t *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; + field_def_t *f = (field_def_t *) 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; + tree_mgr_t *tm = (tree_mgr_t *) 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, +}; + +tree_mgr_t *tree_mgr_new(int ix, char *hdr_str) +{ + tree_mgr_t *t = calloc(1, sizeof(tree_mgr_t)); + + if (!t) + BAIL_OUT(("failed to allocated tree_mgr_t")); + + 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..9c1f5a0 --- /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 + *******************************************************************************/ + + +typedef struct { + int ix; + struct tree *tree; + char *dump_header; +} tree_mgr_t; + +// prototypes +tree_mgr_t *tree_mgr_new(int ix, char *hdr_str); +extern int tree_mgr_dump(tree_mgr_t *t); diff --git a/utils.c b/utils.c index e47c58e..0db37d3 100644 --- a/utils.c +++ b/utils.c @@ -11,12 +11,17 @@ * Contributors: * Daniel Lezcano (IBM Corporation) * - initial API and implementation + * Eric van Tassell + * - minor additions *******************************************************************************/ #define _GNU_SOURCE #include #undef _GNU_SOURCE #include +#include "delimi.h" +#include "utils.h" +#include "regfield.h" /* * This functions is a helper to read a specific file content and store @@ -53,3 +58,67 @@ out_free: free(rpath); return ret; } + +char *strchrnul(char *str, char delim) +{ + // bionic lacks this + char *tmp; + + tmp = strchr(str, delim); + + if (tmp == NULL) + tmp = str + strlen(str) - 1; + return(tmp); +} + +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 + }; + + field_def_t 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; +} + +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; + } +} + +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 power domain config file"));; + + printf("%s: ret = %s\n", __FUNCTION__, ret); + return ret; +} + diff --git a/utils.h b/utils.h index d4ac65a..0d292e3 100644 --- a/utils.h +++ b/utils.h @@ -15,8 +15,23 @@ #ifndef __UTILS_H #define __UTILS_H -extern int file_read_value(const char *path, const char *name, - const char *format, void *value); +#define TRACE_ME(x) {if (x) printf("\n\tGOOBER: %s:%s @ %d\n", __FILE__, __FUNCTION__, __LINE__);} +#define BAIL_OUT(x) \ + { \ + printf x; \ + printf("%s@%d:BAILING OUT HERE:\n", __FUNCTION__, __LINE__); \ + exit(0); \ +} + +#define DBG_PR(x) {printf("%s:",__FUNCTION__);printf x;} +#undef DEBUG_PARSE +enum { CLOCK, REGULATOR, SENSOR, PWRDM, VDD, GPIO }; +// prototypes +extern int file_read_value(const char *path, const char *name, + const char *format, void *value); +char *strchrnul(char *str, char delim); +int is_omap4(void); +char *get_cfg_file(int ix); #endif diff --git a/vdd.regdefs.omap4 b/vdd.regdefs.omap4 new file mode 100644 index 0000000..cbca771 --- /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, TIMEOUEN, 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, TIMEOUEN, 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, TIMEOUEN, 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 -- 1.7.9.5