T60: Add support for Ultrabay Legacy I/O devices (40Y8122)
authorSven Schnelle <svens@stackframe.org>
Sat, 15 Oct 2011 15:31:01 +0000 (17:31 +0200)
committerSven Schnelle <svens@stackframe.org>
Thu, 20 Oct 2011 14:06:35 +0000 (16:06 +0200)
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)
src/ec/lenovo/pmh7/Makefile.inc
src/ec/lenovo/pmh7/pmh7.c
src/mainboard/lenovo/t60/dock.c
src/mainboard/lenovo/t60/dock.h
src/mainboard/lenovo/t60/mainboard.c
src/mainboard/lenovo/t60/mainboard_smi.c
src/mainboard/lenovo/t60/romstage.c

index 4c891b25ab2bd7cb0b35e33f8f64989b2eb8aa20..e441980defb5b42b78873ff65ae4493aeed0ef2e 100644 (file)
@@ -1 +1,3 @@
 driver-y += pmh7.c
+smm-$(CONFIG_HAVE_SMI_HANDLER) += pmh7.c
+romstage-y += pmh7.c
index 30460c9021aa6486dc72308012b09f7ce1bcc5d5..844e233e9f0605c2e2b908a1e37358fb90cbc208 100644 (file)
@@ -91,6 +91,8 @@ void pmh7_register_write(int reg, int val)
        outb(val, EC_LENOVO_PMH7_DATA);
 }
 
+#ifndef __PRE_RAM__
+#ifndef __SMM__
 static void enable_dev(device_t dev)
 {
        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")
        .enable_dev = enable_dev,
 };
+#endif
+#endif
index 6642bb37594ac7784cd3ef45381e18ce24b64d59..5cd8997355fbf2e2150a012f024a550f778cc3b1 100644 (file)
 #include "dock.h"
 #include "superio/nsc/pc87384/pc87384.h"
 #include "ec/acpi/ec.h"
+#include "ec/lenovo/pmh7/pmh7.h"
 #include "southbridge/intel/i82801gx/i82801gx.h"
 
+#define DLPC_CONTROL 0x164c
+
 static void dlpc_write_register(int reg, int value)
 {
        outb(reg, 0x164e);
@@ -102,12 +105,15 @@ int dlpc_init(void)
 
        /* Select DLPC module */
        dlpc_write_register(0x07, 0x19);
-       /* DLPC Base Address 0x164c */
-       dlpc_write_register(0x60, 0x16);
-       dlpc_write_register(0x61, 0x4c);
+       /* DLPC Base Address */
+       dlpc_write_register(0x60, (DLPC_CONTROL >> 8) & 0xff);
+       dlpc_write_register(0x61, DLPC_CONTROL & 0xff);
        /* Activate DLPC */
        dlpc_write_register(0x30, 0x01);
 
+       /* Reset docking state */
+       outb(0x00, DLPC_CONTROL);
+
        dlpc_gpio_init();
        return 0;
 }
@@ -127,7 +133,7 @@ static int dock_superio_init(void)
        /* set GPIO pins to Serial/Parallel Port
         * functions
         */
-       dock_write_register(0x22, 0xeb);
+       dock_write_register(0x22, 0xa9);
 
        dock_write_register(0x07, PC87384_GPIO);
        dock_write_register(0x60, 0x16);
@@ -179,16 +185,16 @@ int dock_connect(void)
 {
        int timeout = 1000;
 
-       outb(0x07, 0x164c);
+       outb(0x07, DLPC_CONTROL);
 
        timeout = 1000;
 
-       while(!(inb(0x164c) & 8) && timeout--)
+       while(!(inb(DLPC_CONTROL) & 8) && timeout--)
                udelay(1000);
 
        if (!timeout) {
                /* docking failed, disable DLPC switch */
-               outb(0x00, 0x164c);
+               outb(0x00, DLPC_CONTROL);
                dlpc_write_register(0x30, 0x00);
                return 1;
        }
@@ -206,14 +212,25 @@ int dock_connect(void)
 void dock_disconnect(void)
 {
        /* disconnect LPC bus */
-       outb(0x00, 0x164c);
+       outb(0x00, DLPC_CONTROL);
        /* Assert PLTRST and DLPCPD */
        outb(0xfc, 0x1680);
 }
 
 int dock_present(void)
 {
-       outb(0x61, 0x15ec);
-       return inb(0x15ee) & 1;
+       return pmh7_register_read(0x61) & 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();
+}
index 9d35d9faf5ecfdd11913cb9e087d6ad463bfba47..631f007488398899bae73b139092c1e454d237ec 100644 (file)
@@ -24,4 +24,7 @@ extern int dock_connect(void);
 extern void dock_disconnect(void);
 extern int dock_present(void);
 extern int dlpc_init(void);
+
+extern int legacy_io_present(void);
+extern void legacy_io_init(void);
 #endif
index 2b8c5fe4b12f6e53ff1c1be702ab1d1d373d421d..8456992044e4aac464eecd0fc808662c67ef5cd9 100644 (file)
@@ -38,6 +38,7 @@
 
 static void mainboard_enable(device_t dev)
 {
+       struct southbridge_intel_i82801gx_config *config;
        device_t dev0, idedev;
        u8 defaults_loaded = 0;
 
@@ -50,8 +51,14 @@ static void mainboard_enable(device_t dev)
                ec_write(0x0c, 0xc7);
 
        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;
                pmh7_ultrabay_power_enable(1);
                ec_write(0x0c, 0x84);
index 4a0b5062c9c6c3e3074d448c4b0f9d840bf60159..eb282564af3d567ec475887e58720fc8d96c1504 100644 (file)
@@ -75,7 +75,13 @@ int mainboard_io_trap_handler(int smif)
 
        switch (smif) {
        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()) {
                        /* set dock LED to indicate status */
                        ec_write(0x0c, 0x08);
index 252ae40023e3516a8a7ec5ee8688ad389720dc5a..7ed776830ea65a6ff1d815cfb9890c790353dc0f 100644 (file)
@@ -210,7 +210,7 @@ static void early_ich7_init(void)
 void main(unsigned long bist)
 {
        u32 reg32;
-       int boot_mode = 0;
+       int boot_mode = 0, dock_err;
        const u8 spd_addrmap[2 * DIMM_SOCKETS] = { 0x50, 0x52, 0x51, 0x53 };
 
        if (bist == 0)
@@ -223,15 +223,21 @@ void main(unsigned long bist)
 
        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
-        *  thinpad side, so this is required even
-        *  if we're undocked.
-        */
-       if (!dlpc_init() && dock_present()) {
+       dock_err = dlpc_init();
+
+       /* We prefer Legacy I/O module over docking */
+       if (legacy_io_present()) {
+               legacy_io_init();
+               early_superio_config();
+       } else if (!dock_err && dock_present()) {
                dock_connect();
                early_superio_config();
-               /* Set up the console */
        }
 
 #if CONFIG_USBDEBUG
@@ -239,6 +245,7 @@ void main(unsigned long bist)
        early_usbdebug_init();
 #endif
 
+       /* Setup the console */
        console_init();
 
        /* Halt if there was a built in self test failure */