aboutsummaryrefslogtreecommitdiff
path: root/src/soc/intel/cannonlake/lpc.c
diff options
context:
space:
mode:
authorLijian Zhao <lijian.zhao@intel.com>2017-08-29 14:37:17 -0700
committerAaron Durbin <adurbin@chromium.org>2017-10-03 20:23:32 +0000
commita515849259f71eb92d5465b6bcd9957b73db1889 (patch)
treeb0bed6c3ccc582d0a479ee1324002bf44fe90f36 /src/soc/intel/cannonlake/lpc.c
parent1483d1fcda092283c303fd1d4f4aeca75dcd0bf1 (diff)
soc/intel/cannonlake: Add lpc pci driver
1.Add common ITSS support as part of LPC driver init code. 2.Add LPC pci driver for CNL Change-Id: I6c810fd7158e1498664b77eecae22132e2f6878f Signed-off-by: Lijian Zhao <lijian.zhao@intel.com> Reviewed-on: https://review.coreboot.org/21277 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Diffstat (limited to 'src/soc/intel/cannonlake/lpc.c')
-rw-r--r--src/soc/intel/cannonlake/lpc.c206
1 files changed, 206 insertions, 0 deletions
diff --git a/src/soc/intel/cannonlake/lpc.c b/src/soc/intel/cannonlake/lpc.c
new file mode 100644
index 0000000000..e906d9981d
--- /dev/null
+++ b/src/soc/intel/cannonlake/lpc.c
@@ -0,0 +1,206 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2008-2009 coresystems GmbH
+ * Copyright (C) 2014 Google Inc.
+ * Copyright (C) 2017 Intel Corporation.
+ *
+ * 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.
+ */
+
+#include "chip.h"
+#include <console/console.h>
+#include <delay.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <pc80/isa-dma.h>
+#include <pc80/i8259.h>
+#include <arch/io.h>
+#include <arch/ioapic.h>
+#include <intelblocks/itss.h>
+#include <intelblocks/lpc_lib.h>
+#include <intelblocks/pcr.h>
+#include <reg_script.h>
+#include <soc/iomap.h>
+#include <soc/pci_devs.h>
+#include <soc/pcr_ids.h>
+
+/*
+* As per the BWG, Chapter 5.9.1. "PCH BIOS component will reserve
+* certain memory range as reserved range for BIOS usage.
+* For this SOC, the range will be from 0FC800000h till FE7FFFFFh"
+*/
+static const struct lpc_mmio_range cnl_lpc_fixed_mmio_ranges[] = {
+ { PCH_PRESERVED_BASE_ADDRESS, PCH_PRESERVED_BASE_SIZE },
+ { 0, 0 }
+};
+
+const struct lpc_mmio_range *soc_get_fixed_mmio_ranges()
+{
+ return cnl_lpc_fixed_mmio_ranges;
+}
+
+static void pch_enable_ioapic(const struct device *dev)
+{
+ u32 reg32;
+ /* PCH-LP has 120 redirection entries */
+ const int redir_entries = 120;
+
+ set_ioapic_id((void *)IO_APIC_ADDR, 0x02);
+
+ /* affirm full set of redirection table entries ("write once") */
+ reg32 = io_apic_read((void *)IO_APIC_ADDR, 0x01);
+
+ reg32 &= ~0x00ff0000;
+ reg32 |= (redir_entries - 1) << 16;
+
+ io_apic_write((void *)IO_APIC_ADDR, 0x01, reg32);
+
+ /*
+ * Select Boot Configuration register (0x03) and
+ * use Processor System Bus (0x01) to deliver interrupts.
+ */
+ io_apic_write((void *)IO_APIC_ADDR, 0x03, 0x01);
+}
+
+void soc_get_gen_io_dec_range(const struct device *dev, uint32_t *gen_io_dec)
+{
+ const config_t *config = dev->chip_info;
+
+ gen_io_dec[0] = config->gen1_dec;
+ gen_io_dec[1] = config->gen2_dec;
+ gen_io_dec[2] = config->gen3_dec;
+ gen_io_dec[3] = config->gen4_dec;
+}
+
+void soc_setup_dmi_pcr_io_dec(uint32_t *gen_io_dec)
+{
+ /* Mirror these same settings in DMI PCR */
+ pcr_write32(PID_DMI, PCR_DMI_LPCLGIR1, gen_io_dec[0]);
+ pcr_write32(PID_DMI, PCR_DMI_LPCLGIR2, gen_io_dec[1]);
+ pcr_write32(PID_DMI, PCR_DMI_LPCLGIR3, gen_io_dec[2]);
+ pcr_write32(PID_DMI, PCR_DMI_LPCLGIR4, gen_io_dec[3]);
+}
+
+
+/*
+ * PIRQ[n]_ROUT[3:0] - PIRQ Routing Control
+ * 0x00 - 0000 = Reserved
+ * 0x01 - 0001 = Reserved
+ * 0x02 - 0010 = Reserved
+ * 0x03 - 0011 = IRQ3
+ * 0x04 - 0100 = IRQ4
+ * 0x05 - 0101 = IRQ5
+ * 0x06 - 0110 = IRQ6
+ * 0x07 - 0111 = IRQ7
+ * 0x08 - 1000 = Reserved
+ * 0x09 - 1001 = IRQ9
+ * 0x0A - 1010 = IRQ10
+ * 0x0B - 1011 = IRQ11
+ * 0x0C - 1100 = IRQ12
+ * 0x0D - 1101 = Reserved
+ * 0x0E - 1110 = IRQ14
+ * 0x0F - 1111 = IRQ15
+ * PIRQ[n]_ROUT[7] - PIRQ Routing Control
+ * 0x80 - The PIRQ is not routed.
+ */
+
+void soc_pch_pirq_init(const struct device *dev)
+{
+ const config_t *config = dev->chip_info;
+ uint8_t pch_interrupt_routing[MAX_PXRC_CONFIG];
+
+ pch_interrupt_routing[0] = config->pirqa_routing;
+ pch_interrupt_routing[1] = config->pirqb_routing;
+ pch_interrupt_routing[2] = config->pirqc_routing;
+ pch_interrupt_routing[3] = config->pirqd_routing;
+ pch_interrupt_routing[4] = config->pirqe_routing;
+ pch_interrupt_routing[5] = config->pirqf_routing;
+ pch_interrupt_routing[6] = config->pirqg_routing;
+ pch_interrupt_routing[7] = config->pirqh_routing;
+
+ itss_irq_init(pch_interrupt_routing);
+
+ device_t irq_dev;
+ for (irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) {
+ u8 int_pin = 0, int_line = 0;
+
+ if (!irq_dev->enabled || irq_dev->path.type != DEVICE_PATH_PCI)
+ continue;
+
+ int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN);
+
+ switch (int_pin) {
+ case 1: /* INTA# */
+ int_line = config->pirqa_routing;
+ break;
+ case 2: /* INTB# */
+ int_line = config->pirqb_routing;
+ break;
+ case 3: /* INTC# */
+ int_line = config->pirqc_routing;
+ break;
+ case 4: /* INTD# */
+ int_line = config->pirqd_routing;
+ break;
+ }
+
+ if (!int_line)
+ continue;
+
+ pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, int_line);
+ }
+}
+
+static void pch_misc_init(void)
+{
+ uint8_t reg8;
+
+ /* Setup NMI on errors, disable SERR */
+ reg8 = (inb(0x61)) & 0xf0;
+ outb(0x61, (reg8 | (1 << 2)));
+
+ /* Disable NMI sources */
+ outb(0x70, (1 << 7));
+};
+
+static void clock_gate_8254(const struct device *dev)
+{
+ const config_t *config = dev->chip_info;
+
+ if (!config->clock_gate_8254)
+ return;
+
+ itss_clock_gate_8254();
+}
+
+void lpc_init(struct device *dev)
+{
+ /* Legacy initialization */
+ isa_dma_init();
+ pch_misc_init();
+
+ /* Enable CLKRUN_EN for power gating LPC */
+ lpc_enable_pci_clk_cntl();
+
+ /* Set LPC Serial IRQ mode */
+ if (IS_ENABLED(CONFIG_SERIRQ_CONTINUOUS_MODE))
+ lpc_set_serirq_mode(SERIRQ_CONTINUOUS);
+ else
+ lpc_set_serirq_mode(SERIRQ_QUIET);
+
+ /* Interrupt configuration */
+ pch_enable_ioapic(dev);
+ soc_pch_pirq_init(dev);
+ setup_i8259();
+ i8259_configure_irq_trigger(9, 1);
+ clock_gate_8254(dev);
+}