Move the old docking code from romstage.c to dock.c, and use that code both in romstage and SMM code.
Signed-off-by: Sven Schnelle svens@stackframe.org --- src/mainboard/lenovo/x60/Makefile.inc | 3 +- src/mainboard/lenovo/x60/acpi/ec.asl | 6 + src/mainboard/lenovo/x60/acpi/gpe.asl | 13 ++ src/mainboard/lenovo/x60/dock.c | 249 ++++++++++++++++++++++++++++++ src/mainboard/lenovo/x60/mainboard_smi.c | 47 +++++-- src/mainboard/lenovo/x60/romstage.c | 88 ++--------- src/mainboard/lenovo/x60/smi.h | 7 + 7 files changed, 324 insertions(+), 89 deletions(-) create mode 100644 src/mainboard/lenovo/x60/dock.c create mode 100644 src/mainboard/lenovo/x60/smi.h
diff --git a/src/mainboard/lenovo/x60/Makefile.inc b/src/mainboard/lenovo/x60/Makefile.inc index fb78b3d..7515258 100644 --- a/src/mainboard/lenovo/x60/Makefile.inc +++ b/src/mainboard/lenovo/x60/Makefile.inc @@ -17,4 +17,5 @@ ## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ##
-smm-$(CONFIG_HAVE_SMI_HANDLER) += mainboard_smi.c +smm-$(CONFIG_HAVE_SMI_HANDLER) += mainboard_smi.c dock.c +romstage-y += dock.c diff --git a/src/mainboard/lenovo/x60/acpi/ec.asl b/src/mainboard/lenovo/x60/acpi/ec.asl index 81532b8..f15b5fa 100644 --- a/src/mainboard/lenovo/x60/acpi/ec.asl +++ b/src/mainboard/lenovo/x60/acpi/ec.asl @@ -19,6 +19,7 @@ * MA 02110-1301 USA */
+#include "smi.h" Device(EC) { Name (_HID, EISAID("PNP0C09")) @@ -83,6 +84,11 @@ Device(EC) \DSPC.BRTD() }
+ Method(_Q18, 0, NotSerialized) + { + TRAP(SMI_DOCK_DISCONNECT) + } + /* AC status change: present */ Method(_Q26, 0, NotSerialized) { diff --git a/src/mainboard/lenovo/x60/acpi/gpe.asl b/src/mainboard/lenovo/x60/acpi/gpe.asl index 1c5d1bd..31d60f2 100644 --- a/src/mainboard/lenovo/x60/acpi/gpe.asl +++ b/src/mainboard/lenovo/x60/acpi/gpe.asl @@ -1,3 +1,4 @@ +#include "smi.h" Scope (_GPE) { Method(_L18, 0, NotSerialized) @@ -5,4 +6,16 @@ Scope (_GPE) /* Read EC register to clear wake status */ Store(_SB.PCI0.LPCB.EC.WAKE, Local0) } + + /* SLICE_ON_3M GPE (Dock status) */ + Method(_L1D, 0, NotSerialized) + { + if (GP13) { + Or(GIV1, 0x20, GIV1) + TRAP(SMI_DOCK_DISCONNECT) + } else { + And(GIV1, 0xdf, GIV1) + TRAP(SMI_DOCK_CONNECT) + } + } } diff --git a/src/mainboard/lenovo/x60/dock.c b/src/mainboard/lenovo/x60/dock.c new file mode 100644 index 0000000..b64d864 --- /dev/null +++ b/src/mainboard/lenovo/x60/dock.c @@ -0,0 +1,249 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011 Sven Schnelle svens@stackframe.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of + * the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include <console/console.h> +#include <device/device.h> +#include <arch/io.h> +#include <boot/tables.h> +#include <delay.h> +#include <arch/io.h> +#include "dock.h" +#include "southbridge/intel/i82801gx/i82801gx.h" +#include "superio/nsc/pc87392/pc87392.h" + +static void dlpc_write_register(int reg, int value) +{ + outb(reg, 0x164e); + outb(value, 0x164f); +} + +static u8 dlpc_read_register(int reg) +{ + outb(reg, 0x164e); + return inb(0x164f); +} + +static void dock_write_register(int reg, int value) +{ + outb(reg, 0x2e); + outb(value, 0x2f); +} + +static u8 dock_read_register(int reg) +{ + outb(reg, 0x2e); + return inb(0x2f); +} + +static void dlpc_gpio_set_mode(int port, int mode) +{ + dlpc_write_register(0xf0, port); + dlpc_write_register(0xf1, mode); +} + +static void dock_gpio_set_mode(int port, int mode, int irq) +{ + dock_write_register(0xf0, port); + dock_write_register(0xf1, mode); + dock_write_register(0xf2, irq); +} + +static void dlpc_gpio_init(void) +{ + /* Select GPIO module */ + dlpc_write_register(0x07, 0x07); + /* GPIO Base Address 0x1680 */ + dlpc_write_register(0x60, 0x16); + dlpc_write_register(0x61, 0x80); + + /* Activate GPIO */ + dlpc_write_register(0x30, 0x01); + + dlpc_gpio_set_mode(0x00, 3); + dlpc_gpio_set_mode(0x01, 3); + dlpc_gpio_set_mode(0x02, 0); + dlpc_gpio_set_mode(0x03, 3); + dlpc_gpio_set_mode(0x04, 4); + dlpc_gpio_set_mode(0x20, 4); + dlpc_gpio_set_mode(0x21, 4); + dlpc_gpio_set_mode(0x23, 4); +} + +int dlpc_init(void) +{ + int timeout = 1000; + + /* Enable 14.318MHz CLK on CLKIN */ + dlpc_write_register(0x29, 0xa0); + while(!(dlpc_read_register(0x29) & 0x10) && timeout--) + udelay(1000); + + if (!timeout) + return 1; + + /* Select DLPC module */ + dlpc_write_register(0x07, 0x19); + /* DLPC Base Address 0x164c */ + dlpc_write_register(0x60, 0x16); + dlpc_write_register(0x61, 0x4c); + /* Activate DLPC */ + dlpc_write_register(0x30, 0x01); + + outb(0x07, 0x164c); + + timeout = 1000; + + while(!(inb(0x164c) & 8) && timeout--) + udelay(1000); + + if (!timeout) { + /* docking failed, disable DLPC switch */ + outb(0x00, 0x164c); + dlpc_write_register(0x30, 0x00); + return 1; + } + + dlpc_gpio_init(); + + return 0; +} + +int dock_connect(void) +{ + int timeout = 1000; + + /* Assert D_PLTRST# */ + outb(0xfe, 0x1680); + udelay(1000); + /* Deassert D_PLTRST# */ + outb(0xff, 0x1680); + + /* startup 14.318MHz Clock */ + dock_write_register(0x29, 0x06); + /* wait until clock is settled */ + while(!(dock_read_register(0x29) & 0x08) && timeout--) + udelay(1000); + + if (!timeout) + return 1; + + /* Pin 6: CLKRUN + * Pin 72: #DR1 + * Pin 19: #SMI + * Pin 73: #MTR + */ + dock_write_register(0x24, 0x37); + + /* PNF active HIGH */ + dock_write_register(0x25, 0xa0); + + /* disable FDC */ + dock_write_register(0x26, 0x01); + + /* Enable GPIO IRQ to #SMI */ + dock_write_register(0x28, 0x02); + + /* select GPIO */ + dock_write_register(0x07, 0x07); + + /* set base address */ + dock_write_register(0x60, 0x16); + dock_write_register(0x61, 0x20); + + /* init GPIO pins */ + dock_gpio_set_mode(0x00, PC87392_GPIO_PIN_DEBOUNCE | + PC87392_GPIO_PIN_PULLUP, 0x00); + + dock_gpio_set_mode(0x01, PC87392_GPIO_PIN_DEBOUNCE | + PC87392_GPIO_PIN_PULLUP, + PC87392_GPIO_PIN_TRIGGERS_SMI); + + dock_gpio_set_mode(0x02, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x03, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x04, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x05, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x06, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x07, PC87392_GPIO_PIN_PULLUP, 0x02); + + dock_gpio_set_mode(0x10, PC87392_GPIO_PIN_DEBOUNCE | + PC87392_GPIO_PIN_PULLUP, + PC87392_GPIO_PIN_TRIGGERS_SMI); + + dock_gpio_set_mode(0x11, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x12, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x13, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x14, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x15, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x16, PC87392_GPIO_PIN_PULLUP | + PC87392_GPIO_PIN_OE , 0x00); + + dock_gpio_set_mode(0x17, PC87392_GPIO_PIN_PULLUP, 0x00); + + dock_gpio_set_mode(0x20, PC87392_GPIO_PIN_TYPE_PUSH_PULL | + PC87392_GPIO_PIN_OE, 0x00); + + dock_gpio_set_mode(0x21, PC87392_GPIO_PIN_TYPE_PUSH_PULL | + PC87392_GPIO_PIN_OE, 0x00); + + dock_gpio_set_mode(0x22, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x23, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x24, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x25, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x26, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x27, PC87392_GPIO_PIN_PULLUP, 0x00); + + dock_gpio_set_mode(0x30, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x31, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x32, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x33, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x34, PC87392_GPIO_PIN_PULLUP, 0x00); + + dock_gpio_set_mode(0x35, PC87392_GPIO_PIN_PULLUP | + PC87392_GPIO_PIN_OE, 0x00); + + dock_gpio_set_mode(0x36, PC87392_GPIO_PIN_PULLUP, 0x00); + dock_gpio_set_mode(0x37, PC87392_GPIO_PIN_PULLUP, 0x00); + + /* enable GPIO */ + dock_write_register(0x30, 0x01); + + outb(0x00, 0x1628); + outb(0x00, 0x1623); + outb(0x82, 0x1622); + outb(0xff, 0x1624); + + /* Enable USB and Ultrabay power */ + outb(0x03, 0x1628); + return 0; +} + +void dock_disconnect(void) +{ + /* disconnect LPC bus */ + outb(0x00, 0x164c); + /* Assert PLTRST and DLPCPD */ + outb(0xfc, 0x1680); +} + +int dock_present(void) +{ + return !((inb(DEFAULT_GPIOBASE + 0x0c) >> 13) & 1); +} diff --git a/src/mainboard/lenovo/x60/mainboard_smi.c b/src/mainboard/lenovo/x60/mainboard_smi.c index 6736ace..5e0f6a9 100644 --- a/src/mainboard/lenovo/x60/mainboard_smi.c +++ b/src/mainboard/lenovo/x60/mainboard_smi.c @@ -24,30 +24,55 @@ #include <console/console.h> #include <cpu/x86/smm.h> #include "southbridge/intel/i82801gx/nvs.h" +#include <ec/acpi/ec.h> +#include "dock.h" +#include "smi.h"
/* The southbridge SMI handler checks whether gnvs has a * valid pointer before calling the trap handler */ extern global_nvs_t *gnvs;
+static void mainboard_smm_init(void) +{ + printk(BIOS_DEBUG, "initializing SMI\n"); + /* Enable 0x1600/0x1600 register pair */ + ec_set_bit(0x00, 0x05); + ec_set_ports(0x1604, 0x1600); +} + int mainboard_io_trap_handler(int smif) { + static int smm_initialized; + + if (!smm_initialized) { + mainboard_smm_init(); + smm_initialized = 1; + } + switch (smif) { - case 0x99: - printk(BIOS_DEBUG, "Sample\n"); - //gnvs->smif = 0; + case SMI_DOCK_CONNECT: + dlpc_init(); + if (!dock_connect()) { + /* set dock LED to indicate status */ + ec_write(0x0c, 0x88); + } else { + /* blink dock LED to indicate failure */ + ec_write(0x0c, 0xc8); + } + break; + + case SMI_DOCK_DISCONNECT: + dock_disconnect(); + ec_write(0x0c, 0x08); break; + default: - return 0; + return 1; }
/* On success, the IO Trap Handler returns 0 - * On failure, the IO Trap Handler returns a value != 0 - * - * For now, we force the return value to 0 and log all traps to - * see what's going on. - */ - //gnvs->smif = 0; - return 1; + * On failure, the IO Trap Handler returns a value != 0 */ + return 0; }
diff --git a/src/mainboard/lenovo/x60/romstage.c b/src/mainboard/lenovo/x60/romstage.c index e2b4a40..bdc2200 100644 --- a/src/mainboard/lenovo/x60/romstage.c +++ b/src/mainboard/lenovo/x60/romstage.c @@ -37,6 +37,7 @@ #include "northbridge/intel/i945/i945.h" #include "northbridge/intel/i945/raminit.h" #include "southbridge/intel/i82801gx/i82801gx.h" +#include "dock.h"
void setup_ich7_gpios(void) { @@ -107,78 +108,6 @@ static void pnp_write_register(device_t dev, int reg, int val) outb(val, port+1); }
-static void dock_write_register(int reg, int value) -{ - outb(reg, 0x164e); - outb(value, 0x164f); - /* original software reads the chip id after every - I/O operation. Not sure if they are doing it for - some code switching depending on hardware or just - to have a delay after every operation. - - Do it the same way for now, we may remove it later - if it isn't needed - */ - outb(0x20, 0x164e); - inb(0x164f); -} - -static void dock_dlpc_init(void) -{ - /* Select DLPC module */ - dock_write_register(0x07, 0x19); - /* DLPC Base Address 0x164c */ - dock_write_register(0x60, 0x16); - dock_write_register(0x61, 0x4c); - /* Activate DLPC */ - dock_write_register(0x30, 0x01); - outb(0x07, 0x164c); - - while(!(inb(0x164c) & 8)) - udelay(100 * 100); -} - -static void dock_gpio_set_mode(int port, int mode) -{ - dock_write_register(0xf0, port); - dock_write_register(0xf1, mode); - -} - -static void dock_gpio_init(void) -{ - /* Select GPIO module */ - dock_write_register(0x07, 0x07); - /* GPIO Base Address 0x1680 */ - dock_write_register(0x60, 0x16); - dock_write_register(0x61, 0x80); - - /* Activate GPIO */ - dock_write_register(0x30, 0x01); - - dock_gpio_set_mode(0x00, 3); - dock_gpio_set_mode(0x01, 3); - dock_gpio_set_mode(0x02, 0); - dock_gpio_set_mode(0x03, 3); - dock_gpio_set_mode(0x04, 4); - dock_gpio_set_mode(0x20, 4); - dock_gpio_set_mode(0x21, 4); - dock_gpio_set_mode(0x23, 4); -} - -static void connect_dock(void) -{ - /* Enable 14.318MHz CLK on CLKIN */ - dock_write_register(0x29, 0x00); - dock_write_register(0x29, 0xa0); - dock_gpio_init(); - /* Assert D_PLTRST# */ - outb(0xfe, 0x1680); - dock_dlpc_init(); - /* Deassert D_PLTRST# */ - outb(0xff, 0x1680); -} - static void early_superio_config(void) { device_t dev; @@ -306,12 +235,17 @@ void main(unsigned long bist)
ich7_enable_lpc();
- connect_dock(); - - early_superio_config();
- /* Set up the console */ - uart_init(); + /* dock_init initializes the DLPC switch on + * thinpad side, so this is required even + * if we're undocked. + */ + if (!dlpc_init() && dock_present()) { + dock_connect(); + early_superio_config(); + /* Set up the console */ + uart_init(); + }
#if CONFIG_USBDEBUG i82801gx_enable_usbdebug(1); diff --git a/src/mainboard/lenovo/x60/smi.h b/src/mainboard/lenovo/x60/smi.h new file mode 100644 index 0000000..6eb8402 --- /dev/null +++ b/src/mainboard/lenovo/x60/smi.h @@ -0,0 +1,7 @@ +#ifndef MAINBOARD_LENOVO_X60_SMI_H +#define MAINBOARD_LENOVO_X60_SMI_H + +#define SMI_DOCK_CONNECT 0x01 +#define SMI_DOCK_DISCONNECT 0x02 + +#endif