From c0a1625df13ac9e95ca4de849ac52bb3af29c7b6 Mon Sep 17 00:00:00 2001 From: Patrick Rudolph Date: Tue, 30 Oct 2018 17:38:13 +0100 Subject: 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 * Use Kconfig values instead of fixed defines * Add documentation Tested on Lenovo T500 with docking 2504 and 2505. Change-Id: Ic4510ffadc67da95961cecd51a6d8ed856b3ac99 Signed-off-by: Patrick Rudolph Reviewed-on: https://review.coreboot.org/29418 Tested-by: build bot (Jenkins) Reviewed-by: Felix Held --- Documentation/mainboard/lenovo/t4xx_series.md | 14 +++++ src/mainboard/lenovo/t400/dock.c | 82 ++++++++++++++------------- src/mainboard/lenovo/t400/dock.h | 27 +++++++++ src/mainboard/lenovo/t400/romstage.c | 12 +++- 4 files changed, 94 insertions(+), 41 deletions(-) diff --git a/Documentation/mainboard/lenovo/t4xx_series.md b/Documentation/mainboard/lenovo/t4xx_series.md index e5e90f1e6f..3ca70470a1 100644 --- a/Documentation/mainboard/lenovo/t4xx_series.md +++ b/Documentation/mainboard/lenovo/t4xx_series.md @@ -18,3 +18,17 @@ the whole device. * Unplug the power cable * Remove the bottom enclosure * Flip the mainboard and remove the main frame + +## Docking stations +The following docking stations are supported by coreboot: +* Type 2505 + * VGA, Ethernet, Modem, PS2, 4 USB Ports + * Dock ID on pc87382 reads as: 2 +* Type 2504 + * Serial, LPT, LEDs, Audio, DVI, VGA, Ethernet, Modem, PS2, 4 USB Ports + * Dock ID on pc87382 reads as: 1 + * PNP IO address of SuperIO pc87384: 0x2e + +There's no hotplug support for LPT and Serial on Type 2504. + +The Dock ID reads as 7 if no dock is connected. diff --git a/src/mainboard/lenovo/t400/dock.c b/src/mainboard/lenovo/t400/dock.c index 3d92a796de..6d1a80c1c1 100644 --- a/src/mainboard/lenovo/t400/dock.c +++ b/src/mainboard/lenovo/t400/dock.c @@ -34,10 +34,8 @@ struct pin_config { 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 int gpio_init(pnp_devfn_t gpio, u16 gpio_base, 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 @@ static int pc87382_init(pnp_devfn_t dlpc, u16 dlpc_base) 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 @@ static void pc87382_close(pnp_devfn_t dlpc) /* 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 @@ static const struct pin_config local_gpio[] = { {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 @@ static void pc87382_disconnect(void) 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 @@ static u8 dock_identify(void) #include -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 const struct pin_config remote_gpio[] = { 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,12 @@ static int pc87384_init(void) 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 (CONFIG_TTYS0_BASE > 0) { + 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 +229,16 @@ static int pc87384_init(void) 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 +256,12 @@ void dock_disconnect(void) 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 74b730ca23..4d2b32b9b7 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 +#ifndef __ACPI__ +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 bc419bf7d0..60e51c9808 100644 --- a/src/mainboard/lenovo/t400/romstage.c +++ b/src/mainboard/lenovo/t400/romstage.c @@ -66,6 +66,7 @@ void mainboard_romstage_entry(unsigned long bist) sysinfo_t sysinfo; int s3resume = 0; int cbmem_initted; + int err; u16 reg16; timestamp_init(get_initial_timestamp()); @@ -81,11 +82,20 @@ void mainboard_romstage_entry(unsigned long bist) 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"); + else + 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))) { -- cgit v1.2.3