debug: Add basic CLI commands for I/O and PCI
These are useful for debug on x86 systems.
BUG=chrome-os-partner:40635
BRANCH=none
TEST=boot on glados to cli and test ior/iow and pcir/pciw
Change-Id: Iebb8a28fb4c17b493b6ea76c3f39bec4607b9406
Signed-off-by: Duncan Laurie <dlaurie@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/275864
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-by: Vadim Bendebury <vbendeb@chromium.org>
diff --git a/src/debug/cli/Makefile.inc b/src/debug/cli/Makefile.inc
index 363da5d..9e64828 100644
--- a/src/debug/cli/Makefile.inc
+++ b/src/debug/cli/Makefile.inc
@@ -15,6 +15,8 @@
## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
##
+depthcharge-$(CONFIG_ARCH_X86) += io.c
+depthcharge-$(CONFIG_ARCH_X86) += pci.c
depthcharge-$(CONFIG_KERNEL_LEGACY) += boot.c
depthcharge-y += audio.c
depthcharge-y += command.c
diff --git a/src/debug/cli/io.c b/src/debug/cli/io.c
new file mode 100644
index 0000000..35587ba
--- /dev/null
+++ b/src/debug/cli/io.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2015 Google Inc.
+ *
+ * Commands for testing x86 LPC I/O.
+ */
+
+#include "common.h"
+
+static int do_ior(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ int size;
+ u16 port;
+
+ if (argc < 2)
+ return CMD_RET_USAGE;
+
+ /* Check for size specification */
+ size = cmd_get_data_size(argv[0], 1);
+ if (size < 1)
+ return CMD_RET_USAGE;
+
+ /* Get IO port */
+ port = strtoul(argv[1], NULL, 16);
+
+ switch (size) {
+ case 4:
+ printf("0x%08x\n", inl(port));
+ break;
+ case 2:
+ printf("0x%04x\n", inw(port));
+ break;
+ case 1:
+ printf("0x%02x\n", inb(port));
+ break;
+ default:
+ return CMD_RET_USAGE;
+ }
+
+ return CMD_RET_SUCCESS;
+}
+
+static int do_iow(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ int size;
+ u16 port;
+ u32 value;
+
+ if (argc < 3)
+ return CMD_RET_USAGE;
+
+ /* Check for size specification */
+ size = cmd_get_data_size(argv[0], 1);
+ if (size < 1)
+ return CMD_RET_USAGE;
+
+ /* Get IO port */
+ port = strtoul(argv[1], NULL, 16);
+
+ /* Get write value */
+ value = strtoul(argv[2], NULL, 16);
+
+ switch (size) {
+ case 4:
+ outl(value, port);
+ break;
+ case 2:
+ outw((u16)value, port);
+ break;
+ case 1:
+ outb((u8)value, port);
+ break;
+ default:
+ return CMD_RET_USAGE;
+ }
+
+ return CMD_RET_SUCCESS;
+}
+
+U_BOOT_CMD(
+ ior, 2, 1,
+ "IO port input",
+ "[.b, .w, .l] port"
+);
+
+U_BOOT_CMD(
+ iow, 3, 1,
+ "IO port output",
+ "[.b, .w, .l] port value"
+);
diff --git a/src/debug/cli/pci.c b/src/debug/cli/pci.c
new file mode 100644
index 0000000..3370bfc
--- /dev/null
+++ b/src/debug/cli/pci.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2015 Google Inc.
+ *
+ * Command for testing PCI.
+ */
+
+#include "common.h"
+
+static int do_pcir(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ unsigned bus, dev, func, reg;
+ u32 device;
+ int size;
+
+ if (argc < 5)
+ return CMD_RET_USAGE;
+
+ /* Check for size specification */
+ size = cmd_get_data_size(argv[0], 1);
+ if (size < 1)
+ return CMD_RET_USAGE;
+
+ /* Get bus, device, function, and register */
+ bus = strtoul(argv[1], NULL, 16);
+ dev = strtoul(argv[2], NULL, 16);
+ func = strtoul(argv[3], NULL, 16);
+ reg = strtoul(argv[4], NULL, 16);
+
+ device = PCI_ADDR(bus, dev, func, reg);
+
+ switch (size) {
+ case 4:
+ printf("0x%08x\n", pci_read_config32(device, reg));
+ break;
+ case 2:
+ printf("0x%04x\n", pci_read_config16(device, reg));
+ break;
+ case 1:
+ printf("0x%02x\n", pci_read_config8(device, reg));
+ break;
+ default:
+ return CMD_RET_USAGE;
+ }
+
+ return CMD_RET_SUCCESS;
+}
+
+static int do_pciw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ unsigned bus, dev, func, reg;
+ int size;
+ u32 device, val;
+
+ if (argc < 6)
+ return CMD_RET_USAGE;
+
+ /* Check for size specification */
+ size = cmd_get_data_size(argv[0], 1);
+ if (size < 1)
+ return CMD_RET_USAGE;
+
+ /* Get bus, device, function, and register */
+ bus = strtoul(argv[1], NULL, 16);
+ dev = strtoul(argv[2], NULL, 16);
+ func = strtoul(argv[3], NULL, 16);
+ reg = strtoul(argv[4], NULL, 16);
+ val = strtoul(argv[5], NULL, 16);
+
+ device = PCI_ADDR(bus, dev, func, reg);
+
+ switch (size) {
+ case 4:
+ pci_write_config32(device, reg, val);
+ break;
+ case 2:
+ pci_write_config16(device, reg, (u16)val);
+ break;
+ case 1:
+ pci_write_config8(device, reg, (u8)val);
+ break;
+ default:
+ return CMD_RET_USAGE;
+ }
+
+ return CMD_RET_SUCCESS;
+}
+
+static int do_lspci(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ unsigned bus, dev, func;
+
+ for (bus = 0; bus <= 0xff; bus++) {
+ for (dev = 0; dev <= 0x1f; dev++) {
+ for (func = 0; func <= 7; func++) {
+ u32 viddid = pci_read_config32(
+ PCI_DEV(bus, dev, func), 0);
+ if (viddid == 0xffffffff ||
+ viddid == 0x00000000 ||
+ viddid == 0xffff0000 ||
+ viddid == 0x0000ffff)
+ continue;
+ printf("%02x %02x %1x %04x %04x\n",
+ bus, dev, func, viddid & 0xffff,
+ viddid >> 16);
+ }
+ }
+ }
+
+ return CMD_RET_SUCCESS;
+}
+
+U_BOOT_CMD(
+ lspci, 1, 1,
+ "List PCI devices",
+ "\n"
+);
+
+U_BOOT_CMD(
+ pcir, 5, 1,
+ "PCI config input",
+ "[.b, .w, .l] bus device function register"
+);
+
+U_BOOT_CMD(
+ pciw, 6, 1,
+ "PCI config output",
+ "[.b, .w, .l] bus device function register value"
+);