[coreboot-gerrit] New patch to review for coreboot: [WIP] lenovo/t400: Rewrite dock from t60

Kyösti Mälkki (kyosti.malkki@gmail.com) gerrit at coreboot.org
Sun Jan 8 08:50:56 CET 2017


Kyösti Mälkki (kyosti.malkki at gmail.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/18054

-gerrit

commit dcec9f257d0df6d67c4c64434b752b971543363b
Author: Kyösti Mälkki <kyosti.malkki at gmail.com>
Date:   Sun Jan 8 09:07:14 2017 +0200

    [WIP] lenovo/t400: Rewrite dock from t60
    
    Old dock.c copied from x201 was incorrect.
    
    Rewrite t60 dock code as pnp devices, completely untested.
    
    Change-Id: Ib20a0eff10d0cde92dd089baf4fca28b117dc999
    Signed-off-by: Kyösti Mälkki <kyosti.malkki at gmail.com>
---
 src/ec/lenovo/h8/h8.h                   |   2 -
 src/mainboard/lenovo/t400/Kconfig       |   3 +-
 src/mainboard/lenovo/t400/Makefile.inc  |   2 +
 src/mainboard/lenovo/t400/devicetree.cb |  30 ++++-
 src/mainboard/lenovo/t400/dock.c        | 230 +++++++++++++++++++++++++++++---
 src/mainboard/lenovo/t400/romstage.c    |   4 +
 6 files changed, 244 insertions(+), 27 deletions(-)

diff --git a/src/ec/lenovo/h8/h8.h b/src/ec/lenovo/h8/h8.h
index 290db91..ac3cfd5 100644
--- a/src/ec/lenovo/h8/h8.h
+++ b/src/ec/lenovo/h8/h8.h
@@ -28,9 +28,7 @@ int h8_ultrabay_device_present(void);
 u8 h8_build_id_and_function_spec_version(char *buf, u8 buf_len);
 void h8_usb_always_on(void);
 
-#if !IS_ENABLED (CONFIG_H8_DOCK_EARLY_INIT)
 void h8_mainboard_init_dock (void);
-#endif
 
 /* EC registers */
 #define H8_CONFIG0 0x00
diff --git a/src/mainboard/lenovo/t400/Kconfig b/src/mainboard/lenovo/t400/Kconfig
index 47e7688..be0b0ca 100644
--- a/src/mainboard/lenovo/t400/Kconfig
+++ b/src/mainboard/lenovo/t400/Kconfig
@@ -8,7 +8,7 @@ config BOARD_SPECIFIC_OPTIONS # dummy
 	select SOUTHBRIDGE_INTEL_I82801IX
 	select EC_LENOVO_PMH7
 	select EC_LENOVO_H8
-	select NO_UART_ON_SUPERIO
+	select H8_DOCK_EARLY_INIT
 	select DRIVERS_ICS_954309
 	select BOARD_ROMSIZE_KB_8192
 	select DRIVERS_GENERIC_IOAPIC
@@ -22,6 +22,7 @@ config BOARD_SPECIFIC_OPTIONS # dummy
 	select MAINBOARD_HAS_NATIVE_VGA_INIT_TEXTMODECFG
 	select INTEL_INT15
 	select SUPERIO_NSC_PC87382
+	select SUPERIO_NSC_PC87384
 	select DRIVERS_LENOVO_HYBRID_GRAPHICS
 
 config MAINBOARD_DIR
diff --git a/src/mainboard/lenovo/t400/Makefile.inc b/src/mainboard/lenovo/t400/Makefile.inc
index b382efb..34720c7 100644
--- a/src/mainboard/lenovo/t400/Makefile.inc
+++ b/src/mainboard/lenovo/t400/Makefile.inc
@@ -13,5 +13,7 @@
 ## GNU General Public License for more details.
 ##
 
+romstage-y += dock.c
+
 ramstage-y += dock.c
 ramstage-y += cstates.c
diff --git a/src/mainboard/lenovo/t400/devicetree.cb b/src/mainboard/lenovo/t400/devicetree.cb
index 46cca1e..1adba8b 100644
--- a/src/mainboard/lenovo/t400/devicetree.cb
+++ b/src/mainboard/lenovo/t400/devicetree.cb
@@ -181,13 +181,29 @@ chip northbridge/intel/gm45
 				end
 
 				chip superio/nsc/pc87382
-					device pnp 164e.3 off end
-					# IR, not connected
-					device pnp 164e.2 off end
-					# GPIO, not connected
-					device pnp 164e.7 off end
-					# DLPC, not connected
-					device pnp 164e.19 off end
+					device pnp 164e.2 off end # IR
+					device pnp 164e.3 off end # Serial Port
+					device pnp 164e.7 on # GPIO
+						io 0x60 = 0x1680
+					end
+					device pnp 164e.19 on # DLPC
+						io 0x60 = 0x164c
+					end
+				end
+
+				chip superio/nsc/pc87384
+					device pnp 2e.1 on # Parallel Port
+						io 0x60 = 0x3bc
+						irq 0x70 = 7
+					end
+					device pnp 2e.2 off end # Serial Port / IR
+					device pnp 2e.3 on # Serial Port
+						io 0x60 = 0x3f8
+						irq 0x70 = 4
+					end
+					device pnp 2e.7 on # GPIO
+						io 0x60 = 0x1620
+					end
 				end
 
 			end
diff --git a/src/mainboard/lenovo/t400/dock.c b/src/mainboard/lenovo/t400/dock.c
index 836ff35..a3412bf 100644
--- a/src/mainboard/lenovo/t400/dock.c
+++ b/src/mainboard/lenovo/t400/dock.c
@@ -20,41 +20,237 @@
 #include <arch/io.h>
 #include <device/device.h>
 #include <device/pci.h>
+#include <device/pnp.h>
 #include <delay.h>
 #include "dock.h"
+#include <superio/nsc/pc87382/pc87382.h>
+
 #include "southbridge/intel/i82801ix/i82801ix.h"
 #include "ec/lenovo/h8/h8.h"
 #include <ec/acpi/ec.h>
 
-#define LPC_DEV PCI_DEV(0, 0x1f, 0)
+struct pin_config {
+	u8 port;
+	u8 mode;
+};
 
-void h8_mainboard_init_dock (void)
+static int poll_clk_stable(pnp_devfn_t dev)
 {
-	if (dock_present()) {
-		printk(BIOS_DEBUG, "dock is connected\n");
-		dock_connect();
-	} else
-		printk(BIOS_DEBUG, "dock is not connected\n");
+	int timeout = 1000;
+
+	/* Enable 14.318MHz CLK on CLKIN */
+	pnp_write_config(dev, 0x29, 0xa0);
+	while(!(pnp_read_config(dev, 0x29) & 0x10) && timeout--)
+		udelay(1000);
+	if (!timeout)
+		return 1;
+
+	return 0;
 }
 
+static int gpio_init(pnp_devfn_t gpio, u16 gpio_base,
+	const struct pin_config pincfg[], int num_cfgs)
+{
+	int i;
+
+	/* Enable GPIO LDN. */
+	pnp_set_logical_device(gpio);
+	pnp_set_iobase(gpio, PNP_IDX_IO0, gpio_base);
+	pnp_set_enable(gpio, 1);
+
+	for (i=0; i < num_cfgs; i++) {
+		pnp_write_config(gpio, 0xf0, pincfg[i].port);
+		pnp_write_config(gpio, 0xf1, pincfg[i].mode);
+		pnp_write_config(gpio, 0xf2, 0x0);
+	}
+	return 0;
+}
+
+static const pnp_devfn_t l_dlpc = PNP_DEV(0x164e, PC87382_DOCK);
+static const pnp_devfn_t l_gpio = PNP_DEV(0x164e, PC87382_GPIO);
+
+#define DLPC_CONTROL	0x164c
+#define DLPC_GPIO_BASE	0x1680
+
+#define DLPC_GPDO0		(DLPC_GPIO_BASE + 0x0)
+#define DLPC_GPDI0		(DLPC_GPIO_BASE + 0x1)
+#define		D_PLTRST	0x01
+#define		D_LPCPD		0x02
+
+#define DLPC_GPDO2		(DLPC_GPIO_BASE + 0x8)
+#define DLPC_GPDI2		(DLPC_GPIO_BASE + 0x9)
+
+static int pc87382_init(pnp_devfn_t dlpc, u16 dlpc_base)
+{
+	int timeout = 1000;
+
+	/* Enable LPC bridge LDN. */
+	pnp_set_logical_device(dlpc);
+	pnp_set_iobase(dlpc, PNP_IDX_IO0, dlpc_base);
+	pnp_set_enable(dlpc, 1);
+
+	/* Reset docking state */
+	outb(0x00, dlpc_base);
+	outb(0x07, dlpc_base);
+	while(!(inb(dlpc_base) & 8) && timeout--)
+		udelay(1000);
+	if (!timeout)
+		return 1;
+
+	return 0;
+}
+
+static void pc87382_close(pnp_devfn_t dlpc)
+{
+	pnp_set_logical_device(dlpc);
+
+	/* Disconnect LPC bus */
+	u16 dlpc_base = pnp_read_iobase(dlpc, PNP_IDX_IO0);
+	outb(0x00, dlpc_base);
+	pnp_set_enable(dlpc, 0);
+}
+
+static const struct pin_config local_gpio[] = {
+	{0x00, 3}, 	{0x01, 3},	{0x02, 0},	{0x03, 3},
+	{0x04, 4},	{0x20, 4},	{0x21, 4},	{0x23, 4},
+};
+
+static int pc87382_connect(void)
+{
+	u8 reg;
+
+	if (poll_clk_stable(l_gpio) != 0)
+		return 1;
+
+	if (gpio_init(l_gpio, DLPC_GPIO_BASE,
+		local_gpio, ARRAY_SIZE(local_gpio)) != 0) {
+		return 1;
+	}
+
+	reg = inb(DLPC_GPDO0);
+	reg |= D_PLTRST | D_LPCPD;
+	/* Deassert D_PLTRST# and D_LPCPD# */
+	outb(reg, DLPC_GPDO0);
+
+	if (pc87382_init(l_dlpc, DLPC_CONTROL) != 0) {
+		return 1;
+	}
+
+	/* Assert D_PLTRST# */
+	reg &= ~D_PLTRST;
+	outb(reg, DLPC_GPDO0);
+	udelay(1000);
+
+	/* Deassert D_PLTRST# */
+	reg |= D_PLTRST;
+	outb(reg, DLPC_GPDO0);
+	udelay(10000);
+
+	return 0;
+}
+
+static void pc87382_disconnect(void)
+{
+	pc87382_close(l_dlpc);
+
+	/* Assert D_PLTRST# and D_LPCPD# */
+	u8 reg = inb(DLPC_GPDO0);
+	reg &= ~(D_PLTRST | D_LPCPD);
+	outb(reg, DLPC_GPDO0);
+}
+
+static u8 dock_identify(void)
+{
+	u8 id;
+
+	id = (inb(DLPC_GPDI0) >> 4) & 1;
+	id |= (inb(DLPC_GPDI2) & 3) << 1;
+
+	return id;
+}
+
+/* Docking station side. */
+
+#include <superio/nsc/pc87384/pc87384.h>
+
+static const pnp_devfn_t r_gpio = PNP_DEV(0x2e, PC87384_GPIO);
+static const pnp_devfn_t r_serial = PNP_DEV(0x2e, PC87384_SP1);
+
+#define DOCK_GPIO_BASE	0x1620
+
+static const struct pin_config remote_gpio[] = {
+	{0x00, PC87384_GPIO_PIN_DEBOUNCE | PC87384_GPIO_PIN_PULLUP},
+	{0x01, PC87384_GPIO_PIN_TYPE_PUSH_PULL | PC87384_GPIO_PIN_OE},
+	{0x02, PC87384_GPIO_PIN_TYPE_PUSH_PULL | PC87384_GPIO_PIN_OE},
+	{0x03, PC87384_GPIO_PIN_DEBOUNCE | PC87384_GPIO_PIN_PULLUP},
+	{0x04, PC87384_GPIO_PIN_DEBOUNCE | PC87384_GPIO_PIN_PULLUP},
+	{0x05, PC87384_GPIO_PIN_DEBOUNCE | PC87384_GPIO_PIN_PULLUP},
+	{0x06, PC87384_GPIO_PIN_DEBOUNCE | PC87384_GPIO_PIN_PULLUP},
+	{0x07, PC87384_GPIO_PIN_DEBOUNCE | PC87384_GPIO_PIN_PULLUP},
+};
+
+static int pc87384_init(void)
+{
+	if (poll_clk_stable(r_gpio) != 0)
+		return 1;
+
+	/* set GPIO pins to Serial/Parallel Port
+	 * functions
+	 */
+	pnp_write_config(r_gpio, 0x22, 0xa9);
+
+	/* enable serial port */
+	pnp_set_logical_device(r_serial);
+	pnp_set_iobase(r_serial, PNP_IDX_IO0, 0x3f8);
+	pnp_set_enable(r_serial, 1);
+
+	if (gpio_init(r_gpio, DOCK_GPIO_BASE,
+		remote_gpio, ARRAY_SIZE(remote_gpio)) != 0)
+		return 1;
+
+	/* no GPIO events enabled for PORT0 */
+	outb(0x00, DOCK_GPIO_BASE + 0x02);
+	/* clear GPIO events on PORT0 */
+	outb(0xff, DOCK_GPIO_BASE + 0x03);
+	outb(0xff, DOCK_GPIO_BASE + 0x04);
+
+	/* no GPIO events enabled for PORT1 */
+	outb(0x00, DOCK_GPIO_BASE + 0x06);
+	/* clear GPIO events on PORT1*/
+	outb(0xff, DOCK_GPIO_BASE + 0x07);
+	outb(0x1f, DOCK_GPIO_BASE + 0x08);
+
+	outb(0xfd, DOCK_GPIO_BASE + 0x00);
+
+	return 0;
+}
+
+/* Mainboard */
+
 void dock_connect(void)
 {
-	u16 gpiobase = pci_read_config16(LPC_DEV, D31F0_GPIO_BASE) & 0xfffc;
-	ec_set_bit(0x02, 0);
-	outl(inl(gpiobase + 0x0c) | (1 << 28), gpiobase + 0x0c);
+	if (dock_identify() == 0)
+		return;
+
+	if (pc87382_connect() != 0) {
+		pc87382_disconnect();
+		return;
+	}
+	pc87384_init();
 }
 
 void dock_disconnect(void)
 {
-	u16 gpiobase = pci_read_config16(LPC_DEV, D31F0_GPIO_BASE) & 0xfffc;
-	ec_clr_bit(0x02, 0);
-	outl(inl(gpiobase + 0x0c) & ~(1 << 28), gpiobase + 0x0c);
+	pc87382_disconnect();
 }
 
-int dock_present(void)
+void h8_mainboard_init_dock(void)
 {
-	u16 gpiobase = pci_read_config16(LPC_DEV, D31F0_GPIO_BASE) & 0xfffc;
-	u8 st = inb(gpiobase + 0x0c);
+	u8 id = dock_identify();
 
-	return ((st >> 2) & 7) != 7;
+	if (id != 0) {
+		printk(BIOS_DEBUG, "dock (id=%d) is present\n", id);
+		dock_connect();
+	} else
+		printk(BIOS_DEBUG, "dock is not connected\n");
 }
diff --git a/src/mainboard/lenovo/t400/romstage.c b/src/mainboard/lenovo/t400/romstage.c
index d110d4f..b1a1e19 100644
--- a/src/mainboard/lenovo/t400/romstage.c
+++ b/src/mainboard/lenovo/t400/romstage.c
@@ -31,6 +31,7 @@
 #include <console/console.h>
 #include <southbridge/intel/i82801ix/i82801ix.h>
 #include <northbridge/intel/gm45/gm45.h>
+#include "dock.h"
 #include "gpio.h"
 
 #define LPC_DEV PCI_DEV(0, 0x1f, 0)
@@ -66,6 +67,9 @@ void mainboard_romstage_entry(unsigned long bist)
 	/* First, run everything needed for console output. */
 	i82801ix_early_init();
 	early_lpc_setup();
+
+	dock_connect();
+
 	console_init();
 	printk(BIOS_DEBUG, "running main(bist = %lu)\n", bist);
 



More information about the coreboot-gerrit mailing list