Patrick Rudolph has uploaded this change for review. ( https://review.coreboot.org/29418
Change subject: mb/lenovo/t400: Improve docking code ......................................................................
mb/lenovo/t400: Improve docking code
* Remove dead code * Add support for types 2504 and 2505 * Print dock info at romstage entry * Improve dock disconnect for type 2505 * Move defines into dock.h for future ACPI code * Reduce timeouts according to spec to decrease boot time on error * Fix no docking detection (reduces boot time by 1 second) * Configure GPIO LDN before reading GPIOs
Tested on Lenovo T500 with docking 2504 and 2505.
Change-Id: Ic4510ffadc67da95961cecd51a6d8ed856b3ac99 Signed-off-by: Patrick Rudolph siro@das-labor.org --- M src/mainboard/lenovo/t400/dock.c M src/mainboard/lenovo/t400/dock.h M src/mainboard/lenovo/t400/romstage.c 3 files changed, 79 insertions(+), 41 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/18/29418/1
diff --git a/src/mainboard/lenovo/t400/dock.c b/src/mainboard/lenovo/t400/dock.c index 0c6db0b..fa33337 100644 --- a/src/mainboard/lenovo/t400/dock.c +++ b/src/mainboard/lenovo/t400/dock.c @@ -34,10 +34,8 @@ u8 mode; };
-static int poll_clk_stable(pnp_devfn_t dev) +static int poll_clk_stable(pnp_devfn_t dev, int timeout) { - int timeout = 1000; - /* Enable 14.318MHz CLK on CLKIN */ pnp_write_config(dev, 0x29, 0xa0); while(!(pnp_read_config(dev, 0x29) & 0x10) && timeout--) @@ -69,20 +67,10 @@ 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; + /* Maximum 3300 LCLKs at 14.318MHz */ + int timeout = 230;
/* Enable LPC bridge LDN. */ pnp_set_logical_device(dlpc); @@ -93,7 +81,7 @@ outb(0x00, dlpc_base); outb(0x07, dlpc_base); while (!(inb(dlpc_base) & 8) && timeout--) - udelay(1000); + udelay(1); if (!timeout) return 1;
@@ -106,8 +94,10 @@
/* Disconnect LPC bus */ u16 dlpc_base = pnp_read_iobase(dlpc, PNP_IDX_IO0); - outb(0x00, dlpc_base); - pnp_set_enable(dlpc, 0); + if (dlpc_base) { + outb(0x00, dlpc_base); + pnp_set_enable(dlpc, 0); + } }
static const struct pin_config local_gpio[] = { @@ -115,18 +105,26 @@ {0x04, 4}, {0x20, 4}, {0x21, 4}, {0x23, 4}, };
-static int pc87382_connect(void) +/* Enable internal clock and configure GPIO LDN */ +int pc87382_early(void) { - u8 reg; - - if (poll_clk_stable(l_gpio) != 0) + /* Wake-up time is 33 msec (maximum). */ + if (poll_clk_stable(l_gpio, 33) != 0) return 1;
+ /* Set up GPIOs */ if (gpio_init(l_gpio, DLPC_GPIO_BASE, local_gpio, ARRAY_SIZE(local_gpio)) != 0) { return 1; }
+ return 0; +} + +static int pc87382_connect(void) +{ + u8 reg; + reg = inb(DLPC_GPDO0); reg |= D_PLTRST | D_LPCPD; /* Deassert D_PLTRST# and D_LPCPD# */ @@ -158,10 +156,12 @@ outb(reg, DLPC_GPDO0); }
+/* Returns 3bit dock id */ static u8 dock_identify(void) { u8 id;
+ /* Make sure GPIO LDN is configured first ! */ id = (inb(DLPC_GPDI0) >> 4) & 1; id |= (inb(DLPC_GPDI2) & 3) << 1;
@@ -172,10 +172,8 @@
#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 pnp_devfn_t r_gpio = PNP_DEV(SUPERIO_DEV, PC87384_GPIO); +static const pnp_devfn_t r_serial = PNP_DEV(SUPERIO_DEV, PC87384_SP1);
static const struct pin_config remote_gpio[] = { {0x00, PC87384_GPIO_PIN_DEBOUNCE | PC87384_GPIO_PIN_PULLUP}, @@ -190,7 +188,7 @@
static int pc87384_init(void) { - if (poll_clk_stable(r_gpio) != 0) + if (poll_clk_stable(r_gpio, 1000) != 0) return 1;
/* set GPIO pins to Serial/Parallel Port @@ -199,9 +197,11 @@ 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 (IS_ENABLED(CONFIG_CONSOLE_SERIAL)) { + pnp_set_logical_device(r_serial); + pnp_set_iobase(r_serial, PNP_IDX_IO0, CONFIG_TTYS0_BASE); + pnp_set_enable(r_serial, 1); + }
if (gpio_init(r_gpio, DOCK_GPIO_BASE, remote_gpio, ARRAY_SIZE(remote_gpio)) != 0) @@ -228,14 +228,16 @@
void dock_connect(void) { - if (dock_identify() == 0) + const u8 id = dock_identify(); + + /* Dock type 2505 doesn't have serial, LPT port or LEDs */ + if (id == DOCK_TYPE_NONE || id == DOCK_TYPE_2505) return;
- if (pc87382_connect() != 0) { + if (pc87382_connect() != 0 || pc87384_init() != 0) { pc87382_disconnect(); return; } - pc87384_init();
ec_write(H8_LED_CONTROL, H8_LED_CONTROL_OFF | H8_LED_CONTROL_DOCK_LED1); @@ -253,13 +255,12 @@ H8_LED_CONTROL_OFF | H8_LED_CONTROL_DOCK_LED2); }
-void h8_mainboard_init_dock(void) +void dock_info(void) { - u8 id = dock_identify(); + const u8 id = dock_identify();
- if (id != 0) { - printk(BIOS_DEBUG, "dock (id=%d) is present\n", id); - dock_connect(); - } else - printk(BIOS_DEBUG, "dock is not connected\n"); + if (id != DOCK_TYPE_NONE) + printk(BIOS_DEBUG, "DOCK: is present: id=%d\n", id); + else + printk(BIOS_DEBUG, "DOCK: not connected\n"); } diff --git a/src/mainboard/lenovo/t400/dock.h b/src/mainboard/lenovo/t400/dock.h index 74b730c..d94cb9e 100644 --- a/src/mainboard/lenovo/t400/dock.h +++ b/src/mainboard/lenovo/t400/dock.h @@ -16,7 +16,34 @@ #ifndef THINKPAD_T400_DOCK_H #define THINKPAD_T400_DOCK_H
+#if ENV_ROMSTAGE || ENV_RAMSTAGE || ENV_SMM +int pc87382_early(void); + void dock_connect(void); void dock_disconnect(void); int dock_present(void); +void dock_info(void); +#endif + +/* pc87382 */ +#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) + + /* Pullups on all GPIOs, dock pulls ID pins low */ +#define DOCK_TYPE_2504 1 +#define DOCK_TYPE_2505 2 +#define DOCK_TYPE_NONE 7 + +/* pc87384 */ +#define SUPERIO_DEV 0x2e +#define DOCK_GPIO_BASE 0x1620 + #endif diff --git a/src/mainboard/lenovo/t400/romstage.c b/src/mainboard/lenovo/t400/romstage.c index 7bf14bf..01886dd 100644 --- a/src/mainboard/lenovo/t400/romstage.c +++ b/src/mainboard/lenovo/t400/romstage.c @@ -66,6 +66,7 @@ sysinfo_t sysinfo; int s3resume = 0; int cbmem_initted; + int err; u16 reg16;
timestamp_init(get_initial_timestamp()); @@ -81,11 +82,20 @@ i82801ix_early_init(); early_lpc_setup();
- dock_connect(); + /* Minimal setup to detect dock */ + err = pc87382_early(); + if (err == 0) + dock_connect();
console_init(); printk(BIOS_DEBUG, "running main(bist = %lu)\n", bist);
+ /* Print dock info */ + if (err) + printk(BIOS_ERR, "DOCK: Failed to init pc87382\n"); + + dock_info(); + reg16 = pci_read_config16(LPC_DEV, D31F0_GEN_PMCON_3); pci_write_config16(LPC_DEV, D31F0_GEN_PMCON_3, reg16); if ((MCHBAR16(SSKPD_MCHBAR) == 0xCAFE) && !(reg16 & (1 << 9))) {