/* * This file is part of the coreboot project. * * Copyright (C) 2008-2009 coresystems GmbH * Copyright (C) 2014 Google Inc. * Copyright (C) 2015 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. * * 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. */ #include #include "chip.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if IS_ENABLED(CONFIG_CHROMEOS) #include #endif static void pch_enable_ioapic(struct device *dev) { u32 reg32; 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); /* PCH-LP has 39 redirection entries */ reg32 &= ~0x00ff0000; reg32 |= 0x00270000; 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); } /* * 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. */ static void pch_pirq_init(device_t dev) { device_t irq_dev; config_t *config = dev->chip_info; pcr_write8(PID_ITSS, R_PCH_PCR_ITSS_PIRQA_ROUT, config->pirqa_routing); pcr_write8(PID_ITSS, R_PCH_PCR_ITSS_PIRQB_ROUT, config->pirqb_routing); pcr_write8(PID_ITSS, R_PCH_PCR_ITSS_PIRQC_ROUT, config->pirqc_routing); pcr_write8(PID_ITSS, R_PCH_PCR_ITSS_PIRQD_ROUT, config->pirqd_routing); pcr_write8(PID_ITSS, R_PCH_PCR_ITSS_PIRQE_ROUT, config->pirqe_routing); pcr_write8(PID_ITSS, R_PCH_PCR_ITSS_PIRQF_ROUT, config->pirqf_routing); pcr_write8(PID_ITSS, R_PCH_PCR_ITSS_PIRQG_ROUT, config->pirqg_routing); pcr_write8(PID_ITSS, R_PCH_PCR_ITSS_PIRQH_ROUT, config->pirqh_routing); 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 const struct reg_script pch_misc_init_script[] = { /* Setup NMI on errors, disable SERR */ REG_IO_RMW8(0x61, ~0xf0, (1 << 2)), /* Disable NMI sources */ REG_IO_OR8(0x70, (1 << 7)), /* Enable BIOS updates outside of SMM */ REG_PCI_RMW8(0xdc, ~(1 << 5), 0), /* Setup SERIRQ, enable continuous mode */ REG_PCI_OR8(SERIRQ_CNTL, (1 << 7) | (1 << 6)), #if !IS_ENABLED(CONFIG_SERIRQ_CONTINUOUS_MODE) REG_PCI_RMW8(SERIRQ_CNTL, ~(1 << 6), 0), #endif REG_SCRIPT_END }; static void lpc_init(struct device *dev) { /* Legacy initialization */ isa_dma_init(); reg_script_run_on_dev(dev, pch_misc_init_script); /* Interrupt configuration */ pch_enable_ioapic(dev); pch_pirq_init(dev); setup_i8259(); i8259_configure_irq_trigger(9, 1); } static void pch_lpc_add_mmio_resources(device_t dev) { u32 reg; struct resource *res; /* * 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 0FD000000h till FE7FFFFFh" * Hence, use FD000000h as PCR_BASE */ const u32 default_decode_base = PCH_PCR_BASE_ADDRESS; res = new_resource(dev, PCI_BASE_ADDRESS_0); res->base = default_decode_base; res->size = 0 - default_decode_base; res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED | IORESOURCE_RESERVE; /* Check LPC Memory Decode register. */ reg = pci_read_config32(dev, LGMR); if (reg & 1) { reg &= ~0xffff; if (reg < default_decode_base) { res = new_resource(dev, LGMR); res->base = reg; res->size = 16 * 1024; res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED | IORESOURCE_RESERVE; } } } /* Default IO range claimed by the LPC device. The upper bound is exclusive. */ #define LPC_DEFAULT_IO_RANGE_LOWER 0 #define LPC_DEFAULT_IO_RANGE_UPPER 0x1000 static inline int pch_io_range_in_default(u16 base, u16 size) { /* Does it start above the range? */ if (base >= LPC_DEFAULT_IO_RANGE_UPPER) return 0; /* Is it entirely contained? */ if (base >= LPC_DEFAULT_IO_RANGE_LOWER && (base + size) < LPC_DEFAULT_IO_RANGE_UPPER) return 1; /* This will return not in range for partial overlaps. */ return 0; } /* * Note: this function assumes there is no overlap with the default LPC device's * claimed range: LPC_DEFAULT_IO_RANGE_LOWER -> LPC_DEFAULT_IO_RANGE_UPPER. */ static void pch_lpc_add_io_resource(device_t dev, u16 base, u16 size, int index) { struct resource *res; if (pch_io_range_in_default(base, size)) return; res = new_resource(dev, index); res->base = base; res->size = size; res->flags = IORESOURCE_IO | IORESOURCE_ASSIGNED | IORESOURCE_FIXED; } static void pch_lpc_add_gen_io_resources(device_t dev, int reg_value, int index) { /* * Check if the register is enabled. If so and the base exceeds the * device's deafult claim range add the resoure. */ if (reg_value & 1) { u16 base = reg_value & 0xfffc; u16 size = (0x3 | ((reg_value >> 16) & 0xfc)) + 1; pch_lpc_add_io_resource(dev, base, size, index); } } static void pch_lpc_add_io_resources(device_t dev) { struct resource *res; config_t *config = dev->chip_info; /* Add the default claimed IO range for the LPC device. */ res = new_resource(dev, 0); res->base = LPC_DEFAULT_IO_RANGE_LOWER; res->size = LPC_DEFAULT_IO_RANGE_UPPER - LPC_DEFAULT_IO_RANGE_LOWER; res->flags = IORESOURCE_IO | IORESOURCE_ASSIGNED | IORESOURCE_FIXED; /* LPC Generic IO Decode range. */ pch_lpc_add_gen_io_resources(dev, config->gen1_dec, LPC_GEN1_DEC); pch_lpc_add_gen_io_resources(dev, config->gen2_dec, LPC_GEN2_DEC); pch_lpc_add_gen_io_resources(dev, config->gen3_dec, LPC_GEN3_DEC); pch_lpc_add_gen_io_resources(dev, config->gen4_dec, LPC_GEN4_DEC); } static void pch_lpc_read_resources(device_t dev) { global_nvs_t *gnvs; /* Get the normal PCI resources of this device. */ pci_dev_read_resources(dev); /* Add non-standard MMIO resources. */ pch_lpc_add_mmio_resources(dev); /* Add IO resources. */ pch_lpc_add_io_resources(dev); /* Allocate ACPI NVS in CBMEM */ gnvs = cbmem_add(CBMEM_ID_ACPI_GNVS, sizeof(global_nvs_t)); if (!acpi_is_wakeup_s3() && gnvs) memset(gnvs, 0, sizeof(global_nvs_t)); } static struct device_operations device_ops = { .read_resources = &pch_lpc_read_resources, .set_resources = &pci_dev_set_resources, .enable_resources = &pci_dev_enable_resources, .acpi_inject_dsdt_generator = southcluster_inject_dsdt, .write_acpi_tables = southcluster_write_acpi_tables, .init = &lpc_init, .scan_bus = &scan_lpc_bus, .ops_pci = &soc_pci_ops, }; static const unsigned short pci_device_ids[] = { PCH_SPT_LP_SAMPLE, PCH_SPT_LP_U_BASE, PCH_SPT_LP_U_PREMIUM, PCH_SPT_LP_Y_PREMIUM, 0 }; static const struct pci_driver pch_lpc __pci_driver = { .ops = &device_ops, .vendor = PCI_VENDOR_ID_INTEL, .devices = pci_device_ids, };