diff options
author | Stefan Reinauer <stefan.reinauer@coreboot.org> | 2016-05-03 15:53:33 -0700 |
---|---|---|
committer | Stefan Reinauer <stefan.reinauer@coreboot.org> | 2016-05-17 21:38:17 +0200 |
commit | 4bab6e79b078c76d0a42883c4b4c9c68615d5a1e (patch) | |
tree | 2c7dda58587f464fa1baee712c95bb48c924ff76 /src/soc/intel | |
parent | 083da160af4a0e3a76506af59477f105d78b9683 (diff) |
intel/sch: Merge northbridge and southbridge in src/soc
Change-Id: I6ea9b9d2353c0d767c837e6d629b45f23b306f6e
Signed-off-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Reviewed-on: https://review.coreboot.org/14599
Tested-by: build bot (Jenkins)
Reviewed-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Reviewed-by: Vladimir Serbinenko <phcoder@gmail.com>
Diffstat (limited to 'src/soc/intel')
42 files changed, 6020 insertions, 0 deletions
diff --git a/src/soc/intel/sch/Kconfig b/src/soc/intel/sch/Kconfig new file mode 100644 index 0000000000..6bbb168782 --- /dev/null +++ b/src/soc/intel/sch/Kconfig @@ -0,0 +1,56 @@ +# +# This file is part of the coreboot project. +# +# Copyright (C) 2007-2010 coresystems GmbH +# +# 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. +# + +config SOC_INTEL_SCH + bool + select MMCONF_SUPPORT + select LATE_CBMEM_INIT + select INTEL_GMA_ACPI + select SOUTHBRIDGE_INTEL_COMMON + select HAVE_USBDEBUG + select HAVE_HARD_RESET + select HAVE_SMI_HANDLER + +if SOC_INTEL_SCH + +config VGA_BIOS_ID + string + default "8086,8108" + +config EHCI_BAR + hex + default 0xfef00000 + +config HAVE_CMC + bool "Add a CMC state machine binary" + help + Select this option to add a CMC state machine binary to + the resulting coreboot image. + + Note: Without this binary coreboot will not work + +config CMC_FILE + string "Intel CMC path and filename" + depends on HAVE_CMC + default "cmc.bin" + help + The path and filename of the file to use as CMC state machine + binary. + +config HPET_MIN_TICKS + hex + default 0x80 + +endif diff --git a/src/soc/intel/sch/Makefile.inc b/src/soc/intel/sch/Makefile.inc new file mode 100644 index 0000000000..0a3cfd6d7d --- /dev/null +++ b/src/soc/intel/sch/Makefile.inc @@ -0,0 +1,48 @@ +# +# This file is part of the coreboot project. +# +# Copyright (C) 2007-2010 coresystems GmbH +# +# 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. +# + +ifeq ($(CONFIG_SOC_INTEL_SCH),y) + +ramstage-y += northbridge.c +ramstage-y += gma.c +ramstage-y += port_access.c +ramstage-y += acpi.c + +ramstage-y += south.c +ramstage-y += audio.c +ramstage-y += lpc.c +ramstage-y += ide.c +ramstage-y += pcie.c +ramstage-y += usb.c +ramstage-y += usb_ehci.c +ramstage-y += usb_client.c +ramstage-y += mmc.c +ramstage-y += smbus.c + +ramstage-y += reset.c + +ramstage-$(CONFIG_HAVE_SMI_HANDLER) += smi.c +ramstage-$(CONFIG_HAVE_SMI_HANDLER) += ../../../cpu/x86/smm/smmrelocate.S +smm-$(CONFIG_HAVE_SMI_HANDLER) += smihandler.c + +ramstage-srcs += src/mainboard/$(MAINBOARDDIR)/hda_verb.c + +# We don't ship that, but booting without it is bound to fail +cbfs-files-$(CONFIG_HAVE_CMC) += cmc.bin +cmc.bin-file := $(call strip_quotes,$(CONFIG_CMC_FILE)) +cmc.bin-type := raw +cmc.bin-position := 0xfffd0000 + +endif diff --git a/src/soc/intel/sch/acpi.c b/src/soc/intel/sch/acpi.c new file mode 100644 index 0000000000..2c941d868e --- /dev/null +++ b/src/soc/intel/sch/acpi.c @@ -0,0 +1,72 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * + * 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 <types.h> +#include <string.h> +#include <console/console.h> +#include <arch/acpi.h> +#include <arch/acpigen.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <cbmem.h> +#include <arch/acpigen.h> +#include <cpu/cpu.h> +#include "sch.h" + +unsigned long acpi_fill_mcfg(unsigned long current) +{ + device_t dev; + u32 pciexbar = 0; + u32 pciexbar_reg; + int max_buses; + + dev = dev_find_device(0x8086, 0x27a0, 0); + if (!dev) + return current; + + pciexbar_reg = pci_read_config32(dev, 0x48); + + /* MMCFG not supported or not enabled. */ + if (!(pciexbar_reg & (1 << 0))) + return current; + + switch ((pciexbar_reg >> 1) & 3) { + case 0: /* 256MB */ + pciexbar = pciexbar_reg & ((1 << 31) | (1 << 30) | (1 << 29) | + (1 << 28)); + max_buses = 256; + break; + case 1: /* 128M */ + pciexbar = pciexbar_reg & ((1 << 31) | (1 << 30) | (1 << 29) | + (1 << 28) | (1 << 27)); + max_buses = 128; + break; + case 2: /* 64M */ + pciexbar = pciexbar_reg & ((1 << 31) | (1 << 30) | (1 << 29) | + (1 << 28) | (1 << 27) | (1 << 26)); + max_buses = 64; + break; + default: /* RSVD */ + return current; + } + + if (!pciexbar) + return current; + + current += acpi_create_mcfg_mmconfig((acpi_mcfg_mmconfig_t *) current, + pciexbar, 0x0, 0x0, max_buses - 1); + return current; +} diff --git a/src/soc/intel/sch/acpi/ac97.asl b/src/soc/intel/sch/acpi/ac97.asl new file mode 100644 index 0000000000..e1db234a63 --- /dev/null +++ b/src/soc/intel/sch/acpi/ac97.asl @@ -0,0 +1,33 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * + * 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 i82801G AC'97 Audio and Modem */ + +// Intel AC'97 Audio 0:1e.2 + +Device (AUD0) +{ + Name (_ADR, 0x001e0002) +} + +// Intel AC'97 Modem 0:1e.3 + +Device (MODM) +{ + Name (_ADR, 0x001e0003) + + Name (_PRW, Package(){ 5, 4 }) +} diff --git a/src/soc/intel/sch/acpi/audio.asl b/src/soc/intel/sch/acpi/audio.asl new file mode 100644 index 0000000000..9e0d997482 --- /dev/null +++ b/src/soc/intel/sch/acpi/audio.asl @@ -0,0 +1,30 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * + * 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 i82801G HDA */ + +// Intel High Definition Audio (Azalia) 0:1b.0 + +Device (HDEF) +{ + Name (_ADR, 0x001b0000) + + // Power Resources for Wake + Name (_PRW, Package(){ + 5, // Bit 5 of GPE + 4 // Can wake from S4 state. + }) +} diff --git a/src/soc/intel/sch/acpi/globalnvs.asl b/src/soc/intel/sch/acpi/globalnvs.asl new file mode 100644 index 0000000000..ea53953928 --- /dev/null +++ b/src/soc/intel/sch/acpi/globalnvs.asl @@ -0,0 +1,156 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * + * 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. + */ + +/* Global Variables */ + +Name(\PICM, 0) // IOAPIC/8259 +Name(\DSEN, 1) // Display Output Switching Enable + +/* Global ACPI memory region. This region is used for passing information + * between coreboot (aka "the system bios"), ACPI, and the SMI handler. + * Since we don't know where this will end up in memory at ACPI compile time, + * we have to fix it up in coreboot's ACPI creation phase. + */ + +External(NVSA) +OperationRegion (GNVS, SystemMemory, NVSA, 0x100) +Field (GNVS, ByteAcc, NoLock, Preserve) +{ + /* Miscellaneous */ + Offset (0x00), + OSYS, 16, // 0x00 - Operating System + SMIF, 8, // 0x02 - SMI function + PRM0, 8, // 0x03 - SMI function parameter + PRM1, 8, // 0x04 - SMI function parameter + SCIF, 8, // 0x05 - SCI function + PRM2, 8, // 0x06 - SCI function parameter + PRM3, 8, // 0x07 - SCI function parameter + LCKF, 8, // 0x08 - Global Lock function for EC + PRM4, 8, // 0x09 - Lock function parameter + PRM5, 8, // 0x0a - Lock function parameter + P80D, 32, // 0x0b - Debug port (IO 0x80) value + LIDS, 8, // 0x0f - LID state (open = 1) + PWRS, 8, // 0x10 - Power State (AC = 1) + DBGS, 8, // 0x11 - Debug State + LINX, 8, // 0x12 - Linux OS + DCKN, 8, // 0x13 - PCIe docking state + /* Thermal policy */ + Offset (0x14), + ACTT, 8, // 0x14 - active trip point + PSVT, 8, // 0x15 - passive trip point + TC1V, 8, // 0x16 - passive trip point TC1 + TC2V, 8, // 0x17 - passive trip point TC2 + TSPV, 8, // 0x18 - passive trip point TSP + CRTT, 8, // 0x19 - critical trip point + DTSE, 8, // 0x1a - Digital Thermal Sensor enable + DTS1, 8, // 0x1b - DT sensor 1 + DTS2, 8, // 0x1c - DT sensor 2 + /* Battery Support */ + Offset (0x1e), + BNUM, 8, // 0x1e - number of batteries + B0SC, 8, // 0x1f - BAT0 stored capacity + B1SC, 8, // 0x20 - BAT1 stored capacity + B2SC, 8, // 0x21 - BAT2 stored capacity + B0SS, 8, // 0x22 - BAT0 stored status + B1SS, 8, // 0x23 - BAT1 stored status + B2SS, 8, // 0x24 - BAT2 stored status + /* Processor Identification */ + Offset (0x28), + APIC, 8, // 0x28 - APIC Enabled by coreboot + MPEN, 8, // 0x29 - Multi Processor Enable + PCP0, 8, // 0x2a - PDC CPU/CORE 0 + PCP1, 8, // 0x2b - PDC CPU/CORE 1 + PPCM, 8, // 0x2c - Max. PPC state + /* Super I/O & CMOS config */ + Offset (0x32), + NATP, 8, // 0x32 - ... + /* Integrated Graphics Device */ + Offset (0x3c), + IGDS, 8, // 0x3c - IGD state (primary = 1) + TLST, 8, // 0x3d - Display Toggle List pointer + CADL, 8, // 0x3e - Currently Attached Devices List + PADL, 8, // 0x3f - Previously Attached Devices List + CSTE, 16, // 0x40 - Current display state + NSTE, 16, // 0x42 - Next display state + SSTE, 16, // 0x44 - Set display state + Offset (0x46), + NDID, 8, // 0x46 - Number of Device IDs + DID1, 32, // 0x47 - Device ID 1 + DID2, 32, // 0x4b - Device ID 2 + DID3, 32, // 0x4f - Device ID 3 + DID4, 32, // 0x53 - Device ID 4 + DID5, 32, // 0x57 - Device ID 5 + /* Backlight Control */ + Offset (0x64), + BLCS, 8, // 0x64 - Backlight control possible? + BRTL, 8, // 0x65 - Brightness Level + ODDS, 8, // 0x66 + /* Ambient Light Sensors */ + Offset (0x6e), + ALSE, 8, // 0x6e - ALS enable + ALAF, 8, // 0x6f - Ambient light adjustment factor + LLOW, 8, // 0x70 - LUX Low + LHIH, 8, // 0x71 - LUX High + /* EMA */ + Offset (0x78), + EMAE, 8, // 0x78 - EMA enable + EMAP, 16, // 0x79 - EMA pointer + EMAL, 16, // 0x7b - EMA length + /* MEF */ + Offset (0x82), + MEFE, 8, // 0x82 - MEF enable + /* TPM support */ + Offset (0x8c), + TPMP, 8, // 0x8c - TPM + TPME, 8, // 0x8d - TPM enable + /* SATA */ + Offset (0x96), + GTF0, 56, // 0x96 - GTF task file buffer for port 0 + GTF1, 56, // 0x9d - GTF task file buffer for port 1 + GTF2, 56, // 0xa4 - GTF task file buffer for port 2 + IDEM, 8, // 0xab - IDE mode (compatible / enhanced) + IDET, 8, // 0xac - IDE + /* IGD OpRegion */ + Offset (0xb4), + ASLB, 32, // 0xb4 - IGD OpRegion Base Address + IBTT, 8, // 0xb8 - IGD boot panel device + IPAT, 8, // 0xb9 - IGD panel type cmos option + ITVF, 8, // 0xba - IGD TV format cmos option + ITVM, 8, // 0xbb - IGD TV minor format option + IPSC, 8, // 0xbc - IGD panel scaling + IBLC, 8, // 0xbd - IGD BLC config + IBIA, 8, // 0xbe - IGD BIA config + ISSC, 8, // 0xbf - IGD SSC config + I409, 8, // 0xc0 - IGD 0409 modified settings + I509, 8, // 0xc1 - IGD 0509 modified settings + I609, 8, // 0xc2 - IGD 0609 modified settings + I709, 8, // 0xc3 - IGD 0709 modified settings + IDMM, 8, // 0xc4 - IGD DVMT Mode + IDMS, 8, // 0xc5 - IGD DVMT memory size + IF1E, 8, // 0xc6 - IGD function 1 enable + HVCO, 8, // 0xc7 - IGD HPLL VCO + NXD1, 32, // 0xc8 - IGD _DGS next DID1 + NXD2, 32, // 0xcc - IGD _DGS next DID2 + NXD3, 32, // 0xd0 - IGD _DGS next DID3 + NXD4, 32, // 0xd4 - IGD _DGS next DID4 + NXD5, 32, // 0xd8 - IGD _DGS next DID5 + NXD6, 32, // 0xdc - IGD _DGS next DID6 + NXD7, 32, // 0xe0 - IGD _DGS next DID7 + NXD8, 32, // 0xe4 - IGD _DGS next DID8 + /* Mainboard Specific (TODO move elsewhere) */ + Offset (0xf0), + DOCK, 8, // 0xf0 - Docking Status +} diff --git a/src/soc/intel/sch/acpi/hostbridge.asl b/src/soc/intel/sch/acpi/hostbridge.asl new file mode 100644 index 0000000000..67bee8c37a --- /dev/null +++ b/src/soc/intel/sch/acpi/hostbridge.asl @@ -0,0 +1,233 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * + * 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/ioapic.h> + +Name(_HID,EISAID("PNP0A08")) // PCIe +Name(_CID,EISAID("PNP0A03")) // PCI + +Name(_ADR, 0) +Name(_BBN, 0) + +Device (MCHC) +{ + Name(_ADR, 0x00000000) // 0:0.0 + + OperationRegion(MCHP, PCI_Config, 0x00, 0x100) + Field (MCHP, DWordAcc, NoLock, Preserve) + { + Offset (0x40), // EPBAR + EPEN, 1, // Enable + , 11, // + EPBR, 20, // EPBAR + + Offset (0x44), // MCHBAR + MHEN, 1, // Enable + , 13, // + MHBR, 18, // MCHBAR + + Offset (0x48), // PCIe BAR + PXEN, 1, // Enable + PXSZ, 2, // BAR size + , 23, // + PXBR, 6, // PCIe BAR + + Offset (0x4c), // DMIBAR + DMEN, 1, // Enable + , 11, // + DMBR, 20, // DMIBAR + + // ... + + Offset (0x90), // PAM0 + , 4, + PM0H, 2, + , 2, + Offset (0x91), // PAM1 + PM1L, 2, + , 2, + PM1H, 2, + , 2, + Offset (0x92), // PAM2 + PM2L, 2, + , 2, + PM2H, 2, + , 2, + Offset (0x93), // PAM3 + PM3L, 2, + , 2, + PM3H, 2, + , 2, + Offset (0x94), // PAM4 + PM4L, 2, + , 2, + PM4H, 2, + , 2, + Offset (0x95), // PAM5 + PM5L, 2, + , 2, + PM5H, 2, + , 2, + Offset (0x96), // PAM6 + PM6L, 2, + , 2, + PM6H, 2, + , 2, + + Offset (0x9c), // Top of Low Used Memory + , 3, + TLUD, 5, + + Offset (0xa0), // Top of Used Memory + TOM, 16, + } + +} + + +// Current Resource Settings +Name (MCRS, ResourceTemplate() +{ + // Bus Numbers + WordBusNumber (ResourceProducer, MinFixed, MaxFixed, PosDecode, + 0x0000, 0x0000, 0x00ff, 0x0000, 0x0100,,, PB00) + + // IO Region 0 + DWordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, + 0x0000, 0x0000, 0x0cf7, 0x0000, 0x0cf8,,, PI00) + + // PCI Config Space + Io (Decode16, 0x0cf8, 0x0cf8, 0x0001, 0x0008) + + // IO Region 1 + DWordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, + 0x0000, 0x0d00, 0xffff, 0x0000, 0xf300,,, PI01) + + // VGA memory (0xa0000-0xbffff) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0x000a0000, 0x000bffff, 0x00000000, + 0x00020000,,, ASEG) + + // OPROM reserved (0xc0000-0xc3fff) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0x000c0000, 0x000c3fff, 0x00000000, + 0x00004000,,, OPR0) + + // OPROM reserved (0xc4000-0xc7fff) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0x000c4000, 0x000c7fff, 0x00000000, + 0x00004000,,, OPR1) + + // OPROM reserved (0xc8000-0xcbfff) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0x000c8000, 0x000cbfff, 0x00000000, + 0x00004000,,, OPR2) + + // OPROM reserved (0xcc000-0xcffff) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0x000cc000, 0x000cffff, 0x00000000, + 0x00004000,,, OPR3) + + // OPROM reserved (0xd0000-0xd3fff) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0x000d0000, 0x000d3fff, 0x00000000, + 0x00004000,,, OPR4) + + // OPROM reserved (0xd4000-0xd7fff) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0x000d4000, 0x000d7fff, 0x00000000, + 0x00004000,,, OPR5) + + // OPROM reserved (0xd8000-0xdbfff) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0x000d8000, 0x000dbfff, 0x00000000, + 0x00004000,,, OPR6) + + // OPROM reserved (0xdc000-0xdffff) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0x000dc000, 0x000dffff, 0x00000000, + 0x00004000,,, OPR7) + + // BIOS Extension (0xe0000-0xe3fff) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0x000e0000, 0x000e3fff, 0x00000000, + 0x00004000,,, ESG0) + + // BIOS Extension (0xe4000-0xe7fff) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0x000e4000, 0x000e7fff, 0x00000000, + 0x00004000,,, ESG1) + + // BIOS Extension (0xe8000-0xebfff) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0x000e8000, 0x000ebfff, 0x00000000, + 0x00004000,,, ESG2) + + // BIOS Extension (0xec000-0xeffff) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0x000ec000, 0x000effff, 0x00000000, + 0x00004000,,, ESG3) + + // System BIOS (0xf0000-0xfffff) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0x000f0000, 0x000fffff, 0x00000000, + 0x00010000,,, FSEG) + + // PCI Memory Region (Top of memory-0xfebfffff) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0x00000000, 0xfebfffff, 0x00000000, + IO_APIC_ADDR,,, PM01) + + // TPM Area (0xfed40000-0xfed44fff) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, 0xfed40000, 0xfed44fff, 0x00000000, + 0x00005000,,, TPMR) +}) + +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) + + // Fix up PCI memory region: + // Enter actual TOLUD. The TOLUD register contains bits 27-31 of + // the top of memory address. + ShiftLeft (^MCHC.TLUD, 27, PMIN) + Add(Subtract(PMAX, PMIN), 1, PLEN) + + Return (MCRS) +} + +/* IRQ assignment is mainboard specific. Get it from mainboard ACPI code */ +#include "acpi/northbridge_pci_irqs.asl" diff --git a/src/soc/intel/sch/acpi/igd.asl b/src/soc/intel/sch/acpi/igd.asl new file mode 100644 index 0000000000..dcc782f0b8 --- /dev/null +++ b/src/soc/intel/sch/acpi/igd.asl @@ -0,0 +1,73 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * + * 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 (GFX0) +{ + Name (_ADR, 0x00020000) + + OperationRegion (GFXC, PCI_Config, 0x00, 0x0100) + Field (GFXC, DWordAcc, NoLock, Preserve) + { + Offset (0x10), + BAR0, 64 + } + + OperationRegion (GFRG, SystemMemory, And(BAR0, 0xfffffffffffffff0), 0x400000) + Field (GFRG, DWordAcc, NoLock, Preserve) + { + Offset (0x61250), + CR1, 32, + BCLV, 16, + BCLM, 16, + } + + Name (BRIG, Package (0x12) + { + 0x61, + 0x61, + 0x2, + 0x4, + 0x5, + 0x7, + 0x9, + 0xb, + 0xd, + 0x11, + 0x14, + 0x17, + 0x1c, + 0x20, + 0x27, + 0x31, + 0x41, + 0x61, + }) + + Method (XBCM, 1, NotSerialized) + { + Store (ShiftLeft (Arg0, 4), BCLV) + Store (0x80000000, CR1) + Store (0x0610, BCLM) + } + + Method (XBQC, 0, NotSerialized) + { + Store (BCLV, Local0) + ShiftRight (Local0, 4, Local0) + Return (Local0) + } +#include <drivers/intel/gma/acpi/common.asl> +} diff --git a/src/soc/intel/sch/acpi/irqlinks.asl b/src/soc/intel/sch/acpi/irqlinks.asl new file mode 100644 index 0000000000..2d029242d8 --- /dev/null +++ b/src/soc/intel/sch/acpi/irqlinks.asl @@ -0,0 +1,487 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * + * 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 (LNKA) +{ + Name (_HID, EISAID("PNP0C0F")) + Name (_UID, 1) + + // Disable method + Method (_DIS, 0, Serialized) + { + Store (0x80, PRTA) + } + + // Possible Resource Settings for this Link + Name (_PRS, ResourceTemplate() + { + IRQ(Level, ActiveLow, Shared) + { 3, 4, 5, 6, 7, 10, 12, 14, 15 } + }) + + // Current Resource Settings for this link + Method (_CRS, 0, Serialized) + { + Name (RTLA, ResourceTemplate() + { + IRQ(Level, ActiveLow, Shared) {} + }) + CreateWordField(RTLA, 1, IRQ0) + + // Clear the WordField + Store (Zero, IRQ0) + + // Set the bit from PRTA + ShiftLeft(1, And(PRTA, 0x0f), IRQ0) + + Return (RTLA) + } + + // Set Resource Setting for this IRQ link + Method (_SRS, 1, Serialized) + { + CreateWordField(Arg0, 1, IRQ0) + + // Which bit is set? + FindSetRightBit(IRQ0, Local0) + + Decrement(Local0) + Store(Local0, PRTA) + } + + // Status + Method (_STA, 0, Serialized) + { + If(And(PRTA, 0x80)) { + Return (0x9) + } Else { + Return (0xb) + } + } +} + +Device (LNKB) +{ + Name (_HID, EISAID("PNP0C0F")) + Name (_UID, 2) + + // Disable method + Method (_DIS, 0, Serialized) + { + Store (0x80, PRTB) + } + + // Possible Resource Settings for this Link + Name (_PRS, ResourceTemplate() + { + IRQ(Level, ActiveLow, Shared) + { 3, 4, 5, 6, 7, 11, 12, 14, 15 } + }) + + // Current Resource Settings for this link + Method (_CRS, 0, Serialized) + { + Name (RTLB, ResourceTemplate() + { + IRQ(Level, ActiveLow, Shared) {} + }) + CreateWordField(RTLB, 1, IRQ0) + + // Clear the WordField + Store (Zero, IRQ0) + + // Set the bit from PRTB + ShiftLeft(1, And(PRTB, 0x0f), IRQ0) + + Return (RTLB) + } + + // Set Resource Setting for this IRQ link + Method (_SRS, 1, Serialized) + { + CreateWordField(Arg0, 1, IRQ0) + + // Which bit is set? + FindSetRightBit(IRQ0, Local0) + + Decrement(Local0) + Store(Local0, PRTB) + } + + // Status + Method (_STA, 0, Serialized) + { + If(And(PRTB, 0x80)) { + Return (0x9) + } Else { + Return (0xb) + } + } +} + +Device (LNKC) +{ + Name (_HID, EISAID("PNP0C0F")) + Name (_UID, 3) + + // Disable method + Method (_DIS, 0, Serialized) + { + Store (0x80, PRTC) + } + + // Possible Resource Settings for this Link + Name (_PRS, ResourceTemplate() + { + IRQ(Level, ActiveLow, Shared) + { 3, 4, 5, 6, 7, 10, 12, 14, 15 } + }) + + // Current Resource Settings for this link + Method (_CRS, 0, Serialized) + { + Name (RTLC, ResourceTemplate() + { + IRQ(Level, ActiveLow, Shared) {} + }) + CreateWordField(RTLC, 1, IRQ0) + + // Clear the WordField + Store (Zero, IRQ0) + + // Set the bit from PRTC + ShiftLeft(1, And(PRTC, 0x0f), IRQ0) + + Return (RTLC) + } + + // Set Resource Setting for this IRQ link + Method (_SRS, 1, Serialized) + { + CreateWordField(Arg0, 1, IRQ0) + + // Which bit is set? + FindSetRightBit(IRQ0, Local0) + + Decrement(Local0) + Store(Local0, PRTC) + } + + // Status + Method (_STA, 0, Serialized) + { + If(And(PRTC, 0x80)) { + Return (0x9) + } Else { + Return (0xb) + } + } +} + +Device (LNKD) +{ + Name (_HID, EISAID("PNP0C0F")) + Name (_UID, 4) + + // Disable method + Method (_DIS, 0, Serialized) + { + Store (0x80, PRTD) + } + + // Possible Resource Settings for this Link + Name (_PRS, ResourceTemplate() + { + IRQ(Level, ActiveLow, Shared) + { 3, 4, 5, 6, 7, 11, 12, 14, 15 } + }) + + // Current Resource Settings for this link + Method (_CRS, 0, Serialized) + { + Name (RTLD, ResourceTemplate() + { + IRQ(Level, ActiveLow, Shared) {} + }) + CreateWordField(RTLD, 1, IRQ0) + + // Clear the WordField + Store (Zero, IRQ0) + + // Set the bit from PRTD + ShiftLeft(1, And(PRTD, 0x0f), IRQ0) + + Return (RTLD) + } + + // Set Resource Setting for this IRQ link + Method (_SRS, 1, Serialized) + { + CreateWordField(Arg0, 1, IRQ0) + + // Which bit is set? + FindSetRightBit(IRQ0, Local0) + + Decrement(Local0) + Store(Local0, PRTD) + } + + // Status + Method (_STA, 0, Serialized) + { + If(And(PRTD, 0x80)) { + Return (0x9) + } Else { + Return (0xb) + } + } +} + +Device (LNKE) +{ + Name (_HID, EISAID("PNP0C0F")) + Name (_UID, 5) + + // Disable method + Method (_DIS, 0, Serialized) + { + Store (0x80, PRTE) + } + + // Possible Resource Settings for this Link + Name (_PRS, ResourceTemplate() + { + IRQ(Level, ActiveLow, Shared) + { 3, 4, 5, 6, 7, 10, 12, 14, 15 } + }) + + // Current Resource Settings for this link + Method (_CRS, 0, Serialized) + { + Name (RTLE, ResourceTemplate() + { + IRQ(Level, ActiveLow, Shared) {} + }) + CreateWordField(RTLE, 1, IRQ0) + + // Clear the WordField + Store (Zero, IRQ0) + + // Set the bit from PRTE + ShiftLeft(1, And(PRTE, 0x0f), IRQ0) + + Return (RTLE) + } + + // Set Resource Setting for this IRQ link + Method (_SRS, 1, Serialized) + { + CreateWordField(Arg0, 1, IRQ0) + + // Which bit is set? + FindSetRightBit(IRQ0, Local0) + + Decrement(Local0) + Store(Local0, PRTE) + } + + // Status + Method (_STA, 0, Serialized) + { + If(And(PRTE, 0x80)) { + Return (0x9) + } Else { + Return (0xb) + } + } +} + +Device (LNKF) +{ + Name (_HID, EISAID("PNP0C0F")) + Name (_UID, 6) + + // Disable method + Method (_DIS, 0, Serialized) + { + Store (0x80, PRTF) + } + + // Possible Resource Settings for this Link + Name (_PRS, ResourceTemplate() + { + IRQ(Level, ActiveLow, Shared) + { 3, 4, 5, 6, 7, 11, 12, 14, 15 } + }) + + // Current Resource Settings for this link + Method (_CRS, 0, Serialized) + { + Name (RTLF, ResourceTemplate() + { + IRQ(Level, ActiveLow, Shared) {} + }) + CreateWordField(RTLF, 1, IRQ0) + + // Clear the WordField + Store (Zero, IRQ0) + + // Set the bit from PRTF + ShiftLeft(1, And(PRTF, 0x0f), IRQ0) + + Return (RTLF) + } + + // Set Resource Setting for this IRQ link + Method (_SRS, 1, Serialized) + { + CreateWordField(Arg0, 1, IRQ0) + + // Which bit is set? + FindSetRightBit(IRQ0, Local0) + + Decrement(Local0) + Store(Local0, PRTF) + } + + // Status + Method (_STA, 0, Serialized) + { + If(And(PRTF, 0x80)) { + Return (0x9) + } Else { + Return (0xb) + } + } +} + +Device (LNKG) +{ + Name (_HID, EISAID("PNP0C0F")) + Name (_UID, 7) + + // Disable method + Method (_DIS, 0, Serialized) + { + Store (0x80, PRTG) + } + + // Possible Resource Settings for this Link + Name (_PRS, ResourceTemplate() + { + IRQ(Level, ActiveLow, Shared) + { 3, 4, 5, 6, 7, 10, 12, 14, 15 } + }) + + // Current Resource Settings for this link + Method (_CRS, 0, Serialized) + { + Name (RTLG, ResourceTemplate() + { + IRQ(Level, ActiveLow, Shared) {} + }) + CreateWordField(RTLG, 1, IRQ0) + + // Clear the WordField + Store (Zero, IRQ0) + + // Set the bit from PRTG + ShiftLeft(1, And(PRTG, 0x0f), IRQ0) + + Return (RTLG) + } + + // Set Resource Setting for this IRQ link + Method (_SRS, 1, Serialized) + { + CreateWordField(Arg0, 1, IRQ0) + + // Which bit is set? + FindSetRightBit(IRQ0, Local0) + + Decrement(Local0) + Store(Local0, PRTG) + } + + // Status + Method (_STA, 0, Serialized) + { + If(And(PRTG, 0x80)) { + Return (0x9) + } Else { + Return (0xb) + } + } +} + +Device (LNKH) +{ + Name (_HID, EISAID("PNP0C0F")) + Name (_UID, 8) + + // Disable method + Method (_DIS, 0, Serialized) + { + Store (0x80, PRTH) + } + + // Possible Resource Settings for this Link + Name (_PRS, ResourceTemplate() + { + IRQ(Level, ActiveLow, Shared) + { 3, 4, 5, 6, 7, 11, 12, 14, 15 } + }) + + // Current Resource Settings for this link + Method (_CRS, 0, Serialized) + { + Name (RTLH, ResourceTemplate() + { + IRQ(Level, ActiveLow, Shared) {} + }) + CreateWordField(RTLH, 1, IRQ0) + + // Clear the WordField + Store (Zero, IRQ0) + + // Set the bit from PRTH + ShiftLeft(1, And(PRTH, 0x0f), IRQ0) + + Return (RTLH) + } + + // Set Resource Setting for this IRQ link + Method (_SRS, 1, Serialized) + { + CreateWordField(Arg0, 1, IRQ0) + + // Which bit is set? + FindSetRightBit(IRQ0, Local0) + + Decrement(Local0) + Store(Local0, PRTH) + } + + // Status + Method (_STA, 0, Serialized) + { + If(And(PRTH, 0x80)) { + Return (0x9) + } Else { + Return (0xb) + } + } +} diff --git a/src/soc/intel/sch/acpi/lpc.asl b/src/soc/intel/sch/acpi/lpc.asl new file mode 100644 index 0000000000..518bdaef8e --- /dev/null +++ b/src/soc/intel/sch/acpi/lpc.asl @@ -0,0 +1,261 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * + * 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) + + OperationRegion(LPC0, PCI_Config, 0x00, 0x100) + Field (LPC0, AnyAcc, NoLock, Preserve) + { + Offset (0x40), + PMBS, 16, // PMBASE + Offset (0x60), // Interrupt Routing Registers + PRTA, 8, + PRTB, 8, + PRTC, 8, + PRTD, 8, + Offset (0x68), + PRTE, 8, + PRTF, 8, + PRTG, 8, + PRTH, 8, + + Offset (0x80), // IO Decode Ranges + IOD0, 8, + IOD1, 8, + + Offset (0xf0), // RCBA + RCEN, 1, + , 13, + RCBA, 18, + } + +// #include "irqlinks.asl" + #include "irqlinks.asl" + + #include "acpi/ec.asl" + + Device (DMAC) // DMA Controller + { + Name(_HID, EISAID("PNP0200")) + Name(_CRS, ResourceTemplate() + { + IO (Decode16, 0x00, 0x00, 0x01, 0x20) + IO (Decode16, 0x81, 0x81, 0x01, 0x11) + IO (Decode16, 0x93, 0x93, 0x01, 0x0d) + IO (Decode16, 0xc0, 0xc0, 0x01, 0x20) + DMA (Compatibility, NotBusMaster, Transfer8_16) { 4 } + }) + } + + Device (FWH) // Firmware Hub + { + Name (_HID, EISAID("INT0800")) + Name (_CRS, ResourceTemplate() + { + Memory32Fixed(ReadOnly, 0xff000000, 0x01000000) + }) + } + + Device (HPET) + { + Name (_HID, EISAID("PNP0103")) + Name (_CID, 0x010CD041) + + Name(BUF0, ResourceTemplate() + { + Memory32Fixed(ReadOnly, 0xfed00000, 0x400, FED0) + }) + + Method (_STA, 0) // Device Status + { + If (HPTE) { + // Note: Ancient versions of Windows don't want + // to see the HPET in order to work right + If (LGreaterEqual(OSYS, 2001)) { + Return (0xf) // Enable and show device + } Else { + Return (0xb) // Enable and don't show device + } + } + + Return (0x0) // Not enabled, don't show. + } + + Method (_CRS, 0, Serialized) // Current resources + { + If (HPTE) { + CreateDWordField(BUF0, \_SB.PCI0.LPCB.HPET.FED0._BAS, HPT0) + If (Lequal(HPAS, 1)) { + Store(0xfed01000, HPT0) + } + + If (Lequal(HPAS, 2)) { + Store(0xfed02000, HPT0) + } + + If (Lequal(HPAS, 3)) { + Store(0xfed03000, HPT0) + } + } + + Return (BUF0) + } + } + + Device(PIC) // 8259 Interrupt Controller + { + Name(_HID,EISAID("PNP0000")) + Name(_CRS, ResourceTemplate() + { + IO (Decode16, 0x20, 0x20, 0x01, 0x02) + IO (Decode16, 0x24, 0x24, 0x01, 0x02) + IO (Decode16, 0x28, 0x28, 0x01, 0x02) + IO (Decode16, 0x2c, 0x2c, 0x01, 0x02) + IO (Decode16, 0x30, 0x30, 0x01, 0x02) + IO (Decode16, 0x34, 0x34, 0x01, 0x02) + IO (Decode16, 0x38, 0x38, 0x01, 0x02) + IO (Decode16, 0x3c, 0x3c, 0x01, 0x02) + IO (Decode16, 0xa0, 0xa0, 0x01, 0x02) + IO (Decode16, 0xa4, 0xa4, 0x01, 0x02) + IO (Decode16, 0xa8, 0xa8, 0x01, 0x02) + IO (Decode16, 0xac, 0xac, 0x01, 0x02) + IO (Decode16, 0xb0, 0xb0, 0x01, 0x02) + IO (Decode16, 0xb4, 0xb4, 0x01, 0x02) + IO (Decode16, 0xb8, 0xb8, 0x01, 0x02) + IO (Decode16, 0xbc, 0xbc, 0x01, 0x02) + IO (Decode16, 0x4d0, 0x4d0, 0x01, 0x02) + IRQNoFlags () { 2 } + }) + } + + Device(MATH) // FPU + { + Name (_HID, EISAID("PNP0C04")) + Name (_CRS, ResourceTemplate() + { + IO (Decode16, 0xf0, 0xf0, 0x01, 0x01) + IRQNoFlags() { 13 } + }) + } + + Device(LDRC) // LPC device: Resource consumption + { + Name (_HID, EISAID("PNP0C02")) + Name (_UID, 2) + Name (_CRS, ResourceTemplate() + { + IO (Decode16, 0x2e, 0x2e, 0x1, 0x02) // First SuperIO + IO (Decode16, 0x4e, 0x4e, 0x1, 0x02) // Second SuperIO + IO (Decode16, 0x61, 0x61, 0x1, 0x01) // NMI Status + IO (Decode16, 0x63, 0x63, 0x1, 0x01) // CPU Reserved + IO (Decode16, 0x65, 0x65, 0x1, 0x01) // CPU Reserved + IO (Decode16, 0x67, 0x67, 0x1, 0x01) // CPU Reserved + IO (Decode16, 0x80, 0x80, 0x1, 0x01) // Port 80 Post + IO (Decode16, 0x92, 0x92, 0x1, 0x01) // CPU Reserved + IO (Decode16, 0xb2, 0xb2, 0x1, 0x02) // SWSMI + // IO (Decode16, 0x680, 0x680, 0x1, 0x70) // IO ??? + IO (Decode16, 0x800, 0x800, 0x1, 0x10) // ACPI I/O trap + IO (Decode16, 0x0500, 0x0500, 0x1, 0x80) // ICH7-M ACPI + IO (Decode16, 0x0480, 0x0480, 0x1, 0x40) // ICH7-M GPIO + // IO (Decode16, 0x1640, 0x1640, 0x1, 0x10) // IO ??? + }) + } + + Device (RTC) // Real Time Clock + { + Name (_HID, EISAID("PNP0B00")) + Name (_CRS, ResourceTemplate() + { + IO (Decode16, 0x70, 0x70, 1, 8) + IRQNoFlags() { 8 } + }) + } + + Device (TIMR) // Intel 8254 timer + { + Name(_HID, EISAID("PNP0100")) + Name(_CRS, ResourceTemplate() + { + IO (Decode16, 0x40, 0x40, 0x01, 0x04) + IO (Decode16, 0x50, 0x50, 0x10, 0x04) + IRQNoFlags() {0} + }) + } + + #include "acpi/superio.asl" + + Device (PS2K) // Keyboard + { + Name(_HID, EISAID("PNP0303")) + Name(_CID, EISAID("PNP030B")) + + Name(_CRS, ResourceTemplate() + { + IO (Decode16, 0x60, 0x60, 0x01, 0x01) + IO (Decode16, 0x64, 0x64, 0x01, 0x01) + IRQ (Edge, ActiveHigh, Exclusive) { 0x01 } // IRQ 1 + }) + + Method (_STA, 0) + { + Return (0xf) + } + } + + Device (PS2M) // Mouse + { + Name(_HID, EISAID("PNP0F13")) + Name(_CRS, ResourceTemplate() + { + IRQ (Edge, ActiveHigh, Exclusive) { 0x0c } // IRQ 12 + }) + + Method(_STA, 0) + { + Return (0xf) + } + } + + Device (FDC0) // Floppy controller + { + Name (_HID, EisaId ("PNP0700")) + Method (_STA, 0, NotSerialized) + { + Return (0x0f) // FIXME + } + + Name(_CRS, ResourceTemplate() + { + IO (Decode16, 0x03F0, 0x03F0, 0x01, 0x06) + IO (Decode16, 0x03F7, 0x03F7, 0x01, 0x01) + IRQNoFlags () {6} + DMA (Compatibility, NotBusMaster, Transfer8) {2} + }) + + Name(_PRS, ResourceTemplate() + { + IO (Decode16, 0x03F0, 0x03F0, 0x01, 0x06) + IO (Decode16, 0x03F7, 0x03F7, 0x01, 0x01) + IRQNoFlags () {6} + DMA (Compatibility, NotBusMaster, Transfer8) {2} + }) + + } +} diff --git a/src/soc/intel/sch/acpi/pata.asl b/src/soc/intel/sch/acpi/pata.asl new file mode 100644 index 0000000000..3d37b672df --- /dev/null +++ b/src/soc/intel/sch/acpi/pata.asl @@ -0,0 +1,74 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * + * 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 PATA Controller 0:1f.1 + +Device (PATA) +{ + Name (_ADR, 0x001f0001) + + Device (PRID) + { + Name (_ADR, 0) + + // Get Timing Mode + Method (_GTM) + { + Name(PBUF, Buffer(20) { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00 }) + + CreateDwordField (PBUF, 0, PIO0) + CreateDwordField (PBUF, 4, DMA0) + CreateDwordField (PBUF, 8, PIO1) + CreateDwordField (PBUF, 12, DMA1) + CreateDwordField (PBUF, 16, FLAG) + + // TODO fill return structure + + Return (PBUF) + } + + // Set Timing Mode + Method (_STM, 3) + { + CreateDwordField (Arg0, 0, PIO0) + CreateDwordField (Arg0, 4, DMA0) + CreateDwordField (Arg0, 8, PIO1) + CreateDwordField (Arg0, 12, DMA1) + CreateDwordField (Arg0, 16, FLAG) + + // TODO: Do the deed + } + + Device (DSK0) + { + Name (_ADR, 0) + // TODO: _RMV ? + // TODO: _GTF ? + } + + Device (DSK1) + { + Name (_ADR, 1) + + // TODO: _RMV ? + // TODO: _GTF ? + } + + } +} diff --git a/src/soc/intel/sch/acpi/pci.asl b/src/soc/intel/sch/acpi/pci.asl new file mode 100644 index 0000000000..d1b0e8be42 --- /dev/null +++ b/src/soc/intel/sch/acpi/pci.asl @@ -0,0 +1,71 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * + * 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 PCI to PCI bridge 0:1e.0 + +Device (PCIB) +{ + Name (_ADR, 0x001e0000) + + Device (SLT1) + { + Name (_ADR, 0x00000000) + Name (_PRW, Package(){ 11, 4 }) + } + + Device (SLT2) + { + Name (_ADR, 0x00010000) + Name (_PRW, Package(){ 11, 4 }) + } + + Device (SLT3) + { + Name (_ADR, 0x00020000) + Name (_PRW, Package(){ 11, 4 }) + } + + Device (SLT6) + { + Name (_ADR, 0x00050000) + Name (_PRW, Package(){ 11, 4 }) + } + + Device (LANC) + { + Name (_ADR, 0x00080000) + Name (_PRW, Package(){ 11, 3 }) + } + + Device (LANR) + { + Name (_ADR, 0x00000000) + Name (_PRW, Package(){ 11, 3 }) + } + + // TODO: How many slots, where? + + // PCI Interrupt Routing. + // If PICM is set, interrupts are routed over the i8259, otherwise + // over the IOAPIC. (Really? If they're above 15 they need to be routed + // fixed over the IOAPIC?) + + Method (_PRT) + { + #include "acpi/southbridge_pci_irqs.asl" + } + +} diff --git a/src/soc/intel/sch/acpi/pcie.asl b/src/soc/intel/sch/acpi/pcie.asl new file mode 100644 index 0000000000..3c644e2311 --- /dev/null +++ b/src/soc/intel/sch/acpi/pcie.asl @@ -0,0 +1,179 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * + * 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 i82801G PCIe support */ + +// PCI Express Ports + +Device (RP01) +{ + NAME(_ADR, 0x001c0000) // FIXME: Have a macro for PCI Devices -> ACPI notation? + //#include "pcie_port.asl" + Method(_PRT) + { + If (PICM) { + Return (Package() { + Package() { 0x0000ffff, 0, 0, 16 }, + Package() { 0x0000ffff, 1, 0, 17 }, + Package() { 0x0000ffff, 2, 0, 18 }, + Package() { 0x0000ffff, 3, 0, 19 } + }) + } Else { + Return (Package() { + Package() { 0x0000ffff, 0, \_SB.PCI0.LPCB.LNKA, 0 }, + Package() { 0x0000ffff, 1, \_SB.PCI0.LPCB.LNKB, 0 }, + Package() { 0x0000ffff, 2, \_SB.PCI0.LPCB.LNKC, 0 }, + Package() { 0x0000ffff, 3, \_SB.PCI0.LPCB.LNKD, 0 } + }) + + } + + } +} + +Device (RP02) +{ + NAME(_ADR, 0x001c0001) // FIXME: Have a macro for PCI Devices -> ACPI notation? + //#include "pcie_port.asl" + Method(_PRT) + { + If (PICM) { + Return (Package() { + Package() { 0x0000ffff, 0, 0, 17 }, + Package() { 0x0000ffff, 1, 0, 18 }, + Package() { 0x0000ffff, 2, 0, 19 }, + Package() { 0x0000ffff, 3, 0, 16 } + }) + } Else { + Return (Package() { + Package() { 0x0000ffff, 0, \_SB.PCI0.LPCB.LNKB, 0 }, + Package() { 0x0000ffff, 1, \_SB.PCI0.LPCB.LNKC, 0 }, + Package() { 0x0000ffff, 2, \_SB.PCI0.LPCB.LNKD, 0 }, + Package() { 0x0000ffff, 3, \_SB.PCI0.LPCB.LNKA, 0 } + }) + + } + + } +} + + +Device (RP03) +{ + NAME(_ADR, 0x001c0002) // FIXME: Have a macro for PCI Devices -> ACPI notation? + //#include "pcie_port.asl" + Method(_PRT) + { + If (PICM) { + Return (Package() { + Package() { 0x0000ffff, 0, 0, 18 }, + Package() { 0x0000ffff, 1, 0, 19 }, + Package() { 0x0000ffff, 2, 0, 16 }, + Package() { 0x0000ffff, 3, 0, 17 } + }) + } Else { + Return (Package() { + Package() { 0x0000ffff, 0, \_SB.PCI0.LPCB.LNKC, 0 }, + Package() { 0x0000ffff, 1, \_SB.PCI0.LPCB.LNKD, 0 }, + Package() { 0x0000ffff, 2, \_SB.PCI0.LPCB.LNKA, 0 }, + Package() { 0x0000ffff, 3, \_SB.PCI0.LPCB.LNKB, 0 } + }) + + } + + } +} + + +Device (RP04) +{ + NAME(_ADR, 0x001c0003) // FIXME: Have a macro for PCI Devices -> ACPI notation? + //#include "pcie_port.asl" + Method(_PRT) + { + If (PICM) { + Return (Package() { + Package() { 0x0000ffff, 0, 0, 19 }, + Package() { 0x0000ffff, 1, 0, 16 }, + Package() { 0x0000ffff, 2, 0, 17 }, + Package() { 0x0000ffff, 3, 0, 18 } + }) + } Else { + Return (Package() { + Package() { 0x0000ffff, 0, \_SB.PCI0.LPCB.LNKD, 0 }, + Package() { 0x0000ffff, 1, \_SB.PCI0.LPCB.LNKA, 0 }, + Package() { 0x0000ffff, 2, \_SB.PCI0.LPCB.LNKB, 0 }, + Package() { 0x0000ffff, 3, \_SB.PCI0.LPCB.LNKC, 0 } + }) + + } + + } +} + + +Device (RP05) +{ + NAME(_ADR, 0x001c0004) // FIXME: Have a macro for PCI Devices -> ACPI notation? + //#include "pcie_port.asl" + Method(_PRT) + { + If (PICM) { + Return (Package() { + Package() { 0x0000ffff, 0, 0, 16 }, + Package() { 0x0000ffff, 1, 0, 17 }, + Package() { 0x0000ffff, 2, 0, 18 }, + Package() { 0x0000ffff, 3, 0, 19 } + }) + } Else { + Return (Package() { + Package() { 0x0000ffff, 0, \_SB.PCI0.LPCB.LNKA, 0 }, + Package() { 0x0000ffff, 1, \_SB.PCI0.LPCB.LNKB, 0 }, + Package() { 0x0000ffff, 2, \_SB.PCI0.LPCB.LNKC, 0 }, + Package() { 0x0000ffff, 3, \_SB.PCI0.LPCB.LNKD, 0 } + }) + + } + + } +} + + +Device (RP06) +{ + NAME(_ADR, 0x001c0005) // FIXME: Have a macro for PCI Devices -> ACPI notation? + //#include "pcie_port.asl" + Method(_PRT) + { + If (PICM) { + Return (Package() { + Package() { 0x0000ffff, 0, 0, 17 }, + Package() { 0x0000ffff, 1, 0, 18 }, + Package() { 0x0000ffff, 2, 0, 19 }, + Package() { 0x0000ffff, 3, 0, 16 } + }) + } Else { + Return (Package() { + Package() { 0x0000ffff, 0, \_SB.PCI0.LPCB.LNKB, 0 }, + Package() { 0x0000ffff, 1, \_SB.PCI0.LPCB.LNKC, 0 }, + Package() { 0x0000ffff, 2, \_SB.PCI0.LPCB.LNKD, 0 }, + Package() { 0x0000ffff, 3, \_SB.PCI0.LPCB.LNKA, 0 } + }) + + } + + } +} diff --git a/src/soc/intel/sch/acpi/peg.asl b/src/soc/intel/sch/acpi/peg.asl new file mode 100644 index 0000000000..227ca27004 --- /dev/null +++ b/src/soc/intel/sch/acpi/peg.asl @@ -0,0 +1,41 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * + * 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 (PEGP) +{ + Name (_ADR, 0x00010000) + + // PCI Interrupt Routing. + Method (_PRT) + { + If (PICM) { + Return (Package() { + Package() { 0x0000ffff, 0, 0, 16 }, + Package() { 0x0000ffff, 1, 0, 17 }, + Package() { 0x0000ffff, 2, 0, 18 }, + Package() { 0x0000ffff, 3, 0, 19 } + }) + } Else { + Return (Package() { + Package() { 0x0000ffff, 0, \_SB.PCI0.LPCB.LNKA, 0 }, + Package() { 0x0000ffff, 1, \_SB.PCI0.LPCB.LNKB, 0 }, + Package() { 0x0000ffff, 2, \_SB.PCI0.LPCB.LNKC, 0 }, + Package() { 0x0000ffff, 3, \_SB.PCI0.LPCB.LNKD, 0 } + }) + } + + } +} diff --git a/src/soc/intel/sch/acpi/sch.asl b/src/soc/intel/sch/acpi/sch.asl new file mode 100644 index 0000000000..9816e7783c --- /dev/null +++ b/src/soc/intel/sch/acpi/sch.asl @@ -0,0 +1,219 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * + * 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 "hostbridge.asl" + +/* PCI Device Resource Consumption */ +Device (PDRC) +{ + Name (_HID, EISAID("PNP0C02")) + Name (_UID, 1) + + // This does not seem to work correctly yet - set values statically for + // now. + + //Name (PDRS, ResourceTemplate() { + // Memory32Fixed(ReadWrite, 0x00000000, 0x00004000, RCRB) // RCBA + // Memory32Fixed(ReadWrite, 0x00000000, 0x00004000, MCHB) // MCHBAR + // Memory32Fixed(ReadWrite, 0x00000000, 0x00001000, DMIB) // DMIBAR + // Memory32Fixed(ReadWrite, 0x00000000, 0x00001000, EGPB) // EPBAR + // Memory32Fixed(ReadWrite, 0x00000000, 0x00000000, PCIE) // PCIE BAR + // Memory32Fixed(ReadWrite, 0xfed20000, 0x00070000, ICHB) // Misc ICH + //}) + + Name (PDRS, ResourceTemplate() { + Memory32Fixed(ReadWrite, 0xfed1c000, 0x00004000) // RCBA + Memory32Fixed(ReadWrite, 0xfed14000, 0x00004000) // MCHBAR + Memory32Fixed(ReadWrite, 0xfed18000, 0x00001000) // DMIBAR + Memory32Fixed(ReadWrite, 0xfed19000, 0x00001000) // EPBAR + Memory32Fixed(ReadWrite, 0xf0000000, 0x04000000) // PCIE BAR + Memory32Fixed(ReadWrite, 0xfed20000, 0x00020000) // Misc ICH + Memory32Fixed(ReadWrite, 0xfed40000, 0x00005000) // Misc ICH + Memory32Fixed(ReadWrite, 0xfed45000, 0x0004b000) // Misc ICH + }) + + // Current Resource Settings + Method (_CRS, 0, Serialized) + { + //CreateDwordField(PDRS, ^RCRB._BAS, RBR0) + //ShiftLeft(\_SB.PCI0.LPCB.RCBA, 14, RBR0) + + //CreateDwordField(PDRS, ^MCHB._BAS, MBR0) + //ShiftLeft(\_SB.PCI0.MCHC.MHBR, 14, MBR0) + + //CreateDwordField(PDRS, ^DMIB._BAS, DBR0) + //ShiftLeft(\_SB.PCI0.MCHC.DMBR, 12, DBR0) + + //CreateDwordField(PDRS, ^EGPB._BAS, EBR0) + //ShiftLeft(\_SB.PCI0.MCHC.EPBR, 12, EBR0) + + //CreateDwordField(PDRS, ^PCIE._BAS, PBR0) + //ShiftLeft(\_SB.PCI0.MCHC.PXBR, 26, PBR0) + + //CreateDwordField(PDRS, ^PCIE._LEN, PSZ0) + //ShiftLeft(0x10000000, \_SB.PCI0.MCHC.PXSZ, PSZ0) + + Return(PDRS) + } +} + +// PCIe graphics port 0:1.0 +#include "peg.asl" + +// Integrated graphics 0:2.0 +#include "igd.asl" + +/* Intel PCH support */ + +Scope(\) +{ + // IO-Trap at 0x800. This is the ACPI->SMI communication interface. + + OperationRegion(IO_T, SystemIO, 0x800, 0x10) + Field(IO_T, ByteAcc, NoLock, Preserve) + { + Offset(0x8), + TRP0, 8 // IO-Trap at 0x808 + } + + // ICH7 Power Management Registers, located at PMBASE (0x1f.0 0x40.l) + // this doesn't work as ACPI initializes regions and packages first, devices second. + // use dynamic operation region? if so, how? XXX + //OperationRegion(PMIO, SystemIO, And(\_SB_.PCI0.LPCB.PMBS, 0xfffc), 0x80) + OperationRegion(PMIO, SystemIO, 0x500, 0x80) + Field(PMIO, ByteAcc, NoLock, Preserve) + { + Offset(0x42), // General Purpose Control + , 1, // skip 1 bit + GPEC, 1, // TCO status + , 9, // skip 9 more bits + SCIS, 1, // TCO DMI status + , 6 // To the end of the word + } + + // ICH7 GPIO IO mapped registers (0x1f.0 reg 0x48.l) + OperationRegion(GPIO, SystemIO, 0x1180, 0x3c) + Field(GPIO, ByteAcc, NoLock, Preserve) + { + Offset(0x00), // GPIO Use Select + GU00, 8, + GU01, 8, + GU02, 8, + GU03, 8, + Offset(0x04), // GPIO IO Select + GIO0, 8, + GIO1, 8, + GIO2, 8, + GIO3, 8, + Offset(0x0c), // GPIO Level + GL00, 8, + GL01, 8, + , 3, + GP27, 1, // SATA_PWR_EN #0 + GP28, 1, // SATA_PWR_EN #1 + , 3, + Offset(0x18), // GPIO Blink + GB00, 8, + GB01, 8, + GB02, 8, + GB03, 8, + Offset(0x2c), // GPIO Invert + GIV0, 8, + GIV1, 8, + GIV2, 8, + GIV3, 8, + Offset(0x30), // GPIO Use Select 2 + GU04, 8, + GU05, 8, + GU06, 8, + GU07, 8, + Offset(0x34), // GPIO IO Select 2 + GIO4, 8, + GIO5, 8, + GIO6, 8, + GIO7, 8, + Offset(0x38), // GPIO Level 2 + , 5, + GP37, 1, // PATA_PWR_EN + GP38, 1, // Battery / Power (?) + GP39, 1, // ?? + GL05, 8, + GL06, 8, + GL07, 8 + } + + + // ICH7 Root Complex Register Block. Memory Mapped through RCBA) + OperationRegion(RCRB, SystemMemory, 0xfed1c000, 0x4000) + Field(RCRB, DWordAcc, Lock, Preserve) + { + Offset(0x0000), // Backbone + Offset(0x1000), // Chipset + Offset(0x3000), // Legacy Configuration Registers + Offset(0x3404), // High Performance Timer Configuration + HPAS, 2, // Address Select + , 5, + HPTE, 1, // Address Enable + Offset(0x3418), // FD (Function Disable) + , 1, // Reserved + PATD, 1, // PATA disable + SATD, 1, // SATA disable + SMBD, 1, // SMBUS disable + HDAD, 1, // Azalia disable + A97D, 1, // AC'97 disable + M97D, 1, // AC'97 disable + ILND, 1, // Internal LAN disable + US1D, 1, // UHCI #1 disable + US2D, 1, // UHCI #2 disable + US3D, 1, // UHCI #3 disable + US4D, 1, // UHCI #4 disable + , 2, // Reserved + LPBD, 1, // LPC bridge disable + EHCD, 1, // EHCI disable + Offset(0x341a), // FD Root Ports + RP1D, 1, // Root Port 1 disable + RP2D, 1, // Root Port 2 disable + RP3D, 1, // Root Port 3 disable + RP4D, 1, // Root Port 4 disable + RP5D, 1, // Root Port 5 disable + RP6D, 1 // Root Port 6 disable + } + +} + +// 0:1b.0 High Definition Audio (Azalia) +#include "audio.asl" + +// PCI Express Ports +#include "pcie.asl" + +// USB +#include "usb.asl" + +// PCI Bridge +#include "pci.asl" + +// AC97 Audio and Modem +#include "ac97.asl" + +// LPC Bridge +#include "lpc.asl" + +// PATA +#include "pata.asl" + +// SMBus +#include "smbus.asl" diff --git a/src/soc/intel/sch/acpi/sleepstates.asl b/src/soc/intel/sch/acpi/sleepstates.asl new file mode 100644 index 0000000000..c05835ac3c --- /dev/null +++ b/src/soc/intel/sch/acpi/sleepstates.asl @@ -0,0 +1,21 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * + * 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. + */ + +Name(\_S0, Package(4){0x0,0x0,0,0}) +Name(\_S1, Package(4){0x1,0x0,0,0}) +Name(\_S3, Package(4){0x5,0x0,0,0}) +Name(\_S4, Package(4){0x6,0x0,0,0}) +Name(\_S5, Package(4){0x7,0x0,0,0}) diff --git a/src/soc/intel/sch/acpi/smbus.asl b/src/soc/intel/sch/acpi/smbus.asl new file mode 100644 index 0000000000..3354b03c4b --- /dev/null +++ b/src/soc/intel/sch/acpi/smbus.asl @@ -0,0 +1,240 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * + * 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 SMBus Controller 0:1f.3 + +Device (SBUS) +{ + Name (_ADR, 0x001f0003) + + OperationRegion (SMBP, PCI_Config, 0x00, 0x100) + Field(SMBP, DWordAcc, NoLock, Preserve) + { + Offset(0x40), + , 2, + I2CE, 1 + } + + /* + OperationRegion (SMBI, SystemIO, 0x400, 0x20) + Field (SMBI, ByteAcc, NoLock, Preserve) + { + HSTS, 8, // Host Status + , 8, + HCNT, 8, // Host Control + HCMD, 8, // Host Command + TXSA, 8, // Transmit Slave Address + DAT0, 8, // Host Data 0 + DAT1, 8, // Host Data 1 + HBDB, 8, // Host Block Data Byte + PECK, 8, // Packet Error Check + RXSA, 8, // Receive Slave Address + RXDA, 16, // Receive Slave Data + AUXS, 8, // Auxiliary Status + AUXC, 8, // Auxiliary Control + SLPC, 8, // SMLink Pin Control + SBPC, 8, // SMBus Pin Control + SSTS, 8, // Slave Status + SCMD, 8, // Slave Command + NADR, 8, // Notify Device Address + NDLB, 8, // Notify Data Low Byte + NDLH, 8, // Notify Data High Byte + } + + // Kill all SMBus communication + Method (KILL, 0, Serialized) + { + Or (HCNT, 0x02, HCNT) // Send Kill + Or (HSTS, 0xff, HSTS) // Clean Status + } + + // Check if last operation completed + // return Failure = 0, Success = 1 + Method (CMPL, 0, Serialized) + { + Store (4000, Local0) // Timeout 200ms in 50us steps + While (Local0) { + If (And(HSTS, 0x02)) { // Completion Status? + Return (1) // Operation Completed + } Else { + Stall (50) + Decrement (Local0) + If (LEqual(Local0, 0)) { + KILL() + } + } + } + + Return (0) // Failure + } + + + // Wait for SMBus to become ready + Method (SRDY, 0, Serialized) + { + Store (200, Local0) // Timeout 200ms + While (Local0) { + If (And(HSTS, 0x40)) { // IN_USE? + Sleep(1) // Wait 1ms + Decrement(Local0) // timeout-- + If (LEqual(Local0, 0)) { + Return (1) + } + } Else { + Store (0, Local0) // We're ready + } + } + + Store (4000, Local0) // Timeout 200ms (50us * 4000) + While (Local0) { + If (And (HSTS, 0x01)) { // Host Busy? + Stall(50) // Wait 50us + Decrement(Local0) // timeout-- + If (LEqual(Local0, 0)) { + KILL() + } + } Else { + Return (0) // Success + } + } + + Return (1) // Failure + } + + // SMBus Send Byte + // Arg0: Address + // Arg1: Data + // Return: 1 = Success, 0=Failure + + Method (SSXB, 2, Serialized) + { + + // Is the SMBus Controller Ready? + If (SRDY()) { + Return (0) + } + + // Send Byte + Store (0, I2CE) // SMBus Enable + Store (0xbf, HSTS) + Store (Arg0, TXSA) // Write Address + Store (Arg1, HCMD) // Write Data + + Store (0x48, HCNT) // Start + Byte Data Protocol + + If (CMPL()) { + Or (HSTS, 0xff, HSTS) // Clean up + Return (1) // Success + } + + Return (0) + } + + + // SMBus Receive Byte + // Arg0: Address + // Return: 0xffff = Failure, Data (8bit) = Success + + Method (SRXB, 2, Serialized) + { + + // Is the SMBus Controller Ready? + If (SRDY()) { + Return (0xffff) + } + + // Receive Byte + Store (0, I2CE) // SMBus Enable + Store (0xbf, HSTS) + Store (Or (Arg0, 1), TXSA) // Write Address + + Store (0x44, HCNT) // Start + + If (CMPL()) { + Or (HSTS, 0xff, HSTS) // Clean up + Return (DAT0) // Success + } + + Return (0xffff) + } + + + // SMBus Write Byte + // Arg0: Address + // Arg1: Command + // Arg2: Data + // Return: 1 = Success, 0=Failure + + Method (SWRB, 3, Serialized) + { + + // Is the SMBus Controller Ready? + If (SRDY()) { + Return (0) + } + + // Send Byte + Store (0, I2CE) // SMBus Enable + Store (0xbf, HSTS) + Store (Arg0, TXSA) // Write Address + Store (Arg1, HCMD) // Write Command + Store (Arg2, DAT0) // Write Data + + Store (0x48, HCNT) // Start + Byte Protocol + + If (CMPL()) { + Or (HSTS, 0xff, HSTS) // Clean up + Return (1) // Success + } + + Return (0) + } + + + // SMBus Read Byte + // Arg0: Address + // Arg1: Command + // Return: 0xffff = Failure, Data (8bit) = Success + + Method (SRDB, 2, Serialized) + { + + // Is the SMBus Controller Ready? + If (SRDY()) { + Return (0xffff) + } + + // Receive Byte + Store (0, I2CE) // SMBus Enable + Store (0xbf, HSTS) + Store (Or (Arg0, 1), TXSA) // Write Address + Store (Arg1, HCMD) // Command + + Store (0x48, HCNT) // Start + + If (CMPL()) { + Or (HSTS, 0xff, HSTS) // Clean up + Return (DAT0) // Success + } + + Return (0xffff) + } + */ + + // Todo: Does anyone ever use these? + // Missing: Read / Write Word + // Missing: Read / Write Block +} diff --git a/src/soc/intel/sch/acpi/usb.asl b/src/soc/intel/sch/acpi/usb.asl new file mode 100644 index 0000000000..fc5f07c5b2 --- /dev/null +++ b/src/soc/intel/sch/acpi/usb.asl @@ -0,0 +1,210 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * + * 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 i82801G USB support */ + +// USB Controller 0:1d.0 + +Device (USB1) +{ + Name(_ADR, 0x001d0000) + + OperationRegion(U01P, PCI_Config, 0, 256) + Field(U01P, DWordAcc, NoLock, Preserve) + { + Offset(0xc4), + U1WE, 2 // USB Wake Enable + } + + Name (_PRW, Package(){ 3, 4 }) // Power Resources for Wake + + Method (_PSW, 1) // Power State Wake method + { + // USB Controller can wake OS from Sleep State + If (Arg0) { + Store (3, U1WE) + } Else { + Store (0, U1WE) + } + } + + // Leave USB ports on for to allow Wake from USB + + Method(_S3D,0) // Highest D State in S3 State + { + Return (2) + } + + Method(_S4D,0) // Highest D State in S4 State + { + Return (2) + } +} + + +// USB Controller 0:1d.1 + +Device (USB2) +{ + Name(_ADR, 0x001d0001) + + OperationRegion(U02P, PCI_Config, 0, 256) + Field(U02P, DWordAcc, NoLock, Preserve) + { + Offset(0xc4), + U2WE, 2 // USB Wake Enable + } + + Name (_PRW, Package(){ 3, 4 }) // Power Resources for Wake + + Method (_PSW, 1) // Power State Wake method + { + // USB Controller can wake OS from Sleep State + If (Arg0) { + Store (3, U2WE) + } Else { + Store (0, U2WE) + } + } + + // Leave USB ports on for to allow Wake from USB + + Method(_S3D,0) // Highest D State in S3 State + { + Return (2) + } + + Method(_S4D,0) // Highest D State in S4 State + { + Return (2) + } + +} + + +// USB Controller 0:1d.2 + +Device (USB3) +{ + Name(_ADR, 0x001d0002) + + OperationRegion(U03P, PCI_Config, 0, 256) + Field(U03P, DWordAcc, NoLock, Preserve) + { + Offset(0xc4), + U3WE, 2 // USB Wake Enable + } + + Name (_PRW, Package(){ 3, 4 }) // Power Resources for Wake + + Method (_PSW, 1) // Power State Wake method + { + // USB Controller can wake OS from Sleep State + If (Arg0) { + Store (3, U3WE) + } Else { + Store (0, U3WE) + } + } + + // Leave USB ports on for to allow Wake from USB + + Method(_S3D,0) // Highest D State in S3 State + { + Return (2) + } + + Method(_S4D,0) // Highest D State in S4 State + { + Return (2) + } + +} + + +// USB Controller 0:1d.3 + +Device (USB4) +{ + Name(_ADR, 0x001d0003) + + OperationRegion(U04P, PCI_Config, 0, 256) + Field(U04P, DWordAcc, NoLock, Preserve) + { + Offset(0xc4), + U4WE, 2 // USB Wake Enable + } + + Name (_PRW, Package(){ 3, 4 }) // Power Resources for Wake + + Method (_PSW, 1) // Power State Wake method + { + // USB Controller can wake OS from Sleep State + If (Arg0) { + Store (3, U4WE) + } Else { + Store (0, U4WE) + } + } + + // Leave USB ports on for to allow Wake from USB + + Method(_S3D,0) // Highest D State in S3 State + { + Return (2) + } + + Method(_S4D,0) // Highest D State in S4 State + { + Return (2) + } + +} + + +// EHCI Controller 0:1d.7 + +Device (EHC1) +{ + Name(_ADR, 0x001d0007) + + Name (_PRW, Package(){ 13, 4 }) // Power Resources for Wake + + // Leave USB ports on for to allow Wake from USB + + Method(_S3D,0) // Highest D State in S3 State + { + Return (2) + } + + Method(_S4D,0) // Highest D State in S4 State + { + Return (2) + } + + Device (HUB7) + { + Name (_ADR, 0x00000000) + + // How many are there? + Device (PRT1) { Name (_ADR, 1) } // USB Port 0 + Device (PRT2) { Name (_ADR, 2) } // USB Port 1 + Device (PRT3) { Name (_ADR, 3) } // USB Port 2 + Device (PRT4) { Name (_ADR, 4) } // USB Port 3 + Device (PRT5) { Name (_ADR, 5) } // USB Port 4 + Device (PRT6) { Name (_ADR, 6) } // USB Port 5 + } +} diff --git a/src/soc/intel/sch/audio.c b/src/soc/intel/sch/audio.c new file mode 100644 index 0000000000..765d8de2a4 --- /dev/null +++ b/src/soc/intel/sch/audio.c @@ -0,0 +1,312 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008 Advanced Micro Devices, Inc. + * Copyright (C) 2008-2009 coresystems GmbH + * + * 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 <device/device.h> +#include <device/azalia_device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include <arch/io.h> +#include <delay.h> + +#define HDA_ICII_REG 0x68 +#define HDA_ICII_BUSY (1 << 0) +#define HDA_ICII_VALID (1 << 1) + +typedef struct southbridge_intel_sch_config config_t; + +static int set_bits(void *port, u32 mask, u32 val) +{ + u32 reg32; + int count; + + /* Write (val & mask) to port */ + val &= mask; + reg32 = read32(port); + reg32 &= ~mask; + reg32 |= val; + write32(port, reg32); + + /* Wait for readback of register to + * match what was just written to it + */ + count = 50; + do { + /* Wait 1ms based on BKDG wait time */ + mdelay(1); + reg32 = read32(port); + reg32 &= mask; + } while ((reg32 != val) && --count); + + /* Timeout occurred */ + if (!count) + return -1; + return 0; +} + +static int codec_detect(u8 *base) +{ + u32 reg32; + int count; + + /* Set Bit 0 to 1 to exit reset state (BAR + 0x8)[0] */ + if (set_bits(base + 0x08, 1, 1) == -1) + goto no_codec; + + /* clear STATESTS bits (BAR + 0xE)[2:0] */ + reg32 = read32(base + 0x0E); + reg32 |= 7; + write32(base + 0x0E, reg32); + + /* Wait for readback of register to + * match what was just written to it + */ + count = 50; + do { + /* Wait 1ms based on BKDG wait time */ + mdelay(1); + reg32 = read32(base + 0x0E); + } while ((reg32 != 0) && --count); + /* Timeout occurred */ + if (!count) + goto no_codec; + + /* Set Bit0 to 0 to enter reset state (BAR + 0x8)[0] */ + if (set_bits(base + 0x08, 1, 0) == -1) + goto no_codec; + + /* Set Bit 0 to 1 to exit reset state (BAR + 0x8)[0] */ + if (set_bits(base + 0x08, 1, 1) == -1) + goto no_codec; + + /* Read in Codec location (BAR + 0xe)[2..0] */ + reg32 = read32(base + 0xe); + reg32 &= 0x0f; + if (!reg32) + goto no_codec; + + return reg32; + +no_codec: + /* Codec Not found */ + /* Put HDA back in reset (BAR + 0x8) [0] */ + set_bits(base + 0x08, 1, 0); + printk(BIOS_DEBUG, "sch_audio: No codec!\n"); + return 0; +} + +static u32 find_verb(struct device *dev, u32 viddid, const u32 ** verb) +{ + printk(BIOS_DEBUG, "sch_audio: dev=%s\n", dev_path(dev)); + printk(BIOS_DEBUG, "sch_audio: Reading viddid=%x\n", viddid); + + int idx = 0; + + while (idx < (cim_verb_data_size / sizeof(u32))) { + u32 verb_size = 4 * cim_verb_data[idx + 2]; // in u32 + verb_size++; // we ship an additional gain value + if (cim_verb_data[idx] != viddid) { + idx += verb_size + 3; // skip verb + header + continue; + } + *verb = &cim_verb_data[idx + 3]; + return verb_size; + } + + /* Not all codecs need to load another verb */ + return 0; +} + +/** + * Wait 50usec for the codec to indicate it is ready + * no response would imply that the codec is non-operative + */ + +static int wait_for_ready(u8 *base) +{ + /* Use a 50 usec timeout - the Linux kernel uses the + * same duration */ + + int timeout = 50; + + while (timeout--) { + u32 reg32 = read32(base + HDA_ICII_REG); + if (!(reg32 & HDA_ICII_BUSY)) + return 0; + udelay(1); + } + + return -1; +} + +/** + * Wait 50usec for the codec to indicate that it accepted + * the previous command. No response would imply that the code + * is non-operative + */ + +static int wait_for_valid(u8 *base) +{ + /* Use a 50 usec timeout - the Linux kernel uses the + * same duration */ + + int timeout = 25; + + write32(base + 0x68, 1); + while (timeout--) { + udelay(1); + } + timeout = 50; + while (timeout--) { + u32 reg32 = read32(base + 0x68); + if ((reg32 & ((1 << 1) | (1 << 0))) == (1 << 1)) { + + write32(base + 0x68, 2); + return 0; + } + udelay(1); + } + + return -1; +} + +static void codec_init(struct device *dev, u8 *base, int addr) +{ + u32 reg32; + const u32 *verb; + u32 verb_size; + int i; + + printk(BIOS_DEBUG, "sch_audio: Initializing codec #%d\n", addr); + + /* 1 */ + if (wait_for_ready(base) == -1) + return; + + reg32 = (addr << 28) | 0x000f0000; + write32(base + 0x60, reg32); + + if (wait_for_valid(base) == -1) + return; + + reg32 = read32(base + 0x0); + printk(BIOS_DEBUG, "sch_audio: GCAP: %08x\n", reg32); + + reg32 = read32(base + 0x4); + printk(BIOS_DEBUG, "sch_audio: OUTPAY: %08x\n", reg32); + reg32 = read32(base + 0x6); + printk(BIOS_DEBUG, "sch_audio: INPAY: %08x\n", reg32); + + reg32 = read32(base + 0x64); + + /* 2 */ + printk(BIOS_DEBUG, "sch_audio: codec viddid: %08x\n", reg32); + verb_size = find_verb(dev, reg32, &verb); + + if (!verb_size) { + printk(BIOS_DEBUG, "sch_audio: No verb!\n"); + return; + } + printk(BIOS_DEBUG, "sch_audio: verb_size: %d\n", verb_size); + + /* 3 */ + for (i = 0; i < verb_size; i++) { + if (wait_for_ready(base) == -1) + return; + + write32(base + 0x60, verb[i]); + + if (wait_for_valid(base) == -1) + return; + } + printk(BIOS_DEBUG, "sch_audio: verb loaded.\n"); +} + +static void codecs_init(struct device *dev, u8 *base, u32 codec_mask) +{ + int i; + + for (i = 2; i >= 0; i--) { + if (codec_mask & (1 << i)) + codec_init(dev, base, i); + } +} + +static void sch_audio_init(struct device *dev) +{ + u8 *base; + struct resource *res; + u32 codec_mask; + u32 reg32; + + res = find_resource(dev, 0x10); + if (!res) + return; + + reg32 = pci_read_config32(dev, PCI_COMMAND); + pci_write_config32(dev, PCI_COMMAND, reg32 | PCI_COMMAND_MEMORY); + + // NOTE this will break as soon as the sch_audio get's a bar above + // 4G. Is there anything we can do about it? + base = res2mmio(res, 0, 0); + printk(BIOS_DEBUG, "sch_audio: base = %px\n", base); + codec_mask = codec_detect(base); + + if (codec_mask) { + printk(BIOS_DEBUG, "sch_audio: codec_mask = %02x\n", + codec_mask); + codecs_init(dev, base, codec_mask); + } else { + /* No audio codecs found disable HD audio controller */ + pci_write_config32(dev, 0x10, 0); + pci_write_config32(dev, PCI_COMMAND, 0); + reg32 = pci_read_config32(dev, 0xFC); + pci_write_config32(dev, 0xFC, reg32 | 1); + } +} + +static void sch_audio_set_subsystem(device_t dev, unsigned vendor, + unsigned device) +{ + if (!vendor || !device) { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + pci_read_config32(dev, PCI_VENDOR_ID)); + } else { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + ((device & 0xffff) << 16) | (vendor & 0xffff)); + } +} + +static struct pci_operations sch_audio_pci_ops = { + .set_subsystem = sch_audio_set_subsystem, +}; + +static struct device_operations sch_audio_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = sch_audio_init, + .scan_bus = 0, + .ops_pci = &sch_audio_pci_ops, +}; + +/* SCH audio function */ +static const struct pci_driver sch_audio __pci_driver = { + .ops = &sch_audio_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x811B, +}; diff --git a/src/soc/intel/sch/chip.h b/src/soc/intel/sch/chip.h new file mode 100644 index 0000000000..27d7c7334b --- /dev/null +++ b/src/soc/intel/sch/chip.h @@ -0,0 +1,39 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2008 coresystems GmbH + * 2012 secunet Security Networks AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef SOC_INTEL_SCH_CHIP_H +#define SOC_INTEL_SCH_CHIP_H + +#include <drivers/intel/gma/i915.h> + +struct soc_intel_sch_config { + struct i915_gpu_controller_info gfx; + + /** + * Interrupt Routing configuration + * If bit7 is 1, the interrupt is disabled. + */ + uint8_t pirqa_routing; + uint8_t pirqb_routing; + uint8_t pirqc_routing; + uint8_t pirqd_routing; + uint8_t pirqe_routing; + uint8_t pirqf_routing; + uint8_t pirqg_routing; + uint8_t pirqh_routing; +}; + +#endif /* SOC_INTEL_SCH_CHIP_H */ diff --git a/src/soc/intel/sch/early_init.c b/src/soc/intel/sch/early_init.c new file mode 100644 index 0000000000..ccc8022246 --- /dev/null +++ b/src/soc/intel/sch/early_init.c @@ -0,0 +1,216 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2009-2010 iWave Systems + * + * 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 "sch.h" + +#if 0 +static void sch_set_mtrr(void) +{ + msr_t msr; + printk(BIOS_DEBUG, "1"); + msr.hi = 0x06060606; + msr.lo = 0x06060606; + wrmsr(0x250, msr); + printk(BIOS_DEBUG, "2"); + msr.hi = 0x06060606; + msr.lo = 0x06060606; + wrmsr(0x258, msr); + printk(BIOS_DEBUG, "3"); + msr.hi = 0x0; + msr.lo = 0x0; + wrmsr(0x259, msr); + printk(BIOS_DEBUG, "4"); + msr.hi = 0x04040404; + msr.lo = 0x04040404; + wrmsr(0x268, msr); + printk(BIOS_DEBUG, "5"); + msr.hi = 0x04040404; + msr.lo = 0x04040404; + wrmsr(0x269, msr); + printk(BIOS_DEBUG, "6"); + msr.hi = 0x04040404; + msr.lo = 0x04040404; + wrmsr(0x26A, msr); + printk(BIOS_DEBUG, "7"); + msr.hi = 0x04040404; + msr.lo = 0x04040404; + wrmsr(0x26B, msr); + printk(BIOS_DEBUG, "8"); + msr.hi = 0x04040404; + msr.lo = 0x04040404; + wrmsr(0x26C, msr); + printk(BIOS_DEBUG, "9"); + msr.hi = 0x05050505; + msr.lo = 0x05050505; + wrmsr(0x26D, msr); + printk(BIOS_DEBUG, "10"); + msr.hi = 0x05050505; + msr.lo = 0x05050505; + wrmsr(0x26E, msr); + printk(BIOS_DEBUG, "11"); + msr.hi = 0x05050505; + msr.lo = 0x05050505; + wrmsr(0x26f, msr); + printk(BIOS_DEBUG, "12"); + msr.hi = 0x0; + msr.lo = 0x6; + wrmsr(0x202, msr); + printk(BIOS_DEBUG, "13"); + msr.hi = 0x0; + msr.lo = 0xC0000800; + wrmsr(0x203, msr); + printk(BIOS_DEBUG, "14"); + msr.hi = 0x0; + msr.lo = 0x3FAF0000; + wrmsr(0x204, msr); + printk(BIOS_DEBUG, "15"); + msr.hi = 0x0; + msr.lo = 0xFFFF0800; + wrmsr(0x205, msr); + printk(BIOS_DEBUG, "16"); + msr.hi = 0x0; + msr.lo = 0x3FB00000; + wrmsr(0x206, msr); + printk(BIOS_DEBUG, "16"); + msr.hi = 0x0; + msr.lo = 0xFFF00800; + wrmsr(0x207, msr); + printk(BIOS_DEBUG, "17"); + msr.hi = 0x0; + msr.lo = 0x3FC00000; + wrmsr(0x208, msr); + printk(BIOS_DEBUG, "18"); + msr.hi = 0x0; + msr.lo = 0xFFC00800; + wrmsr(0x209, msr); + printk(BIOS_DEBUG, "19"); + msr.hi = 0x0; + msr.lo = 0x0; + wrmsr(0x20A, msr); + printk(BIOS_DEBUG, "20"); + msr.hi = 0x0; + msr.lo = 0x0; + wrmsr(0x20B, msr); + printk(BIOS_DEBUG, "21"); + msr.hi = 0x0; + msr.lo = 0x0; + wrmsr(0x20a, msr); + printk(BIOS_DEBUG, "22"); + msr.hi = 0x0; + msr.lo = 0x0; + wrmsr(0x20B, msr); + printk(BIOS_DEBUG, "23"); + msr.hi = 0x0; + msr.lo = 0x0; + wrmsr(0x20c, msr); + msr.hi = 0x0; + msr.lo = 0x0; + wrmsr(0x20d, msr); + msr.hi = 0x0; + msr.lo = 0x0; + wrmsr(0x20E, msr); + msr.hi = 0x0; + msr.lo = 0x0; + wrmsr(0x20F, msr); + msr.hi = 0x0; + msr.lo = 0XC00; + wrmsr(0x2FF, msr); + printk(BIOS_DEBUG, "end"); +} +#endif + +static void sch_detect_chipset(void) +{ + u16 reg16; + u8 reg8; + printk(BIOS_INFO, "\n"); + reg16 = pci_read_config16(PCI_DEV(0, 0x00, 0), 0x2); + switch (reg16) { + case 0x8101: + printk(BIOS_INFO, "UL11L/US15L"); + break; + case 0x8100: + printk(BIOS_INFO, "US15W"); + break; + default: + /* Others reserved. */ + printk(BIOS_INFO, "Unknown (%02x)", reg16); + } + printk(BIOS_INFO, " Chipset "); + + reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0x8); + switch (reg8) { + case 3: + printk(BIOS_INFO, "Qual. Sample ES1, Stepping B1"); + break; + case 4: + printk(BIOS_INFO, "Qual. Sample ES2, Stepping C0"); + break; + case 5: + printk(BIOS_INFO, "Qual. Sample ES2-Prime, Stepping D0"); + break; + case 6: + printk(BIOS_INFO, "Qual. Sample QS, Stepping D1"); + break; + default: + /* Others reserved. */ + printk(BIOS_INFO, "Unknown (%02x)", reg8); + } + printk(BIOS_INFO, "\n"); +} + +static void sch_setup_non_standard_bars(void) +{ + printk(BIOS_DEBUG, "Setting up ACPI PM1 block "); + /* Address 0x1000 size 16B */ + pci_write_config32(PCI_DEV(0, 0x1f, 0), 0x48, + (0x80000000 | DEFAULT_PMBASE)); + + printk(BIOS_DEBUG, "Setting up ACPI P block "); + /* Address 0x1010 size 16B */ + sch_port_access_write(4, 0x70, 4, 0x80001010); + + /* SMBus address 0x1040 size 64B */ + pci_write_config32(PCI_DEV(0, 0x1f, 0), 0x40, 0x80001040); + + /* GPIO address 0x1080 size 64B */ + pci_write_config32(PCI_DEV(0, 0x1f, 0), 0x44, 0x80001080); + + /* GPE0 address 0x10C0 size 64B */ + pci_write_config32(PCI_DEV(0, 0x1f, 0), 0x4C, 0x800010C0); + + sch_port_access_write(2, 4, 4, 0x3F703F76); /* FIXME: SMM Control */ + + /* Base of Stolen Memory Address 0x1080 size 64B */ + pci_write_config32(PCI_DEV(0, 0x02, 0), 0x5C, 0x3F800000); + + sch_port_access_write(0, 0, 4, DEFAULT_PCIEXBAR | 1); /* pre-b1 */ + sch_port_access_write(2, 9, 4, DEFAULT_PCIEXBAR | 1); /* b1+ */ + + /* RCBA */ + pci_write_config32(PCI_DEV(0, 0x1f, 0), 0xF0, + ((uintptr_t)DEFAULT_RCBABASE | 1)); + + printk(BIOS_DEBUG, " done.\n"); +} + +static void sch_early_initialization(void) +{ + /* Print some chipset specific information. */ + sch_detect_chipset(); + + /* Setup all non standard BARs. */ + sch_setup_non_standard_bars(); +} diff --git a/src/soc/intel/sch/early_smbus.c b/src/soc/intel/sch/early_smbus.c new file mode 100644 index 0000000000..2f9cdeb060 --- /dev/null +++ b/src/soc/intel/sch/early_smbus.c @@ -0,0 +1,57 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008-2009 coresystems GmbH + * + * 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/pci_ids.h> +#include <device/pci_def.h> +#include "i82801gx.h" +#include "smbus.h" + +void enable_smbus(void) +{ + device_t dev; + + /* Set the SMBus device statically. */ + dev = PCI_DEV(0x0, 0x1f, 0x3); + + /* Check to make sure we've got the right device. */ + if (pci_read_config16(dev, 0x2) != 0x27da) { + die("SMBus controller not found!"); + } + + /* Set SMBus I/O base. */ + pci_write_config32(dev, SMB_BASE, + SMBUS_IO_BASE | PCI_BASE_ADDRESS_SPACE_IO); + + /* Set SMBus enable. */ + pci_write_config8(dev, HOSTC, HST_EN); + + /* Set SMBus I/O space enable. */ + pci_write_config16(dev, PCI_COMMAND, PCI_COMMAND_IO); + + /* Disable interrupt generation. */ + outb(0, SMBUS_IO_BASE + SMBHSTCTL); + + /* Clear any lingering errors, so transactions can run. */ + outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT); + printk(BIOS_DEBUG, "SMBus controller enabled.\n"); +} + +int smbus_read_byte(unsigned device, unsigned address) +{ + return do_smbus_read_byte(SMBUS_IO_BASE, device, address); +} diff --git a/src/soc/intel/sch/gma.c b/src/soc/intel/sch/gma.c new file mode 100644 index 0000000000..4c92444060 --- /dev/null +++ b/src/soc/intel/sch/gma.c @@ -0,0 +1,85 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008-2009 coresystems GmbH + * + * 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 <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <drivers/intel/gma/i915.h> +#include "chip.h" + +static void gma_func0_init(struct device *dev) +{ + u32 reg32; + + /* IGD needs to be bus master. */ + reg32 = pci_read_config32(dev, PCI_COMMAND); + pci_write_config32(dev, PCI_COMMAND, reg32 | PCI_COMMAND_MASTER); + + pci_dev_init(dev); +} + +static void gma_set_subsystem(device_t dev, unsigned vendor, unsigned device) +{ + if (!vendor || !device) { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + pci_read_config32(dev, PCI_VENDOR_ID)); + } else { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + ((device & 0xffff) << 16) | (vendor & 0xffff)); + } +} + +const struct i915_gpu_controller_info * +intel_gma_get_controller_info(void) +{ + device_t dev = dev_find_slot(0, PCI_DEVFN(0x2,0)); + if (!dev) { + return NULL; + } + struct soc_intel_sch_config *chip = dev->chip_info; + return &chip->gfx; +} + +static void gma_ssdt(device_t device) +{ + const struct i915_gpu_controller_info *gfx = intel_gma_get_controller_info(); + if (!gfx) { + return; + } + + drivers_intel_gma_displays_ssdt_generate(gfx); +} + +static struct pci_operations gma_pci_ops = { + .set_subsystem = gma_set_subsystem, +}; + +static struct device_operations gma_func0_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .acpi_fill_ssdt_generator = gma_ssdt, + .init = gma_func0_init, + .scan_bus = 0, + .enable = 0, + .ops_pci = &gma_pci_ops, +}; + +static const struct pci_driver sch_gma_func0_driver __pci_driver = { + .ops = &gma_func0_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x8108, +}; diff --git a/src/soc/intel/sch/ide.c b/src/soc/intel/sch/ide.c new file mode 100644 index 0000000000..56e51a5cac --- /dev/null +++ b/src/soc/intel/sch/ide.c @@ -0,0 +1,87 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2009-2010 iWave Systems + * + * 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 <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> + +/* PCI Configuration Space (D31:F1): IDE */ +#define INTR_LN 0x3c +#define IDE_TIM_PRI 0x80 /* IDE timings, primary */ + +extern int sch_port_access_read(int port, int reg, int bytes); + +static void ide_init(struct device *dev) +{ + u32 ideTimingConfig, reg32; + + printk(BIOS_DEBUG, "sch_ide: initializing... "); + + reg32 = pci_read_config32(dev, PCI_COMMAND); + pci_write_config32(dev, PCI_COMMAND, + reg32 | PCI_COMMAND_IO | PCI_COMMAND_MASTER); + + /* Program the clock. */ + if (sch_port_access_read(5, 3, 4) & (1 << 3)) { + /* 533MHz, Read PCI MC register */ + reg32 = pci_read_config32(dev, 0x60); + pci_write_config32(dev, 0x60, reg32 | 1); + } else { + /* 400MHz */ + reg32 = pci_read_config32(dev, 0x60); + reg32 &= ~1; + pci_write_config32(dev, 0x60, reg32); + } + + /* Enable primary IDE interface. 80=04 81=00 82=02 83=80 */ + ideTimingConfig = 0x80020000; + printk(BIOS_DEBUG, "IDE0 "); + pci_write_config32(dev, IDE_TIM_PRI, ideTimingConfig); + + /* Set Interrupt Line. */ + /* Interrupt Pin is set by D31IP.PIP */ + printk(BIOS_DEBUG, "\n"); +} + +static void ide_set_subsystem(device_t dev, unsigned vendor, unsigned device) +{ + if (!vendor || !device) { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + pci_read_config32(dev, PCI_VENDOR_ID)); + } else { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + ((device & 0xffff) << 16) | (vendor & 0xffff)); + } +} + +static struct pci_operations ide_pci_ops = { + .set_subsystem = ide_set_subsystem, +}; + +static struct device_operations ide_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = ide_init, + .scan_bus = 0, + .ops_pci = &ide_pci_ops, +}; + +static const struct pci_driver sch_ide __pci_driver = { + .ops = &ide_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x811A, +}; diff --git a/src/soc/intel/sch/lpc.c b/src/soc/intel/sch/lpc.c new file mode 100644 index 0000000000..f5e17d880a --- /dev/null +++ b/src/soc/intel/sch/lpc.c @@ -0,0 +1,230 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008-2009 coresystems GmbH + * Copyright (C) 2009-2010 iWave Systems + * + * 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 <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <arch/io.h> +#include <arch/ioapic.h> +#include <arch/acpigen.h> +#include <arch/acpigen.h> +#include <cpu/cpu.h> +#include <cbmem.h> +#include <string.h> +#include <drivers/intel/gma/i915.h> +#include "nvs.h" +#include "chip.h" + +/* SCH LPC defines */ +#define SCH_ACPI_CTL 0x58 +#define SCH_SIRQ_CTL 0x68 +#define PIRQA_ROUT 0x60 +#define PIRQB_ROUT 0x61 +#define PIRQC_ROUT 0x62 +#define PIRQD_ROUT 0x63 +#define PIRQE_ROUT 0x64 +#define PIRQF_ROUT 0x65 +#define PIRQG_ROUT 0x66 +#define PIRQH_ROUT 0x67 + +typedef struct soc_intel_sch_config config_t; + +/* PIRQ[n]_ROUT[3:0] - PIRQ Routing Control + * 0x00 - 0000 = Reserved + * 0x01 - 0001 = Reserved + * 0x02 - 0010 = Reserved + * 0x03 - 0011 = IRQ3 + * 0x04 - 0100 = IRQ4 + * 0x05 - 0101 = IRQ5 + * 0x06 - 0110 = IRQ6 + * 0x07 - 0111 = IRQ7 + * 0x08 - 1000 = Reserved + * 0x09 - 1001 = IRQ9 + * 0x0A - 1010 = IRQ10 + * 0x0B - 1011 = IRQ11 + * 0x0C - 1100 = IRQ12 + * 0x0D - 1101 = Reserved + * 0x0E - 1110 = IRQ14 + * 0x0F - 1111 = IRQ15 + * PIRQ[n]_ROUT[7] - PIRQ Routing Control + * 0x80 - The PIRQ is not routed. + */ + +#define PIRQA 0x03 +#define PIRQB 0x05 +#define PIRQC 0x06 +#define PIRQD 0x07 +#define PIRQE 0x09 +#define PIRQF 0x0A +#define PIRQG 0x0B +#define PIRQH 0x0C + +static void sch_pirq_init(device_t dev) +{ + device_t irq_dev; + + /* Get the chip configuration */ + config_t *config = dev->chip_info; + + pci_write_config8(dev, PIRQA_ROUT, config->pirqa_routing); + pci_write_config8(dev, PIRQB_ROUT, config->pirqb_routing); + pci_write_config8(dev, PIRQC_ROUT, config->pirqc_routing); + pci_write_config8(dev, PIRQD_ROUT, config->pirqd_routing); + + pci_write_config8(dev, PIRQE_ROUT, config->pirqe_routing); + pci_write_config8(dev, PIRQF_ROUT, config->pirqf_routing); + pci_write_config8(dev, PIRQG_ROUT, config->pirqg_routing); + pci_write_config8(dev, PIRQH_ROUT, config->pirqh_routing); + + /* Eric Biederman once said we should let the OS do this. + * I am not so sure anymore he was right. + */ + + for (irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) { + u8 int_pin = 0, int_line = 0; + + if (!irq_dev->enabled || irq_dev->path.type != DEVICE_PATH_PCI) + continue; + + int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN); + + switch (int_pin) { + case 1: /* INTA# */ + int_line = config->pirqa_routing; + break; + case 2: /* INTB# */ + int_line = config->pirqb_routing; + break; + case 3: /* INTC# */ + int_line = config->pirqc_routing; + break; + case 4: /* INTD# */ + int_line = config->pirqd_routing; + break; + } + + if (!int_line) + continue; + + pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, int_line); + } +} + +static void sch_fixups(struct device *dev) +{ + u32 rcba_base; + + /* This needs to happen after PCI enumeration. */ + /* RCBA32(0x1d40) |= 1; */ + rcba_base = pci_read_config32(dev, 0xF0); + + /* Remove the enable bit. */ + rcba_base = rcba_base >> 1; + rcba_base = rcba_base << 1; + *((volatile u32 *)(rcba_base +0x104)) &= 0xFF00FFFF; +} + +static void lpc_init(struct device *dev) +{ + printk(BIOS_DEBUG, "SCH: lpc_init\n"); + + /* Setup the PIRQ. */ + sch_pirq_init(dev); + pci_write_config8(dev, SCH_SIRQ_CTL,0x80); + sch_fixups(dev); +} + +static void sch_lpc_read_resources(device_t dev) +{ + struct resource *res; + + /* Get the normal PCI resources of this device. */ + pci_dev_read_resources(dev); + + /* Add an extra subtractive resource for both memory and I/O. */ + res = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0)); + res->base = 0; + res->size = 0xe000; + res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | + IORESOURCE_ASSIGNED | IORESOURCE_FIXED; + + res = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0)); + res->base = 0xff800000; + res->size = 0x00800000; /* 8 MB for flash */ + res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | + IORESOURCE_ASSIGNED | IORESOURCE_FIXED; + + res = new_resource(dev, 3); + res->base = IO_APIC_ADDR; + res->size = 0x00001000; + res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED; +} + +static void set_subsystem(device_t dev, unsigned vendor, unsigned device) +{ + if (!vendor || !device) { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + pci_read_config32(dev, PCI_VENDOR_ID)); + } else { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + ((device & 0xffff) << 16) | (vendor & 0xffff)); + } +} + +static void southbridge_inject_dsdt(device_t dev) +{ + global_nvs_t *gnvs = cbmem_add (CBMEM_ID_ACPI_GNVS, sizeof (*gnvs)); + + if (gnvs) { + const struct i915_gpu_controller_info *gfx = intel_gma_get_controller_info(); + memset(gnvs, 0, sizeof(*gnvs)); + acpi_create_gnvs(gnvs); + + gnvs->ndid = gfx->ndid; + memcpy(gnvs->did, gfx->did, sizeof(gnvs->did)); + + /* And tell SMI about it */ + smm_setup_structures(gnvs, NULL, NULL); + + /* Add it to SSDT. */ + acpigen_write_scope("\\"); + acpigen_write_name_dword("NVSA", (u32) gnvs); + acpigen_pop_len(); + } +} + +static struct pci_operations pci_ops = { + .set_subsystem = set_subsystem, +}; + +static struct device_operations device_ops = { + .read_resources = sch_lpc_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .acpi_inject_dsdt_generator = southbridge_inject_dsdt, + .write_acpi_tables = acpi_write_hpet, + .init = lpc_init, + .scan_bus = scan_lpc_bus, + .ops_pci = &pci_ops, +}; + +/* SCH LPC Interface */ +static const struct pci_driver sch_lpc __pci_driver = { + .ops = &device_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x8119, +}; diff --git a/src/soc/intel/sch/mmc.c b/src/soc/intel/sch/mmc.c new file mode 100644 index 0000000000..ccc2dc1687 --- /dev/null +++ b/src/soc/intel/sch/mmc.c @@ -0,0 +1,76 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2009-2010 iWave Systems + * + * 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 <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <arch/io.h> + +static void sch_mmc_init(struct device *dev) +{ + u32 reg32; + + printk(BIOS_DEBUG, "MMC: Setting up controller.. "); + reg32 = pci_read_config32(dev, PCI_COMMAND); + reg32 |= PCI_COMMAND_MASTER; + reg32 |= PCI_COMMAND_MEMORY; + pci_write_config32(dev, PCI_COMMAND, reg32); + printk(BIOS_DEBUG, "done.\n"); +} + +static void sch_mmc_set_subsystem(device_t dev, unsigned vendor, + unsigned device) +{ + if (!vendor || !device) { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + pci_read_config32(dev, PCI_VENDOR_ID)); + } else { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + ((device & 0xffff) << 16) | (vendor & 0xffff)); + } +} + +static struct pci_operations lops_pci = { + .set_subsystem = &sch_mmc_set_subsystem, +}; + +static struct device_operations sch_mmc_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = sch_mmc_init, + .scan_bus = 0, + .ops_pci = &lops_pci, +}; + +static const struct pci_driver sch_mmc1 __pci_driver = { + .ops = &sch_mmc_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x811C, +}; + +static const struct pci_driver sch_mmc2 __pci_driver = { + .ops = &sch_mmc_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x811D, +}; + +static const struct pci_driver sch_mmc3 __pci_driver = { + .ops = &sch_mmc_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x811E, + +}; diff --git a/src/soc/intel/sch/northbridge.c b/src/soc/intel/sch/northbridge.c new file mode 100644 index 0000000000..390a0bcb2e --- /dev/null +++ b/src/soc/intel/sch/northbridge.c @@ -0,0 +1,294 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * + * 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 <arch/io.h> +#include <stdint.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/hypertransport.h> +#include <stdlib.h> +#include <string.h> +#include <cbmem.h> +#include <cpu/cpu.h> +#include <arch/acpi.h> +#include "sch.h" + +static int get_pcie_bar(u32 *base, u32 *len) +{ + device_t dev; + u32 pciexbar_reg; + + dev = dev_find_slot(0, PCI_DEVFN(0, 0)); + if (!dev) + return 0; + + /* FIXME: Determine at runtime. */ +#ifdef POULSBO_PRE_B1 + pciexbar_reg = sch_port_access_read(0, 0, 4); +#else + pciexbar_reg = sch_port_access_read(2, 9, 4); +#endif + + if (!(pciexbar_reg & (1 << 0))) + return 0; + + switch ((pciexbar_reg >> 1) & 3) { + case 0: /* 256MB */ + *base = pciexbar_reg & ((1 << 31) | (1 << 30) | (1 << 29) | + (1 << 28)); + *len = 256 * 1024 * 1024; + return 1; + case 1: /* 128M */ + *base = pciexbar_reg & ((1 << 31) | (1 << 30) | (1 << 29) | + (1 << 28) | (1 << 27)); + *len = 128 * 1024 * 1024; + return 1; + case 2: /* 64M */ + *base = pciexbar_reg & ((1 << 31) | (1 << 30) | (1 << 29) | + (1 << 28) | (1 << 27) | (1 << 26)); + *len = 64 * 1024 * 1024; + return 1; + } + + return 0; +} + +static void add_fixed_resources(struct device *dev, int index) +{ + struct resource *resource; + u32 pcie_config_base, pcie_config_size; + + if (get_pcie_bar(&pcie_config_base, &pcie_config_size)) { + printk(BIOS_DEBUG, "Adding PCIe config bar\n"); + resource = new_resource(dev, index++); + resource->base = (resource_t) pcie_config_base; + resource->size = (resource_t) pcie_config_size; + resource->flags = IORESOURCE_MEM | IORESOURCE_RESERVE | + IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED; + } + + printk(BIOS_DEBUG, "Adding CMC shadow area\n"); + resource = new_resource(dev, index++); + resource->base = (resource_t) CMC_SHADOW; + resource->size = (resource_t) (64 * 1024); + resource->flags = IORESOURCE_MEM | IORESOURCE_RESERVE | + IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED; +} + +static void pci_domain_set_resources(device_t dev) +{ + u32 pci_tolm; + u8 reg8; + u16 reg16; + unsigned long long tomk, tolud, tomk_stolen; + uint64_t uma_memory_base = 0, uma_memory_size = 0; + uint64_t tseg_memory_base = 0, tseg_memory_size = 0; + + /* Can we find out how much memory we can use at most this way? */ + pci_tolm = find_pci_tolm(dev->link_list); + printk(BIOS_DEBUG, "pci_tolm: 0x%x\n", pci_tolm); + printk(BIOS_SPEW, "Base of stolen memory: 0x%08x\n", + pci_read_config32(dev_find_slot(0, PCI_DEVFN(2, 0)), 0x5c)); + + tolud = sch_port_access_read(2, 8, 4); + printk(BIOS_SPEW, "Top of Low Used DRAM: 0x%08llx\n", tolud); + + tomk = tolud / 1024; + tomk_stolen = tomk; + + /* Note: subtract IGD device and TSEG. */ + reg8 = pci_read_config8(dev_find_slot(0, PCI_DEVFN(0, 0)), 0x9e); + if (reg8 & 1) { + int tseg_size = 0; + printk(BIOS_DEBUG, "TSEG decoded, subtracting "); + reg8 >>= 1; + reg8 &= 3; + switch (reg8) { + case 0: + tseg_size = 1024; /* TSEG = 1M */ + break; + case 1: + tseg_size = 2048; /* TSEG = 2M */ + break; + case 2: + tseg_size = 8192; /* TSEG = 8M */ + break; + } + + printk(BIOS_DEBUG, "%dM\n", tseg_size >> 10); + tomk_stolen -= tseg_size; + + /* For reserving TSEG memory in the memory map */ + tseg_memory_base = tomk_stolen * 1024ULL; + tseg_memory_size = tseg_size * 1024ULL; + } + + reg16 = pci_read_config16(dev_find_slot(0, PCI_DEVFN(2, 0)), GGC); + if (!(reg16 & 2)) { + int uma_size = 0; + printk(BIOS_DEBUG, "IGD decoded, subtracting "); + reg16 >>= 4; + reg16 &= 7; + switch (reg16) { + case 1: + uma_size = 1024; + break; + case 2: + uma_size = 4096; + break; + case 3: + uma_size = 8192; + break; + } + printk(BIOS_DEBUG, "%dM UMA\n", uma_size >> 10); + tomk_stolen -= uma_size; + + /* For reserving UMA memory in the memory map. */ + uma_memory_base = tomk_stolen * 1024ULL; + uma_memory_size = uma_size * 1024ULL; + } + + /* + * The following needs to be 2 lines, otherwise the second + * number is always 0. + */ + printk(BIOS_INFO, "Available memory: %dK", (u32) tomk); + printk(BIOS_INFO, " (%dM)\n", (u32) (tomk >> 10)); + + /* Report the memory regions. */ + ram_resource(dev, 3, 0, 640); + ram_resource(dev, 4, 768, (tomk - 768)); + uma_resource(dev, 5, uma_memory_base >> 10, uma_memory_size >> 10); + mmio_resource(dev, 6, tseg_memory_base >> 10, tseg_memory_size >> 10); + + add_fixed_resources(dev, 7); + + assign_resources(dev->link_list); + + set_top_of_ram(tomk * 1024 - uma_memory_size - tseg_memory_base); +} + +/* + * TODO: We could determine how many PCIe busses we need in the bar. For now + * that number is hardcoded to a max of 64. + * See e7525/northbridge.c for an example. + */ +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, +}; + +static void mc_read_resources(device_t dev) +{ + struct resource *resource; + + pci_dev_read_resources(dev); + + /* + * So, this is one of the big mysteries in the coreboot resource + * allocator. This resource should make sure that the address space + * of the PCIe memory mapped config space bar. But it does not. + */ + + /* + * We use 0xcf as an unused index for our PCIe bar so that we find + * it again. + */ + resource = new_resource(dev, 0xcf); + resource->flags = IORESOURCE_MEM | IORESOURCE_FIXED | + IORESOURCE_STORED | IORESOURCE_ASSIGNED; + get_pcie_bar((u32 *)&resource->base, (u32 *)&resource->size); + printk(BIOS_DEBUG, + "Adding PCIe enhanced config space BAR 0x%08lx-0x%08lx.\n", + (unsigned long)(resource->base), + (unsigned long)(resource->base + resource->size)); +} + +static void mc_set_resources(device_t dev) +{ + struct resource *resource; + + /* Report the PCIe BAR. */ + resource = find_resource(dev, 0xcf); + if (resource) + report_resource_stored(dev, resource, "<mmconfig>"); + + /* And call the normal set_resources. */ + pci_dev_set_resources(dev); +} + +static void intel_set_subsystem(device_t dev, unsigned vendor, unsigned device) +{ + if (!vendor || !device) { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + pci_read_config32(dev, PCI_VENDOR_ID)); + } else { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + ((device & 0xffff) << 16) | (vendor & 0xffff)); + } +} + +static struct pci_operations intel_pci_ops = { + .set_subsystem = intel_set_subsystem, +}; + +static struct device_operations mc_ops = { + .read_resources = mc_read_resources, + .set_resources = mc_set_resources, + .enable_resources = pci_dev_enable_resources, + .acpi_fill_ssdt_generator = generate_cpu_entries, + .scan_bus = 0, + .ops_pci = &intel_pci_ops, +}; + +static const struct pci_driver mc_driver __pci_driver = { + .ops = &mc_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x8100, +}; + +static void cpu_bus_init(device_t dev) +{ + initialize_cpus(dev->link_list); +} + +static struct device_operations cpu_bus_ops = { + .read_resources = DEVICE_NOOP, + .set_resources = DEVICE_NOOP, + .enable_resources = DEVICE_NOOP, + .init = cpu_bus_init, + .scan_bus = 0, +}; + +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; + } +} + +struct chip_operations northbridge_intel_sch_ops = { + CHIP_NAME("Intel SCH Northbridge") + .enable_dev = enable_dev, +}; diff --git a/src/soc/intel/sch/nvs.h b/src/soc/intel/sch/nvs.h new file mode 100644 index 0000000000..88c4998094 --- /dev/null +++ b/src/soc/intel/sch/nvs.h @@ -0,0 +1,140 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008-2009 coresystems GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef SOC_INTEL_SCH_NVS_H +#define SOC_INTEL_SCH_NVS_H + +typedef struct { + /* Miscellaneous */ + u16 osys; /* 0x00 - Operating System */ + u8 smif; /* 0x02 - SMI function call ("TRAP") */ + u8 prm0; /* 0x03 - SMI function call parameter */ + u8 prm1; /* 0x04 - SMI function call parameter */ + u8 scif; /* 0x05 - SCI function call (via _L00) */ + u8 prm2; /* 0x06 - SCI function call parameter */ + u8 prm3; /* 0x07 - SCI function call parameter */ + u8 lckf; /* 0x08 - Global Lock function for EC */ + u8 prm4; /* 0x09 - Lock function parameter */ + u8 prm5; /* 0x0a - Lock function parameter */ + u32 p80d; /* 0x0b - Debug port (IO 0x80) value */ + u8 lids; /* 0x0f - LID state (open = 1) */ + u8 pwrs; /* 0x10 - Power state (AC = 1) */ + u8 dbgs; /* 0x11 - Debug state */ + u8 linx; /* 0x12 - Linux OS */ + u8 dckn; /* 0x13 - PCIe docking state */ + /* Thermal policy */ + u8 actt; /* 0x14 - active trip point */ + u8 psvt; /* 0x15 - passive trip point */ + u8 tc1v; /* 0x16 - passive trip point TC1 */ + u8 tc2v; /* 0x17 - passive trip point TC2 */ + u8 tspv; /* 0x18 - passive trip point TSP */ + u8 crtt; /* 0x19 - critical trip point */ + u8 dtse; /* 0x1a - Digital Thermal Sensor enable */ + u8 dts1; /* 0x1b - DT sensor 1 */ + u8 dts2; /* 0x1c - DT sensor 2 */ + u8 rsvd2; + /* Battery Support */ + u8 bnum; /* 0x1e - number of batteries */ + u8 b0sc, b1sc, b2sc; /* 0x1f-0x21 - stored capacity */ + u8 b0ss, b1ss, b2ss; /* 0x22-0x24 - stored status */ + u8 rsvd3[3]; + /* Processor Identification */ + u8 apic; /* 0x28 - APIC enabled */ + u8 mpen; /* 0x29 - MP capable/enabled */ + u8 pcp0; /* 0x2a - PDC CPU/CORE 0 */ + u8 pcp1; /* 0x2b - PDC CPU/CORE 1 */ + u8 ppcm; /* 0x2c - Max. PPC state */ + u8 rsvd4[5]; + /* Super I/O & CMOS config */ + u8 natp; /* 0x32 - SIO type */ + u8 cmap; /* 0x33 - */ + u8 cmbp; /* 0x34 - */ + u8 lptp; /* 0x35 - LPT port */ + u8 fdcp; /* 0x36 - Floppy Disk Controller */ + u8 rfdv; /* 0x37 - */ + u8 hotk; /* 0x38 - Hot Key */ + u8 rtcf; + u8 util; + u8 acin; + /* Integrated Graphics Device */ + u8 igds; /* 0x3c - IGD state */ + u8 tlst; /* 0x3d - Display Toggle List Pointer */ + u8 cadl; /* 0x3e - currently attached devices */ + u8 padl; /* 0x3f - previously attached devices */ + u16 cste; /* 0x40 - current display state */ + u16 nste; /* 0x42 - next display state */ + u16 sste; /* 0x44 - set display state */ + u8 ndid; /* 0x46 - number of device ids */ + u32 did[5]; /* 0x47 - 5b device id 1..5 */ + u8 rsvd5[0x9]; + /* Backlight Control */ + u8 blcs; /* 0x64 - Backlight Control possible */ + u8 brtl; + u8 odds; + u8 rsvd6[0x7]; + /* Ambient Light Sensors*/ + u8 alse; /* 0x6e - ALS enable */ + u8 alaf; + u8 llow; + u8 lhih; + u8 rsvd7[0x6]; + /* EMA */ + u8 emae; /* 0x78 - EMA enable */ + u16 emap; + u16 emal; + u8 rsvd8[0x5]; + /* MEF */ + u8 mefe; /* 0x82 - MEF enable */ + u8 rsvd9[0x9]; + /* TPM support */ + u8 tpmp; /* 0x8c - TPM */ + u8 tpme; + u8 rsvd10[8]; + /* SATA */ + u8 gtf0[7]; /* 0x96 - GTF task file buffer for port 0 */ + u8 gtf1[7]; + u8 gtf2[7]; + u8 idem; + u8 idet; + u8 rsvd11[7]; + /* IGD OpRegion (not implemented yet) */ + u32 aslb; /* 0xb4 - IGD OpRegion Base Address */ + u8 ibtt; + u8 ipat; + u8 itvf; + u8 itvm; + u8 ipsc; + u8 iblc; + u8 ibia; + u8 issc; + u8 i409; + u8 i509; + u8 i609; + u8 i709; + u8 idmm; + u8 idms; + u8 if1e; + u8 hvco; + u32 nxd[8]; + u8 rsvd12[8]; + /* Mainboard specific */ + u8 dock; /* 0xf0 - Docking Status */ + u8 bten; + u8 rsvd13[14]; +} __attribute__((packed)) global_nvs_t; + +void acpi_create_gnvs(global_nvs_t * gnvs); + +#endif /* SOC_INTEL_SCH_NVS_H */ diff --git a/src/soc/intel/sch/pcie.c b/src/soc/intel/sch/pcie.c new file mode 100644 index 0000000000..6ad5345f8a --- /dev/null +++ b/src/soc/intel/sch/pcie.c @@ -0,0 +1,91 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008-2009 coresystems GmbH + * Copyright (C) 2009-2010 iWave Systems + * + * 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 <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> + +static void pci_init(struct device *dev) +{ + u16 reg16; + u32 reg32; + + printk(BIOS_DEBUG, "Initializing SCH PCIe bridge.\n"); + + /* Enable Bus Master */ + reg32 = pci_read_config32(dev, PCI_COMMAND); + reg32 |= PCI_COMMAND_MASTER; + pci_write_config32(dev, PCI_COMMAND, reg32); + + /* Set Cache Line Size to 0x10 */ + // This has no effect but the OS might expect it + pci_write_config8(dev, 0x0c, 0x10); + //pci_write_config32(dev, 0x18, 0x11); + + //reg16 = pci_read_config16(dev, 0x3e); + //reg16 &= ~(1 << 0); /* disable parity error response */ + // reg16 &= ~(1 << 1); /* disable SERR */ + //reg16 |= (1 << 2); /* ISA enable */ + //pci_write_config16(dev, 0x3e, reg16); + /* Slot implemented. */ + reg16 = pci_read_config16(dev, 0x42); + reg16 |= (1 << 8); + pci_write_config16(dev, 0x42, reg16); + + reg16 = pci_read_config16(dev, 0x48); + reg16 |= 0xf; + pci_write_config16(dev, 0x48, reg16); +} + +static void pcie_set_subsystem(device_t dev, unsigned vendor, unsigned device) +{ + /* NOTE: This is not the default position! */ + if (!vendor || !device) { + pci_write_config32(dev, 0x94, pci_read_config32(dev, 0)); + } else { + pci_write_config32(dev, 0x94, + ((device & 0xffff) << 16) | (vendor & 0xffff)); + } +} + +static struct pci_operations pci_ops = { + .set_subsystem = pcie_set_subsystem, +}; + +static struct device_operations device_ops = { + .read_resources = pci_bus_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_bus_enable_resources, + .init = pci_init, + .scan_bus = pci_scan_bridge, + .ops_pci = &pci_ops, +}; + +/* Port 1 */ +static const struct pci_driver sch_pcie_port1 __pci_driver = { + .ops = &device_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x8110, +}; + +/*Port 2 */ +static const struct pci_driver sch_pcie_port2 __pci_driver = { + .ops = &device_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x8112, +}; diff --git a/src/soc/intel/sch/port_access.c b/src/soc/intel/sch/port_access.c new file mode 100644 index 0000000000..320c537069 --- /dev/null +++ b/src/soc/intel/sch/port_access.c @@ -0,0 +1,73 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2009-2010 iWave Systems + * + * 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. + */ + +// Use simple device model for this file even in ramstage +#define __SIMPLE_DEVICE__ + +#include <stdint.h> +#include <arch/io.h> +#include <device/pci_def.h> +#include <device/pnp_def.h> +#include <cpu/x86/lapic.h> +#include "sch.h" + +/* + * Restricted Access Regions: + * + * MCR - Message Control Register + * 31 24 16 8 4 0 + * ---------------------------------------------------------------------------- + * | | | Target | Write | | + * | Opcode | Port | register | byte | Reserved | + * | | | Address | Enables | | + * ---------------------------------------------------------------------------- + * + * MDR - Message Data Register + * 31 0 + * ---------------------------------------------------------------------------- + * | | + * | Data | + * | | + * ---------------------------------------------------------------------------- + */ + +#define MSG_OPCODE_READ 0xD0000000 +#define MSG_OPCODE_WRITE 0xE0000000 + +#define MCR 0xD0 +#define MDR 0xD4 + +int sch_port_access_read(int port, int reg, int bytes) +{ + pci_write_config32(PCI_DEV(0, 0, 0), MCR, + (MSG_OPCODE_READ | (port << 16) | (reg << 8))); + return pci_read_config32(PCI_DEV(0, 0, 0), MDR); +} + +void sch_port_access_write(int port, int reg, int bytes, long data) +{ + pci_write_config32(PCI_DEV(0, 0, 0), MDR, data); + pci_write_config32(PCI_DEV(0, 0, 0), MCR, + (MSG_OPCODE_WRITE | (port << 16) | (reg << 8))); + pci_read_config32(PCI_DEV(0, 0, 0), MDR); +} + +void sch_port_access_write_ram_cmd(int cmd, int port, int reg, int data) +{ + pci_write_config32(PCI_DEV(0, 0, 0), MDR, data); + pci_write_config32(PCI_DEV(0, 0, 0), MCR, + ((cmd << 24) | (port << 16) | (reg << 8))); + pci_read_config32(PCI_DEV(0, 0, 0), MDR); +} diff --git a/src/soc/intel/sch/raminit.c b/src/soc/intel/sch/raminit.c new file mode 100644 index 0000000000..d5ec4ef8ad --- /dev/null +++ b/src/soc/intel/sch/raminit.c @@ -0,0 +1,373 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2009-2010 iWave Systems + * + * 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 <string.h> +#include <cpu/x86/mtrr.h> +#include <cpu/x86/cache.h> +#include <spd.h> +#include "raminit.h" +#include "sch.h" + +#define DEBUG_RAM_SETUP +#define SOFTSTRSP(base, off) *((volatile u8 *)((base) + (off))) + +/* Debugging macros. */ +#if defined(DEBUG_RAM_SETUP) +#define PRINTK_DEBUG(x...) printk(BIOS_DEBUG, x) +#else +#define PRINTK_DEBUG(x...) +#endif + +#define BOOT_MODE_RESUME 1 +#define BOOT_MODE_NORMAL 0 + +#include "port_access.c" + +static void detect_fsb(struct sys_info *sysinfo) +{ + u32 reg32; + + reg32 = sch_port_access_read(5, 3, 4); + if (reg32 & BIT(3)) + sysinfo->fsb_frequency = 533; + else + sysinfo->fsb_frequency = 400; +} + +static u32 detect_softstrap_base(void) +{ + u32 reg32, base_addr; + + reg32 = sch_port_access_read(4, 0x71, 2); + reg32 &= 0x700; + reg32 = reg32 >> 7; + switch (reg32) { + case 7: + base_addr = 0xFFFB0000; + break; + case 6: + base_addr = 0xFFFC0000; + break; + case 5: + base_addr = 0xFFFD0000; + break; + case 4: + base_addr = 0xFFFE0000; + break; + default: + base_addr = 0; + die("No valid softstrap base found.\n"); + } + return base_addr; +} + +static void detect_softstraps(struct sys_info *sysinfo) +{ + u8 reg8, temp; + u32 sbase = detect_softstrap_base(); + + reg8 = SOFTSTRSP(sbase, 0x87f2); + sysinfo->ranks = reg8; + if (reg8 == 0) { + sysinfo->ram_param_source = RAM_PARAM_SOURCE_SPD; + /* FIXME: Implement SPD reading. */ + die("No support for reading DIMM config from SPD yet!"); + return; + } else { + sysinfo->ram_param_source = RAM_PARAM_SOURCE_SOFTSTRAP; + /* Timings from soft strap */ + reg8 = SOFTSTRSP(sbase, 0x87f0); + temp = reg8 & 0x30; + temp = temp >> 4; + sysinfo->cl = temp; + temp = reg8 & 0x0c; + temp = temp >> 2; + sysinfo->trcd = temp; + temp = reg8 & 0x03; + sysinfo->trp = temp; + + /* Geometry from Softstrap */ + reg8 = SOFTSTRSP(sbase, 0x87f1); + + temp = reg8 & 0x06; + temp = temp >> 1; + sysinfo->device_density = temp; + + temp = reg8 & 0x01; + sysinfo->data_width = temp; + + /* Refresh rate default 7.8us */ + sysinfo->refresh = 3; + } +} + +static void program_sch_dram_data(struct sys_info *sysinfo) +{ + u32 reg32; + + /* + * Program DRP DRAM Rank Population and Interface Register as per data + * in sysinfo SCH port 1 register 0..0xFF. + */ + reg32 = + sch_port_access_read(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DRP, 4); + reg32 &= ~(DRP_FIELDS); /* Clear all DRP fields we'll change. */ + /* Rank0 Device Width, Density, Enable */ + reg32 |= sysinfo->data_width | (sysinfo->device_density << 1) | (1 << 3); + /* Rank1 Device Width, Density, Enable */ + reg32 |= (sysinfo->data_width << 4) + | ((sysinfo->device_density) << 5) | (1 << 7); + sch_port_access_write(SCH_MSG_DUNIT_PORT, + SCH_MSG_DUNIT_REG_DRP, 4, reg32); + + /* + * Program DTR DRAM Timing Register as per data in sysinfo SCH port 1 + * register 1. + * + * tRD_dly = 2 (15:13 = 010b) + * 0X3F + */ + reg32 = + sch_port_access_read(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DTR, 4); + reg32 &= ~(DTR_FIELDS); /* Clear all DTR fields we'll change. */ + + reg32 = (sysinfo->trp); + reg32 |= (sysinfo->trcd) << 2; + reg32 |= (sysinfo->cl) << 4; + reg32 |= 0X4000; /* tRD_dly = 2 (15:13 = 010b) */ + sch_port_access_write(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DTR, 4, + reg32); + + /* + * DCO DRAM Controller Operation Register as per data in sysinfo + * SCH port 1 register 2 0xF. + */ + reg32 = + sch_port_access_read(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DCO, 4); + reg32 &= ~(DCO_FIELDS); /* Clear all DTR fields we'll change. */ + + if (sysinfo->fsb_frequency == 533) + reg32 |= 1; + else + reg32 &= ~(BIT(0)); + reg32 = 0x006911c; // FIXME ? + + sch_port_access_write(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DCO, 4, + reg32); +} + +static void program_dll_config(struct sys_info *sysinfo) +{ + if (sysinfo->fsb_frequency == 533) { + sch_port_access_write(SCH_MSG_DUNIT_PORT, 0x21, 4, 0x46464646); + sch_port_access_write(SCH_MSG_DUNIT_PORT, 0x22, 4, 0x46464646); + } else { + sch_port_access_write(SCH_MSG_DUNIT_PORT, 0x21, 4, 0x58585858); + sch_port_access_write(SCH_MSG_DUNIT_PORT, 0x22, 4, 0x58585858); + } + sch_port_access_write(SCH_MSG_DUNIT_PORT, 0x23, 4, 0x2222); + if (sysinfo->fsb_frequency == 533) + sch_port_access_write(SCH_MSG_DUNIT_PORT, 0x20, 4, 0x993B); + else + sch_port_access_write(SCH_MSG_DUNIT_PORT, 0x20, 4, 0xCC3B); +} + +static void do_jedec_init(struct sys_info *sysinfo) +{ + u32 reg32, rank, cmd, temp, num_ranks; + + /* Performs JEDEC memory initializattion for all memory rows */ + /* Set CKE0/1 low */ + reg32 = + sch_port_access_read(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DRP, 4); + reg32 |= DRP_CKE_DIS; + sch_port_access_write(SCH_MSG_DUNIT_PORT, + SCH_MSG_DUNIT_REG_DRP, 4, reg32); + reg32 = + sch_port_access_read(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DRP, 4); + rank = 0; + num_ranks = sysinfo->ranks; + + do { + /* Start clocks */ + reg32 = sch_port_access_read(SCH_MSG_DUNIT_PORT, + SCH_MSG_DUNIT_REG_DRP, 4); + reg32 &= ~(DRP_SCK_DIS); /* Enable all SCK/SCKB by def. */ + sch_port_access_write(1, SCH_MSG_DUNIT_REG_DRP, 4, reg32); + /* Program misc. SCH registers on rank 0 initialization. */ + reg32 = sch_port_access_read(SCH_MSG_DUNIT_PORT, + SCH_MSG_DUNIT_REG_DRP, 4); + if (rank == 0) + program_dll_config(sysinfo); + + printk(BIOS_DEBUG, "Setting up RAM \n"); + + /* + * Wait 200us + * reg32 = inb(ACPI_BASE + 8); PM1 Timer + * reg32 &=0xFFFFFF; + * reg32 +=0x2EE; + * do { + * reg32 = inb(ACPI_BASE + 8);PM1 Timer + * reg32 &= 0xFFFFFF; + * } while (reg32 < 0x2EE); + */ + + /* Apply NOP. */ + cmd = rank; + cmd |= SCH_DRAMINIT_CMD_NOP; + sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT, + SCH_MSG_DUNIT_PORT, 0, cmd); + /* Set CKE=high. */ + reg32 = sch_port_access_read(SCH_MSG_DUNIT_PORT, + SCH_MSG_DUNIT_REG_DRP, 4); + reg32 &= 0xFFFF9FFF; /* Clear both the CKE static disables. */ + sch_port_access_write(SCH_MSG_DUNIT_PORT, + SCH_MSG_DUNIT_REG_DRP, 4, reg32); + /* + * Wait 400ns (not needed when executing from flash). + * Precharge all. + */ + reg32 = sch_port_access_read(SCH_MSG_DUNIT_PORT, + SCH_MSG_DUNIT_REG_DRP, 4); + cmd = rank; + cmd |= SCH_DRAMINIT_CMD_PALL; + sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT, + SCH_MSG_DUNIT_PORT, 0, cmd); + + /* + * EMRS(2); High temp self refresh=disabled, + * partial array self refresh=full. + */ + cmd = rank; + cmd |= SCH_DRAMINIT_CMD_EMRS2; + sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT, + SCH_MSG_DUNIT_PORT, 0, cmd); + + /* EMRS(3) (no command). */ + cmd = rank; + cmd |= SCH_DRAMINIT_CMD_EMRS3; + sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT, + SCH_MSG_DUNIT_PORT, 0, cmd); + + /* EMRS(1); Enable DLL (Leave all bits in the command at 0). */ + cmd = rank; + cmd |= SCH_DRAMINIT_CMD_EMRS1; + sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT, + SCH_MSG_DUNIT_PORT, 0, cmd); + + /* MRS; Reset DLL (Set memory address bit 8). */ + cmd = rank; + cmd |= SCH_DRAMINIT_CMD_MRS; + cmd |= (SCH_JEDEC_DLLRESET << SCH_DRAMINIT_ADDR_OFFSET); + sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT, + SCH_MSG_DUNIT_PORT, 0, cmd); + + /* Precharge all. */ + cmd = rank; + cmd |= SCH_DRAMINIT_CMD_PALL; + sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT, + SCH_MSG_DUNIT_PORT, 0, cmd); + + /* Issue 2 auto-refresh commands. */ + cmd = rank; + cmd |= SCH_DRAMINIT_CMD_AREF; + sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT, + SCH_MSG_DUNIT_PORT, 0, cmd); + sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT, + SCH_MSG_DUNIT_PORT, 0, cmd); + + /* MRS command including tCL, tWR, burst length (always 4). */ + cmd = rank; + cmd |= (SCH_DRAMINIT_CMD_MRS + JEDEC_STATIC_PARAM); /* Static param */ + temp = sysinfo->cl; + temp += TCL_LOW; /* Adjust for the TCL base. */ + temp = temp << ((SCH_JEDEC_CL_OFFSET + + SCH_DRAMINIT_ADDR_OFFSET)); /* Ready the CAS latency */ + cmd |= temp; + sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT, + SCH_MSG_DUNIT_PORT, 0, cmd); + + /* + * Wait 200 clocks (max of 1us, so no need to delay). + * Issue EMRS(1):OCD default. + */ + cmd = rank; + cmd |= SCH_DRAMINIT_CMD_EMRS1; + cmd |= (SCH_JEDEC_OCD_DEFAULT << SCH_DRAMINIT_ADDR_OFFSET); + sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT, + SCH_MSG_DUNIT_PORT, 0, cmd); + + /* Issue EMRS(1): OCD cal. mode exit. */ + cmd = rank; + cmd |= SCH_DRAMINIT_CMD_EMRS1; + cmd |= (SCH_JEDEC_DQS_DIS << SCH_DRAMINIT_ADDR_OFFSET); + sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT, + SCH_MSG_DUNIT_PORT, 0, cmd); + rank += SCH_DRAMINIT_RANK_MASK; + num_ranks--; + } while (num_ranks); +} + +/** + * @param boot_mode 0 = normal, 1 = resume + */ +void sdram_initialize(int boot_mode) +{ + struct sys_info sysinfo; + u32 reg32; + + printk(BIOS_DEBUG, "Setting up RAM controller.\n"); + + memset(&sysinfo, 0, sizeof(sysinfo)); + + detect_fsb(&sysinfo); + detect_softstraps(&sysinfo); + + program_sch_dram_data(&sysinfo); + + /* cold boot */ + if (boot_mode == BOOT_MODE_NORMAL) + do_jedec_init(&sysinfo); + else + program_dll_config(&sysinfo); + + /* RAM init complete. */ + reg32 = + sch_port_access_read(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DCO, 4); + reg32 |= DCO_IC; + reg32 |= ((sysinfo.refresh) << 2); + reg32 = 0x006919c; + sch_port_access_write(SCH_MSG_DUNIT_PORT, + SCH_MSG_DUNIT_REG_DCO, 4, reg32); + + /* Setting up TOM. */ + reg32 = 0x10000000; + reg32 = reg32 >> sysinfo.data_width; + reg32 = reg32 << sysinfo.device_density; + reg32 = reg32 << sysinfo.ranks; + reg32 = 0x40000000; + sch_port_access_write(2, 8, 4, reg32); + + /* Resume mode. */ + if (boot_mode == BOOT_MODE_RESUME) + sch_port_access_write_ram_cmd(SCH_OPCODE_WAKEFULLON, + SCH_MSG_DUNIT_PORT, 0, 0); + + sch_port_access_write(2, 0, 4, 0x98); + sch_port_access_write(2, 3, 4, 0x7); + sch_port_access_write(3, 2, 4, 0x408); + sch_port_access_write(4, 0x71, 4, 0x600); +} diff --git a/src/soc/intel/sch/raminit.h b/src/soc/intel/sch/raminit.h new file mode 100644 index 0000000000..4a81ec1580 --- /dev/null +++ b/src/soc/intel/sch/raminit.h @@ -0,0 +1,178 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2009-2010 iWave Systems + * + * 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 RAMINIT_H +#define RAMINIT_H + +/** + * Bit Equates + **/ +#define BIT(x) (1<<x) + +#define EBP_TRP_MASK (BIT(1) | BIT(0)) +#define TRP_LOW 3h +#define TRP_HIGH 5h +#define EBP_TRP_OFFSET 0 /* Start of TRP field in EBP*/ +#define EBP_TRCD_MASK (BIT(3) | BIT(2)) +#define TRCD_LOW 3h +#define TRCD_HIGH 5h +#define EBP_TRCD_OFFSET 2 /* Start of TRCD field in EBP*/ +#define EBP_TCL_MASK (BIT(5) | BIT(4)) +#define TCL_LOW 3 /* Minimum supported CL*/ +#define TCL_HIGH 5 /* Maximum supported CL*/ +#define EBP_TCL_OFFSET 4 /* EBP bit( )for CL mask*/ +#define EBP_DDR2_CL_5_0 BIT(5) /* CL 5.0 = 10b*/ +#define EBP_DDR2_CL_4_0 BIT(4) /* CL 4.0 = 01b*/ +#define EBP_DDR2_CL_3_0 00h /* CL 3.0 = 00b*/ +#define EBP_FREQ_MASK (BIT(10)| BIT(9)) +#define EBP_FREQ_OFFSET 9 /* EBP bit( )for frequency mask*/ +#define EBP_FREQ_400 0 /* 400MHz EBP[10:9] = 00b*/ +#define EBP_FREQ_533 BIT(9) /* 533MHz EBP[10:9] = 01b*/ +#define EBP_REFRESH_MASK (BIT(12)| BIT(11)) +#define EBP_REFRESH_OFFSET 11 /* Bit offset of refresh field*/ +#define EBP_REF_DIS 00h /* Mask for refresh disabled*/ +#define EBP_REF_128CLK BIT(11) /* Mask for 128 clks referesh rate*/ +#define EBP_REF_3_9 BIT(12) /* Mask for 3.9us refresh rate*/ +#define EBP_REF_7_8 (BIT(12)| BIT(11))/* Mask for 7.8us refresh rate*/ +#define EBP_WIDTH_MASK BIT(15) +#define EBP_WIDTH_OFFSET 15 /* Bit offset of EBP width field*/ +#define EBP_SOCKET_X16 BIT(15) /* Bit mask of x8/x16 bit*/ +#define EBP_DENSITY_MASK (BIT(17)| BIT(16)) +#define EBP_DENSITY_OFFSET 16 +#define EBP_DENSITY_512 BIT(16) /* 512Mbit density*/ +#define EBP_DENSITY_1024 BIT(17) /* 1024Mbit density*/ +#define EBP_DENSITY_2048 (BIT(17)| BIT(16))/* 2048Mbit density*/ +#define EBP_RANKS_MASK BIT(18) +#define EBP_RANKS_OFFSET 18 +#define EBP_RANKS BIT(18) /* Bit offset of # of ranks bit*/ +#define EBP_PACKAGE_TYPE BIT(19) /* Package type (stacked or not)*/ +#define EBP_2X_MASK BIT(20) +#define EBP_2X_OFFSET 20 /* Bit offset of ebp 2x refresh field*/ +#define EBP_2X_AUTO_REFRESH BIT(20) /* Bit mask of 2x refresh field*/ +#define EBP_DRAM_PARM_MASK BIT(21) +#define EBP_DRAM_PARM_OFFSET 21 +#define EBP_DRAM_PARM_SPD 0 /* Use SPD to get DRAM parameters*/ +#define EBP_DRAM_PARM_CMC BIT(21) /* DRAM parameters in CMC binary*/ +#define EBP_BOOT_PATH BIT(31) + + + + +#define HB_REG_MCR 0xD0 /* Message Control Register */ +#define HB_REG_MCR_OP_OFFSET 24 /* Offset of the opcode field in MCR */ +#define HB_REG_MCR_PORT_OFFSET 16 /* Offset of the port field in MCR */ +#define HB_REG_MCR_REG_OFFSET 8 /* Offset of the register field in MCR */ +#define HB_REG_MDR 0xD4 /* Message Data Register */ + +/* SCH Message OpCodes and Attributes*/ +#define SCH_OPCODE_WAKEFULLON 0x2 /* SCH message bus "Wake Full On" opcode*/ +#define SCH_OPCODE_DRAMINIT 0xA0 /* SCH message bus "DRAM Init" opcode */ +#define SCH_DRAMINIT_CMD_MRS 0x4000 /* MRS command */ +#define SCH_DRAMINIT_CMD_EMRS1 0x8 /* EMRS 1 command */ +#define SCH_DRAMINIT_CMD_EMRS2 0x10 /* EMRS 2 command */ +#define SCH_DRAMINIT_CMD_EMRS3 0x18 /* EMRS 3 command */ +#define SCH_DRAMINIT_CMD_CBR 0x1 /* CBR command */ +#define SCH_DRAMINIT_CMD_AREF 0x10001 /* Refresh command, MA10=0->All */ +#define SCH_DRAMINIT_CMD_PALL 0x10002 /* Precharge command, MA10=1->All */ +#define SCH_DRAMINIT_CMD_BACT 0x3 /* Bank activate command */ +#define SCH_DRAMINIT_CMD_NOP 0x7 /* NOP command */ +#define SCH_DRAMINIT_RANK_OFFSET 21 /* Offset of the rank selection bit */ +#define SCH_DRAMINIT_RANK_MASK BIT(21) +#define SCH_DRAMINIT_ADDR_OFFSET 6 /* Offset of the address field in MDR */ +#define SCH_DRAMINIT_INTLV BIT(3) /* Interleave burst type */ +#define SCH_DRAMINIT_BL4 2 /* Burst Length = 4 */ +#define SCH_DRAMINIT_CL_OFFSET 4 /* CAS Latency bit offset */ +#define SCH_DRAMINIT_OCD_DEFAULT 0xE000 /* OCD Default command */ +#define SCH_DRAMINIT_DQS_DIS BIT(16) /* DQS Disable command */ +#define SCH_OPCODE_READ 0xD0 /* SCH message bus "read" opcode */ +#define SCH_OPCODE_WRITE 0xE0 /* SCH message bus "write" opcode */ + +/* SCH Message Ports and Registers*/ + +#define SCH_MSG_DUNIT_PORT 0x1 /* DRAM unit port */ +#define SCH_MSG_DUNIT_REG_DRP 0x0 /* DRAM Rank Population and Interface */ +#define DRP_FIELDS 0xFF /* Pertinent fields in DRP */ +#define DRP_RANK0_OFFSET 3 /* Rank 0 enable offset */ +#define DRP_RANK1_OFFSET 7 /* Rank 1 enable offset */ +#define DRP_DENSITY0_OFFSET 1 /* Density offset - Rank 0 */ +#define DRP_DENSITY1_OFFSET 5 /* Density offset - Rank 1 */ +#define DRP_WIDTH0_OFFSET 0 /* Width offset - Rank 0 */ +#define DRP_WIDTH1_OFFSET 4 /* Width offset - Rank 1 */ +#define DRP_CKE_DIS (BIT(14)| BIT(13)) /* CKE disable bits for both ranks */ +#define DRP_CKE_DIS0 BIT(13) /* CKE disable bit - Rank 0 */ +#define DRP_CKE_DIS1 BIT(14) /* CKE disable bit - Rank 1 */ +#define DRP_SCK_DIS (BIT(11)| BIT(10)) /* SCK/SCKB disable bits */ +#define DRP_SCK_DIS1 BIT(11) /* SCK[1]/SCKB[1] disable */ +#define DRP_SCK_DIS0 BIT(10) /* SCK[0]/SCKB[0] disable */ +#define SCH_MSG_DUNIT_REG_DTR 0x01 /* DRAM Timing Register */ +#define DTR_FIELDS 0x3F /* Pertinent fields in DTR */ +#define DTR_TCL_OFFSET 4 /* CAS latency offset */ +#define DTR_TRCD_OFFSET 2 /* RAS CAS Delay Offset */ +#define DTR_TRP_OFFSET 0 /* RAS Precharge Delay Offset */ +#define SCH_MSG_DUNIT_REG_DCO 0x2 /* DRAM Control Register */ +#define DCO_FIELDS 0xF /* Pertinent fields in DCO */ +#define DCO_REFRESH_OFFSET 2 /* Refresh Rate Field Offset */ +#define DCO_FREQ_OFFSET 0 /* DRAM Frequency Field Offset */ +#define DCO_IC BIT(7) /* Initialization complete bit */ +#define SCH_MSG_PUNIT_PORT 04h /* Punit Port */ +#define SCH_MSG_PUNIT_REG_PCR 71h /* Punit Control Register */ +#define SCH_MSG_TEST_PORT 05h /* Test port */ +#define SCH_MSG_TEST_REG_MSR 03h /* Mode and Status Register */ + + +/* Jedec initialization mapping into the MDR address field for DRAM init messages*/ + + +#define SCH_JEDEC_DLLRESET BIT(8) /* DLL Reset bit( ) */ +#define SCH_JEDEC_INTLV BIT(3) /* Interleave/NOT(Sequential) bit( ) */ +#define SCH_JEDEC_CL_OFFSET 4 /* Offset of the CAS latency field */ +#define SCH_JEDEC_OCD_DEFAULT (BIT(7)| BIT(8)| BIT(9)) /* OCD default value */ +#define SCH_JEDEC_DQS_DIS BIT(10) /* DQS disable bit */ +#define SCH_JEDEC_BL4 BIT(1) /* Burst length 4 value */ +/*static values used during JEDEC iniatialization. These values are not +dependent on memory or chipset configuration.*/ +#define JEDEC_STATIC_PARAM ((SCH_JEDEC_INTLV << SCH_DRAMINIT_ADDR_OFFSET) + (SCH_JEDEC_BL4 << SCH_DRAMINIT_ADDR_OFFSET)) + +#define DIMM_SOCKETS 2 + +#define DIMM_SPD_BASE 0x50 +#define DIMM_TCO_BASE 0x30 + +/* Burst length is always 8 */ +#define BURSTLENGTH 8 +#define RAM_PARAM_SOURCE_SOFTSTRAP 1 +#define RAM_PARAM_SOURCE_SPD 0 +struct sys_info { + + u16 memory_frequency; /* 400 or 533*/ + u16 fsb_frequency; /* 400 or 533*/ + + u8 trp; /*3,4,5 DRAM clocks */ + u8 trcd; /*3,4,5 DRAM clocks */ + u8 cl; /*CAS Latency 3,4,5*/ + + u8 refresh; /*Refresh rate disabled,128 DRAM clocks,3.9us,7.8us */ + + u8 data_width; /*x8/x16 data width */ + u8 device_density; /*SDRAM Device Density 512/1024/2048Mbit */ + u8 ranks; /*Single/Double */ + u8 ram_param_source; /*DRAM Parameter Source SPD/SoftStraps(R) Block (down memory) */ + u8 boot_path; + +} __attribute__ ((packed)); + +void sdram_initialize(int boot_mode); + +#endif /* RAMINIT_H */ diff --git a/src/soc/intel/sch/reset.c b/src/soc/intel/sch/reset.c new file mode 100644 index 0000000000..2574565f75 --- /dev/null +++ b/src/soc/intel/sch/reset.c @@ -0,0 +1,29 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008-2009 coresystems GmbH + * + * 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 <reset.h> + +void soft_reset(void) +{ + outb(0x04, 0xcf9); +} + +void hard_reset(void) +{ + outb(0x02, 0xcf9); + outb(0x06, 0xcf9); +} diff --git a/src/soc/intel/sch/sch.h b/src/soc/intel/sch/sch.h new file mode 100644 index 0000000000..bdaddb296b --- /dev/null +++ b/src/soc/intel/sch/sch.h @@ -0,0 +1,69 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2010 coresystems GmbH + * Copyright (C) 2009-2010 iWave Systems + * + * 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 __SCH_POULSBO_H__ +#define __SCH_POULSBO_H__ + +#if !defined(__ASSEMBLER__) +int sch_port_access_read(int port, int reg, int bytes); +void sch_port_access_write(int port, int reg, int bytes, long data); +void sch_port_access_write_ram_cmd(int cmd, int port, int reg, int data); +#endif + +/* Southbridge IO BARs */ +/* TODO Make sure these don't get changed by stage2 */ +#define SCH_ENABLE_BIT (1<<31) +#define DEFAULT_ACPIPBLKBASE 0x510 + +#define DEFAULT_SMBUSBASE 0x540 +#define DEFAULT_GPIOBASE 0x588 +#define DEFAULT_GPE0BASE 0x5C0 +#define DEFAULT_SMMCNTRLBASE 0x3F703F76 + +#define DEFAULT_RCBABASE ((u8 *)0xfed1c000) + +#define DEFAULT_PCIEXBAR CONFIG_MMCONF_BASE_ADDRESS /* 4 KB per PCIe device */ + +/* IGD */ +#define GGC 0x52 + +/* Root Complex Register Block */ +#define RCBA8(x) *((volatile u8 *)(DEFAULT_RCBABASE + x)) +#define RCBA16(x) *((volatile u16 *)(DEFAULT_RCBABASE + x)) +#define RCBA32(x) *((volatile u32 *)(DEFAULT_RCBABASE + x)) + +/* FIXME: should probably be in southbridge, but is setup in romstage, too */ +#define CMC_SHADOW 0x3faf0000 + +#define DEFAULT_PMBASE 0x500 + +/* SMBus I/O bits. */ +#define SMBHSTSTAT 0x0 +#define SMBHSTCTL 0x2 +#define SMBHSTCMD 0x3 +#define SMBXMITADD 0x4 +#define SMBHSTDAT0 0x5 +#define SMBHSTDAT1 0x6 +#define SMBBLKDAT 0x7 +#define SMBTRNSADD 0x9 +#define SMBSLVDATA 0xa +#define SMLINK_PIN_CTL 0xe +#define SMBUS_PIN_CTL 0xf + +#define SMBUS_TIMEOUT (10 * 1000 * 100) + +#endif /* __SCH_POULSBO_H__ */ diff --git a/src/soc/intel/sch/smbus.c b/src/soc/intel/sch/smbus.c new file mode 100644 index 0000000000..54baa68228 --- /dev/null +++ b/src/soc/intel/sch/smbus.c @@ -0,0 +1,75 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008-2009 coresystems GmbH + * + * 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 <device/device.h> +#include <device/path.h> +#include <device/smbus.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include <arch/io.h> +#include "sch.h" +#include "smbus.h" + +static int lsmbus_read_byte(device_t dev, u8 address) +{ + u16 device; + struct resource *res; + struct bus *pbus; + + device = dev->path.i2c.device; + pbus = get_pbus_smbus(dev); + res = find_resource(pbus->dev, 0x20); + + return do_smbus_read_byte(res->base, device, address); +} + +static struct smbus_bus_operations lops_smbus_bus = { + .read_byte = lsmbus_read_byte, +}; + +static void smbus_set_subsystem(device_t dev, unsigned vendor, unsigned device) +{ + if (!vendor || !device) { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + pci_read_config32(dev, PCI_VENDOR_ID)); + } else { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + ((device & 0xffff) << 16) | (vendor & 0xffff)); + } +} + +static struct pci_operations smbus_pci_ops = { + .set_subsystem = smbus_set_subsystem, +}; + +static struct device_operations smbus_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = 0, + .scan_bus = scan_smbus, + .ops_smbus_bus = &lops_smbus_bus, + .ops_pci = &smbus_pci_ops, +}; + +// FIXME +/* 82801GB/GR/GDH/GBM/GHM/GU (ICH7/ICH7R/ICH7DH/ICH7-M/ICH7-M DH/ICH7-U) */ +static const struct pci_driver i82801gx_smbus __pci_driver = { + .ops = &smbus_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x27da, +}; diff --git a/src/soc/intel/sch/smbus.h b/src/soc/intel/sch/smbus.h new file mode 100644 index 0000000000..e34ca52cb0 --- /dev/null +++ b/src/soc/intel/sch/smbus.h @@ -0,0 +1,94 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com> + * Copyright (C) 2009 coresystems GmbH + * + * 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/smbus_def.h> + +static void smbus_delay(void) +{ + inb(0x80); +} + +static int smbus_wait_until_ready(u16 smbus_base) +{ + unsigned loops = SMBUS_TIMEOUT; + unsigned char byte; + do { + smbus_delay(); + if (--loops == 0) + break; + byte = inb(smbus_base + SMBHSTSTAT); + } while (byte & 1); + return loops ? 0 : -1; +} + +static int smbus_wait_until_done(u16 smbus_base) +{ + unsigned loops = SMBUS_TIMEOUT; + unsigned char byte; + do { + smbus_delay(); + if (--loops == 0) + break; + byte = inb(smbus_base + SMBHSTSTAT); + } while ((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0); + return loops ? 0 : -1; +} + +static int do_smbus_read_byte(unsigned smbus_base, unsigned device, + unsigned address) +{ + unsigned char global_status_register; + unsigned char byte; + + if (smbus_wait_until_ready(smbus_base) < 0) { + return SMBUS_WAIT_UNTIL_READY_TIMEOUT; + } + /* Setup transaction */ + /* Disable interrupts */ + outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL); + /* Set the device I'm talking too */ + outb(((device & 0x7f) << 1) | 1, smbus_base + SMBXMITADD); + /* Set the command/address... */ + outb(address & 0xff, smbus_base + SMBHSTCMD); + /* Set up for a byte data read */ + outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x2 << 2), + (smbus_base + SMBHSTCTL)); + /* Clear any lingering errors, so the transaction will run */ + outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT); + + /* Clear the data byte... */ + outb(0, smbus_base + SMBHSTDAT0); + + /* Start the command */ + outb((inb(smbus_base + SMBHSTCTL) | 0x40), smbus_base + SMBHSTCTL); + + /* Poll for transaction completion */ + if (smbus_wait_until_done(smbus_base) < 0) { + return SMBUS_WAIT_UNTIL_DONE_TIMEOUT; + } + + global_status_register = inb(smbus_base + SMBHSTSTAT); + + /* Ignore the "In Use" status... */ + global_status_register &= ~(3 << 5); + + /* Read results of transaction */ + byte = inb(smbus_base + SMBHSTDAT0); + if (global_status_register != (1 << 1)) { + return SMBUS_ERROR; + } + return byte; +} diff --git a/src/soc/intel/sch/smi.c b/src/soc/intel/sch/smi.c new file mode 100644 index 0000000000..24628e52e6 --- /dev/null +++ b/src/soc/intel/sch/smi.c @@ -0,0 +1,337 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008-2009 coresystems GmbH + * + * 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 <console/console.h> +#include <arch/io.h> +#include <cpu/x86/cache.h> +#include <cpu/x86/smm.h> +#include <cpu/cpu.h> +#include <string.h> +#include "chip.h" +#include "sch.h" + +extern unsigned char _binary_smm_start; +extern unsigned char _binary_smm_size; + +/* I945 */ +#define SMRAM 0x9d +#define D_OPEN (1 << 6) +#define D_CLS (1 << 5) +#define D_LCK (1 << 4) +#define G_SMRAME (1 << 3) +#define C_BASE_SEG ((0 << 2) | (1 << 1) | (0 << 0)) + +/* ICH7 */ +#define PM1_STS 0x00 +#define PM1_EN 0x02 +#define PM1_CNT 0x04 +#define PM1_TMR 0x08 +#define PROC_CNT 0x10 +#define LV2 0x14 +#define LV3 0x15 +#define LV4 0x16 +#define PM2_CNT 0x20 // mobile only +#define GPE0_STS 0x28 +#define GPE0_EN 0x2c +#define SMI_EN 0x30 +#define EL_SMI_EN (1 << 25) // Intel Quick Resume Technology +#define INTEL_USB2_EN (1 << 18) // Intel-Specific USB2 SMI logic +#define LEGACY_USB2_EN (1 << 17) // Legacy USB2 SMI logic +#define PERIODIC_EN (1 << 14) // SMI on PERIODIC_STS in SMI_STS +#define TCO_EN (1 << 13) // Enable TCO Logic (BIOSWE et al) +#define MCSMI_EN (1 << 11) // Trap microcontroller range access +#define BIOS_RLS (1 << 7) // asserts SCI on bit set +#define SWSMI_TMR_EN (1 << 6) // start software smi timer on bit set +#define APMC_EN (1 << 5) // Writes to APM_CNT cause SMI# +#define SLP_SMI_EN (1 << 4) // Write to SLP_EN in PM1_CNT asserts SMI# +#define LEGACY_USB_EN (1 << 3) // Legacy USB circuit SMI logic +#define BIOS_EN (1 << 2) // Assert SMI# on setting GBL_RLS bit +#define EOS (1 << 1) // End of SMI (deassert SMI#) +#define GBL_SMI_EN (1 << 0) // SMI# generation at all? +#define SMI_STS 0x34 +#define ALT_GP_SMI_EN 0x38 +#define ALT_GP_SMI_STS 0x3a +#define GPE_CNTL 0x42 +#define DEVACT_STS 0x44 +#define SS_CNT 0x50 +#define C3_RES 0x54 + +/* While we read PMBASE dynamically in case it changed, let's + * initialize it with a sane value + */ + +static u16 pmbase = DEFAULT_PMBASE; +/** + * @brief read and clear PM1_STS + * @return PM1_STS register + */ +static u16 reset_pm1_status(void) +{ + u16 reg16; + + reg16 = inw(pmbase + PM1_STS); + /* set status bits are cleared by writing 1 to them */ + outw(reg16, pmbase + PM1_STS); + + return reg16; +} + +static void dump_pm1_status(u16 pm1_sts) +{ + printk(BIOS_DEBUG, "PM1_STS: "); + if (pm1_sts & (1 << 15)) printk(BIOS_DEBUG, "WAK "); + if (pm1_sts & (1 << 14)) printk(BIOS_DEBUG, "PCIEXPWAK "); + if (pm1_sts & (1 << 11)) printk(BIOS_DEBUG, "PRBTNOR "); + if (pm1_sts & (1 << 10)) printk(BIOS_DEBUG, "RTC "); + if (pm1_sts & (1 << 8)) printk(BIOS_DEBUG, "PWRBTN "); + if (pm1_sts & (1 << 5)) printk(BIOS_DEBUG, "GBL "); + if (pm1_sts & (1 << 4)) printk(BIOS_DEBUG, "BM "); + if (pm1_sts & (1 << 0)) printk(BIOS_DEBUG, "TMROF "); + printk(BIOS_DEBUG, "\n"); +} + +/** + * @brief read and clear SMI_STS + * @return SMI_STS register + */ +static u32 reset_smi_status(void) +{ + u32 reg32; + + reg32 = inl(pmbase + SMI_STS); + /* set status bits are cleared by writing 1 to them */ + outl(reg32, pmbase + SMI_STS); + + return reg32; +} + +static void dump_smi_status(u32 smi_sts) +{ + printk(BIOS_DEBUG, "SMI_STS: "); + if (smi_sts & (1 << 26)) printk(BIOS_DEBUG, "SPI "); + if (smi_sts & (1 << 25)) printk(BIOS_DEBUG, "EL_SMI "); + if (smi_sts & (1 << 21)) printk(BIOS_DEBUG, "MONITOR "); + if (smi_sts & (1 << 20)) printk(BIOS_DEBUG, "PCI_EXP_SMI "); + if (smi_sts & (1 << 18)) printk(BIOS_DEBUG, "INTEL_USB2 "); + if (smi_sts & (1 << 17)) printk(BIOS_DEBUG, "LEGACY_USB2 "); + if (smi_sts & (1 << 16)) printk(BIOS_DEBUG, "SMBUS_SMI "); + if (smi_sts & (1 << 15)) printk(BIOS_DEBUG, "SERIRQ_SMI "); + if (smi_sts & (1 << 14)) printk(BIOS_DEBUG, "PERIODIC "); + if (smi_sts & (1 << 13)) printk(BIOS_DEBUG, "TCO "); + if (smi_sts & (1 << 12)) printk(BIOS_DEBUG, "DEVMON "); + if (smi_sts & (1 << 11)) printk(BIOS_DEBUG, "MCSMI "); + if (smi_sts & (1 << 10)) printk(BIOS_DEBUG, "GPI "); + if (smi_sts & (1 << 9)) printk(BIOS_DEBUG, "GPE0 "); + if (smi_sts & (1 << 8)) printk(BIOS_DEBUG, "PM1 "); + if (smi_sts & (1 << 6)) printk(BIOS_DEBUG, "SWSMI_TMR "); + if (smi_sts & (1 << 5)) printk(BIOS_DEBUG, "APM "); + if (smi_sts & (1 << 4)) printk(BIOS_DEBUG, "SLP_SMI "); + if (smi_sts & (1 << 3)) printk(BIOS_DEBUG, "LEGACY_USB "); + if (smi_sts & (1 << 2)) printk(BIOS_DEBUG, "BIOS "); + printk(BIOS_DEBUG, "\n"); +} + +/** + * @brief read and clear GPE0_STS + * @return GPE0_STS register + */ +static u32 reset_gpe0_status(void) +{ + u32 reg32; + + reg32 = inl(pmbase + GPE0_STS); + /* set status bits are cleared by writing 1 to them */ + outl(reg32, pmbase + GPE0_STS); + + return reg32; +} + +static void dump_gpe0_status(u32 gpe0_sts) +{ + int i; + printk(BIOS_DEBUG, "GPE0_STS: "); + for (i=31; i>= 16; i--) { + if (gpe0_sts & (1 << i)) printk(BIOS_DEBUG, "GPIO%d ", (i-16)); + } + if (gpe0_sts & (1 << 14)) printk(BIOS_DEBUG, "USB4 "); + if (gpe0_sts & (1 << 13)) printk(BIOS_DEBUG, "PME_B0 "); + if (gpe0_sts & (1 << 12)) printk(BIOS_DEBUG, "USB3 "); + if (gpe0_sts & (1 << 11)) printk(BIOS_DEBUG, "PME "); + if (gpe0_sts & (1 << 10)) printk(BIOS_DEBUG, "EL_SCI/BATLOW "); + if (gpe0_sts & (1 << 9)) printk(BIOS_DEBUG, "PCI_EXP "); + if (gpe0_sts & (1 << 8)) printk(BIOS_DEBUG, "RI "); + if (gpe0_sts & (1 << 7)) printk(BIOS_DEBUG, "SMB_WAK "); + if (gpe0_sts & (1 << 6)) printk(BIOS_DEBUG, "TCO_SCI "); + if (gpe0_sts & (1 << 5)) printk(BIOS_DEBUG, "AC97 "); + if (gpe0_sts & (1 << 4)) printk(BIOS_DEBUG, "USB2 "); + if (gpe0_sts & (1 << 3)) printk(BIOS_DEBUG, "USB1 "); + if (gpe0_sts & (1 << 2)) printk(BIOS_DEBUG, "HOT_PLUG "); + if (gpe0_sts & (1 << 0)) printk(BIOS_DEBUG, "THRM "); + printk(BIOS_DEBUG, "\n"); +} + +/** + * @brief read and clear TCOx_STS + * @return TCOx_STS registers + */ +static u32 reset_tco_status(void) +{ + u32 tcobase = pmbase + 0x60; + u32 reg32; + + reg32 = inl(tcobase + 0x04); + /* set status bits are cleared by writing 1 to them */ + outl(reg32 & ~(1<<18), tcobase + 0x04); // Don't clear BOOT_STS before SECOND_TO_STS + if (reg32 & (1 << 18)) + outl(reg32 & (1<<18), tcobase + 0x04); // clear BOOT_STS + + return reg32; +} + +static void dump_tco_status(u32 tco_sts) +{ + printk(BIOS_DEBUG, "TCO_STS: "); + if (tco_sts & (1 << 20)) printk(BIOS_DEBUG, "SMLINK_SLV "); + if (tco_sts & (1 << 18)) printk(BIOS_DEBUG, "BOOT "); + if (tco_sts & (1 << 17)) printk(BIOS_DEBUG, "SECOND_TO "); + if (tco_sts & (1 << 16)) printk(BIOS_DEBUG, "INTRD_DET "); + if (tco_sts & (1 << 12)) printk(BIOS_DEBUG, "DMISERR "); + if (tco_sts & (1 << 10)) printk(BIOS_DEBUG, "DMISMI "); + if (tco_sts & (1 << 9)) printk(BIOS_DEBUG, "DMISCI "); + if (tco_sts & (1 << 8)) printk(BIOS_DEBUG, "BIOSWR "); + if (tco_sts & (1 << 7)) printk(BIOS_DEBUG, "NEWCENTURY "); + if (tco_sts & (1 << 3)) printk(BIOS_DEBUG, "TIMEOUT "); + if (tco_sts & (1 << 2)) printk(BIOS_DEBUG, "TCO_INT "); + if (tco_sts & (1 << 1)) printk(BIOS_DEBUG, "SW_TCO "); + if (tco_sts & (1 << 0)) printk(BIOS_DEBUG, "NMI2SMI "); + printk(BIOS_DEBUG, "\n"); +} + +/** + * @brief Set the EOS bit + */ +static void smi_set_eos(void) +{ +// FIXME: disabled until SMM actually works +#if 0 + u8 reg8; + + reg8 = inb(pmbase + SMI_EN); + reg8 |= EOS; + outb(reg8, pmbase + SMI_EN); +#endif +} + +extern uint8_t smm_relocation_start, smm_relocation_end; + +static void smm_relocate(void) +{ + u32 smi_en; + + printk(BIOS_DEBUG, "Initializing SMM handler..."); + + pmbase = pci_read_config16(dev_find_slot(0, PCI_DEVFN(0x1f, 0)), 0x40) & 0xfffc; + printk(BIOS_SPEW, " ... pmbase = 0x%04x\n", pmbase); + + smi_en = inl(pmbase + SMI_EN); + if (smi_en & APMC_EN) { + printk(BIOS_INFO, "SMI# handler already enabled?\n"); + return; + } + + /* copy the SMM relocation code */ + memcpy((void *)0x38000, &smm_relocation_start, + &smm_relocation_end - &smm_relocation_start); + + printk(BIOS_DEBUG, "\n"); + dump_smi_status(reset_smi_status()); + dump_pm1_status(reset_pm1_status()); + dump_gpe0_status(reset_gpe0_status()); + dump_tco_status(reset_tco_status()); + + /* Enable SMI generation: + * - on TCO events + * - on APMC writes (io 0xb2) + * - on writes to SLP_EN (sleep states) + * - on writes to GBL_RLS (bios commands) + * No SMIs: + * - on microcontroller writes (io 0x62/0x66) + */ + outl(smi_en | (TCO_EN | APMC_EN | SLP_SMI_EN | BIOS_EN | + EOS | GBL_SMI_EN), pmbase + SMI_EN); + + /** + * There are several methods of raising a controlled SMI# via + * software, among them: + * - Writes to io 0xb2 (APMC) + * - Writes to the Local Apic ICR with Delivery mode SMI. + * + * Using the local apic is a bit more tricky. According to + * AMD Family 11 Processor BKDG no destination shorthand must be + * used. + * The whole SMM initialization is quite a bit hardware specific, so + * I'm not too worried about the better of the methods at the moment + */ + + /* raise an SMI interrupt */ + printk(BIOS_SPEW, " ... raise SMI#\n"); + outb(0x00, 0xb2); +} + +static void smm_install(void) +{ + /* enable the SMM memory window */ + pci_write_config8(dev_find_slot(0, PCI_DEVFN(0, 0)), SMRAM, + D_OPEN | G_SMRAME | C_BASE_SEG); + + /* copy the real SMM handler */ + memcpy((void *)0xa0000, &_binary_smm_start, (size_t)&_binary_smm_size); + wbinvd(); + + /* close the SMM memory window and enable normal SMM */ + pci_write_config8(dev_find_slot(0, PCI_DEVFN(0, 0)), SMRAM, + G_SMRAME | C_BASE_SEG); +} + +void smm_init(void) +{ + smm_relocate(); + smm_install(); + smi_set_eos(); +} + +void smm_lock(void) +{ + /* LOCK the SMM memory window and enable normal SMM. + * After running this function, only a full reset can + * make the SMM registers writable again. + */ + printk(BIOS_DEBUG, "Locking SMM.\n"); + pci_write_config8(dev_find_slot(0, PCI_DEVFN(0, 0)), SMRAM, + D_LCK | G_SMRAME | C_BASE_SEG); +} + +void smm_setup_structures(void *gnvs, void *tcg, void *smi1) +{ + /* The GDT or coreboot table is going to live here. But a long time + * after we relocated the GNVS, so this is not troublesome. + */ + *(u32 *)0x500 = (u32)gnvs; + *(u32 *)0x504 = (u32)tcg; + *(u32 *)0x508 = (u32)smi1; + outb(0xea, 0xb2); +} diff --git a/src/soc/intel/sch/smihandler.c b/src/soc/intel/sch/smihandler.c new file mode 100644 index 0000000000..57eb35c23b --- /dev/null +++ b/src/soc/intel/sch/smihandler.c @@ -0,0 +1,399 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008-2009 coresystems GmbH + * + * 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 <cpu/x86/cache.h> +#include <cpu/x86/smm.h> +#include "sch.h" + +#define DEBUG_SMI + +/* I945 */ +#define SMRAM 0x9d +#define D_OPEN (1 << 6) +#define D_CLS (1 << 5) +#define D_LCK (1 << 4) +#define G_SMRANE (1 << 3) +#define C_BASE_SEG ((0 << 2) | (1 << 1) | (0 << 0)) + +/* ICH7 */ +#define PM1_STS 0x00 +#define PM1_EN 0x02 +#define PM1_CNT 0x04 +#define PM1_TMR 0x08 +#define PROC_CNT 0x10 +#define LV2 0x14 +#define LV3 0x15 +#define LV4 0x16 +#define PM2_CNT 0x20 // mobile only +#define GPE0_STS 0x28 +#define GPE0_EN 0x2c +#define SMI_EN 0x30 +#define EL_SMI_EN (1 << 25) // Intel Quick Resume Technology +#define INTEL_USB2_EN (1 << 18) // Intel-Specific USB2 SMI logic +#define LEGACY_USB2_EN (1 << 17) // Legacy USB2 SMI logic +#define PERIODIC_EN (1 << 14) // SMI on PERIODIC_STS in SMI_STS +#define TCO_EN (1 << 13) // Enable TCO Logic (BIOSWE et al) +#define MCSMI_EN (1 << 11) // Trap microcontroller range access +#define BIOS_RLS (1 << 7) // asserts SCI on bit set +#define SWSMI_TMR_EN (1 << 6) // start software smi timer on bit set +#define APMC_EN (1 << 5) // Writes to APM_CNT cause SMI# +#define SLP_SMI_EN (1 << 4) // Write to SLP_EN in PM1_CNT asserts SMI# +#define LEGACY_USB_EN (1 << 3) // Legacy USB circuit SMI logic +#define BIOS_EN (1 << 2) // Assert SMI# on setting GBL_RLS bit +#define EOS (1 << 1) // End of SMI (deassert SMI#) +#define GBL_SMI_EN (1 << 0) // SMI# generation at all? +#define SMI_STS 0x34 +#define ALT_GP_SMI_EN 0x38 +#define ALT_GP_SMI_STS 0x3a +#define GPE_CNTL 0x42 +#define DEVACT_STS 0x44 +#define SS_CNT 0x50 +#define C3_RES 0x54 + +//#include "i82801gx_nvs.h" + +/* While we read PMBASE dynamically in case it changed, let's + * initialize it with a sane value + */ +static u16 pmbase = DEFAULT_PMBASE; + +// disabled because SMM doesn't actually work yet +#if 0 +/** + * @brief read and clear PM1_STS + * @return PM1_STS register + */ +static u16 reset_pm1_status(void) +{ + u16 reg16; + + reg16 = inw(pmbase + PM1_STS); + /* set status bits are cleared by writing 1 to them */ + outw(reg16, pmbase + PM1_STS); + + return reg16; +} + +static void dump_pm1_status(u16 pm1_sts) +{ + printk(BIOS_DEBUG, "PM1_STS: "); + if (pm1_sts & (1 << 15)) printk(BIOS_DEBUG, "WAK "); + if (pm1_sts & (1 << 14)) printk(BIOS_DEBUG, "PCIEXPWAK "); + if (pm1_sts & (1 << 11)) printk(BIOS_DEBUG, "PRBTNOR "); + if (pm1_sts & (1 << 10)) printk(BIOS_DEBUG, "RTC "); + if (pm1_sts & (1 << 8)) printk(BIOS_DEBUG, "PWRBTN "); + if (pm1_sts & (1 << 5)) printk(BIOS_DEBUG, "GBL "); + if (pm1_sts & (1 << 4)) printk(BIOS_DEBUG, "BM "); + if (pm1_sts & (1 << 0)) printk(BIOS_DEBUG, "TMROF "); + printk(BIOS_DEBUG, "\n"); +} + +/** + * @brief read and clear SMI_STS + * @return SMI_STS register + */ +static u32 reset_smi_status(void) +{ + u32 reg32; + + reg32 = inl(pmbase + SMI_STS); + /* set status bits are cleared by writing 1 to them */ + outl(reg32, pmbase + SMI_STS); + + return reg32; +} + +static void dump_smi_status(u32 smi_sts) +{ + printk(BIOS_DEBUG, "SMI_STS: "); + if (smi_sts & (1 << 26)) printk(BIOS_DEBUG, "SPI "); + if (smi_sts & (1 << 25)) printk(BIOS_DEBUG, "EL_SMI "); + if (smi_sts & (1 << 21)) printk(BIOS_DEBUG, "MONITOR "); + if (smi_sts & (1 << 20)) printk(BIOS_DEBUG, "PCI_EXP_SMI "); + if (smi_sts & (1 << 18)) printk(BIOS_DEBUG, "INTEL_USB2 "); + if (smi_sts & (1 << 17)) printk(BIOS_DEBUG, "LEGACY_USB2 "); + if (smi_sts & (1 << 16)) printk(BIOS_DEBUG, "SMBUS_SMI "); + if (smi_sts & (1 << 15)) printk(BIOS_DEBUG, "SERIRQ_SMI "); + if (smi_sts & (1 << 14)) printk(BIOS_DEBUG, "PERIODIC "); + if (smi_sts & (1 << 13)) printk(BIOS_DEBUG, "TCO "); + if (smi_sts & (1 << 12)) printk(BIOS_DEBUG, "DEVMON "); + if (smi_sts & (1 << 11)) printk(BIOS_DEBUG, "MCSMI "); + if (smi_sts & (1 << 10)) printk(BIOS_DEBUG, "GPI "); + if (smi_sts & (1 << 9)) printk(BIOS_DEBUG, "GPE0 "); + if (smi_sts & (1 << 8)) printk(BIOS_DEBUG, "PM1 "); + if (smi_sts & (1 << 6)) printk(BIOS_DEBUG, "SWSMI_TMR "); + if (smi_sts & (1 << 5)) printk(BIOS_DEBUG, "APM "); + if (smi_sts & (1 << 4)) printk(BIOS_DEBUG, "SLP_SMI "); + if (smi_sts & (1 << 3)) printk(BIOS_DEBUG, "LEGACY_USB "); + if (smi_sts & (1 << 2)) printk(BIOS_DEBUG, "BIOS "); + printk(BIOS_DEBUG, "\n"); +} + + +/** + * @brief read and clear GPE0_STS + * @return GPE0_STS register + */ +static u32 reset_gpe0_status(void) +{ + u32 reg32; + + reg32 = inl(pmbase + GPE0_STS); + /* set status bits are cleared by writing 1 to them */ + outl(reg32, pmbase + GPE0_STS); + + return reg32; +} + +static void dump_gpe0_status(u32 gpe0_sts) +{ + int i; + printk(BIOS_DEBUG, "GPE0_STS: "); + for (i=31; i>= 16; i--) { + if (gpe0_sts & (1 << i)) printk(BIOS_DEBUG, "GPIO%d ", (i-16)); + } + if (gpe0_sts & (1 << 14)) printk(BIOS_DEBUG, "USB4 "); + if (gpe0_sts & (1 << 13)) printk(BIOS_DEBUG, "PME_B0 "); + if (gpe0_sts & (1 << 12)) printk(BIOS_DEBUG, "USB3 "); + if (gpe0_sts & (1 << 11)) printk(BIOS_DEBUG, "PME "); + if (gpe0_sts & (1 << 10)) printk(BIOS_DEBUG, "EL_SCI/BATLOW "); + if (gpe0_sts & (1 << 9)) printk(BIOS_DEBUG, "PCI_EXP "); + if (gpe0_sts & (1 << 8)) printk(BIOS_DEBUG, "RI "); + if (gpe0_sts & (1 << 7)) printk(BIOS_DEBUG, "SMB_WAK "); + if (gpe0_sts & (1 << 6)) printk(BIOS_DEBUG, "TCO_SCI "); + if (gpe0_sts & (1 << 5)) printk(BIOS_DEBUG, "AC97 "); + if (gpe0_sts & (1 << 4)) printk(BIOS_DEBUG, "USB2 "); + if (gpe0_sts & (1 << 3)) printk(BIOS_DEBUG, "USB1 "); + if (gpe0_sts & (1 << 2)) printk(BIOS_DEBUG, "HOT_PLUG "); + if (gpe0_sts & (1 << 0)) printk(BIOS_DEBUG, "THRM "); + printk(BIOS_DEBUG, "\n"); +} + + +/** + * @brief read and clear TCOx_STS + * @return TCOx_STS registers + */ +static u32 reset_tco_status(void) +{ + u32 tcobase = pmbase + 0x60; + u32 reg32; + + reg32 = inl(tcobase + 0x04); + /* set status bits are cleared by writing 1 to them */ + outl(reg32 & ~(1<<18), tcobase + 0x04); // Don't clear BOOT_STS before SECOND_TO_STS + if (reg32 & (1 << 18)) + outl(reg32 & (1<<18), tcobase + 0x04); // clear BOOT_STS + + return reg32; +} + + +static void dump_tco_status(u32 tco_sts) +{ + printk(BIOS_DEBUG, "TCO_STS: "); + if (tco_sts & (1 << 20)) printk(BIOS_DEBUG, "SMLINK_SLV "); + if (tco_sts & (1 << 18)) printk(BIOS_DEBUG, "BOOT "); + if (tco_sts & (1 << 17)) printk(BIOS_DEBUG, "SECOND_TO "); + if (tco_sts & (1 << 16)) printk(BIOS_DEBUG, "INTRD_DET "); + if (tco_sts & (1 << 12)) printk(BIOS_DEBUG, "DMISERR "); + if (tco_sts & (1 << 10)) printk(BIOS_DEBUG, "DMISMI "); + if (tco_sts & (1 << 9)) printk(BIOS_DEBUG, "DMISCI "); + if (tco_sts & (1 << 8)) printk(BIOS_DEBUG, "BIOSWR "); + if (tco_sts & (1 << 7)) printk(BIOS_DEBUG, "NEWCENTURY "); + if (tco_sts & (1 << 3)) printk(BIOS_DEBUG, "TIMEOUT "); + if (tco_sts & (1 << 2)) printk(BIOS_DEBUG, "TCO_INT "); + if (tco_sts & (1 << 1)) printk(BIOS_DEBUG, "SW_TCO "); + if (tco_sts & (1 << 0)) printk(BIOS_DEBUG, "NMI2SMI "); + printk(BIOS_DEBUG, "\n"); +} +#endif + +int southbridge_io_trap_handler(int smif) +{ + //global_nvs_t *gnvs = (global_nvs_t *)0xc00; + + switch (smif) { + case 0x32: + printk(BIOS_DEBUG, "OS Init\n"); + //gnvs->smif = 0; + break; + default: + /* Not handled */ + return 0; + } + + /* On success, the IO Trap Handler returns 0 + * On failure, the IO Trap Handler returns a value != 0 + * + * For now, we force the return value to 0 and log all traps to + * see what's going on. + */ + //gnvs->smif = 0; + return 1; /* IO trap handled */ +} + +/** + * @brief Set the EOS bit + */ +void southbridge_smi_set_eos(void) +{ + u8 reg8; + + reg8 = inb(pmbase + SMI_EN); + reg8 |= EOS; + outb(reg8, pmbase + SMI_EN); +} + +/** + * @brief Interrupt handler for SMI# + * @param node + * @param state_save + */ +void southbridge_smi_handler(unsigned int node, smm_state_save_area_t *state_save) +{ +// FIXME: the necessary magic isn't available yet. the code +// below is a partially adapted ICH7 version of the handler +#if 0 + u8 reg8; + u16 pmctrl; + u16 pm1_sts; + u32 smi_sts, gpe0_sts, tco_sts; + + pmbase = pcie_read_config16(PCI_DEV(0, 0x1f, 0), 0x48) & 0xfffc; + printk(BIOS_SPEW, "SMI#: pmbase = 0x%04x\n", pmbase); + + /* We need to clear the SMI status registers, or we won't see what's + * happening in the following calls. + */ + smi_sts = reset_smi_status(); + dump_smi_status(smi_sts); + + if (smi_sts & (1 << 21)) { // MONITOR + global_nvs_t *gnvs = (global_nvs_t *)0xc00; + u32 reg32; + + reg32 = RCBA32(0x1e00); TRSR - Trap Status Register +//#if 0 + /* Comment in for some useful debug */ + for (i=0; i<4; i++) { + if (reg32 & (1 << i)) { + printk(BIOS_DEBUG, " io trap #%d\n", i); + } + } +//#endif + RCBA32(0x1e00) = reg32; TRSR + + reg32 = RCBA32(0x1e10); + + if ((reg32 & 0xfffc) != 0x808) { + printk(BIOS_DEBUG, " trapped io address = 0x%x\n", reg32 & 0xfffc); + printk(BIOS_DEBUG, " AHBE = %x\n", (reg32 >> 16) & 0xf); + printk(BIOS_DEBUG, " read/write: %s\n", (reg32 & (1 << 24)) ? "read" : + "write"); + } + + if (!(reg32 & (1 << 24))) { + /* Write Cycle */ + reg32 = RCBA32(0x1e18); + printk(BIOS_DEBUG, " iotrap written data = 0x%08x\n", reg32); + + } + + if (gnvs->smif) + io_trap_handler(gnvs->smif); // call function smif + } + + if (smi_sts & (1 << 13)) { // TCO + tco_sts = reset_tco_status(); + dump_tco_status(tco_sts); + + if (tco_sts & (1 << 8)) { // BIOSWR + u8 bios_cntl; + bios_cntl = pcie_read_config16(PCI_DEV(0, 0x1f, 0), 0xdc); + if (bios_cntl & 1) { + /* BWE is RW, so the SMI was caused by a + * write to BWE, not by a write to the BIOS + */ + + /* This is the place where we notice someone + * is trying to tinker with the BIOS. We are + * trying to be nice and just ignore it. A more + * resolute answer would be to power down the + * box. + */ + printk(BIOS_DEBUG, "Switching back to RO\n"); + pcie_write_config32(PCI_DEV(0, 0x1f, 0), 0xdc, (bios_cntl & ~1)); + } /* No else for now? */ + } + } + + if (smi_sts & (1 << 8)) { // PM1 + pm1_sts = reset_pm1_status(); + dump_pm1_status(pm1_sts); + } + + if (smi_sts & (1 << 9)) { // GPE0 + gpe0_sts = reset_gpe0_status(); + dump_gpe0_status(gpe0_sts); + } + + if (smi_sts & (1 << 5)) { // APM + /* Emulate B2 register as the FADT / Linux expects it */ + + reg8 = inb(0xb2); + switch (reg8) { + case ACPI_DISABLE: + pmctrl = inw(pmbase + 0x04); + pmctrl |= (1 << 0); + outw(pmctrl, pmbase + 0x04); + printk(BIOS_DEBUG, "SMI#: ACPI disabled.\n"); + break; + case ACPI_ENABLE: + pmctrl = inw(pmbase + 0x04); + pmctrl &= ~(1 << 0); + outw(pmctrl, pmbase + 0x04); + printk(BIOS_DEBUG, "SMI#: ACPI enabled.\n"); + break; + } + } + + if (smi_sts & (1 << 4)) { // SLP_SMI + u32 reg32; + + /* First, disable further SMIs */ + reg8 = inb(pmbase + SMI_EN); + reg8 &= ~SLP_SMI_EN; + outb(reg8, pmbase + SMI_EN); + + /* Next, do the deed, we should change + * power on after power loss bits here + * if we're going to S5 + */ + + /* Write back to the SLP register to cause the + * originally intended event again. We need to set BIT13 + * (SLP_EN) though to make the sleep happen. + */ + reg32 = inl(pmbase + 0x04); + printk(BIOS_DEBUG, "SMI#: SLP = 0x%08x\n", reg32); + printk(BIOS_DEBUG, "SMI#: Powering off.\n"); + outl(reg32 | (1 << 13), pmbase + 0x04); + } +#endif +} diff --git a/src/soc/intel/sch/south.c b/src/soc/intel/sch/south.c new file mode 100644 index 0000000000..b096ab69f7 --- /dev/null +++ b/src/soc/intel/sch/south.c @@ -0,0 +1,22 @@ +/* + * 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; 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 <device/device.h> +#include <device/pci.h> + +struct chip_operations southbridge_intel_sch_ops = { + CHIP_NAME("Intel SCH Southbridge") +}; diff --git a/src/soc/intel/sch/usb.c b/src/soc/intel/sch/usb.c new file mode 100644 index 0000000000..a7ada4b8f1 --- /dev/null +++ b/src/soc/intel/sch/usb.c @@ -0,0 +1,87 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008-2010 coresystems GmbH + * Copyright (C) 2009-2010 iWave Systems + * + * 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 <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> + +static void usb_init(struct device *dev) +{ + u32 reg32; + + /* USB Specification says the device must be Bus Master. */ + printk(BIOS_DEBUG, "UHCI: Setting up controller.. "); + + reg32 = pci_read_config32(dev, PCI_COMMAND); + pci_write_config32(dev, PCI_COMMAND, reg32 | PCI_COMMAND_MASTER); + /* Disable clock gating. */ + reg32 = pci_read_config32(dev, 0xFC); + reg32 |= (1 << 2); + pci_write_config32(dev, 0xFC, reg32); + pci_write_config8(dev, 0xF8, 0x86); + pci_write_config8(dev, 0xF9, 0x0F); + pci_write_config8(dev, 0xFA, 0x06); + reg32 = pci_read_config32(dev, 0x4); + printk(BIOS_DEBUG, "PCI_COMMAND %x.\n", reg32); + reg32 = pci_read_config32(dev, 0x20); + printk(BIOS_DEBUG, "PCI_BASE %x.\n", reg32); + reg32 = pci_read_config32(dev, 0xFC); + printk(BIOS_DEBUG, "PCI_FD %x.\n", reg32); + printk(BIOS_DEBUG, "done.\n"); +} + +static void usb_set_subsystem(device_t dev, unsigned vendor, unsigned device) +{ + if (!vendor || !device) { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + pci_read_config32(dev, PCI_VENDOR_ID)); + } else { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + ((device & 0xffff) << 16) | (vendor & 0xffff)); + } +} + +static struct pci_operations usb_pci_ops = { + .set_subsystem = usb_set_subsystem, +}; + +static struct device_operations usb_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = usb_init, + .scan_bus = 0, + .ops_pci = &usb_pci_ops, +}; + +static const struct pci_driver sch_usb0 __pci_driver = { + .ops = &usb_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x8114, +}; + +static const struct pci_driver sch_usb1 __pci_driver = { + .ops = &usb_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x8115, +}; + +static const struct pci_driver sch_usb2 __pci_driver = { + .ops = &usb_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x8116, +}; diff --git a/src/soc/intel/sch/usb_client.c b/src/soc/intel/sch/usb_client.c new file mode 100644 index 0000000000..02f5b8253c --- /dev/null +++ b/src/soc/intel/sch/usb_client.c @@ -0,0 +1,62 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2009-2010 iWave Systems + * + * 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 <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <arch/io.h> + +static void usb_client_init(struct device *dev) +{ + u32 reg32; + + printk(BIOS_DEBUG, "USB Client: Setting up controller.. "); + reg32 = pci_read_config32(dev, PCI_COMMAND); + reg32 |= PCI_COMMAND_MASTER; + reg32 |= PCI_COMMAND_MEMORY; + pci_write_config32(dev, PCI_COMMAND, reg32); + printk(BIOS_DEBUG, "done.\n"); +} + +static void usb_client_set_subsystem(device_t dev, unsigned vendor, unsigned device) +{ + if (!vendor || !device) { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + pci_read_config32(dev, PCI_VENDOR_ID)); + } else { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + ((device & 0xffff) << 16) | (vendor & 0xffff)); + } +} + +static struct pci_operations lops_pci = { + .set_subsystem = &usb_client_set_subsystem, +}; + +static struct device_operations usb_client_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = usb_client_init, + .scan_bus = 0, + .ops_pci = &lops_pci, +}; + +static const struct pci_driver sch_usb_client __pci_driver = { + .ops = &usb_client_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x8118, +}; diff --git a/src/soc/intel/sch/usb_ehci.c b/src/soc/intel/sch/usb_ehci.c new file mode 100644 index 0000000000..8191d0aba7 --- /dev/null +++ b/src/soc/intel/sch/usb_ehci.c @@ -0,0 +1,91 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008-2010 coresystems GmbH + * Copyright (C) 2009-2010 iWave Systems + * + * 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 <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <arch/io.h> + +static void usb_ehci_init(struct device *dev) +{ + u32 reg32; + + printk(BIOS_DEBUG, "EHCI: Setting up controller.. "); + reg32 = pci_read_config32(dev, PCI_COMMAND); + reg32 |= PCI_COMMAND_MASTER; + pci_write_config32(dev, PCI_COMMAND, reg32); + /* Disable clock gating */ +#if 0 + reg32 = pci_read_config32(dev, 0xc0); + reg32 |= (1 << 2); + pci_write_config32(dev, 0xc0, reg32); +#endif + // pci_write_config32(dev, 0x3c, 0x17); + reg32 = pci_read_config32(dev, 0xFC); + reg32 |= (1 << 28); + pci_write_config32(dev, 0xFC, reg32); + + reg32 = pci_read_config32(dev, 0x4); + printk(BIOS_DEBUG, "PCI_COMMAND %x.\n", reg32); + reg32 = pci_read_config32(dev, 0x20); + printk(BIOS_DEBUG, "PCI_BASE %x.\n", reg32); + reg32 = pci_read_config32(dev, 0xC0); + printk(BIOS_DEBUG, "PCI_FD %x.\n", reg32); + printk(BIOS_DEBUG, "done.\n"); +} + +static void usb_ehci_set_subsystem(device_t dev, unsigned vendor, + unsigned device) +{ + u8 access_cntl; + + access_cntl = pci_read_config8(dev, 0x80); + + /* Enable writes to protected registers. */ + pci_write_config8(dev, 0x80, access_cntl | 1); + + if (!vendor || !device) { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + pci_read_config32(dev, PCI_VENDOR_ID)); + } else { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + ((device & 0xffff) << 16) | (vendor & 0xffff)); + } + + /* Restore protection. */ + pci_write_config8(dev, 0x80, access_cntl); +} + +static struct pci_operations lops_pci = { + .set_subsystem = &usb_ehci_set_subsystem, +}; + +static struct device_operations usb_ehci_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = usb_ehci_init, + .scan_bus = 0, + .ops_pci = &lops_pci, +}; + +static const struct pci_driver sch_usb_ehci __pci_driver = { + .ops = &usb_ehci_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x8117, +}; |