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>
diff --git a/src/soc/intel/cannonlake/Kconfig b/src/soc/intel/cannonlake/Kconfig
index 03f98d2..cb90248 100644
--- a/src/soc/intel/cannonlake/Kconfig
+++ b/src/soc/intel/cannonlake/Kconfig
@@ -24,6 +24,7 @@
 	select HAVE_MONOTONIC_TIMER
 	select INTEL_CAR_NEM_ENHANCED
 	select INTEL_GMA_ADD_VBT_DATA_FILE if RUN_FSP_GOP
+	select IOAPIC
 	select PARALLEL_MP
 	select PARALLEL_MP_AP_WORK
 	select PLATFORM_USES_FSP2_0
@@ -43,6 +44,8 @@
 	select SOC_INTEL_COMMON_BLOCK_FAST_SPI
 	select SOC_INTEL_COMMON_BLOCK_GPIO
 	select SOC_INTEL_COMMON_BLOCK_GSPI
+	select SOC_INTEL_COMMON_BLOCK_ITSS
+	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/cannonlake/Makefile.inc b/src/soc/intel/cannonlake/Makefile.inc
index e06c3ef..80bc791 100644
--- a/src/soc/intel/cannonlake/Makefile.inc
+++ b/src/soc/intel/cannonlake/Makefile.inc
@@ -32,6 +32,7 @@
 ramstage-y += gpio.c
 ramstage-y += gspi.c
 ramstage-y += gpio.c
+ramstage-y += lpc.c
 ramstage-y += memmap.c
 ramstage-y += pmc.c
 ramstage-y += pmutil.c
diff --git a/src/soc/intel/cannonlake/chip.h b/src/soc/intel/cannonlake/chip.h
index 5a4dfd3..ee908f0 100644
--- a/src/soc/intel/cannonlake/chip.h
+++ b/src/soc/intel/cannonlake/chip.h
@@ -194,6 +194,9 @@
 
 	/* Enable/Disable EIST. 1b:Enabled, 0b:Disabled */
 	uint8_t eist_enable;
+
+	/* Statically clock gate 8254 PIT. */
+	uint8_t clock_gate_8254;
 	/* Enable C6 DRAM */
 	uint8_t enable_c6dram;
 	/*
diff --git a/src/soc/intel/cannonlake/include/soc/irq.h b/src/soc/intel/cannonlake/include/soc/irq.h
new file mode 100644
index 0000000..5b6715f
--- /dev/null
+++ b/src/soc/intel/cannonlake/include/soc/irq.h
@@ -0,0 +1,106 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * 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.
+ */
+
+#ifndef _SOC_IRQ_H_
+#define _SOC_IRQ_H_
+
+#define GPIO_IRQ14 14
+#define GPIO_IRQ15 15
+
+#define PCH_IRQ10 10
+#define PCH_IRQ11 11
+
+#define SCI_IRQ9 9
+#define SCI_IRQ10 10
+#define SCI_IRQ11 11
+#define SCI_IRQ20 20
+#define SCI_IRQ21 21
+#define SCI_IRQ22 22
+#define SCI_IRQ23 23
+
+#define TCO_IRQ9 9
+#define TCO_IRQ10 10
+#define TCO_IRQ11 11
+#define TCO_IRQ20 20
+#define TCO_IRQ21 21
+#define TCO_IRQ22 22
+#define TCO_IRQ23 23
+
+#define LPSS_I2C0_IRQ 16
+#define LPSS_I2C1_IRQ 17
+#define LPSS_I2C2_IRQ 18
+#define LPSS_I2C3_IRQ 19
+#define LPSS_I2C4_IRQ 32
+#define LPSS_I2C5_IRQ 33
+#define LPSS_SPI0_IRQ 22
+#define LPSS_SPI1_IRQ 23
+#define LPSS_SPI2_IRQ 24
+#define LPSS_UART0_IRQ 20
+#define LPSS_UART1_IRQ 21
+#define LPSS_UART2_IRQ 34
+#define SDIO_IRQ 22
+
+#define cAVS_INTA_IRQ 16
+#define SMBUS_INTA_IRQ 16
+#define SMBUS_INTB_IRQ 17
+#define GbE_INTA_IRQ 16
+#define GbE_INTC_IRQ 18
+#define TRACE_HUB_INTA_IRQ 16
+#define TRACE_HUB_INTD_IRQ 19
+
+#define eMMC_IRQ 16
+#define SD_IRQ 19
+
+#define PCIE_1_IRQ 16
+#define PCIE_2_IRQ 17
+#define PCIE_3_IRQ 18
+#define PCIE_4_IRQ 19
+#define PCIE_5_IRQ 16
+#define PCIE_6_IRQ 17
+#define PCIE_7_IRQ 18
+#define PCIE_8_IRQ 19
+#define PCIE_9_IRQ 16
+#define PCIE_10_IRQ 17
+#define PCIE_11_IRQ 18
+#define PCIE_12_IRQ 19
+
+#define SATA_IRQ 16
+
+#define HECI_1_IRQ 16
+#define HECI_2_IRQ 17
+#define IDER_IRQ 18
+#define KT_IRQ 19
+#define HECI_3_IRQ 16
+
+#define XHCI_IRQ 16
+#define OTG_IRQ 17
+#define THRMAL_IRQ 16
+#define CNViWIFI_IRQ 16
+#define UFS_IRQ 16
+#define CIO_INTA_IRQ 16
+#define CIO_INTD_IRQ 19
+#define ISH_IRQ 20
+
+#define PEG_RP_INTA_IRQ 16
+#define PEG_RP_INTB_IRQ 17
+#define PEG_RP_INTC_IRQ 18
+#define PEG_RP_INTD_IRQ 19
+
+#define IGFX_IRQ 16
+#define SA_THERMAL_IRQ 16
+#define SKYCAM_IRQ 16
+#define GMM_IRQ 16
+#endif /* _SOC_IRQ_H_ */
diff --git a/src/soc/intel/cannonlake/include/soc/itss.h b/src/soc/intel/cannonlake/include/soc/itss.h
new file mode 100644
index 0000000..06dcc2e
--- /dev/null
+++ b/src/soc/intel/cannonlake/include/soc/itss.h
@@ -0,0 +1,23 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * 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.
+ */
+
+#ifndef SOC_INTEL_CNL_ITSS_H
+#define SOC_INTEL_CNL_ITSS_H
+
+#define ITSS_MAX_IRQ	119
+#define IRQS_PER_IPC	32
+#define NUM_IPC_REGS	((ITSS_MAX_IRQ + IRQS_PER_IPC - 1)/IRQS_PER_IPC)
+
+#endif	/* SOC_INTEL_CNL_ITSS_H */
diff --git a/src/soc/intel/cannonlake/lpc.c b/src/soc/intel/cannonlake/lpc.c
new file mode 100644
index 0000000..e906d99
--- /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);
+}