diff options
Diffstat (limited to 'src/soc/intel')
-rw-r--r-- | src/soc/intel/apollolake/Kconfig | 1 | ||||
-rw-r--r-- | src/soc/intel/apollolake/Makefile.inc | 4 | ||||
-rw-r--r-- | src/soc/intel/apollolake/chip.h | 8 | ||||
-rw-r--r-- | src/soc/intel/apollolake/include/soc/lpc.h | 72 | ||||
-rw-r--r-- | src/soc/intel/apollolake/lpc.c | 187 | ||||
-rw-r--r-- | src/soc/intel/apollolake/romstage.c | 15 | ||||
-rw-r--r-- | src/soc/intel/common/block/include/intelblocks/lpc_lib.h | 86 | ||||
-rw-r--r-- | src/soc/intel/common/block/lpc/Kconfig | 5 | ||||
-rw-r--r-- | src/soc/intel/common/block/lpc/Makefile.inc | 6 | ||||
-rw-r--r-- | src/soc/intel/common/block/lpc/lpc.c | 123 | ||||
-rw-r--r-- | src/soc/intel/common/block/lpc/lpc_def.h | 46 | ||||
-rw-r--r-- | src/soc/intel/common/block/lpc/lpc_lib.c (renamed from src/soc/intel/apollolake/lpc_lib.c) | 182 |
12 files changed, 441 insertions, 294 deletions
diff --git a/src/soc/intel/apollolake/Kconfig b/src/soc/intel/apollolake/Kconfig index 1323f573d1..49e56aa6d7 100644 --- a/src/soc/intel/apollolake/Kconfig +++ b/src/soc/intel/apollolake/Kconfig @@ -70,6 +70,7 @@ config CPU_SPECIFIC_OPTIONS select SOC_INTEL_COMMON_BLOCK_GPIO_IOSTANDBY select SOC_INTEL_COMMON_BLOCK_ITSS select SOC_INTEL_COMMON_BLOCK_I2C + select SOC_INTEL_COMMON_BLOCK_LPC select SOC_INTEL_COMMON_BLOCK_LPSS select SOC_INTEL_COMMON_BLOCK_PCR select SOC_INTEL_COMMON_BLOCK_PMC diff --git a/src/soc/intel/apollolake/Makefile.inc b/src/soc/intel/apollolake/Makefile.inc index 589b846012..e860daa5ce 100644 --- a/src/soc/intel/apollolake/Makefile.inc +++ b/src/soc/intel/apollolake/Makefile.inc @@ -12,7 +12,7 @@ bootblock-y += bootblock/bootblock.c bootblock-y += car.c bootblock-y += heci.c bootblock-y += i2c.c -bootblock-y += lpc_lib.c +bootblock-y += lpc.c bootblock-y += mmap_boot.c bootblock-y += pmutil.c bootblock-y += spi.c @@ -24,7 +24,6 @@ romstage-$(CONFIG_PLATFORM_USES_FSP2_0) += romstage.c romstage-y += heci.c romstage-y += i2c.c romstage-$(CONFIG_SOC_UART_DEBUG) += uart_early.c -romstage-y += lpc_lib.c romstage-y += memmap.c romstage-y += meminit.c ifeq ($(CONFIG_SOC_INTEL_GLK),y) @@ -55,7 +54,6 @@ ramstage-y += heci.c ramstage-y += i2c.c ramstage-$(CONFIG_SOC_UART_DEBUG) += uart_early.c ramstage-y += lpc.c -ramstage-y += lpc_lib.c ramstage-y += memmap.c ramstage-y += mmap_boot.c ramstage-y += p2sb.c diff --git a/src/soc/intel/apollolake/chip.h b/src/soc/intel/apollolake/chip.h index 93bb5a1c40..7b36089b3c 100644 --- a/src/soc/intel/apollolake/chip.h +++ b/src/soc/intel/apollolake/chip.h @@ -20,6 +20,7 @@ #include <soc/gpe.h> #include <soc/gpio.h> +#include <intelblocks/lpc_lib.h> #include <intelblocks/lpss_i2c.h> #include <device/i2c.h> #include <soc/pm.h> @@ -28,13 +29,6 @@ #define CLKREQ_DISABLED 0xf #define APOLLOLAKE_I2C_DEV_MAX 8 -/* Serial IRQ control. SERIRQ_QUIET is the default (0). */ -enum serirq_mode { - SERIRQ_QUIET, - SERIRQ_CONTINUOUS, - SERIRQ_OFF, -}; - struct soc_intel_apollolake_config { /* * Mapping from PCIe root port to CLKREQ input on the SOC. The SOC has diff --git a/src/soc/intel/apollolake/include/soc/lpc.h b/src/soc/intel/apollolake/include/soc/lpc.h deleted file mode 100644 index da918a16b4..0000000000 --- a/src/soc/intel/apollolake/include/soc/lpc.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2016 Intel Corp. - * (Written by Alexandru Gagniuc <alexandrux.gagniuc@intel.com> for Intel Corp.) - * - * 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; either version 2 of the License, or - * (at your option) any later version. - * - * 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. - */ - -#ifndef _SOC_APOLLOLAKE_LPC_H_ -#define _SOC_APOLLOLAKE_LPC_H_ - -#include <stddef.h> -#include <stdint.h> - -#define REG_SERIRQ_CTL 0x64 -#define SCNT_EN (1 << 7) -#define SCNT_MODE (1 << 6) - -/* - * IO decode enable macros are in the format IO_<peripheral>_<IO port>. - * For example, to open ports 0x60, 0x64 for the keyboard controller, - * use IOE_KBC_60_64 macro. For IOE_ macros that do not specify a port range, - * the port range is selectable via the IO decodes register. - */ -#define REG_IO_DECODE 0x80 -#define IOD_COMA_RANGE (0 << 0) /* 0x3F8 - 0x3FF COMA*/ -#define IOD_COMB_RANGE (1 << 4) /* 0x2F8 - 0x2FF COMB*/ -#define REG_IO_ENABLES 0x82 -#define IOE_EC_4E_4F (1 << 13) -#define IOE_SUPERIO_2E_2F (1 << 12) -#define IOE_EC_62_66 (1 << 11) -#define IOE_KBC_60_64 (1 << 10) -#define IOE_HGE_208 (1 << 9) -#define IOE_LGE_200 (1 << 8) -#define IOE_FDD_EN (1 << 3) -#define IOE_LPT_EN (1 << 2) -#define IOE_COMB_EN (1 << 1) -#define IOE_COMA_EN (1 << 0) -#define REG_GENERIC_IO_RANGE(n) ((((n) & 0x3) * 4) + 0x84) -#define LGIR_AMASK_MASK (0xfc << 16) -#define LGIR_ADDR_MASK 0xfffc -#define LGIR_EN (1 << 0) -#define LGIR_MAX_WINDOW_SIZE 256 -#define NUM_GENERIC_IO_RANGES 4 -#define REG_GENERIC_MEM_RANGE 0x98 -#define LGMR_ADDR_MASK 0xffff0000 -#define LGMR_EN (1 << 0) -#define LGMR_WINDOW_SIZE (64 * KiB) - -/* Configure the SOC's LPC pads and mux them to the LPC function. */ -void lpc_configure_pads(void); -/* Enable fixed IO ranges to LPC. IOE_* macros can be OR'ed together. */ -void lpc_enable_fixed_io_ranges(uint16_t io_enables); -/* Open a generic IO window to the LPC bus. Four windows are available. */ -void lpc_open_pmio_window(uint16_t base, uint16_t size); -/* Close all generic IO windows to the LPC bus. */ -void lpc_close_pmio_windows(void); -/* Open a generic MMIO window to the LPC bus. One window is available. */ -void lpc_open_mmio_window(uintptr_t base, size_t size); -/* Returns true if given window is decoded to LPC via a fixed range. */ -bool lpc_fits_fixed_mmio_window(uintptr_t base, size_t size); - -#endif /* _SOC_APOLLOLAKE_LPC_H_ */ diff --git a/src/soc/intel/apollolake/lpc.c b/src/soc/intel/apollolake/lpc.c index 67c87b1f22..6c7ffff200 100644 --- a/src/soc/intel/apollolake/lpc.c +++ b/src/soc/intel/apollolake/lpc.c @@ -1,8 +1,7 @@ /* * This file is part of the coreboot project. * - * Copyright (C) 2015-2016 Intel Corp. - * (Written by Lance Zhao <lijian.zhao@intel.com> for Intel Corp.) + * Copyright (C) 2017 Intel Corp. * * 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 @@ -17,34 +16,72 @@ #include <cbmem.h> #include <console/console.h> -#include <device/device.h> #include <device/pci.h> #include <device/pci_ids.h> +#include <intelblocks/lpc_lib.h> +#include <intelblocks/rtc.h> #include <pc80/mc146818rtc.h> -#include <soc/acpi.h> -#include <soc/lpc.h> +#include <soc/gpio.h> +#include <soc/pcr_ids.h> #include <soc/pm.h> #include <vboot/vbnv.h> - #include "chip.h" -/* - * SCOPE: - * The purpose of this driver is to eliminate manual resource allocation for - * devices under the LPC bridge. - * - * BACKGROUND: - * The resource allocator reserves IO and memory resources to devices on the - * LPC bus, but it is up to the hardware driver to make sure that those - * resources are decoded to the LPC bus. This is what this driver does. - * - * THEORY OF OPERATION: - * The .scan_bus member of the driver's ops will scan the static device tree - * (devicetree.cb) and invoke drivers of devices on the LPC bus. This creates - * a list of child devices, along with their resources. set_child_resources() - * parses that list and looks for resources needed by the child devices. It - * opens up IO and memory windows as needed. - */ +static const struct lpc_mmio_range apl_lpc_fixed_mmio_ranges[] = { + { 0xfed40000, 0x8000 }, + { 0xfedc0000, 0x4000 }, + { 0xfed20800, 16 }, + { 0xfed20880, 8 }, + { 0xfed208e0, 16 }, + { 0xfed208f0, 8 }, + { 0xfed30800, 16 }, + { 0xfed30880, 8 }, + { 0xfed308e0, 16 }, + { 0xfed308f0, 8 }, + { 0, 0 } +}; + +const struct lpc_mmio_range *soc_get_fixed_mmio_ranges(void) +{ + return apl_lpc_fixed_mmio_ranges; +} + +static const struct pad_config lpc_gpios[] = { +#if IS_ENABLED(CONFIG_SOC_INTEL_GLK) + PAD_CFG_NF(GPIO_147, UP_20K, DEEP, NF1), /* LPC_ILB_SERIRQ */ + PAD_CFG_NF_IOSSTATE_IOSTERM(GPIO_148, UP_20K, DEEP, NF1, HIZCRx1, + DISPUPD), /* LPC_CLKOUT0 */ + PAD_CFG_NF_IOSSTATE_IOSTERM(GPIO_149, UP_20K, DEEP, NF1, HIZCRx1, + DISPUPD), /* LPC_CLKOUT1 */ + PAD_CFG_NF_IOSSTATE_IOSTERM(GPIO_150, UP_20K, DEEP, NF1, HIZCRx1, + DISPUPD), /* LPC_AD0 */ + PAD_CFG_NF_IOSSTATE_IOSTERM(GPIO_151, UP_20K, DEEP, NF1, HIZCRx1, + DISPUPD), /* LPC_AD1 */ + PAD_CFG_NF_IOSSTATE_IOSTERM(GPIO_152, UP_20K, DEEP, NF1, HIZCRx1, + DISPUPD), /* LPC_AD2 */ + PAD_CFG_NF_IOSSTATE_IOSTERM(GPIO_153, UP_20K, DEEP, NF1, HIZCRx1, + DISPUPD), /* LPC_AD3 */ + PAD_CFG_NF_IOSSTATE_IOSTERM(GPIO_154, UP_20K, DEEP, NF1, HIZCRx1, + DISPUPD), /* LPC_CLKRUNB */ + PAD_CFG_NF_IOSSTATE_IOSTERM(GPIO_155, UP_20K, DEEP, NF1, HIZCRx1, + DISPUPD), /* LPC_FRAMEB*/ +#else + PAD_CFG_NF(LPC_ILB_SERIRQ, UP_20K, DEEP, NF1), + PAD_CFG_NF(LPC_CLKRUNB, UP_20K, DEEP, NF1), + PAD_CFG_NF(LPC_AD0, UP_20K, DEEP, NF1), + PAD_CFG_NF(LPC_AD1, UP_20K, DEEP, NF1), + PAD_CFG_NF(LPC_AD2, UP_20K, DEEP, NF1), + PAD_CFG_NF(LPC_AD3, UP_20K, DEEP, NF1), + PAD_CFG_NF(LPC_FRAMEB, NATIVE, DEEP, NF1), + PAD_CFG_NF(LPC_CLKOUT0, UP_20K, DEEP, NF1), + PAD_CFG_NF(LPC_CLKOUT1, UP_20K, DEEP, NF1) +#endif +}; + +void lpc_configure_pads(void) +{ + gpio_configure_pads(lpc_gpios, ARRAY_SIZE(lpc_gpios)); +} static void rtc_init(void) { @@ -65,10 +102,9 @@ static void rtc_init(void) cmos_init(rtc_fail); } -static void lpc_init(struct device *dev) +void lpc_init(struct device *dev) { - uint8_t scnt; - struct soc_intel_apollolake_config *cfg; + const struct soc_intel_apollolake_config *cfg; cfg = dev->chip_info; if (!cfg) { @@ -76,104 +112,9 @@ static void lpc_init(struct device *dev) return; } - scnt = pci_read_config8(dev, REG_SERIRQ_CTL); - scnt &= ~(SCNT_EN | SCNT_MODE); - if (cfg->serirq_mode == SERIRQ_QUIET) - scnt |= SCNT_EN; - else if (cfg->serirq_mode == SERIRQ_CONTINUOUS) - scnt |= SCNT_EN | SCNT_MODE; - pci_write_config8(dev, REG_SERIRQ_CTL, scnt); + /* Set LPC Serial IRQ mode */ + lpc_set_serirq_mode(cfg->serirq_mode); /* Initialize RTC */ rtc_init(); } - -static void soc_lpc_add_io_resources(device_t dev) -{ - struct resource *res; - - /* Add the default claimed legacy IO range for the LPC device. */ - res = new_resource(dev, 0); - res->base = 0; - res->size = 0x1000; - res->flags = IORESOURCE_IO | IORESOURCE_ASSIGNED | IORESOURCE_FIXED; -} - -static void soc_lpc_read_resources(device_t dev) -{ - /* Get the PCI resources of this device. */ - pci_dev_read_resources(dev); - - /* Add IO resources to LPC. */ - soc_lpc_add_io_resources(dev); -} - -static void set_child_resources(struct device *dev); - -static void loop_resources(struct device *dev) -{ - struct resource *res; - - for (res = dev->resource_list; res; res = res->next) { - - if (res->flags & IORESOURCE_IO) - lpc_open_pmio_window(res->base, res->size); - - if (res->flags & IORESOURCE_MEM) { - /* Check if this is already decoded. */ - if (lpc_fits_fixed_mmio_window(res->base, res->size)) - continue; - - lpc_open_mmio_window(res->base, res->size); - } - - } - set_child_resources(dev); -} - -/* - * Loop through all the child devices' resources, and open up windows to the - * LPC bus, as appropriate. - */ -static void set_child_resources(struct device *dev) -{ - struct bus *link; - struct device *child; - - for (link = dev->link_list; link; link = link->next) { - for (child = link->children; child; child = child->sibling) - loop_resources(child); - } -} - -static void set_resources(device_t dev) -{ - pci_dev_set_resources(dev); - - /* Close all previously opened windows and allocate from scratch. */ - lpc_close_pmio_windows(); - /* Now open up windows to devices which have declared resources. */ - set_child_resources(dev); -} - -static struct device_operations device_ops = { - .read_resources = &soc_lpc_read_resources, - .set_resources = set_resources, - .enable_resources = &pci_dev_enable_resources, - .write_acpi_tables = southbridge_write_acpi_tables, - .acpi_inject_dsdt_generator = southbridge_inject_dsdt, - .init = lpc_init, - .scan_bus = scan_lpc_bus, -}; - -static const unsigned short pci_device_ids[] = { - PCI_DEVICE_ID_INTEL_APL_LPC, - PCI_DEVICE_ID_INTEL_GLK_LPC, - 0, -}; - -static const struct pci_driver soc_lpc __pci_driver = { - .ops = &device_ops, - .vendor = PCI_VENDOR_ID_INTEL, - .devices = pci_device_ids, -}; diff --git a/src/soc/intel/apollolake/romstage.c b/src/soc/intel/apollolake/romstage.c index 59278a6942..2017d84d18 100644 --- a/src/soc/intel/apollolake/romstage.c +++ b/src/soc/intel/apollolake/romstage.c @@ -28,6 +28,7 @@ #include <cpu/x86/mtrr.h> #include <device/pci_def.h> #include <device/resource.h> +#include <intelblocks/lpc_lib.h> #include <fsp/api.h> #include <fsp/memmap.h> #include <fsp/util.h> @@ -38,7 +39,6 @@ #include <soc/cpu.h> #include <soc/intel/common/mrc_cache.h> #include <soc/iomap.h> -#include <soc/lpc.h> #include <soc/systemagent.h> #include <soc/pci_devs.h> #include <soc/pm.h> @@ -96,17 +96,8 @@ static void soc_early_romstage_init(void) pci_write_config8(PCH_DEV_P2SB, P2SB_HPTC, P2SB_HPTC_ADDRESS_SELECT_0 | P2SB_HPTC_ADDRESS_ENABLE); - if (IS_ENABLED(CONFIG_DRIVERS_UART_8250IO)) { - /* - * I/O Decode Range Register for LPC - * ComA Range 3F8h-3FFh [2:0] - * ComB Range 2F8h-2FFh [6:4] - */ - pci_write_config16(PCH_DEV_LPC, REG_IO_DECODE, - IOD_COMA_RANGE | IOD_COMB_RANGE); - /* Enable ComA and ComB Port */ - lpc_enable_fixed_io_ranges(IOE_COMA_EN | IOE_COMB_EN); - } + if (IS_ENABLED(CONFIG_DRIVERS_UART_8250IO)) + lpc_io_setup_comm_a_b(); } static void disable_watchdog(void) diff --git a/src/soc/intel/common/block/include/intelblocks/lpc_lib.h b/src/soc/intel/common/block/include/intelblocks/lpc_lib.h new file mode 100644 index 0000000000..596c2b5b26 --- /dev/null +++ b/src/soc/intel/common/block/include/intelblocks/lpc_lib.h @@ -0,0 +1,86 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2017 Intel Corp. + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +#ifndef _SOC_COMMON_BLOCK_LPC_LIB_H_ +#define _SOC_COMMON_BLOCK_LPC_LIB_H_ + +#include <device/device.h> +#include <stddef.h> +#include <stdint.h> + +/* + * IO decode enable macros are in the format IO_<peripheral>_<IO port>. + * For example, to open ports 0x60, 0x64 for the keyboard controller, + * use IOE_KBC_60_64 macro. For IOE_ macros that do not specify a port range, + * the port range is selectable via the IO decodes register. + */ +#define LPC_IOE_EC_4E_4F (1 << 13) +#define LPC_IOE_SUPERIO_2E_2F (1 << 12) +#define LPC_IOE_EC_62_66 (1 << 11) +#define LPC_IOE_KBC_60_64 (1 << 10) +#define LPC_IOE_HGE_208 (1 << 9) +#define LPC_IOE_LGE_200 (1 << 8) +#define LPC_IOE_FDD_EN (1 << 3) +#define LPC_IOE_LPT_EN (1 << 2) +#define LPC_IOE_COMB_EN (1 << 1) +#define LPC_IOE_COMA_EN (1 << 0) + +/* Serial IRQ control. SERIRQ_QUIET is the default (0). */ +enum serirq_mode { + SERIRQ_QUIET, + SERIRQ_CONTINUOUS, + SERIRQ_OFF, +}; + +struct lpc_mmio_range { + uintptr_t base; + size_t size; +}; + +/* Enable fixed IO ranges to LPC. IOE_* macros can be OR'ed together. */ +void lpc_enable_fixed_io_ranges(uint16_t io_enables); +/* Open a generic IO window to the LPC bus. Four windows are available. */ +void lpc_open_pmio_window(uint16_t base, uint16_t size); +/* Close all generic IO windows to the LPC bus. */ +void lpc_close_pmio_windows(void); +/* Open a generic MMIO window to the LPC bus. One window is available. */ +void lpc_open_mmio_window(uintptr_t base, size_t size); +/* Returns true if given window is decoded to LPC via a fixed range. */ +bool lpc_fits_fixed_mmio_window(uintptr_t base, size_t size); +/* Init SoC Spcific LPC features. Common definition will be weak and +each soc will need to define the init. */ +void lpc_init(struct device *dev); +/* Init LPC GPIO pads */ +void lpc_configure_pads(void); +/* Get SoC speicific MMIO ranges */ +const struct lpc_mmio_range *soc_get_fixed_mmio_ranges(void); +/* Set LPC BIOS Control BILD bit. */ +void lpc_set_bios_interface_lock_down(void); +/* Set LPC BIOS Control LE bit. */ +void lpc_set_lock_enable(void); +/* Set LPC BIOS Control EISS bit. */ +void lpc_set_eiss(void); +/* Set LPC Serial IRQ mode. */ +void lpc_set_serirq_mode(enum serirq_mode mode); +/* +* Setup I/O Decode Range Register for LPC +* ComA Range 3F8h-3FFh [2:0] +* ComB Range 2F8h-2FFh [6:4] +* Enable ComA and ComB Port +*/ +void lpc_io_setup_comm_a_b(void); + +#endif /* _SOC_COMMON_BLOCK_LPC_LIB_H_ */ diff --git a/src/soc/intel/common/block/lpc/Kconfig b/src/soc/intel/common/block/lpc/Kconfig new file mode 100644 index 0000000000..c384c343f3 --- /dev/null +++ b/src/soc/intel/common/block/lpc/Kconfig @@ -0,0 +1,5 @@ +config SOC_INTEL_COMMON_BLOCK_LPC + bool + help + Use common LPC code for platform. Only soc specific code needs to + be implemented as per requirement. diff --git a/src/soc/intel/common/block/lpc/Makefile.inc b/src/soc/intel/common/block/lpc/Makefile.inc new file mode 100644 index 0000000000..428ade9ade --- /dev/null +++ b/src/soc/intel/common/block/lpc/Makefile.inc @@ -0,0 +1,6 @@ +bootblock-$(CONFIG_SOC_INTEL_COMMON_BLOCK_LPC) += lpc_lib.c + +romstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_LPC) += lpc_lib.c + +ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_LPC) += lpc_lib.c +ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_LPC) += lpc.c diff --git a/src/soc/intel/common/block/lpc/lpc.c b/src/soc/intel/common/block/lpc/lpc.c new file mode 100644 index 0000000000..0559d95399 --- /dev/null +++ b/src/soc/intel/common/block/lpc/lpc.c @@ -0,0 +1,123 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2017 Intel Corp. + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <intelblocks/lpc_lib.h> +#include <soc/acpi.h> +#include <soc/pm.h> + +/* Common weak definition, needs to be implemented in each soc LPC driver. */ +__attribute__((weak)) void lpc_init(struct device *dev) { /* no-op */ } + +static void soc_lpc_add_io_resources(device_t dev) +{ + struct resource *res; + + /* Add the default claimed legacy IO range for the LPC device. */ + res = new_resource(dev, 0); + res->base = 0; + res->size = 0x1000; + res->flags = IORESOURCE_IO | IORESOURCE_ASSIGNED | IORESOURCE_FIXED; +} + +static void soc_lpc_read_resources(device_t dev) +{ + /* Get the PCI resources of this device. */ + pci_dev_read_resources(dev); + + /* Add IO resources to LPC. */ + soc_lpc_add_io_resources(dev); +} + +static void set_child_resources(struct device *dev); + +static void loop_resources(struct device *dev) +{ + struct resource *res; + + for (res = dev->resource_list; res; res = res->next) { + if (res->flags & IORESOURCE_IO) + lpc_open_pmio_window(res->base, res->size); + + if (res->flags & IORESOURCE_MEM) { + /* Check if this is already decoded. */ + if (lpc_fits_fixed_mmio_window(res->base, res->size)) + continue; + + lpc_open_mmio_window(res->base, res->size); + } + } + set_child_resources(dev); +} + +/* + * Loop through all the child devices' resources, and open up windows to the + * LPC bus, as appropriate. + */ +static void set_child_resources(struct device *dev) +{ + struct bus *link; + struct device *child; + + for (link = dev->link_list; link; link = link->next) { + for (child = link->children; child; child = child->sibling) + loop_resources(child); + } +} + +static void set_resources(device_t dev) +{ + pci_dev_set_resources(dev); + + /* Now open up windows to devices which have declared resources. */ + set_child_resources(dev); +} + +static struct device_operations device_ops = { + .read_resources = soc_lpc_read_resources, + .set_resources = set_resources, + .enable_resources = pci_dev_enable_resources, + .write_acpi_tables = southbridge_write_acpi_tables, + .acpi_inject_dsdt_generator = southbridge_inject_dsdt, + .init = lpc_init, + .scan_bus = scan_lpc_bus, +}; + +static const unsigned short pci_device_ids[] = { + PCI_DEVICE_ID_INTEL_SPT_LP_SAMPLE, + PCI_DEVICE_ID_INTEL_SPT_LP_U_BASE, + PCI_DEVICE_ID_INTEL_SPT_LP_U_PREMIUM, + PCI_DEVICE_ID_INTEL_SPT_LP_Y_PREMIUM, + PCI_DEVICE_ID_INTEL_KBP_H_C236, + PCI_DEVICE_ID_INTEL_KBP_H_PREMIUM, + PCI_DEVICE_ID_INTEL_KBP_H_QM170, + PCI_DEVICE_ID_INTEL_SPT_LP_Y_PREMIUM_HDCP22, + PCI_DEVICE_ID_INTEL_SPT_LP_U_PREMIUM_HDCP22, + PCI_DEVICE_ID_INTEL_KBP_LP_SUPER_SKU, + PCI_DEVICE_ID_INTEL_KBP_LP_U_PREMIUM, + PCI_DEVICE_ID_INTEL_KBP_LP_Y_PREMIUM, + PCI_DEVICE_ID_INTEL_APL_LPC, + PCI_DEVICE_ID_INTEL_GLK_LPC, + 0 +}; + +static const struct pci_driver soc_lpc __pci_driver = { + .ops = &device_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .devices = pci_device_ids, +}; diff --git a/src/soc/intel/common/block/lpc/lpc_def.h b/src/soc/intel/common/block/lpc/lpc_def.h new file mode 100644 index 0000000000..da73608a70 --- /dev/null +++ b/src/soc/intel/common/block/lpc/lpc_def.h @@ -0,0 +1,46 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2017 Intel Corp. + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +#ifndef _SOC_COMMON_BLOCK_LPC_DEF_H_ +#define _SOC_COMMON_BLOCK_LPC_DEF_H_ + +#define LPC_SERIRQ_CTL 0x64 +#define LPC_SCNT_EN (1 << 7) +#define LPC_SCNT_MODE (1 << 6) +#define LPC_IO_DECODE 0x80 +#define LPC_IOD_COMA_RANGE (0 << 0) /* 0x3F8 - 0x3FF COMA*/ +#define LPC_IOD_COMB_RANGE (1 << 4) /* 0x2F8 - 0x2FF COMB*/ +/* Use IO_<peripheral>_<IO port> style macros defined in lpc_lib.h + * to enable decoding of I/O locations for a peripheral. */ +#define LPC_IO_ENABLES 0x82 +#define LPC_GENERIC_IO_RANGE(n) ((((n) & 0x3) * 4) + 0x84) +#define LPC_LGIR_AMASK_MASK (0xfc << 16) +#define LPC_LGIR_ADDR_MASK 0xfffc +#define LPC_LGIR_EN (1 << 0) +#define LPC_LGIR_MAX_WINDOW_SIZE 256 +#define LPC_NUM_GENERIC_IO_RANGES 4 +#define LPC_GENERIC_MEM_RANGE 0x98 +#define LPC_LGMR_ADDR_MASK 0xffff0000 +#define LPC_LGMR_EN (1 << 0) +#define LPC_LGMR_WINDOW_SIZE (64 * KiB) +#define LPC_BIOS_CNTL 0xdc +#define LPC_BC_BILD (1 << 7) /* BILD */ +#define LPC_BC_LE (1 << 2) /* LE */ +#define LPC_BC_EISS (1 << 5) /* EISS */ +#define LPC_PCCTL 0xE0 /* PCI Clock Control */ +#define LPC_PCCTL_CLKRUN_EN (1 << 0) + +#endif /* _SOC_COMMON_BLOCK_LPC_DEF_H_ */ diff --git a/src/soc/intel/apollolake/lpc_lib.c b/src/soc/intel/common/block/lpc/lpc_lib.c index 08a97b1f19..6b5f29a038 100644 --- a/src/soc/intel/apollolake/lpc_lib.c +++ b/src/soc/intel/common/block/lpc/lpc_lib.c @@ -17,78 +17,21 @@ #define __SIMPLE_DEVICE__ +#include <assert.h> #include <console/console.h> #include <device/pci.h> +#include <intelblocks/lpc_lib.h> #include <lib.h> -#include <soc/gpio.h> -#include <soc/lpc.h> +#include "lpc_def.h" #include <soc/pci_devs.h> -/* - * These are MMIO ranges that the silicon designers decided are always going to - * be decoded to LPC. - */ -static const struct lpc_mmio_range { - uintptr_t base; - size_t size; -} lpc_fixed_mmio_ranges[] = { - { 0xfed40000, 0x8000 }, - { 0xfedc0000, 0x4000 }, - { 0xfed20800, 16 }, - { 0xfed20880, 8 }, - { 0xfed208e0, 16 }, - { 0xfed208f0, 8 }, - { 0xfed30800, 16 }, - { 0xfed30880, 8 }, - { 0xfed308e0, 16 }, - { 0xfed308f0, 8 }, - { 0, 0 } -}; - -static const struct pad_config lpc_gpios[] = { -#if IS_ENABLED(CONFIG_SOC_INTEL_GLK) - PAD_CFG_NF(GPIO_147, UP_20K, DEEP, NF1), /* LPC_ILB_SERIRQ */ - PAD_CFG_NF_IOSSTATE_IOSTERM(GPIO_148, UP_20K, DEEP, NF1, HIZCRx1, - DISPUPD), /* LPC_CLKOUT0 */ - PAD_CFG_NF_IOSSTATE_IOSTERM(GPIO_149, UP_20K, DEEP, NF1, HIZCRx1, - DISPUPD), /* LPC_CLKOUT1 */ - PAD_CFG_NF_IOSSTATE_IOSTERM(GPIO_150, UP_20K, DEEP, NF1, HIZCRx1, - DISPUPD), /* LPC_AD0 */ - PAD_CFG_NF_IOSSTATE_IOSTERM(GPIO_151, UP_20K, DEEP, NF1, HIZCRx1, - DISPUPD), /* LPC_AD1 */ - PAD_CFG_NF_IOSSTATE_IOSTERM(GPIO_152, UP_20K, DEEP, NF1, HIZCRx1, - DISPUPD), /* LPC_AD2 */ - PAD_CFG_NF_IOSSTATE_IOSTERM(GPIO_153, UP_20K, DEEP, NF1, HIZCRx1, - DISPUPD), /* LPC_AD3 */ - PAD_CFG_NF_IOSSTATE_IOSTERM(GPIO_154, UP_20K, DEEP, NF1, HIZCRx1, - DISPUPD), /* LPC_CLKRUNB */ - PAD_CFG_NF_IOSSTATE_IOSTERM(GPIO_155, UP_20K, DEEP, NF1, HIZCRx1, - DISPUPD), /* LPC_FRAMEB*/ -#else - PAD_CFG_NF(LPC_ILB_SERIRQ, UP_20K, DEEP, NF1), - PAD_CFG_NF(LPC_CLKRUNB, UP_20K, DEEP, NF1), - PAD_CFG_NF(LPC_AD0, UP_20K, DEEP, NF1), - PAD_CFG_NF(LPC_AD1, UP_20K, DEEP, NF1), - PAD_CFG_NF(LPC_AD2, UP_20K, DEEP, NF1), - PAD_CFG_NF(LPC_AD3, UP_20K, DEEP, NF1), - PAD_CFG_NF(LPC_FRAMEB, NATIVE, DEEP, NF1), - PAD_CFG_NF(LPC_CLKOUT0, UP_20K, DEEP, NF1), - PAD_CFG_NF(LPC_CLKOUT1, UP_20K, DEEP, NF1) -#endif -}; - -void lpc_configure_pads(void) -{ - gpio_configure_pads(lpc_gpios, ARRAY_SIZE(lpc_gpios)); -} - void lpc_enable_fixed_io_ranges(uint16_t io_enables) { uint16_t reg_io_enables; - reg_io_enables = pci_read_config16(PCH_DEV_LPC, REG_IO_ENABLES); + reg_io_enables = pci_read_config16(PCH_DEV_LPC, LPC_IO_ENABLES); io_enables |= reg_io_enables; - pci_write_config16(PCH_DEV_LPC, REG_IO_ENABLES, io_enables); + pci_write_config16(PCH_DEV_LPC, LPC_IO_ENABLES, io_enables); } /* @@ -100,10 +43,10 @@ static int find_unused_pmio_window(void) int i; uint32_t lgir; - for (i = 0; i < NUM_GENERIC_IO_RANGES; i++) { - lgir = pci_read_config32(PCH_DEV_LPC, REG_GENERIC_IO_RANGE(i)); + for (i = 0; i < LPC_NUM_GENERIC_IO_RANGES; i++) { + lgir = pci_read_config32(PCH_DEV_LPC, LPC_GENERIC_IO_RANGE(i)); - if (!(lgir & LGIR_EN)) + if (!(lgir & LPC_LGIR_EN)) return i; } @@ -114,8 +57,8 @@ void lpc_close_pmio_windows(void) { size_t i; - for (i = 0; i < NUM_GENERIC_IO_RANGES; i++) - pci_write_config32(PCH_DEV_LPC, REG_GENERIC_IO_RANGE(i), 0); + for (i = 0; i < LPC_NUM_GENERIC_IO_RANGES; i++) + pci_write_config32(PCH_DEV_LPC, LPC_GENERIC_IO_RANGE(i), 0); } void lpc_open_pmio_window(uint16_t base, uint16_t size) @@ -139,18 +82,18 @@ void lpc_open_pmio_window(uint16_t base, uint16_t size) printk(BIOS_ERR, "No more IO windows\n"); return; } - lgir_reg_offset = REG_GENERIC_IO_RANGE(lgir_reg_num); + lgir_reg_offset = LPC_GENERIC_IO_RANGE(lgir_reg_num); /* Each IO range register can only open a 256-byte window. */ - window_size = MIN(size, LGIR_MAX_WINDOW_SIZE); + window_size = MIN(size, LPC_LGIR_MAX_WINDOW_SIZE); /* Window size must be a power of two for the AMASK to work. */ alignment = 1 << (log2_ceil(window_size)); window_size = ALIGN_UP(window_size, alignment); /* Address[15:2] in LGIR[15:12] and Mask[7:2] in LGIR[23:18]. */ - lgir = (bridge_base & LGIR_ADDR_MASK) | LGIR_EN; - lgir |= ((window_size - 1) << 16) & LGIR_AMASK_MASK; + lgir = (bridge_base & LPC_LGIR_ADDR_MASK) | LPC_LGIR_EN; + lgir |= ((window_size - 1) << 16) & LPC_LGIR_AMASK_MASK; pci_write_config32(PCH_DEV_LPC, lgir_reg_offset, lgir); @@ -167,9 +110,9 @@ void lpc_open_mmio_window(uintptr_t base, size_t size) { uint32_t lgmr; - lgmr = pci_read_config32(PCH_DEV_LPC, REG_GENERIC_MEM_RANGE); + lgmr = pci_read_config32(PCH_DEV_LPC, LPC_GENERIC_MEM_RANGE); - if (lgmr & LGMR_EN) { + if (lgmr & LPC_LGMR_EN) { printk(BIOS_ERR, "LPC: Cannot open window to resource %lx size %zx\n", base, size); @@ -177,21 +120,23 @@ void lpc_open_mmio_window(uintptr_t base, size_t size) return; } - if (size > LGMR_WINDOW_SIZE) { + if (size > LPC_LGMR_WINDOW_SIZE) { printk(BIOS_WARNING, "LPC: Resource %lx size %zx larger than window(%x)\n", - base, size, LGMR_WINDOW_SIZE); + base, size, LPC_LGMR_WINDOW_SIZE); } - lgmr = (base & LGMR_ADDR_MASK) | LGMR_EN; + lgmr = (base & LPC_LGMR_ADDR_MASK) | LPC_LGMR_EN; - pci_write_config32(PCH_DEV_LPC, REG_GENERIC_MEM_RANGE, lgmr); + pci_write_config32(PCH_DEV_LPC, LPC_GENERIC_MEM_RANGE, lgmr); } bool lpc_fits_fixed_mmio_window(uintptr_t base, size_t size) { resource_t res_end, range_end; const struct lpc_mmio_range *range; + const struct lpc_mmio_range *lpc_fixed_mmio_ranges = + soc_get_fixed_mmio_ranges(); for (range = lpc_fixed_mmio_ranges; range->size; range++) { range_end = range->base + range->size; @@ -207,3 +152,86 @@ bool lpc_fits_fixed_mmio_window(uintptr_t base, size_t size) } return false; } + +/* + * Set FAST_SPIBAR BIOS Control register based on input bit field. + */ +static void lpc_set_bios_control_reg(uint8_t bios_cntl_bit) +{ + device_t dev = PCH_DEV_LPC; + uint8_t bc_cntl; + + assert((bios_cntl_bit & (bios_cntl_bit - 1)) == 0); + bc_cntl = pci_read_config8(dev, LPC_BIOS_CNTL); + bc_cntl |= bios_cntl_bit; + pci_write_config8(dev, LPC_BIOS_CNTL, bc_cntl); + + /* + * Ensure an additional read back after performing lock down + */ + pci_read_config8(PCH_DEV_LPC, LPC_BIOS_CNTL); +} + +/* +* Set LPC BIOS Control BILD bit. +*/ +void lpc_set_bios_interface_lock_down(void) +{ + lpc_set_bios_control_reg(LPC_BC_BILD); +} + +/* +* Set LPC BIOS Control LE bit. +*/ +void lpc_set_lock_enable(void) +{ + lpc_set_bios_control_reg(LPC_BC_LE); +} + +/* +* Set LPC BIOS Control EISS bit. +*/ +void lpc_set_eiss(void) +{ + lpc_set_bios_control_reg(LPC_BC_EISS); +} + +/* +* Set LPC Serial IRQ mode. +*/ +void lpc_set_serirq_mode(enum serirq_mode mode) +{ + device_t dev = PCH_DEV_LPC; + uint8_t scnt; + + scnt = pci_read_config8(dev, LPC_SERIRQ_CTL); + scnt &= ~(LPC_SCNT_EN | LPC_SCNT_MODE); + + switch (mode) { + case SERIRQ_QUIET: + scnt |= LPC_SCNT_EN; + break; + case SERIRQ_CONTINUOUS: + scnt |= LPC_SCNT_EN | LPC_SCNT_MODE; + break; + case SERIRQ_OFF: + default: + break; + } + + pci_write_config8(dev, LPC_SERIRQ_CTL, scnt); +} + + +void lpc_io_setup_comm_a_b(void) +{ + /* + * Setup I/O Decode Range Register for LPC + * ComA Range 3F8h-3FFh [2:0] + * ComB Range 2F8h-2FFh [6:4] + */ + pci_write_config16(PCH_DEV_LPC, LPC_IO_DECODE, + LPC_IOD_COMA_RANGE | LPC_IOD_COMB_RANGE); + /* Enable ComA and ComB Port */ + lpc_enable_fixed_io_ranges(LPC_IOE_COMA_EN | LPC_IOE_COMB_EN); +} |