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"
+);