[coreboot-gerrit] Patch set updated for coreboot: lenovo/t400: Rewrite dock from t60

Kyösti Mälkki (kyosti.malkki@gmail.com) gerrit at coreboot.org
Wed Mar 8 08:55:05 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 c265836adaa456699b2efc309b179a44196d66b3
Author: Kyösti Mälkki <kyosti.malkki at gmail.com>
Date:   Sun Jan 8 09:07:14 2017 +0200

    lenovo/t400: Rewrite dock from t60
    
    Old dock.c copied from x201 was incorrect. Do a rewrite of t60 dock
    code as pnp devices.
    
    Fixes USB and serial on the dock, if it is already connected when
    computer is powered on. DVI and ethernet worked without this patch.
    
    Hot-plug is yet to be fixed.
    
    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 c721d38..42d279f 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 8eb1a57..031e9e8 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 BOARD_ROMSIZE_KB_8192
 	select DRIVERS_GENERIC_IOAPIC
 	select HAVE_MP_TABLE
@@ -21,6 +21,7 @@ config BOARD_SPECIFIC_OPTIONS # dummy
 	select MAINBOARD_HAS_NATIVE_VGA_INIT_TEXTMODECFG
 	select INTEL_INT15
 	select SUPERIO_NSC_PC87382
+	select SUPERIO_NSC_PC87384
 
 config MAINBOARD_DIR
 	string
diff --git a/src/mainboard/lenovo/t400/Makefile.inc b/src/mainboard/lenovo/t400/Makefile.inc
index c02a70b..3aa94b5 100644
--- a/src/mainboard/lenovo/t400/Makefile.inc
+++ b/src/mainboard/lenovo/t400/Makefile.inc
@@ -13,6 +13,8 @@
 ## GNU General Public License for more details.
 ##
 
+romstage-y += dock.c
+
 ramstage-y += dock.c
 ramstage-y += cstates.c
 romstage-y += hybrid_graphics.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 2a3a770..31a80a4 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)
@@ -68,6 +69,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