From 045f153a4fe2b6e1cb193db01866218d0316f253 Mon Sep 17 00:00:00 2001 From: Duncan Laurie Date: Mon, 17 Dec 2012 11:29:10 -0800 Subject: lynxpoint: Add new GPIO interface for Lynxpoint-LP The low power variant of the chipset introduces a completely new interface to the GPIOs. This is a 1KB region and so needs to be moved as well so it does not conflict with other IO regions. Also expose the gpio_get functions to ramstage and move the prototypes to pch.h so they can be used for both GPIO interfaces. Change-Id: I20bc18669525af16de8cdf99f0ccfa9612be63ad Signed-off-by: Duncan Laurie Reviewed-on: http://review.coreboot.org/2648 Tested-by: build bot (Jenkins) Reviewed-by: Marc Jones --- src/southbridge/intel/lynxpoint/Makefile.inc | 10 ++- src/southbridge/intel/lynxpoint/acpi/lpc.asl | 17 +++- src/southbridge/intel/lynxpoint/gpio.c | 20 ++++- src/southbridge/intel/lynxpoint/gpio.h | 24 ++++-- src/southbridge/intel/lynxpoint/lp_gpio.c | 113 +++++++++++++++++++++++++++ src/southbridge/intel/lynxpoint/lp_gpio.h | 110 ++++++++++++++++++++++++++ src/southbridge/intel/lynxpoint/lpc.c | 9 ++- src/southbridge/intel/lynxpoint/pch.h | 35 ++++----- 8 files changed, 307 insertions(+), 31 deletions(-) create mode 100644 src/southbridge/intel/lynxpoint/lp_gpio.c create mode 100644 src/southbridge/intel/lynxpoint/lp_gpio.h diff --git a/src/southbridge/intel/lynxpoint/Makefile.inc b/src/southbridge/intel/lynxpoint/Makefile.inc index d4522c35fd..c14a53881d 100644 --- a/src/southbridge/intel/lynxpoint/Makefile.inc +++ b/src/southbridge/intel/lynxpoint/Makefile.inc @@ -45,10 +45,18 @@ smm-$(CONFIG_SPI_FLASH_SMM) += spi.c ramstage-$(CONFIG_HAVE_SMI_HANDLER) += smi.c smm-$(CONFIG_HAVE_SMI_HANDLER) += smihandler.c me_9.x.c finalize.c -romstage-y += early_usb.c early_smbus.c early_me.c me_status.c gpio.c +romstage-y += early_usb.c early_smbus.c early_me.c me_status.c romstage-$(CONFIG_USBDEBUG) += usb_debug.c romstage-y += reset.c early_spi.c +ifeq ($(CONFIG_INTEL_LYNXPOINT_LP),y) +romstage-y += lp_gpio.c +ramstage-y += lp_gpio.c +else +romstage-y += gpio.c +ramstage-y += gpio.c +endif + lynxpoint_add_me: $(obj)/coreboot.pre $(IFDTOOL) printf " DD Adding Intel Firmware Descriptor\n" dd if=3rdparty/mainboard/$(MAINBOARDDIR)/descriptor.bin \ diff --git a/src/southbridge/intel/lynxpoint/acpi/lpc.asl b/src/southbridge/intel/lynxpoint/acpi/lpc.asl index cc59850ec4..03d61ebd3b 100644 --- a/src/southbridge/intel/lynxpoint/acpi/lpc.asl +++ b/src/southbridge/intel/lynxpoint/acpi/lpc.asl @@ -194,7 +194,22 @@ Device (LPCB) IO (Decode16, 0xb2, 0xb2, 0x1, 0x02) // SWSMI //IO (Decode16, 0x800, 0x800, 0x1, 0x10) // ACPI I/O trap IO (Decode16, DEFAULT_PMBASE, DEFAULT_PMBASE, 0x1, 0x80) // ICH7-M ACPI - IO (Decode16, DEFAULT_GPIOBASE, DEFAULT_GPIOBASE, 0x1, 0x40) // ICH7-M GPIO + +#if CONFIG_INTEL_LYNXPOINT_LP + // LynxPoint LP GPIO is 1KB + IO (Decode16, DEFAULT_GPIOBASE, + DEFAULT_GPIOBASE, 0x1, 0xff) + IO (Decode16, Add(DEFAULT_GPIOBASE, 0x100), + Add(DEFAULT_GPIOBASE, 0x100), 0x1, 0xff) + IO (Decode16, Add(DEFAULT_GPIOBASE, 0x200), + Add(DEFAULT_GPIOBASE, 0x200), 0x1, 0xff) + IO (Decode16, Add(DEFAULT_GPIOBASE, 0x300), + Add(DEFAULT_GPIOBASE, 0x300), 0x1, 0xff) +#else + // LynxPoint GPIO is 128 bytes + IO (Decode16, DEFAULT_GPIOBASE, + DEFAULT_GPIOBASE, 0x1, DEFAULT_GPIOSIZE) +#endif }) } diff --git a/src/southbridge/intel/lynxpoint/gpio.c b/src/southbridge/intel/lynxpoint/gpio.c index 25eda9a74c..9d36887dd1 100644 --- a/src/southbridge/intel/lynxpoint/gpio.c +++ b/src/southbridge/intel/lynxpoint/gpio.c @@ -20,16 +20,32 @@ #include #include #include + +#ifdef __PRE_RAM__ #include +#else +#include +#include +#endif #include "pch.h" #include "gpio.h" #define MAX_GPIO_NUMBER 75 /* zero based */ +static u16 get_gpio_base(void) +{ +#ifdef __PRE_RAM__ + return pci_read_config16(PCH_LPC_DEV, GPIO_BASE) & 0xfffc; +#else + return pci_read_config16(dev_find_slot(0, PCI_DEVFN(0x1f, 0)), + GPIO_BASE) & 0xfffc; +#endif +} + void setup_pch_gpios(const struct pch_gpio_map *gpio) { - u16 gpiobase = pci_read_config16(PCH_LPC_DEV, GPIO_BASE) & 0xfffc; + u16 gpiobase = get_gpio_base(); /* GPIO Set 1 */ if (gpio->set1.level) @@ -69,7 +85,7 @@ void setup_pch_gpios(const struct pch_gpio_map *gpio) int get_gpio(int gpio_num) { static const int gpio_reg_offsets[] = {0xc, 0x38, 0x48}; - u16 gpio_base = pci_read_config16(PCH_LPC_DEV, GPIO_BASE) & 0xfffc; + u16 gpio_base = get_gpio_base(); int index, bit; if (gpio_num > MAX_GPIO_NUMBER) diff --git a/src/southbridge/intel/lynxpoint/gpio.h b/src/southbridge/intel/lynxpoint/gpio.h index a6f99f681d..20e2eea0af 100644 --- a/src/southbridge/intel/lynxpoint/gpio.h +++ b/src/southbridge/intel/lynxpoint/gpio.h @@ -20,6 +20,22 @@ #ifndef INTEL_LYNXPOINT_GPIO_H #define INTEL_LYNXPOINT_GPIO_H +/* ICH7 GPIOBASE */ +#define GPIO_USE_SEL 0x00 +#define GP_IO_SEL 0x04 +#define GP_LVL 0x0c +#define GPO_BLINK 0x18 +#define GPI_INV 0x2c +#define GPIO_USE_SEL2 0x30 +#define GP_IO_SEL2 0x34 +#define GP_LVL2 0x38 +#define GPIO_USE_SEL3 0x40 +#define GP_IO_SEL3 0x44 +#define GP_LVL3 0x48 +#define GP_RST_SEL1 0x60 +#define GP_RST_SEL2 0x64 +#define GP_RST_SEL3 0x68 + #define GPIO_MODE_NATIVE 0 #define GPIO_MODE_GPIO 1 #define GPIO_MODE_NONE 1 @@ -150,12 +166,4 @@ struct pch_gpio_map { /* Configure GPIOs with mainboard provided settings */ void setup_pch_gpios(const struct pch_gpio_map *gpio); -/* get GPIO pin value */ -int get_gpio(int gpio_num); -/* - * get a number comprised of multiple GPIO values. gpio_num_array points to - * the array of gpio pin numbers to scan, terminated by -1. - */ -unsigned get_gpios(const int *gpio_num_array); - #endif diff --git a/src/southbridge/intel/lynxpoint/lp_gpio.c b/src/southbridge/intel/lynxpoint/lp_gpio.c new file mode 100644 index 0000000000..2d2e0576ea --- /dev/null +++ b/src/southbridge/intel/lynxpoint/lp_gpio.c @@ -0,0 +1,113 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * 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 +#include +#include +#ifdef __PRE_RAM__ +#include +#else +#include +#include +#endif + +#include "pch.h" +#include "lp_gpio.h" + +static u16 get_gpio_base(void) +{ +#ifdef __PRE_RAM__ + return pci_read_config16(PCH_LPC_DEV, GPIO_BASE) & 0xfffc; +#else + return pci_read_config16(dev_find_slot(0, PCI_DEVFN(0x1f, 0)), + GPIO_BASE) & 0xfffc; +#endif +} + +void setup_pch_lp_gpios(const struct pch_lp_gpio_map map[]) +{ + u16 gpio_base = get_gpio_base(); + const struct pch_lp_gpio_map *config; + u32 owner[3] = {0}; + u32 route[3] = {0}; + u32 irqen[3] = {0}; + u32 reset[3] = {0}; + u32 blink = 0; + int set, bit; + + for (config = map; config->gpio != GPIO_LIST_END; config++) { + if (config->gpio > MAX_GPIO_NUMBER) + continue; + + /* Setup Configuration registers 1 and 2 */ + outl(config->conf0, gpio_base + GPIO_CONFIG0(config->gpio)); + outl(config->conf1, gpio_base + GPIO_CONFIG1(config->gpio)); + + /* Determine set and bit based on GPIO number */ + set = config->gpio >> 5; + bit = config->gpio % 32; + + /* Apply settings to set specific bits */ + owner[set] |= config->owner << bit; + route[set] |= config->route << bit; + irqen[set] |= config->irqen << bit; + reset[set] |= config->reset << bit; + + if (set == 0) + blink |= config->blink << bit; + } + + for (set = 0; set <= 2; set++) { + outl(owner[set], gpio_base + GPIO_OWNER(set)); + outl(route[set], gpio_base + GPIO_ROUTE(set)); + outl(irqen[set], gpio_base + GPIO_IRQ_IE(set)); + outl(reset[set], gpio_base + GPIO_RESET(set)); + } + + outl(blink, gpio_base + GPIO_BLINK); +} + +int get_gpio(int gpio_num) +{ + u16 gpio_base = get_gpio_base(); + + if (gpio_num < MAX_GPIO_NUMBER) + return 0; + + return !!(inl(gpio_base + GPIO_CONFIG0(gpio_num)) & GPI_LEVEL); +} + +/* + * get a number comprised of multiple GPIO values. gpio_num_array points to + * the array of gpio pin numbers to scan, terminated by -1. + */ +unsigned get_gpios(const int *gpio_num_array) +{ + int gpio; + unsigned bitmask = 1; + unsigned vector = 0; + + while (bitmask && + ((gpio = *gpio_num_array++) != -1)) { + if (get_gpio(gpio)) + vector |= bitmask; + bitmask <<= 1; + } + return vector; +} diff --git a/src/southbridge/intel/lynxpoint/lp_gpio.h b/src/southbridge/intel/lynxpoint/lp_gpio.h new file mode 100644 index 0000000000..067b6e2060 --- /dev/null +++ b/src/southbridge/intel/lynxpoint/lp_gpio.h @@ -0,0 +1,110 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * 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 + */ + +#ifndef INTEL_LYNXPOINT_LP_GPIO_H +#define INTEL_LYNXPOINT_LP_GPIO_H + +/* LynxPoint LP GPIOBASE Registers */ +#define GPIO_OWNER(set) (0x00 + ((set) * 4)) +#define GPIO_PIRQ_APIC_EN 0x10 +#define GPIO_BLINK 0x18 +#define GPIO_SER_BLINK 0x1c +#define GPIO_SER_BLINK_CS 0x20 +#define GPIO_SER_BLINK_DATA 0x24 +#define GPIO_ROUTE(set) (0x30 + ((set) * 4)) +#define GPIO_ALT_GPI_SMI_STS 0x50 +#define GPIO_ALT_GPI_SMI_EN 0x54 +#define GPIO_RESET(set) (0x60 + ((set) * 4)) +#define GPIO_GLOBAL_CONFIG 0x7c +#define GPIO_IRQ_IS(set) (0x80 + ((set) * 4)) +#define GPIO_IRQ_IE(set) (0x90 + ((set) * 4)) +#define GPIO_CONFIG0(gpio) (0x100 + ((gpio) * 8)) +#define GPIO_CONFIG1(gpio) (0x104 + ((gpio) * 8)) + +#define MAX_GPIO_NUMBER 94 /* zero based */ +#define GPIO_LIST_END 0xff + +/* conf0 */ + +#define GPIO_MODE_NATIVE (0 << 0) +#define GPIO_MODE_GPIO (1 << 0) + +#define GPIO_DIR_OUTPUT (0 << 2) +#define GPIO_DIR_INPUT (1 << 2) + +#define GPIO_NO_INVERT (0 << 3) +#define GPIO_INVERT (1 << 3) + +#define GPIO_IRQ_EDGE (0 << 4) +#define GPIO_IRQ_LEVEL (1 << 4) + +#define GPI_LEVEL (1 << 30) + +#define GPO_LEVEL_LOW (0 << 31) +#define GPO_LEVEL_HIGH (1 << 31) + +/* conf1 */ + +#define GPIO_PULL_NONE (0 << 0) +#define GPIO_PULL_DOWN (1 << 0) +#define GPIO_PULL_UP (2 << 0) + +#define GPIO_SENSE_ENABLE (0 << 2) +#define GPIO_SENSE_DISABLE (1 << 2) + +/* owner */ + +#define GPIO_OWNER_ACPI 0 +#define GPIO_OWNER_GPIO 1 + +/* route */ + +#define GPIO_ROUTE_SCI 0 +#define GPIO_ROUTE_SMI 1 + +/* irqen */ + +#define GPIO_IRQ_DISABLE 0 +#define GPIO_IRQ_ENABLE 1 + +/* blink */ + +#define GPO_NO_BLINK 0 +#define GPO_BLINK 1 + +/* reset */ + +#define GPIO_RESET_PWROK 0 +#define GPIO_RESET_RSMRST 1 + +struct pch_lp_gpio_map { + u8 gpio; + u32 conf0; + u32 conf1; + u8 owner; + u8 route; + u8 irqen; + u8 reset; + u8 blink; +} __attribute__ ((packed)); + +/* Configure GPIOs with mainboard provided settings */ +void setup_pch_lp_gpios(const struct pch_lp_gpio_map map[]); + +#endif diff --git a/src/southbridge/intel/lynxpoint/lpc.c b/src/southbridge/intel/lynxpoint/lpc.c index a121e49874..378d62477b 100644 --- a/src/southbridge/intel/lynxpoint/lpc.c +++ b/src/southbridge/intel/lynxpoint/lpc.c @@ -561,13 +561,20 @@ static void pch_lpc_read_resources(device_t dev) res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED | IORESOURCE_FIXED; + /* GPIOBASE */ + res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0)); + res->base = DEFAULT_GPIOBASE; + res->size = DEFAULT_GPIOSIZE; + res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | + IORESOURCE_ASSIGNED | IORESOURCE_FIXED; + res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0)); res->base = 0xff800000; res->size = 0x00800000; /* 8 MB for flash */ res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED | IORESOURCE_FIXED; - res = new_resource(dev, 3); /* IOAPIC */ + res = new_resource(dev, io_index++); /* IOAPIC */ res->base = IO_APIC_ADDR; res->size = 0x00001000; res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED; diff --git a/src/southbridge/intel/lynxpoint/pch.h b/src/southbridge/intel/lynxpoint/pch.h index e1d9db4378..f6707f7bdb 100644 --- a/src/southbridge/intel/lynxpoint/pch.h +++ b/src/southbridge/intel/lynxpoint/pch.h @@ -63,10 +63,16 @@ */ #define SMBUS_IO_BASE 0x0400 #define SMBUS_SLAVE_ADDR 0x24 -/* TODO Make sure these don't get changed by stage2 */ -#define DEFAULT_GPIOBASE 0x0480 #define DEFAULT_PMBASE 0x0500 +#if CONFIG_INTEL_LYNXPOINT_LP +#define DEFAULT_GPIOBASE 0x1000 +#define DEFAULT_GPIOSIZE 0x400 +#else +#define DEFAULT_GPIOBASE 0x480 +#define DEFAULT_GPIOSIZE 0x80 +#endif + #define HPET_ADDR 0xfed00000 #define DEFAULT_RCBA 0xfed1c000 @@ -97,6 +103,15 @@ void enable_usb_bar(void); int smbus_read_byte(unsigned device, unsigned address); int early_spi_read(u32 offset, u32 size, u8 *buffer); #endif +/* + * get GPIO pin value + */ +int get_gpio(int gpio_num); +/* + * get a number comprised of multiple GPIO values. gpio_num_array points to + * the array of gpio pin numbers to scan, terminated by -1. + */ +unsigned get_gpios(const int *gpio_num_array); #endif #define MAINBOARD_POWER_OFF 0 @@ -438,22 +453,6 @@ int early_spi_read(u32 offset, u32 size, u8 *buffer); #define PCH_DISABLE_MEI1 (1 << 1) #define PCH_ENABLE_DBDF (1 << 0) -/* ICH7 GPIOBASE */ -#define GPIO_USE_SEL 0x00 -#define GP_IO_SEL 0x04 -#define GP_LVL 0x0c -#define GPO_BLINK 0x18 -#define GPI_INV 0x2c -#define GPIO_USE_SEL2 0x30 -#define GP_IO_SEL2 0x34 -#define GP_LVL2 0x38 -#define GPIO_USE_SEL3 0x40 -#define GP_IO_SEL3 0x44 -#define GP_LVL3 0x48 -#define GP_RST_SEL1 0x60 -#define GP_RST_SEL2 0x64 -#define GP_RST_SEL3 0x68 - /* ICH7 PMBASE */ #define PM1_STS 0x00 #define WAK_STS (1 << 15) -- cgit v1.2.3