/* SPDX-License-Identifier: GPL-2.0-only */ #include <console/console.h> #include <device/device.h> #include <arch/io.h> #include <delay.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); dlpc_gpio_init(); return 0; } int dock_connect(void) { int timeout = 1000; 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; } /* Assert D_PLTRST# */ outb(0xfe, 0x1680); udelay(100000); /* Deassert D_PLTRST# */ outb(0xff, 0x1680); udelay(100000); /* startup 14.318MHz Clock */ dock_write_register(0x29, 0x06); /* wait until clock is settled */ timeout = 1000; 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); dock_write_register(0x07, 0x03); dock_write_register(0x30, 0x01); return 0; } void dock_disconnect(void) { printk(BIOS_DEBUG, "%s enter\n", __func__); /* disconnect LPC bus */ outb(0x00, 0x164c); udelay(10000); /* Assert PLTRST and DLPCPD */ outb(0xfc, 0x1680); udelay(10000); /* disable Ultrabay and USB Power */ outb(0x00, 0x1628); udelay(10000); printk(BIOS_DEBUG, "%s finish\n", __func__); } int dock_present(void) { return !((inw(DEFAULT_GPIOBASE + 0x0c) >> 13) & 1); } int dock_ultrabay_device_present(void) { return inb(0x1621) & 0x02 ? 0 : 1; }