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 <siro@das-labor.org>
Reviewed-on: https://review.coreboot.org/29418
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Felix Held <felix-coreboot@felixheld.de>
This commit is contained in:
Patrick Rudolph 2018-10-30 17:38:13 +01:00 committed by Felix Held
parent d2c2f83964
commit c0a1625df1
4 changed files with 94 additions and 41 deletions

View File

@ -18,3 +18,17 @@ the whole device.
* Unplug the power cable * Unplug the power cable
* Remove the bottom enclosure * Remove the bottom enclosure
* Flip the mainboard and remove the main frame * 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.

View File

@ -34,10 +34,8 @@ struct pin_config {
u8 mode; 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 */ /* Enable 14.318MHz CLK on CLKIN */
pnp_write_config(dev, 0x29, 0xa0); pnp_write_config(dev, 0x29, 0xa0);
while(!(pnp_read_config(dev, 0x29) & 0x10) && timeout--) 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_dlpc = PNP_DEV(0x164e, PC87382_DOCK);
static const pnp_devfn_t l_gpio = PNP_DEV(0x164e, PC87382_GPIO); 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) 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. */ /* Enable LPC bridge LDN. */
pnp_set_logical_device(dlpc); 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(0x00, dlpc_base);
outb(0x07, dlpc_base); outb(0x07, dlpc_base);
while (!(inb(dlpc_base) & 8) && timeout--) while (!(inb(dlpc_base) & 8) && timeout--)
udelay(1000); udelay(1);
if (!timeout) if (!timeout)
return 1; return 1;
@ -106,8 +94,10 @@ static void pc87382_close(pnp_devfn_t dlpc)
/* Disconnect LPC bus */ /* Disconnect LPC bus */
u16 dlpc_base = pnp_read_iobase(dlpc, PNP_IDX_IO0); u16 dlpc_base = pnp_read_iobase(dlpc, PNP_IDX_IO0);
outb(0x00, dlpc_base); if (dlpc_base) {
pnp_set_enable(dlpc, 0); outb(0x00, dlpc_base);
pnp_set_enable(dlpc, 0);
}
} }
static const struct pin_config local_gpio[] = { 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}, {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; /* Wake-up time is 33 msec (maximum). */
if (poll_clk_stable(l_gpio, 33) != 0)
if (poll_clk_stable(l_gpio) != 0)
return 1; return 1;
/* Set up GPIOs */
if (gpio_init(l_gpio, DLPC_GPIO_BASE, if (gpio_init(l_gpio, DLPC_GPIO_BASE,
local_gpio, ARRAY_SIZE(local_gpio)) != 0) { local_gpio, ARRAY_SIZE(local_gpio)) != 0) {
return 1; return 1;
} }
return 0;
}
static int pc87382_connect(void)
{
u8 reg;
reg = inb(DLPC_GPDO0); reg = inb(DLPC_GPDO0);
reg |= D_PLTRST | D_LPCPD; reg |= D_PLTRST | D_LPCPD;
/* Deassert D_PLTRST# and D_LPCPD# */ /* Deassert D_PLTRST# and D_LPCPD# */
@ -158,10 +156,12 @@ static void pc87382_disconnect(void)
outb(reg, DLPC_GPDO0); outb(reg, DLPC_GPDO0);
} }
/* Returns 3bit dock id */
static u8 dock_identify(void) static u8 dock_identify(void)
{ {
u8 id; u8 id;
/* Make sure GPIO LDN is configured first ! */
id = (inb(DLPC_GPDI0) >> 4) & 1; id = (inb(DLPC_GPDI0) >> 4) & 1;
id |= (inb(DLPC_GPDI2) & 3) << 1; id |= (inb(DLPC_GPDI2) & 3) << 1;
@ -172,10 +172,8 @@ static u8 dock_identify(void)
#include <superio/nsc/pc87384/pc87384.h> #include <superio/nsc/pc87384/pc87384.h>
static const pnp_devfn_t r_gpio = PNP_DEV(0x2e, PC87384_GPIO); static const pnp_devfn_t r_gpio = PNP_DEV(SUPERIO_DEV, PC87384_GPIO);
static const pnp_devfn_t r_serial = PNP_DEV(0x2e, PC87384_SP1); static const pnp_devfn_t r_serial = PNP_DEV(SUPERIO_DEV, PC87384_SP1);
#define DOCK_GPIO_BASE 0x1620
static const struct pin_config remote_gpio[] = { static const struct pin_config remote_gpio[] = {
{0x00, PC87384_GPIO_PIN_DEBOUNCE | PC87384_GPIO_PIN_PULLUP}, {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) static int pc87384_init(void)
{ {
if (poll_clk_stable(r_gpio) != 0) if (poll_clk_stable(r_gpio, 1000) != 0)
return 1; return 1;
/* set GPIO pins to Serial/Parallel Port /* set GPIO pins to Serial/Parallel Port
@ -199,9 +197,12 @@ static int pc87384_init(void)
pnp_write_config(r_gpio, 0x22, 0xa9); pnp_write_config(r_gpio, 0x22, 0xa9);
/* enable serial port */ /* enable serial port */
pnp_set_logical_device(r_serial);
pnp_set_iobase(r_serial, PNP_IDX_IO0, 0x3f8); if (CONFIG_TTYS0_BASE > 0) {
pnp_set_enable(r_serial, 1); 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, if (gpio_init(r_gpio, DOCK_GPIO_BASE,
remote_gpio, ARRAY_SIZE(remote_gpio)) != 0) remote_gpio, ARRAY_SIZE(remote_gpio)) != 0)
@ -228,14 +229,16 @@ static int pc87384_init(void)
void dock_connect(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; return;
if (pc87382_connect() != 0) { if (pc87382_connect() != 0 || pc87384_init() != 0) {
pc87382_disconnect(); pc87382_disconnect();
return; return;
} }
pc87384_init();
ec_write(H8_LED_CONTROL, ec_write(H8_LED_CONTROL,
H8_LED_CONTROL_OFF | H8_LED_CONTROL_DOCK_LED1); 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); 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) { if (id != DOCK_TYPE_NONE)
printk(BIOS_DEBUG, "dock (id=%d) is present\n", id); printk(BIOS_DEBUG, "DOCK: is present: id=%d\n", id);
dock_connect(); else
} else printk(BIOS_DEBUG, "DOCK: not connected\n");
printk(BIOS_DEBUG, "dock is not connected\n");
} }

View File

@ -16,7 +16,34 @@
#ifndef THINKPAD_T400_DOCK_H #ifndef THINKPAD_T400_DOCK_H
#define THINKPAD_T400_DOCK_H #define THINKPAD_T400_DOCK_H
#ifndef __ACPI__
int pc87382_early(void);
void dock_connect(void); void dock_connect(void);
void dock_disconnect(void); void dock_disconnect(void);
int dock_present(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 #endif

View File

@ -66,6 +66,7 @@ void mainboard_romstage_entry(unsigned long bist)
sysinfo_t sysinfo; sysinfo_t sysinfo;
int s3resume = 0; int s3resume = 0;
int cbmem_initted; int cbmem_initted;
int err;
u16 reg16; u16 reg16;
timestamp_init(get_initial_timestamp()); timestamp_init(get_initial_timestamp());
@ -81,11 +82,20 @@ void mainboard_romstage_entry(unsigned long bist)
i82801ix_early_init(); i82801ix_early_init();
early_lpc_setup(); early_lpc_setup();
dock_connect(); /* Minimal setup to detect dock */
err = pc87382_early();
if (err == 0)
dock_connect();
console_init(); console_init();
printk(BIOS_DEBUG, "running main(bist = %lu)\n", bist); 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); reg16 = pci_read_config16(LPC_DEV, D31F0_GEN_PMCON_3);
pci_write_config16(LPC_DEV, D31F0_GEN_PMCON_3, reg16); pci_write_config16(LPC_DEV, D31F0_GEN_PMCON_3, reg16);
if ((MCHBAR16(SSKPD_MCHBAR) == 0xCAFE) && !(reg16 & (1 << 9))) { if ((MCHBAR16(SSKPD_MCHBAR) == 0xCAFE) && !(reg16 & (1 << 9))) {