Hannah Williams (hannah.williams@intel.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/17809
-gerrit
commit 4f5e229316fa9b66b4882b1623b704d05c541019 Author: Hannah Williams hannah.williams@intel.com Date: Mon Oct 3 14:52:26 2016 -0700
soc/glk: Add GLK SOC (WIP - need more patches for successful build)
Derived from Apollolake Following IP blocks are same for Apollolake and GLK, hence starting with Apollolake codebase UART,SPI, I2C, SMBUS, SDIO, Graphics, PCIe, USB
Change-Id: Ie1c8964d6bc463cd7f71ddbb8544cfbd79183bd3 Signed-off-by: Hannah Williams hannah.williams@intel.com --- src/soc/intel/glk/Kconfig | 257 +++++++++++++ src/soc/intel/glk/Makefile.inc | 142 +++++++ src/soc/intel/glk/acpi.c | 266 +++++++++++++ src/soc/intel/glk/acpi/cpu.asl | 118 ++++++ src/soc/intel/glk/acpi/dptf.asl | 44 +++ src/soc/intel/glk/acpi/globalnvs.asl | 46 +++ src/soc/intel/glk/acpi/gpio.asl | 201 ++++++++++ src/soc/intel/glk/acpi/gpiolib.asl | 67 ++++ src/soc/intel/glk/acpi/lpc.asl | 23 ++ src/soc/intel/glk/acpi/lpss.asl | 116 ++++++ src/soc/intel/glk/acpi/northbridge.asl | 132 +++++++ src/soc/intel/glk/acpi/pch_hda.asl | 84 +++++ src/soc/intel/glk/acpi/pci_irqs.asl | 63 ++++ src/soc/intel/glk/acpi/pcie.asl | 126 +++++++ src/soc/intel/glk/acpi/platform.asl | 20 + src/soc/intel/glk/acpi/scs.asl | 67 ++++ src/soc/intel/glk/acpi/sleepstates.asl | 21 ++ src/soc/intel/glk/acpi/soc_int.asl | 58 +++ src/soc/intel/glk/acpi/southbridge.asl | 41 ++ src/soc/intel/glk/acpi/xhci.asl | 31 ++ src/soc/intel/glk/bootblock/bootblock.c | 187 ++++++++++ src/soc/intel/glk/bootblock/cache_as_ram.S | 251 +++++++++++++ src/soc/intel/glk/car.c | 58 +++ src/soc/intel/glk/chip.c | 462 +++++++++++++++++++++++ src/soc/intel/glk/chip.h | 124 ++++++ src/soc/intel/glk/cpu.c | 154 ++++++++ src/soc/intel/glk/dsp.c | 32 ++ src/soc/intel/glk/elog.c | 107 ++++++ src/soc/intel/glk/exit_car.S | 68 ++++ src/soc/intel/glk/gpio.c | 418 +++++++++++++++++++++ src/soc/intel/glk/graphics.c | 103 +++++ src/soc/intel/glk/heci.c | 36 ++ src/soc/intel/glk/i2c.c | 126 +++++++ src/soc/intel/glk/i2c_early.c | 116 ++++++ src/soc/intel/glk/include/FspUpd.h | 48 +++ src/soc/intel/glk/include/soc/acpi.h | 28 ++ src/soc/intel/glk/include/soc/cpu.h | 63 ++++ src/soc/intel/glk/include/soc/gpe.h | 139 +++++++ src/soc/intel/glk/include/soc/gpio.h | 177 +++++++++ src/soc/intel/glk/include/soc/gpio_defs.h | 559 ++++++++++++++++++++++++++++ src/soc/intel/glk/include/soc/heci.h | 43 +++ src/soc/intel/glk/include/soc/i2c.h | 50 +++ src/soc/intel/glk/include/soc/iomap.h | 42 +++ src/soc/intel/glk/include/soc/iosf.h | 42 +++ src/soc/intel/glk/include/soc/itss.h | 29 ++ src/soc/intel/glk/include/soc/lpc.h | 69 ++++ src/soc/intel/glk/include/soc/meminit.h | 121 ++++++ src/soc/intel/glk/include/soc/mmap_boot.h | 22 ++ src/soc/intel/glk/include/soc/nhlt.h | 43 +++ src/soc/intel/glk/include/soc/northbridge.h | 40 ++ src/soc/intel/glk/include/soc/nvs.h | 48 +++ src/soc/intel/glk/include/soc/p2sb.h | 23 ++ src/soc/intel/glk/include/soc/pci_devs.h | 122 ++++++ src/soc/intel/glk/include/soc/pci_ids.h | 47 +++ src/soc/intel/glk/include/soc/pm.h | 216 +++++++++++ src/soc/intel/glk/include/soc/romstage.h | 27 ++ src/soc/intel/glk/include/soc/smm.h | 41 ++ src/soc/intel/glk/include/soc/spi.h | 88 +++++ src/soc/intel/glk/include/soc/uart.h | 36 ++ src/soc/intel/glk/itss.c | 129 +++++++ src/soc/intel/glk/lpc.c | 176 +++++++++ src/soc/intel/glk/lpc_lib.c | 180 +++++++++ src/soc/intel/glk/meminit.c | 341 +++++++++++++++++ src/soc/intel/glk/memmap.c | 54 +++ src/soc/intel/glk/mmap_boot.c | 171 +++++++++ src/soc/intel/glk/nhlt.c | 142 +++++++ src/soc/intel/glk/northbridge.c | 169 +++++++++ src/soc/intel/glk/p2sb.c | 74 ++++ src/soc/intel/glk/pmc.c | 157 ++++++++ src/soc/intel/glk/pmutil.c | 543 +++++++++++++++++++++++++++ src/soc/intel/glk/reset.c | 73 ++++ src/soc/intel/glk/romstage.c | 192 ++++++++++ src/soc/intel/glk/smi.c | 87 +++++ src/soc/intel/glk/smihandler.c | 68 ++++ src/soc/intel/glk/spi.c | 395 ++++++++++++++++++++ src/soc/intel/glk/tsc_freq.c | 25 ++ src/soc/intel/glk/uart.c | 61 +++ src/soc/intel/glk/uart_early.c | 86 +++++ src/soc/intel/glk/xhci.c | 105 ++++++ 79 files changed, 9556 insertions(+)
diff --git a/src/soc/intel/glk/Kconfig b/src/soc/intel/glk/Kconfig new file mode 100644 index 0000000..9d40e3b --- /dev/null +++ b/src/soc/intel/glk/Kconfig @@ -0,0 +1,257 @@ +config SOC_INTEL_GLK + bool + help + Intel GLK support + +if SOC_INTEL_GLK +config CPU_SPECIFIC_OPTIONS + def_bool y + select ACPI_INTEL_HARDWARE_SLEEP_VALUES + select ARCH_BOOTBLOCK_X86_32 + select ARCH_RAMSTAGE_X86_32 + select ARCH_ROMSTAGE_X86_32 + select ARCH_VERSTAGE_X86_32 + select BOOTBLOCK_CONSOLE + select BOOT_DEVICE_SPI_FLASH_RW_NOMMAP_EARLY if BOOT_DEVICE_SPI_FLASH + select BOOT_DEVICE_SUPPORTS_WRITES + # CPU specific options + select CPU_INTEL_FIRMWARE_INTERFACE_TABLE + select IOAPIC + select SMP + select SSE2 + select SUPPORT_CPU_UCODE_IN_CBFS + # Audio options + select ACPI_NHLT + select SOC_INTEL_COMMON_NHLT + # Misc options + select C_ENVIRONMENT_BOOTBLOCK + select COLLECT_TIMESTAMPS + select COMMON_FADT + select GENERIC_GPIO_LIB + select HAVE_INTEL_FIRMWARE + select HAVE_SMI_HANDLER + select MMCONF_SUPPORT + select MMCONF_SUPPORT_DEFAULT + select NO_FIXED_XIP_ROM_SIZE + select NO_STAGE_CACHE + select NO_XIP_EARLY_STAGES + select PARALLEL_MP + select PCIEXP_ASPM + select PCIEXP_COMMON_CLOCK + select PCIEXP_CLK_PM + select PCIEXP_L1_SUB_STATE + select POSTCAR_CONSOLE + select POSTCAR_STAGE + select REG_SCRIPT + select RELOCATABLE_RAMSTAGE # Build fails if this is not selected + select RTC + select SMM_TSEG + select SOC_INTEL_COMMON + select SOC_INTEL_COMMON_ACPI + select SOC_INTEL_COMMON_ACPI_WAKE_SOURCE + select SOC_INTEL_COMMON_LPSS_I2C + select SOC_INTEL_COMMON_SMI + select UDELAY_TSC + select TSC_CONSTANT_RATE + select TSC_MONOTONIC_TIMER + select HAVE_MONOTONIC_TIMER + select PLATFORM_USES_FSP2_0 + select HAVE_HARD_RESET + select SOC_INTEL_COMMON + select SOC_INTEL_COMMON_GFX_OPREGION + select ADD_VBT_DATA_FILE + select SOC_INTEL_COMMON_RESET + +config CHROMEOS + select CHROMEOS_RAMOOPS_DYNAMIC + select EC_SOFTWARE_SYNC if EC_GOOGLE_CHROMEEC + select SEPARATE_VERSTAGE + select VBOOT_OPROM_MATTERS + select VBOOT_SAVE_RECOVERY_REASON_ON_REBOOT + select VBOOT_STARTS_IN_BOOTBLOCK + select VBOOT_VBNV_CMOS + select VBOOT_VBNV_CMOS_BACKUP_TO_FLASH + select VIRTUAL_DEV_SWITCH + +config TPM_ON_FAST_SPI + bool + default n + select LPC_TPM + help + TPM part is conntected on Fast SPI interface, but the LPC MMIO + TPM transactions are decoded and serialized over the SPI interface. + +config SOC_INTEL_COMMON_RESET + bool + default y + +config MMCONF_BASE_ADDRESS + hex "PCI MMIO Base Address" + default 0xe0000000 + +config IOSF_BASE_ADDRESS + hex "MMIO Base Address of sideband bus" + default 0xd0000000 + +config DCACHE_RAM_BASE + hex "Base address of cache-as-RAM" + default 0xfef00000 + +config DCACHE_RAM_SIZE + hex "Length in bytes of cache-as-RAM" + default 0xc0000 + help + The size of the cache-as-ram region required during bootblock + and/or romstage. + +config DCACHE_BSP_STACK_SIZE + hex + default 0x4000 + help + The amount of anticipated stack usage in CAR by bootblock and + other stages. + +config CPU_ADDR_BITS + int + default 36 + +config SOC_INTEL_COMMON_LPSS_I2C_CLOCK_MHZ + depends on SOC_INTEL_COMMON_LPSS_I2C + int + default 133 + +config CONSOLE_UART_BASE_ADDRESS + depends on CONSOLE_SERIAL + hex "MMIO base address for UART" + default 0xde000000 + +config SOC_UART_DEBUG + bool "Enable SoC UART debug port selected by UART_FOR_CONSOLE." + default n + select CONSOLE_SERIAL + select DRIVERS_UART + select DRIVERS_UART_8250MEM_32 + select NO_UART_ON_SUPERIO + +# 32KiB bootblock is all that is mapped in by the CSE at top of 4GiB. +config C_ENV_BOOTBLOCK_SIZE + hex + default 0x8000 + +# This SoC does not map SPI flash like many previous SoC. Therefore we provide +# a custom media driver that facilitates mapping +config X86_TOP4G_BOOTMEDIA_MAP + bool + default n + +config ROMSTAGE_ADDR + hex + default 0xfef20000 + help + The base address (in CAR) where romstage should be linked + +config VERSTAGE_ADDR + hex + default 0xfef40000 + help + The base address (in CAR) where verstage should be linked + +config CACHE_MRC_SETTINGS + bool + default y + +config FSP_M_ADDR + hex + default 0xfef40000 + help + The address FSP-M will be relocated to during build time + +config NEED_LBP2 + bool "Write contents for logical boot partition 2." + default n + help + Write the contents from a file into the logical boot partition 2 + region defined by LBP2_FMAP_NAME. + +config LBP2_FMAP_NAME + string "Name of FMAP region to put logical boot partition 2" + depends on NEED_LBP2 + default "SIGN_CSE" + help + Name of FMAP region to write logical boot partition 2 data. + +config LBP2_FILE_NAME + string "Path of file to write to logical boot partition 2 region" + depends on NEED_LBP2 + default "3rdparty/blobs/mainboard/$(CONFIG_MAINBOARD_DIR)/lbp2.bin" + help + Name of file to store in the logical boot partition 2 region. + +config NEED_IFWI + bool "Write content into IFWI region" + default n + help + Write the content from a file into IFWI region defined by + IFWI_FMAP_NAME. + +config IFWI_FMAP_NAME + string "Name of FMAP region to pull IFWI into" + depends on NEED_IFWI + default "IFWI" + help + Name of FMAP region to write IFWI. + +config IFWI_FILE_NAME + string "Path of file to write to IFWI region" + depends on NEED_IFWI + default "3rdparty/blobs/mainboard/$(CONFIG_MAINBOARD_DIR)/ifwi.bin" + help + Name of file to store in the IFWI region. + +config NHLT_DMIC_2CH_16B + bool + depends on ACPI_NHLT + default n + help + Include DSP firmware settings for 2 channel 16B DMIC array. + +config NHLT_MAX98357 + bool + depends on ACPI_NHLT + default n + help + Include DSP firmware settings for headset codec. + +config NHLT_DA7219 + bool + depends on ACPI_NHLT + default n + help + Include DSP firmware settings for headset codec. +choice + prompt "Cache-as-ram implementation" + default CAR_CQOS + help + This option allows you to select how cache-as-ram (CAR) is set up. + +config CAR_NEM + bool "Non-evict mode" + help + Traditionally, CAR is set up by using Non-Evict mode. This method + does not allow CAR and cache to co-exist, because cache fills are + block in NEM mode. + +config CAR_CQOS + bool "Cache Quality of Service" + help + Cache Quality of Service allows more fine-grained control of cache + usage. As result, it is possible to set up portion of L2 cache for + CAR and use remainder for actual caching. + +endchoice + +config SPI_FLASH_INCLUDE_ALL_DRIVERS + bool + default n + +endif diff --git a/src/soc/intel/glk/Makefile.inc b/src/soc/intel/glk/Makefile.inc new file mode 100644 index 0000000..fb59981 --- /dev/null +++ b/src/soc/intel/glk/Makefile.inc @@ -0,0 +1,142 @@ +ifeq ($(CONFIG_SOC_INTEL_GLK),y) + +subdirs-y += ../../../cpu/intel/microcode +subdirs-y += ../../../cpu/intel/turbo +subdirs-y += ../../../cpu/x86/lapic +subdirs-y += ../../../cpu/x86/mtrr +subdirs-y += ../../../cpu/x86/smm +subdirs-y += ../../../cpu/x86/tsc +subdirs-y += ../../../cpu/x86/cache + +bootblock-y += bootblock/bootblock.c +bootblock-y += bootblock/cache_as_ram.S +bootblock-y += bootblock/bootblock.c +bootblock-y += car.c +bootblock-y += gpio.c +bootblock-y += heci.c +bootblock-y += itss.c +bootblock-y += lpc_lib.c +bootblock-y += mmap_boot.c +bootblock-y += pmutil.c +bootblock-y += spi.c +bootblock-y += tsc_freq.c +bootblock-$(CONFIG_SOC_UART_DEBUG) += uart_early.c + +romstage-y += car.c +romstage-$(CONFIG_PLATFORM_USES_FSP2_0) += romstage.c +romstage-y += gpio.c +romstage-y += heci.c +romstage-y += i2c_early.c +romstage-y += itss.c +romstage-$(CONFIG_SOC_UART_DEBUG) += uart_early.c +romstage-y += lpc_lib.c +romstage-y += memmap.c +romstage-y += meminit.c +romstage-y += mmap_boot.c +romstage-y += tsc_freq.c +romstage-y += pmutil.c +romstage-y += reset.c +romstage-y += spi.c + +smm-y += mmap_boot.c +smm-y += pmutil.c +smm-y += gpio.c +smm-y += smihandler.c +smm-y += spi.c +smm-y += tsc_freq.c +smm-y += uart_early.c + +ramstage-$(CONFIG_HAVE_ACPI_TABLES) += acpi.c +ramstage-y += cpu.c +ramstage-y += chip.c +ramstage-y += elog.c +ramstage-y += dsp.c +ramstage-y += gpio.c +ramstage-y += graphics.c +ramstage-y += heci.c +ramstage-y += i2c.c +ramstage-y += itss.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 +ramstage-y += uart.c +ramstage-y += nhlt.c +ramstage-y += northbridge.c +ramstage-y += spi.c +ramstage-y += tsc_freq.c +ramstage-y += pmutil.c +ramstage-y += pmc.c +ramstage-y += reset.c +ramstage-y += smi.c +ramstage-y += spi.c +ramstage-y += xhci.c + +postcar-y += exit_car.S +postcar-y += memmap.c +postcar-y += mmap_boot.c +postcar-y += spi.c +postcar-$(CONFIG_SOC_UART_DEBUG) += uart_early.c +postcar-y += tsc_freq.c + +verstage-y += car.c +verstage-y += i2c_early.c +verstage-y += heci.c +verstage-y += memmap.c +verstage-y += mmap_boot.c +verstage-$(CONFIG_SOC_UART_DEBUG) += uart_early.c +verstage-y += tsc_freq.c +verstage-y += pmutil.c +verstage-y += reset.c +verstage-y += spi.c + +CPPFLAGS_common += -I$(src)/soc/intel/glk/include +CPPFLAGS_common += -I$(src)/vendorcode/intel/fsp/fsp2_0/apollolake + +# Since FSP-M runs in CAR we need to relocate it to a specific address +$(CONFIG_FSP_M_CBFS)-options := -b $(CONFIG_FSP_M_ADDR) + +ifeq ($(CONFIG_NEED_LBP2),y) +files_added:: + $(CBFSTOOL) $(obj)/coreboot.rom write -r $(CONFIG_LBP2_FMAP_NAME) -f $(CONFIG_LBP2_FILE_NAME) --fill-upward +endif + +# Bootblock on Apollolake platform lies in the IFWI region. In order to place +# the bootblock at the right location in IFWI image - +# a. Using ifwitool: +# 1. Create IFWI image (ifwi.bin.tmp) from input image +# (CONFIG_IFWI_FILE_NAME). +# 2. Delete OBBP sub-partition, if present. +# 3. Replace IBBL directory entry in IBBP sub-partition with currently +# generated bootblock.bin. +# b. Using cbfstool: +# 1. Write ifwi.bin.tmp to coreboot.rom using CONFIG_IFWI_FMAP_NAME. +ifeq ($(CONFIG_NEED_IFWI),y) +files_added:: $(IFWITOOL) + $(IFWITOOL) $(CONFIG_IFWI_FILE_NAME) create -f $(objcbfs)/ifwi.bin.tmp + $(IFWITOOL) $(objcbfs)/ifwi.bin.tmp delete -n OBBP + $(IFWITOOL) $(objcbfs)/ifwi.bin.tmp replace -n IBBP -f $(objcbfs)/bootblock.bin -d -e IBBL + $(CBFSTOOL) $(obj)/coreboot.rom write -r $(CONFIG_IFWI_FMAP_NAME) -f $(objcbfs)/ifwi.bin.tmp --fill-upward +endif + +# DSP firmware settings files. +NHLT_BLOB_PATH = 3rdparty/blobs/soc/intel/apollolake/nhlt-blobs +DMIC_2CH_48KHZ_16B = dmic-2ch-48khz-16b.bin +MAX98357_RENDER = max98357-render-2ch-48khz-24b.bin +DA7219_RENDER_CAPTURE = dialog-2ch-48khz-24b.bin + +cbfs-files-$(CONFIG_NHLT_DMIC_2CH_16B) += $(DMIC_2CH_48KHZ_16B) +$(DMIC_2CH_48KHZ_16B)-file := $(NHLT_BLOB_PATH)/$(DMIC_2CH_48KHZ_16B) +$(DMIC_2CH_48KHZ_16B)-type := raw + +cbfs-files-$(CONFIG_NHLT_MAX98357) += $(MAX98357_RENDER) +$(MAX98357_RENDER)-file := $(NHLT_BLOB_PATH)/$(MAX98357_RENDER) +$(MAX98357_RENDER)-type := raw + +cbfs-files-$(CONFIG_NHLT_DA7219) += $(DA7219_RENDER_CAPTURE) +$(DA7219_RENDER_CAPTURE)-file := $(NHLT_BLOB_PATH)/$(DA7219_RENDER_CAPTURE) +$(DA7219_RENDER_CAPTURE)-type := raw + +endif diff --git a/src/soc/intel/glk/acpi.c b/src/soc/intel/glk/acpi.c new file mode 100644 index 0000000..ca479b8 --- /dev/null +++ b/src/soc/intel/glk/acpi.c @@ -0,0 +1,266 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2016 Intel Corp. + * (Written by Lance Zhao lijian.zhao@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. + */ + +#include <arch/acpi.h> +#include <arch/acpigen.h> +#include <arch/ioapic.h> +#include <arch/smp/mpspec.h> +#include <cbmem.h> +#include <cpu/x86/smm.h> +#include <cpu/cpu.h> +#include <soc/acpi.h> +#include <soc/intel/common/acpi.h> +#include <soc/iomap.h> +#include <soc/pm.h> +#include <soc/nvs.h> +#include <soc/pci_devs.h> +#include <string.h> +#include <soc/gpio.h> +#include "chip.h" + +#define CSTATE_RES(address_space, width, offset, address) \ + { \ + .space_id = address_space, \ + .bit_width = width, \ + .bit_offset = offset, \ + .addrl = address, \ + } + +unsigned long acpi_fill_mcfg(unsigned long current) +{ + /* PCI Segment Group 0, Start Bus Number 0, End Bus Number is 255 */ + current += acpi_create_mcfg_mmconfig((void *) current, + CONFIG_MMCONF_BASE_ADDRESS, 0, 0, + 255); + return current; +} + +static int acpi_sci_irq(void) +{ + int sci_irq = 9; + return sci_irq; +} + +static unsigned long acpi_madt_irq_overrides(unsigned long current) +{ + int sci = acpi_sci_irq(); + uint16_t flags = MP_IRQ_TRIGGER_LEVEL | MP_IRQ_POLARITY_LOW;; + + /* INT_SRC_OVR */ + current += acpi_create_madt_irqoverride((void *)current, 0, 0, 2, 0); + + /* SCI */ + current += acpi_create_madt_irqoverride((void *)current, 0, sci, sci, flags); + + return current; +} + +unsigned long acpi_fill_madt(unsigned long current) +{ + /* Local APICs */ + current = acpi_create_madt_lapics(current); + + /* IOAPIC */ + current += acpi_create_madt_ioapic((void *) current, + 2, IO_APIC_ADDR, 0); + + return acpi_madt_irq_overrides(current); +} + +void acpi_fill_fadt(acpi_fadt_t * fadt) +{ + const uint16_t pmbase = ACPI_PMIO_BASE; + + /* Use ACPI 5.0 revision. */ + fadt->header.revision = ACPI_FADT_REV_ACPI_5_0; + + fadt->sci_int = acpi_sci_irq(); + fadt->smi_cmd = APM_CNT; + fadt->acpi_enable = APM_CNT_ACPI_ENABLE; + fadt->acpi_disable = APM_CNT_ACPI_DISABLE; + + fadt->pm1a_evt_blk = pmbase + PM1_STS; + fadt->pm1a_cnt_blk = pmbase + PM1_CNT; + fadt->pm_tmr_blk = pmbase + PM1_TMR; + fadt->gpe0_blk = pmbase + GPE0_STS(0); + + fadt->pm1_evt_len = 4; + fadt->pm1_cnt_len = 2; + fadt->pm_tmr_len = 4; + /* There are 4 GPE0 STS/EN pairs each 32 bits wide. */ + fadt->gpe0_blk_len = 2 * GPE0_REG_MAX * sizeof(uint32_t); + fadt->p_lvl2_lat = ACPI_FADT_C2_NOT_SUPPORTED; + fadt->p_lvl3_lat = ACPI_FADT_C3_NOT_SUPPORTED; + fadt->flush_size = 0x400; /* twice of cache size*/ + fadt->flush_stride = 0x10; /* Cache line width */ + fadt->duty_offset = 1; + fadt->duty_width = 3; + fadt->day_alrm = 0xd; + fadt->iapc_boot_arch = ACPI_FADT_LEGACY_DEVICES | ACPI_FADT_8042; + + fadt->flags = ACPI_FADT_WBINVD | ACPI_FADT_C1_SUPPORTED | + ACPI_FADT_C2_MP_SUPPORTED | ACPI_FADT_SLEEP_BUTTON | + ACPI_FADT_RESET_REGISTER | ACPI_FADT_SEALED_CASE | + ACPI_FADT_S4_RTC_WAKE | ACPI_FADT_PLATFORM_CLOCK; + + fadt->reset_reg.space_id = 1; + fadt->reset_reg.bit_width = 8; + fadt->reset_reg.addrl = 0xcf9; + fadt->reset_value = 6; + + fadt->x_pm1a_evt_blk.space_id = 1; + fadt->x_pm1a_evt_blk.bit_width = fadt->pm1_evt_len * 8; + fadt->x_pm1a_evt_blk.addrl = pmbase + PM1_STS; + + fadt->x_pm1b_evt_blk.space_id = 1; + + fadt->x_pm1a_cnt_blk.space_id = 1; + fadt->x_pm1a_cnt_blk.bit_width = fadt->pm1_cnt_len * 8; + fadt->x_pm1a_cnt_blk.addrl = pmbase + PM1_CNT; + + fadt->x_pm1b_cnt_blk.space_id = 1; + + fadt->x_pm_tmr_blk.space_id = 1; + fadt->x_pm_tmr_blk.bit_width = fadt->pm_tmr_len * 8; + fadt->x_pm_tmr_blk.addrl = pmbase + PM1_TMR; + + fadt->x_gpe1_blk.space_id = 1; +} + +unsigned long southbridge_write_acpi_tables(device_t device, + unsigned long current, + struct acpi_rsdp *rsdp) +{ + return acpi_write_hpet(device, current, rsdp); +} + +static void acpi_create_gnvs(struct global_nvs_t *gnvs) +{ + struct soc_intel_glk_config *cfg; + struct device *dev = NB_DEV_ROOT; + + /* Clear out GNVS. */ + memset(gnvs, 0, sizeof(*gnvs)); + + if (IS_ENABLED(CONFIG_CONSOLE_CBMEM)) + gnvs->cbmc = (uintptr_t)cbmem_find(CBMEM_ID_CONSOLE); + + if (IS_ENABLED(CONFIG_CHROMEOS)) { + /* Initialize Verified Boot data */ + chromeos_init_vboot(&gnvs->chromeos); + gnvs->chromeos.vbt2 = ACTIVE_ECFW_RO; + } + + /* Set unknown wake source */ + gnvs->pm1i = ~0ULL; + + if (!dev || !dev->chip_info) { + printk(BIOS_ERR, "BUG! Could not find SOC devicetree config\n"); + return; + } + cfg = dev->chip_info; + + /* Enable DPTF based on mainboard configuration */ + gnvs->dpte = cfg->dptf_enable; + + /* Assign address of PERST_0 if GPIO is defined in devicetree */ + if (cfg->prt0_gpio != GPIO_PRT0_UDEF) + gnvs->prt0 = (uintptr_t)gpio_dwx_address(cfg->prt0_gpio); +} + +/* Save wake source information for calculating ACPI _SWS values */ +int soc_fill_acpi_wake(uint32_t *pm1, uint32_t **gpe0) +{ + struct chipset_power_state *ps; + static uint32_t gpe0_sts[GPE0_REG_MAX]; + uint32_t pm1_en; + int i; + + ps = cbmem_find(CBMEM_ID_POWER_STATE); + if (ps == NULL) + return -1; + + /* + * PM1_EN to check the basic wake events which can happen through + * powerbtn or any other wake source like lidopen, key board press etc. + * WAK_STS bit is set when the system is in one of the sleep states + * (via the SLP_EN bit) and an enabled wake event occurs. Upon setting + * this bit, the PMC will transition the system to the ON state and + * can only be set by hardware and can only be cleared by writing a one + * to this bit position. + */ + pm1_en = ps->pm1_en | WAK_STS | RTC_EN | PWRBTN_EN; + *pm1 = ps->pm1_sts & pm1_en; + + /* Mask off GPE0 status bits that are not enabled */ + *gpe0 = &gpe0_sts[0]; + for (i = 0; i < GPE0_REG_MAX; i++) + gpe0_sts[i] = ps->gpe0_sts[i] & ps->gpe0_en[i]; + + return GPE0_REG_MAX; +} + +void southbridge_inject_dsdt(device_t device) +{ + struct global_nvs_t *gnvs; + + gnvs = cbmem_find(CBMEM_ID_ACPI_GNVS); + + if (gnvs) { + acpi_create_gnvs(gnvs); + acpi_save_gnvs((uintptr_t)gnvs); + /* And tell SMI about it */ + smm_setup_structures(gnvs, NULL, NULL); + + /* Add it to DSDT. */ + acpigen_write_scope("\"); + acpigen_write_name_dword("NVSA", (uintptr_t)gnvs); + acpigen_pop_len(); + } +} +static acpi_cstate_t cstate_map[] = { + { + /* C1 */ + .ctype = 1, /* ACPI C1 */ + .latency = 1, + .power = 1000, + .resource = CSTATE_RES(ACPI_ADDRESS_SPACE_FIXED, 0, 0, 0), + }, + { + .ctype = 2, /* ACPI C2 */ + .latency = 50, + .power = 10, + .resource = CSTATE_RES(ACPI_ADDRESS_SPACE_IO, 8, 0, 0x415), + }, + { + .ctype = 3, /* ACPI C3 */ + .latency = 150, + .power = 10, + .resource = CSTATE_RES(ACPI_ADDRESS_SPACE_IO, 8, 0, 0x419), + } +}; + +acpi_cstate_t *soc_get_cstate_map(int *entries) +{ + *entries = ARRAY_SIZE(cstate_map); + return cstate_map; +} + +uint16_t soc_get_acpi_base_address(void) +{ + return ACPI_PMIO_BASE; +} diff --git a/src/soc/intel/glk/acpi/cpu.asl b/src/soc/intel/glk/acpi/cpu.asl new file mode 100644 index 0000000..a202ceb --- /dev/null +++ b/src/soc/intel/glk/acpi/cpu.asl @@ -0,0 +1,118 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2014 Google Inc. + * + * 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. + */ + +/* These devices are created at runtime */ +External (_PR.CP00, DeviceObj) +External (_PR.CP01, DeviceObj) +External (_PR.CP02, DeviceObj) +External (_PR.CP03, DeviceObj) +External (_PR.CP04, DeviceObj) +External (_PR.CP05, DeviceObj) +External (_PR.CP06, DeviceObj) +External (_PR.CP07, DeviceObj) + +/* Notify OS to re-read CPU tables, assuming ^2 CPU count */ +Method (PNOT) +{ + If (LGreaterEqual (\PCNT, 2)) { + Notify (_PR.CP00, 0x81) // _CST + Notify (_PR.CP01, 0x81) // _CST + } + If (LGreaterEqual (\PCNT, 4)) { + Notify (_PR.CP02, 0x81) // _CST + Notify (_PR.CP03, 0x81) // _CST + } + If (LGreaterEqual (\PCNT, 8)) { + Notify (_PR.CP04, 0x81) // _CST + Notify (_PR.CP05, 0x81) // _CST + Notify (_PR.CP06, 0x81) // _CST + Notify (_PR.CP07, 0x81) // _CST + } +} + +/* Notify OS to re-read CPU _PPC limit, assuming ^2 CPU count */ +Method (PPCN) +{ + If (LGreaterEqual (\PCNT, 2)) { + Notify (_PR.CP00, 0x80) // _PPC + Notify (_PR.CP01, 0x80) // _PPC + } + If (LGreaterEqual (\PCNT, 4)) { + Notify (_PR.CP02, 0x80) // _PPC + Notify (_PR.CP03, 0x80) // _PPC + } + If (LGreaterEqual (\PCNT, 8)) { + Notify (_PR.CP04, 0x80) // _PPC + Notify (_PR.CP05, 0x80) // _PPC + Notify (_PR.CP06, 0x80) // _PPC + Notify (_PR.CP07, 0x80) // _PPC + } +} + +/* Notify OS to re-read Throttle Limit tables, assuming ^2 CPU count */ +Method (TNOT) +{ + If (LGreaterEqual (\PCNT, 2)) { + Notify (_PR.CP00, 0x82) // _TPC + Notify (_PR.CP01, 0x82) // _TPC + } + If (LGreaterEqual (\PCNT, 4)) { + Notify (_PR.CP02, 0x82) // _TPC + Notify (_PR.CP03, 0x82) // _TPC + } + If (LGreaterEqual (\PCNT, 8)) { + Notify (_PR.CP04, 0x82) // _TPC + Notify (_PR.CP05, 0x82) // _TPC + Notify (_PR.CP06, 0x82) // _TPC + Notify (_PR.CP07, 0x82) // _TPC + } +} + +/* Return a package containing enabled processor entries */ +Method (PPKG) +{ + If (LGreaterEqual (\PCNT, 8)) { + Return (Package() + { + _PR.CP00, + _PR.CP01, + _PR.CP02, + _PR.CP03, + _PR.CP04, + _PR.CP05, + _PR.CP06, + _PR.CP07 + }) + } ElseIf (LGreaterEqual (\PCNT, 4)) { + Return (Package () + { + _PR.CP00, + _PR.CP01, + _PR.CP02, + _PR.CP03 + }) + } ElseIf (LGreaterEqual (\PCNT, 2)) { + Return (Package () + { + _PR.CP00, + _PR.CP01 + }) + } Else { + Return (Package () + { + _PR.CP00 + }) + } +} diff --git a/src/soc/intel/glk/acpi/dptf.asl b/src/soc/intel/glk/acpi/dptf.asl new file mode 100644 index 0000000..743fa92 --- /dev/null +++ b/src/soc/intel/glk/acpi/dptf.asl @@ -0,0 +1,44 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2016 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. + */ + +#define DPTF_CPU_DEVICE TCPU + +#ifndef DPTF_CPU_PASSIVE +#definie DPTF_CPU_PASSIVE 80 +#endif + +#ifndef DPTF_CPU_CRITICAL +#define DPTF_CPU_CRITICAL 90 +#endif + +#ifndef DPTF_CPU_ACTIVE_AC0 +#define DPTF_CPU_ACTIVE_AC0 90 +#endif + +#ifndef DPTF_CPU_ACTIVE_AC1 +#define DPTF_CPU_ACTIVE_AC1 80 +#endif + +#ifndef DPTF_CPU_ACTIVE_AC2 +#define DPTF_CPU_ACTIVE_AC2 70 +#endif + +#ifndef DPTF_CPU_ACTIVE_AC3 +#define DPTF_CPU_ACTIVE_AC3 60 +#endif + +#ifndef DPTF_CPU_ACTIVE_AC4 +#define DPTF_CPU_ACTIVE_AC4 50 +#endif diff --git a/src/soc/intel/glk/acpi/globalnvs.asl b/src/soc/intel/glk/acpi/globalnvs.asl new file mode 100644 index 0000000..5eeacfe --- /dev/null +++ b/src/soc/intel/glk/acpi/globalnvs.asl @@ -0,0 +1,46 @@ +/* + * 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. + */ + +/* + * NOTE: The layout of the GNVS structure below must match the layout in + * soc/intel/glk/include/soc/nvs.h !!! + * + */ + +External (NVSA) + +OperationRegion (GNVS, SystemMemory, NVSA, 0x1000) +Field (GNVS, ByteAcc, NoLock, Preserve) +{ + /* Miscellaneous */ + Offset (0x00), + PCNT, 8, // 0x00 - Processor Count + PPCM, 8, // 0x01 - Max PPC State + LIDS, 8, // 0x02 - LID State + PWRS, 8, // 0x03 - AC Power State + DPTE, 8, // 0x04 - Enable DPTF + CBMC, 32, // 0x05 - 0x08 - Coreboot Memory Console + PM1I, 64, // 0x09 - 0x10 - System Wake Source - PM1 Index + GPEI, 64, // 0x11 - 0x18 - GPE Wake Source + NHLA, 64, // 0x19 - 0x20 - NHLT Address + NHLL, 32, // 0x21 - 0x24 - NHLT Length + PRT0, 32, // 0x25 - 0x28 - PERST_0 Address + + /* ChromeOS stuff (0x100 -> 0xfff, size 0xeff) */ + Offset (0x100), + #include <vendorcode/google/chromeos/acpi/gnvs.asl> +} diff --git a/src/soc/intel/glk/acpi/gpio.asl b/src/soc/intel/glk/acpi/gpio.asl new file mode 100644 index 0000000..ffc5b75 --- /dev/null +++ b/src/soc/intel/glk/acpi/gpio.asl @@ -0,0 +1,201 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2016 Intel Corp. + * (Written by Lance Zhao lijian.zhao@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. + */ +#include <soc/gpio_defs.h> +#include "gpiolib.asl" + +scope (_SB) { + + Device (GPO0) + { + Name (_ADR, 0) + Name (_HID, "INT3452") + Name (_CID, "INT3452") + Name (_DDN, "General Purpose Input/Output (GPIO) Controller - North" ) + Name (_UID, 1) + + Name (RBUF, ResourceTemplate () + { + Memory32Fixed (ReadWrite, 0, 0x4000, RMEM) + Interrupt (ResourceConsumer, Level, ActiveLow, Shared, , , ) + { + GPIO_BANK_INT + } + }) + + Method (_CRS, 0x0, NotSerialized) + { + CreateDwordField (^RBUF, ^RMEM._BAS, RBAS) + ShiftLeft (GPIO_N, 16, Local0) + Or (CONFIG_IOSF_BASE_ADDRESS, Local0, RBAS) + Return (^RBUF) + } + + Method (_STA, 0x0, NotSerialized) + { + Return(0xf) + } + } + + Device (GPO1) + { + Name (_ADR, 0) + Name (_HID, "INT3452") + Name (_CID, "INT3452") + Name (_DDN, "General Purpose Input/Output (GPIO) Controller - Northwest" ) + Name (_UID, 2) + + Name (RBUF, ResourceTemplate () + { + Memory32Fixed (ReadWrite, 0, 0x4000, RMEM) + Interrupt (ResourceConsumer, Level, ActiveLow, Shared, , , ) + { + GPIO_BANK_INT + } + }) + + Method (_CRS, 0x0, NotSerialized) + { + CreateDwordField (^RBUF, ^RMEM._BAS, RBAS) + ShiftLeft (GPIO_NW, 16, Local0) + Or (CONFIG_IOSF_BASE_ADDRESS, Local0, RBAS) + Return (^RBUF) + } + + Method (_STA, 0x0, NotSerialized) + { + Return(0xf) + } + } + + Device (GPO2) + { + Name (_ADR, 0) + Name (_HID, "INT3452") + Name (_CID, "INT3452") + Name (_DDN, "General Purpose Input/Output (GPIO) Controller - West" ) + Name (_UID, 3) + + Name (RBUF, ResourceTemplate () + { + Memory32Fixed (ReadWrite, 0, 0x4000, RMEM) + Interrupt (ResourceConsumer, Level, ActiveLow, Shared, , , ) + { + GPIO_BANK_INT + } + }) + + Method (_CRS, 0x0, NotSerialized) + { + CreateDwordField (^RBUF, ^RMEM._BAS, RBAS) + ShiftLeft (GPIO_W, 16, Local0) + Or (CONFIG_IOSF_BASE_ADDRESS, Local0, RBAS) + Return (^RBUF) + } + + Method (_STA, 0x0, NotSerialized) + { + Return(0xf) + } + } + + Device (GPO3) + { + Name (_ADR, 0) + Name (_HID, "INT3452") + Name (_CID, "INT3452") + Name (_DDN, "General Purpose Input/Output (GPIO) Controller - Southwest" ) + Name (_UID, 4) + + Name (RBUF, ResourceTemplate () + { + Memory32Fixed (ReadWrite, 0, 0x4000, RMEM) + Interrupt (ResourceConsumer, Level, ActiveLow, Shared, , , ) + { + GPIO_BANK_INT + } + }) + + Method (_CRS, 0x0, NotSerialized) + { + CreateDwordField (^RBUF, ^RMEM._BAS, RBAS) + ShiftLeft (GPIO_SW, 16, Local0) + Or (CONFIG_IOSF_BASE_ADDRESS, Local0, RBAS) + Return (^RBUF) + } + + Method (_STA, 0x0, NotSerialized) + { + Return(0xf) + } + } + + Scope(_SB.PCI0) { + /* PERST Assertion + * Note: PERST is Active High + */ + Method (PRAS, 0x1, Serialized) + { + /* + * Assert PERST + * local1 - to toggle Tx pin of Dw0 + * local2 - Address of PERST + */ + Store (Arg0, Local2) + Store (_SB.GPC0 (Local2), Local1) + Or (Local1, PAD_CFG0_TX_STATE, Local1) + _SB.SPC0 (Local2, Local1) + } + + /* PERST DE-Assertion */ + Method (PRDA, 0x1, Serialized) + { + /* + * De-assert PERST + * local1 - to toggle Tx pin of Dw0 + * local2 - Address of PERST + */ + Store (Arg0, Local2) + Store (_SB.GPC0 (Local2), Local1) + And (Local1, Not (PAD_CFG0_TX_STATE), Local1) + _SB.SPC0 (Local2, Local1) + } + } + + /* + * Sleep button device ASL code. We are using this device to + * add the _PRW method for a dummy wake event to kernel so that + * before going to sleep kernel does not clear bit 15 in ACPI + * gpe0a enable register which is actually the GPIO_TIER1_SCI_EN bit. + */ + Device (SLP) + { + Name (_HID, EisaId ("PNP0C0E")) + + Name (_PRW, Package() { GPE0A_GPIO_TIER1_SCI_STS, 0x3 }) + } +} + +Scope(_GPE) +{ + /* + * Dummy method for the Tier 1 GPIO SCI enable bit. When kernel reads + * _L0F in scope GPE it sets bit for gpio_tier1_sci_en in ACPI enable + * register at 0x430. For APL ACPI enable register DW0 i.e., ACPI + * GPE0a_EN at 0x430 is reserved. + */ + Method(_L0F, 0) {} +} diff --git a/src/soc/intel/glk/acpi/gpiolib.asl b/src/soc/intel/glk/acpi/gpiolib.asl new file mode 100644 index 0000000..cec6d36 --- /dev/null +++ b/src/soc/intel/glk/acpi/gpiolib.asl @@ -0,0 +1,67 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2016 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. + */ + +Scope (_SB) +{ + /* Get Pad Configuration DW0 register value */ + Method (GPC0, 0x1, Serialized) + { + /* Arg0 - GPIO DW0 address */ + Store (Arg0, Local0) + OperationRegion (PDW0, SystemMemory, Local0, 4) + Field (PDW0, AnyAcc, NoLock, Preserve) { + TEMP, 32 + } + Return (TEMP) + } + + /* Set Pad Configuration DW0 register value */ + Method (SPC0, 0x2, Serialized) + { + /* Arg0 - GPIO DW0 address */ + /* Arg1 - Value for DW0 register */ + Store (Arg0, Local0) + OperationRegion (PDW0, SystemMemory, Local0, 4) + Field (PDW0, AnyAcc, NoLock, Preserve) { + TEMP,32 + } + Store (Arg1, TEMP) + } + + /* Get Pad Configuration DW1 register value */ + Method (GPC1, 0x1, Serialized) + { + /* Arg0 - GPIO DW0 address */ + Store (Add (Arg0, 0x4), Local0) + OperationRegion (PDW1, SystemMemory, Local0, 4) + Field (PDW1, AnyAcc, NoLock, Preserve) { + TEMP, 32 + } + Return (TEMP) + } + + /* Set Pad Configuration DW1 register value */ + Method (SPC1, 0x2, Serialized) + { + /* Arg0 - GPIO DW0 address */ + /* Arg1 - Value for DW1 register */ + Store (Add (Arg0, 0x4), Local0) + OperationRegion (PDW1, SystemMemory, Local0, 4) + Field(PDW1, AnyAcc, NoLock, Preserve) { + TEMP,32 + } + Store (Arg1, TEMP) + } +} diff --git a/src/soc/intel/glk/acpi/lpc.asl b/src/soc/intel/glk/acpi/lpc.asl new file mode 100644 index 0000000..749daf7 --- /dev/null +++ b/src/soc/intel/glk/acpi/lpc.asl @@ -0,0 +1,23 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * Copyright (C) 2013 Google Inc. + * + * 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. + */ + +/* Intel LPC Bus Device - 0:1f.0 */ + +Device (LPCB) +{ + Name (_ADR, 0x001f0000) +} diff --git a/src/soc/intel/glk/acpi/lpss.asl b/src/soc/intel/glk/acpi/lpss.asl new file mode 100644 index 0000000..ab97374 --- /dev/null +++ b/src/soc/intel/glk/acpi/lpss.asl @@ -0,0 +1,116 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2016 Intel Corp. + * (Written by Lance Zhao lijian.zhao@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. + */ + +scope (_SB.PCI0) { + + /* LPIO1 PWM */ + Device(PWM) { + Name (_ADR, 0x001A0000) + Name (_DDN, "Intel(R) PWM Controller") + } + + /* LPIO1 HS-UART #1 */ + Device(URT1) { + Name (_ADR, 0x00180000) + Name (_DDN, "Intel(R) HS-UART Controller #1") + } + + /* LPIO1 HS-UART #2 */ + Device(URT2) { + Name (_ADR, 0x00180001) + Name (_DDN, "Intel(R) HS-UART Controller #2") + } + + /* LPIO1 HS-UART #3 */ + Device(URT3) { + Name (_ADR, 0x00180002) + Name (_DDN, "Intel(R) HS-UART Controller #3") + } + + /* LPIO1 HS-UART #4 */ + Device(URT4) { + Name (_ADR, 0x00180003) + Name (_DDN, "Intel(R) HS-UART Controller #4") + } + + /* LPIO1 SPI */ + Device(SPI1) { + Name (_ADR, 0x00190000) + Name (_DDN, "Intel(R) SPI Controller #1") + } + + /* LPIO1 SPI #2 */ + Device(SPI2) { + Name (_ADR, 0x00190001) + Name (_DDN, "Intel(R) SPI Controller #2") + } + + /* LPIO1 SPI #3 */ + Device(SPI3) { + Name (_ADR, 0x00190002) + Name (_DDN, "Intel(R) SPI Controller #3") + } + + + /* LPIO2 I2C #0 */ + Device(I2C0) { + Name (_ADR, 0x00160000) + Name (_DDN, "Intel(R) I2C Controller #0") + } + + /* LPIO2 I2C #1 */ + Device(I2C1) { + Name (_ADR, 0x00160001) + Name (_DDN, "Intel(R) I2C Controller #1") + } + + /* LPIO2 I2C #2 */ + Device(I2C2) { + Name (_ADR, 0x00160002) + Name (_DDN, "Intel(R) I2C Controller #2") + } + + /* LPIO2 I2C #3 */ + Device(I2C3) { + Name (_ADR, 0x00160003) + Name (_DDN, "Intel(R) I2C Controller #3") + } + + /* LPIO2 I2C #4 */ + Device(I2C4) { + Name (_ADR, 0x00170000) + Name (_DDN, "Intel(R) I2C Controller #4") + } + + /* LPIO2 I2C #5 */ + Device(I2C5) { + Name (_ADR, 0x00170001) + Name (_DDN, "Intel(R) I2C Controller #5") + } + + /* LPIO2 I2C #6 */ + Device(I2C6) { + Name (_ADR, 0x00170002) + Name (_DDN, "Intel(R) I2C Controller #6") + } + + /* LPIO2 I2C #7 */ + Device(I2C7) { + Name (_ADR, 0x00170003) + Name (_DDN, "Intel(R) I2C Controller #7") + } +} diff --git a/src/soc/intel/glk/acpi/northbridge.asl b/src/soc/intel/glk/acpi/northbridge.asl new file mode 100644 index 0000000..919026a --- /dev/null +++ b/src/soc/intel/glk/acpi/northbridge.asl @@ -0,0 +1,132 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2016 Intel Corp. + * (Written by Lance Zhao lijian.zhao@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. + */ + + Name(_HID, EISAID("PNP0A08")) /* PCIe */ + Name(_CID, EISAID("PNP0A03")) /* PCI */ + Name(_ADR, 0) + Name(_BBN, 0) + +Device (MCHC) +{ + Name (_ADR, 0x00000000) /*Dev0 Func0 */ + + OperationRegion (MCHP, PCI_Config, 0x00, 0x100) + Field (MCHP, DWordAcc, NoLock, Preserve) + { + Offset(0x60), + MCNF, 32, /* PCI MMCONF base */ + Offset (0xA8), + TUUD, 64, /* Top of Upper Used Memory */ + Offset(0xB4), + BGSM, 32, /* Base of Graphics Stolen Memory */ + Offset(0xBC), + TLUD, 32, /* Top of Low Useable DRAM */ + } +} +Name (MCRS, ResourceTemplate() +{ + /* Bus Numbers */ + WordBusNumber (ResourceProducer, MinFixed, MaxFixed, PosDecode, + 0x0000, 0x0000, 0x00ff, 0x0000, 0x0100,,,) + + /* IO Region 0 */ + DWordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, + 0x0000, 0x0000, 0x0cf7, 0x0000, 0x0cf8,,,) + + /* PCI Config Space */ + Io (Decode16, 0x0cf8, 0x0cf8, 0x0001, 0x0008) + + /* IO Region 1 */ + DWordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, + 0x0000, 0x01000, 0xffff, 0x0000, 0xf000,,,) + + /* VGA memory (0xa0000-0xbffff) */ + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0x000a0000, 0x000bffff, 0x00000000, + 0x00020000,,,) + + /* Data and GFX stolen memory */ + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0x3be00000, 0x3fffffff, 0x00000000, + 0x04200000,,, STOM) + + /* + * PCI MMIO Region (TOLUD - PCI extended base MMCONF) + * This assumes that MMCONF is placed after PCI config space, + * and that no resources are allocated after the MMCONF region. + * This works, sicne MMCONF is hardcoded to 0xe00000000. + */ + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + NonCacheable, ReadWrite, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000,,, PM01) + + /* PCI Memory Region (TOUUD - (TOUUD + ABOVE_4G_MMIO_SIZE)) */ + QWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + NonCacheable, ReadWrite, + 0x00000000, 0x10000, 0x1ffff, 0x00000000, + 0x10000,,, PM02) +}) + +/* Current Resource Settings */ +Method (_CRS, 0, Serialized) +{ + + /* Find PCI resource area in MCRS */ + CreateDwordField (MCRS, ^PM01._MIN, PMIN) + CreateDwordField (MCRS, ^PM01._MAX, PMAX) + CreateDwordField (MCRS, ^PM01._LEN, PLEN) + + /* Read C-Unit PCI CFG Reg. 0xBC for TOLUD (shadow from B-Unit) */ + And(^MCHC.TLUD, 0xFFF00000, PMIN) + /* Read MMCONF base */ + And(^MCHC.MCNF, 0xF0000000, PMAX) + + /* Calculate PCI MMIO Length */ + Add(Subtract(PMAX, PMIN), 1, PLEN) + + /* Find GFX resource area in GCRS */ + CreateDwordField(MCRS, ^STOM._MIN, GMIN) + CreateDwordField(MCRS, ^STOM._MAX, GMAX) + CreateDwordField(MCRS, ^STOM._LEN, GLEN) + + /* Read BGSM */ + And(^MCHC.BGSM, 0xFFF00000, GMIN) + + /* Read TOLUD */ + And(^MCHC.TLUD, 0xFFF00000, GMAX) + Decrement(GMAX) + Add(Subtract(GMAX, GMIN), 1, GLEN) + + /* Patch PM02 range based on Memory Size */ + CreateQwordField (MCRS, ^PM02._MIN, MMIN) + CreateQwordField (MCRS, ^PM02._MAX, MMAX) + CreateQwordField (MCRS, ^PM02._LEN, MLEN) + + Store (^MCHC.TUUD, Local0) + + If (LLessEqual (Local0, 0x1000000000)) + { + Store (0, MMIN) + Store (0, MLEN) + } + Subtract (Add (MMIN, MLEN), 1, MMAX) + + Return (MCRS) +} diff --git a/src/soc/intel/glk/acpi/pch_hda.asl b/src/soc/intel/glk/acpi/pch_hda.asl new file mode 100644 index 0000000..33cd771 --- /dev/null +++ b/src/soc/intel/glk/acpi/pch_hda.asl @@ -0,0 +1,84 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2016 Intel Corporation. + * Copyright (C) 2016 Google Inc. + * + * 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. + * + */ + +/* Audio Controller - Device 14, Function 0 */ + +Device (HDAS) +{ + Name (_ADR, 0x000E0000) + Name (_DDN, "Audio Controller") + Name (UUID, ToUUID("A69F886E-6CEB-4594-A41F-7B5DCE24C553")) + + /* Device is D3 wake capable */ + Name (_S0W, 3) + + /* NHLT Table Address populated from GNVS values */ + Name (NBUF, ResourceTemplate() { + QWordMemory (ResourceConsumer, PosDecode, MinFixed, + MaxFixed, Cacheable, ReadOnly, + 0, 0, 0, 0, 1,,, NHLT, AddressRangeACPI) + } + ) + + /* + * Device Specific Method + * Arg0 - UUID + * Arg1 - Revision + * Arg2 - Function Index + */ + Method (_DSM, 4) { + If (LEqual (Arg0, ^UUID)) { + /* + * Function 0: Function Support Query + * Returns a bitmask of functions supported. + */ + If (LEqual (Arg2, Zero)) { + /* + * NHLT Query only supported for revision 1 and + * if NHLT address and length are set in NVS. + */ + If (LAnd (LEqual (Arg1, One), + LAnd (LNotEqual (NHLA, Zero), + LNotEqual (NHLL, Zero)))) { + Return (Buffer (One) { 0x03 }) + } + Else { + Return (Buffer (One) { 0x01 }) + } + } + + /* + * Function 1: Query NHLT memory address used by + * Intel Offload Engine Driver to discover any non-HDA + * devices that are supported by the DSP. + * + * Returns a pointer to NHLT table in memory. + */ + If (LEqual (Arg2, One)) { + CreateQWordField (NBUF, ^NHLT._MIN, NBAS) + CreateQWordField (NBUF, ^NHLT._MAX, NMAS) + CreateQWordField (NBUF, ^NHLT._LEN, NLEN) + Store (NHLA, NBAS) + Store (NHLA, NMAS) + Store (NHLL, NLEN) + Return (NBUF) + } + } + + Return (Buffer (One) { 0x00 }) + } +} diff --git a/src/soc/intel/glk/acpi/pci_irqs.asl b/src/soc/intel/glk/acpi/pci_irqs.asl new file mode 100644 index 0000000..22878c6 --- /dev/null +++ b/src/soc/intel/glk/acpi/pci_irqs.asl @@ -0,0 +1,63 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2016 Intel Corp. + * (Written by Lance Zhao lijian.zhao@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. + */ + +#include "soc_int.asl" + +Method(_PRT) +{ + Return(Package() { + + Package(){0x0000FFFF, 0, 0, NPK_INT}, + Package(){0x0000FFFF, 1, 0, PUNIT_INT}, + Package(){0x0002FFFF, 0, 0, GEN_INT}, + Package(){0x0003FFFF, 0, 0, IUNIT_INT}, + Package(){0x000DFFFF, 1, 0, PMC_INT}, + Package(){0x000EFFFF, 0, 0, AUDIO_INT}, + Package(){0x000FFFFF, 0, 0, CSE_INT}, + Package(){0x0011FFFF, 0, 0, ISH_INT}, + Package(){0x0012FFFF, 0, 0, SATA_INT}, + Package(){0x0013FFFF, 0, 0, PIRQA_INT}, + Package(){0x0013FFFF, 1, 0, PIRQB_INT}, + Package(){0x0013FFFF, 2, 0, PIRQC_INT}, + Package(){0x0013FFFF, 3, 0, PIRQD_INT}, + Package(){0x0014FFFF, 0, 0, PIRQB_INT}, + Package(){0x0014FFFF, 1, 0, PIRQC_INT}, + Package(){0x0014FFFF, 2, 0, PIRQD_INT}, + Package(){0x0014FFFF, 3, 0, PIRQA_INT}, + Package(){0x0015FFFF, 0, 0, XHCI_INT}, + Package(){0x0015FFFF, 1, 0, XDCI_INT}, + Package(){0x0016FFFF, 0, 0, I2C0_INT}, + Package(){0x0016FFFF, 1, 0, I2C1_INT}, + Package(){0x0016FFFF, 2, 0, I2C2_INT}, + Package(){0x0016FFFF, 3, 0, I2C3_INT}, + Package(){0x0017FFFF, 0, 0, I2C4_INT}, + Package(){0x0017FFFF, 1, 0, I2C5_INT}, + Package(){0x0017FFFF, 2, 0, I2C6_INT}, + Package(){0x0017FFFF, 3, 0, I2C7_INT}, + Package(){0x0018FFFF, 0, 0, UART0_INT}, + Package(){0x0018FFFF, 1, 0, UART1_INT}, + Package(){0x0018FFFF, 2, 0, UART2_INT}, + Package(){0x0018FFFF, 3, 0, UART3_INT}, + Package(){0x0019FFFF, 0, 0, SPI0_INT}, + Package(){0x0019FFFF, 1, 0, SPI1_INT}, + Package(){0x0019FFFF, 2, 0, SPI2_INT}, + Package(){0x001BFFFF, 0, 0, SDCARD_INT}, + Package(){0x001CFFFF, 0, 0, EMMC_INT}, + Package(){0x001EFFFF, 0, 0, SDIO_INT}, + Package(){0x001FFFFF, 1, 0, SMBUS_INT}, + }) +} diff --git a/src/soc/intel/glk/acpi/pcie.asl b/src/soc/intel/glk/acpi/pcie.asl new file mode 100644 index 0000000..050f2f0 --- /dev/null +++ b/src/soc/intel/glk/acpi/pcie.asl @@ -0,0 +1,126 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2016 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. + */ + +Device (RP01) +{ + Name (_ADR, 0x00140000) + Name (_DDN, "PCIe-B 0") + Name (PDST, 0) /* present Detect status */ + + /* lowest D-state supported by + * PCIe root port during S0 state + */ + Name (_S0W, 4) + + /* Dynamic Opregion needed to access registers + * when the controller is in D3 cold + */ + OperationRegion (PX01, PCI_Config, 0x00, 0xFF) + Field (PX01, AnyAcc, NoLock, Preserve) + { + Offset(0x5A), + , 6, + PDS, 1, /* 6, Presence detect Change */ + Offset(0xE2), /* RPPGEN - Root Port Power Gating Enable */ + , 2, + L23E, 1, /* 2, L23_Rdy Entry Request (L23ER) */ + L23R, 1, /* 3, L23_Rdy to Detect Transition (L23R2DT) */ + Offset(0xF4), /* BLKPLLEN */ + , 10, + BPLL, 1, + } + + OperationRegion (PX02, PCI_Config, 0x338, 0x4) + Field (PX02, AnyAcc, NoLock, Preserve) + { + , 26, + BDQA, 1 /* BLKDQDA */ + } + + PowerResource (PXP, 0, 0) + { + /* Define the PowerResource for PCIe slot */ + Method (_STA, 0, Serialized) + { + Store (PDS, PDST) + If (LEqual (PDS, 1)) { + Return (0xf) + } Else { + Return (0) + } + } + + Method (_ON, 0, Serialized) + { + If (LAnd (LEqual (PDST, 1), LNotEqual (\PRT0, 0))) { + /* Enter this condition if device + * is connected + */ + + /* De-assert PERST */ + _SB.PCI0.PRDA (\PRT0) + + Store (0, BDQA) /* Set BLKDQDA to 0 */ + Store (0, BPLL) /* Set BLKPLLEN to 0 */ + + /* Set L23_Rdy to Detect Transition + * (L23R2DT) + */ + Store (1, L23R) + Sleep (16) + Store (0, Local0) + + /* Delay for transition Detect + * and link to train + */ + While (L23R) { + If (Lgreater (Local0, 4)) { + Break + } + Sleep (16) + Increment (Local0) + } + } /* End PDS condition check */ + } + + Method (_OFF, 0, Serialized) + { + /* Set L23_Rdy Entry Request (L23ER) */ + If (LAnd (LEqual (PDST, 1), LNotEqual (\PRT0, 0))) { + /* enter this condition if device + * is connected + */ + Store (1, L23E) + Sleep (16) + Store (0, Local0) + While (L23E) { + If (Lgreater (Local0, 4)) { + Break + } + Sleep (16) + Increment (Local0) + } + Store (1, BDQA) /* Set BLKDQDA to 1 */ + Store (1, BPLL) /* Set BLKPLLEN to 1 */ + + /* Assert PERST */ + _SB.PCI0.PRAS (\PRT0) + } /* End PDS condition check */ + } /* End of Method_OFF */ + } /* End PXP */ + + Name(_PR0, Package() { PXP }) + Name(_PR3, Package() { PXP }) +} diff --git a/src/soc/intel/glk/acpi/platform.asl b/src/soc/intel/glk/acpi/platform.asl new file mode 100644 index 0000000..f3202a0 --- /dev/null +++ b/src/soc/intel/glk/acpi/platform.asl @@ -0,0 +1,20 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * Copyright (C) 2012 Google Inc. + * Copyright (C) 2016 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; 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. + */ + +/* Enable ACPI _SWS methods */ +#include <soc/intel/common/acpi/acpi_wake_source.asl> +#include <soc/intel/common/acpi/platform.asl> diff --git a/src/soc/intel/glk/acpi/scs.asl b/src/soc/intel/glk/acpi/scs.asl new file mode 100644 index 0000000..4108017 --- /dev/null +++ b/src/soc/intel/glk/acpi/scs.asl @@ -0,0 +1,67 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2016 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. + */ + +Scope (_SB.PCI0) { + /* 0xD6- is the port address */ + /* 0x600- is the dynamic clock gating control register offset (GENR) */ + OperationRegion (SBMM, SystemMemory, + Or ( Or (CONFIG_IOSF_BASE_ADDRESS, + ShiftLeft(0xD6, 16)), 0x0600), 0x18) + Field (SBMM, DWordAcc, NoLock, Preserve) + { + GENR, 32, + } + + /* SCC power gate control method, this method must be serialized as + * multiple device will control the GENR register + * + * Arguments: (2) + * Arg0: 0-AND 1-OR + * Arg1: Value + */ + Method (SCPG, 2, Serialized) + { + if (LEqual(Arg0, 0x1)) { + Or (^GENR, Arg1, ^GENR) + } ElseIf (LEqual(Arg0, 0x0)){ + And (^GENR, Arg1, ^GENR) + } + } + + /* eMMC */ + Device (SDHA) { + Name (_ADR, 0x001C0000) + Name (_DDN, "Intel(R) eMMC Controller - 80865ACC") + + Method (_PS0, 0, NotSerialized) + { + /* Clear clock gate + * Clear bit 6 and 0 + */ + ^^SCPG(0,0xFFFFFFBE) + /* Sleep 2 ms */ + Sleep (2) + } + + Method (_PS3, 0, NotSerialized) + { + /* Enable power gate + * Restore clock gate + * Restore bit 6 and 0 + */ + ^^SCPG(1,0x00000041) + } + } /* Device (SDHA) */ +} diff --git a/src/soc/intel/glk/acpi/sleepstates.asl b/src/soc/intel/glk/acpi/sleepstates.asl new file mode 100644 index 0000000..e79f2f0 --- /dev/null +++ b/src/soc/intel/glk/acpi/sleepstates.asl @@ -0,0 +1,21 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * Copyright (C) 2014 Google Inc. + * Copyright (C) 2015-2016 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; 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. + */ + +Name (_S0, Package () { 0x0, 0x0, 0x0, 0x0 }) +Name (_S3, Package () { 0x5, 0x5, 0x0, 0x0 }) +Name (_S5, Package () { 0x7, 0x7, 0x0, 0x0 }) diff --git a/src/soc/intel/glk/acpi/soc_int.asl b/src/soc/intel/glk/acpi/soc_int.asl new file mode 100644 index 0000000..c643244 --- /dev/null +++ b/src/soc/intel/glk/acpi/soc_int.asl @@ -0,0 +1,58 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2016 Intel Corp. + * (Written by Lance Zhao lijian.zhao@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_INT_DEFINE_ASL_ +#define _SOC_INT_DEFINE_ASL_ + +#define SDCARD_INT 3 /* Need to be shared by PMC and SCC only*/ +#define UART0_INT 4 /* Need to be shared by PMC and SCC only*/ +#define UART1_INT 5 /* Need to be shared by PMC and SCC only*/ +#define UART2_INT 6 /* Need to be shared by PMC and SCC only*/ +#define UART3_INT 7 /* Need to be shared by PMC and SCC only*/ +#define XDCI_INT 13 /* Need to be shared by PMC and SCC only*/ +#define GPIO_BANK_INT 14 +#define NPK_INT 16 +#define PIRQA_INT 16 +#define PIRQB_INT 17 +#define PIRQC_INT 18 +#define SATA_INT 19 +#define GEN_INT 19 +#define PIRQD_INT 19 +#define XHCI_INT 17 /* Need to be shared by PMC and SCC only*/ +#define SMBUS_INT 20 /* PIRQE */ +#define CSE_INT 20 /* PIRQE */ +#define IUNIT_INT 21 /* PIRQF */ +#define PUNIT_INT 24 +#define AUDIO_INT 25 +#define ISH_INT 26 +#define I2C0_INT 27 +#define I2C1_INT 28 +#define I2C2_INT 29 +#define I2C3_INT 30 +#define I2C4_INT 31 +#define I2C5_INT 32 +#define I2C6_INT 33 +#define I2C7_INT 34 +#define SPI0_INT 35 +#define SPI1_INT 36 +#define SPI2_INT 37 +#define UFS_INT 38 +#define EMMC_INT 39 +#define PMC_INT 40 +#define SDIO_INT 42 + +#endif /* _SOC_INT_DEFINE_ASL_ */ diff --git a/src/soc/intel/glk/acpi/southbridge.asl b/src/soc/intel/glk/acpi/southbridge.asl new file mode 100644 index 0000000..d7ced0f --- /dev/null +++ b/src/soc/intel/glk/acpi/southbridge.asl @@ -0,0 +1,41 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2016 Intel Corp. + * (Written by Lance Zhao lijian.zhao@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. + */ + +#include <soc/gpe.h> + +/* PCIE device */ +#include "pcie.asl" + +/* LPSS device */ +#include "lpss.asl" + +/* PCI IRQ assignment */ +#include "pci_irqs.asl" + +/* GPIO controller */ +#include "gpio.asl" + +#include "xhci.asl" + +/* LPC */ +#include "lpc.asl" + +/* eMMC */ +#include "scs.asl" + +/* PCI _OSC */ +#include <soc/intel/common/acpi/pci_osc.asl> diff --git a/src/soc/intel/glk/acpi/xhci.asl b/src/soc/intel/glk/acpi/xhci.asl new file mode 100644 index 0000000..c07c707 --- /dev/null +++ b/src/soc/intel/glk/acpi/xhci.asl @@ -0,0 +1,31 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2016 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. + */ + +/* XHCI Controller 0:15.0 */ +Device (XHC1) { + Name (_ADR, 0x00150000) /* Device 21, Function 0 */ + + Name (_S3D, 3) /* D3 supported in S3 */ + Name (_S0W, 3) /* D3 can wake device in S0 */ + Name (_S3W, 3) /* D3 can wake system from S3 */ + + /* Declare XHCI GPE status and enable bits are bit 13 */ + Name (_PRW, Package() { GPE0A_XHCI_PME_STS, 3 }) + + Method (_STA, 0) + { + Return (0xF) + } +} diff --git a/src/soc/intel/glk/bootblock/bootblock.c b/src/soc/intel/glk/bootblock/bootblock.c new file mode 100644 index 0000000..d88ba1d --- /dev/null +++ b/src/soc/intel/glk/bootblock/bootblock.c @@ -0,0 +1,187 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2016 Intel Corp. + * (Written by Andrey Petrov andrey.petrov@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. + */ +#include <arch/cpu.h> +#include <bootblock_common.h> +#include <cpu/x86/mtrr.h> +#include <device/pci.h> +#include <lib.h> +#include <soc/iomap.h> +#include <soc/cpu.h> +#include <soc/gpio.h> +#include <soc/iosf.h> +#include <soc/mmap_boot.h> +#include <soc/northbridge.h> +#include <soc/pci_devs.h> +#include <soc/pm.h> +#include <soc/uart.h> +#include <spi-generic.h> +#include <timestamp.h> + +static const struct pad_config tpm_spi_configs[] = { +}; + +static void tpm_enable(void) +{ + /* Configure gpios */ + gpio_configure_pads(tpm_spi_configs, ARRAY_SIZE(tpm_spi_configs)); +} + +static void enable_pm_timer(void) +{ + /* ACPI PM timer emulation */ + msr_t msr; + /* + * The derived frequency is calculated as follows: + * (CTC_FREQ * msr[63:32]) >> 32 = target frequency. + * Back solve the multiplier so the 3.579545MHz ACPI timer + * frequency is used. + */ + msr.hi = (3579545ULL << 32) / CTC_FREQ; + /* Set PM1 timer IO port and enable*/ + msr.lo = EMULATE_PM_TMR_EN | (ACPI_PMIO_BASE + R_ACPI_PM1_TMR); + wrmsr(MSR_EMULATE_PM_TMR, msr); +} + +static void enable_cmos_upper_bank(void) +{ + uint32_t reg = iosf_read(IOSF_RTC_PORT_ID, RTC_CONFIG); + reg |= RTC_CONFIG_UCMOS_ENABLE; + iosf_write(IOSF_RTC_PORT_ID, RTC_CONFIG, reg); +} + +void asmlinkage bootblock_c_entry(uint64_t base_timestamp) +{ + device_t dev = NB_DEV_ROOT; + + /* Set PCI Express BAR */ + pci_io_write_config32(dev, PCIEXBAR, CONFIG_MMCONF_BASE_ADDRESS | 1); + /* + * Clear TSEG register - TSEG register comes out of reset with a + * non-zero default value. Clear this register to ensure that there are + * no surprises in CBMEM handling. + */ + pci_write_config32(dev, TSEG, 0); + + dev = P2SB_DEV; + /* BAR and MMIO enable for IOSF, so that GPIOs can be configured */ + pci_write_config32(dev, PCI_BASE_ADDRESS_0, CONFIG_IOSF_BASE_ADDRESS); + pci_write_config32(dev, PCI_BASE_ADDRESS_1, 0); + pci_write_config16(dev, PCI_COMMAND, + PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY); + + /* Decode the ACPI I/O port range for early firmware verification.*/ + dev = PMC_DEV; + pci_write_config16(dev, PCI_BASE_ADDRESS_4, ACPI_PMIO_BASE); + pci_write_config16(dev, PCI_COMMAND, + PCI_COMMAND_IO | PCI_COMMAND_MASTER); + + enable_cmos_upper_bank(); + + /* Call lib/bootblock.c main */ + bootblock_main_with_timestamp(base_timestamp); +} + +static void cache_bios_region(void) +{ + int mtrr; + size_t rom_size; + uint32_t alignment; + + mtrr = get_free_var_mtrr(); + + if (mtrr==-1) + return; + + /* Only the IFD BIOS region is memory mapped (at top of 4G) */ + rom_size = get_bios_size(); + + if (!rom_size) + return; + + /* Round to power of two */ + alignment = 1 << (log2_ceil(rom_size)); + rom_size = ALIGN_UP(rom_size, alignment); + set_var_mtrr(mtrr, 4ULL*GiB - rom_size, rom_size, MTRR_TYPE_WRPROT); +} + +/* + * Program temporary BAR for SPI in case any of the stages before ramstage need + * to access SPI MMIO regs. Ramstage will assign a new BAR during PCI + * enumeration. + */ +static void enable_spibar(void) +{ + device_t dev = SPI_DEV; + uint8_t val; + + /* Disable Bus Master and MMIO space. */ + val = pci_read_config8(dev, PCI_COMMAND); + val &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY); + pci_write_config8(dev, PCI_COMMAND, val); + + /* Program Temporary BAR for SPI */ + pci_write_config32(dev, PCI_BASE_ADDRESS_0, + PRERAM_SPI_BASE_ADDRESS | + PCI_BASE_ADDRESS_SPACE_MEMORY); + + /* Enable Bus Master and MMIO Space */ + val = pci_read_config8(dev, PCI_COMMAND); + val |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; + pci_write_config8(dev, PCI_COMMAND, val); + + /* Initialize SPI to allow BIOS to write/erase on flash. */ + spi_init(); +} + +static void enable_pmcbar(void) +{ + device_t pmc = PMC_DEV; + + /* Set PMC base addresses and enable decoding. */ + pci_write_config32(pmc, PCI_BASE_ADDRESS_0, PMC_BAR0); + pci_write_config32(pmc, PCI_BASE_ADDRESS_1, 0); /* 64-bit BAR */ + pci_write_config32(pmc, PCI_BASE_ADDRESS_2, PMC_BAR1); + pci_write_config32(pmc, PCI_BASE_ADDRESS_3, 0); /* 64-bit BAR */ + pci_write_config16(pmc, PCI_BASE_ADDRESS_4, ACPI_PMIO_BASE); + pci_write_config16(pmc, PCI_COMMAND, + PCI_COMMAND_IO | PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER); +} + +void bootblock_soc_early_init(void) +{ + enable_pmcbar(); + + /* Clear global reset promotion bit */ + global_reset_enable(0); + + /* Prepare UART for serial console. */ + if (IS_ENABLED(CONFIG_SOC_UART_DEBUG)) + soc_console_uart_init(); + + if (IS_ENABLED(CONFIG_TPM_ON_FAST_SPI)) + tpm_enable(); + + enable_pm_timer(); + + enable_spibar(); + + cache_bios_region(); + + /* Initialize GPE for use as interrupt status */ + pmc_gpe_init(); +} diff --git a/src/soc/intel/glk/bootblock/cache_as_ram.S b/src/soc/intel/glk/bootblock/cache_as_ram.S new file mode 100644 index 0000000..65dd4c8 --- /dev/null +++ b/src/soc/intel/glk/bootblock/cache_as_ram.S @@ -0,0 +1,251 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015-2016 Intel Corp. + * (Written by Andrey Petrov andrey.petrov@intel.com for 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. + */ + +#include <device/pci_def.h> +#include <commonlib/helpers.h> +#include <cpu/x86/mtrr.h> +#include <cpu/x86/cache.h> +#include <cpu/x86/cr.h> +#include <cpu/x86/post_code.h> +#include <soc/cpu.h> + +.global bootblock_pre_c_entry +bootblock_pre_c_entry: + +.global cache_as_ram +cache_as_ram: + post_code(0x21) + + /* Clear/disable fixed MTRRs */ + mov $fixed_mtrr_list_size, %ebx + xor %eax, %eax + xor %edx, %edx +clear_fixed_mtrr: + add $-2, %ebx + movzwl fixed_mtrr_list(%ebx), %ecx + wrmsr + jnz clear_fixed_mtrr + + post_code(0x22) + + /* Figure put how many MTRRs we have, and clear them out */ + mov $MTRR_CAP_MSR, %ecx + rdmsr + movzb %al, %ebx /* Number of variable MTRRs */ + mov $MTRR_PHYS_BASE(0), %ecx + xor %eax, %eax + xor %edx, %edx + +clear_var_mtrr: + wrmsr + inc %ecx + wrmsr + inc %ecx + dec %ebx + jnz clear_var_mtrr + + post_code(0x23) + + /* Configure default memory type to uncacheable (UC) */ + mov $MTRR_DEF_TYPE_MSR, %ecx + rdmsr + /* Clear enable bits and set default type to UC. */ + and $~(MTRR_DEF_TYPE_MASK | MTRR_DEF_TYPE_EN | \ + MTRR_DEF_TYPE_FIX_EN), %eax + wrmsr + + post_code(0x24) + +#if ((CONFIG_DCACHE_RAM_SIZE & (CONFIG_DCACHE_RAM_SIZE - 1)) == 0) + /* Configure CAR region as write-back (WB) */ + mov $MTRR_PHYS_BASE(0), %ecx + mov $CONFIG_DCACHE_RAM_BASE, %eax + or $MTRR_TYPE_WRBACK, %eax + xor %edx,%edx + wrmsr + + /* Configure the MTRR mask for the size region */ + mov $MTRR_PHYS_MASK(0), %ecx + mov $~(CONFIG_DCACHE_RAM_SIZE - 1), %eax /* size mask */ + or $MTRR_PHYS_MASK_VALID, %eax + wrmsr +#elif (CONFIG_DCACHE_RAM_SIZE == 768 * KiB) /* 768 KiB */ + mov $MTRR_PHYS_BASE(0), %ecx + mov $CONFIG_DCACHE_RAM_BASE, %eax + or $MTRR_TYPE_WRBACK, %eax + xor %edx,%edx + wrmsr + + mov $MTRR_PHYS_MASK(0), %ecx + mov $~(512 * KiB - 1), %eax /* size mask */ + or $MTRR_PHYS_MASK_VALID, %eax + wrmsr + + mov $MTRR_PHYS_BASE(1), %ecx + mov $(CONFIG_DCACHE_RAM_BASE + 512 * KiB), %eax + or $MTRR_TYPE_WRBACK, %eax + xor %edx,%edx + wrmsr + + mov $MTRR_PHYS_MASK(1), %ecx + mov $~(256 * KiB - 1), %eax /* size mask */ + or $MTRR_PHYS_MASK_VALID, %eax + wrmsr +#else +#error "DCACHE_RAM_SIZE is not a power of 2 and setup code is missing" +#endif + + post_code(0x25) + + /* Enable variable MTRRs */ + mov $MTRR_DEF_TYPE_MSR, %ecx + rdmsr + or $MTRR_DEF_TYPE_EN, %eax + wrmsr + + /* Enable caching */ + mov %cr0, %eax + and $~(CR0_CD | CR0_NW), %eax + invd + mov %eax, %cr0 + +#if IS_ENABLED(CONFIG_CAR_NEM) + /* Disable cache eviction (setup stage) */ + mov $MSR_EVICT_CTL, %ecx + rdmsr + or $0x1, %eax + wrmsr +#else + /* + * Disable both L1 and L2 prefetcher. For yet-to-understood reason, + * prefetchers slow down filling cache with rep stos in CQOS mode. + */ + mov $MSR_PREFETCH_CTL, %ecx + rdmsr + or $(PREFETCH_L1_DISABLE | PREFETCH_L2_DISABLE), %eax + wrmsr +#endif + +#if IS_ENABLED(CONFIG_CAR_CQOS) +#if (CONFIG_DCACHE_RAM_SIZE == L2_CACHE_SIZE) +/* + * If CAR size is set to full L2 size, mask is calculated as all-zeros. + * This is not supported by the CPU/uCode. + */ +#error "CQOS CAR may not use whole L2 cache area" +#endif + /* Calculate how many bits to be used for CAR */ + xor %edx, %edx + mov $CONFIG_DCACHE_RAM_SIZE, %eax /* dividend */ + mov $CACHE_QOS_SIZE_PER_BIT, %ecx /* divisor */ + div %ecx /* result is in eax */ + mov %eax, %ecx /* save to ecx */ + mov $1, %ebx + shl %cl, %ebx + sub $1, %ebx /* resulting mask is is in ebx */ + + /* Set this mask for initial cache fill */ + mov $MSR_L2_QOS_MASK(0), %ecx + rdmsr + mov %bl, %al + wrmsr + + /* Set CLOS selector to 0 */ + mov $MSR_IA32_PQR_ASSOC, %ecx + rdmsr + and $~IA32_PQR_ASSOC_MASK, %edx /* select mask 0 */ + wrmsr + + /* We will need to block CAR region from evicts */ + mov $MSR_L2_QOS_MASK(1), %ecx + rdmsr + /* Invert bits that are to be used for cache */ + mov %bl, %al + xor $~0, %al /* invert 8 bits */ + wrmsr +#endif + post_code(0x26) + + /* Clear the cache memory region. This will also fill up the cache */ + mov $CONFIG_DCACHE_RAM_BASE, %edi + mov $(CONFIG_DCACHE_RAM_SIZE >> 2), %ecx + xor %eax, %eax + rep stos %eax, %es:(%edi) + + post_code(0x27) + +#if IS_ENABLED(CONFIG_CAR_NEM) + /* Disable cache eviction (run stage) */ + mov $MSR_EVICT_CTL, %ecx + rdmsr + or $0x2, %eax + wrmsr +#else + /* Cache is populated. Use mask 1 that will block evicts */ + mov $MSR_IA32_PQR_ASSOC, %ecx + rdmsr + and $~IA32_PQR_ASSOC_MASK, %edx /* clear index bits first */ + or $1, %edx /* select mask 1 */ + wrmsr + + /* Enable prefetchers */ + mov $MSR_PREFETCH_CTL, %ecx + rdmsr + and $~(PREFETCH_L1_DISABLE | PREFETCH_L2_DISABLE), %eax + wrmsr +#endif + + post_code(0x28) + +car_init_done: + + /* Setup bootblock stack */ + mov $_car_stack_end, %esp + +before_carstage: + post_code(0x2b) + + /* Restore the timestamp from bootblock_crt0.S (mm2:mm1) */ + movd %mm2, %eax + push %eax + movd %mm1, %eax + push %eax + + /* We can call into C functions now */ + call bootblock_c_entry + + /* Never reached */ + +.halt_forever: + post_code(POST_DEAD_CODE) + hlt + jmp .halt_forever + +fixed_mtrr_list: + .word MTRR_FIX_64K_00000 + .word MTRR_FIX_16K_80000 + .word MTRR_FIX_16K_A0000 + .word MTRR_FIX_4K_C0000 + .word MTRR_FIX_4K_C8000 + .word MTRR_FIX_4K_D0000 + .word MTRR_FIX_4K_D8000 + .word MTRR_FIX_4K_E0000 + .word MTRR_FIX_4K_E8000 + .word MTRR_FIX_4K_F0000 + .word MTRR_FIX_4K_F8000 +fixed_mtrr_list_size = . - fixed_mtrr_list diff --git a/src/soc/intel/glk/car.c b/src/soc/intel/glk/car.c new file mode 100644 index 0000000..68bcb31 --- /dev/null +++ b/src/soc/intel/glk/car.c @@ -0,0 +1,58 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2016 Intel Corp. + * Copyright 2016 Google Inc. + * + * 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 <arch/cpu.h> +#include <assert.h> +#include <program_loading.h> +#include <soc/cpu.h> + +/* + * This file supports the necessary hoops one needs to jump through since + * early FSP component and early stages are running from cache-as-ram. + */ + +static void flush_l1d_to_l2(void) +{ + msr_t msr = rdmsr(MSR_POWER_MISC); + msr.lo |= (1 << 8); + wrmsr(MSR_POWER_MISC, msr); +} + +static inline int is_car_addr(uintptr_t addr) +{ + return ((addr >= CONFIG_DCACHE_RAM_BASE) && + (addr < (CONFIG_DCACHE_RAM_BASE + CONFIG_DCACHE_RAM_SIZE))); +} + +void platform_segment_loaded(uintptr_t start, size_t size, int flags) +{ + /* Bail out if this is not the final segment. */ + if (!(flags & SEG_FINAL)) + return; + + char start_car_check = is_car_addr(start); + char end_car_check = is_car_addr(start + size - 1); + + /* Bail out if loaded program segment does not lie in CAR region. */ + if (!start_car_check && !end_car_check) + return; + + /* Loaded program segment should lie entirely within CAR region. */ + assert (start_car_check && end_car_check); + + flush_l1d_to_l2(); +} diff --git a/src/soc/intel/glk/chip.c b/src/soc/intel/glk/chip.c new file mode 100644 index 0000000..916096b --- /dev/null +++ b/src/soc/intel/glk/chip.c @@ -0,0 +1,462 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 Intel Corp. + * (Written by Alexandru Gagniuc alexandrux.gagniuc@intel.com for Intel Corp.) + * (Written by Andrey Petrov andrey.petrov@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. + */ + +#include <arch/acpi.h> +#include <bootstate.h> +#include <cbmem.h> +#include <console/console.h> +#include <cpu/cpu.h> +#include <device/device.h> +#include <device/pci.h> +#include <fsp/api.h> +#include <fsp/util.h> +#include <soc/iomap.h> +#include <soc/cpu.h> +#include <soc/intel/common/vbt.h> +#include <soc/itss.h> +#include <soc/nvs.h> +#include <soc/pci_devs.h> +#include <spi-generic.h> +#include <soc/pm.h> +#include <soc/p2sb.h> +#include <soc/northbridge.h> + +#include "chip.h" + +static void *vbt; +static struct region_device vbt_rdev; + +static const char *soc_acpi_name(struct device *dev) +{ + if (dev->path.type == DEVICE_PATH_DOMAIN) + return "PCI0"; + + if (dev->path.type != DEVICE_PATH_PCI) + return NULL; + + switch (dev->path.pci.devfn) { + /* DSDT: acpi/northbridge.asl */ + case NB_DEVFN: + return "MCHC"; + /* DSDT: acpi/lpc.asl */ + case LPC_DEVFN: + return "LPCB"; + /* DSDT: acpi/xhci.asl */ + case XHCI_DEVFN: + return "XHCI"; + /* DSDT: acpi/pch_hda.asl */ + case HDA_DEVFN: + return "HDAS"; + /* DSDT: acpi/lpss.asl */ + case LPSS_DEVFN_UART0: + return "URT1"; + case LPSS_DEVFN_UART1: + return "URT2"; + case LPSS_DEVFN_UART2: + return "URT3"; + case LPSS_DEVFN_UART3: + return "URT4"; + case LPSS_DEVFN_SPI0: + return "SPI1"; + case LPSS_DEVFN_SPI1: + return "SPI2"; + case LPSS_DEVFN_SPI2: + return "SPI3"; + case LPSS_DEVFN_PWM: + return "PWM"; + case LPSS_DEVFN_I2C0: + return "I2C0"; + case LPSS_DEVFN_I2C1: + return "I2C1"; + case LPSS_DEVFN_I2C2: + return "I2C2"; + case LPSS_DEVFN_I2C3: + return "I2C3"; + case LPSS_DEVFN_I2C4: + return "I2C4"; + case LPSS_DEVFN_I2C5: + return "I2C5"; + case LPSS_DEVFN_I2C6: + return "I2C6"; + case LPSS_DEVFN_I2C7: + return "I2C7"; + /* Storage */ + case SDCARD_DEVFN: + return "SDCD"; + case EMMC_DEVFN: + return "EMMC"; + case SDIO_DEVFN: + return "SDIO"; + /* PCIe */ + case PCIEB0_DEVFN: + return "RP01"; + } + + return NULL; +} + +static void pci_domain_set_resources(device_t dev) +{ + assign_resources(dev->link_list); +} + +static struct device_operations pci_domain_ops = { + .read_resources = pci_domain_read_resources, + .set_resources = pci_domain_set_resources, + .enable_resources = NULL, + .init = NULL, + .scan_bus = pci_domain_scan_bus, + .ops_pci_bus = pci_bus_default_ops, + .acpi_name = &soc_acpi_name, +}; + +static struct device_operations cpu_bus_ops = { + .read_resources = DEVICE_NOOP, + .set_resources = DEVICE_NOOP, + .enable_resources = DEVICE_NOOP, + .init = glk_init_cpus, + .scan_bus = NULL, + .acpi_fill_ssdt_generator = generate_cpu_entries, +}; + +static void enable_dev(device_t dev) +{ + /* Set the operations if it is a special bus type */ + if (dev->path.type == DEVICE_PATH_DOMAIN) { + dev->ops = &pci_domain_ops; + } else if (dev->path.type == DEVICE_PATH_CPU_CLUSTER) { + dev->ops = &cpu_bus_ops; + } +} + +/* + * If the PCIe root port at function 0 is disabled, + * the PCIe root ports might be coalesced after FSP silicon init. + * The below function will swap the devfn of the first enabled device + * in devicetree and function 0 resides a pci device + * so that it won't confuse coreboot. + */ +static void pcie_update_device_tree(unsigned int devfn0, int num_funcs) +{ + device_t func0; + unsigned int devfn; + int i; + unsigned int inc = PCI_DEVFN(0, 1); + + func0 = dev_find_slot(0, devfn0); + if (func0 == NULL) + return; + + /* No more functions if function 0 is disabled. */ + if (pci_read_config32(func0, PCI_VENDOR_ID) == 0xffffffff) + return; + + devfn = devfn0 + inc; + + /* + * Increase funtion by 1. + * Then find first enabled device to replace func0 + * as that port was move to func0. + */ + for (i = 1; i < num_funcs; i++, devfn += inc) { + device_t dev = dev_find_slot(0, devfn); + if (dev == NULL) + continue; + + if (!dev->enabled) + continue; + /* Found the first enabled device in given dev number */ + func0->path.pci.devfn = dev->path.pci.devfn; + dev->path.pci.devfn = devfn0; + break; + } +} + +static void pcie_override_devicetree_after_silicon_init(void) +{ + pcie_update_device_tree(PCIEA0_DEVFN, 4); + pcie_update_device_tree(PCIEB0_DEVFN, 2); +} + +static void rapl_update(void) +{ + uint32_t *rapl_reg; + uint32_t val; + const uint32_t power_mw = 15000; + + rapl_reg = (void*)(uintptr_t) (MCH_BASE_ADDR + MCHBAR_RAPL_PPL); + + /* Due to an incorrect value set for the power limit PL1 as 6W in RAPL + * MMIO register from FSP code, the system is not able to leverage full + * TDP capacity. This RAPL MMIO register is a physically separate + * instance from RAPL MSR register. Punit algorithm controls to the + * minimum power limit PL1 mentioned in the RAPL MMIO and MSR registers. + * Here, setting RAPL PL1 in Bits[14:0] to 15W in RAPL MMIO register. */ + val = (power_mw << (rdmsr(MSR_PKG_POWER_SKU_UNIT).lo & 0xf)) / 1000; + write32(rapl_reg, (read32(rapl_reg) & ~0x7fff) | val); +} + +static void soc_init(void *data) +{ + struct global_nvs_t *gnvs; + + /* Save VBT info and mapping */ + vbt = vbt_get(&vbt_rdev); + + /* Snapshot the current GPIO IRQ polarities. FSP is setting a + * default policy that doesn't honor boards' requirements. */ + itss_snapshot_irq_polarities(GPIO_IRQ_START, GPIO_IRQ_END); + + fsp_silicon_init(); + + /* Restore GPIO IRQ polarities back to previous settings. */ + itss_restore_irq_polarities(GPIO_IRQ_START, GPIO_IRQ_END); + + /* override 'enabled' setting in device tree if needed */ + pcie_override_devicetree_after_silicon_init(); + + /* + * Keep the P2SB device visible so it and the other devices are + * visible in coreboot for driver support and PCI resource allocation. + * There is a UPD setting for this, but it's more consistent to use + * hide and unhide symmetrically. + */ + p2sb_unhide(); + + /* Allocate ACPI NVS in CBMEM */ + gnvs = cbmem_add(CBMEM_ID_ACPI_GNVS, sizeof(*gnvs)); + + /* Update RAPL package power limit */ + rapl_update(); +} + +static void soc_final(void *data) +{ + if (vbt) + rdev_munmap(&vbt_rdev, vbt); + + /* Disable global reset, just in case */ + global_reset_enable(0); + /* Make sure payload/OS can't trigger global reset */ + global_reset_lock(); +} + +static void disable_dev(struct device *dev, FSP_S_CONFIG *silconfig) { + + switch (dev->path.pci.devfn) { + case ISH_DEVFN: + silconfig->IshEnable = 0; + break; + case SATA_DEVFN: + silconfig->EnableSata = 0; + break; + case PCIEB0_DEVFN: + silconfig->PcieRootPortEn[0] = 0; + silconfig->PcieRpHotPlug[0] = 0; + break; + case PCIEB1_DEVFN: + silconfig->PcieRootPortEn[1] = 0; + silconfig->PcieRpHotPlug[1] = 0; + break; + case PCIEA0_DEVFN: + silconfig->PcieRootPortEn[2] = 0; + silconfig->PcieRpHotPlug[2] = 0; + break; + case PCIEA1_DEVFN: + silconfig->PcieRootPortEn[3] = 0; + silconfig->PcieRpHotPlug[3] = 0; + break; + case PCIEA2_DEVFN: + silconfig->PcieRootPortEn[4] = 0; + silconfig->PcieRpHotPlug[4] = 0; + break; + case PCIEA3_DEVFN: + silconfig->PcieRootPortEn[5] = 0; + silconfig->PcieRpHotPlug[5] = 0; + break; + case XHCI_DEVFN: + silconfig->Usb30Mode = 0; + break; + case XDCI_DEVFN: + silconfig->UsbOtg = 0; + break; + case LPSS_DEVFN_I2C0: + silconfig->I2c0Enable = 0; + break; + case LPSS_DEVFN_I2C1: + silconfig->I2c1Enable = 0; + break; + case LPSS_DEVFN_I2C2: + silconfig->I2c2Enable = 0; + break; + case LPSS_DEVFN_I2C3: + silconfig->I2c3Enable = 0; + break; + case LPSS_DEVFN_I2C4: + silconfig->I2c4Enable = 0; + break; + case LPSS_DEVFN_I2C5: + silconfig->I2c5Enable = 0; + break; + case LPSS_DEVFN_I2C6: + silconfig->I2c6Enable = 0; + break; + case LPSS_DEVFN_I2C7: + silconfig->I2c7Enable = 0; + break; + case LPSS_DEVFN_UART0: + silconfig->Hsuart0Enable = 0; + break; + case LPSS_DEVFN_UART1: + silconfig->Hsuart1Enable = 0; + break; + case LPSS_DEVFN_UART2: + silconfig->Hsuart2Enable = 0; + break; + case LPSS_DEVFN_UART3: + silconfig->Hsuart3Enable = 0; + break; + case LPSS_DEVFN_SPI0: + silconfig->Spi0Enable = 0; + break; + case LPSS_DEVFN_SPI1: + silconfig->Spi1Enable = 0; + break; + case LPSS_DEVFN_SPI2: + silconfig->Spi2Enable = 0; + break; + case SDCARD_DEVFN: + silconfig->SdcardEnabled = 0; + break; + case EMMC_DEVFN: + silconfig->eMMCEnabled = 0; + break; + case SDIO_DEVFN: + silconfig->SdioEnabled = 0; + break; + case SMBUS_DEVFN: + silconfig->SmbusEnable = 0; + break; + default: + printk(BIOS_WARNING, "PCI:%02x.%01x: Could not disable the device\n", + PCI_SLOT(dev->path.pci.devfn), + PCI_FUNC(dev->path.pci.devfn)); + break; + } +} + +static void parse_devicetree(FSP_S_CONFIG *silconfig) +{ + struct device *dev = NB_DEV_ROOT; + + if (!dev) { + printk(BIOS_ERR, "Could not find root device\n"); + return; + } + /* Only disable bus 0 devices. */ + for (dev = dev->bus->children; dev; dev = dev->sibling) { + if (!dev->enabled) + disable_dev(dev, silconfig); + } +} + +void platform_fsp_silicon_init_params_cb(FSPS_UPD *silupd) +{ + FSP_S_CONFIG *silconfig = &silupd->FspsConfig; + static struct soc_intel_glk_config *cfg; + + /* Load VBT before devicetree-specific config. */ + silconfig->GraphicsConfigPtr = (uintptr_t)vbt; + + struct device *dev = NB_DEV_ROOT; + + if (!dev || !dev->chip_info) { + printk(BIOS_ERR, "BUG! Could not find SOC devicetree config\n"); + return; + } + + cfg = dev->chip_info; + + /* Parse device tree and disable unused device*/ + parse_devicetree(silconfig); + + silconfig->PcieRpClkReqNumber[0] = cfg->pcie_rp0_clkreq_pin; + silconfig->PcieRpClkReqNumber[1] = cfg->pcie_rp1_clkreq_pin; + silconfig->PcieRpClkReqNumber[2] = cfg->pcie_rp2_clkreq_pin; + silconfig->PcieRpClkReqNumber[3] = cfg->pcie_rp3_clkreq_pin; + silconfig->PcieRpClkReqNumber[4] = cfg->pcie_rp4_clkreq_pin; + silconfig->PcieRpClkReqNumber[5] = cfg->pcie_rp5_clkreq_pin; + + if (cfg->emmc_tx_cmd_cntl != 0) + silconfig->EmmcTxCmdCntl = cfg->emmc_tx_cmd_cntl; + if (cfg->emmc_tx_data_cntl1 != 0) + silconfig->EmmcTxDataCntl1 = cfg->emmc_tx_data_cntl1; + if (cfg->emmc_tx_data_cntl2 != 0) + silconfig->EmmcTxDataCntl2 = cfg->emmc_tx_data_cntl2; + if (cfg->emmc_rx_cmd_data_cntl1 != 0) + silconfig->EmmcRxCmdDataCntl1 = cfg->emmc_rx_cmd_data_cntl1; + if (cfg->emmc_rx_strobe_cntl != 0) + silconfig->EmmcRxStrobeCntl = cfg->emmc_rx_strobe_cntl; + if (cfg->emmc_rx_cmd_data_cntl2 != 0) + silconfig->EmmcRxCmdDataCntl2 = cfg->emmc_rx_cmd_data_cntl2; + + silconfig->LPSS_S0ixEnable = cfg->lpss_s0ix_enable; + + /* Disable monitor mwait since it is broken due to a hardware bug without a fix */ + silconfig->MonitorMwaitEnable = 0; + + /* Disable setting of EISS bit in FSP. */ + silconfig->SpiEiss = 0; + + /* Disable FSP from locking access to the RTC NVRAM */ + silconfig->RtcLock = 0; + + /* Enable Audio clk gate and power gate */ + silconfig->HDAudioClkGate = cfg->hdaudio_clk_gate_enable; + silconfig->HDAudioPwrGate = cfg->hdaudio_pwr_gate_enable; + /* Bios config lockdown Audio clk and power gate */ + silconfig->BiosCfgLockDown = cfg->hdaudio_bios_config_lockdown; + +} + +struct chip_operations soc_intel_glk_ops = { + CHIP_NAME("Intel GLK SOC") + .enable_dev = &enable_dev, + .init = &soc_init, + .final = &soc_final +}; + +void platform_fsp_notify_status(enum fsp_notify_phase phase) +{ + /* Hide the P2SB device to align with previous behavior. */ + if (phase == END_OF_FIRMWARE) + p2sb_hide(); +} + +/* + * spi_init() needs to run unconditionally on every boot (including resume) to + * allow write protect to be disabled for eventlog and nvram updates. This needs + * to be done as early as possible in ramstage. Thus, add a callback for entry + * into BS_PRE_DEVICE. + */ +static void spi_init_cb(void *unused) +{ + spi_init(); +} + +BOOT_STATE_INIT_ENTRY(BS_PRE_DEVICE, BS_ON_ENTRY, spi_init_cb, NULL); diff --git a/src/soc/intel/glk/chip.h b/src/soc/intel/glk/chip.h new file mode 100644 index 0000000..40247db --- /dev/null +++ b/src/soc/intel/glk/chip.h @@ -0,0 +1,124 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 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_GLK_CHIP_H_ +#define _SOC_GLK_CHIP_H_ + +#include <soc/gpe.h> +#include <soc/gpio_defs.h> +#include <soc/gpio.h> +#include <soc/intel/common/lpss_i2c.h> +#include <device/i2c.h> +#include <soc/pm.h> + +#define CLKREQ_DISABLED 0xf +#define GLK_I2C_DEV_MAX 8 + +struct glk_i2c_config { + /* Bus should be enabled prior to ramstage with temporary base */ + int early_init; + /* Bus speed in Hz, default is I2C_SPEED_FAST (400 KHz) */ + enum i2c_speed speed; + /* Specific bus speed configuration */ + struct lpss_i2c_speed_config speed_config[LPSS_I2C_SPEED_CONFIG_COUNT]; +}; + +/* Serial IRQ control. SERIRQ_QUIET is the default (0). */ +enum serirq_mode { + SERIRQ_QUIET, + SERIRQ_CONTINUOUS, + SERIRQ_OFF, +}; + +struct soc_intel_glk_config { + /* + * Mapping from PCIe root port to CLKREQ input on the SOC. The SOC has + * four CLKREQ inputs, but six root ports. Root ports without an + * associated CLKREQ signal must be marked with "CLKREQ_DISABLED" + */ + uint8_t pcie_rp0_clkreq_pin; + uint8_t pcie_rp1_clkreq_pin; + uint8_t pcie_rp2_clkreq_pin; + uint8_t pcie_rp3_clkreq_pin; + uint8_t pcie_rp4_clkreq_pin; + uint8_t pcie_rp5_clkreq_pin; + + /* [14:8] DDR mode Number of dealy elements.Each = 125pSec. + * [6:0] SDR mode Number of dealy elements.Each = 125pSec. + */ + uint32_t emmc_tx_cmd_cntl; + + /* [14:8] HS400 mode Number of dealy elements.Each = 125pSec. + * [6:0] SDR104/HS200 mode Number of dealy elements.Each = 125pSec. + */ + uint32_t emmc_tx_data_cntl1; + + /* [30:24] SDR50 mode Number of dealy elements.Each = 125pSec. + * [22:16] DDR50 mode Number of dealy elements.Each = 125pSec. + * [14:8] SDR25/HS50 mode Number of dealy elements.Each = 125pSec. + * [6:0] SDR12/Compatibility mode Number of dealy elements.Each = 125pSec. + */ + uint32_t emmc_tx_data_cntl2; + + /* [30:24] SDR50 mode Number of dealy elements.Each = 125pSec. + * [22:16] DDR50 mode Number of dealy elements.Each = 125pSec. + * [14:8] SDR25/HS50 mode Number of dealy elements.Each = 125pSec. + * [6:0] SDR12/Compatibility mode Number of dealy elements.Each = 125pSec. + */ + uint32_t emmc_rx_cmd_data_cntl1; + + /* [14:8] HS400 mode 1 Number of dealy elements.Each = 125pSec. + * [6:0] HS400 mode 2 Number of dealy elements.Each = 125pSec. + */ + uint32_t emmc_rx_strobe_cntl; + + /* [13:8] Auto Tuning mode Number of dealy elements.Each = 125pSec. + * [6:0] SDR104/HS200 Number of dealy elements.Each = 125pSec. + */ + uint32_t emmc_rx_cmd_data_cntl2; + + /* Configure serial IRQ (SERIRQ) line. */ + enum serirq_mode serirq_mode; + + /* I2C bus configuration */ + struct glk_i2c_config i2c[GLK_I2C_DEV_MAX]; + + uint8_t gpe0_dw1; /* GPE0_63_32 STS/EN */ + uint8_t gpe0_dw2; /* GPE0_95_64 STS/EN */ + uint8_t gpe0_dw3; /* GPE0_127_96 STS/EN */ + + /* Configure LPSS S0ix Enable */ + uint8_t lpss_s0ix_enable; + + /* Enable DPTF support */ + int dptf_enable; + + /* Configure Audio clk gate and power gate + * IOSF-SB port ID 92 offset 0x530 [5] and [3] + */ + uint8_t hdaudio_clk_gate_enable; + uint8_t hdaudio_pwr_gate_enable; + uint8_t hdaudio_bios_config_lockdown; + + /* SLP S3 minimum assertion width. */ + int slp_s3_assertion_width_usecs; + + /* GPIO pin for PERST_0 */ + uint16_t prt0_gpio; +}; + +#endif /* _SOC_GLK_CHIP_H_ */ diff --git a/src/soc/intel/glk/cpu.c b/src/soc/intel/glk/cpu.c new file mode 100644 index 0000000..7d74c2b --- /dev/null +++ b/src/soc/intel/glk/cpu.c @@ -0,0 +1,154 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015-2016 Intel Corp. + * (Written by Andrey Petrov andrey.petrov@intel.com for 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. + */ + +#include <console/console.h> +#include <cpu/cpu.h> +#include <cpu/x86/cache.h> +#include <cpu/x86/mp.h> +#include <cpu/intel/microcode.h> +#include <cpu/x86/msr.h> +#include <cpu/x86/mtrr.h> +#include <device/device.h> +#include <device/pci.h> +#include <soc/cpu.h> +#include <soc/smm.h> + +static struct device_operations cpu_dev_ops = { + .init = DEVICE_NOOP, +}; + +static struct cpu_device_id cpu_table[] = { + { X86_VENDOR_INTEL, CPUID_GLK_A0 }, + { 0, 0 }, +}; + +static const struct cpu_driver driver __cpu_driver = { + .ops = &cpu_dev_ops, + .id_table = cpu_table, +}; + +/* + * MP and SMM loading initialization. + */ +struct smm_relocation_attrs { + uint32_t smbase; + uint32_t smrr_base; + uint32_t smrr_mask; +}; + +static struct smm_relocation_attrs relo_attrs; + +static void read_cpu_topology(unsigned int *num_phys, unsigned int *num_virt) +{ + msr_t msr; + msr = rdmsr(MSR_CORE_THREAD_COUNT); + *num_virt = (msr.lo >> 0) & 0xffff; + *num_phys = (msr.lo >> 16) & 0xffff; +} + +/* + * Do essential initialization tasks before APs can be fired up + * + * 1. Prevent race condition in MTRR solution. Enable MTRRs on the BSP. This + * creates the MTRR solution that the APs will use. Otherwise APs will try to + * apply the incomplete solution as the BSP is calculating it. + */ +static void pre_mp_init(void) +{ + x86_setup_mtrrs_with_detect(); + x86_mtrr_check(); +} + +/* Find CPU topology */ +static int get_cpu_count(void) +{ + unsigned int num_virt_cores, num_phys_cores; + + read_cpu_topology(&num_phys_cores, &num_virt_cores); + + printk(BIOS_DEBUG, "Detected %u core, %u thread CPU.\n", + num_phys_cores, num_virt_cores); + + return num_virt_cores; +} + +static void get_microcode_info(const void **microcode, int *parallel) +{ + *microcode = intel_microcode_find(); + *parallel = 1; +} + +static void get_smm_info(uintptr_t *perm_smbase, size_t *perm_smsize, + size_t *smm_save_state_size) +{ + void *smm_base; + size_t smm_size; + + /* All range registers are aligned to 4KiB */ + const uint32_t rmask = ~((1 << 12) - 1); + + /* Initialize global tracking state. */ + smm_region(&smm_base, &smm_size); + relo_attrs.smbase = (uint32_t)smm_base; + relo_attrs.smrr_base = relo_attrs.smbase | MTRR_TYPE_WRBACK; + relo_attrs.smrr_mask = ~(smm_size - 1) & rmask; + relo_attrs.smrr_mask |= MTRR_PHYS_MASK_VALID; + + *perm_smbase = relo_attrs.smbase; + *perm_smsize = smm_size - CONFIG_SMM_RESERVED_SIZE; + *smm_save_state_size = sizeof(em64t100_smm_state_save_area_t); +} + +static void relocation_handler(int cpu, uintptr_t curr_smbase, + uintptr_t staggered_smbase) +{ + msr_t smrr; + em64t100_smm_state_save_area_t *smm_state; + /* Set up SMRR. */ + smrr.lo = relo_attrs.smrr_base; + smrr.hi = 0; + wrmsr(SMRR_PHYS_BASE, smrr); + smrr.lo = relo_attrs.smrr_mask; + smrr.hi = 0; + wrmsr(SMRR_PHYS_MASK, smrr); + smm_state = (void *)(SMM_EM64T100_SAVE_STATE_OFFSET + curr_smbase); + smm_state->smbase = staggered_smbase; +} +/* + * CPU initialization recipe + * + * Note that no microcode update is passed to the init function. CSE updates + * the microcode on all cores before releasing them from reset. That means that + * the BSP and all APs will come up with the same microcode revision. + */ +static const struct mp_ops mp_ops = { + .pre_mp_init = pre_mp_init, + .get_cpu_count = get_cpu_count, + .get_smm_info = get_smm_info, + .get_microcode_info = get_microcode_info, + .pre_mp_smm_init = southbridge_smm_clear_state, + .relocation_handler = relocation_handler, + .post_mp_init = southbridge_smm_enable_smi, +}; + +void glk_init_cpus(device_t dev) +{ + /* Clear for take-off */ + if (mp_init_with_smm(dev->link_list, &mp_ops) < 0) + printk(BIOS_ERR, "MP initialization failure.\n"); +} diff --git a/src/soc/intel/glk/dsp.c b/src/soc/intel/glk/dsp.c new file mode 100644 index 0000000..a2d21aa --- /dev/null +++ b/src/soc/intel/glk/dsp.c @@ -0,0 +1,32 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2016 Google Inc. + * + * 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 <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <soc/pci_ids.h> + +static struct device_operations dsp_dev_ops = { + .read_resources = &pci_dev_read_resources, + .set_resources = &pci_dev_set_resources, + .enable_resources = &pci_dev_enable_resources, + .scan_bus = &scan_static_bus, +}; + +static const struct pci_driver apollolake_dsp __pci_driver = { + .ops = &dsp_dev_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_APOLLOLAKE_AUDIO +}; diff --git a/src/soc/intel/glk/elog.c b/src/soc/intel/glk/elog.c new file mode 100644 index 0000000..0dd44c2 --- /dev/null +++ b/src/soc/intel/glk/elog.c @@ -0,0 +1,107 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2016 Google Inc. + * Copyright (C) 2016 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 <bootstate.h> +#include <cbmem.h> +#include <console/console.h> +#include <elog.h> +#include <soc/pm.h> +#include <soc/pci_devs.h> +#include <stdint.h> + +static void pch_log_gpio_gpe(u32 gpe0_sts, u32 gpe0_en, int start) +{ + int i; + + gpe0_sts &= gpe0_en; + + for (i = 0; i <= 31; i++) { + if (gpe0_sts & (1 << i)) + elog_add_event_wake(ELOG_WAKE_SOURCE_GPIO, i + start); + } +} + +static void pch_log_wake_source(struct chipset_power_state *ps) +{ + /* Power Button */ + if (ps->pm1_sts & PWRBTN_STS) + elog_add_event_wake(ELOG_WAKE_SOURCE_PWRBTN, 0); + + /* RTC */ + if (ps->pm1_sts & RTC_STS) + elog_add_event_wake(ELOG_WAKE_SOURCE_RTC, 0); + + /* PCI Express (TODO: determine wake device) */ + if (ps->pm1_sts & PCIEXPWAK_STS) + elog_add_event_wake(ELOG_WAKE_SOURCE_PCIE, 0); + + /* PME */ + if(ps->gpe0_sts[GPE0_A] & CSE_PME_STS) + elog_add_event_wake(ELOG_WAKE_SOURCE_PME, 0); + + /* SMBUS Wake */ + if (ps->gpe0_sts[GPE0_A] & SMB_WAK_STS) + elog_add_event_wake(ELOG_WAKE_SOURCE_SMBUS, 0); + + /* ACPI Wake Event - Always Log prev_sleep_state*/ + elog_add_event_byte(ELOG_TYPE_ACPI_WAKE, ps->prev_sleep_state); + + /* Log GPIO events in set A-D */ + pch_log_gpio_gpe(ps->gpe0_sts[GPE0_A], ps->gpe0_en[GPE0_A], 0); + pch_log_gpio_gpe(ps->gpe0_sts[GPE0_B], ps->gpe0_en[GPE0_B], 32); + pch_log_gpio_gpe(ps->gpe0_sts[GPE0_C], ps->gpe0_en[GPE0_C], 64); + pch_log_gpio_gpe(ps->gpe0_sts[GPE0_D], ps->gpe0_en[GPE0_D], 96); +} + +static void pch_log_power_and_resets(struct chipset_power_state *ps) +{ + /* RTC Reset */ + if (ps->gen_pmcon1 & RPS) + elog_add_event(ELOG_TYPE_RTC_RESET); + + /* System Reset */ + if (ps->gen_pmcon1 & SRS) + elog_add_event(ELOG_TYPE_SYSTEM_RESET); + + /* TCO Timeout */ + if (ps->prev_sleep_state != ACPI_S3 && + ps->tco_sts & TCO_TIMEOUT) + elog_add_event(ELOG_TYPE_TCO_RESET); + + /* Power Button Override */ + if (ps->pm1_sts & PRBTNOR_STS) + elog_add_event(ELOG_TYPE_POWER_BUTTON_OVERRIDE); + +} + +void pch_log_state(void) +{ + struct chipset_power_state *ps = cbmem_find(CBMEM_ID_POWER_STATE); + + if (ps == NULL) { + printk(BIOS_ERR, + "Not logging power state information. " + "Power state not found in cbmem.\n"); + return; + } + + /* Power and Reset */ + pch_log_power_and_resets(ps); + + /* Wake Sources */ + if (ps->prev_sleep_state > ACPI_S0) + pch_log_wake_source(ps); +} diff --git a/src/soc/intel/glk/exit_car.S b/src/soc/intel/glk/exit_car.S new file mode 100644 index 0000000..e21aa29 --- /dev/null +++ b/src/soc/intel/glk/exit_car.S @@ -0,0 +1,68 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2016 Google Inc. + * + * 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 <cpu/x86/mtrr.h> +#include <cpu/x86/cr.h> +#include <soc/cpu.h> + +.text +.global chipset_teardown_car +chipset_teardown_car: + /* + * Retrieve return address from stack as it will get trashed below if + * execution is utilizing the cache-as-ram stack. + */ + pop %ebx + + /* Disable MTRRs. */ + mov $(MTRR_DEF_TYPE_MSR), %ecx + rdmsr + and $(~(MTRR_DEF_TYPE_EN | MTRR_DEF_TYPE_FIX_EN)), %eax + wrmsr + +#if IS_ENABLED(CONFIG_CAR_CQOS) + /* Go back to all-evicting mode, set both masks to all-1s */ + mov $MSR_L2_QOS_MASK(0), %ecx + rdmsr + mov $~0, %al + wrmsr + + mov $MSR_L2_QOS_MASK(1), %ecx + rdmsr + mov $~0, %al + wrmsr + + /* Reset CLOS selector to 0 */ + mov $MSR_IA32_PQR_ASSOC, %ecx + rdmsr + and $~IA32_PQR_ASSOC_MASK, %edx + wrmsr +#endif + /* invalidate cache contents. */ + invd + +#if IS_ENABLED(CONFIG_CAR_NEM) + /* Knock down bit 1 then bit 0 of NEM control not combining steps. */ + mov $(MSR_EVICT_CTL), %ecx + rdmsr + and $(~(1 << 1)), %eax + wrmsr + and $(~(1 << 0)), %eax + wrmsr +#endif + + /* Return to caller. */ + jmp *%ebx diff --git a/src/soc/intel/glk/gpio.c b/src/soc/intel/glk/gpio.c new file mode 100644 index 0000000..4731d56 --- /dev/null +++ b/src/soc/intel/glk/gpio.c @@ -0,0 +1,418 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 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. + */ + +#include <assert.h> +#include <gpio.h> +#include <soc/gpio.h> +#include <soc/iosf.h> +#include <soc/itss.h> +#include <soc/pm.h> + +/* This list must be in order, from highest pad numbers, to lowest pad numbers*/ +static const struct pad_community { + uint16_t first_pad; + uint8_t port; + uint8_t num_gpi_regs; + uint8_t gpi_offset; + const char *grp_name; +} gpio_communities[] = { + { + .port = GPIO_SW, + .first_pad = SW_OFFSET, + .num_gpi_regs = NUM_SW_GPI_REGS, + .gpi_offset = 0, + .grp_name = "GPIO_GPE_SW", + }, { + .port = GPIO_W, + .first_pad = W_OFFSET, + .num_gpi_regs = NUM_W_GPI_REGS, + .gpi_offset = NUM_SW_GPI_REGS, + .grp_name = "GPIO_GPE_W", + }, { + .port = GPIO_NW, + .first_pad = NW_OFFSET, + .num_gpi_regs = NUM_NW_GPI_REGS, + .gpi_offset = NUM_W_GPI_REGS + NUM_SW_GPI_REGS, + .grp_name = "GPIO_GPE_NW", + }, { + .port = GPIO_N, + .first_pad = N_OFFSET, + .num_gpi_regs = NUM_N_GPI_REGS, + .gpi_offset = NUM_NW_GPI_REGS+ NUM_W_GPI_REGS + NUM_SW_GPI_REGS, + .grp_name = "GPIO_GPE_N", + } +}; + +static const struct pad_community *gpio_get_community(uint16_t pad) +{ + const struct pad_community *map = gpio_communities; + + assert(pad < TOTAL_PADS); + + while (map->first_pad > pad) + map++; + + return map; +} + +static void gpio_configure_itss(const struct pad_config *cfg, + uint16_t port, uint16_t pad_cfg_offset) +{ + /* No ITSS configuration in SMM. */ + if (ENV_SMM) + return; + + int irq; + + /* Set up ITSS polarity if pad is routed to APIC. + * + * The ITSS takes only active high interrupt signals. Therefore, + * if the pad configuration indicates an inversion assume the + * intent is for the ITSS polarity. Before forwarding on the + * request to the APIC there's an inversion setting for how the + * signal is forwarded to the APIC. Honor the inversion setting + * in the GPIO pad configuration so that a hardware active low + * signal looks that way to the APIC (double inversion). + */ + if (!(cfg->config0 & PAD_CFG0_ROUTE_IOAPIC)) + return; + + irq = iosf_read(port, pad_cfg_offset + sizeof(uint32_t)); + irq &= PAD_CFG1_IRQ_MASK; + if (!irq) { + printk(BIOS_ERR, "GPIO %u doesn't support APIC routing,\n", + cfg->pad); + return; + } + + itss_set_irq_polarity(irq, !!(cfg->config0 & PAD_CFG0_RX_POL_INVERT)); +} + +static void gpio_configure_owner(const struct pad_config *cfg, + uint16_t port, int pin) +{ + uint32_t val; + uint16_t hostsw_reg; + + /* The 4th bit in pad_config 1 (RO) is used to indicate if the pad + * needs GPIO driver ownership. + */ + if (!(cfg->config1 & PAD_CFG1_GPIO_DRIVER)) + return; + + /* Based on the gpio pin number configure the corresponding bit in + * HOSTSW_OWN register. Value of 0x1 indicates GPIO Driver onwership. + */ + hostsw_reg = HOSTSW_OWN_REG_BASE + ((pin / 32) * sizeof(uint32_t)); + val = iosf_read(port, hostsw_reg); + val |= 1 << (pin % 32); + iosf_write(port, hostsw_reg, val); +} + +static void gpi_enable_smi(const struct pad_config *cfg, uint16_t port, int pin) +{ + uint32_t value; + uint16_t sts_reg; + uint16_t en_reg; + int group; + + if (((cfg->config0) & PAD_CFG0_ROUTE_SMI) != PAD_CFG0_ROUTE_SMI) + return; + + group = pin / GPIO_MAX_NUM_PER_GROUP; + + sts_reg = GPI_SMI_STS_OFFSET(group); + value = iosf_read(port, sts_reg); + /* Write back 1 to reset the sts bits */ + iosf_write(port, sts_reg, value); + + /* Set enable bits */ + en_reg = GPI_SMI_EN_OFFSET(group); + value = iosf_read(port, en_reg ); + value |= 1 << (pin % GPIO_MAX_NUM_PER_GROUP); + iosf_write(port, en_reg , value); +} + +void gpio_configure_pad(const struct pad_config *cfg) +{ + uint32_t dw1; + const struct pad_community *comm = gpio_get_community(cfg->pad); + uint16_t config_offset = PAD_CFG_OFFSET(cfg->pad - comm->first_pad); + + /* Iostandby bits are tentatively stored in [3:0] bits (RO) of config1. + * dw1 is used to extract the bits of Iostandby. + * This is done to preserve config1 size as unit16 in gpio.h. + */ + dw1 = cfg->config1 & ~PAD_CFG1_IOSSTATE_MASK; + dw1 |= (cfg->config1 & PAD_CFG1_IOSSTATE_MASK) << PAD_CFG1_IOSSTATE_SHIFT; + + iosf_write(comm->port, config_offset, cfg->config0); + iosf_write(comm->port, config_offset + sizeof(uint32_t), dw1); + + gpio_configure_itss(cfg, comm->port, config_offset); + gpio_configure_owner(cfg, comm->port, cfg->pad - comm->first_pad); + + gpi_enable_smi(cfg, comm->port, cfg->pad - comm->first_pad); +} + +void gpio_configure_pads(const struct pad_config *cfg, size_t num_pads) +{ + uint32_t i; + + for (i = 0; i < num_pads; i++) + gpio_configure_pad(cfg + i); +} + +void * gpio_dwx_address(const uint16_t pad) +{ + /* Calculate Address of DW0 register for given GPIO + * pad - GPIO number + * returns - address of GPIO + */ + const struct pad_community *comm = gpio_get_community(pad); + return iosf_address(comm->port, PAD_CFG_OFFSET(pad - comm->first_pad)); +} + +void gpio_input_pulldown(gpio_t gpio) +{ + struct pad_config cfg = PAD_CFG_GPI(gpio, DN_20K, DEEP); + gpio_configure_pad(&cfg); +} + +void gpio_input_pullup(gpio_t gpio) +{ + struct pad_config cfg = PAD_CFG_GPI(gpio, UP_20K, DEEP); + gpio_configure_pad(&cfg); +} + +void gpio_input(gpio_t gpio) +{ + struct pad_config cfg = PAD_CFG_GPI(gpio, NONE, DEEP); + gpio_configure_pad(&cfg); +} + +void gpio_output(gpio_t gpio, int value) +{ + struct pad_config cfg = PAD_CFG_GPO(gpio, value, DEEP); + gpio_configure_pad(&cfg); +} + +int gpio_get(gpio_t gpio_num) +{ + uint32_t reg; + const struct pad_community *comm = gpio_get_community(gpio_num); + uint16_t config_offset = PAD_CFG_OFFSET(gpio_num - comm->first_pad); + + reg = iosf_read(comm->port, config_offset); + + return !!(reg & PAD_CFG0_RX_STATE); +} + +void gpio_set(gpio_t gpio_num, int value) +{ + uint32_t reg; + const struct pad_community *comm = gpio_get_community(gpio_num); + uint16_t config_offset = PAD_CFG_OFFSET(gpio_num - comm->first_pad); + + reg = iosf_read(comm->port, config_offset); + reg &= ~PAD_CFG0_TX_STATE; + reg |= !!value & PAD_CFG0_TX_STATE; + iosf_write(comm->port, config_offset, reg); +} + +const char *gpio_acpi_path(gpio_t gpio_num) +{ + const struct pad_community *comm = gpio_get_community(gpio_num); + + switch (comm->port) { + case GPIO_N: + return "\_SB.GPO0"; + case GPIO_NW: + return "\_SB.GPO1"; + case GPIO_W: + return "\_SB.GPO2"; + case GPIO_SW: + return "\_SB.GPO3"; + } + + return NULL; +} + +uint16_t gpio_acpi_pin(gpio_t gpio_num) +{ + const struct pad_community *comm = gpio_get_community(gpio_num); + + switch (comm->port) { + case GPIO_N: + return PAD_N(gpio_num); + case GPIO_NW: + return PAD_NW(gpio_num); + case GPIO_W: + return PAD_W(gpio_num); + case GPIO_SW: + return PAD_SW(gpio_num); + } + + return gpio_num; +} + +static void print_gpi_status(const struct gpi_status *sts) +{ + int i; + int group; + int index = 0; + int bit_set; + int num_groups; + int abs_bit; + const struct pad_community *comm; + + for (i = 0; i < ARRAY_SIZE(gpio_communities); i++) { + comm = &gpio_communities[i]; + num_groups = comm->num_gpi_regs; + index = comm->gpi_offset; + for (group = 0; group < num_groups; group++, index++) { + for (bit_set = 31; bit_set >= 0; bit_set--) { + if (!(sts->grp[index] & (1 << bit_set))) + continue; + + abs_bit = bit_set; + abs_bit += group * GPIO_MAX_NUM_PER_GROUP; + printk(BIOS_DEBUG, "%s %d\n",comm->grp_name, + abs_bit); + } + } + } +} + +void gpi_clear_get_smi_status(struct gpi_status *sts) +{ + int i; + int group; + int index = 0; + uint32_t sts_value; + uint32_t en_value; + int num_groups; + const struct pad_community *comm; + + for (i = 0; i < ARRAY_SIZE(gpio_communities); i++) { + comm = &gpio_communities[i]; + num_groups = comm->num_gpi_regs; + index = comm->gpi_offset; + for (group = 0; group < num_groups; group++, index++) { + sts_value = iosf_read(gpio_communities[i].port, + GPI_SMI_STS_OFFSET(group)); + en_value = iosf_read(gpio_communities[i].port, + GPI_SMI_EN_OFFSET(group)); + sts->grp[index] = sts_value & en_value; + /* Clear the set status bits. */ + iosf_write(gpio_communities[i].port, + GPI_SMI_STS_OFFSET(group), sts->grp[index]); + } + } + + if (IS_ENABLED(CONFIG_DEBUG_SMI)) + print_gpi_status(sts); + +} + +int gpi_status_get(const struct gpi_status *sts, gpio_t gpi) +{ + uint8_t sts_index; + const struct pad_community *comm = gpio_get_community(gpi); + + /* Check if valid gpi */ + if (comm == NULL) + return 0; + + sts_index = comm->gpi_offset + ((gpi - comm->first_pad) / + GPIO_MAX_NUM_PER_GROUP); + + return !!(sts->grp[sts_index] & (1 << (gpi % GPIO_MAX_NUM_PER_GROUP))); +} + +/* Helper function to map PMC register groups to tier1 sci groups */ +static int pmc_gpe_route_to_gpio(int route) +{ + switch(route) { + case PMC_GPE_SW_31_0: + return GPIO_GPE_SW_31_0; + case PMC_GPE_SW_63_32: + return GPIO_GPE_SW_63_32; + case PMC_GPE_NW_31_0: + return GPIO_GPE_NW_31_0; + case PMC_GPE_NW_63_32: + return GPIO_GPE_NW_63_32; + case PMC_GPE_NW_95_64: + return GPIO_GPE_NW_95_64; + case PMC_GPE_N_31_0: + return GPIO_GPE_N_31_0; + case PMC_GPE_N_63_32: + return GPIO_GPE_N_63_32; + case PMC_GPE_W_31_0: + return GPIO_GPE_W_31_0; + default: + return -1; + } +} + +void gpio_route_gpe(uint8_t gpe0b, uint8_t gpe0c, uint8_t gpe0d) +{ + int i; + uint32_t misccfg_mask; + uint32_t misccfg_value; + uint32_t value; + int ret; + + /* Get the group here for community specific MISCCFG register. + * If any of these returns -1 then there is some error in devicetree + * where the group is probably hardcoded and does not comply with the + * PMC group defines. So we return from here and MISCFG is set to + * default. + */ + ret = pmc_gpe_route_to_gpio(gpe0b); + if (ret == -1) + return; + gpe0b = ret; + + ret = pmc_gpe_route_to_gpio(gpe0c); + if (ret == -1) + return; + gpe0c = ret; + + ret = pmc_gpe_route_to_gpio(gpe0d); + if (ret == -1) + return; + gpe0d = ret; + + misccfg_value = gpe0b << MISCCFG_GPE0_DW0_SHIFT; + misccfg_value |= gpe0c << MISCCFG_GPE0_DW1_SHIFT; + misccfg_value |= gpe0d << MISCCFG_GPE0_DW2_SHIFT; + + /* Program GPIO_MISCCFG */ + misccfg_mask = ~(MISCCFG_GPE0_DW2_MASK | + MISCCFG_GPE0_DW1_MASK | + MISCCFG_GPE0_DW0_MASK); + + for (i = 0; i < ARRAY_SIZE(gpio_communities); i++) { + const struct pad_community *comm = &gpio_communities[i]; + + value = iosf_read(comm->port, GPIO_MISCCFG); + value &= misccfg_mask; + value |= misccfg_value; + iosf_write(comm->port, GPIO_MISCCFG, value); + } +} diff --git a/src/soc/intel/glk/graphics.c b/src/soc/intel/glk/graphics.c new file mode 100644 index 0000000..9b4dbc9 --- /dev/null +++ b/src/soc/intel/glk/graphics.c @@ -0,0 +1,103 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015-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. + */ + +#include <arch/acpi.h> +#include <arch/acpigen.h> +#include <console/console.h> +#include <fsp/util.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <soc/pci_devs.h> +#include <soc/pci_ids.h> +#include <soc/intel/common/opregion.h> + +uintptr_t fsp_soc_get_igd_bar(void) +{ + return find_resource(IGD_DEV, PCI_BASE_ADDRESS_2)->base; +} + +static void igd_set_resources(struct device *dev) +{ + pci_dev_set_resources(dev); +} + +static unsigned long igd_write_opregion(device_t dev, unsigned long current, + struct acpi_rsdp *rsdp) +{ + igd_opregion_t *opregion; + uint16_t reg16; + + printk(BIOS_DEBUG, "ACPI: * IGD OpRegion\n"); + opregion = (igd_opregion_t *)current; + + if (!init_igd_opregion(opregion)) + return current; + + current += sizeof(igd_opregion_t); + + /* TODO Initialize Mailbox 3 */ + opregion->mailbox3.bclp = IGD_BACKLIGHT_BRIGHTNESS; + opregion->mailbox3.pfit = IGD_FIELD_VALID | IGD_PFIT_STRETCH; + opregion->mailbox3.pcft = 0; /* should be (IMON << 1) & 0x3e */ + opregion->mailbox3.cblv = IGD_FIELD_VALID | IGD_INITIAL_BRIGHTNESS; + opregion->mailbox3.bclm[0] = IGD_WORD_FIELD_VALID + 0x0000; + opregion->mailbox3.bclm[1] = IGD_WORD_FIELD_VALID + 0x0a19; + opregion->mailbox3.bclm[2] = IGD_WORD_FIELD_VALID + 0x1433; + opregion->mailbox3.bclm[3] = IGD_WORD_FIELD_VALID + 0x1e4c; + opregion->mailbox3.bclm[4] = IGD_WORD_FIELD_VALID + 0x2866; + opregion->mailbox3.bclm[5] = IGD_WORD_FIELD_VALID + 0x327f; + opregion->mailbox3.bclm[6] = IGD_WORD_FIELD_VALID + 0x3c99; + opregion->mailbox3.bclm[7] = IGD_WORD_FIELD_VALID + 0x46b2; + opregion->mailbox3.bclm[8] = IGD_WORD_FIELD_VALID + 0x50cc; + opregion->mailbox3.bclm[9] = IGD_WORD_FIELD_VALID + 0x5ae5; + opregion->mailbox3.bclm[10] = IGD_WORD_FIELD_VALID + 0x64ff; + + /* + * TODO This needs to happen in S3 resume, too. + * Maybe it should move to the finalize handler. + */ + + pci_write_config32(dev, ASLS, (uintptr_t)opregion); + reg16 = pci_read_config16(dev, SWSCI); + reg16 &= ~(1 << 0); + reg16 |= (1 << 15); + pci_write_config16(dev, SWSCI, reg16); + + return acpi_align_current(current); +} + +static const struct device_operations igd_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = igd_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = pci_dev_init, + .write_acpi_tables = igd_write_opregion, + .enable = DEVICE_NOOP +}; + +static const unsigned short pci_device_ids[] = { + PCI_DEVICE_ID_APOLLOLAKE_IGD_HD_505, + PCI_DEVICE_ID_APOLLOLAKE_IGD_HD_500, + 0, +}; + +static const struct pci_driver integrated_graphics_driver __pci_driver = { + .ops = &igd_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .devices= pci_device_ids, +}; diff --git a/src/soc/intel/glk/heci.c b/src/soc/intel/glk/heci.c new file mode 100644 index 0000000..4685895 --- /dev/null +++ b/src/soc/intel/glk/heci.c @@ -0,0 +1,36 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2016 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_def.h> +#include <device/pci_ops.h> +#include <soc/heci.h> +#include <soc/pci_devs.h> + +uint32_t heci_fw_sts(void) +{ + return pci_read_config32(CSE_DEV, REG_SEC_FW_STS0); +} + +bool heci_cse_normal(void) +{ + return ((heci_fw_sts() & MASK_SEC_STATUS) == SEC_STATE_NORMAL); +} + +bool heci_cse_done(void) +{ + return (!!(heci_fw_sts() & MASK_SEC_FIRMWARE_COMPLETE)); +} diff --git a/src/soc/intel/glk/i2c.c b/src/soc/intel/glk/i2c.c new file mode 100644 index 0000000..4080987 --- /dev/null +++ b/src/soc/intel/glk/i2c.c @@ -0,0 +1,126 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2016 Google Inc. + * + * 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 <arch/acpi_device.h> +#include <arch/acpigen.h> +#include <device/device.h> +#include <device/i2c.h> +#include <device/pci.h> +#include <device/pci_def.h> +#include <device/pci_ids.h> +#include <soc/i2c.h> +#include <soc/intel/common/lpss_i2c.h> +#include <soc/pci_devs.h> +#include <soc/pci_ids.h> +#include "chip.h" + +uintptr_t lpss_i2c_base_address(unsigned bus) +{ + unsigned devfn; + struct device *dev; + struct resource *res; + + /* bus -> devfn */ + devfn = i2c_bus_to_devfn(bus); + if (devfn >= 0) { + /* devfn -> dev */ + dev = dev_find_slot(0, devfn); + if (dev) { + /* dev -> bar0 */ + res = find_resource(dev, PCI_BASE_ADDRESS_0); + if (res) + return res->base; + } + } + + return (uintptr_t)NULL; +} + +static int i2c_dev_to_bus(struct device *dev) +{ + return i2c_devfn_to_bus(dev->path.pci.devfn); +} + +/* + * The device should already be enabled and out of reset, + * either from early init in coreboot or FSP-S. + */ +static void i2c_dev_init(struct device *dev) +{ + struct soc_intel_glk_config *config = dev->chip_info; + const struct lpss_i2c_speed_config *sptr; + enum i2c_speed speed; + int i, bus = i2c_dev_to_bus(dev); + + if (!config || bus < 0) + return; + + speed = config->i2c[bus].speed ? : I2C_SPEED_FAST; + lpss_i2c_init(bus, speed); + + /* Apply custom speed config if it has been set by the board */ + for (i = 0; i < LPSS_I2C_SPEED_CONFIG_COUNT; i++) { + sptr = &config->i2c[bus].speed_config[i]; + if (sptr->speed == speed) { + lpss_i2c_set_speed_config(bus, sptr); + break; + } + } +} + +static void i2c_fill_ssdt(struct device *dev) +{ + struct soc_intel_glk_config *config = dev->chip_info; + int bus = i2c_dev_to_bus(dev); + + if (!config || bus < 0) + return; + + acpigen_write_scope(acpi_device_path(dev)); + lpss_i2c_acpi_fill_ssdt(config->i2c[bus].speed_config); + acpigen_pop_len(); +} + +static struct i2c_bus_operations i2c_bus_ops = { + .dev_to_bus = &i2c_dev_to_bus, +}; + +static struct device_operations i2c_dev_ops = { + .read_resources = &pci_dev_read_resources, + .set_resources = &pci_dev_set_resources, + .enable_resources = &pci_dev_enable_resources, + .scan_bus = &scan_smbus, + .ops_i2c_bus = &i2c_bus_ops, + .init = &i2c_dev_init, + .acpi_fill_ssdt_generator = &i2c_fill_ssdt, +}; + +static const unsigned short pci_device_ids[] = { + PCI_DEVICE_ID_APOLLOLAKE_I2C0, + PCI_DEVICE_ID_APOLLOLAKE_I2C1, + PCI_DEVICE_ID_APOLLOLAKE_I2C2, + PCI_DEVICE_ID_APOLLOLAKE_I2C3, + PCI_DEVICE_ID_APOLLOLAKE_I2C4, + PCI_DEVICE_ID_APOLLOLAKE_I2C5, + PCI_DEVICE_ID_APOLLOLAKE_I2C6, + PCI_DEVICE_ID_APOLLOLAKE_I2C7, + 0, +}; + +static const struct pci_driver pch_i2c __pci_driver = { + .ops = &i2c_dev_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .devices = pci_device_ids, +}; diff --git a/src/soc/intel/glk/i2c_early.c b/src/soc/intel/glk/i2c_early.c new file mode 100644 index 0000000..dbd10e5 --- /dev/null +++ b/src/soc/intel/glk/i2c_early.c @@ -0,0 +1,116 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2016 Google Inc. + * + * 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 <arch/io.h> +#include <commonlib/helpers.h> +#include <console/console.h> +#include <device/device.h> +#include <device/i2c.h> +#include <device/pci_def.h> +#include <soc/intel/common/lpss_i2c.h> +#include <soc/i2c.h> +#include <soc/iomap.h> +#include <soc/pci_devs.h> +#include "chip.h" + +static int i2c_early_init_bus(unsigned bus) +{ + ROMSTAGE_CONST struct soc_intel_glk_config *config; + ROMSTAGE_CONST struct device *tree_dev; + const struct lpss_i2c_speed_config *sptr; + enum i2c_speed speed; + pci_devfn_t dev; + unsigned devfn; + uintptr_t base; + uint32_t value; + void *reg; + + /* Find the PCI device for this bus controller */ + devfn = i2c_bus_to_devfn(bus); + if (devfn < 0) { + printk(BIOS_ERR, "I2C%u device not found\n", bus); + return -1; + } + + /* Look up the controller device in the devicetree */ + dev = PCI_DEV(0, PCI_SLOT(devfn), PCI_FUNC(devfn)); + tree_dev = dev_find_slot(0, devfn); + if (!tree_dev || !tree_dev->enabled) { + printk(BIOS_ERR, "I2C%u device not enabled\n", bus); + return -1; + } + + /* Skip if not enabled for early init */ + config = tree_dev->chip_info; + if (!config || !config->i2c[bus].early_init) { + printk(BIOS_ERR, "I2C%u not enabled for early init\n", bus); + return -1; + } + + /* Prepare early base address for access before memory */ + base = PRERAM_I2C_BASE_ADDRESS(bus); + pci_write_config32(dev, PCI_BASE_ADDRESS_0, base); + pci_write_config32(dev, PCI_COMMAND, + PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + + /* Take device out of reset */ + reg = (void *)(base + I2C_LPSS_REG_RESET); + value = read32(reg); + value |= I2C_LPSS_RESET_RELEASE_HC; + write32(reg, value); + + /* Initialize the controller */ + speed = config->i2c[bus].speed ? : I2C_SPEED_FAST; + if (lpss_i2c_init(bus, speed) < 0) { + printk(BIOS_ERR, "I2C%u failed to initialize\n", bus); + return -1; + } + + /* Apply custom speed config if it has been set by the board */ + for (value = 0; value < LPSS_I2C_SPEED_CONFIG_COUNT; value++) { + sptr = &config->i2c[bus].speed_config[value]; + if (sptr->speed == speed) { + lpss_i2c_set_speed_config(bus, sptr); + break; + } + } + + return 0; +} + +uintptr_t lpss_i2c_base_address(unsigned bus) +{ + unsigned devfn; + pci_devfn_t dev; + uintptr_t base; + + /* Find device+function for this controller */ + devfn = i2c_bus_to_devfn(bus); + if (devfn < 0) + return (uintptr_t)NULL; + + /* Form a PCI address for this device */ + dev = PCI_DEV(0, PCI_SLOT(devfn), PCI_FUNC(devfn)); + + /* Read the first base address for this device */ + base = ALIGN_DOWN(pci_read_config32(dev, PCI_BASE_ADDRESS_0), 16); + + /* Attempt to initialize bus if base is not set yet */ + if (!base && !i2c_early_init_bus(bus)) + base = ALIGN_DOWN(pci_read_config32(dev, PCI_BASE_ADDRESS_0), + 16); + + return base; +} diff --git a/src/soc/intel/glk/include/FspUpd.h b/src/soc/intel/glk/include/FspUpd.h new file mode 100644 index 0000000..a7114ce --- /dev/null +++ b/src/soc/intel/glk/include/FspUpd.h @@ -0,0 +1,48 @@ +/** @file + +Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. +* Neither the name of Intel Corporation nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + THE POSSIBILITY OF SUCH DAMAGE. + + This file is automatically generated. Please do NOT modify !!! + +**/ + +#ifndef __FSPUPD_H__ +#define __FSPUPD_H__ + +#include <FspEas.h> + +#pragma pack(push, 1) + +#define FSPT_UPD_SIGNATURE 0x545F4450554C5041 /* 'APLUPD_T' */ + +#define FSPM_UPD_SIGNATURE 0x4D5F4450554C5041 /* 'APLUPD_M' */ + +#define FSPS_UPD_SIGNATURE 0x535F4450554C5041 /* 'APLUPD_S' */ + +#pragma pack(pop) + +#endif diff --git a/src/soc/intel/glk/include/soc/acpi.h b/src/soc/intel/glk/include/soc/acpi.h new file mode 100644 index 0000000..3cbb380 --- /dev/null +++ b/src/soc/intel/glk/include/soc/acpi.h @@ -0,0 +1,28 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2016 Intel Corp. + * (Written by Lance Zhao lijian.zhao@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_GLK_ACPI_H_ +#define _SOC_GLK_ACPI_H_ + +#include <arch/acpi.h> + +unsigned long southbridge_write_acpi_tables(device_t device, + unsigned long current, struct acpi_rsdp *rsdp); + +void southbridge_inject_dsdt(device_t device); + +#endif /* _SOC_GLK_ACPI_H_ */ diff --git a/src/soc/intel/glk/include/soc/cpu.h b/src/soc/intel/glk/include/soc/cpu.h new file mode 100644 index 0000000..f0a827e --- /dev/null +++ b/src/soc/intel/glk/include/soc/cpu.h @@ -0,0 +1,63 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 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_GLK_CPU_H_ +#define _SOC_GLK_CPU_H_ + +#ifndef __ASSEMBLER__ +#include <cpu/x86/msr.h> +#include <device/device.h> + +void glk_init_cpus(struct device *dev); +#endif + +#define CPUID_GLK_A0 0x706a0 + +#define MSR_PLATFORM_INFO 0xce +#define MSR_POWER_MISC 0x120 +#define MSR_CORE_THREAD_COUNT 0x35 +#define MSR_EVICT_CTL 0x2e0 +#define MSR_EMULATE_PM_TMR 0x121 +#define EMULATE_PM_TMR_EN (1 << 16) +#define MSR_PREFETCH_CTL 0x1a4 +#define PREFETCH_L1_DISABLE (1 << 0) +#define PREFETCH_L2_DISABLE (1 << 2) + +#define MSR_PKG_POWER_SKU_UNIT 0x606 + +#define MSR_L2_QOS_MASK(reg) (0xd10 + reg) +#define MSR_IA32_PQR_ASSOC 0xc8f +/* MSR bits 33:32 encode slot number 0-3 */ +#define IA32_PQR_ASSOC_MASK (1 << 0 | 1 << 1) +/* 16 way cache, 8 bits per QOS, 64 byte cache line, 1024 sets */ +#define CACHE_WAYS 16 +#define CACHE_BITS_PER_MASK 8 +#define CACHE_LINE_SIZE 64 +#define CACHE_SETS 1024 +/* + * Each bit in QOS mask controls this many bytes. This is calculated as: + * (CACHE_WAYS / CACHE_BITS_PER_MASK) * CACHE_LINE_SIZE * CACHE_SETS + */ +#define CACHE_QOS_SIZE_PER_BIT (128 * KiB) +#define L2_CACHE_SIZE 0x100000 + +#define BASE_CLOCK_MHZ 100 + +/* Common Timer Copy (CTC) frequency - 19.2MHz. */ +#define CTC_FREQ 19200000 + +#endif /* _SOC_GLK_CPU_H_ */ diff --git a/src/soc/intel/glk/include/soc/gpe.h b/src/soc/intel/glk/include/soc/gpe.h new file mode 100644 index 0000000..5482ed3 --- /dev/null +++ b/src/soc/intel/glk/include/soc/gpe.h @@ -0,0 +1,139 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2016 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_GPE_H_ +#define _SOC_GPE_H_ + +/* bit position in GPE0a_STS register */ +#define GPE0A_PCIE_SCI_STS 0 +#define GPE0A_SWGPE_STS 2 +#define GPE0A_PCIE_WAKE0_STS 3 +#define GPE0A_PUNIT_SCI_STS 4 +#define GPE0A_PCIE_WAKE1_STS 6 +#define GPE0A_PCIE_WAKE2_STS 7 +#define GPE0A_PCIE_WAKE3_STS 8 +#define GPE0A_PCIE_GPE_STS 9 +#define GPE0A_BATLOW_STS 10 +#define GPE0A_CSE_PME_STS 11 +#define GPE0A_XDCI_PME_STS 12 +#define GPE0A_XHCI_PME_STS 13 +#define GPE0A_AVS_PME_STS 14 +#define GPE0A_GPIO_TIER1_SCI_STS 15 +#define GPE0A_SMB_WAK_STS 16 +#define GPE0A_SATA_PME_STS 17 + +/* Group DW0 is reserved in Apollolake */ + +/* GPE_63_32 */ +#define GPE0_DW1_00 32 +#define GPE0_DW1_01 33 +#define GPE0_DW1_02 34 +#define GPE0_DW1_03 36 +#define GPE0_DW1_04 36 +#define GPE0_DW1_05 37 +#define GPE0_DW1_06 38 +#define GPE0_DW1_07 39 +#define GPE0_DW1_08 40 +#define GPE0_DW1_09 41 +#define GPE0_DW1_10 42 +#define GPE0_DW1_11 43 +#define GPE0_DW1_12 44 +#define GPE0_DW1_13 45 +#define GPE0_DW1_14 46 +#define GPE0_DW1_15 47 +#define GPE0_DW1_16 48 +#define GPE0_DW1_17 49 +#define GPE0_DW1_18 50 +#define GPE0_DW1_19 51 +#define GPE0_DW1_20 52 +#define GPE0_DW1_21 53 +#define GPE0_DW1_22 54 +#define GPE0_DW1_23 55 +#define GPE0_DW1_24 56 +#define GPE0_DW1_25 57 +#define GPE0_DW1_26 58 +#define GPE0_DW1_27 59 +#define GPE0_DW1_28 60 +#define GPE0_DW1_29 61 +#define GPE0_DW1_30 62 +#define GPE0_DW1_31 63 +/* GPE_95_64 */ +#define GPE0_DW2_00 64 +#define GPE0_DW2_01 65 +#define GPE0_DW2_02 66 +#define GPE0_DW2_03 67 +#define GPE0_DW2_04 68 +#define GPE0_DW2_05 69 +#define GPE0_DW2_06 70 +#define GPE0_DW2_07 71 +#define GPE0_DW2_08 72 +#define GPE0_DW2_09 73 +#define GPE0_DW2_10 74 +#define GPE0_DW2_11 75 +#define GPE0_DW2_12 76 +#define GPE0_DW2_13 77 +#define GPE0_DW2_14 78 +#define GPE0_DW2_15 79 +#define GPE0_DW2_16 80 +#define GPE0_DW2_17 81 +#define GPE0_DW2_18 82 +#define GPE0_DW2_19 83 +#define GPE0_DW2_20 84 +#define GPE0_DW2_21 85 +#define GPE0_DW2_22 86 +#define GPE0_DW2_23 87 +#define GPE0_DW2_24 88 +#define GPE0_DW2_25 89 +#define GPE0_DW2_26 90 +#define GPE0_DW2_27 91 +#define GPE0_DW2_28 92 +#define GPE0_DW2_29 93 +#define GPE0_DW2_30 94 +#define GPE0_DW2_31 95 +/* GPE_127_96 */ +#define GPE0_DW3_00 96 +#define GPE0_DW3_01 97 +#define GPE0_DW3_02 98 +#define GPE0_DW3_03 99 +#define GPE0_DW3_04 100 +#define GPE0_DW3_05 101 +#define GPE0_DW3_06 102 +#define GPE0_DW3_07 103 +#define GPE0_DW3_08 104 +#define GPE0_DW3_09 105 +#define GPE0_DW3_10 106 +#define GPE0_DW3_11 107 +#define GPE0_DW3_12 108 +#define GPE0_DW3_13 109 +#define GPE0_DW3_14 110 +#define GPE0_DW3_15 111 +#define GPE0_DW3_16 112 +#define GPE0_DW3_17 113 +#define GPE0_DW3_18 114 +#define GPE0_DW3_19 115 +#define GPE0_DW3_20 116 +#define GPE0_DW3_21 117 +#define GPE0_DW3_22 118 +#define GPE0_DW3_23 119 +#define GPE0_DW3_24 120 +#define GPE0_DW3_25 121 +#define GPE0_DW3_26 122 +#define GPE0_DW3_27 123 +#define GPE0_DW3_28 124 +#define GPE0_DW3_29 125 +#define GPE0_DW3_30 126 +#define GPE0_DW3_31 127 + +#endif diff --git a/src/soc/intel/glk/include/soc/gpio.h b/src/soc/intel/glk/include/soc/gpio.h new file mode 100644 index 0000000..9495a0f --- /dev/null +++ b/src/soc/intel/glk/include/soc/gpio.h @@ -0,0 +1,177 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 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_GLK_GPIO_H_ +#define _SOC_GLK_GPIO_H_ + +#include <soc/gpio_defs.h> +/* __ACPI__ guard is needed to ignore below code in ACPI/ASL compilation */ +#ifndef __ACPI__ +#include <types.h> + +typedef uint32_t gpio_t; + +/* + * Structure to represent GPI status for GPE and SMI. Use helper + * functions for interrogating particular GPIs. Here the number of + * array elements is total number of groups that can be present in all + * the communities. + */ +struct gpi_status { + uint32_t grp[NUM_GPI_STATUS_REGS]; +}; + +/* + * Clear GPI SMI status and fill in the structure representing enabled + * and set status. + */ +void gpi_clear_get_smi_status(struct gpi_status *sts); + +/* Return 1 if gpio is set in the gpi_status struct. Otherwise 0. */ +int gpi_status_get(const struct gpi_status *sts, gpio_t gpi); + +#define PAD_FUNC(value) PAD_CFG0_MODE_##value +#define PAD_RESET(value) PAD_CFG0_RESET_##value +#define PAD_PULL(value) PAD_CFG1_PULL_##value +#define PAD_IOSSTATE(value) PAD_CFG1_IOSSTATE_##value +#define PAD_IRQ_CFG(route, trig, inv) \ + (PAD_CFG0_ROUTE_##route | \ + PAD_CFG0_TRIG_##trig | \ + (PAD_CFG0_RX_POL_##inv)) + +#define _PAD_CFG_STRUCT(__pad, __config0, __config1) \ + { \ + .pad = __pad, \ + .config0 = __config0, \ + .config1 = __config1, \ + } + +/* Native function configuration */ +#define PAD_CFG_NF(pad, pull, rst, func) \ + _PAD_CFG_STRUCT(pad, PAD_RESET(rst) | PAD_FUNC(func), PAD_PULL(pull) | \ + PAD_IOSSTATE(TxLASTRxE)) + +/* Native function configuration for standby state */ +#define PAD_CFG_NF_IOSSTATE(pad, pull, rst, func, iosstate) \ + _PAD_CFG_STRUCT(pad, PAD_RESET(rst) | PAD_FUNC(func), PAD_PULL(pull) | \ + PAD_IOSSTATE(iosstate)) + +/* General purpose output, no pullup/down. */ +#define PAD_CFG_GPO(pad, val, rst) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_RX_DISABLE | !!val, \ + PAD_PULL(NONE) | PAD_IOSSTATE(TxLASTRxE)) + +/* General purpose input */ +#define PAD_CFG_GPI(pad, pull, rst) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE, \ + PAD_PULL(pull) | PAD_IOSSTATE(TxLASTRxE)) + +/* General purpose input. The following macro sets the + * Host Software Pad Ownership to GPIO Driver mode. + */ +#define PAD_CFG_GPI_GPIO_DRIVER(pad, pull, rst) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE, \ + PAD_PULL(pull) | PAD_CFG1_GPIO_DRIVER | PAD_IOSSTATE(TxLASTRxE)) + +/* No Connect configuration for unused pad. + * NC should be GPI with Term as PU20K, PD20K, NONE depending upon default Term + */ +#define PAD_NC(pad, pull) PAD_CFG_GPI(pad, pull, DEEP) + +/* General purpose input, routed to APIC */ +#define PAD_CFG_GPI_APIC(pad, pull, rst, trig, inv) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \ + PAD_IRQ_CFG(IOAPIC, trig, inv), PAD_PULL(pull) | \ + PAD_IOSSTATE(TxLASTRxE)) + +/* + * The following APIC macros assume the APIC will handle the filtering + * on its own end. One just needs to pass an active high message into the + * ITSS. + */ +#define PAD_CFG_GPI_APIC_LOW(pad, pull, rst) \ + PAD_CFG_GPI_APIC(pad, pull, rst, LEVEL, INVERT) + +#define PAD_CFG_GPI_APIC_HIGH(pad, pull, rst) \ + PAD_CFG_GPI_APIC(pad, pull, rst, LEVEL, NONE) + +/* General purpose input, routed to SMI */ +#define PAD_CFG_GPI_SMI(pad, pull, rst, trig, inv) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \ + PAD_IRQ_CFG(SMI, trig, inv), PAD_PULL(pull) | \ + PAD_IOSSTATE(TxLASTRxE)) + +#define PAD_CFG_GPI_SMI_LOW(pad, pull, rst, trig) \ + PAD_CFG_GPI_SMI(pad, pull, rst, trig, INVERT) + +#define PAD_CFG_GPI_SMI_HIGH(pad, pull, rst, trig) \ + PAD_CFG_GPI_SMI(pad, pull, rst, trig, NONE) + +/* General purpose input, routed to SCI */ +#define PAD_CFG_GPI_SCI(pad, pull, rst, trig, inv) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \ + PAD_IRQ_CFG(SCI, trig, inv), PAD_PULL(pull) | \ + PAD_IOSSTATE(TxLASTRxE)) + +#define PAD_CFG_GPI_SCI_LOW(pad, pull, rst, trig) \ + PAD_CFG_GPI_SCI(pad, pull, rst, trig, INVERT) + +#define PAD_CFG_GPI_SCI_HIGH(pad, pull, rst, trig) \ + PAD_CFG_GPI_SCI(pad, pull, rst, trig, NONE) + +/* General purpose input, routed to NMI */ +#define PAD_CFG_GPI_NMI(pad, pull, rst, trig, inv) \ + _PAD_CFG_STRUCT(pad, \ + PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \ + PAD_IRQ_CFG(NMI, trig, inv), PAD_PULL(pull) | \ + PAD_IOSSTATE(TxLASTRxE)) + +struct pad_config { + uint32_t config0; + uint16_t config1; + uint16_t pad; +}; + +/* + * Configuration for raw pads. Some pads are designated as only special function + * pins, and don't have an associated GPIO number, so we need to expose the raw + * pad configuration functionality. + */ +void gpio_configure_pad(const struct pad_config *cfg); +void gpio_configure_pads(const struct pad_config *cfg, size_t num_pads); + +/* Calculate GPIO DW0 address */ +void * gpio_dwx_address(const uint16_t pad); +/* + * Set the GPIO groups for the GPE blocks. The values from PMC register GPE_CFG + * are passed which is then mapped to proper groups for MISCCFG. This basically + * sets the MISCCFG register bits: + * dw0 = gpe0_route[11:8]. This is ACPI GPE0b. + * dw1 = gpe0_route[15:12]. This is ACPI GPE0c. + * dw2 = gpe0_route[19:16]. This is ACPI GPE0d. + */ +void gpio_route_gpe(uint8_t gpe0b, uint8_t gpe0c, uint8_t gpe0d); + +#endif /* __ACPI__ */ + +#endif /* _SOC_GLK_GPIO_H_ */ diff --git a/src/soc/intel/glk/include/soc/gpio_defs.h b/src/soc/intel/glk/include/soc/gpio_defs.h new file mode 100644 index 0000000..b46957c --- /dev/null +++ b/src/soc/intel/glk/include/soc/gpio_defs.h @@ -0,0 +1,559 @@ +/* + * Definitions for the GPIO subsystem on Apollolake + * + * Placed in a separate file since some of these definitions can be used from + * assembly code + * + * This file is part of the coreboot project. + * + * Copyright (C) 2015 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_GLK_GPIO_DEFS_H_ +#define _SOC_GLK_GPIO_DEFS_H_ + +/* + * Miscellaneous Configuration register(MISCCFG).These are community specific + * registers and are meant to house miscellaneous configuration fields per + * community. There are 8 GPIO groups: GPP_0 -> GPP_8 (Group 3 is absent) + */ +#define GPIO_MISCCFG 0x10 /* Miscellaneous Configuration offset */ +#define GPIO_GPE_SW_31_0 0 /* SOUTHWEST GPIO# 0 ~ 31 belong to GROUP0 */ +#define GPIO_GPE_SW_63_32 1 /* SOUTHWEST GPIO# 32 ~ 42 belong to GROUP1 */ +#define GPIO_GPE_W_31_0 2 /* WEST GPIO# 0 ~ 25 belong to GROUP2 */ +#define GPIO_GPE_NW_31_0 4 /* NORTHWEST GPIO# 0 ~ 17 belong to GROUP4 */ +#define GPIO_GPE_NW_63_32 5 /* NORTHWEST GPIO# 32 ~ 63 belong to GROUP5 */ +#define GPIO_GPE_NW_95_64 6 /* NORTHWEST GPIO# 64 ~ 76 belong to GROUP6 */ +#define GPIO_GPE_N_31_0 7 /* NORTH GPIO# 0 ~ 31 belong to GROUP7 */ +#define GPIO_GPE_N_63_32 8 /* NORTH GPIO# 32 ~ 61 belong to GROUP8 */ + +#define GPIO_MAX_NUM_PER_GROUP 32 + +#define MISCCFG_GPE0_DW0_SHIFT 8 +#define MISCCFG_GPE0_DW0_MASK (0xf << MISCCFG_GPE0_DW0_SHIFT) +#define MISCCFG_GPE0_DW1_SHIFT 12 +#define MISCCFG_GPE0_DW1_MASK (0xf << MISCCFG_GPE0_DW1_SHIFT) +#define MISCCFG_GPE0_DW2_SHIFT 16 +#define MISCCFG_GPE0_DW2_MASK (0xf << MISCCFG_GPE0_DW2_SHIFT) + +/* Host Software Pad Ownership Register. + * The pins in the community are divided into 3 groups : + * GPIO 0 ~ 31, GPIO 32 ~ 63, GPIO 64 ~ 95 + */ +#define HOSTSW_OWN_REG_BASE 0x80 + +#define PAD_CFG0_TX_STATE (1 << 0) +#define PAD_CFG0_RX_STATE (1 << 1) +#define PAD_CFG0_TX_DISABLE (1 << 8) +#define PAD_CFG0_RX_DISABLE (1 << 9) +#define PAD_CFG0_MODE_MASK (7 << 10) +#define PAD_CFG0_MODE_GPIO (0 << 10) +#define PAD_CFG0_MODE_FUNC(x) ((x) << 10) +#define PAD_CFG0_MODE_NF1 (1 << 10) +#define PAD_CFG0_MODE_NF2 (2 << 10) +#define PAD_CFG0_MODE_NF3 (3 << 10) +#define PAD_CFG0_MODE_NF4 (4 << 10) +#define PAD_CFG0_MODE_NF5 (5 << 10) +#define PAD_CFG0_ROUTE_NMI (1 << 17) +#define PAD_CFG0_ROUTE_SMI (1 << 18) +#define PAD_CFG0_ROUTE_SCI (1 << 19) +#define PAD_CFG0_ROUTE_IOAPIC (1 << 20) +#define PAD_CFG0_RX_POL_INVERT (1 << 23) +#define PAD_CFG0_RX_POL_NONE (0 << 23) + +#define PAD_CFG0_TRIG_MASK (3 << 25) +#define PAD_CFG0_TRIG_LEVEL (0 << 25) +#define PAD_CFG0_TRIG_EDGE_SINGLE (1 << 25) /* controlled by RX_INVERT*/ +#define PAD_CFG0_TRIG_OFF (2 << 25) +#define PAD_CFG0_TRIG_EDGE_BOTH (3 << 25) +#define PAD_CFG0_RESET_MASK (3 << 30) +#define PAD_CFG0_RESET_PWROK (0 << 30) +#define PAD_CFG0_RESET_DEEP (1 << 30) +#define PAD_CFG0_RESET_PLTRST (2 << 30) +#define PAD_CFG0_RESET_RSMRST (3 << 30) + +/* Use the fourth bit in IntSel field to indicate gpio + * ownership. This field is RO and hence not used during + * gpio configuration. + */ +#define PAD_CFG1_GPIO_DRIVER (0x1 << 4) +#define PAD_CFG1_IRQ_MASK (0xff << 0) +#define PAD_CFG1_PULL_MASK (0xf << 10) +#define PAD_CFG1_PULL_NONE (0x0 << 10) +#define PAD_CFG1_PULL_DN_5K (0x2 << 10) +#define PAD_CFG1_PULL_DN_20K (0x4 << 10) +#define PAD_CFG1_PULL_UP_1K (0x9 << 10) +#define PAD_CFG1_PULL_UP_5K (0xa << 10) +#define PAD_CFG1_PULL_UP_2K (0xb << 10) +#define PAD_CFG1_PULL_UP_20K (0xc << 10) +#define PAD_CFG1_PULL_UP_667 (0xd << 10) +#define PAD_CFG1_PULL_NATIVE (0xf << 10) +/* Tx enabled driving last value driven, Rx enabled */ +#define PAD_CFG1_IOSSTATE_TxLASTRxE (0x0 << 0) +/* Tx enabled driving 0, Rx disabled and Rx driving 0 back to its controller + * internally */ +#define PAD_CFG1_IOSSTATE_Tx0RxDCRx0 (0x1 << 0) +/* Tx enabled driving 0, Rx disabled and Rx driving 1 back to its controller + * internally */ +#define PAD_CFG1_IOSSTATE_Tx0RXDCRx1 (0x2 << 0) +/* Tx enabled driving 1, Rx disabled and Rx driving 0 back to its controller + * internally */ +#define PAD_CFG1_IOSSTATE_Tx1RXDCRx0 (0x3 << 0) +/* Tx enabled driving 1, Rx disabled and Rx driving 1 back to its controller + * internally */ +#define PAD_CFG1_IOSSTATE_Tx1RxDCRx1 (0x4 << 0) +/* Tx enabled driving 0, Rx enabled */ +#define PAD_CFG1_IOSSTATE_Tx0RxE (0x5 << 0) +/* Tx enabled driving 1, Rx enabled */ +#define PAD_CFG1_IOSSTATE_Tx1RxE (0x6 << 0) +/* Hi-Z, Rx driving 0 back to its controller internally */ +#define PAD_CFG1_IOSSTATE_HIZCRx0 (0x7 << 0) +/* Hi-Z, Rx driving 1 back to its controller internally */ +#define PAD_CFG1_IOSSTATE_HIZCRx1 (0x8 << 0) +#define PAD_CFG1_IOSSTATE_TxDRxE (0x9 << 0) /* Tx disabled, Rx enabled */ +#define PAD_CFG1_IOSSTATE_IGNORE (0xf << 0) /* Ignore Iostandby */ +#define PAD_CFG1_IOSSTATE_MASK 0xf /* mask to extract Iostandby bits */ +#define PAD_CFG1_IOSSTATE_SHIFT 14 /* set Iostandby bits [17:14] */ + +#define PAD_CFG_BASE 0x500 +#define PAD_CFG_OFFSET(pad) (PAD_CFG_BASE + ((pad) * 8)) + +/* IOSF port numbers for GPIO comminuties*/ +#define GPIO_SW 0xc0 +#define GPIO_S 0xc2 +#define GPIO_NW 0xc4 +#define GPIO_N 0xc5 +#define GPIO_W 0xc7 + +#define GPI_SMI_STS_0 0x140 +#define GPI_SMI_EN_0 0x150 +#define GPI_SMI_STS_OFFSET(group) (GPI_SMI_STS_0 + ((group) * 4)) +#define GPI_SMI_EN_OFFSET(group) (GPI_SMI_EN_0 + ((group) * 4)) + +#define NUM_N_PADS (PAD_N(SVID0_CLK) + 1) +#define NUM_NW_PADS (PAD_NW(GPIO_123) + 1) +#define NUM_W_PADS (PAD_W(SUSPWRDNACK) + 1) +#define NUM_SW_PADS (PAD_SW(LPC_FRAMEB) + 1) + +#define NUM_N_GPI_REGS \ + (ALIGN_UP(NUM_N_PADS, GPIO_MAX_NUM_PER_GROUP) / GPIO_MAX_NUM_PER_GROUP) + +#define NUM_NW_GPI_REGS \ + (ALIGN_UP(NUM_NW_PADS, GPIO_MAX_NUM_PER_GROUP) / GPIO_MAX_NUM_PER_GROUP) + +#define NUM_W_GPI_REGS \ + (ALIGN_UP(NUM_W_PADS, GPIO_MAX_NUM_PER_GROUP) / GPIO_MAX_NUM_PER_GROUP) + +#define NUM_SW_GPI_REGS \ + (ALIGN_UP(NUM_SW_PADS, GPIO_MAX_NUM_PER_GROUP) / GPIO_MAX_NUM_PER_GROUP) + +#define NUM_GPI_STATUS_REGS (NUM_N_GPI_REGS + NUM_NW_GPI_REGS \ + + NUM_W_GPI_REGS + NUM_SW_GPI_REGS) + +/* North community pads */ +#define GPIO_0 0 +#define GPIO_1 1 +#define GPIO_2 2 +#define GPIO_3 3 +#define GPIO_4 4 +#define GPIO_5 5 +#define GPIO_6 6 +#define GPIO_7 7 +#define GPIO_8 8 +#define GPIO_9 9 +#define GPIO_10 10 +#define GPIO_11 11 +#define GPIO_12 12 +#define GPIO_13 13 +#define GPIO_14 14 +#define GPIO_15 15 +#define GPIO_16 16 +#define GPIO_17 17 +#define GPIO_18 18 +#define GPIO_19 19 +#define GPIO_20 20 +#define GPIO_21 21 +#define GPIO_22 22 +#define GPIO_23 23 +#define GPIO_24 24 +#define GPIO_25 25 +#define GPIO_26 26 +#define GPIO_27 27 +#define GPIO_28 28 +#define GPIO_29 29 +#define GPIO_30 30 +#define GPIO_31 31 +#define GPIO_32 32 +#define GPIO_33 33 +#define GPIO_34 34 +#define GPIO_35 35 +#define GPIO_36 36 +#define GPIO_37 37 +#define GPIO_38 38 +#define GPIO_39 39 +#define GPIO_40 40 +#define GPIO_41 41 +#define GPIO_42 42 +#define GPIO_43 43 +#define GPIO_44 44 +#define GPIO_45 45 +#define GPIO_46 46 +#define GPIO_47 47 +#define GPIO_48 48 +#define GPIO_49 49 +#define GPIO_62 50 +#define GPIO_63 51 +#define GPIO_64 52 +#define GPIO_65 53 +#define GPIO_66 54 +#define GPIO_67 55 +#define GPIO_68 56 +#define GPIO_69 57 +#define GPIO_70 58 +#define GPIO_71 59 +#define GPIO_72 60 +#define GPIO_73 61 +#define TCK 62 +#define TRST_B 63 +#define TMS 64 +#define TDI 65 +#define CX_PMODE 66 +#define CX_PREQ_B 67 +#define JTAGX 68 +#define CX_PRDY_B 69 +#define TDO 70 +#define CNV_BRI_DT 71 +#define CNV_BRI_RSP 72 +#define CNV_RGI_DT 73 +#define CNV_RGI_RSP 74 +#define SVID0_ALERT_B 75 +#define SVID0_DATA 76 +#define SVID0_CLK 77 + +/* Northwest community pads */ +#define GPIO_187 78 +#define GPIO_188 79 +#define GPIO_189 80 +#define GPIO_190 81 +#define GPIO_191 82 +#define GPIO_192 83 +#define GPIO_193 84 +#define GPIO_194 85 +#define GPIO_195 86 +#define GPIO_196 87 +#define GPIO_197 88 +#define GPIO_198 89 +#define GPIO_199 90 +#define GPIO_200 91 +#define GPIO_201 92 +#define GPIO_202 93 +#define GPIO_203 94 +#define GPIO_204 95 +#define PMC_SPI_FS0 96 +#define PMC_SPI_FS1 97 +#define PMC_SPI_FS2 98 +#define PMC_SPI_RXD 99 +#define PMC_SPI_TXD 100 +#define PMC_SPI_CLK 101 +#define PMIC_PWRGOOD 102 +#define PMIC_RESET_B 103 +#define GPIO_213 104 +#define GPIO_214 105 +#define GPIO_215 106 +#define PMIC_THERMTRIP_B 107 +#define PMIC_STDBY 108 +#define PROCHOT_B 109 +#define PMIC_I2C_SCL 110 +#define PMIC_I2C_SDA 111 +#define GPIO_74 112 +#define GPIO_75 113 +#define GPIO_76 114 +#define GPIO_77 115 +#define GPIO_78 116 +#define GPIO_79 117 +#define GPIO_80 118 +#define GPIO_81 119 +#define GPIO_82 120 +#define GPIO_83 121 +#define GPIO_84 122 +#define GPIO_85 123 +#define GPIO_86 124 +#define GPIO_87 125 +#define GPIO_88 126 +#define GPIO_89 127 +#define GPIO_90 128 +#define GPIO_91 129 +#define GPIO_92 130 +#define GPIO_97 131 +#define GPIO_98 132 +#define GPIO_99 133 +#define GPIO_100 134 +#define GPIO_101 135 +#define GPIO_102 136 +#define GPIO_103 137 +#define FST_SPI_CLK_FB 138 +#define GPIO_104 139 +#define GPIO_105 140 +#define GPIO_106 141 +#define GPIO_109 142 +#define GPIO_110 143 +#define GPIO_111 144 +#define GPIO_112 145 +#define GPIO_113 146 +#define GPIO_116 147 +#define GPIO_117 148 +#define GPIO_118 149 +#define GPIO_119 150 +#define GPIO_120 151 +#define GPIO_121 152 +#define GPIO_122 153 +#define GPIO_123 154 + +/* West community pads */ +#define GPIO_124 155 +#define GPIO_125 156 +#define GPIO_126 157 +#define GPIO_127 158 +#define GPIO_128 159 +#define GPIO_129 160 +#define GPIO_130 161 +#define GPIO_131 162 +#define GPIO_132 163 +#define GPIO_133 164 +#define GPIO_134 165 +#define GPIO_135 166 +#define GPIO_136 167 +#define GPIO_137 168 +#define GPIO_138 169 +#define GPIO_139 170 +#define GPIO_146 171 +#define GPIO_147 172 +#define GPIO_148 173 +#define GPIO_149 174 +#define GPIO_150 175 +#define GPIO_151 176 +#define GPIO_152 177 +#define GPIO_153 178 +#define GPIO_154 179 +#define GPIO_155 180 +#define GPIO_209 181 +#define GPIO_210 182 +#define GPIO_211 183 +#define GPIO_212 184 +#define OSC_CLK_OUT_0 185 +#define OSC_CLK_OUT_1 186 +#define OSC_CLK_OUT_2 187 +#define OSC_CLK_OUT_3 188 +#define OSC_CLK_OUT_4 189 +#define PMU_AC_PRESENT 190 +#define PMU_BATLOW_B 191 +#define PMU_PLTRST_B 192 +#define PMU_PWRBTN_B 193 +#define PMU_RESETBUTTON_B 194 +#define PMU_SLP_S0_B 195 +#define PMU_SLP_S3_B 196 +#define PMU_SLP_S4_B 197 +#define PMU_SUSCLK 198 +#define PMU_WAKE_B 199 +#define SUS_STAT_B 200 +#define SUSPWRDNACK 201 + +/* Southwest community pads */ +#define GPIO_205 202 +#define GPIO_206 203 +#define GPIO_207 204 +#define GPIO_208 205 +#define GPIO_156 206 +#define GPIO_157 207 +#define GPIO_158 208 +#define GPIO_159 209 +#define GPIO_160 210 +#define GPIO_161 211 +#define GPIO_162 212 +#define GPIO_163 213 +#define GPIO_164 214 +#define GPIO_165 215 +#define GPIO_166 216 +#define GPIO_167 217 +#define GPIO_168 218 +#define GPIO_169 219 +#define GPIO_170 220 +#define GPIO_171 221 +#define GPIO_172 222 +#define GPIO_179 223 +#define GPIO_173 224 +#define GPIO_174 225 +#define GPIO_175 226 +#define GPIO_176 227 +#define GPIO_177 228 +#define GPIO_178 229 +#define GPIO_186 230 +#define GPIO_182 231 +#define GPIO_183 232 +#define SMB_ALERTB 233 +#define SMB_CLK 234 +#define SMB_DATA 235 +#define LPC_ILB_SERIRQ 236 +#define LPC_CLKOUT0 237 +#define LPC_CLKOUT1 238 +#define LPC_AD0 239 +#define LPC_AD1 240 +#define LPC_AD2 241 +#define LPC_AD3 242 +#define LPC_CLKRUNB 243 +#define LPC_FRAMEB 244 + +/* PERST_0 not defined */ +#define GPIO_PRT0_UDEF 0xFF + +#define TOTAL_PADS 245 +#define N_OFFSET GPIO_0 +#define NW_OFFSET GPIO_187 +#define W_OFFSET GPIO_124 +#define SW_OFFSET GPIO_205 + +/* Macros for translating a global pad offset to a local offset */ +#define PAD_N(pad) (pad - N_OFFSET) +#define PAD_NW(pad) (pad - NW_OFFSET) +#define PAD_W(pad) (pad - W_OFFSET) +#define PAD_SW(pad) (pad - SW_OFFSET) + +/* Linux names of the GPIO devices. */ +#define GPIO_COMM_N_NAME "INT3452:00" +#define GPIO_COMM_NW_NAME "INT3452:01" +#define GPIO_COMM_W_NAME "INT3452:02" +#define GPIO_COMM_SW_NAME "INT3452:03" + +/* Default configurations */ +#define PAD_CFG0_DEFAULT_FUNC(x) (PAD_CFG0_RESET_DEEP | PAD_CFG0_MODE_FUNC(x)) +#define PAD_CFG0_DEFAULT_NATIVE PAD_CFG0_DEFAULT_FUNC(1) + +#define PAD_CFG1_DEFAULT_PULLUP PAD_CFG1_PULL_UP_20K +#define PAD_CFG1_DEFAULT_NATIVE PAD_CFG1_PULL_NATIVE + +/* + * IOxAPIC IRQs for the GPIOs, overlap is expected as we encourage to use + * shared IRQ instead of direct IRQ, in case of overlapping, we can easily + * program one of the overlap to shared IRQ to avoid the conflict. + */ + +/* NorthWest community pads */ +#define PMIC_I2C_SDA_IRQ 0x32 +#define GPIO_74_IRQ 0x33 +#define GPIO_75_IRQ 0x34 +#define GPIO_76_IRQ 0x35 +#define GPIO_77_IRQ 0x36 +#define GPIO_78_IRQ 0x37 +#define GPIO_79_IRQ 0x38 +#define GPIO_80_IRQ 0x39 +#define GPIO_81_IRQ 0x3A +#define GPIO_82_IRQ 0x3B +#define GPIO_83_IRQ 0x3C +#define GPIO_84_IRQ 0x3D +#define GPIO_85_IRQ 0x3E +#define GPIO_86_IRQ 0x3F +#define GPIO_87_IRQ 0x40 +#define GPIO_88_IRQ 0x41 +#define GPIO_89_IRQ 0x42 +#define GPIO_90_IRQ 0x43 +#define GPIO_91_IRQ 0x44 +#define GPIO_97_IRQ 0x49 +#define GPIO_98_IRQ 0x4A +#define GPIO_99_IRQ 0x4B +#define GPIO_100_IRQ 0x4C +#define GPIO_101_IRQ 0x4D +#define GPIO_102_IRQ 0x4E +#define GPIO_103_IRQ 0x4F +#define GPIO_104_IRQ 0x50 +#define GPIO_105_IRQ 0x51 +#define GPIO_106_IRQ 0x52 +#define GPIO_109_IRQ 0x54 +#define GPIO_110_IRQ 0x55 +#define GPIO_111_IRQ 0x56 +#define GPIO_112_IRQ 0x57 +#define GPIO_113_IRQ 0x58 +#define GPIO_116_IRQ 0x5B +#define GPIO_117_IRQ 0x5C +#define GPIO_118_IRQ 0x5D +#define GPIO_119_IRQ 0x5E +#define GPIO_120_IRQ 0x5F +#define GPIO_121_IRQ 0x60 +#define GPIO_122_IRQ 0x61 +#define GPIO_123_IRQ 0x62 + +/* North community pads */ +#define GPIO_0_IRQ 0x63 +#define GPIO_1_IRQ 0x64 +#define GPIO_2_IRQ 0x65 +#define GPIO_3_IRQ 0x66 +#define GPIO_4_IRQ 0x67 +#define GPIO_5_IRQ 0x68 +#define GPIO_6_IRQ 0x69 +#define GPIO_7_IRQ 0x6A +#define GPIO_8_IRQ 0x6B +#define GPIO_9_IRQ 0x6C +#define GPIO_10_IRQ 0x6D +#define GPIO_11_IRQ 0x6E +#define GPIO_12_IRQ 0x6F +#define GPIO_13_IRQ 0x6F +#define GPIO_14_IRQ 0x71 +#define GPIO_15_IRQ 0x72 +#define GPIO_16_IRQ 0x73 +#define GPIO_17_IRQ 0x74 +#define GPIO_18_IRQ 0x75 +#define GPIO_19_IRQ 0x76 +#define GPIO_20_IRQ 0x77 +#define GPIO_21_IRQ 0x32 +#define GPIO_22_IRQ 0x33 +#define GPIO_23_IRQ 0x34 +#define GPIO_24_IRQ 0x35 +#define GPIO_25_IRQ 0x36 +#define GPIO_26_IRQ 0x37 +#define GPIO_27_IRQ 0x38 +#define GPIO_28_IRQ 0x39 +#define GPIO_29_IRQ 0x3A +#define GPIO_30_IRQ 0x3B +#define GPIO_31_IRQ 0x3C +#define GPIO_32_IRQ 0x3D +#define GPIO_33_IRQ 0x3E +#define GPIO_34_IRQ 0x3F +#define GPIO_35_IRQ 0x40 +#define GPIO_36_IRQ 0x41 +#define GPIO_37_IRQ 0x42 +#define GPIO_38_IRQ 0x43 +#define GPIO_39_IRQ 0x44 +#define GPIO_40_IRQ 0x45 +#define GPIO_41_IRQ 0x46 +#define GPIO_42_IRQ 0x47 +#define GPIO_43_IRQ 0x48 +#define GPIO_44_IRQ 0x49 +#define GPIO_45_IRQ 0x4A +#define GPIO_46_IRQ 0x4B +#define GPIO_47_IRQ 0x4C +#define GPIO_48_IRQ 0x4D +#define GPIO_49_IRQ 0x4E +#define GPIO_62_IRQ 0x5B +#define GPIO_63_IRQ 0x5C +#define GPIO_64_IRQ 0x5D +#define GPIO_65_IRQ 0x5E +#define GPIO_66_IRQ 0x5F +#define GPIO_67_IRQ 0x60 +#define GPIO_68_IRQ 0x61 +#define GPIO_69_IRQ 0x62 +#define GPIO_70_IRQ 0x63 +#define GPIO_71_IRQ 0x64 +#define GPIO_72_IRQ 0x65 +#define GPIO_73_IRQ 0x66 + +#endif /* _SOC_GLK_GPIO_DEFS_H_ */ diff --git a/src/soc/intel/glk/include/soc/heci.h b/src/soc/intel/glk/include/soc/heci.h new file mode 100644 index 0000000..82b89a9 --- /dev/null +++ b/src/soc/intel/glk/include/soc/heci.h @@ -0,0 +1,43 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2016 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_GLK_HECI_H_ +#define _SOC_GLK_HECI_H_ + +enum sec_status { + SEC_STATE_RESET = 0, + SEC_STATE_INIT, + SEC_STATE_RECOVERY, + SEC_STATE_UNKNOWN0, + SEC_STATE_UNKNOWN1, + SEC_STATE_NORMAL, + SEC_STATE_DISABLE_WAIT, + SEC_STATE_TRANSITION, + SEC_STATE_INVALID_CPU +}; + +#define REG_SEC_FW_STS0 0x40 +#define MASK_SEC_FIRMWARE_COMPLETE (1 << 9) +#define MASK_SEC_STATUS 0xf + +/* Read Firmware Status register */ +uint32_t heci_fw_sts(void); +/* Returns true if CSE is in normal status */ +bool heci_cse_normal(void); +/* Returns true if CSE is done with whatever it was doing */ +bool heci_cse_done(void); + +#endif diff --git a/src/soc/intel/glk/include/soc/i2c.h b/src/soc/intel/glk/include/soc/i2c.h new file mode 100644 index 0000000..95ccc4a --- /dev/null +++ b/src/soc/intel/glk/include/soc/i2c.h @@ -0,0 +1,50 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2016 Google Inc. + * + * 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_GLK_I2C_H_ +#define _SOC_GLK_I2C_H_ + +#include <device/pci_def.h> +#include <soc/pci_devs.h> + +/* I2C Controller Reset in MMIO private region */ +#define I2C_LPSS_REG_RESET 0x204 +#define I2C_LPSS_RESET_RELEASE_HC ((1 << 1) | (1 << 0)) +#define I2C_LPSS_RESET_RELEASE_IDMA (1 << 2) + +/* Convert I2C bus number to PCI device and function */ +static inline int i2c_bus_to_devfn(unsigned bus) +{ + if (bus >= 0 && bus <= 3) + return PCI_DEVFN(LPSS_DEV_SLOT_I2C_D0, bus); + else if (bus >= 4 && bus <= 7) + return PCI_DEVFN(LPSS_DEV_SLOT_I2C_D1, (bus - 4)); + else + return -1; +} + +/* Convert PCI device and function to I2C bus number */ +static inline int i2c_devfn_to_bus(unsigned devfn) +{ + if (PCI_SLOT(devfn) == LPSS_DEV_SLOT_I2C_D0) + return PCI_FUNC(devfn); + else if (PCI_SLOT(devfn) == LPSS_DEV_SLOT_I2C_D1) + return PCI_FUNC(devfn) + 4; + else + return -1; +} + +#endif /* _SOC_GLK_I2C_H_ */ diff --git a/src/soc/intel/glk/include/soc/iomap.h b/src/soc/intel/glk/include/soc/iomap.h new file mode 100644 index 0000000..ef1bc68 --- /dev/null +++ b/src/soc/intel/glk/include/soc/iomap.h @@ -0,0 +1,42 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 Intel Corp. + * (Written by Andrey Petrov andrey.petrov@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_GLK_IOMAP_H_ +#define _SOC_GLK_IOMAP_H_ + +#include <commonlib/helpers.h> + +#define P2SB_BAR CONFIG_IOSF_BASE_ADDRESS +#define P2SB_SIZE (16 * MiB) +#define MCH_BASE_ADDR 0xfed10000 +#define MCH_BASE_SIZE (32 * KiB) + +#define ACPI_PMIO_BASE 0x400 +#define ACPI_PMIO_SIZE 0x100 +#define R_ACPI_PM1_TMR 0x8 + +/* Accesses to these BARs are hardcoded in FSP */ +#define PMC_BAR0 0xfe042000 +#define PMC_BAR1 0xfe044000 + +/* Temporary BAR for SPI until PCI enumeration assigns a BAR in ramstage. */ +#define PRERAM_SPI_BASE_ADDRESS 0xfe010000 + +/* Temporary BAR for early I2C bus access */ +#define PRERAM_I2C_BASE_ADDRESS(x) (0xfe020000 + (0x1000 * (x))) + +#endif /* _SOC_GLK_IOMAP_H_ */ diff --git a/src/soc/intel/glk/include/soc/iosf.h b/src/soc/intel/glk/include/soc/iosf.h new file mode 100644 index 0000000..77f6bf8 --- /dev/null +++ b/src/soc/intel/glk/include/soc/iosf.h @@ -0,0 +1,42 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 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_GLK_IOSF_H_ +#define _SOC_GLK_IOSF_H_ + +#include <arch/io.h> + +#define IOSF_RTC_PORT_ID 0xD1 +#define RTC_CONFIG 0x3400 +#define RTC_CONFIG_UCMOS_ENABLE (1 << 2) + +static inline void * iosf_address(uint16_t port, uint16_t reg) +{ + uintptr_t addr = (CONFIG_IOSF_BASE_ADDRESS | (port << 16) | (reg & ~3)); + return (void *)addr; +} + +inline static void iosf_write(uint16_t port, uint16_t reg, uint32_t val) +{ + write32(iosf_address(port, reg), val); +} + +inline static uint32_t iosf_read(uint16_t port, uint16_t reg) +{ + return read32(iosf_address(port, reg)); +} +#endif /* _SOC_GLK_IOSF_H_ */ diff --git a/src/soc/intel/glk/include/soc/itss.h b/src/soc/intel/glk/include/soc/itss.h new file mode 100644 index 0000000..2669fed --- /dev/null +++ b/src/soc/intel/glk/include/soc/itss.h @@ -0,0 +1,29 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2016 Google Inc. + * + * 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_GLK_ITSS_H_ +#define _SOC_GLK_ITSS_H_ + +#define GPIO_IRQ_START 50 +#define GPIO_IRQ_END 119 + +/* Set the interrupt polarity for provided IRQ to the APIC. */ +void itss_set_irq_polarity(int irq, int active_low); + +/* Snapshot and restore IRQ polarity settings for the inclusive range. */ +void itss_snapshot_irq_polarities(int start, int end); +void itss_restore_irq_polarities(int start, int end); + +#endif /* _SOC_GLK_ITSS_H_ */ diff --git a/src/soc/intel/glk/include/soc/lpc.h b/src/soc/intel/glk/include/soc/lpc.h new file mode 100644 index 0000000..e104478 --- /dev/null +++ b/src/soc/intel/glk/include/soc/lpc.h @@ -0,0 +1,69 @@ +/* + * 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_GLK_LPC_H_ +#define _SOC_GLK_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 (not referenced). + */ +#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_GLK_LPC_H_ */ diff --git a/src/soc/intel/glk/include/soc/meminit.h b/src/soc/intel/glk/include/soc/meminit.h new file mode 100644 index 0000000..34d0a98 --- /dev/null +++ b/src/soc/intel/glk/include/soc/meminit.h @@ -0,0 +1,121 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2016 Google Inc. + * + * 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_GLK_MEMINIT_H_ +#define _SOC_GLK_MEMINIT_H_ + +#include <stddef.h> +#include <stdint.h> +#include <fsp/soc_binding.h> + +/* + * LPDDR4 helper routines for configuring the memory UPD for LPDDR4 operation. + * There are 4 physical LPDDR4 channels each 32-bits wide. There are 2 logical + * channels using 2 physical channels together to form a 64-bit interface to + * memory for each logical channel. + */ + +enum { + LP4_PHYS_CH0A, + LP4_PHYS_CH0B, + LP4_PHYS_CH1A, + LP4_PHYS_CH1B, + LP4_NUM_PHYS_CHANNELS, +}; + +/* Logical channel identification. */ +enum { + LP4_LCH0, + LP4_LCH1, +}; + +/* + * The DQs within a physical channel can be bit-swizzled within each byte. + * Within a channel the bytes can be swapped, but the DQs need to be routed + * with the corresponding DQS (strobe). + */ +enum { + LP4_DQS0, + LP4_DQS1, + LP4_DQS2, + LP4_DQS3, + LP4_NUM_BYTE_LANES, + DQ_BITS_PER_DQS = 8, +}; + +enum { + /* RL-tRCD-tRP */ + LP4_SPEED_1600 = 1600, /* 14-15-15 */ + LP4_SPEED_2133 = 2133, /* 20-20-20 */ + LP4_SPEED_2400 = 2400, /* 24-22-22 */ +}; + +/* LPDDR4 module density in bits. */ +enum { + LP4_8Gb_DENSITY = 2, + LP4_12Gb_DESNITY, + LP4_16Gb_DENSITY, +}; + +/* Provide bit swizzling per DQS and byte swapping within a channel. */ +struct lpddr4_chan_swizzle_cfg { + uint8_t dqs[LP4_NUM_BYTE_LANES][DQ_BITS_PER_DQS]; +}; + +struct lpddr4_swizzle_cfg { + struct lpddr4_chan_swizzle_cfg phys[LP4_NUM_PHYS_CHANNELS]; +}; + +/* + * Initialize default LPDDR4 settings with provided speed. No logical channels + * are enabled. Subsequent calls to logical channel enabling are required. + */ +void meminit_lpddr4(FSP_M_CONFIG *cfg, int speed); + +/* + * Enable logical channel providing the full lpddr4_swizzle_config to + * fill in per channel swizzle definitions. This assumes a 64-bit wide + * memory width per logical channel -- i.e. 2 physical channels are configured + * to the memory reference code. + */ +void meminit_lpddr4_enable_channel(FSP_M_CONFIG *cfg, int logical_chan, + int rank_density, int dual_rank, + const struct lpddr4_swizzle_cfg *scfg); + +struct lpddr4_sku { + int speed; + int ch0_rank_density; + int ch1_rank_density; + int ch0_dual_rank; + int ch1_dual_rank; + const char *part_num; + bool disable_periodic_retraining; +}; + +struct lpddr4_cfg { + const struct lpddr4_sku *skus; + size_t num_skus; + const struct lpddr4_swizzle_cfg *swizzle_config; +}; + +/* + * Initialize LPDDR4 settings by the provided lpddr4_cfg information and sku id. + * The sku id is an index into the sku array within the lpddr4_cfg struct. + */ +void meminit_lpddr4_by_sku(FSP_M_CONFIG *cfg, + const struct lpddr4_cfg *lpcfg, size_t sku_id); +void save_lpddr4_dimm_info(const struct lpddr4_cfg *lpcfg, size_t mem_sku); + +#endif /* _SOC_GLK_MEMINIT_H_ */ diff --git a/src/soc/intel/glk/include/soc/mmap_boot.h b/src/soc/intel/glk/include/soc/mmap_boot.h new file mode 100644 index 0000000..b638336 --- /dev/null +++ b/src/soc/intel/glk/include/soc/mmap_boot.h @@ -0,0 +1,22 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2016 Google Inc. + * + * 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_GLK_MMAP_BOOT_H__ +#define __SOC_GLK_MMAP_BOOT_H__ + +size_t get_bios_size(void); + +#endif /* __SOC_GLK_MMAP_BOOT_H__ */ diff --git a/src/soc/intel/glk/include/soc/nhlt.h b/src/soc/intel/glk/include/soc/nhlt.h new file mode 100644 index 0000000..d5a462e --- /dev/null +++ b/src/soc/intel/glk/include/soc/nhlt.h @@ -0,0 +1,43 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2016 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_GLK_NHLT_H_ +#define _SOC_GLK_NHLT_H_ + +#include <nhlt.h> + +#define NHLT_VID 0x8086 +#define NHLT_DID_DMIC 0xae20 +#define NHLT_DID_BT 0xae30 +#define NHLT_DID_SSP 0xae34 + +/* The following link values should be used for the hwlink parameters below. */ +enum { + AUDIO_LINK_SSP0, + AUDIO_LINK_SSP1, + AUDIO_LINK_SSP2, + AUDIO_LINK_SSP3, + AUDIO_LINK_SSP4, + AUDIO_LINK_SSP5, + AUDIO_LINK_DMIC, +}; + +/* Returns < 0 on error, 0 on success. */ +int nhlt_soc_add_dmic_array(struct nhlt *nhlt, int num_channels); +int nhlt_soc_add_max98357(struct nhlt *nhlt, int hwlink); +int nhlt_soc_add_da7219(struct nhlt *nhlt, int hwlink); + +#endif diff --git a/src/soc/intel/glk/include/soc/northbridge.h b/src/soc/intel/glk/include/soc/northbridge.h new file mode 100644 index 0000000..ba79838 --- /dev/null +++ b/src/soc/intel/glk/include/soc/northbridge.h @@ -0,0 +1,40 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 Intel Corp. + * (Written by Andrey Petrov andrey.petrov@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_GLK_NORTHBRIDGE_H_ +#define _SOC_GLK_NORTHBRIDGE_H_ + +#define MCHBAR 0x48 +#define PCIEXBAR 0x60 +#define PCIEX_SIZE (256 * MiB) + +#define BDSM 0xb0 /* Base Data Stolen Memory */ +#define BGSM 0xb4 /* Base GTT Stolen Memory */ +#define TSEG 0xb8 /* TSEG base */ +#define TOLUD 0xbc /* Top of Low Used Memory */ +#define TOUUD 0xa8 /* Top of Upper Usable DRAM */ + +/* IMR registers are found under MCHBAR. */ +#define MCHBAR_IMR0BASE 0x6870 +#define MCHBAR_IMR0MASK 0x6874 +#define MCH_IMR_PITCH 0x20 +#define MCH_NUM_IMRS 20 + +/* RAPL Package Power Limit register under MCHBAR. */ +#define MCHBAR_RAPL_PPL 0x70A8 + +#endif /* _SOC_GLK_NORTHBRIDGE_H_ */ diff --git a/src/soc/intel/glk/include/soc/nvs.h b/src/soc/intel/glk/include/soc/nvs.h new file mode 100644 index 0000000..f468c1a --- /dev/null +++ b/src/soc/intel/glk/include/soc/nvs.h @@ -0,0 +1,48 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 Intel Corp. + * (Written by Lance Zhao lijian.zhao@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. + */ + +/* + * NOTE: The layout of the global_nvs_t structure below must match the layout + * in soc/intel/glk/acpi/globalnvs.asl !!! + * + */ + +#ifndef _SOC_GLK_NVS_H_ +#define _SOC_GLK_NVS_H_ + +#include <vendorcode/google/chromeos/gnvs.h> + +typedef struct global_nvs_t { + /* Miscellaneous */ + uint8_t pcnt; /* 0x00 - Processor Count */ + uint8_t ppcm; /* 0x01 - Max PPC State */ + uint8_t lids; /* 0x02 - LID State */ + uint8_t pwrs; /* 0x03 - AC Power State */ + uint8_t dpte; /* 0x04 - Enable DPTF */ + uint32_t cbmc; /* 0x05 - 0x08 - Coreboot Memory Console */ + uint64_t pm1i; /* 0x09 - 0x10 - System Wake Source - PM1 Index */ + uint64_t gpei; /* 0x11 - 0x18 - GPE Wake Source */ + uint64_t nhla; /* 0x19 - 0x20 - NHLT Address */ + uint32_t nhll; /* 0x21 - 0x24 - NHLT Length */ + uint32_t prt0; /* 0x25 - 0x28 - PERST_0 Address */ + uint8_t unused[215]; + + /* ChromeOS specific (0x100 - 0xfff) */ + chromeos_acpi_t chromeos; +} __attribute__((packed)) global_nvs_t; + +#endif /* _SOC_GLK_NVS_H_ */ diff --git a/src/soc/intel/glk/include/soc/p2sb.h b/src/soc/intel/glk/include/soc/p2sb.h new file mode 100644 index 0000000..6cc3b8c --- /dev/null +++ b/src/soc/intel/glk/include/soc/p2sb.h @@ -0,0 +1,23 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2016 Google Inc. + * + * 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_GLK_P2SB_H_ +#define _SOC_GLK_P2SB_H_ + +void p2sb_unhide(void); +void p2sb_hide(void); + +#endif /* _SOC_GLK_P2SB_H_ */ diff --git a/src/soc/intel/glk/include/soc/pci_devs.h b/src/soc/intel/glk/include/soc/pci_devs.h new file mode 100644 index 0000000..1ecfdaf --- /dev/null +++ b/src/soc/intel/glk/include/soc/pci_devs.h @@ -0,0 +1,122 @@ +/* + * This file is part of the coreboot project. + * + * 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_GLK_PCI_DEVS_H_ +#define _SOC_GLK_PCI_DEVS_H_ + +#include <rules.h> + +#define _LPSS_PCI_DEVFN(slot, func) PCI_DEVFN(LPSS_DEV_SLOT_##slot, func) +#define _PCI_DEVFN(slot, func) PCI_DEVFN(slot, func) + +#if !defined(__SIMPLE_DEVICE__) +#include <device/device.h> +#include <device/pci_def.h> +#define _LPSS_PCI_DEV(slot, func) dev_find_slot(0, _LPSS_PCI_DEVFN(slot, func)) +#define _PCI_DEV(slot, func) dev_find_slot(0, PCI_DEVFN(slot, func)) +#else +#include <arch/io.h> +#define _LPSS_PCI_DEV(slot, func) PCI_DEV(0, LPSS_DEV_SLOT_##slot, func) +#define _PCI_DEV(slot, func) PCI_DEV(0, slot, func) +#endif + +#define NB_DEVFN _PCI_DEVFN(0, 0) +#define NB_DEV_ROOT _PCI_DEV(0x0, 0) + +#define IGD_DEV _PCI_DEV(0x2, 0) +#define IGD_DEVFN _PCI_DEVFN(0x2, 0) + +#define P2SB_DEV _PCI_DEV(0xd, 0) +#define P2SB_DEVFN _PCI_DEVFN(0xd, 0) + +#define PMC_DEV _PCI_DEV(0xd, 1) +#define PMC_DEVFN _PCI_DEVFN(0xd, 1) + +#define SPI_DEV _PCI_DEV(0xd, 2) +#define SPI_DEVFN _PCI_DEVFN(0xd, 2) + +#define HDA_DEV _PCI_DEV(0xe, 0) +#define HDA_DEVFN _PCI_DEVFN(0xe, 0) + +#define CSE_DEV _PCI_DEV(0xf, 0) +#define CSE_DEVFN _PCI_DEVFN(0xf, 0) + +#define ISH_DEV _PCI_DEV(0x11, 0) +#define ISH_DEVFN _PCI_DEVFN(0x11, 0) + +#define SATA_DEV _PCI_DEV(0x12, 0) +#define SATA_DEVFN _PCI_DEVFN(0x12, 0) + +#define PCIEA0_DEVFN _PCI_DEVFN(0x13, 0) +#define PCIEA1_DEVFN _PCI_DEVFN(0x13, 1) +#define PCIEA2_DEVFN _PCI_DEVFN(0x13, 2) +#define PCIEA3_DEVFN _PCI_DEVFN(0x13, 3) +#define PCIEB0_DEVFN _PCI_DEVFN(0x14, 0) +#define PCIEB1_DEVFN _PCI_DEVFN(0x14, 1) + +#define XHCI_DEV _PCI_DEV(0x15, 0) +#define XHCI_DEVFN _PCI_DEVFN(0x15, 0) + +#define XDCI_DEV _PCI_DEV(0x15, 1) +#define XDCI_DEVFN _PCI_DEVFN(0x15, 1) + +/* LPSS I2C, 2 devices cover 8 controllers */ +#define LPSS_DEV_SLOT_I2C_D0 0x16 +#define LPSS_DEVFN_I2C0 _LPSS_PCI_DEVFN(I2C_D0, 0) +#define LPSS_DEVFN_I2C1 _LPSS_PCI_DEVFN(I2C_D0, 1) +#define LPSS_DEVFN_I2C2 _LPSS_PCI_DEVFN(I2C_D0, 2) +#define LPSS_DEVFN_I2C3 _LPSS_PCI_DEVFN(I2C_D0, 3) +#define LPSS_DEV_SLOT_I2C_D1 0x17 +#define LPSS_DEVFN_I2C4 _LPSS_PCI_DEVFN(I2C_D1, 0) +#define LPSS_DEVFN_I2C5 _LPSS_PCI_DEVFN(I2C_D1, 1) +#define LPSS_DEVFN_I2C6 _LPSS_PCI_DEVFN(I2C_D1, 2) +#define LPSS_DEVFN_I2C7 _LPSS_PCI_DEVFN(I2C_D1, 3) + +/* LPSS UART */ +#define LPSS_DEV_SLOT_UART 0x18 +#define LPSS_DEVFN_UART0 _LPSS_PCI_DEVFN(UART, 0) +#define LPSS_DEVFN_UART1 _LPSS_PCI_DEVFN(UART, 1) +#define LPSS_DEVFN_UART2 _LPSS_PCI_DEVFN(UART, 2) +#define LPSS_DEVFN_UART3 _LPSS_PCI_DEVFN(UART, 3) +#define LPSS_DEV_UART0 _LPSS_PCI_DEV(UART, 0) +#define LPSS_DEV_UART1 _LPSS_PCI_DEV(UART, 1) +#define LPSS_DEV_UART2 _LPSS_PCI_DEV(UART, 2) +#define LPSS_DEV_UART3 _LPSS_PCI_DEV(UART, 3) + +/* LPSS SPI */ +#define LPSS_DEV_SLOT_SPI 0x19 +#define LPSS_DEVFN_SPI0 _LPSS_PCI_DEVFN(SPI, 0) +#define LPSS_DEVFN_SPI1 _LPSS_PCI_DEVFN(SPI, 1) +#define LPSS_DEVFN_SPI2 _LPSS_PCI_DEVFN(SPI, 2) + +/* LPSS PWM */ +#define LPSS_DEV_SLOT_PWM 0x1a +#define LPSS_DEVFN_PWM _LPSS_PCI_DEVFN(PWM, 0) + +#define SDCARD_DEV _PCI_DEV(0x1b, 0) +#define SDCARD_DEVFN _PCI_DEVFN(0x1b, 0) + +#define EMMC_DEV _PCI_DEV(0x1c, 0) +#define EMMC_DEVFN _PCI_DEVFN(0x1c, 0) + +#define SDIO_DEV _PCI_DEV(0x1e, 0) +#define SDIO_DEVFN _PCI_DEVFN(0x1e, 0) + +#define LPC_DEV _PCI_DEV(0x1f, 0) +#define LPC_DEVFN _PCI_DEVFN(0x1f, 0) + +#define SMBUS_DEV _PCI_DEV(0x1f, 1) +#define SMBUS_DEVFN _PCI_DEVFN(0x1f, 1) + +#endif diff --git a/src/soc/intel/glk/include/soc/pci_ids.h b/src/soc/intel/glk/include/soc/pci_ids.h new file mode 100644 index 0000000..e1adc21 --- /dev/null +++ b/src/soc/intel/glk/include/soc/pci_ids.h @@ -0,0 +1,47 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 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_GLK_PCI_IDS_H_ +#define _SOC_GLK_PCI_IDS_H_ + +#define PCI_DEVICE_ID_APOLLOLAKE_NB 0x5af0 /* 00:00.0 */ +#define PCI_DEVICE_ID_APOLLOLAKE_IGD_HD_505 0x5a84 /* 00:02.0 */ +#define PCI_DEVICE_ID_APOLLOLAKE_IGD_HD_500 0x5a85 /* 00:02.0 */ +#define PCI_DEVICE_ID_APOLLOLAKE_P2SB 0x5a92 /* 00:0d.0 */ +#define PCI_DEVICE_ID_APOLLOLAKE_PMC 0x5a94 /* 00:0d.1 */ +#define PCI_DEVICE_ID_APOLLOLAKE_HWSEQ_SPI 0x5a96 /* 00:0d.2 */ +#define PCI_DEVICE_ID_APOLLOLAKE_AUDIO 0x5a98 /* 00:0e.0 */ +#define PCI_DEVICE_ID_APOLLOLAKE_SATA 0x5ae0 /* 00:12.0 */ +#define PCI_DEVICE_ID_APOLLOLAKE_XHCI 0x5aa8 /* 00:15.0 */ +#define PCI_DEVICE_ID_APOLLOLAKE_I2C0 0x5aac /* 00:16.0 */ +#define PCI_DEVICE_ID_APOLLOLAKE_I2C1 0x5aae /* 00:16.1 */ +#define PCI_DEVICE_ID_APOLLOLAKE_I2C2 0x5ab0 /* 00:16.2 */ +#define PCI_DEVICE_ID_APOLLOLAKE_I2C3 0x5ab2 /* 00:16.3 */ +#define PCI_DEVICE_ID_APOLLOLAKE_I2C4 0x5ab4 /* 00:17.0 */ +#define PCI_DEVICE_ID_APOLLOLAKE_I2C5 0x5ab6 /* 00:17.1 */ +#define PCI_DEVICE_ID_APOLLOLAKE_I2C6 0x5ab8 /* 00:17.2 */ +#define PCI_DEVICE_ID_APOLLOLAKE_I2C7 0x5aba /* 00:17.3 */ +#define PCI_DEVICE_ID_APOLLOLAKE_UART0 0x5abc /* 00:18.0 */ +#define PCI_DEVICE_ID_APOLLOLAKE_UART1 0x5abe /* 00:18.1 */ +#define PCI_DEVICE_ID_APOLLOLAKE_UART2 0x5ac0 /* 00:18.2 */ +#define PCI_DEVICE_ID_APOLLOLAKE_UART3 0x5aee /* 00:18.3 */ +#define PCI_DEVICE_ID_APOLLOLAKE_SPI0 0x5ac2 /* 00:19.0 */ +#define PCI_DEVICE_ID_APOLLOLAKE_SPI1 0x5ac4 /* 00:19.1 */ +#define PCI_DEVICE_ID_APOLLOLAKE_SPI2 0x5ac6 /* 00:19.2 */ +#define PCI_DEVICE_ID_APOLLOLAKE_LPC 0x5ae8 /* 00:1f.0 */ + +#endif /* _SOC_GLK_PCI_IDS_H_ */ diff --git a/src/soc/intel/glk/include/soc/pm.h b/src/soc/intel/glk/include/soc/pm.h new file mode 100644 index 0000000..3805649 --- /dev/null +++ b/src/soc/intel/glk/include/soc/pm.h @@ -0,0 +1,216 @@ +/* + * 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.) + * + * 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_GLK_PM_H_ +#define _SOC_GLK_PM_H_ + +#include <stdint.h> +#include <arch/acpi.h> + +/* ACPI_BASE_ADDRESS */ + +#define PM1_STS 0x00 +#define WAK_STS (1 << 15) +#define PCIEXPWAK_STS (1 << 14) +#define PRBTNOR_STS (1 << 11) +#define RTC_STS (1 << 10) +#define PWRBTN_STS (1 << 8) +#define GBL_STS (1 << 5) + +#define PM1_EN 0x02 +#define PCIEXPWAK_DIS (1 << 14) +#define RTC_EN (1 << 10) +#define PWRBTN_EN (1 << 8) +#define GBL_EN (1 << 5) + +#define PM1_CNT 0x04 +#define SCI_EN (1 << 0) + +#define PM1_TMR 0x08 + +#define SMI_EN 0x40 + +#define SMI_OCP_CSE 27 +#define SMI_SPI 26 +#define SMI_SPI_SSMI 25 +#define SMI_SCC2 21 +#define SMI_PCIE 20 +#define SMI_SCS 19 +#define SMI_HOST_SMBUS 18 +#define SMI_XHCI 17 +#define SMI_SMBUS 16 +#define SMI_SERIRQ 15 +#define SMI_PERIODIC 14 +#define SMI_TCO 13 +#define SMI_MCSMI 12 +#define SMI_GPIO_UNLOCK_SSMI 11 +#define SMI_GPIO 10 +#define SMI_BIOS_RLS 7 +#define SMI_SWSMI_TMR 6 +#define SMI_APMC 5 +#define SMI_SLP 4 +#define SMI_LEGACY_USB 3 +#define SMI_BIOS 2 +#define SMI_EOS 1 +#define SMI_GBL 0 + +#define USB_EN (1 << SMI_XHCI) /* Legacy USB2 SMI logic */ +#define PERIODIC_EN (1 << SMI_PERIODIC) /* SMI on PERIODIC_STS in SMI_STS */ +#define TCO_EN (1 << SMI_TCO) /* Enable TCO Logic (BIOSWE et al) */ +#define GPIO_EN (1 << SMI_GPIO) /* Enable GPIO SMI */ +#define BIOS_RLS (1 << SMI_BIOS_RLS) /* asserts SCI on bit set */ +#define SWSMI_TMR_EN (1 << SMI_SWSMI_TMR) /* start software smi timer on bit set */ +#define APMC_EN (1 << SMI_APMC) /* Writes to APM_CNT cause SMI# */ +#define SLP_SMI_EN (1 << SMI_SLP) /* Write to SLP_EN in PM1_CNT asserts SMI# */ +#define BIOS_EN (1 << SMI_BIOS) /* Assert SMI# on GBL_RLS bit */ +#define EOS (1 << SMI_EOS) /* End of SMI (deassert SMI#) */ +#define GBL_SMI_EN (1 << SMI_GBL) /* Global SMI Enable */ + +#define SMI_STS 0x44 +/* Bits for SMI status */ +#define PMC_OCP_SMI_STS 27 +#define SPI_SMI_STS 26 +#define SPI_SSMI_STS 25 +#define SCC2_SMI_STS 21 +#define PCIE_SMI_STS 20 +#define SCS_SMI_STS 19 +#define HSMBUS_SMI_STS 18 +#define XHCI_SMI_STS 17 +#define SMBUS_SMI_STS 16 +#define SERIRQ_SMI_STS 15 +#define PERIODIC_SMI_STS 14 +#define TCO_SMI_STS 13 +#define MC_SMI_STS 12 +#define GPIO_UNLOCK_SMI_STS 11 +#define GPIO_SMI_STS 10 +#define FAKE_PM1_SMI_STS 8 +#define SWSMI_TMR_SMI_STS 6 +#define APM_SMI_STS 5 +#define SLP_SMI_STS 4 +#define LEGACY_USB_SMI_STS 3 +#define BIOS_SMI_STS 2 + +#define GPE_CNTL 0x50 +#define DEVACT_STS 0x4c +#define TCO_STS 0x64 +#define TCO_TIMEOUT (1 << 3) +#define TCO1_CNT 0x68 +#define TCO_TMR_HLT (1 << 11) + +#define GPE0_REG_MAX 4 +#define GPE0_REG_SIZE 32 +#define GPE0_STS(x) (0x20 + (x * 4)) +#define GPE0_A 0 +#define GPE0_B 1 +#define GPE0_C 2 +#define GPE0_D 3 +#define SATA_PME_STS (1 << 17) +#define SMB_WAK_STS (1 << 16) +#define AVS_PME_STS (1 << 14) +#define XHCI_PME_STS (1 << 13) +#define XDCI_PME_STS (1 << 12) +#define CSE_PME_STS (1 << 11) +#define BATLOW_STS (1 << 10) +#define PCIE_GPE_STS (1 << 9) +#define SWGPE_STS (1 << 2) +#define GPE0_EN(x) (0x30 + (x * 4)) +#define SATA_PME_EN (1 << 17) +#define SMB_WAK_EN (1 << 16) +#define AVS_PME_EN (1 << 14) +#define PME_B0_EN (1 << 13) +#define XDCI_PME_EN (1 << 12) +#define CSE_PME_EN (1 << 11) +#define BATLOW_EN (1 << 10) +#define PCIE_GPE_EN (1 << 9) +#define SWGPE_EN (1 << 2) + +/* Memory mapped IO registers behind PMC_BASE_ADDRESS */ +#define PRSTS 0x1000 +#define GEN_PMCON1 0x1020 +#define SRS (1 << 20) +#define RPS (1 << 2) +#define GEN_PMCON2 0x1024 +#define GEN_PMCON3 0x1028 +# define SLP_S3_ASSERT_WIDTH_SHIFT 10 +# define SLP_S3_ASSERT_MASK (0x3 << SLP_S3_ASSERT_WIDTH_SHIFT) +# define SLP_S3_ASSERT_60_USEC 0x0 +# define SLP_S3_ASSERT_1_MSEC 0x1 +# define SLP_S3_ASSERT_50_MSEC 0x2 +# define SLP_S3_ASSERT_2_SEC 0x3 +#define ETR 0x1048 +# define CF9_LOCK (1 << 31) +# define CF9_GLB_RST (1 << 20) +#define GPIO_GPE_CFG 0x1050 +#define GPE0_DWX_MASK 0xf +#define GPE0_DW1_SHIFT 4 +#define GPE0_DW2_SHIFT 8 +#define GPE0_DW3_SHIFT 12 + +#define PMC_GPE_SW_31_0 0 +#define PMC_GPE_SW_63_32 1 +#define PMC_GPE_NW_31_0 3 +#define PMC_GPE_NW_63_32 4 +#define PMC_GPE_NW_95_64 5 +#define PMC_GPE_N_31_0 6 +#define PMC_GPE_N_63_32 7 +#define PMC_GPE_W_31_0 9 + +/* Track power state from reset to log events. */ +struct chipset_power_state { + uint16_t pm1_sts; + uint16_t pm1_en; + uint32_t pm1_cnt; + uint32_t gpe0_sts[GPE0_REG_MAX]; + uint32_t gpe0_en[GPE0_REG_MAX]; + uint32_t tco_sts; + uint32_t prsts; + uint32_t gen_pmcon1; + uint32_t gen_pmcon2; + uint32_t gen_pmcon3; + uint32_t prev_sleep_state; +} __attribute__((packed)); + +int fill_power_state(struct chipset_power_state *ps); +int chipset_prev_sleep_state(struct chipset_power_state *ps); +/* Rewrite the gpe0 registers in cbmem to proper values as per routing table */ +void fixup_power_state(void); + +/* Power Management Utility Functions. */ +uint32_t clear_smi_status(void); +uint16_t clear_pm1_status(void); +uint32_t clear_tco_status(void); +uint32_t clear_gpe_status(void); +void clear_pmc_status(void); +void clear_gpi_gpe_sts(void); +uint32_t get_smi_en(void); +void enable_smi(uint32_t mask); +void disable_smi(uint32_t mask); +void enable_pm1(uint16_t events); +void enable_pm1_control(uint32_t mask); +void disable_pm1_control(uint32_t mask); +void enable_gpe(uint32_t mask); +void disable_gpe(uint32_t mask); +void disable_all_gpe(void); +uintptr_t get_pmc_mmio_bar(void); +void pmc_gpe_init(void); + +void global_reset_enable(bool enable); +void global_reset_lock(void); + +void pch_log_state(void); + +#endif diff --git a/src/soc/intel/glk/include/soc/romstage.h b/src/soc/intel/glk/include/soc/romstage.h new file mode 100644 index 0000000..fb046ef --- /dev/null +++ b/src/soc/intel/glk/include/soc/romstage.h @@ -0,0 +1,27 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 Intel Corp. + * (Written by Andrey Petrov andrey.petrov@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_GLK_ROMSTAGE_H_ +#define _SOC_GLK_ROMSTAGE_H_ + +#include <arch/cpu.h> +#include <fsp/api.h> + +void mainboard_memory_init_params(FSPM_UPD *mupd); +void mainboard_save_dimm_info(void); + +#endif /* _SOC_GLK_ROMSTAGE_H_ */ diff --git a/src/soc/intel/glk/include/soc/smm.h b/src/soc/intel/glk/include/soc/smm.h new file mode 100644 index 0000000..7a9846e --- /dev/null +++ b/src/soc/intel/glk/include/soc/smm.h @@ -0,0 +1,41 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2016 Intel Corp. + * (Written by Lance Zhao lijian.zhao@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_SMM_H_ +#define _SOC_SMM_H_ + +#include <stdint.h> +#include <soc/gpio.h> + +/* These helpers are for performing SMM relocation. */ +void southbridge_clear_smi_status(void); + +/* + * The initialization of the southbridge is split into 2 compoments. One is + * for clearing the state in the SMM registers. The other is for enabling + * SMIs. + */ +void southbridge_smm_clear_state(void); +void southbridge_smm_enable_smi(void); + +/* Mainboard handler for GPI SMIs*/ +void mainboard_smi_gpi_handler(const struct gpi_status *sts); + +/* Fills in the arguments for the entire SMM region covered by chipset + * protections. e.g. TSEG. */ +void smm_region(void **start, size_t *size); +#endif diff --git a/src/soc/intel/glk/include/soc/spi.h b/src/soc/intel/glk/include/soc/spi.h new file mode 100644 index 0000000..7acdfb8 --- /dev/null +++ b/src/soc/intel/glk/include/soc/spi.h @@ -0,0 +1,88 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2016 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_GLK_SPI_H_ +#define _SOC_GLK_SPI_H_ + +/* PCI configuration registers */ +#define SPIBAR_BIOS_CONTROL 0xdc +/* Bit definitions for BIOS_CONTROL */ +#define SPIBAR_BIOS_CONTROL_WPD (1 << 0) +#define SPIBAR_BIOS_CONTROL_CACHE_DISABLE (1 << 2) +#define SPIBAR_BIOS_CONTROL_PREFETCH_ENABLE (1 << 3) +#define SPIBAR_BIOS_CONTROL_EISS (1 << 5) + +/* Maximum bytes of data that can fit in FDATAn registers */ +#define SPIBAR_FDATA_FIFO_SIZE 0x40 + +/* Register offsets from the MMIO region base (PCI_BASE_ADDRESS_0) */ +#define SPIBAR_BIOS_BFPREG 0x00 +#define SPIBAR_HSFSTS_CTL 0x04 +#define SPIBAR_FADDR 0x08 +#define SPIBAR_FDATA(n) (0x10 + ((n) & 0xf) * 4) +#define SPIBAR_PTINX 0xcc +#define SPIBAR_PTDATA 0xd0 + +/* Bit definitions and masks for BIOS_BFPREG register. */ +#define SPIBAR_BFPREG_PRB_MASK (0x7fff) +#define SPIBAR_BFPREG_PRL_SHIFT (16) +#define SPIBAR_BFPREG_PRL_MASK (0x7fff << SPIBAR_BFPREG_PRL_SHIFT) +#define SPIBAR_BFPREG_SBRS (1 << 31) + +/* Bit definitions for HSFSTS_CTL register */ +#define SPIBAR_HSFSTS_FBDC_MASK (0x3f << 24) +#define SPIBAR_HSFSTS_FBDC(n) (((n) << 24) & SPIBAR_HSFSTS_FBDC_MASK) +#define SPIBAR_HSFSTS_WET (1 << 21) +#define SPIBAR_HSFSTS_FCYCLE_MASK (0xf << 17) +#define SPIBAR_HSFSTS_FCYCLE(cyc) (((cyc) << 17) & SPIBAR_HSFSTS_FCYCLE_MASK) +#define SPIBAR_HSFSTS_FGO (1 << 16) +#define SPIBAR_HSFSTS_FLOCKDN (1 << 15) +#define SPIBAR_HSFSTS_FDV (1 << 14) +#define SPIBAR_HSFSTS_FDOPSS (1 << 13) +#define SPIBAR_HSFSTS_SAF_CE (1 << 8) +#define SPIBAR_HSFSTS_SAF_ACTIVE (1 << 7) +#define SPIBAR_HSFSTS_SAF_LE (1 << 6) +#define SPIBAR_HSFSTS_SCIP (1 << 5) +#define SPIBAR_HSFSTS_SAF_DLE (1 << 4) +#define SPIBAR_HSFSTS_SAF_ERROR (1 << 3) +#define SPIBAR_HSFSTS_AEL (1 << 2) +#define SPIBAR_HSFSTS_FCERR (1 << 1) +#define SPIBAR_HSFSTS_FDONE (1 << 0) +#define SPIBAR_HSFSTS_W1C_BITS (0xff) +/* Supported flash cycle types */ +#define SPIBAR_HSFSTS_CYCLE_READ SPIBAR_HSFSTS_FCYCLE(0) +#define SPIBAR_HSFSTS_CYCLE_WRITE SPIBAR_HSFSTS_FCYCLE(2) +#define SPIBAR_HSFSTS_CYCLE_4K_ERASE SPIBAR_HSFSTS_FCYCLE(3) +#define SPIBAR_HSFSTS_CYCLE_64K_ERASE SPIBAR_HSFSTS_FCYCLE(4) +#define SPIBAR_HSFSTS_CYCLE_RD_STATUS SPIBAR_HSFSTS_FCYCLE(8) + +/* Bit definitions for PTINX register */ +#define SPIBAR_PTINX_COMP_0 (0 << 14) +#define SPIBAR_PTINX_COMP_1 (1 << 14) +#define SPIBAR_PTINX_HORD_SFDP (0 << 12) +#define SPIBAR_PTINX_HORD_PARAM (1 << 12) +#define SPIBAR_PTINX_HORD_JEDEC (2 << 12) +#define SPIBAR_PTINX_IDX_MASK 0xffc + +/* + * Reads status register. On success returns 0 and status contains the value + * read from the status register. On error returns -1. + */ +int spi_read_status(uint8_t *status); + +/* Read SPI controller register. */ +uint32_t spi_ctrlr_reg_read(uint16_t reg); +#endif diff --git a/src/soc/intel/glk/include/soc/uart.h b/src/soc/intel/glk/include/soc/uart.h new file mode 100644 index 0000000..4a71c0a --- /dev/null +++ b/src/soc/intel/glk/include/soc/uart.h @@ -0,0 +1,36 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 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_GLK_UART_H_ +#define _SOC_GLK_UART_H_ + +/* Clock is 100MHz * (M / N).*/ +#define UART_CLK 0x200 +# define UART_CLK_UPDATE (1 << 31) +# define UART_CLK_DIV_N(n) (((n) & 0x7fff) << 16) +# define UART_CLK_DIV_M(m) (((m) & 0x7fff) << 1) +# define UART_CLK_EN (1 << 0) +#define UART_RESET 0x204 +# define UART_RESET_DMA_EN (1 << 2) +# define UART_RESET_UART_EN (3 << 0) + +void lpss_console_uart_init(void); + +/* Initialize the console UART including the pads for the configured UART. */ +void soc_console_uart_init(void); + +#endif /* _SOC_GLK_UART_H_ */ diff --git a/src/soc/intel/glk/itss.c b/src/soc/intel/glk/itss.c new file mode 100644 index 0000000..9c49d6c --- /dev/null +++ b/src/soc/intel/glk/itss.c @@ -0,0 +1,129 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2016 Google Inc. + * + * 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 <commonlib/helpers.h> +#include <console/console.h> +#include <stdint.h> +#include <soc/iosf.h> +#include <soc/itss.h> + +#define IOSF_ITSS_PORT_ID 0xd0 +#define ITSS_MAX_IRQ 119 +#define IPC0 0x3200 +#define IRQS_PER_IPC 32 +#define NUM_IPC_REGS ((ITSS_MAX_IRQ + IRQS_PER_IPC - 1)/IRQS_PER_IPC) + +void itss_set_irq_polarity(int irq, int active_low) +{ + uint32_t mask; + uint32_t val; + uint16_t reg; + const uint16_t port = IOSF_ITSS_PORT_ID; + + if (irq < 0 || irq > ITSS_MAX_IRQ) + return; + + reg = IPC0 + sizeof(uint32_t) * (irq / IRQS_PER_IPC); + mask = 1 << (irq % IRQS_PER_IPC); + + val = iosf_read(port, reg); + val &= ~mask; + /* Setting the bit makes the IRQ active low. */ + val |= active_low ? mask : 0; + iosf_write(port, reg, val); +} + +static uint32_t irq_snapshot[NUM_IPC_REGS]; + +void itss_snapshot_irq_polarities(int start, int end) +{ + int i; + int reg_start; + int reg_end; + const uint16_t port = IOSF_ITSS_PORT_ID; + + if (start < 0 || start > ITSS_MAX_IRQ || + end < 0 || end > ITSS_MAX_IRQ || end < start) + return; + + reg_start = start / IRQS_PER_IPC; + reg_end = (end + IRQS_PER_IPC - 1) / IRQS_PER_IPC; + + for (i = reg_start; i < reg_end; i++) { + uint16_t reg = IPC0 + sizeof(uint32_t) * i; + irq_snapshot[i] = iosf_read(port, reg); + } +} + +static void show_irq_polarities(const char *msg) +{ + int i; + const uint16_t port = IOSF_ITSS_PORT_ID; + + printk(BIOS_INFO, "ITSS IRQ Polarities %s:\n", msg); + for (i = 0; i < NUM_IPC_REGS; i++) { + uint16_t reg = IPC0 + sizeof(uint32_t) * i; + printk(BIOS_INFO, "IPC%d: 0x%08x\n", i, iosf_read(port, reg)); + } +} + +void itss_restore_irq_polarities(int start, int end) +{ + int i; + int reg_start; + int reg_end; + const uint16_t port = IOSF_ITSS_PORT_ID; + + if (start < 0 || start > ITSS_MAX_IRQ || + end < 0 || end > ITSS_MAX_IRQ || end < start) + return; + + show_irq_polarities("Before"); + + reg_start = start / IRQS_PER_IPC; + reg_end = (end + IRQS_PER_IPC - 1) / IRQS_PER_IPC; + + for (i = reg_start; i < reg_end; i++) { + uint32_t mask; + uint32_t val; + uint16_t reg; + int irq_start; + int irq_end; + + irq_start = i * IRQS_PER_IPC; + irq_end = MIN(irq_start + IRQS_PER_IPC - 1, ITSS_MAX_IRQ); + + if (start > irq_end) + continue; + if (end < irq_start) + break; + + /* Track bits within the bounds of of the register. */ + irq_start = MAX(start, irq_start) % IRQS_PER_IPC; + irq_end = MIN(end, irq_end) % IRQS_PER_IPC; + + /* Create bitmask of the inclusive range of start and end. */ + mask = (((1U << irq_end) - 1) | (1U << irq_end)); + mask &= ~((1U << irq_start) - 1); + + reg = IPC0 + sizeof(uint32_t) * i; + val = iosf_read(port, reg); + val &= ~mask; + val |= mask & irq_snapshot[i]; + iosf_write(port, reg, val); + } + + show_irq_polarities("After"); +} diff --git a/src/soc/intel/glk/lpc.c b/src/soc/intel/glk/lpc.c new file mode 100644 index 0000000..aec8a9f --- /dev/null +++ b/src/soc/intel/glk/lpc.c @@ -0,0 +1,176 @@ +/* + * 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.) + * + * 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 <cbmem.h> +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <pc80/mc146818rtc.h> +#include <soc/acpi.h> +#include <soc/lpc.h> +#include <soc/pci_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 void rtc_init(void) +{ + int rtc_fail; + const struct chipset_power_state *ps = cbmem_find(CBMEM_ID_POWER_STATE); + + if (!ps) { + printk(BIOS_ERR, "Could not find power state in cbmem, RTC init aborted\n"); + return; + } + + rtc_fail = !!(ps->gen_pmcon1 & RPS); + /* Ensure the date is set including century byte. */ + cmos_check_update_date(); + if (IS_ENABLED(CONFIG_VBOOT_VBNV_CMOS)) + init_vbnv_cmos(rtc_fail); + else + cmos_init(rtc_fail); +} + +static void lpc_init(struct device *dev) +{ + uint8_t scnt; + struct soc_intel_glk_config *cfg; + + cfg = dev->chip_info; + if (!cfg) { + printk(BIOS_ERR, "BUG! Could not find SOC devicetree config\n"); + 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); + + /* 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 struct pci_driver soc_lpc __pci_driver = { + .ops = &device_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_APOLLOLAKE_LPC, +}; diff --git a/src/soc/intel/glk/lpc_lib.c b/src/soc/intel/glk/lpc_lib.c new file mode 100644 index 0000000..5bda51d --- /dev/null +++ b/src/soc/intel/glk/lpc_lib.c @@ -0,0 +1,180 @@ +/* + * 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. + */ + +#define __SIMPLE_DEVICE__ + +#include <console/console.h> +#include <device/pci.h> +#include <lib.h> +#include <soc/gpio.h> +#include <soc/lpc.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[] = { +}; + +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(LPC_DEV, REG_IO_ENABLES); + io_enables |= reg_io_enables; + pci_write_config16(LPC_DEV, REG_IO_ENABLES, io_enables); +} + +/* + * Find the first unused IO window. + * Returns -1 if not found, 0 for reg 0x84, 1 for reg 0x88 ... + */ +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(LPC_DEV, REG_GENERIC_IO_RANGE(i)); + + if (!(lgir & LGIR_EN)) + return i; + } + + return -1; +} + +void lpc_close_pmio_windows(void) +{ + size_t i; + + for (i = 0; i < NUM_GENERIC_IO_RANGES; i++) + pci_write_config32(LPC_DEV, REG_GENERIC_IO_RANGE(i), 0); +} + +void lpc_open_pmio_window(uint16_t base, uint16_t size) +{ + int lgir_reg_num; + uint32_t lgir_reg_offset, lgir, window_size, alignment; + resource_t bridged_size, bridge_base; + + printk(BIOS_SPEW, "LPC: Trying to open IO window from %x size %x\n", + base, size); + + bridged_size = 0; + bridge_base = base; + + while (bridged_size < size) { + lgir_reg_num = find_unused_pmio_window(); + if (lgir_reg_num < 0) { + printk(BIOS_ERR, + "LPC: Cannot open IO window: %llx size %llx\n", + bridge_base, size - bridged_size); + printk(BIOS_ERR, "No more IO windows\n"); + return; + } + lgir_reg_offset = REG_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 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; + + pci_write_config32(LPC_DEV, lgir_reg_offset, lgir); + + printk(BIOS_DEBUG, + "LPC: Opened IO window LGIR%d: base %llx size %x\n", + lgir_reg_num, bridge_base, window_size); + + bridged_size += window_size; + bridge_base += window_size; + } +} + +void lpc_open_mmio_window(uintptr_t base, size_t size) +{ + uint32_t lgmr; + + lgmr = pci_read_config32(LPC_DEV, REG_GENERIC_MEM_RANGE); + + if (lgmr & LGMR_EN) { + printk(BIOS_ERR, + "LPC: Cannot open window to resource %lx size %zx\n", + base, size); + printk(BIOS_ERR, "LPC: MMIO window already in use\n"); + return; + } + + if (size > LGMR_WINDOW_SIZE) { + printk(BIOS_WARNING, + "LPC: Resource %lx size %zx larger than window(%x)\n", + base, size, LGMR_WINDOW_SIZE); + } + + lgmr = (base & LGMR_ADDR_MASK) | LGMR_EN; + + pci_write_config32(LPC_DEV, REG_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; + + for (range = lpc_fixed_mmio_ranges; range->size; range++) { + range_end = range->base + range->size; + res_end = base + size; + + if ((base >= range->base) && (res_end <= range_end)) { + printk(BIOS_DEBUG, + "Resource %lx size %zx fits in fixed window" + " %lx size %zx\n", + base, size, range->base, range->size); + return true; + } + } + return false; +} diff --git a/src/soc/intel/glk/meminit.c b/src/soc/intel/glk/meminit.c new file mode 100644 index 0000000..0f553ee --- /dev/null +++ b/src/soc/intel/glk/meminit.c @@ -0,0 +1,341 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2016 Google Inc. + * + * 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 <cbmem.h> +#include <console/console.h> +#include <fsp/util.h> +#include <memory_info.h> +#include <smbios.h> +#include <soc/meminit.h> +#include <stddef.h> /* required for FspmUpd.h */ +#include <fsp/soc_binding.h> +#include <string.h> + +static void set_lpddr4_defaults(FSP_M_CONFIG *cfg) +{ + /* Enable memory down BGA since it's the only LPDDR4 packaging. */ + cfg->Package = 1; + cfg->MemoryDown = 1; + + cfg->ScramblerSupport = 1; + cfg->ChannelHashMask = 0x36; + cfg->SliceHashMask = 0x9; + cfg->InterleavedMode = 2; + cfg->ChannelsSlicesEnable = 0; + cfg->MinRefRate2xEnable = 0; + cfg->DualRankSupportEnable = 1; + /* Don't enforce a memory size limit. */ + cfg->MemorySizeLimit = 0; + /* Use a 2GiB I/O hole -- field is in MiB units. */ + cfg->LowMemoryMaxValue = 2 * (GiB/MiB); + /* No restrictions on memory above 4GiB */ + cfg->HighMemoryMaxValue = 0; + + /* Always default to attempt to use saved training data. */ + cfg->DisableFastBoot = 0; + + /* LPDDR4 is memory down so no SPD addresses. */ + cfg->DIMM0SPDAddress = 0; + cfg->DIMM1SPDAddress = 0; + + /* Clear all the rank enables. */ + cfg->Ch0_RankEnable = 0x0; + cfg->Ch1_RankEnable = 0x0; + cfg->Ch2_RankEnable = 0x0; + cfg->Ch3_RankEnable = 0x0; + + /* + * Set the device width to x16 which is half a LPDDR4 module as that's + * what the reference code expects. + */ + cfg->Ch0_DeviceWidth = 0x1; + cfg->Ch1_DeviceWidth = 0x1; + cfg->Ch2_DeviceWidth = 0x1; + cfg->Ch3_DeviceWidth = 0x1; + + /* + * Enable bank hashing (bit 1) and rank interleaving (bit 0) with + * a 1KiB address mapping (bits 5:4). + */ + cfg->Ch0_Option = 0x3; + cfg->Ch1_Option = 0x3; + cfg->Ch2_Option = 0x3; + cfg->Ch3_Option = 0x3; + + /* Weak on-die termination. */ + cfg->Ch0_OdtConfig = 0; + cfg->Ch1_OdtConfig = 0; + cfg->Ch2_OdtConfig = 0; + cfg->Ch3_OdtConfig = 0; +} + +void meminit_lpddr4(FSP_M_CONFIG *cfg, int speed) +{ + uint8_t profile; + + switch (speed) { + case LP4_SPEED_1600: + profile = 0x9; + break; + case LP4_SPEED_2133: + profile = 0xa; + break; + case LP4_SPEED_2400: + profile = 0xb; + break; + default: + printk(BIOS_WARNING, "Invalid LPDDR4 speed: %d\n", speed); + /* Set defaults. */ + speed = LP4_SPEED_1600; + profile = 0x9; + } + + printk(BIOS_INFO, "LP4DDR speed is %dMHz\n", speed); + cfg->Profile = profile; + + set_lpddr4_defaults(cfg); +} + +static void enable_logical_chan0(FSP_M_CONFIG *cfg, + int rank_density, int dual_rank, + const struct lpddr4_swizzle_cfg *scfg) +{ + const struct lpddr4_chan_swizzle_cfg *chan; + /* Number of bytes to copy per DQS. */ + const size_t sz = DQ_BITS_PER_DQS; + int rank_mask; + + /* + * Logical channel 0 is comprised of physical channel 0 and 1. + * Physical channel 0 is comprised of the CH0_DQB signals. + * Physical channel 1 is comprised of the CH0_DQA signals. + */ + cfg->Ch0_DramDensity = rank_density; + cfg->Ch1_DramDensity = rank_density; + /* Enable ranks on both channels depending on dual rank option. */ + rank_mask = dual_rank ? 0x3 : 0x1; + cfg->Ch0_RankEnable = rank_mask; + cfg->Ch1_RankEnable = rank_mask; + + /* + * CH0_DQB byte lanes in the bit swizzle configuration field are + * not 1:1. The mapping within the swizzling field is: + * indicies [0:7] - byte lane 1 (DQS1) DQ[8:15] + * indicies [8:15] - byte lane 0 (DQS0) DQ[0:7] + * indicies [16:23] - byte lane 3 (DQS3) DQ[24:31] + * indicies [24:31] - byte lane 2 (DQS2) DQ[16:23] + */ + chan = &scfg->phys[LP4_PHYS_CH0B]; + memcpy(&cfg->Ch0_Bit_swizzling[0], &chan->dqs[LP4_DQS1], sz); + memcpy(&cfg->Ch0_Bit_swizzling[8], &chan->dqs[LP4_DQS0], sz); + memcpy(&cfg->Ch0_Bit_swizzling[16], &chan->dqs[LP4_DQS3], sz); + memcpy(&cfg->Ch0_Bit_swizzling[24], &chan->dqs[LP4_DQS2], sz); + + /* + * CH0_DQA byte lanes in the bit swizzle configuration field are 1:1. + */ + chan = &scfg->phys[LP4_PHYS_CH0A]; + memcpy(&cfg->Ch1_Bit_swizzling[0], &chan->dqs[LP4_DQS0], sz); + memcpy(&cfg->Ch1_Bit_swizzling[8], &chan->dqs[LP4_DQS1], sz); + memcpy(&cfg->Ch1_Bit_swizzling[16], &chan->dqs[LP4_DQS2], sz); + memcpy(&cfg->Ch1_Bit_swizzling[24], &chan->dqs[LP4_DQS3], sz); +} + +static void enable_logical_chan1(FSP_M_CONFIG *cfg, + int rank_density, int dual_rank, + const struct lpddr4_swizzle_cfg *scfg) +{ + const struct lpddr4_chan_swizzle_cfg *chan; + /* Number of bytes to copy per DQS. */ + const size_t sz = DQ_BITS_PER_DQS; + int rank_mask; + + /* + * Logical channel 1 is comprised of physical channel 2 and 3. + * Physical channel 2 is comprised of the CH1_DQB signals. + * Physical channel 3 is comprised of the CH1_DQA signals. + */ + cfg->Ch2_DramDensity = rank_density; + cfg->Ch3_DramDensity = rank_density; + /* Enable ranks on both channels depending on dual rank option. */ + rank_mask = dual_rank ? 0x3 : 0x1; + cfg->Ch2_RankEnable = rank_mask; + cfg->Ch3_RankEnable = rank_mask; + + /* + * CH1_DQB byte lanes in the bit swizzle configuration field are + * not 1:1. The mapping within the swizzling field is: + * indicies [0:7] - byte lane 1 (DQS1) DQ[8:15] + * indicies [8:15] - byte lane 0 (DQS0) DQ[0:7] + * indicies [16:23] - byte lane 3 (DQS3) DQ[24:31] + * indicies [24:31] - byte lane 2 (DQS2) DQ[16:23] + */ + chan = &scfg->phys[LP4_PHYS_CH1B]; + memcpy(&cfg->Ch2_Bit_swizzling[0], &chan->dqs[LP4_DQS1], sz); + memcpy(&cfg->Ch2_Bit_swizzling[8], &chan->dqs[LP4_DQS0], sz); + memcpy(&cfg->Ch2_Bit_swizzling[16], &chan->dqs[LP4_DQS3], sz); + memcpy(&cfg->Ch2_Bit_swizzling[24], &chan->dqs[LP4_DQS2], sz); + + /* + * CH1_DQA byte lanes in the bit swizzle configuration field are 1:1. + */ + chan = &scfg->phys[LP4_PHYS_CH1A]; + memcpy(&cfg->Ch3_Bit_swizzling[0], &chan->dqs[LP4_DQS0], sz); + memcpy(&cfg->Ch3_Bit_swizzling[8], &chan->dqs[LP4_DQS1], sz); + memcpy(&cfg->Ch3_Bit_swizzling[16], &chan->dqs[LP4_DQS2], sz); + memcpy(&cfg->Ch3_Bit_swizzling[24], &chan->dqs[LP4_DQS3], sz); +} + +void meminit_lpddr4_enable_channel(FSP_M_CONFIG *cfg, int logical_chan, + int rank_density, int dual_rank, + const struct lpddr4_swizzle_cfg *scfg) +{ + if (rank_density < LP4_8Gb_DENSITY || + rank_density > LP4_16Gb_DENSITY) { + printk(BIOS_ERR, "Invalid LPDDR4 density: %d\n", rank_density); + return; + } + + switch (logical_chan) { + case LP4_LCH0: + enable_logical_chan0(cfg, rank_density, dual_rank, scfg); + break; + case LP4_LCH1: + enable_logical_chan1(cfg, rank_density, dual_rank, scfg); + break; + default: + printk(BIOS_ERR, "Invalid logical channel: %d\n", logical_chan); + break; + } +} + +void meminit_lpddr4_by_sku(FSP_M_CONFIG *cfg, + const struct lpddr4_cfg *lpcfg, size_t sku_id) +{ + const struct lpddr4_sku *sku; + + if (sku_id >= lpcfg->num_skus) { + printk(BIOS_ERR, "Too few LPDDR4 SKUs: 0x%zx/0x%zx\n", + sku_id, lpcfg->num_skus); + return; + } + + printk(BIOS_INFO, "LPDDR4 SKU id = 0x%zx\n", sku_id); + + sku = &lpcfg->skus[sku_id]; + + meminit_lpddr4(cfg, sku->speed); + + if (sku->ch0_rank_density) { + printk(BIOS_INFO, "LPDDR4 Ch0 density = %d\n", + sku->ch0_rank_density); + meminit_lpddr4_enable_channel(cfg, LP4_LCH0, + sku->ch0_rank_density, + sku->ch0_dual_rank, + lpcfg->swizzle_config); + } + + if (sku->ch1_rank_density) { + printk(BIOS_INFO, "LPDDR4 Ch1 density = %d\n", + sku->ch1_rank_density); + meminit_lpddr4_enable_channel(cfg, LP4_LCH1, + sku->ch1_rank_density, + sku->ch1_dual_rank, + lpcfg->swizzle_config); + } + + cfg->PeriodicRetrainingDisable = sku->disable_periodic_retraining; +} + +void save_lpddr4_dimm_info(const struct lpddr4_cfg *lp4cfg, size_t mem_sku) +{ + int channel, dimm, dimm_max, index; + size_t hob_size; + const DIMM_INFO *src_dimm; + struct dimm_info *dest_dimm; + struct memory_info *mem_info; + const CHANNEL_INFO *channel_info; + const FSP_SMBIOS_MEMORY_INFO *memory_info_hob; + + if (mem_sku >= lp4cfg->num_skus) { + printk(BIOS_ERR, "Too few LPDDR4 SKUs: 0x%zx/0x%zx\n", + mem_sku, lp4cfg->num_skus); + return; + } + + memory_info_hob = fsp_find_smbios_memory_info(&hob_size); + + /* + * Allocate CBMEM area for DIMM information used to populate SMBIOS + * table 17 + */ + mem_info = cbmem_add(CBMEM_ID_MEMINFO, sizeof(*mem_info)); + if (mem_info == NULL) { + printk(BIOS_ERR, "CBMEM entry for DIMM info missing\n"); + return; + } + memset(mem_info, 0, sizeof(*mem_info)); + + /* Describe the first N DIMMs in the system */ + index = 0; + dimm_max = ARRAY_SIZE(mem_info->dimm); + for (channel = 0; channel < memory_info_hob->ChannelCount; channel++) { + if (index >= dimm_max) + break; + channel_info = &memory_info_hob->ChannelInfo[channel]; + for (dimm = 0; dimm < channel_info->DimmCount; dimm++) { + if (index >= dimm_max) + break; + src_dimm = &channel_info->DimmInfo[dimm]; + dest_dimm = &mem_info->dimm[index]; + + if (!src_dimm->SizeInMb) + continue; + + /* Populate the DIMM information */ + dest_dimm->dimm_size = src_dimm->SizeInMb; + dest_dimm->ddr_type = memory_info_hob->MemoryType; + dest_dimm->ddr_frequency = + memory_info_hob->MemoryFrequencyInMHz; + dest_dimm->channel_num = channel_info->ChannelId; + dest_dimm->dimm_num = src_dimm->DimmId; + strncpy((char *)dest_dimm->module_part_number, + lp4cfg->skus[mem_sku].part_num, + sizeof(dest_dimm->module_part_number)); + + switch (memory_info_hob->DataWidth) { + case 8: + dest_dimm->bus_width = MEMORY_BUS_WIDTH_8; + break; + case 16: + dest_dimm->bus_width = MEMORY_BUS_WIDTH_16; + break; + case 32: + dest_dimm->bus_width = MEMORY_BUS_WIDTH_32; + break; + case 64: + dest_dimm->bus_width = MEMORY_BUS_WIDTH_64; + break; + case 128: + dest_dimm->bus_width = MEMORY_BUS_WIDTH_128; + break; + default: + printk(BIOS_ERR, "Incorrect DIMM Data Width"); + } + index++; + } + } + mem_info->dimm_cnt = index; + printk(BIOS_DEBUG, "%d DIMMs found\n", mem_info->dimm_cnt); +} diff --git a/src/soc/intel/glk/memmap.c b/src/soc/intel/glk/memmap.c new file mode 100644 index 0000000..ea6f447 --- /dev/null +++ b/src/soc/intel/glk/memmap.c @@ -0,0 +1,54 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 Intel Corp. + * (Written by Andrey Petrov andrey.petrov@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. + */ + +/* + * The device_t returned by dev_find_slot() is different than the device_t + * passed to pci_write_config32(). If one needs to get access to the config.h + * of a device and perform i/o things are incorrect. One is a pointer while + * the other is a 32-bit integer. + */ +#define __SIMPLE_DEVICE__ + +#include <arch/io.h> +#include <cbmem.h> +#include <device/pci.h> +#include <soc/northbridge.h> +#include <soc/pci_devs.h> +#include <soc/smm.h> + +static uintptr_t smm_region_start(void) +{ + return ALIGN_DOWN(pci_read_config32(NB_DEV_ROOT, TSEG), 1*MiB); +} + +static size_t smm_region_size(void) +{ + uintptr_t smm_end = + ALIGN_DOWN(pci_read_config32(NB_DEV_ROOT, BGSM), 1*MiB); + return smm_end - smm_region_start(); +} + +void *cbmem_top(void) +{ + return (void *)smm_region_start(); +} + +void smm_region(void **start, size_t *size) +{ + *start = (void *)smm_region_start(); + *size = smm_region_size(); +} diff --git a/src/soc/intel/glk/mmap_boot.c b/src/soc/intel/glk/mmap_boot.c new file mode 100644 index 0000000..bf2e5b9 --- /dev/null +++ b/src/soc/intel/glk/mmap_boot.c @@ -0,0 +1,171 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 Intel Corp. + * (Written by Andrey Petrov andrey.petrov@intel.com for 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. + */ + +#include <arch/early_variables.h> +#include <boot_device.h> +#include <cbfs.h> +#include <commonlib/region.h> +#include <console/console.h> +#include <fmap.h> +#include <soc/intel/common/nvm.h> +#include <soc/mmap_boot.h> +#include <soc/spi.h> + +/* + * BIOS region on the flash is mapped right below 4GiB in the address + * space. However, 256KiB right below 4GiB is decoded by read-only SRAM and not + * boot media. + * + * +----------------+ 0 + * | | + * | | + * | | + * | | + * | | + * | | + * | | + * | | + * +------------+ | | + * | IFD | | | + * bios_start +---> +------------+--------------------------> +----------------+ 4GiB - bios_size + * ^ | | ^ | | + * | | | | | | + * | | | bios_mapped_size | BIOS | + * | | BIOS | | | | + * bios_size | | | | | + * | | | v | | + * | | +--------------------------> +----------------+ 4GiB - 256KiB + * v | | | Read only SRAM | + * bios_end +---> +------------+ +----------------+ 4GiB + * | Device ext | + * +------------+ + * + */ + +static size_t bios_start CAR_GLOBAL; +static size_t bios_size CAR_GLOBAL; + +static struct mem_region_device shadow_dev CAR_GLOBAL; +static struct xlate_region_device real_dev CAR_GLOBAL; + +static void bios_mmap_init(void) +{ + size_t size; + + size = car_get_var(bios_size); + + /* If bios_size is initialized, then bail out. */ + if (size != 0) + return; + + size_t start, bios_end, bios_mapped_size; + uintptr_t base; + + /* + * BIOS_BFPREG provides info about BIOS Flash Primary Region + * Base and Limit. + * Base and Limit fields are in units of 4KiB. + */ + uint32_t val = spi_ctrlr_reg_read(SPIBAR_BIOS_BFPREG); + + start = (val & SPIBAR_BFPREG_PRB_MASK) * 4 * KiB; + bios_end = (((val & SPIBAR_BFPREG_PRL_MASK) >> + SPIBAR_BFPREG_PRL_SHIFT) + 1) * 4 * KiB; + size = bios_end - start; + + /* BIOS region is mapped right below 4G. */ + base = 4ULL * GiB - size; + + /* + * The 256 KiB right below 4G are decoded by readonly SRAM, + * not boot media. + */ + bios_mapped_size = size - 256 * KiB; + + struct mem_region_device *shadow_dev_ptr; + struct xlate_region_device *real_dev_ptr; + shadow_dev_ptr = car_get_var_ptr(&shadow_dev); + real_dev_ptr = car_get_var_ptr(&real_dev); + + mem_region_device_ro_init(shadow_dev_ptr, (void *)base, + bios_mapped_size); + + xlate_region_device_ro_init(real_dev_ptr, &shadow_dev_ptr->rdev, + start, bios_mapped_size, + CONFIG_ROM_SIZE); + + car_set_var(bios_start, start); + car_set_var(bios_size, size); +} + +const struct region_device *boot_device_ro(void) +{ + bios_mmap_init(); + + struct xlate_region_device *real_dev_ptr; + real_dev_ptr = car_get_var_ptr(&real_dev); + + return &real_dev_ptr->rdev; +} + +static int iafw_boot_region_properties(struct cbfs_props *props) +{ + struct region regn; + + /* use fmap to locate CBFS area */ + if (fmap_locate_area("COREBOOT", ®n)) + return -1; + + props->offset = region_offset(®n); + props->size = region_sz(®n); + + printk(BIOS_DEBUG, "CBFS @ %zx size %zx\n", props->offset, props->size); + + return 0; +} + +/* + * Named cbfs_master_header_locator so that it overrides the default, but + * incompatible locator in cbfs.c + */ +const struct cbfs_locator cbfs_master_header_locator = { + .name = "IAFW Locator", + .locate = iafw_boot_region_properties, +}; + +uint32_t nvm_mmio_to_flash_offset(void *p) +{ + bios_mmap_init(); + + size_t start, size; + start = car_get_var(bios_start); + size = car_get_var(bios_size); + + /* + * Returns : + * addr - base of mmaped region in addr space + offset of mmaped region + * start on flash + */ + return (uintptr_t)p - (4ULL * GiB - size) + start; +} + +size_t get_bios_size(void) +{ + bios_mmap_init(); + return car_get_var(bios_size); +} diff --git a/src/soc/intel/glk/nhlt.c b/src/soc/intel/glk/nhlt.c new file mode 100644 index 0000000..3670a13 --- /dev/null +++ b/src/soc/intel/glk/nhlt.c @@ -0,0 +1,142 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2016 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 <console/console.h> +#include <nhlt.h> +#include <soc/nhlt.h> + +static const struct nhlt_format_config dmic_2ch_formats[] = { + /* 48 KHz 16-bits per sample. */ + { + .num_channels = 2, + .sample_freq_khz = 48, + .container_bits_per_sample = 16, + .valid_bits_per_sample = 16, + .settings_file = "dmic-2ch-48khz-16b.bin", + }, +}; + +static const struct nhlt_dmic_array_config dmic_2ch_mic_config = { + .tdm_config = { + .config_type = NHLT_TDM_MIC_ARRAY, + }, + .array_type = NHLT_MIC_ARRAY_2CH_SMALL, +}; + +static const struct nhlt_endp_descriptor dmic_2ch_descriptors[] = { + { + .link = NHLT_LINK_PDM, + .device = NHLT_PDM_DEV, + .direction = NHLT_DIR_CAPTURE, + .vid = NHLT_VID, + .did = NHLT_DID_DMIC, + .cfg = &dmic_2ch_mic_config, + .cfg_size = sizeof(dmic_2ch_mic_config), + .formats = dmic_2ch_formats, + .num_formats = ARRAY_SIZE(dmic_2ch_formats), + }, +}; + +static const struct nhlt_format_config da7219_formats[] = { + /* 48 KHz 24-bits per sample. */ + { + .num_channels = 2, + .sample_freq_khz = 48, + .container_bits_per_sample = 32, + .valid_bits_per_sample = 24, + .settings_file = "dialog-2ch-48khz-24b.bin", + }, +}; + +static const struct nhlt_tdm_config tdm_config = { + .virtual_slot = 0, + .config_type = NHLT_TDM_BASIC, +}; + +static const struct nhlt_endp_descriptor da7219_descriptors[] = { + /* Render Endpoint */ + { + .link = NHLT_LINK_SSP, + .device = NHLT_SSP_DEV_I2S, + .direction = NHLT_DIR_RENDER, + .vid = NHLT_VID, + .did = NHLT_DID_SSP, + .cfg = &tdm_config, + .cfg_size = sizeof(tdm_config), + .formats = da7219_formats, + .num_formats = ARRAY_SIZE(da7219_formats), + }, + /* Capture Endpoint */ + { + .link = NHLT_LINK_SSP, + .device = NHLT_SSP_DEV_I2S, + .direction = NHLT_DIR_CAPTURE, + .vid = NHLT_VID, + .did = NHLT_DID_SSP, + .cfg = &tdm_config, + .cfg_size = sizeof(tdm_config), + .formats = da7219_formats, + .num_formats = ARRAY_SIZE(da7219_formats), + }, +}; + +static const struct nhlt_format_config max98357_formats[] = { + /* 48 KHz 24-bits per sample. */ + { + .num_channels = 2, + .sample_freq_khz = 48, + .container_bits_per_sample = 32, + .valid_bits_per_sample = 24, + .settings_file = "max98357-render-2ch-48khz-24b.bin", + }, +}; + +static const struct nhlt_endp_descriptor max98357_descriptors[] = { + { + .link = NHLT_LINK_SSP, + .device = NHLT_SSP_DEV_I2S, + .direction = NHLT_DIR_RENDER, + .vid = NHLT_VID, + .did = NHLT_DID_SSP, + .formats = max98357_formats, + .num_formats = ARRAY_SIZE(max98357_formats), + }, +}; + +int nhlt_soc_add_dmic_array(struct nhlt *nhlt, int num_channels) +{ + if (num_channels != 2) { + printk(BIOS_ERR, "APL only supports 2CH DMIC array.\n"); + return -1; + } + + return nhlt_add_endpoints(nhlt, dmic_2ch_descriptors, + ARRAY_SIZE(dmic_2ch_descriptors)); +} + +int nhlt_soc_add_da7219(struct nhlt *nhlt, int hwlink) +{ + /* Virtual bus id of SSP links are the hardware port ids proper. */ + return nhlt_add_ssp_endpoints(nhlt, hwlink, da7219_descriptors, + ARRAY_SIZE(da7219_descriptors)); +} + +int nhlt_soc_add_max98357(struct nhlt *nhlt, int hwlink) +{ + /* Virtual bus id of SSP links are the hardware port ids proper. */ + return nhlt_add_ssp_endpoints(nhlt, hwlink, max98357_descriptors, + ARRAY_SIZE(max98357_descriptors)); +} diff --git a/src/soc/intel/glk/northbridge.c b/src/soc/intel/glk/northbridge.c new file mode 100644 index 0000000..cc097ba --- /dev/null +++ b/src/soc/intel/glk/northbridge.c @@ -0,0 +1,169 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 Intel Corp. + * (Written by Andrey Petrov andrey.petrov@intel.com for 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. + */ + +#include <console/console.h> +#include <soc/iomap.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <soc/northbridge.h> +#include <soc/pci_ids.h> + +static uint32_t get_bar(device_t dev, unsigned int index) +{ + uint32_t bar; + + bar = pci_read_config32(dev, index); + + /* If not enabled return 0 else strip enabled bit */ + return (bar & 1) ? (bar & ~1) : 0; +} + +static int mc_add_fixed_mmio_resources(device_t dev, int index) +{ + unsigned long addr; + + /* PCI extended config region */ + addr = ALIGN_DOWN(get_bar(dev, PCIEXBAR), 256*MiB) / KiB; + mmio_resource(dev, index++, addr, PCIEX_SIZE / KiB); + + /* Memory Controller Hub */ + addr = ALIGN_DOWN(get_bar(dev, MCHBAR), 32*KiB) / KiB; + mmio_resource(dev, index++, addr, MCH_BASE_SIZE / KiB); + + return index; +} + +static bool is_imr_enabled(uint32_t imr_base_reg) +{ + return !!(imr_base_reg & (1 << 31)); +} + +static void imr_resource(device_t dev, int idx, uint32_t base, uint32_t mask) +{ + uint32_t base_k, size_k; + /* Bits 28:0 encode the base address bits 38:10, hence the KiB unit. */ + base_k = (base & 0x0fffffff); + /* Bits 28:0 encode the AND mask used for comparison, in KiB. */ + size_k = ((~mask & 0x0fffffff) + 1); + /* + * IMRs sit in lower DRAM. Mark them cacheable, otherwise we run + * out of MTRRs. Memory reserved by IMRs is not usable for host + * so mark it reserved. + */ + reserved_ram_resource(dev, idx, base_k, size_k); +} + +static int mc_add_imr_resources(device_t dev, int index) +{ + uint8_t *mchbar; + size_t i, imr_offset; + uint32_t base, mask; + + mchbar = (void *)(ALIGN_DOWN(get_bar(dev, MCHBAR), 32*KiB)); + + for (i = 0; i < MCH_NUM_IMRS; i ++) { + imr_offset = i * MCH_IMR_PITCH; + base = read32(mchbar + imr_offset + MCHBAR_IMR0BASE); + mask = read32(mchbar + imr_offset + MCHBAR_IMR0MASK); + + if (is_imr_enabled(base)) { + imr_resource(dev, index++, base, mask); + } + } + + return index; +} + + +static int mc_add_dram_resources(device_t dev, int index) +{ + unsigned long base_k, size_k; + uint32_t bgsm, bdsm, tolud, tseg; + uint64_t touud; + + bgsm = ALIGN_DOWN(pci_read_config32(dev, BGSM), MiB); + bdsm = ALIGN_DOWN(pci_read_config32(dev, BDSM), MiB); + tolud = ALIGN_DOWN(pci_read_config32(dev, TOLUD), MiB); + tseg = ALIGN_DOWN(pci_read_config32(dev, TSEG), MiB); + + /* TOUUD is naturally a 64 bit integer */ + touud = pci_read_config32(dev, TOUUD + sizeof(uint32_t)); + touud <<= 32; + touud |= ALIGN_DOWN(pci_read_config32(dev, TOUUD), MiB); + + /* 0 - > 0xa0000: 640kb of DOS memory. Not enough for anybody nowadays */ + ram_resource(dev, index++, 0, 640); + + /* 0xa0000 - 0xbffff: legacy VGA */ + mmio_resource(dev, index++, 640, 128); + + /* 0xc0000 -> 0xfffff: leave without e820 entry, as it has special uses */ + /* 0x100000 -> top_of_ram */ + base_k = 1024; + size_k = (tseg / KiB) - base_k; + ram_resource(dev, index++, base_k, size_k); + + /* TSEG -> BGSM */ + reserved_ram_resource(dev, index++, tseg / KiB, (bgsm - tseg) / KiB); + + /* BGSM -> BDSM */ + mmio_resource(dev, index++, bgsm / KiB, (bdsm - bgsm) / KiB); + + /* BDSM -> TOLUD */ + mmio_resource(dev, index++, bdsm / KiB, (tolud - bdsm) / KiB); + + /* 4G -> TOUUD */ + base_k = 4ULL*GiB / KiB; + size_k = (touud / KiB) - base_k; + ram_resource(dev, index++, base_k, size_k); + + + return index; +} + +static void northbridge_read_resources(device_t dev) +{ + + int index = 0; + /* Read standard PCI resources. */ + pci_dev_read_resources(dev); + + /* Add all fixed MMIO resources. */ + index = mc_add_fixed_mmio_resources(dev, index); + + /* Calculate and add DRAM resources. */ + index = mc_add_dram_resources(dev, index); + + /* Add the isolated memory ranges (IMRs). */ + mc_add_imr_resources(dev, index); + +} + +static struct device_operations northbridge_ops = { + .read_resources = northbridge_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = DEVICE_NOOP, + .enable = DEVICE_NOOP +}; + +static const struct pci_driver northbridge_driver __pci_driver = { + .ops = &northbridge_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_APOLLOLAKE_NB +}; diff --git a/src/soc/intel/glk/p2sb.c b/src/soc/intel/glk/p2sb.c new file mode 100644 index 0000000..7834e38 --- /dev/null +++ b/src/soc/intel/glk/p2sb.c @@ -0,0 +1,74 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2016 Google Inc. + * + * 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 <arch/io.h> +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <rules.h> +#include <soc/iomap.h> +#include <soc/pci_devs.h> +#include <soc/pci_ids.h> +#include <soc/p2sb.h> + +#define P2SB_E0 0xe0 +#define HIDE_BIT (1 << 0) + +static void p2sb_set_hide_bit(int hide) +{ + struct device *dev; + const uint16_t reg = P2SB_E0 + 1; + const uint8_t mask = HIDE_BIT; + uint8_t val; + + dev = P2SB_DEV; + + val = pci_read_config8(dev, reg); + val &= ~mask; + if (hide) + val |= mask; + pci_write_config8(dev, reg, val); +} + +void p2sb_unhide(void) +{ + p2sb_set_hide_bit(0); +} + +void p2sb_hide(void) +{ + p2sb_set_hide_bit(HIDE_BIT); +} + +static void read_resources(struct device *dev) +{ + /* + * There's only one resource on the P2SB device. It's also already + * manually set to a fixed address in earlier boot stages. + */ + mmio_resource(dev, PCI_BASE_ADDRESS_0, P2SB_BAR / KiB, P2SB_SIZE / KiB); +} + +static const struct device_operations device_ops = { + .read_resources = read_resources, + .set_resources = DEVICE_NOOP, +}; + +static const struct pci_driver pmc __pci_driver = { + .ops = &device_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_APOLLOLAKE_P2SB, +}; diff --git a/src/soc/intel/glk/pmc.c b/src/soc/intel/glk/pmc.c new file mode 100644 index 0000000..7e5cf35 --- /dev/null +++ b/src/soc/intel/glk/pmc.c @@ -0,0 +1,157 @@ +/* + * 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. + */ + +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <console/console.h> +#include <cpu/x86/smm.h> +#include <soc/iomap.h> +#include <soc/pci_ids.h> +#include <soc/gpio.h> +#include <soc/pci_devs.h> +#include <soc/pm.h> +#include <timer.h> +#include "chip.h" + +/* + * The ACPI IO BAR (offset 0x20) is not PCI compliant. We've observed cases + * where the BAR reads back as 0, but the IO window is open. This also means + * that it will not respond to PCI probing. In the event that probing the BAR + * fails, we still need to create a resource for it. + */ +static void read_resources(device_t dev) +{ + struct resource *res; + pci_dev_read_resources(dev); + + res = new_resource(dev, PCI_BASE_ADDRESS_4); + res->base = ACPI_PMIO_BASE; + res->size = ACPI_PMIO_SIZE; + res->flags = IORESOURCE_IO | IORESOURCE_ASSIGNED | IORESOURCE_FIXED; +} + +/* + * Part 2: + * Resources are assigned, and no other device was given an IO resource to + * overlap with our ACPI BAR. But because the resource is FIXED, + * pci_dev_set_resources() will not store it for us. We need to do that + * explicitly. + */ +static void set_resources(device_t dev) +{ + struct resource *res; + + pci_dev_set_resources(dev); + + res = find_resource(dev, PCI_BASE_ADDRESS_4); + pci_write_config32(dev, res->index, res->base); + dev->command |= PCI_COMMAND_IO; + res->flags |= IORESOURCE_STORED; + report_resource_stored(dev, res, " ACPI BAR"); +} + +static void pch_set_acpi_mode(void) +{ + if (IS_ENABLED(CONFIG_HAVE_SMI_HANDLER) && !acpi_is_wakeup_s3()) { + printk(BIOS_DEBUG, "Disabling ACPI via APMC:"); + outb(APM_CNT_ACPI_DISABLE, APM_CNT); + printk(BIOS_DEBUG, "Done.\n"); + } +} + +static int choose_slp_s3_assertion_width(int width_usecs) +{ + int i; + static const struct { + int max_width; + int value; + } slp_s3_settings[] = { + { + .max_width = 60, + .value = SLP_S3_ASSERT_60_USEC, + }, + { + .max_width = 1 * USECS_PER_MSEC, + .value = SLP_S3_ASSERT_1_MSEC, + }, + { + .max_width = 50 * USECS_PER_MSEC, + .value = SLP_S3_ASSERT_50_MSEC, + }, + { + .max_width = 2 * USECS_PER_SEC, + .value = SLP_S3_ASSERT_2_SEC, + }, + }; + + for (i = 0; i < ARRAY_SIZE(slp_s3_settings); i++) { + if (width_usecs <= slp_s3_settings[i].max_width) + break; + } + + /* Provide conservative default if nothing set in devicetree + * or requested assertion width too large. */ + if (width_usecs <= 0 || i == ARRAY_SIZE(slp_s3_settings)) + i = ARRAY_SIZE(slp_s3_settings) - 1; + + printk(BIOS_DEBUG, "SLP S3 assertion width: %d usecs\n", + slp_s3_settings[i].max_width); + + return slp_s3_settings[i].value; +} + +static void set_slp_s3_assertion_width(int width_usecs) +{ + uint32_t reg; + uintptr_t gen_pmcon3 = get_pmc_mmio_bar() + GEN_PMCON3; + int setting = choose_slp_s3_assertion_width(width_usecs); + + reg = read32((void *)gen_pmcon3); + reg &= ~SLP_S3_ASSERT_MASK; + reg |= setting << SLP_S3_ASSERT_WIDTH_SHIFT; + write32((void *)gen_pmcon3, reg); +} + +static void pmc_init(struct device *dev) +{ + const struct soc_intel_glk_config *cfg = dev->chip_info; + + /* Set up GPE configuration */ + pmc_gpe_init(); + fixup_power_state(); + pch_set_acpi_mode(); + + if (cfg != NULL) + set_slp_s3_assertion_width(cfg->slp_s3_assertion_width_usecs); + + /* Log power state */ + pch_log_state(); +} + +static const struct device_operations device_ops = { + .read_resources = read_resources, + .set_resources = set_resources, + .enable_resources = pci_dev_enable_resources, + .init = &pmc_init, +}; + +static const struct pci_driver pmc __pci_driver = { + .ops = &device_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_APOLLOLAKE_PMC, +}; diff --git a/src/soc/intel/glk/pmutil.c b/src/soc/intel/glk/pmutil.c new file mode 100644 index 0000000..2f2e24f --- /dev/null +++ b/src/soc/intel/glk/pmutil.c @@ -0,0 +1,543 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 Google Inc. + * Copyright (C) 2015-2016 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; 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. + */ + +#define __SIMPLE_DEVICE__ + +#include <arch/acpi.h> +#include <arch/io.h> +#include <console/console.h> +#include <cbmem.h> +#include <rules.h> +#include <device/pci_def.h> +#include <halt.h> +#include <soc/iomap.h> +#include <soc/pci_devs.h> +#include <soc/pm.h> +#include <device/device.h> +#include <device/pci.h> +#include <vboot/vboot_common.h> +#include "chip.h" + +static uintptr_t read_pmc_mmio_bar(void) +{ + uint32_t bar = pci_read_config32(PMC_DEV, PCI_BASE_ADDRESS_0); + return bar & ~PCI_BASE_ADDRESS_MEM_ATTR_MASK; +} + +uintptr_t get_pmc_mmio_bar(void) +{ + return read_pmc_mmio_bar(); +} + +static void print_num_status_bits(int num_bits, uint32_t status, + const char * const bit_names[]) +{ + int i; + + if (!status) + return; + + for (i = num_bits - 1; i >= 0; i--) { + if (status & (1 << i)) { + if (bit_names[i]) + printk(BIOS_DEBUG, "%s ", bit_names[i]); + else + printk(BIOS_DEBUG, "BIT%d ", i); + } + } +} + +static uint32_t print_smi_status(uint32_t smi_sts) +{ + static const char * const smi_sts_bits[] = { + [BIOS_SMI_STS] = "BIOS", + [LEGACY_USB_SMI_STS] = "LEGACY USB", + [SLP_SMI_STS] = "SLP_SMI", + [APM_SMI_STS] = "APM", + [SWSMI_TMR_SMI_STS] = "SWSMI_TMR", + [FAKE_PM1_SMI_STS] = "PM1", + [GPIO_SMI_STS]= "GPIO_SMI", + [GPIO_UNLOCK_SMI_STS]= "GPIO_UNLOCK_SSMI", + [MC_SMI_STS] = "MCSMI", + [TCO_SMI_STS] = "TCO", + [PERIODIC_SMI_STS] = "PERIODIC", + [SERIRQ_SMI_STS] = "SERIRQ", + [SMBUS_SMI_STS] = "SMBUS_SMI", + [XHCI_SMI_STS] = "XHCI", + [HSMBUS_SMI_STS] = "HOST_SMBUS", + [SCS_SMI_STS] = "SCS", + [PCIE_SMI_STS] = "PCI_EXP_SMI", + [SCC2_SMI_STS] = "SCC2", + [SPI_SSMI_STS] = "SPI_SSMI", + [SPI_SMI_STS] = "SPI", + [PMC_OCP_SMI_STS] = "OCP_CSE", + }; + + if (!smi_sts) + return 0; + + printk(BIOS_DEBUG, "SMI_STS: "); + print_num_status_bits(ARRAY_SIZE(smi_sts_bits), smi_sts, smi_sts_bits); + printk(BIOS_DEBUG, "\n"); + + return smi_sts; +} + +static uint32_t reset_smi_status(void) +{ + uint32_t smi_sts = inl(ACPI_PMIO_BASE + SMI_STS); + outl(smi_sts, ACPI_PMIO_BASE + SMI_STS); + return smi_sts; +} + +uint32_t clear_smi_status(void) +{ + uint32_t sts = reset_smi_status(); + + /* + * Check for power button status if nothing else is indicating an SMI + * and SMIs aren't turned into SCIs. Apparently, there is no PM1 status + * bit in the SMI status register. That makes things difficult for + * determining if the power button caused an SMI. + */ + if (sts == 0 && !(inl(ACPI_PMIO_BASE + PM1_CNT) & SCI_EN)) { + uint16_t pm1_sts = inw(ACPI_PMIO_BASE + PM1_STS); + + /* Fake PM1 status bit if power button pressed. */ + if (pm1_sts & PWRBTN_STS) + sts |= (1 << FAKE_PM1_SMI_STS); + } + + return print_smi_status(sts); +} + +uint32_t get_smi_en(void) +{ + return inl(ACPI_PMIO_BASE + SMI_EN); +} + +void enable_smi(uint32_t mask) +{ + uint32_t smi_en = inl(ACPI_PMIO_BASE + SMI_EN); + smi_en |= mask; + outl(smi_en, ACPI_PMIO_BASE + SMI_EN); +} + +void disable_smi(uint32_t mask) +{ + uint32_t smi_en = inl(ACPI_PMIO_BASE + SMI_EN); + smi_en &= ~mask; + outl(smi_en, ACPI_PMIO_BASE + SMI_EN); +} + +void enable_pm1_control(uint32_t mask) +{ + uint32_t pm1_cnt = inl(ACPI_PMIO_BASE + PM1_CNT); + pm1_cnt |= mask; + outl(pm1_cnt, ACPI_PMIO_BASE + PM1_CNT); +} + +void disable_pm1_control(uint32_t mask) +{ + uint32_t pm1_cnt = inl(ACPI_PMIO_BASE + PM1_CNT); + pm1_cnt &= ~mask; + outl(pm1_cnt, ACPI_PMIO_BASE + PM1_CNT); +} + +static uint16_t reset_pm1_status(void) +{ + uint16_t pm1_sts = inw(ACPI_PMIO_BASE + PM1_STS); + outw(pm1_sts, ACPI_PMIO_BASE + PM1_STS); + return pm1_sts; +} + +static uint16_t print_pm1_status(uint16_t pm1_sts) +{ + static const char * const pm1_sts_bits[] = { + [0] = "TMROF", + [5] = "GBL", + [8] = "PWRBTN", + [10] = "RTC", + [11] = "PRBTNOR", + [13] = "USB", + [14] = "PCIEXPWAK", + [15] = "WAK", + }; + + if (!pm1_sts) + return 0; + + printk(BIOS_SPEW, "PM1_STS: "); + print_num_status_bits(ARRAY_SIZE(pm1_sts_bits), pm1_sts, pm1_sts_bits); + printk(BIOS_SPEW, "\n"); + + return pm1_sts; +} + +uint16_t clear_pm1_status(void) +{ + return print_pm1_status(reset_pm1_status()); +} + +void enable_pm1(uint16_t events) +{ + outw(events, ACPI_PMIO_BASE + PM1_EN); +} + +static uint32_t print_tco_status(uint32_t tco_sts) +{ + static const char * const tco_sts_bits[] = { + [3] = "TIMEOUT", + [17] = "SECOND_TO", + }; + + if (!tco_sts) + return 0; + + printk(BIOS_DEBUG, "TCO_STS: "); + print_num_status_bits(ARRAY_SIZE(tco_sts_bits), tco_sts, tco_sts_bits); + printk(BIOS_DEBUG, "\n"); + + return tco_sts; +} + +static uint32_t reset_tco_status(void) +{ + uint32_t tco_sts = inl(ACPI_PMIO_BASE + TCO_STS); + uint32_t tco_en = inl(ACPI_PMIO_BASE + TCO1_CNT); + + outl(tco_sts, ACPI_PMIO_BASE + TCO_STS); + return tco_sts & tco_en; +} + +uint32_t clear_tco_status(void) +{ + return print_tco_status(reset_tco_status()); +} + +void enable_gpe(uint32_t mask) +{ + uint32_t gpe0a_en = inl(ACPI_PMIO_BASE + GPE0_EN(0)); + gpe0a_en |= mask; + outl(gpe0a_en, ACPI_PMIO_BASE + GPE0_EN(0)); +} + +void disable_gpe(uint32_t mask) +{ + uint32_t gpe0a_en = inl(ACPI_PMIO_BASE + GPE0_EN(0)); + gpe0a_en &= ~mask; + outl(gpe0a_en, ACPI_PMIO_BASE + GPE0_EN(0)); +} + +void disable_all_gpe(void) +{ + disable_gpe(~0); +} + +/* Clear the gpio gpe0 status bits in ACPI registers */ +void clear_gpi_gpe_sts(void) +{ + int i; + + for (i = 1; i < GPE0_REG_MAX; i++) { + uint32_t gpe_sts = inl(ACPI_PMIO_BASE + GPE0_STS(i)); + outl(gpe_sts, ACPI_PMIO_BASE + GPE0_STS(i)); + } +} + +static uint32_t reset_gpe_status(void) +{ + uint32_t gpe_sts = inl(ACPI_PMIO_BASE + GPE0_STS(0)); + outl(gpe_sts, ACPI_PMIO_BASE + GPE0_STS(0)); + return gpe_sts; +} + +static uint32_t print_gpe_sts(uint32_t gpe_sts) +{ + static const char * const gpe_sts_bits[] = { + [0] = "PCIE_SCI", + [2] = "SWGPE", + [3] = "PCIE_WAKE0", + [4] = "PUNIT", + [6] = "PCIE_WAKE1", + [7] = "PCIE_WAKE2", + [8] = "PCIE_WAKE3", + [9] = "PCI_EXP", + [10] = "BATLOW", + [11] = "CSE_PME", + [12] = "XDCI_PME", + [13] = "XHCI_PME", + [14] = "AVS_PME", + [15] = "GPIO_TIER1_SCI", + [16] = "SMB_WAK", + [17] = "SATA_PME", + }; + + if (!gpe_sts) + return gpe_sts; + + printk(BIOS_DEBUG, "GPE0a_STS: "); + print_num_status_bits(ARRAY_SIZE(gpe_sts_bits), gpe_sts, gpe_sts_bits); + printk(BIOS_DEBUG, "\n"); + + return gpe_sts; +} + +uint32_t clear_gpe_status(void) +{ + return print_gpe_sts(reset_gpe_status()); +} + +/* Read and clear GPE status (defined in arch/acpi.h) */ +int acpi_get_gpe(int gpe) +{ + int bank; + uint32_t mask, sts; + + if (gpe < 0 || gpe > GPE0_DW3_31) + return -1; + + bank = gpe / 32; + mask = 1 << (gpe % 32); + + sts = inl(ACPI_PMIO_BASE + GPE0_STS(bank)); + if (sts & mask) { + outl(mask, ACPI_PMIO_BASE + GPE0_STS(bank)); + return 1; + } + return 0; +} + +void clear_pmc_status(void) +{ + uint32_t prsts; + uint32_t gen_pmcon1; + uintptr_t pmc_bar0 = read_pmc_mmio_bar(); + + prsts = read32((void *)(pmc_bar0 + PRSTS)); + gen_pmcon1 = read32((void *)(pmc_bar0 + GEN_PMCON1)); + + /* Clear the status bits. The RPS field is cleared on a 0 write. */ + write32((void *)(pmc_bar0 + GEN_PMCON1), gen_pmcon1 & ~RPS); + write32((void *)(pmc_bar0 + PRSTS), prsts); +} + + +/* Return 0, 3, or 5 to indicate the previous sleep state. */ +int chipset_prev_sleep_state(struct chipset_power_state *ps) +{ + /* Default to S0. */ + int prev_sleep_state = ACPI_S0; + + if (ps->pm1_sts & WAK_STS) { + switch (acpi_sleep_from_pm1(ps->pm1_cnt)) { + case ACPI_S3: + if (IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)) + prev_sleep_state = ACPI_S3; + break; + case ACPI_S5: + prev_sleep_state = ACPI_S5; + break; + } + + /* Clear SLP_TYP. */ + outl(ps->pm1_cnt & ~(SLP_TYP), ACPI_PMIO_BASE + PM1_CNT); + } + return prev_sleep_state; +} + +/* + * This function re-writes the gpe0 register values in power state + * cbmem variable. After system wakes from sleep state internal PMC logic + * writes default values in GPE_CFG register which gives a wrong offset to + * calculate the wake reason. So we need to set it again to the routing + * table as per the devicetree. + */ +void fixup_power_state(void) +{ + int i; + struct chipset_power_state *ps; + + ps = cbmem_find(CBMEM_ID_POWER_STATE); + if (ps == NULL) + return; + + for (i = 0; i < GPE0_REG_MAX; i++) { + ps->gpe0_sts[i] = inl(ACPI_PMIO_BASE + GPE0_STS(i)); + ps->gpe0_en[i] = inl(ACPI_PMIO_BASE + GPE0_EN(i)); + printk(BIOS_DEBUG, "gpe0_sts[%d]: %08x gpe0_en[%d]: %08x\n", + i, ps->gpe0_sts[i], i, ps->gpe0_en[i]); + } +} + +/* returns prev_sleep_state */ +int fill_power_state(struct chipset_power_state *ps) +{ + int i; + uintptr_t pmc_bar0 = read_pmc_mmio_bar(); + + ps->pm1_sts = inw(ACPI_PMIO_BASE + PM1_STS); + ps->pm1_en = inw(ACPI_PMIO_BASE + PM1_EN); + ps->pm1_cnt = inl(ACPI_PMIO_BASE + PM1_CNT); + ps->tco_sts = inl(ACPI_PMIO_BASE + TCO_STS); + ps->prsts = read32((void *)(pmc_bar0 + PRSTS)); + ps->gen_pmcon1 =read32((void *)(pmc_bar0 + GEN_PMCON1)); + ps->gen_pmcon2 = read32((void *)(pmc_bar0 + GEN_PMCON2)); + ps->gen_pmcon3 = read32((void *)(pmc_bar0 + GEN_PMCON3)); + + ps->prev_sleep_state = chipset_prev_sleep_state(ps); + + printk(BIOS_DEBUG, "pm1_sts: %04x pm1_en: %04x pm1_cnt: %08x\n", + ps->pm1_sts, ps->pm1_en, ps->pm1_cnt); + printk(BIOS_DEBUG, "prsts: %08x tco_sts: %08x\n", + ps->prsts, ps->tco_sts); + printk(BIOS_DEBUG, + "gen_pmcon1: %08x gen_pmcon2: %08x gen_pmcon3: %08x\n", + ps->gen_pmcon1, ps->gen_pmcon2, ps->gen_pmcon3); + printk(BIOS_DEBUG, "smi_en: %08x smi_sts: %08x\n", + inl(ACPI_PMIO_BASE + SMI_EN), inl(ACPI_PMIO_BASE + SMI_STS)); + for (i=0; i < GPE0_REG_MAX; i++) { + ps->gpe0_sts[i] = inl(ACPI_PMIO_BASE + GPE0_STS(i)); + ps->gpe0_en[i] = inl(ACPI_PMIO_BASE + GPE0_EN(i)); + printk(BIOS_DEBUG, "gpe0_sts[%d]: %08x gpe0_en[%d]: %08x\n", + i, ps->gpe0_sts[i], i, ps->gpe0_en[i]); + } + printk(BIOS_DEBUG, "prev_sleep_state %d\n", ps->prev_sleep_state); + return ps->prev_sleep_state; +} + +int vboot_platform_is_resuming(void) +{ + if (!(inw(ACPI_PMIO_BASE + PM1_STS) & WAK_STS)) + return 0; + + return acpi_sleep_from_pm1(inl(ACPI_PMIO_BASE + PM1_CNT)) == ACPI_S3; +} + +/* + * If possible, lock 0xcf9. Once the register is locked, it can't be changed. + * This lock is reset on cold boot, hard reset, soft reset and Sx. + */ +void global_reset_lock(void) +{ + uintptr_t etr = read_pmc_mmio_bar() + ETR; + uint32_t reg; + + reg = read32((void *)etr); + if (reg & CF9_LOCK) + return; + reg |= CF9_LOCK; + write32((void *)etr, reg); +} + +/* + * Enable or disable global reset. If global reset is enabled, hard reset and + * soft reset will trigger global reset, where both host and TXE are reset. + * This is cleared on cold boot, hard reset, soft reset and Sx. + */ +void global_reset_enable(bool enable) +{ + uintptr_t etr = read_pmc_mmio_bar() + ETR; + uint32_t reg; + + reg = read32((void *)etr); + reg = enable ? reg | CF9_GLB_RST : reg & ~CF9_GLB_RST; + write32((void *)etr, reg); +} + +/* + * The PM1 control is set to S5 when vboot requests a reboot because the power + * state code above may not have collected its data yet. Therefore, set it to + * S5 when vboot requests a reboot. That's necessary if vboot fails in the + * resume path and requests a reboot. This prevents a reboot loop where the + * error is continually hit on the failing vboot resume path. + */ +void vboot_platform_prepare_reboot(void) +{ + const uint16_t port = ACPI_PMIO_BASE + PM1_CNT; + outl((inl(port) & ~(SLP_TYP)) | (SLP_TYP_S5 << SLP_TYP_SHIFT), port); +} + +void poweroff(void) +{ + enable_pm1_control(SLP_EN | (SLP_TYP_S5 << SLP_TYP_SHIFT)); + + /* + * Setting SLP_TYP_S5 in PM1 triggers SLP_SMI, which is handled by SMM + * to transition to S5 state. If halt is called in SMM, then it prevents + * the SMI handler from being triggered and system never enters S5. + */ + if (!ENV_SMM) + halt(); +} + +void pmc_gpe_init(void) +{ + uint32_t gpio_cfg = 0; + uint32_t gpio_cfg_reg; + uint8_t dw1, dw2, dw3; + ROMSTAGE_CONST struct soc_intel_glk_config *config; + + /* Look up the device in devicetree */ + ROMSTAGE_CONST struct device *dev = dev_find_slot(0, NB_DEVFN); + if (!dev || !dev->chip_info) { + printk(BIOS_ERR, "BUG! Could not find SOC devicetree config\n"); + return; + } + config = dev->chip_info; + + uintptr_t pmc_bar = get_pmc_mmio_bar(); + + const uint32_t gpio_cfg_mask = + (GPE0_DWX_MASK << GPE0_DW1_SHIFT) | + (GPE0_DWX_MASK << GPE0_DW2_SHIFT) | + (GPE0_DWX_MASK << GPE0_DW3_SHIFT); + + /* Assign to local variable */ + dw1 = config->gpe0_dw1; + dw2 = config->gpe0_dw2; + dw3 = config->gpe0_dw3; + + /* Making sure that bad values don't bleed into the other fields */ + dw1 &= GPE0_DWX_MASK; + dw2 &= GPE0_DWX_MASK; + dw3 &= GPE0_DWX_MASK; + + /* Route the GPIOs to the GPE0 block. Determine that all values + * are different, and if they aren't use the reset values. + * DW0 is reserved/unused */ + if (dw1 == dw2 || dw2 == dw3) { + printk(BIOS_INFO, "PMC: Using default GPE route.\n"); + gpio_cfg = read32((void *)pmc_bar + GPIO_GPE_CFG); + + dw1 = (gpio_cfg >> GPE0_DW1_SHIFT) & GPE0_DWX_MASK; + dw2 = (gpio_cfg >> GPE0_DW2_SHIFT) & GPE0_DWX_MASK; + dw3 = (gpio_cfg >> GPE0_DW3_SHIFT) & GPE0_DWX_MASK; + } else { + gpio_cfg |= (uint32_t)dw1 << GPE0_DW1_SHIFT; + gpio_cfg |= (uint32_t)dw2 << GPE0_DW2_SHIFT; + gpio_cfg |= (uint32_t)dw3 << GPE0_DW3_SHIFT; + } + + gpio_cfg_reg = read32((void *)pmc_bar + GPIO_GPE_CFG) & ~gpio_cfg_mask; + gpio_cfg_reg |= gpio_cfg & gpio_cfg_mask; + + write32((void *)pmc_bar + GPIO_GPE_CFG, gpio_cfg_reg); + + /* Set the routes in the GPIO communities as well. */ + gpio_route_gpe(dw1, dw2, dw3); +} diff --git a/src/soc/intel/glk/reset.c b/src/soc/intel/glk/reset.c new file mode 100644 index 0000000..3e62d81 --- /dev/null +++ b/src/soc/intel/glk/reset.c @@ -0,0 +1,73 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2016 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 <console/console.h> +#include <delay.h> +#include <fsp/util.h> +#include <reset.h> +#include <soc/heci.h> +#include <soc/pm.h> +#include <timer.h> + +#define CSE_WAIT_MAX_MS 1000 + +void global_reset(void) +{ + global_reset_enable(1); + hard_reset(); +} + +void reset_prepare(void) +{ + struct stopwatch sw; + + /* + * If CSE state is something else than 'normal', it is probably in some + * recovery state. In this case there is no point in waiting for it to + * get ready so we cross fingers and reset. + */ + if (!heci_cse_normal()) { + printk(BIOS_DEBUG, "CSE is not in normal state, resetting\n"); + return; + } + + /* Reset if CSE is ready */ + if (heci_cse_done()) + return; + + printk(BIOS_SPEW, "CSE is not yet ready, waiting\n"); + stopwatch_init_msecs_expire(&sw, CSE_WAIT_MAX_MS); + while (!heci_cse_done()) { + if (stopwatch_expired(&sw)) { + printk(BIOS_SPEW, "CSE timed out. Resetting\n"); + return; + } + mdelay(1); + } + printk(BIOS_SPEW, "CSE took %lu ms\n", stopwatch_duration_msecs(&sw)); +} + +void chipset_handle_reset(uint32_t status) +{ + switch(status) { + case FSP_STATUS_RESET_REQUIRED_5: /* Global Reset */ + global_reset(); + break; + default: + printk(BIOS_ERR, "unhandled reset type %x\n", status); + die("unknown reset type"); + break; + } +} diff --git a/src/soc/intel/glk/romstage.c b/src/soc/intel/glk/romstage.c new file mode 100644 index 0000000..e5b50da --- /dev/null +++ b/src/soc/intel/glk/romstage.c @@ -0,0 +1,192 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 Intel Corp. + * (Written by Alexandru Gagniuc alexandrux.gagniuc@intel.com for Intel Corp.) + * (Written by Andrey Petrov andrey.petrov@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. + */ + +#include <arch/cpu.h> +#include <arch/early_variables.h> +#include <arch/io.h> +#include <arch/symbols.h> +#include <assert.h> +#include <bootmode.h> +#include <cbfs.h> +#include <cbmem.h> +#include <console/console.h> +#include <cpu/x86/mtrr.h> +#include <device/pci_def.h> +#include <device/resource.h> +#include <fsp/api.h> +#include <fsp/util.h> +#include <soc/iomap.h> +#include <soc/northbridge.h> +#include <soc/pci_devs.h> +#include <soc/pm.h> +#include <soc/romstage.h> +#include <soc/spi.h> +#include <soc/uart.h> +#include <string.h> +#include <timestamp.h> + +static struct chipset_power_state power_state CAR_GLOBAL; + +/* High Performance Event Timer Configuration */ +#define P2SB_HPTC 0x60 +#define P2SB_HPTC_ADDRESS_ENABLE (1 << 7) +/* + * ADDRESS_SELECT ENCODING_RANGE + * 0 0xFED0 0000 - 0xFED0 03FF + * 1 0xFED0 1000 - 0xFED0 13FF + * 2 0xFED0 2000 - 0xFED0 23FF + * 3 0xFED0 3000 - 0xFED0 33FF + */ +#define P2SB_HPTC_ADDRESS_SELECT_0 (0 << 0) +#define P2SB_HPTC_ADDRESS_SELECT_1 (1 << 0) +#define P2SB_HPTC_ADDRESS_SELECT_2 (2 << 0) +#define P2SB_HPTC_ADDRESS_SELECT_3 (3 << 0) + +/* + * Enables several BARs and devices which are needed for memory init + * - MCH_BASE_ADDR is needed in order to talk to the memory controller + * - HPET is enabled because FSP wants to store a pointer to global data in the + * HPET comparator register + */ +static void soc_early_romstage_init(void) +{ + /* Set MCH base address and enable bit */ + pci_write_config32(NB_DEV_ROOT, MCHBAR, MCH_BASE_ADDR | 1); + + /* Enable decoding for HPET. Needed for FSP global pointer storage */ + pci_write_config8(P2SB_DEV, P2SB_HPTC, P2SB_HPTC_ADDRESS_SELECT_0 | + P2SB_HPTC_ADDRESS_ENABLE); +} + +static void disable_watchdog(void) +{ + uint32_t reg; + + /* Stop TCO timer */ + reg = inl(ACPI_PMIO_BASE + TCO1_CNT); + reg |= TCO_TMR_HLT; + outl(reg, ACPI_PMIO_BASE + TCO1_CNT); +} + +static void migrate_power_state(int is_recovery) +{ + struct chipset_power_state *ps_cbmem; + struct chipset_power_state *ps_car; + + ps_car = car_get_var_ptr(&power_state); + ps_cbmem = cbmem_add(CBMEM_ID_POWER_STATE, sizeof(*ps_cbmem)); + + if (ps_cbmem == NULL) { + printk(BIOS_DEBUG, "Unable to add power state to cbmem!\n"); + return; + } + memcpy(ps_cbmem, ps_car, sizeof(*ps_cbmem)); +} +ROMSTAGE_CBMEM_INIT_HOOK(migrate_power_state); + +asmlinkage void car_stage_entry(void) +{ + struct postcar_frame pcf; + uintptr_t top_of_ram; + bool s3wake; + struct chipset_power_state *ps = car_get_var_ptr(&power_state); + + timestamp_add_now(TS_START_ROMSTAGE); + + soc_early_romstage_init(); + disable_watchdog(); + + console_init(); + + s3wake = fill_power_state(ps) == ACPI_S3; + fsp_memory_init(s3wake); + if (postcar_frame_init(&pcf, 1*KiB)) + die("Unable to initialize postcar frame.\n"); + + mainboard_save_dimm_info(); + + /* + * We need to make sure ramstage will be run cached. At this point exact + * location of ramstage in cbmem is not known. Instruct postcar to cache + * 16 megs under cbmem top which is a safe bet to cover ramstage. + */ + top_of_ram = (uintptr_t) cbmem_top(); + /* cbmem_top() needs to be at least 16 MiB aligned */ + assert(ALIGN_DOWN(top_of_ram, 16*MiB) == top_of_ram); + postcar_frame_add_mtrr(&pcf, top_of_ram - 16*MiB, 16*MiB, MTRR_TYPE_WRBACK); + + /* Cache the memory-mapped boot media. */ + if (IS_ENABLED(CONFIG_BOOT_DEVICE_MEMORY_MAPPED)) + postcar_frame_add_mtrr(&pcf, -CONFIG_ROM_SIZE, CONFIG_ROM_SIZE, + MTRR_TYPE_WRPROT); + + run_postcar_phase(&pcf); +} + +static void fill_console_params(FSPM_UPD *mupd) +{ + if (IS_ENABLED(CONFIG_CONSOLE_SERIAL)) { + mupd->FspmConfig.SerialDebugPortDevice = CONFIG_UART_FOR_CONSOLE; + /* use MMIO port type */ + mupd->FspmConfig.SerialDebugPortType = 2; + /* use 4 byte register stride */ + mupd->FspmConfig.SerialDebugPortStrideSize = 2; + /* used only for port type set to external */ + mupd->FspmConfig.SerialDebugPortAddress = 0; + } else { + mupd->FspmConfig.SerialDebugPortType = 0; + } +} + +void platform_fsp_memory_init_params_cb(FSPM_UPD *mupd, uint32_t version) +{ + fill_console_params(mupd); + mainboard_memory_init_params(mupd); + + /* Do NOT let FSP do any GPIO pad configuration */ + mupd->FspmConfig.PreMemGpioTablePtr = (uintptr_t) NULL; + + /* + * Tell CSE we do not need to use Ring Buffer Protocol (RBP) to fetch + * firmware for us if we are using memory-mapped SPI. This lets CSE + * state machine transition to next boot state, so that it can function + * as designed. + */ + mupd->FspmConfig.SkipCseRbp = + IS_ENABLED(CONFIG_BOOT_DEVICE_MEMORY_MAPPED); +} + +__attribute__ ((weak)) +void mainboard_memory_init_params(FSPM_UPD *mupd) +{ + printk(BIOS_DEBUG, "WEAK: %s/%s called\n", __FILE__, __func__); +} + +__attribute__ ((weak)) +void mainboard_save_dimm_info(void) +{ + printk(BIOS_DEBUG, "WEAK: %s/%s called\n", __FILE__, __func__); +} + +int get_sw_write_protect_state(void) +{ + uint8_t status; + + /* Return unprotected status if status read fails. */ + return spi_read_status(&status) ? 0 : !!(status & 0x80); +} diff --git a/src/soc/intel/glk/smi.c b/src/soc/intel/glk/smi.c new file mode 100644 index 0000000..3ad33fd --- /dev/null +++ b/src/soc/intel/glk/smi.c @@ -0,0 +1,87 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2016 Intel Corp. + * (Written by Lance Zhao lijian.zhao@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. + */ + +#include <device/device.h> +#include <device/pci.h> +#include <console/console.h> +#include <arch/io.h> +#include <cpu/cpu.h> +#include <cpu/x86/cache.h> +#include <cpu/x86/smm.h> +#include <string.h> +#include <soc/pm.h> +#include <soc/smm.h> + +void southbridge_smm_clear_state(void) +{ + printk(BIOS_DEBUG, "Initializing Southbridge SMI..."); + + if (get_smi_en() & APMC_EN) { + printk(BIOS_INFO, "SMI# handler already enabled?\n"); + return; + } + + printk(BIOS_DEBUG, "Done\n"); + + /* Dump and clear status registers */ + clear_smi_status(); + clear_pm1_status(); + clear_tco_status(); + clear_gpe_status(); +} + +void southbridge_smm_enable_smi(void) +{ + printk(BIOS_DEBUG, "Enabling SMIs.\n"); + /* Configure events */ + enable_pm1(PWRBTN_EN | GBL_EN); + disable_gpe(PME_B0_EN); + + /* Enable SMI generation */ + enable_smi(APMC_EN | SLP_SMI_EN | GBL_SMI_EN | EOS | GPIO_EN); +} + +void southbridge_clear_smi_status(void) +{ + /* Clear SMI status */ + clear_smi_status(); + + /* Clear PM1 status */ + clear_pm1_status(); + + /* Set EOS bit so other SMIs can occur. */ + enable_smi(EOS); +} + +void smm_setup_structures(void *gnvs, void *tcg, void *smi1) +{ + /* + * Issue SMI to set the gnvs pointer in SMM. + * tcg and smi1 are unused. + * + * EAX = APM_CNT_GNVS_UPDATE + * EBX = gnvs pointer + * EDX = APM_CNT + */ + asm volatile ( + "outb %%al, %%dx\n\t" + : /* ignore result */ + : "a" (APM_CNT_GNVS_UPDATE), + "b" ((u32)gnvs), + "d" (APM_CNT) + ); +} diff --git a/src/soc/intel/glk/smihandler.c b/src/soc/intel/glk/smihandler.c new file mode 100644 index 0000000..b84e5cb --- /dev/null +++ b/src/soc/intel/glk/smihandler.c @@ -0,0 +1,68 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 Google Inc. + * Copyright (C) 2015-2016 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; 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 <arch/hlt.h> +#include <arch/io.h> +#include <console/console.h> +#include <cpu/x86/cache.h> +#include <cpu/x86/smm.h> +#include <device/pci_def.h> +#include <elog.h> +#include <soc/nvs.h> +#include <soc/pm.h> +#include <soc/gpio.h> +#include <soc/iomap.h> +#include <soc/pci_devs.h> +#include <soc/intel/common/smi.h> +#include <spi-generic.h> +#include <stdint.h> +#include <stdlib.h> +#include <soc/smm.h> + +int smm_disable_busmaster(device_t dev) +{ + if (dev == PMC_DEV) + return 0; + return 1; +} + +const struct smm_save_state_ops *get_smm_save_state_ops(void) +{ + return &em64t100_smm_ops; +} + +void __attribute__((weak)) +mainboard_smi_gpi_handler(const struct gpi_status *sts) { } + +static void southbridge_smi_gpi(const struct smm_save_state_ops *save_state_ops) +{ + struct gpi_status smi_sts; + + gpi_clear_get_smi_status(&smi_sts); + mainboard_smi_gpi_handler(&smi_sts); + + /* Clear again after mainboard handler */ + gpi_clear_get_smi_status(&smi_sts); +} + +const smi_handler_t southbridge_smi[32] = { + [SLP_SMI_STS] = southbridge_smi_sleep, + [APM_SMI_STS] = southbridge_smi_apmc, + [FAKE_PM1_SMI_STS] = southbridge_smi_pm1, + [GPIO_SMI_STS] = southbridge_smi_gpi, + [TCO_SMI_STS] = southbridge_smi_tco, + [PERIODIC_SMI_STS] = southbridge_smi_periodic, +}; diff --git a/src/soc/intel/glk/spi.c b/src/soc/intel/glk/spi.c new file mode 100644 index 0000000..139d36c --- /dev/null +++ b/src/soc/intel/glk/spi.c @@ -0,0 +1,395 @@ +/* + * 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. + */ + +#define __SIMPLE_DEVICE__ + +#include <arch/early_variables.h> +#include <arch/io.h> +#include <device/device.h> +#include <device/pci.h> +#include <soc/pci_devs.h> +#include <soc/spi.h> +#include <spi_flash.h> +#include <stdlib.h> +#include <string.h> + +/* Helper to create a SPI context on API entry. */ +#define BOILERPLATE_CREATE_CTX(ctx) \ + struct spi_ctx real_ctx; \ + struct spi_ctx *ctx = &real_ctx; \ + _spi_get_ctx(ctx) + +/* + * Anything that's not success is <0. Provided solely for readability, as these + * constants are not used outside this file. + */ +enum errors { + SUCCESS = 0, + E_NOT_IMPLEMENTED = -1, + E_TIMEOUT = -2, + E_HW_ERROR = -3, + E_ARGUMENT = -4, +}; + +/* Reduce data-passing burden by grouping transaction data in a context. */ +struct spi_ctx { + uintptr_t mmio_base; + device_t pci_dev; + uint32_t hsfsts_on_last_error; +}; + +static void _spi_get_ctx(struct spi_ctx *ctx) +{ + uint32_t bar; + + /* FIXME: use device definition */ + ctx->pci_dev = SPI_DEV; + + bar = pci_read_config32(ctx->pci_dev, PCI_BASE_ADDRESS_0); + ctx->mmio_base = bar & ~PCI_BASE_ADDRESS_MEM_ATTR_MASK; + ctx->hsfsts_on_last_error = 0; +} + +/* Read register from the SPI controller. 'reg' is the register offset. */ +static uint32_t _spi_ctrlr_reg_read(struct spi_ctx *ctx, uint16_t reg) +{ + uintptr_t addr = ALIGN_DOWN(ctx->mmio_base + reg, 4); + return read32((void *)addr); +} + +uint32_t spi_ctrlr_reg_read(uint16_t reg) +{ + BOILERPLATE_CREATE_CTX(ctx); + return _spi_ctrlr_reg_read(ctx, reg); +} + +/* Write to register in the SPI controller. 'reg' is the register offset. */ +static void _spi_ctrlr_reg_write(struct spi_ctx *ctx, uint16_t reg, + uint32_t val) +{ + uintptr_t addr = ALIGN_DOWN(ctx->mmio_base + reg, 4); + write32((void *)addr, val); + +} + +/* + * The hardware datasheet is not clear on what HORD values actually do. It + * seems that HORD_SFDP provides access to the first 8 bytes of the SFDP, which + * is the signature and revision fields. HORD_JEDEC provides access to the + * actual flash parameters, and is most likely what you want to use when + * probing the flash from software. + * It's okay to rely on SFPD, since the SPI controller requires an SFDP 1.5 or + * newer compliant SPI chip. + * NOTE: Due to the register layout of the hardware, all accesses will be + * aligned to a 4 byte boundary. + */ +static uint32_t read_spi_sfdp_param(struct spi_ctx *ctx, uint16_t sfdp_reg) +{ + uint32_t ptinx_index = sfdp_reg & SPIBAR_PTINX_IDX_MASK; + _spi_ctrlr_reg_write(ctx, SPIBAR_PTINX, + ptinx_index | SPIBAR_PTINX_HORD_JEDEC); + return _spi_ctrlr_reg_read(ctx, SPIBAR_PTDATA); +} + +/* Fill FDATAn FIFO in preparation for a write transaction. */ +static void fill_xfer_fifo(struct spi_ctx *ctx, const void *data, size_t len) +{ + len = min(len, SPIBAR_FDATA_FIFO_SIZE); + + /* YES! memcpy() works. FDATAn does not require 32-bit accesses. */ + memcpy((void*)(ctx->mmio_base + SPIBAR_FDATA(0)), data, len); +} + +/* Drain FDATAn FIFO after a read transaction populates data. */ +static void drain_xfer_fifo(struct spi_ctx *ctx, void *dest, size_t len) +{ + len = min(len, SPIBAR_FDATA_FIFO_SIZE); + + /* YES! memcpy() works. FDATAn does not require 32-bit accesses. */ + memcpy(dest, (void*)(ctx->mmio_base + SPIBAR_FDATA(0)), len); +} + +/* Fire up a transfer using the hardware sequencer. */ +static void start_hwseq_xfer(struct spi_ctx *ctx, uint32_t hsfsts_cycle, + uint32_t flash_addr, size_t len) +{ + /* Make sure all W1C status bits get cleared. */ + uint32_t hsfsts = SPIBAR_HSFSTS_W1C_BITS; + /* Set up transaction parameters. */ + hsfsts |= hsfsts_cycle & SPIBAR_HSFSTS_FCYCLE_MASK; + hsfsts |= SPIBAR_HSFSTS_FBDC(len - 1); + + _spi_ctrlr_reg_write(ctx, SPIBAR_FADDR, flash_addr); + _spi_ctrlr_reg_write(ctx, SPIBAR_HSFSTS_CTL, + hsfsts | SPIBAR_HSFSTS_FGO); +} + +static void print_xfer_error(struct spi_ctx *ctx, const char *failure_reason, + uint32_t flash_addr) +{ + printk(BIOS_ERR, "SPI Transaction %s at flash offset %x.\n" + "\tHSFSTS = 0x%08x\n", + failure_reason, flash_addr, ctx->hsfsts_on_last_error); +} + +static int wait_for_hwseq_xfer(struct spi_ctx *ctx) +{ + uint32_t hsfsts; + do { + hsfsts = _spi_ctrlr_reg_read(ctx, SPIBAR_HSFSTS_CTL); + + if (hsfsts & SPIBAR_HSFSTS_FCERR) { + ctx->hsfsts_on_last_error = hsfsts; + return E_HW_ERROR; + } + /* TODO: set up timer and abort on timeout */ + } while (!(hsfsts & SPIBAR_HSFSTS_FDONE)); + + return SUCCESS; +} + +/* Execute SPI transfer. This is a blocking call. */ +static int exec_sync_hwseq_xfer(struct spi_ctx *ctx, uint32_t hsfsts_cycle, + uint32_t flash_addr, size_t len) +{ + int ret; + start_hwseq_xfer(ctx, hsfsts_cycle, flash_addr, len); + ret = wait_for_hwseq_xfer(ctx); + if (ret != SUCCESS) { + const char *reason = (ret == E_TIMEOUT) ? "timeout" : "error"; + print_xfer_error(ctx, reason, flash_addr); + } + return ret; +} + +unsigned int spi_crop_chunk(unsigned int cmd_len, unsigned int buf_len) +{ + return MIN(buf_len, SPIBAR_FDATA_FIFO_SIZE); +} + +int spi_xfer(struct spi_slave *slave, const void *dout, + unsigned int bytesout, void *din, unsigned int bytesin) +{ + printk(BIOS_DEBUG, "NOT IMPLEMENTED: %s() !!!\n", __func__); + return E_NOT_IMPLEMENTED; +} + +/* + * Write-protection status for BIOS region (BIOS_CONTROL register): + * EISS/WPD bits 00 01 10 11 + * -- -- -- -- + * normal mode RO RW RO RO + * SMM mode RO RW RO RW + */ +void spi_init(void) +{ + uint32_t bios_ctl; + + BOILERPLATE_CREATE_CTX(ctx); + + bios_ctl = pci_read_config32(ctx->pci_dev, SPIBAR_BIOS_CONTROL); + bios_ctl |= SPIBAR_BIOS_CONTROL_WPD; + bios_ctl &= ~SPIBAR_BIOS_CONTROL_EISS; + + /* Enable Prefetching and caching. */ + bios_ctl |= SPIBAR_BIOS_CONTROL_PREFETCH_ENABLE; + bios_ctl &= ~SPIBAR_BIOS_CONTROL_CACHE_DISABLE; + + pci_write_config32(ctx->pci_dev, SPIBAR_BIOS_CONTROL, bios_ctl); +} + +int spi_claim_bus(struct spi_slave *slave) +{ + /* There's nothing we need to to here. */ + return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ + /* No magic needed here. */ +} + +static int nuclear_spi_erase(struct spi_flash *flash, uint32_t offset, size_t len) +{ + int ret; + size_t erase_size; + uint32_t erase_cycle; + + BOILERPLATE_CREATE_CTX(ctx); + + if (!IS_ALIGNED(offset, 4 * KiB) || !IS_ALIGNED(len, 4 * KiB)) { + printk(BIOS_ERR, "BUG! SPI erase region not sector aligned.\n"); + return E_ARGUMENT; + } + + while (len) { + if (IS_ALIGNED(offset, 64 * KiB) && (len >= 64 * KiB)) { + erase_size = 64 * KiB; + erase_cycle = SPIBAR_HSFSTS_CYCLE_64K_ERASE; + } else { + erase_size = 4 * KiB; + erase_cycle = SPIBAR_HSFSTS_CYCLE_4K_ERASE; + } + printk(BIOS_SPEW, "Erasing flash addr %x + %zu KiB\n", + offset, erase_size / KiB); + + ret = exec_sync_hwseq_xfer(ctx, erase_cycle, offset, 0); + if (ret != SUCCESS) + return ret; + + offset += erase_size; + len -= erase_size; + } + + return SUCCESS; +} + +static int nuclear_spi_read(struct spi_flash *flash, uint32_t addr, size_t len, void *buf) +{ + int ret; + size_t xfer_len; + uint8_t *data = buf; + + BOILERPLATE_CREATE_CTX(ctx); + + while (len) { + xfer_len = min(len, SPIBAR_FDATA_FIFO_SIZE); + + ret = exec_sync_hwseq_xfer(ctx, SPIBAR_HSFSTS_CYCLE_READ, + addr, xfer_len); + if (ret != SUCCESS) + return ret; + + drain_xfer_fifo(ctx, data, xfer_len); + + addr += xfer_len; + data += xfer_len; + len -= xfer_len; + } + + return SUCCESS; +} + +static int nuclear_spi_write(struct spi_flash *flash, + uint32_t addr, size_t len, const void *buf) +{ + int ret; + size_t xfer_len; + const uint8_t *data = buf; + + BOILERPLATE_CREATE_CTX(ctx); + + while (len) { + xfer_len = min(len, SPIBAR_FDATA_FIFO_SIZE); + fill_xfer_fifo(ctx, data, xfer_len); + + ret = exec_sync_hwseq_xfer(ctx, SPIBAR_HSFSTS_CYCLE_WRITE, + addr, xfer_len); + if (ret != SUCCESS) + return ret; + + addr += xfer_len; + data += xfer_len; + len -= xfer_len; + } + + return SUCCESS; +} + +static int nuclear_spi_status(struct spi_flash *flash, uint8_t *reg) +{ + printk(BIOS_DEBUG, "NOT IMPLEMENTED: %s() !!!\n", __func__); + return E_NOT_IMPLEMENTED; +} + +static struct spi_slave boot_spi CAR_GLOBAL; +static struct spi_flash boot_flash CAR_GLOBAL; + +/* + * We can't use FDOC and FDOD to read FLCOMP, as previous platforms did. + * For details see: + * Ch 31, SPI: p. 194 + * The size of the flash component is always taken from density field in the + * SFDP table. FLCOMP.C0DEN is no longer used by the Flash Controller. + */ +static struct spi_flash *nuclear_flash_probe(struct spi_slave *spi) +{ + BOILERPLATE_CREATE_CTX(ctx); + struct spi_flash *flash; + uint32_t flash_bits; + + flash = car_get_var_ptr(&boot_flash); + + /* + * bytes = (bits + 1) / 8; + * But we need to do the addition in a way which doesn't overflow for + * 4 Gbit devices (flash_bits == 0xffffffff). + */ + /* FIXME: Don't hardcode 0x04 ? */ + flash_bits = read_spi_sfdp_param(ctx, 0x04); + flash->size = (flash_bits >> 3) + 1; + + flash->spi = spi; + flash->name = "Apollolake hardware sequencer"; + + /* Can erase both 4 KiB and 64 KiB chunks. Declare the smaller size. */ + flash->sector_size = 4 * KiB; + /* + * FIXME: Get erase+cmd, and status_cmd from SFDP. + * + * flash->erase_cmd = ??? + * flash->status_cmd = ??? + */ + + flash->write = nuclear_spi_write; + flash->erase = nuclear_spi_erase; + flash->read = nuclear_spi_read; + flash->status = nuclear_spi_status; + + return flash; +} + +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs) +{ + BOILERPLATE_CREATE_CTX(ctx); + + /* This is special hardware. We expect bus 0 and CS line 0 here. */ + if ((bus != 0) || (cs != 0)) + return NULL; + + struct spi_slave *slave = car_get_var_ptr(&boot_spi); + + slave->bus = bus; + slave->cs = cs; + slave->programmer_specific_probe = nuclear_flash_probe; + slave->force_programmer_specific = 1; + + return slave; +} + +int spi_read_status(uint8_t *status) +{ + BOILERPLATE_CREATE_CTX(ctx); + + if (exec_sync_hwseq_xfer(ctx, SPIBAR_HSFSTS_CYCLE_RD_STATUS, 0, + sizeof(*status)) != SUCCESS) + return -1; + + drain_xfer_fifo(ctx, status, sizeof(*status)); + + return 0; +} diff --git a/src/soc/intel/glk/tsc_freq.c b/src/soc/intel/glk/tsc_freq.c new file mode 100644 index 0000000..9dd1dea --- /dev/null +++ b/src/soc/intel/glk/tsc_freq.c @@ -0,0 +1,25 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 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 <cpu/x86/msr.h> +#include <cpu/x86/tsc.h> +#include <soc/cpu.h> + +unsigned long tsc_freq_mhz(void) +{ + msr_t msr = rdmsr(MSR_PLATFORM_INFO); + return (BASE_CLOCK_MHZ * ((msr.lo >> 8) & 0xff)); +} diff --git a/src/soc/intel/glk/uart.c b/src/soc/intel/glk/uart.c new file mode 100644 index 0000000..7b50a21 --- /dev/null +++ b/src/soc/intel/glk/uart.c @@ -0,0 +1,61 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 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. + */ + +/* + * The sole purpose of this driver is to avoid BAR to be changed during + * resource allocation. Since configuration space is just 32 bytes it + * shouldn't cause any fragmentation. + */ + +#include <console/uart.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <soc/pci_ids.h> +#include <soc/pci_devs.h> + +static void aplk_uart_read_resources(struct device *dev) +{ + pci_dev_read_resources(dev); + + if ((IS_ENABLED(CONFIG_SOC_UART_DEBUG) && + dev->path.pci.devfn == _LPSS_PCI_DEVFN(UART, + CONFIG_UART_FOR_CONSOLE))) { + /* will override existing resource. */ + fixed_mem_resource(dev, PCI_BASE_ADDRESS_0, + CONFIG_CONSOLE_UART_BASE_ADDRESS >> 10, 4, 0); + } +} + +static struct device_operations uart_ops = { + .read_resources = aplk_uart_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = pci_dev_init, + .enable = DEVICE_NOOP +}; + +static const unsigned short uart_ids[] = { + PCI_DEVICE_ID_APOLLOLAKE_UART0, PCI_DEVICE_ID_APOLLOLAKE_UART1, + PCI_DEVICE_ID_APOLLOLAKE_UART2, PCI_DEVICE_ID_APOLLOLAKE_UART3, + 0 +}; + +static const struct pci_driver uart_driver __pci_driver = { + .ops = &uart_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .devices = uart_ids +}; diff --git a/src/soc/intel/glk/uart_early.c b/src/soc/intel/glk/uart_early.c new file mode 100644 index 0000000..ea7d902 --- /dev/null +++ b/src/soc/intel/glk/uart_early.c @@ -0,0 +1,86 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 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. + */ + +#include <console/uart.h> +#include <device/pci.h> +#include <soc/gpio.h> +#include <soc/uart.h> +#include <soc/pci_devs.h> + +static void lpss_uart_write(uint16_t reg, uint32_t val) +{ + uintptr_t base = CONFIG_CONSOLE_UART_BASE_ADDRESS | reg; + write32((void *)base, val); +} + +static inline int invalid_uart_for_console(void) +{ + /* There are actually only 2 UARTS, and they are named UART1 and + * UART2. They live at pci functions 1 and 2 respectively. */ + if (CONFIG_UART_FOR_CONSOLE > 2 || CONFIG_UART_FOR_CONSOLE < 1) + return 1; + return 0; +} + +void lpss_console_uart_init(void) +{ + uint32_t clk_sel; + device_t uart = _LPSS_PCI_DEV(UART, CONFIG_UART_FOR_CONSOLE & 3); + + if (invalid_uart_for_console()) + return; + + /* Enable BAR0 for the UART -- this is where the 8250 registers hide */ + pci_write_config32(uart, PCI_BASE_ADDRESS_0, + CONFIG_CONSOLE_UART_BASE_ADDRESS); + + /* Enable memory access and bus master */ + pci_write_config32(uart, PCI_COMMAND, + PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + + /* Take UART out of reset */ + lpss_uart_write(UART_RESET, UART_RESET_UART_EN); + + /* These values get us a 1.836 MHz clock (ideally we want 1.843 MHz) */ + clk_sel = UART_CLK_DIV_N(0x7fff) | UART_CLK_DIV_M(0x025a); + /* Set M and N divisor inputs and enable clock */ + lpss_uart_write(UART_CLK, clk_sel | UART_CLK_UPDATE); + lpss_uart_write(UART_CLK, clk_sel | UART_CLK_EN); + +} + +uintptr_t uart_platform_base(int idx) +{ + return (CONFIG_CONSOLE_UART_BASE_ADDRESS); +} + +static const struct pad_config uart_gpios[] = { +}; + +void soc_console_uart_init(void) +{ + /* Get a 0-based pad index. See invalid_uart_for_console() above. */ + //const int pad_index = CONFIG_UART_FOR_CONSOLE - 1; + + if (invalid_uart_for_console()) + return; + + /* Configure the 2 pads per UART. */ + //gpio_configure_pads(&uart_gpios[pad_index * 2], 2); + + lpss_console_uart_init(); +} diff --git a/src/soc/intel/glk/xhci.c b/src/soc/intel/glk/xhci.c new file mode 100644 index 0000000..7b3cb46 --- /dev/null +++ b/src/soc/intel/glk/xhci.c @@ -0,0 +1,105 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2016 Google Inc. + * + * 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 <arch/io.h> +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <soc/pci_devs.h> +#include <soc/pci_ids.h> +#include <timer.h> + +#define DUAL_ROLE_CFG0 0x80d8 +# define DRD_CONFIG_MASK (0x3 << 0) +# define DRD_CONFIG_DYNAMIC (0x0 << 0) +# define DRD_CONFIG_HOST (0x1 << 0) +# define DRD_CONFIG_DEVICE (0x2 << 0) +# define SW_VBUS_VALID_MASK (1 << 24) +# define SW_VBUS_DEASSERT_VALID (0 << 24) +# define SW_VBUS_ASSERT_VALID (1 << 24) +# define SW_IDPIN_EN_MASK (1 << 21) +# define SW_IDPIN_DIS (0 << 21) +# define SW_IDPIN_EN (1 << 21) +# define SW_IDPIN_MASK (1 << 20) +# define SW_IDPIN_HOST (0 << 20) +# define SW_IDPIN_DEVICE (1 << 20) +#define DUAL_ROLE_CFG1 0x80dc +# define DRD_MODE_MASK (1 << 29) +# define DRD_MODE_DEVICE (0 << 29) +# define DRD_MODE_HOST (1 << 29) + +static void configure_host_mode_port0(struct device *dev) +{ + uint32_t *cfg0; + uint32_t *cfg1; + const struct resource *res; + uint32_t reg; + struct device *xdci_dev = XDCI_DEV; + struct stopwatch sw; + + /* + * Only default to host mode if the xdci device is present and + * enabled. If it's disabled assume the switch was already done + * in FSP. + */ + if (xdci_dev == NULL || !xdci_dev->enabled) + return; + + printk(BIOS_INFO, "Putting port 0 into host mode.\n"); + + res = find_resource(dev, PCI_BASE_ADDRESS_0); + + cfg0 = (void *)(uintptr_t)(res->base + DUAL_ROLE_CFG0); + cfg1 = (void *)(uintptr_t)(res->base + DUAL_ROLE_CFG1); + + reg = read32(cfg0); + reg &= ~(DRD_CONFIG_MASK | SW_IDPIN_EN_MASK | SW_IDPIN_MASK); + reg &= ~(SW_VBUS_VALID_MASK); + reg |= DRD_CONFIG_DYNAMIC | SW_IDPIN_EN | SW_IDPIN_HOST; + reg |= SW_VBUS_DEASSERT_VALID; + write32(cfg0, reg); + + stopwatch_init_msecs_expire(&sw, 10); + + /* Wait for the host mode status bit. */ + while ((read32(cfg1) & DRD_MODE_MASK) != DRD_MODE_HOST) { + if (stopwatch_expired(&sw)) { + printk(BIOS_INFO, "Timed out waiting for host mode.\n"); + break; + } + } + + printk(BIOS_INFO, "XHCI port 0 host switch over took %lu ms\n", + stopwatch_duration_msecs(&sw)); +} + +static void xhci_init(struct device *dev) +{ + configure_host_mode_port0(dev); +} + +static const struct device_operations device_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = xhci_init, +}; + +static const struct pci_driver pmc __pci_driver = { + .ops = &device_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_APOLLOLAKE_XHCI, +};