aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEvgeny Zinoviev <me@ch1p.com>2018-08-24 21:10:41 +0300
committerEvgeny Zinoviev <me@ch1p.com>2018-08-24 21:10:41 +0300
commit63fa4173ae241b2c9a4bdebb2f0bb6022fce15e6 (patch)
tree09924fde1a6a406601a22139eea6586d1c07dce0
initial
-rw-r--r--Makefile38
-rw-r--r--README.md2
-rw-r--r--pmh7tool.c214
-rw-r--r--pmh7tool.h29
4 files changed, 283 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..091fbc5
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,38 @@
+##
+## Makefile for pmh7tool
+##
+## Copyright (C) 2018 Evgeny Zinoviev <me@ch1p.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.
+##
+
+CC = gcc
+CFLAGS = -O2 -Wall -W -Werror
+PROGRAM = pmh7tool
+INSTALL = /usr/bin/install
+PREFIX = /usr/local
+
+all: $(PROGRAM)
+
+$(PROGRAM): pmh7tool.o
+ $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
+
+install: $(PROGRAM)
+ $(INSTALL) $(PROGRAM) $(PREFIX)/sbin
+
+clean:
+ rm -f *.o $(PROGRAM)
+
+distclean: clean
+
+%.o: %.c
+ $(CC) $(CFLAGS) -c $^ -I. -o $@
+
+.PHONY: all install clean distclean
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..a0120ec
--- /dev/null
+++ b/README.md
@@ -0,0 +1,2 @@
+# pmh7tool
+# pmh7tool
diff --git a/pmh7tool.c b/pmh7tool.c
new file mode 100644
index 0000000..d0c652e
--- /dev/null
+++ b/pmh7tool.c
@@ -0,0 +1,214 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2018 Evgeny Zinoviev <me@ch1p.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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <sys/io.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+#include "pmh7tool.h"
+
+uint8_t pmh7_register_read(uint16_t reg)
+{
+ outb(reg & 0xff, EC_LENOVO_PMH7_ADDR_L);
+ outb((reg & 0xff00) >> 8, EC_LENOVO_PMH7_ADDR_H);
+ return inb(EC_LENOVO_PMH7_DATA);
+}
+
+void pmh7_register_write(uint16_t reg, uint8_t val)
+{
+ outb(reg & 0xff, EC_LENOVO_PMH7_ADDR_L);
+ outb((reg & 0xff00) >> 8, EC_LENOVO_PMH7_ADDR_H);
+ outb(val, EC_LENOVO_PMH7_DATA);
+}
+
+void pmh7_register_set_bit(uint16_t reg, uint8_t bit)
+{
+ uint8_t val;
+
+ val = pmh7_register_read(reg);
+ pmh7_register_write(reg, val | (1 << bit));
+}
+
+void pmh7_register_clear_bit(uint16_t reg, uint8_t bit)
+{
+ uint8_t val;
+
+ val = pmh7_register_read(reg);
+ pmh7_register_write(reg, val & ~(1 << bit));
+}
+
+void print_usage(const char *name)
+{
+ printf("usage: %s\n", name);
+ printf("\n"
+ " -h, --help: print this help\n"
+ " -d, --dump: print registers\n"
+ " -w, --write <addr> <data>: write to register\n"
+ " -r, --read <addr>: read from register\n"
+ " -c, --clear-bit <addr> <bit>\n"
+ " -s, --set-bit <addr> <bit>\n"
+ "\n"
+ "Attention! Writing to PMH7 registers is very dangerous, as you\n"
+ " directly manipulate the power rails, enable lines,\n"
+ " interrupt lines or something else of the device.\n"
+ " Proceed with caution."
+ "\n");
+}
+
+enum action {HELP, DUMP, WRITE, READ, CLEAR, SET};
+
+int main(int argc, char *argv[])
+{
+ enum action act = HELP;
+ int opt, option_index = 0;
+ long input_addr = 0, input_data = 0;
+
+ static struct option long_options[] = {
+ {"help", 0, 0, 'h'},
+ {"dump", 0, 0, 'd'},
+ {"write", 1, 0, 'w'},
+ {"read", 1, 0, 'r'},
+ {"clear-bit", 1, 0, 'c'},
+ {"set-bit", 1, 0, 's'},
+ {0, 0, 0, 0}
+ };
+
+ if (argv[1] == NULL) {
+ print_usage(argv[0]);
+ exit(0);
+ }
+
+ while ((opt = getopt_long(argc, argv, "hdw:r:c:s:",
+ long_options, &option_index)) != EOF) {
+ switch (opt) {
+ case 'd':
+ act = DUMP;
+ break;
+
+ case 'r':
+ input_addr = strtoul(optarg, NULL, 16);
+ act = READ;
+ break;
+
+ case 'w':
+ case 'c':
+ case 's':
+ input_addr = strtoul(optarg, NULL, 16);
+
+ if (optind < argc && *argv[optind] != '-') {
+ input_data = strtoul(argv[optind], NULL, 16);
+ optind++;
+ } else {
+ fprintf(stderr,
+ "Error: -%c option requires two arguments\n",
+ opt);
+ exit(1);
+ }
+
+ switch (opt) {
+ case 'w':
+ act = WRITE;
+ break;
+ case 'c':
+ act = CLEAR;
+ break;
+ case 's':
+ act = SET;
+ break;
+ }
+ break;
+ }
+ }
+
+ if (optind < argc) {
+ fprintf(stderr, "Error: Extra parameter found.\n");
+ print_usage(argv[0]);
+ exit(1);
+ }
+
+ if (act == HELP) {
+ print_usage(argv[0]);
+ exit(0);
+ }
+
+ if (input_addr > 0x1ff) {
+ fprintf(stderr,
+ "Error: <addr> cannot be greater than 9 bits long.\n");
+ exit(1);
+ }
+
+ if (act == SET || act == CLEAR) {
+ if (input_data > 7) {
+ fprintf(stderr,
+ "Error: <bit> cannot be greater than 7.\n");
+ exit(1);
+ }
+ } else {
+ if (input_data > 0xff) {
+ fprintf(stderr,
+ "Error: <data> cannot be greater than 8 bits long.\n");
+ exit(1);
+ }
+ }
+
+ if (geteuid() != 0) {
+ fprintf(stderr, "You must be root.\n");
+ exit(1);
+ }
+
+ if (ioperm(EC_LENOVO_PMH7_BASE, 0x10, 1)) {
+ fprintf(stderr, "ioperm: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ switch (act) {
+ case DUMP:
+ for (int i = 0; i < 0x200; i++) {
+ if ((i % 0x10) == 0) {
+ if (i != 0)
+ printf("\n");
+ printf("%04x: ", i);
+ }
+ printf("%02x ", pmh7_register_read(i));
+ }
+ printf("\n");
+ break;
+
+ case READ:
+ printf("%02x\n", pmh7_register_read(input_addr));
+ break;
+
+ case WRITE:
+ pmh7_register_write(input_addr, input_data);
+ break;
+
+ case CLEAR:
+ pmh7_register_clear_bit(input_addr, input_data);
+ break;
+
+ case SET:
+ pmh7_register_set_bit(input_addr, input_data);
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
diff --git a/pmh7tool.h b/pmh7tool.h
new file mode 100644
index 0000000..37d5027
--- /dev/null
+++ b/pmh7tool.h
@@ -0,0 +1,29 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2018 Evgeny Zinoviev <me@ch1p.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.
+ */
+
+#ifndef PMH7TOOL_H
+#define PMH7TOOL_H
+
+#define EC_LENOVO_PMH7_BASE 0x15e0
+#define EC_LENOVO_PMH7_ADDR_L (EC_LENOVO_PMH7_BASE + 0x0c)
+#define EC_LENOVO_PMH7_ADDR_H (EC_LENOVO_PMH7_BASE + 0x0d)
+#define EC_LENOVO_PMH7_DATA (EC_LENOVO_PMH7_BASE + 0x0e)
+
+uint8_t pmh7_register_read(uint16_t reg);
+void pmh7_register_write(uint16_t reg, uint8_t val);
+void pmh7_register_set_bit(uint16_t reg, uint8_t bit);
+void pmh7_register_clear_bit(uint16_t reg, uint8_t bit);
+
+#endif /* PMH7TOOL_H */