T60: Add support for Ultrabay Legacy I/O devices (40Y8122)
Those modules have basically the same Super I/O capabilities as the Docking station. Unfortunately, the Super I/O in the module shares the same I/O address as the Docking station, so we're not allowed to connect the LPC Docking Bus if such a module is present. To be able to detect this device and use it as early console for coreboot, we have to initialize the GPIO Controller before, as this device is detected via GPIO06. Change-Id: If7c38bb6797f76cf28f09f3614ab9a33878571fb Signed-off-by: Sven Schnelle <svens@stackframe.org> Reviewed-on: http://review.coreboot.org/282 Tested-by: build bot (Jenkins)
This commit is contained in:
parent
2588db496d
commit
b538110532
|
@ -1 +1,3 @@
|
||||||
driver-y += pmh7.c
|
driver-y += pmh7.c
|
||||||
|
smm-$(CONFIG_HAVE_SMI_HANDLER) += pmh7.c
|
||||||
|
romstage-y += pmh7.c
|
||||||
|
|
|
@ -91,6 +91,8 @@ void pmh7_register_write(int reg, int val)
|
||||||
outb(val, EC_LENOVO_PMH7_DATA);
|
outb(val, EC_LENOVO_PMH7_DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef __PRE_RAM__
|
||||||
|
#ifndef __SMM__
|
||||||
static void enable_dev(device_t dev)
|
static void enable_dev(device_t dev)
|
||||||
{
|
{
|
||||||
struct ec_lenovo_pmh7_config *conf = dev->chip_info;
|
struct ec_lenovo_pmh7_config *conf = dev->chip_info;
|
||||||
|
@ -115,3 +117,5 @@ struct chip_operations ec_lenovo_pmh7_ops = {
|
||||||
CHIP_NAME("Lenovo Power Management Hardware Hub 7")
|
CHIP_NAME("Lenovo Power Management Hardware Hub 7")
|
||||||
.enable_dev = enable_dev,
|
.enable_dev = enable_dev,
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
|
@ -28,8 +28,11 @@
|
||||||
#include "dock.h"
|
#include "dock.h"
|
||||||
#include "superio/nsc/pc87384/pc87384.h"
|
#include "superio/nsc/pc87384/pc87384.h"
|
||||||
#include "ec/acpi/ec.h"
|
#include "ec/acpi/ec.h"
|
||||||
|
#include "ec/lenovo/pmh7/pmh7.h"
|
||||||
#include "southbridge/intel/i82801gx/i82801gx.h"
|
#include "southbridge/intel/i82801gx/i82801gx.h"
|
||||||
|
|
||||||
|
#define DLPC_CONTROL 0x164c
|
||||||
|
|
||||||
static void dlpc_write_register(int reg, int value)
|
static void dlpc_write_register(int reg, int value)
|
||||||
{
|
{
|
||||||
outb(reg, 0x164e);
|
outb(reg, 0x164e);
|
||||||
|
@ -102,12 +105,15 @@ int dlpc_init(void)
|
||||||
|
|
||||||
/* Select DLPC module */
|
/* Select DLPC module */
|
||||||
dlpc_write_register(0x07, 0x19);
|
dlpc_write_register(0x07, 0x19);
|
||||||
/* DLPC Base Address 0x164c */
|
/* DLPC Base Address */
|
||||||
dlpc_write_register(0x60, 0x16);
|
dlpc_write_register(0x60, (DLPC_CONTROL >> 8) & 0xff);
|
||||||
dlpc_write_register(0x61, 0x4c);
|
dlpc_write_register(0x61, DLPC_CONTROL & 0xff);
|
||||||
/* Activate DLPC */
|
/* Activate DLPC */
|
||||||
dlpc_write_register(0x30, 0x01);
|
dlpc_write_register(0x30, 0x01);
|
||||||
|
|
||||||
|
/* Reset docking state */
|
||||||
|
outb(0x00, DLPC_CONTROL);
|
||||||
|
|
||||||
dlpc_gpio_init();
|
dlpc_gpio_init();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -127,7 +133,7 @@ static int dock_superio_init(void)
|
||||||
/* set GPIO pins to Serial/Parallel Port
|
/* set GPIO pins to Serial/Parallel Port
|
||||||
* functions
|
* functions
|
||||||
*/
|
*/
|
||||||
dock_write_register(0x22, 0xeb);
|
dock_write_register(0x22, 0xa9);
|
||||||
|
|
||||||
dock_write_register(0x07, PC87384_GPIO);
|
dock_write_register(0x07, PC87384_GPIO);
|
||||||
dock_write_register(0x60, 0x16);
|
dock_write_register(0x60, 0x16);
|
||||||
|
@ -179,16 +185,16 @@ int dock_connect(void)
|
||||||
{
|
{
|
||||||
int timeout = 1000;
|
int timeout = 1000;
|
||||||
|
|
||||||
outb(0x07, 0x164c);
|
outb(0x07, DLPC_CONTROL);
|
||||||
|
|
||||||
timeout = 1000;
|
timeout = 1000;
|
||||||
|
|
||||||
while(!(inb(0x164c) & 8) && timeout--)
|
while(!(inb(DLPC_CONTROL) & 8) && timeout--)
|
||||||
udelay(1000);
|
udelay(1000);
|
||||||
|
|
||||||
if (!timeout) {
|
if (!timeout) {
|
||||||
/* docking failed, disable DLPC switch */
|
/* docking failed, disable DLPC switch */
|
||||||
outb(0x00, 0x164c);
|
outb(0x00, DLPC_CONTROL);
|
||||||
dlpc_write_register(0x30, 0x00);
|
dlpc_write_register(0x30, 0x00);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -206,14 +212,25 @@ int dock_connect(void)
|
||||||
void dock_disconnect(void)
|
void dock_disconnect(void)
|
||||||
{
|
{
|
||||||
/* disconnect LPC bus */
|
/* disconnect LPC bus */
|
||||||
outb(0x00, 0x164c);
|
outb(0x00, DLPC_CONTROL);
|
||||||
/* Assert PLTRST and DLPCPD */
|
/* Assert PLTRST and DLPCPD */
|
||||||
outb(0xfc, 0x1680);
|
outb(0xfc, 0x1680);
|
||||||
}
|
}
|
||||||
|
|
||||||
int dock_present(void)
|
int dock_present(void)
|
||||||
{
|
{
|
||||||
outb(0x61, 0x15ec);
|
return pmh7_register_read(0x61) & 1;
|
||||||
return inb(0x15ee) & 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int legacy_io_present(void)
|
||||||
|
{
|
||||||
|
return !(inb(DEFAULT_GPIOBASE + 0x0c) & 0x40);
|
||||||
|
}
|
||||||
|
|
||||||
|
void legacy_io_init(void)
|
||||||
|
{
|
||||||
|
/* Enable Power for Ultrabay slot */
|
||||||
|
pmh7_ultrabay_power_enable(1);
|
||||||
|
udelay(100000);
|
||||||
|
dock_superio_init();
|
||||||
|
}
|
||||||
|
|
|
@ -24,4 +24,7 @@ extern int dock_connect(void);
|
||||||
extern void dock_disconnect(void);
|
extern void dock_disconnect(void);
|
||||||
extern int dock_present(void);
|
extern int dock_present(void);
|
||||||
extern int dlpc_init(void);
|
extern int dlpc_init(void);
|
||||||
|
|
||||||
|
extern int legacy_io_present(void);
|
||||||
|
extern void legacy_io_init(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
|
|
||||||
static void mainboard_enable(device_t dev)
|
static void mainboard_enable(device_t dev)
|
||||||
{
|
{
|
||||||
|
struct southbridge_intel_i82801gx_config *config;
|
||||||
device_t dev0, idedev;
|
device_t dev0, idedev;
|
||||||
u8 defaults_loaded = 0;
|
u8 defaults_loaded = 0;
|
||||||
|
|
||||||
|
@ -50,8 +51,14 @@ static void mainboard_enable(device_t dev)
|
||||||
ec_write(0x0c, 0xc7);
|
ec_write(0x0c, 0xc7);
|
||||||
|
|
||||||
idedev = dev_find_slot(0, PCI_DEVFN(0x1f,1));
|
idedev = dev_find_slot(0, PCI_DEVFN(0x1f,1));
|
||||||
if (idedev && idedev->chip_info && h8_ultrabay_device_present()) {
|
|
||||||
struct southbridge_intel_i82801gx_config *config = idedev->chip_info;
|
if (!(inb(DEFAULT_GPIOBASE + 0x0c) & 0x40)) {
|
||||||
|
/* legacy I/O connected */
|
||||||
|
pmh7_ultrabay_power_enable(1);
|
||||||
|
ec_write(0x0c, 0x84);
|
||||||
|
} else if (idedev && idedev->chip_info &&
|
||||||
|
h8_ultrabay_device_present()) {
|
||||||
|
config = idedev->chip_info;
|
||||||
config->ide_enable_primary = 1;
|
config->ide_enable_primary = 1;
|
||||||
pmh7_ultrabay_power_enable(1);
|
pmh7_ultrabay_power_enable(1);
|
||||||
ec_write(0x0c, 0x84);
|
ec_write(0x0c, 0x84);
|
||||||
|
|
|
@ -75,7 +75,13 @@ int mainboard_io_trap_handler(int smif)
|
||||||
|
|
||||||
switch (smif) {
|
switch (smif) {
|
||||||
case SMI_DOCK_CONNECT:
|
case SMI_DOCK_CONNECT:
|
||||||
dlpc_init();
|
/* If there's an legacy I/O module present, we're not
|
||||||
|
* allowed to connect the Docking LPC Bus, as both Super I/O
|
||||||
|
* chips are using 0x2e as base address.
|
||||||
|
*/
|
||||||
|
if (legacy_io_present())
|
||||||
|
break;
|
||||||
|
|
||||||
if (!dock_connect()) {
|
if (!dock_connect()) {
|
||||||
/* set dock LED to indicate status */
|
/* set dock LED to indicate status */
|
||||||
ec_write(0x0c, 0x08);
|
ec_write(0x0c, 0x08);
|
||||||
|
|
|
@ -210,7 +210,7 @@ static void early_ich7_init(void)
|
||||||
void main(unsigned long bist)
|
void main(unsigned long bist)
|
||||||
{
|
{
|
||||||
u32 reg32;
|
u32 reg32;
|
||||||
int boot_mode = 0;
|
int boot_mode = 0, dock_err;
|
||||||
const u8 spd_addrmap[2 * DIMM_SOCKETS] = { 0x50, 0x52, 0x51, 0x53 };
|
const u8 spd_addrmap[2 * DIMM_SOCKETS] = { 0x50, 0x52, 0x51, 0x53 };
|
||||||
|
|
||||||
if (bist == 0)
|
if (bist == 0)
|
||||||
|
@ -223,15 +223,21 @@ void main(unsigned long bist)
|
||||||
|
|
||||||
ich7_enable_lpc();
|
ich7_enable_lpc();
|
||||||
|
|
||||||
|
/* We want early GPIO setup, to be able to detect legacy I/O module */
|
||||||
|
pci_write_config32(PCI_DEV(0, 0x1f, 0), GPIOBASE, DEFAULT_GPIOBASE | 1);
|
||||||
|
/* Enable GPIOs */
|
||||||
|
pci_write_config8(PCI_DEV(0, 0x1f, 0), 0x4c /* GC */ , 0x10);
|
||||||
|
setup_ich7_gpios();
|
||||||
|
|
||||||
/* dock_init initializes the DLPC switch on
|
dock_err = dlpc_init();
|
||||||
* thinpad side, so this is required even
|
|
||||||
* if we're undocked.
|
/* We prefer Legacy I/O module over docking */
|
||||||
*/
|
if (legacy_io_present()) {
|
||||||
if (!dlpc_init() && dock_present()) {
|
legacy_io_init();
|
||||||
|
early_superio_config();
|
||||||
|
} else if (!dock_err && dock_present()) {
|
||||||
dock_connect();
|
dock_connect();
|
||||||
early_superio_config();
|
early_superio_config();
|
||||||
/* Set up the console */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if CONFIG_USBDEBUG
|
#if CONFIG_USBDEBUG
|
||||||
|
@ -239,6 +245,7 @@ void main(unsigned long bist)
|
||||||
early_usbdebug_init();
|
early_usbdebug_init();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Setup the console */
|
||||||
console_init();
|
console_init();
|
||||||
|
|
||||||
/* Halt if there was a built in self test failure */
|
/* Halt if there was a built in self test failure */
|
||||||
|
|
Loading…
Reference in New Issue