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:
parent
d2c2f83964
commit
c0a1625df1
|
@ -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.
|
||||||
|
|
|
@ -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");
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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))) {
|
||||||
|
|
Loading…
Reference in New Issue