Edward O'Callaghan (eocallaghan@alterapraxis.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/6762
-gerrit
commit b89610fcfd0c976a96a4e3aa1cd014da1c7cfbf4 Author: Edward O'Callaghan eocallaghan@alterapraxis.com Date: Tue Aug 26 00:12:03 2014 +1000
util/intelgpio: Handy tool to build gpio.h from dumped values
This purpose of this tool is to build the 'gpio.h' header from dumped values out of the inteltool.
Change-Id: I2812a3546849347567efe71c714fefe39e02e5d7 Signed-off-by: Edward O'Callaghan eocallaghan@alterapraxis.com --- .gitignore | 1 + util/intelgpio/Makefile | 47 ++++++++ util/intelgpio/dump_parse.c | 81 ++++++++++++++ util/intelgpio/intelgpio.c | 259 ++++++++++++++++++++++++++++++++++++++++++++ util/intelgpio/intelgpio.h | 52 +++++++++ 5 files changed, 440 insertions(+)
diff --git a/.gitignore b/.gitignore index 203ad9a..0a05520 100644 --- a/.gitignore +++ b/.gitignore @@ -71,6 +71,7 @@ util/ifdtool/ifdtool util/ifdfake/ifdfake util/inteltool/.dependencies util/inteltool/inteltool +util/intelgpio/intelgpio util/k8resdump/k8resdump util/lbtdump/lbtdump util/mptable/mptable diff --git a/util/intelgpio/Makefile b/util/intelgpio/Makefile new file mode 100644 index 0000000..b09bca9 --- /dev/null +++ b/util/intelgpio/Makefile @@ -0,0 +1,47 @@ +# +# Makefile for intelgpio utility +# +# Copyright (C) 2014 Edward O'Callaghan eocallaghan@alterapraxis.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +PROGRAM = intelgpio + +CC ?= clang +INSTALL ?= /usr/bin/install +PREFIX ?= /usr/local +CFLAGS ?= -O2 -g -Wall -W +LDFLAGS += + +OBJS = intelgpio.o dump_parse.o + +all: $(PROGRAM) + +$(PROGRAM): $(OBJS) + $(CC) $(CFLAGS) -o $(PROGRAM) $(OBJS) $(LDFLAGS) + +clean: + rm -f $(PROGRAM) *.o *~ + +install: $(PROGRAM) + mkdir -p $(DESTDIR)$(PREFIX)/sbin + $(INSTALL) $(PROGRAM) $(DESTDIR)$(PREFIX)/sbin + mkdir -p $(DESTDIR)$(PREFIX)/share/man/man8 + $(INSTALL) -p -m644 $(PROGRAM).8 $(DESTDIR)$(PREFIX)/share/man/man8 + +.PHONY: all clean + +-include .dependencies diff --git a/util/intelgpio/dump_parse.c b/util/intelgpio/dump_parse.c new file mode 100644 index 0000000..ecac9f7 --- /dev/null +++ b/util/intelgpio/dump_parse.c @@ -0,0 +1,81 @@ +/* + * inteltool - Prepare gpio.h file from register dumps from inteltool. + * + * Copyright (C) 2014 Edward O'Callaghan eocallaghan@alterapraxis.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> + +#include "intelgpio.h" + +/** + * Parse a line out of a inteltool dump, NULL is returned when a line could + * not be parsed. + */ +static struct dump_tuple * parse_line(char * line) +{ + struct dump_tuple * row = NULL; + uint32_t addr, val; + + /* tokenizes line */ + if (sscanf(line, "0x%04x:", &addr) != 1) + return NULL; // if no address could be read + if (sscanf(line, "0x%08x", &val) != 1) + return NULL; // if no value could be read + + row = (struct dump_tuple *) malloc(sizeof(struct dump_tuple)); + row->address = addr; + row->registers = val; + row->next = NULL; + + return row; +} + +/** + * Returns a linked list of each row of the dump where each node is type + * struct dump_tuple. + */ +struct dump_tuple * process_stdin(FILE *fp) +{ + struct dump_tuple * head = NULL, * node = NULL; + char * line = NULL; + size_t len = 0; + + if (fp == NULL) + return NULL; + + while (getline(&line, &len, fp) != -1) { + if (head == NULL) { + head = parse_line(line); + node = head; + } + else { + node->next = parse_line(line); + node = node->next; + } + if (node == NULL) { + fprintf(stderr, "dump malformed!\n"); + exit(1); // FIXME: memory leak here, free-up linked-list ! + } + } + + if (line) + free(line); + + return head; +} diff --git a/util/intelgpio/intelgpio.c b/util/intelgpio/intelgpio.c new file mode 100644 index 0000000..53178fa --- /dev/null +++ b/util/intelgpio/intelgpio.c @@ -0,0 +1,259 @@ +/* + * inteltool - Prepare gpio.h file from register dumps from inteltool. + * + * Copyright (C) 2014 Edward O'Callaghan eocallaghan@alterapraxis.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define INTELGPIO_VERSION "0.1" + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <getopt.h> + +#include "intelgpio.h" + +static const __attribute__((unused)) char *mode[] = {"MODE_NATIVE", "MODE_GPIO", "mode"}; +static const __attribute__((unused)) char *dir[] = {"DIR_OUTPUT", "DIR_INPUT", "direction"}; +static const __attribute__((unused)) char *invert[] = {"NO_INVERT", "GPIO_INVERT", "invert"}; +static const __attribute__((unused)) char *level[] = {"LEVEL_LOW", "LEVEL_HIGH", "level"}; +static const __attribute__((unused)) char *blink[] = {"NO_BLINK", "BLINK", "blink"}; +static const __attribute__((unused)) char *reset[] = {"RESET_PWROK", "RESET_RSMRST", "reset"}; + +static void print_version(void) +{ + printf("intelgpio v%s -- ", INTELGPIO_VERSION); + printf("Copyright (C) 2014 Edward O'Callaghan\n\n"); + printf( + "This program is free software: you can redistribute it and/or modify\n" + "it under the terms of the GNU General Public License as published by\n" + "the Free Software Foundation, version 2 of the License.\n\n" + "This program is distributed in the hope that it will be useful,\n" + "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + "GNU General Public License for more details.\n\n" + "You should have received a copy of the GNU General Public License\n" + "along with this program. If not, see http://www.gnu.org/licenses/.\n\n"); +} + +static void print_usage(const char *name) +{ + printf("usage: %s [-vh?sdmlia]\n", name); + printf("\n" + " -v | --version: print the version\n" + " -h | --help: print this help\n\n" + " -b | --boardname= name of mainboard\n" + " -s | --set= GPIO register set\n" + " -d | --direction= direction val\n" + " -m | --mode= mode val\n" + " -l | --level= level val\n" + " -i | --invert= invert val\n" + " -a | --all: all register sets 1,2,3\n" + "\n"); + exit(1); +} + +static void build_structs(const char *boardname) +{ + unsigned int set; + + for (set = 1; set < 4; set++) { + printf("const struct pch_gpio_map %s_gpio_map = {\n", boardname); + printf("\t.set%i = {\n", set); + printf("\t\t.mode\t\t= &pch_gpio_set%i_mode,\n", set); + printf("\t\t.direction\t= &pch_gpio_set%i_direction,\n", set); + printf("\t\t.level\t\t= &pch_gpio_set%i_level,\n", set); + if (set == 1) + printf("\t\t.invert\t\t= &pch_gpio_set%i_invert,\n", set); + printf("\t},\n"); + printf("};\n\n"); + } +} + +static void print_gpio_config(const char *type[], uint8_t set, uint32_t gpioval) { + unsigned int i; + uint8_t pin; +// char pin_flag; + + printf("const struct pch_gpio_set%i pch_gpio_set%i_%s = {\n", set, set, type[2]); + for (i = 0; i < 32; i++) { + pin = ((set - 1) * 32 + i); +// pin_flag = (pin < 10 ? ' ': '\0'); +// printf("\t.gpio%i%c = GPIO_%s,\n", pin, pin_flag + printf("\t.gpio%i = GPIO_%s,\n", pin + , type[(gpioval >> i) & 1]); + } + printf("};\n\n"); +} + +// TODO write to file.. or keep as stdout??? +static void write_gpio_header(uint8_t set, uint32_t mv, uint32_t dv, uint32_t lv, uint32_t iv) +{ + // TODO: check bounds on mode, dir, level & invert for sane values?? + print_gpio_config(mode, set, mv); + print_gpio_config(dir, set, dv); + print_gpio_config(level, set, lv); + if (set == 1) + print_gpio_config(invert, set, iv); +} + +static void build_header(struct dump_tuple * head, char * board_name) +{ + struct dump_tuple * node = head, * prev = NULL; + uint32_t direction1 = 0, mode1 = 0, level1 = 0, invert = 0; + uint32_t direction2 = 0, mode2 = 0, level2 = 0; + uint32_t direction3 = 0, mode3 = 0, level3 = 0; + uint32_t blink = 0; + + if (board_name != NULL) { + printf("#ifndef %s_GPIO_H\n", board_name); + printf("#define %s_GPIO_H\n\n", board_name); + } else { + printf("#ifndef GENERIC_GPIO_H\n"); + printf("#define GENERIC_GPIO_H\n\n"); + } + +// FIXME: convert switch to const array map for lookups. + while (node != NULL) { + switch(node->address) { + case GPIO_USE_SEL: + mode1 = node->registers; + break; + case GP_IO_SEL: + direction1 = node->registers; + break; + case GP_LVL: + level1 = node->registers; + break; + case GPO_BLINK: + blink = node->registers; // TODO.. + break; + case GPI_INV: + invert = node->registers; + break; + case GPIO_USE_SEL2: + mode2 = node->registers; + break; + case GP_IO_SEL2: + direction2 = node->registers; + break; + case GP_LVL2: + level2 = node->registers; + break; + case GPIO_USE_SEL3: + mode3 = node->registers; + break; + case GP_IO_SEL3: + direction3 = node->registers; + break; + case GP_LVL3: + level3 = node->registers; + break; + default: + fprintf(stderr, "Unknown GPIO address of 0x%04x\n", node->address); + break; + } + prev = node; + node = node->next; + free(prev); + } + + write_gpio_header(1, mode1, direction1, level1, invert); + write_gpio_header(2, mode2, direction2, level2, 0); + write_gpio_header(3, mode3, direction3, level3, 0); + + if (board_name != NULL) { + build_structs(board_name); + } else { + build_structs("generic"); + } + printf("#endif\n"); +} + +int main(int argc, char *argv[]) +{ + int opt, option_index = 0; + uint8_t dump_set = 0, dump_all_sets = 0; + uint32_t direction = 0, mode = 0, level = 0, invert = 0; + char * mainboard_name = NULL; + struct dump_tuple * head = NULL; + + static struct option long_options[] = { + {"version", no_argument, 0, 'v'}, + {"help", no_argument, 0, 'h'}, + {"set", required_argument, 0, 's'}, + {"boardname", optional_argument, 0, 'b'}, + {"direction", required_argument, 0, 'd'}, + {"mode", required_argument, 0, 'm'}, + {"level", required_argument, 0, 'l'}, + {"invert", required_argument, 0, 'i'}, + {"all", 0, 0, 'a'}, + {0, 0, 0, 0} + }; + + while ((opt = getopt_long(argc, argv, "vh?b:s:d:m:l:i:a", + long_options, &option_index)) != EOF) { + switch (opt) { + case 'v': + print_version(); + exit(0); + break; + case 'b': + mainboard_name = optarg; + break; + case 's': + dump_set = atoi(optarg); + break; + case 'd': + direction = strtol(optarg, NULL, 16); + break; + case 'm': + mode = strtol(optarg, NULL, 16); + break; + case 'l': + level = strtol(optarg, NULL, 16); + break; + case 'i': + invert = strtol(optarg, NULL, 16); + break; + case 'a': + dump_all_sets = 1; + break; + case 'h': + case '?': + default: + print_usage(argv[0]); + exit(0); + break; + } + } + + if (dump_all_sets) { + head = process_stdin(stdin); + build_header(head, mainboard_name); + } + + +// FIXME: check if mode, direction, level and invert were /all/ set.. + if ((dump_set >= 1) && (dump_set <= 3)) { + write_gpio_header(dump_set, mode, direction, level, invert); + } else if (!dump_all_sets) { + print_usage(argv[0]); + exit(0); + } + + return 0; +} diff --git a/util/intelgpio/intelgpio.h b/util/intelgpio/intelgpio.h new file mode 100644 index 0000000..a7544b3 --- /dev/null +++ b/util/intelgpio/intelgpio.h @@ -0,0 +1,52 @@ +/* + * inteltool - Prepare gpio.h file from register dumps from inteltool. + * + * Copyright (C) 2014 Edward O'Callaghan eocallaghan@alterapraxis.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _INTELGPIO_H +#define _INTELGPIO_H + +#include <stdint.h> + +/* ICH7 GPIOBASE */ +#define GPIO_USE_SEL 0x00 +#define GP_IO_SEL 0x04 +#define GP_LVL 0x0c +#define GPO_BLINK 0x18 +#define GPI_INV 0x2c +#define GPIO_USE_SEL2 0x30 +#define GP_IO_SEL2 0x34 +#define GP_LVL2 0x38 +#define GPIO_USE_SEL3 0x40 +#define GP_IO_SEL3 0x44 +#define GP_LVL3 0x48 +#define GP_RST_SEL1 0x60 +#define GP_RST_SEL2 0x64 +#define GP_RST_SEL3 0x68 + + +struct dump_tuple; + +struct dump_tuple { + uint32_t address; + uint32_t registers; + struct dump_tuple * next; +}; + +struct dump_tuple * process_stdin(FILE *fp); + +#endif /* _INTELGPIO_H */