mail.coreboot.org
Sign In Sign Up
Manage this list Sign In Sign Up

Keyboard Shortcuts

Thread View

  • j: Next unread message
  • k: Previous unread message
  • j a: Jump to all threads
  • j l: Jump to MailingList overview

coreboot-gerrit

Download
Threads by month
  • ----- 2026 -----
  • January
  • ----- 2025 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2024 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2023 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2022 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2021 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2020 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2019 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2018 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2017 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2016 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2015 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2014 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2013 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
coreboot-gerrit@coreboot.org

June 2013

  • 1 participants
  • 744 discussions
New patch to review for coreboot: b228080 haswell: allow for disabled hyperthreading
by Aaron Durbin June 3, 2013

June 3, 2013
Aaron Durbin (adurbin(a)google.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/3353 -gerrit commit b2280806bcbca6b6df011da8b387be02c5c9bc79 Author: Aaron Durbin <adurbin(a)chromium.org> Date: Tue May 28 14:26:29 2013 -0500 haswell: allow for disabled hyperthreading There were assumptions being made in the haswell MP and SMM code which assumed the APIC id space was 1:1 w.r.t. cpu number. When hyperthreading is disabled the APIC ids of the logical processors are all even. That means the APIC id space is sparse. Handle this situation. Change-Id: Ibe79ab156c0a171208a77db8a252aa5b73205d6c Signed-off-by: Aaron Durbin <adurbin(a)chromium.org> --- src/cpu/intel/haswell/haswell.h | 3 +++ src/cpu/intel/haswell/mp_init.c | 22 +++++++++++++++++++--- src/cpu/intel/haswell/smmrelocate.c | 32 +++++++++++++++++++++++++++++--- 3 files changed, 51 insertions(+), 6 deletions(-) diff --git a/src/cpu/intel/haswell/haswell.h b/src/cpu/intel/haswell/haswell.h index c550cfa..4a739a9 100644 --- a/src/cpu/intel/haswell/haswell.h +++ b/src/cpu/intel/haswell/haswell.h @@ -175,6 +175,9 @@ int setup_ap_init(struct bus *cpu_bus, int *max_cpus, /* Returns 0 on success, < 0 on failure. */ int start_aps(struct bus *cpu_bus, int max_cpus); void release_aps_for_smm_relocation(int do_parallel_relocation); +/* Determine if HyperThreading is disabled. The variable is not valid until + * setup_ap_init() has been called. */ +extern int ht_disabled; #endif /* This structure is saved along with the relocated ramstage program in SMM diff --git a/src/cpu/intel/haswell/mp_init.c b/src/cpu/intel/haswell/mp_init.c index 357fbb2..1358418 100644 --- a/src/cpu/intel/haswell/mp_init.c +++ b/src/cpu/intel/haswell/mp_init.c @@ -80,6 +80,8 @@ static atomic_t num_aps; static atomic_t num_aps_relocated_smm; /* Barrier to stop APs from performing SMM relcoation. */ static int smm_relocation_barrier_begin __attribute__ ((aligned (64))); +/* Determine if hyperthreading is disabled. */ +int ht_disabled; static inline void mfence(void) { @@ -197,6 +199,8 @@ static void asmlinkage ap_init(unsigned int cpu, void *microcode_ptr) static void setup_default_sipi_vector_params(struct sipi_params *sp) { int i; + u8 apic_id; + u8 apic_id_inc; sp->gdt = (u32)&gdt; sp->gdtlimit = (u32)&gdt_end - (u32)&gdt - 1; @@ -205,9 +209,15 @@ static void setup_default_sipi_vector_params(struct sipi_params *sp) sp->stack_top = (u32)&_estack; /* Adjust the stack top to take into account cpu_info. */ sp->stack_top -= sizeof(struct cpu_info); - /* Default to linear APIC id space. */ - for (i = 0; i < CONFIG_MAX_CPUS; i++) - sp->apic_to_cpu_num[i] = i; + + /* Default to linear APIC id space if HT is enabled. If it is + * disabled the APIC ids increase by 2 as the odd numbered APIC + * ids are not present.*/ + apic_id_inc = (ht_disabled) ? 2 : 1; + for (i = 0, apic_id = 0; i < CONFIG_MAX_CPUS; i++) { + sp->apic_to_cpu_num[i] = apic_id; + apic_id += apic_id_inc; + } } #define NUM_FIXED_MTRRS 11 @@ -374,6 +384,10 @@ static int allocate_cpu_devices(struct bus *cpu_bus, int *total_hw_threads) max_cpus = CONFIG_MAX_CPUS; } + /* Determine if hyperthreading is enabled. If not, the APIC id space + * is sparse with ids incrementing by 2 instead of 1. */ + ht_disabled = num_threads == num_cores; + for (i = 1; i < max_cpus; i++) { struct device_path cpu_path; device_t new; @@ -381,6 +395,8 @@ static int allocate_cpu_devices(struct bus *cpu_bus, int *total_hw_threads) /* Build the cpu device path */ cpu_path.type = DEVICE_PATH_APIC; cpu_path.apic.apic_id = info->cpu->path.apic.apic_id + i; + if (ht_disabled) + cpu_path.apic.apic_id = cpu_path.apic.apic_id * 2; /* Allocate the new cpu device structure */ new = alloc_find_dev(cpu_bus, &cpu_path); diff --git a/src/cpu/intel/haswell/smmrelocate.c b/src/cpu/intel/haswell/smmrelocate.c index 6caeafa..4fe6489 100644 --- a/src/cpu/intel/haswell/smmrelocate.c +++ b/src/cpu/intel/haswell/smmrelocate.c @@ -286,6 +286,22 @@ static void fill_in_relocation_params(device_t dev, params->uncore_emrr_mask.hi = (1 << (39 - 32)) - 1; } +static void adjust_apic_id_map(struct smm_loader_params *smm_params) +{ + struct smm_runtime *runtime; + int i; + + /* Adjust the APIC id map if HT is disabled. */ + if (!ht_disabled) + return; + + runtime = smm_params->runtime; + + /* The APIC ids increment by 2 when HT is disabled. */ + for (i = 0; i < CONFIG_MAX_CPUS; i++) + runtime->apic_id_to_cpu[i] = runtime->apic_id_to_cpu[i] * 2; +} + static int install_relocation_handler(int num_cpus, struct smm_relocation_params *relo_params) { @@ -305,7 +321,12 @@ static int install_relocation_handler(int num_cpus, .handler_arg = (void *)relo_params, }; - return smm_setup_relocation_handler(&smm_params); + if (smm_setup_relocation_handler(&smm_params)) + return -1; + + adjust_apic_id_map(&smm_params); + + return 0; } static void setup_ied_area(struct smm_relocation_params *params) @@ -347,8 +368,13 @@ static int install_permanent_handler(int num_cpus, printk(BIOS_DEBUG, "Installing SMM handler to 0x%08x\n", relo_params->smram_base); - return smm_load_module((void *)relo_params->smram_base, - relo_params->smram_size, &smm_params); + if (smm_load_module((void *)relo_params->smram_base, + relo_params->smram_size, &smm_params)) + return -1; + + adjust_apic_id_map(&smm_params); + + return 0; } static int cpu_smm_setup(void)
1 0
0 0
New patch to review for coreboot: b3e579a haswell: fix overflow handling TOUUD
by Aaron Durbin June 3, 2013

June 3, 2013
Aaron Durbin (adurbin(a)google.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/3352 -gerrit commit b3e579a7855edf4cbd4e75ad17ce8c08b64895ec Author: Aaron Durbin <adurbin(a)chromium.org> Date: Mon Jun 3 09:46:56 2013 -0500 haswell: fix overflow handling TOUUD It's possible that the TOUUD can be set to less than 4GiB. When that is the case the size_k variable is an extremely large value. Instead ensure TOUUD is greater than 4GiB before adding said resources. Change-Id: I456633d6210824e60665281538300fd15656b86d Signed-off-by: Aaron Durbin <adurbin(a)chromium.org> --- src/northbridge/intel/haswell/northbridge.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/northbridge/intel/haswell/northbridge.c b/src/northbridge/intel/haswell/northbridge.c index 5c1ab3e..45d967e 100644 --- a/src/northbridge/intel/haswell/northbridge.c +++ b/src/northbridge/intel/haswell/northbridge.c @@ -312,6 +312,7 @@ static void mc_report_map_entries(device_t dev, uint64_t *values) static void mc_add_dram_resources(device_t dev) { unsigned long base_k, size_k; + unsigned long touud_k; unsigned long index; struct resource *resource; uint64_t mc_values[NUM_MAP_ENTRIES]; @@ -396,8 +397,9 @@ static void mc_add_dram_resources(device_t dev) /* 4GiB -> TOUUD */ base_k = 4096 * 1024; /* 4GiB */ - size_k = (unsigned long)(mc_values[TOUUD_REG] >> 10) - base_k; - if (size_k > 0) + touud_k = mc_values[TOUUD_REG] >> 10; + size_k = touud_k - base_k; + if (touud_k > base_k) ram_resource(dev, index++, base_k, size_k); /* Reserve everything between A segment and 1MB:
1 0
0 0
Patch set updated for coreboot: de083ae AMD Geode LX: Add AES PCI device 0:1.2 to `devicetree.cb`
by Paul Menzel June 3, 2013

June 3, 2013
Paul Menzel (paulepanter(a)users.sourceforge.net) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/3326 -gerrit commit de083aee374c0a2e03d3fe438190a3ec6a7dd648 Author: Paul Menzel <paulepanter(a)users.sourceforge.net> Date: Tue May 28 20:59:50 2013 +0200 AMD Geode LX: Add AES PCI device 0:1.2 to `devicetree.cb` The AMD Geode LX processor features a security block [1], which is exposed as PCI device 0:1.2. Currently some Geode LX boards in the tree mention it in their `devicetree.cb` and others do not. So add device pci 1.2 on end # AES to the boards not having this line to describe all devices. No functionality is changed, as coreboot was able to discover the AES security block anyway. 00:01.2 Entertainment encryption device [1010]: Advanced Micro Devices [AMD] Geode LX AES Security Block [1022:2082] The following command was used to find all Geode LX `devicetree.cb` files. $ find src/mainboard -name devicetree.cb | xargs grep -l 'amd/lx' [1] http://en.wikipedia.org/wiki/AMD_Geode#Geode_LX Change-Id: Id4565c83ac2c0a3f2994535650bb9f642c0feced Signed-off-by: Paul Menzel <paulepanter(a)users.sourceforge.net> --- src/mainboard/amd/db800/devicetree.cb | 1 + src/mainboard/amd/norwich/devicetree.cb | 1 + src/mainboard/artecgroup/dbe61/devicetree.cb | 1 + src/mainboard/digitallogic/msm800sev/devicetree.cb | 1 + src/mainboard/iei/pcisa-lx-800-r10/devicetree.cb | 1 + src/mainboard/pcengines/alix1c/devicetree.cb | 1 + src/mainboard/pcengines/alix2d/devicetree.cb | 1 + src/mainboard/traverse/geos/devicetree.cb | 1 + src/mainboard/winent/pl6064/devicetree.cb | 1 + 9 files changed, 9 insertions(+) diff --git a/src/mainboard/amd/db800/devicetree.cb b/src/mainboard/amd/db800/devicetree.cb index 3331a12..db78d7c 100644 --- a/src/mainboard/amd/db800/devicetree.cb +++ b/src/mainboard/amd/db800/devicetree.cb @@ -2,6 +2,7 @@ chip northbridge/amd/lx device domain 0 on device pci 1.0 on end # Northbridge device pci 1.1 on end # Graphics + device pci 1.2 on end # AES chip southbridge/amd/cs5536 # IRQ 12 and 1 unmasked, Keyboard and Mouse IRQs. OK # SIRQ Mode = Active(Quiet) mode. Save power.... diff --git a/src/mainboard/amd/norwich/devicetree.cb b/src/mainboard/amd/norwich/devicetree.cb index 93effaa..e4c02b4 100644 --- a/src/mainboard/amd/norwich/devicetree.cb +++ b/src/mainboard/amd/norwich/devicetree.cb @@ -2,6 +2,7 @@ chip northbridge/amd/lx device domain 0 on device pci 1.0 on end # Northbridge device pci 1.1 on end # Graphics + device pci 1.2 on end # AES chip southbridge/amd/cs5536 # IRQ 12 and 1 unmasked, Keyboard and Mouse IRQs. OK # SIRQ Mode = Active(Quiet) mode. Save power.... diff --git a/src/mainboard/artecgroup/dbe61/devicetree.cb b/src/mainboard/artecgroup/dbe61/devicetree.cb index d270f3d..d70ffeb 100644 --- a/src/mainboard/artecgroup/dbe61/devicetree.cb +++ b/src/mainboard/artecgroup/dbe61/devicetree.cb @@ -2,6 +2,7 @@ chip northbridge/amd/lx device domain 0 on device pci 1.0 on end # Northbridge device pci 1.1 on end # Graphics + device pci 1.2 on end # AES chip southbridge/amd/cs5536 # IRQ 12 and 1 unmasked, Keyboard and Mouse IRQs. OK # SIRQ Mode = Active(Quiet) mode. Save power.... diff --git a/src/mainboard/digitallogic/msm800sev/devicetree.cb b/src/mainboard/digitallogic/msm800sev/devicetree.cb index 839b767..63377ec 100644 --- a/src/mainboard/digitallogic/msm800sev/devicetree.cb +++ b/src/mainboard/digitallogic/msm800sev/devicetree.cb @@ -2,6 +2,7 @@ chip northbridge/amd/lx device domain 0 on device pci 1.0 on end device pci 1.1 on end + device pci 1.2 on end chip southbridge/amd/cs5536 # IRQ 12 and 1 unmasked, Keyboard and Mouse IRQs. OK # SIRQ Mode = Active(Quiet) mode. Save power.... diff --git a/src/mainboard/iei/pcisa-lx-800-r10/devicetree.cb b/src/mainboard/iei/pcisa-lx-800-r10/devicetree.cb index a6dba30..b30c169 100644 --- a/src/mainboard/iei/pcisa-lx-800-r10/devicetree.cb +++ b/src/mainboard/iei/pcisa-lx-800-r10/devicetree.cb @@ -2,6 +2,7 @@ chip northbridge/amd/lx device domain 0 on device pci 1.0 on end # Northbridge device pci 1.1 on end # Graphics + device pci 1.2 on end # AES chip southbridge/amd/cs5536 # IRQ 12 and 1 unmasked, Keyboard and Mouse IRQs. OK # SIRQ Mode = Active(Quiet) mode. Save power.... diff --git a/src/mainboard/pcengines/alix1c/devicetree.cb b/src/mainboard/pcengines/alix1c/devicetree.cb index 85e967a..e33d277 100644 --- a/src/mainboard/pcengines/alix1c/devicetree.cb +++ b/src/mainboard/pcengines/alix1c/devicetree.cb @@ -2,6 +2,7 @@ chip northbridge/amd/lx device domain 0 on device pci 1.0 on end device pci 1.1 on end + device pci 1.2 on end chip southbridge/amd/cs5536 # IRQ 12 and 1 unmasked, Keyboard and Mouse IRQs. OK # SIRQ Mode = Active(Quiet) mode. Save power.... diff --git a/src/mainboard/pcengines/alix2d/devicetree.cb b/src/mainboard/pcengines/alix2d/devicetree.cb index d8aa3bc..2b51908 100644 --- a/src/mainboard/pcengines/alix2d/devicetree.cb +++ b/src/mainboard/pcengines/alix2d/devicetree.cb @@ -2,6 +2,7 @@ chip northbridge/amd/lx device domain 0 on device pci 1.0 on end device pci 1.1 on end + device pci 1.2 on end chip southbridge/amd/cs5536 # IRQ 12 and 1 unmasked, Keyboard and Mouse IRQs. OK # SIRQ Mode = Active(Quiet) mode. Save power.... diff --git a/src/mainboard/traverse/geos/devicetree.cb b/src/mainboard/traverse/geos/devicetree.cb index 4a2674e..ee10c78 100644 --- a/src/mainboard/traverse/geos/devicetree.cb +++ b/src/mainboard/traverse/geos/devicetree.cb @@ -2,6 +2,7 @@ chip northbridge/amd/lx device domain 0 on device pci 1.0 on end # Northbridge device pci 1.1 on end # Graphics + device pci 1.2 on end # AES chip southbridge/amd/cs5536 # IRQ 12 and 1 unmasked, Keyboard and Mouse IRQs. OK # SIRQ Mode = Active(Quiet) mode. Save power.... diff --git a/src/mainboard/winent/pl6064/devicetree.cb b/src/mainboard/winent/pl6064/devicetree.cb index f900f78..4b88479 100644 --- a/src/mainboard/winent/pl6064/devicetree.cb +++ b/src/mainboard/winent/pl6064/devicetree.cb @@ -2,6 +2,7 @@ chip northbridge/amd/lx device domain 0 on device pci 1.0 on end # Northbridge device pci 1.1 on end # Graphics + device pci 1.2 on end # AES chip southbridge/amd/cs5536 # IRQ 12 and 1 unmasked, Keyboard and Mouse IRQs. OK # SIRQ Mode = Active(Quiet) mode. Save power....
1 0
0 0
Patch set updated for coreboot: 84d41ea NOTFORMERGE: VX900 early init, and EPIA M850 board
by Alexandru Gagniuc June 3, 2013

June 3, 2013
Alexandru Gagniuc (mr.nuke.me(a)gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/1228 -gerrit commit 84d41eaf5a6395d943f4902a93e78b2fbe5bdbae Author: Alexandru Gagniuc <mr.nuke.me(a)gmail.com> Date: Tue May 21 14:51:26 2013 -0500 NOTFORMERGE: VX900 early init, and EPIA M850 board I will split this up into pallatable chunks once the dependencies are merged. This is the patch where all VX900 development is taking place. The NOTFORMERGE modifier is here to indicate that the code ain't ready. =========================================================================== == Early initialization for VIA VX900: --------------------------------------------------------------------------- MMCONF: Works from very early ramstage. Enabling MMCONF only seems to save a few milliseconds of boot time. The plan is to change the MMCONF implementation in coreboot to allow dynamically changing the MMCONF_BASE, and then use the resource allocator to get a 256MB chunk for MMCONF. SMBUS is functional. RAMINIT: Raminit works with 1 rank, but not with several ranks. DRAM calibration when more than one DIMM is does not work well. The delay calibration strategy is to put some predefined delays for the DQ input delays, and run hardware calibration on the other three delays (DQS input, DQ/DQS output). For the future, we could change this strategy to one that uses the hardware calibration of DQ input. Unfortunately, according to my testing, the DQ input delay calibration does not work reliably. Memtest runs through the serial console. It whines about memory errors during the random test (#7), but this seems to be because it tries to use the VGA memory hole (Errors start consistently at 128MB + 768K). =========================================================================== == VX900 in ramstage: --------------------------------------------------------------------------- MP tables and IOAPIC: VX900 code enables the IOAPICs are enabled as long as they're declared in devicetree.cb. Since we rely on automatic MP table generation, if an IOAPIC is not properly declared, the code spits out an error, and continues without initializing it. LPC: Implemented LPC driver with PIC interrupt routing. VGA: Still displays garbage and/or nothing. Video BIOS depends on proprietary interrupt handlers, some of which are implemented as YABEL interrupt handlers. If run in YABEL mode, the VGA BIOS requires access to other PCI devices and direct hardware access, it seems. GRUB2 and Linux are capable of initializing the VGA post-coreboot. Linux can use the VGA normally, but hangs after a while. SATA: The controller does not support AHCI, or a compliant SATA implementation. Normally SATA is done by setting RAID mode, but then SeaBIOS will not use it to boot. The only viable option is to keep the controller in native IDE mode. SATA device detection works reliably when one drive is attached. ATA DMA mode works reliably. =========================================================================== == VIA EPIA M850 board: --------------------------------------------------------------------------- Minimal infrastructure to compile a coreboot image for this board is added. PIRQ_TABLE: Implemented, Linux can find and use irqs with "noapic acpi=off" MP_TABLE: Partially generated from devicetree.cb. Not tested. KEYBOARD WORKS!!! Change-Id: I7624944dbc05fbf3019897a116954d71dfda0031 Signed-off-by: Alexandru Gagniuc <mr.nuke.me(a)gmail.com> --- src/cpu/via/nano/Makefile.inc | 2 +- src/cpu/via/nano/nano_ucode_blob.c | 900 ++++++++++++++ src/include/lib.h | 1 + src/lib/ramtest.c | 35 + src/mainboard/via/Kconfig | 3 + src/mainboard/via/epia-m850/Kconfig | 50 + src/mainboard/via/epia-m850/Makefile.inc | 21 + src/mainboard/via/epia-m850/devicetree.cb | 111 ++ src/mainboard/via/epia-m850/irq_tables.c | 75 ++ src/mainboard/via/epia-m850/mainboard.c | 24 + src/mainboard/via/epia-m850/romstage.c | 134 +++ src/northbridge/via/Kconfig | 1 + src/northbridge/via/Makefile.inc | 1 + src/northbridge/via/vx900/Kconfig | 40 + src/northbridge/via/vx900/Makefile.inc | 42 + src/northbridge/via/vx900/chip.h | 52 + src/northbridge/via/vx900/chrome9hd.c | 441 +++++++ src/northbridge/via/vx900/ddr3_mrs_util.c | 214 ++++ src/northbridge/via/vx900/ddr3_mrs_util.h | 113 ++ src/northbridge/via/vx900/early_host_bus_ctl.c | 73 ++ src/northbridge/via/vx900/early_smbus.c | 209 ++++ src/northbridge/via/vx900/early_vx900.c | 133 ++ src/northbridge/via/vx900/early_vx900.h | 106 ++ src/northbridge/via/vx900/lpc.c | 220 ++++ src/northbridge/via/vx900/northbridge.c | 188 +++ src/northbridge/via/vx900/pcie.c | 142 +++ src/northbridge/via/vx900/raminit.h | 100 ++ src/northbridge/via/vx900/raminit_ddr3.c | 1536 ++++++++++++++++++++++++ src/northbridge/via/vx900/romstrap.inc | 60 + src/northbridge/via/vx900/romstrap.lds | 27 + src/northbridge/via/vx900/sata.c | 295 +++++ src/northbridge/via/vx900/traf_ctrl.c | 156 +++ src/northbridge/via/vx900/vx900.h | 78 ++ 33 files changed, 5582 insertions(+), 1 deletion(-) diff --git a/src/cpu/via/nano/Makefile.inc b/src/cpu/via/nano/Makefile.inc index f08b482..1349949 100644 --- a/src/cpu/via/nano/Makefile.inc +++ b/src/cpu/via/nano/Makefile.inc @@ -28,6 +28,6 @@ ramstage-y += update_ucode.c # We need to hear from VIA to get permission to include this file in the # official coreboot repository. Until then, we leave this commented out -# cpu-microcode-y += nano_ucode_blob.c +cpu_microcode-$(CONFIG_CPU_MICROCODE_CBFS_GENERATE) += nano_ucode_blob.c cpu_incs += $(src)/cpu/via/car/cache_as_ram.inc diff --git a/src/cpu/via/nano/nano_ucode_blob.c b/src/cpu/via/nano/nano_ucode_blob.c new file mode 100644 index 0000000..6fc04db --- /dev/null +++ b/src/cpu/via/nano/nano_ucode_blob.c @@ -0,0 +1,900 @@ +unsigned array[3588] = +{ + 0x53415252, 0x00000000, 0x010f07d9, 0x000006f2, + 0x04bb1af1, 0x00000001, 0xffffffff, 0x00000ca0, + 0x00000cd0, 0x46363030, 0x45325032, 0x00000000, + 0xcb93e3bb, 0x191b8d4a, 0x1863851e, 0x5073b90e, + 0x637e23a3, 0xfb2b5429, 0x04714c6c, 0xc15656b7, + 0x1a338d28, 0x1b182ec1, 0x3c52af0a, 0x6d370976, + 0x969bc177, 0x64487a31, 0xcc081129, 0x5e1eab09, + 0x60510c3c, 0x8a8056df, 0xd63b03a9, 0xa44b1274, + 0x0debc269, 0x8b0345ed, 0x4970a2f6, 0x207d49ea, + 0x204d200f, 0x382f15c8, 0xa036eb02, 0xb4a7bc00, + 0xdb71ba56, 0x94b7c995, 0x9a62daf2, 0x1121f430, + 0x3e4a5be0, 0x3c7161fc, 0x871cf176, 0x401b4152, + 0x7666d9e6, 0xa7d0a300, 0xba2badc0, 0xb76c09d7, + 0x20188e4c, 0x790a4683, 0xc9e67da8, 0x0e06ac83, + 0x61a20460, 0xff613e2b, 0x75987149, 0x1f377798, + 0x0d2d0a03, 0x80770351, 0xfdd1521a, 0x9e0c3559, + 0x615cff3f, 0x4b52bf4f, 0x7f147ef1, 0x8710413d, + 0xa1f56c83, 0x82b4e353, 0x41059fd8, 0x0ba3cee2, + 0xec086b55, 0x30884385, 0x8de9db16, 0x5b43fe34, + 0x181d9769, 0xaf85ba70, 0xc1e0339d, 0x57543307, + 0x6a9f4dae, 0xc311f618, 0xb517af2e, 0xf1dee71b, + 0x055b82d4, 0x2c87f018, 0x855e566e, 0x62902b91, + 0x81add936, 0x369c1e10, 0x580b5188, 0x72884066, + 0x60451175, 0x33f8c435, 0xeb7a0000, 0x403bb343, + 0xa7af4cee, 0x52dc1a70, 0x0f14769b, 0xc3322154, + 0xbe2d133c, 0x18631717, 0x4dd84315, 0x004885c0, + 0xeb301a26, 0xff84832c, 0xcba0da4a, 0xa62d6358, + 0x63f014e7, 0xfd11a7cd, 0xe4caac35, 0xee8eac91, + 0xf46f29e6, 0x98b09104, 0xf3e95a8d, 0x66b0a414, + 0xd8fc6cd4, 0x5ffd91e9, 0x59df2432, 0x5a76aba5, + 0x39564d85, 0x05743921, 0x0f8c6cc2, 0xc75205b0, + 0x69ebf3a1, 0xbd742cf5, 0x75b4904f, 0xb6757441, + 0x0019eb84, 0x65186919, 0x5cda5257, 0x9abec161, + 0x2703a74d, 0xb8e17040, 0xcee1b384, 0x13e81aed, + 0x5f1accea, 0x61593e03, 0x1e3a816e, 0xddd02632, + 0x489c55c3, 0x999ee852, 0x6f1fc127, 0xb8a3dda1, + 0x88218af7, 0xafd4a7c1, 0x8a9cd570, 0x525b63d8, + 0x39ca4752, 0x18cda626, 0xc6871457, 0x53606f5f, + 0x57e6bc19, 0xe7fca134, 0x5b554854, 0xa92ca963, + 0x9fefd3ff, 0x208c2169, 0x585520fa, 0x1661b36e, + 0x47ab65ee, 0xdfebfbf9, 0x9c66a187, 0x17dad804, + 0x2c78cadc, 0xd5e76482, 0xc5325e9f, 0x75f4e6a3, + 0x5bf89d31, 0xe3b8343b, 0x66ae81c0, 0xb08e79bd, + 0x7c14f7d3, 0x77c55a1c, 0xb9564471, 0x7fbf729a, + 0x80b59bd8, 0xa11c09fd, 0x07e3ca4c, 0xbab01bcd, + 0x3789f6bc, 0x9818d37d, 0xe6d32289, 0x0f6a4bf6, + 0xcd25812f, 0xb77d2cdb, 0xfc2d2824, 0xb86998dd, + 0x66de552c, 0x063f6eba, 0xd65591a3, 0x59ade6b7, + 0x5dfa16eb, 0x8c5b0b17, 0xc5b92112, 0x2f5a48b8, + 0x81ad574a, 0x42259f3e, 0x79403f4b, 0x0924fc75, + 0x108fe221, 0xa251e85f, 0x4e8c16ec, 0x365c9527, + 0x2abbb52f, 0x118c79a7, 0xb05ba6c0, 0x0eb2b3ed, + 0x8b011c88, 0x79175adb, 0xcbafe02c, 0x9307c24f, + 0xd15209ca, 0x23e569fd, 0x26815346, 0x425bd748, + 0x504217c2, 0x64e9d2c0, 0x400ba29a, 0x632e3858, + 0x7ab4e2d5, 0x6e868452, 0x85bd8005, 0x189cd3c0, + 0xd3cbe3f7, 0x820a90aa, 0x4f68b900, 0x65c53860, + 0x9a86de7f, 0x4c836b6b, 0x73841092, 0x78590b4a, + 0xcd4afc02, 0x73e79113, 0xafefe0f9, 0x30bec385, + 0x1fc9252f, 0x6ee8ce4d, 0x3cfa91bb, 0xf493ad13, + 0xf02593e0, 0xa63b96da, 0xa7a9c5cb, 0xdcf34661, + 0xdabcc8c9, 0x1f330aa8, 0x288df4de, 0xffc2462a, + 0xba825a78, 0x6a12478b, 0xda32e0a9, 0xb832887e, + 0x5fe63cc3, 0x26cc1f1b, 0x4c7015be, 0x52b54080, + 0xb025f5f1, 0x8f8d5ede, 0xbfd6ce2f, 0x924891c3, + 0xbe57187d, 0x46e5774f, 0x60a835a3, 0x55a976d3, + 0xe30f0595, 0xca07e54a, 0x8231e320, 0x8f977146, + 0x475d7c82, 0x10d413c6, 0xc052b913, 0x4c837bc3, + 0xbb18ba72, 0x504e64d8, 0x6981f723, 0xda361a85, + 0x93443179, 0x74ee16a6, 0xe69a40a5, 0xc117916c, + 0xef2f94ac, 0xa06b1e43, 0xdc6e01f9, 0x738e45d0, + 0x6b691cca, 0xd3aee7a7, 0x4fe6ee6c, 0xaf2c3419, + 0x936e5354, 0xaa757d6d, 0xd01d94fc, 0x47472d81, + 0x59489f6d, 0x05cc8f75, 0xeaf2c914, 0xde038603, + 0x421e1d5d, 0x45130e4f, 0x8567c50a, 0x240a6fe6, + 0x2d270151, 0xeebc219e, 0x0c144950, 0x7d720b18, + 0xe6fcf50f, 0x0cda08b2, 0x9241fad6, 0x93152f2d, + 0x168b85b9, 0x6eeaeacd, 0xd260c66e, 0x98722b57, + 0xe7fcce71, 0x8cf65088, 0x7c218a64, 0x9e957b44, + 0xb2f65850, 0x077e049f, 0x2e53ea65, 0x7bf3cb90, + 0xca9a4364, 0xddacedc2, 0x1d14f350, 0x3bde8346, + 0xf7e5d1ee, 0x7328349d, 0xd665e46f, 0xeffc771b, + 0xb8e40217, 0xaf1ffddb, 0xacef49f0, 0x7a4767e1, + 0x29659ac1, 0x8fdfee86, 0x2652e871, 0x32ef6440, + 0x23981fef, 0xd6956341, 0x44996531, 0xc6dac529, + 0xdb49a5c1, 0xb49e0268, 0x03b9a628, 0x859a9cb5, + 0x2324f6de, 0x8e09a640, 0x73111b32, 0x209d2265, + 0xf8ce7adf, 0x1fee2336, 0x91be0cc2, 0xa6231b34, + 0x2ee23a48, 0x1f9f0f02, 0xcef888d5, 0x54928d45, + 0x84a864f8, 0xdffdc2ac, 0xedead650, 0x895781ca, + 0x2c1ae5c7, 0x7cd560f0, 0xf346ad96, 0x2a919ca3, + 0xe845fb6a, 0x5d571861, 0xa28f98f7, 0x0625128f, + 0xb3032eea, 0x5e737938, 0xab4e2758, 0x30da5a1a, + 0x0700091c, 0x49e24af7, 0xb8739db8, 0x7071cb8d, + 0xe8b664cf, 0x5fd996ac, 0x69949200, 0x7e8e89ed, + 0xb534a7bc, 0x79fcab56, 0xf7c922c0, 0x260db9df, + 0x044a7415, 0x771bf7c6, 0x43c80438, 0xa68f9d6e, + 0x26866efd, 0x069dbef7, 0x5ec95f89, 0x118a6f4e, + 0x04f307c8, 0xd2442831, 0xc3a4055d, 0x38dd57bb, + 0x5a2bf99e, 0x943c8216, 0x8a8a8d67, 0x06d8933d, + 0x36d8c238, 0x52892351, 0x233fca34, 0x8f37f14a, + 0x03da33bb, 0x5403344c, 0x89abc6db, 0x0c615ee4, + 0x841c70f6, 0x2eb7465a, 0xbe04d7f2, 0x58d30b98, + 0x684f579c, 0x04968042, 0xa1288066, 0xa02d7561, + 0xef31130a, 0x7af7c497, 0xd06ac0f2, 0xd7d213f3, + 0xc7151981, 0x6f62d944, 0xfa29cd6e, 0xcc39d1c6, + 0x1ac2747b, 0x3c15dd86, 0x9c0c31eb, 0x81297dc2, + 0x1da797fc, 0x7eede51d, 0xb7acaba4, 0x3fe2d1af, + 0x72255af0, 0x99649635, 0x993f7868, 0x400d58f5, + 0x6d606432, 0xb3a02790, 0xbc8b9346, 0x001c3213, + 0xf0521676, 0x8fed58a2, 0x91a13447, 0x2a2e3fe3, + 0x3d961ac1, 0xee9f3e1a, 0xdb1e5cc0, 0x91170710, + 0x3bb17cd9, 0xa87cc42a, 0x29fb31dd, 0x540fa9c9, + 0xe74c97ef, 0x08e2ac05, 0xee5255cb, 0x8ccb8dad, + 0x14508794, 0x75702112, 0x05ecb30b, 0x5b68f36f, + 0xdd90f0f0, 0x4c60e9fe, 0x1152b8b2, 0x1598fe5e, + 0x10f1a26d, 0x95b63950, 0x4360fd96, 0x65c82329, + 0x2a4b6080, 0x9ff2d6aa, 0x8ff3c3af, 0x2ebdbdec, + 0xc42c46d9, 0x1af653ee, 0x5fbf4d3a, 0xa9936322, + 0xdc317ab0, 0x7671bdbd, 0xc971f3aa, 0x07978288, + 0x7c47615b, 0x0db52c1b, 0x3d0eda0b, 0xe63c6102, + 0xd56ef998, 0xaa755081, 0x0a749833, 0xcf4ec8ed, + 0x34a92cff, 0xee1bf9a1, 0xb59b0b64, 0x96354086, + 0x9d7d5a3c, 0x8144a9ad, 0x96830ca9, 0x90703b77, + 0x44db18c2, 0x0932960c, 0xc89dbf7b, 0x3ca76c1c, + 0xe6cc836b, 0x368eede3, 0x55c18caf, 0x00cbafd5, + 0xc3078024, 0x7d15441c, 0xd23ad62c, 0xf7661a68, + 0x98847057, 0xd6767a16, 0x196501b6, 0x68396b86, + 0xef4af71b, 0xa81367c2, 0xa4d13e7d, 0xbb8eebeb, + 0x4db5f47a, 0x731be642, 0xc2a15f27, 0x3324a7ea, + 0x0db10f7b, 0xaba8fe35, 0x225eb533, 0x9f188e3d, + 0xa5da4ad3, 0x3464c397, 0xc7572bc2, 0x43bc38e5, + 0x3a79ff7f, 0x3021c8f4, 0x822d257e, 0x295f9ee3, + 0xa62aa886, 0xeedfdbd0, 0x10ba9b9b, 0x6304cbca, + 0x03bbb766, 0x5fccc253, 0x6434c05e, 0xabd80cac, + 0x036ea64a, 0xc7babe5a, 0xde7b2fbe, 0xbcd2d22a, + 0x5f8219a6, 0xfc75fedf, 0x4f17ce1c, 0x6e670ca9, + 0x625b6ae6, 0xee8e9f95, 0x3b3eaae1, 0x9b3ca894, + 0x0b0ba78b, 0xfad8065d, 0xa1006779, 0xad9dc956, + 0x9f1d8e3d, 0x92f57a18, 0x9bc9e111, 0xc318ae8f, + 0xb6862269, 0x3d06fb0d, 0x861c740b, 0xb95e8053, + 0x419e7fd2, 0xc360dc82, 0x26d99c21, 0x4336524b, + 0x8a9414e5, 0xef9e020e, 0x57e81247, 0xa32a3cab, + 0x568e0a11, 0x4daf23bd, 0x1b5d7277, 0x212b7332, + 0xdb34afb5, 0xf3d0c01d, 0x5ca627df, 0xaa39c230, + 0x4192aa29, 0xed166fa9, 0x071922a6, 0x61074f39, + 0xfa700b5a, 0x4a60ed83, 0x1d1d9850, 0x5fe6c671, + 0x17730867, 0x6b2c5bfc, 0x0e0dd897, 0xa5c82db3, + 0xffcd57cb, 0x962ec9fb, 0x1ac2bdfc, 0x8b85b190, + 0x7a4b5a35, 0xd1224522, 0x900462c7, 0x32805daa, + 0xa1a8b29b, 0x4720559b, 0x1d846a68, 0x08edd510, + 0x02ca010f, 0xeadce4c4, 0x038cde06, 0xbdbfadac, + 0x9144d599, 0x670e6072, 0xc14d3857, 0x61f2de60, + 0x003d684f, 0xc1ddece7, 0x66c453b6, 0xaf66d81a, + 0xe15a2f94, 0xbb3c1f59, 0xab6f1f7d, 0x3b24d812, + 0xd629cd94, 0x09d51c81, 0x45cc0259, 0x8eaa8b98, + 0xbd945c62, 0x4e74d9ba, 0x449372d0, 0x59bbc106, + 0xaa2e4bda, 0xeb24fd0b, 0xc461db59, 0x89fb5031, + 0xd51d68bd, 0xe43f615f, 0x0cda1656, 0xe5d77e7a, + 0x8136b5c1, 0x13b0c9fd, 0x424adc1c, 0x62797556, + 0x450ac473, 0x7f1a6b9d, 0xf678b474, 0x56bd0f0e, + 0xe0d75f60, 0x29fc1192, 0xed79a7de, 0x331ffd62, + 0xacdac9e9, 0x59de2860, 0x81765718, 0x288c9049, + 0x5aa21365, 0x1d8c1119, 0x1f69f6aa, 0x9d5fecc7, + 0xccab7d03, 0x611dd66d, 0x88cff2c3, 0xa32df329, + 0xfb79f49c, 0xa5673b94, 0x01ca3e4a, 0x4a3c4a3a, + 0x79e381ee, 0xfdccd33a, 0xdfffe03c, 0x71785391, + 0xd35dc0a3, 0x90c514d7, 0x7f272154, 0x2fbade0b, + 0x7e7a40f7, 0x81225389, 0xbc7959fe, 0xfc11b819, + 0xb35a6494, 0xf2536a6f, 0x08797aa8, 0x448cd990, + 0x9444e16e, 0x03e145ae, 0xd5df6c1b, 0xbf11e6bf, + 0xa4cfa985, 0xa22bfbfe, 0x0a51c5c8, 0xdc037e99, + 0x22433d50, 0x734d2ba1, 0x8462dcd9, 0x93c0eaca, + 0xef87a4bd, 0x7ddfcd1e, 0x73e7d2c6, 0x55c6a86c, + 0xc1d99aae, 0xe88fa687, 0xbeadd303, 0x91af28c0, + 0x38e178a0, 0x903911b9, 0x804982e8, 0x4e28b42c, + 0x50d16e74, 0x5cf89c55, 0xa5e4a723, 0x69647877, + 0xb9e426a6, 0x5f0b5419, 0x4c810a84, 0x99c0bc0b, + 0x1c66db66, 0x9d664e5c, 0x97c517f4, 0xcd7bf742, + 0x284a6299, 0x29a414f6, 0x266b30bf, 0x341a3c0f, + 0x03649f3c, 0x3baaff4f, 0x150626e4, 0xcc705cac, + 0x97f93343, 0x5c667935, 0x796e0213, 0x87339a47, + 0xb67e7c0b, 0x19d36387, 0xfdebd50f, 0x2ccbb93a, + 0x53418f96, 0xb9913750, 0x474e557d, 0x39066bfe, + 0xc132ed2f, 0x969eef68, 0xeea46a2b, 0xf38d3ac8, + 0x94fa4b4a, 0x0f3d5a39, 0x663681bb, 0x052d913d, + 0x0ed760d8, 0x6a86a5e6, 0x3b4f8215, 0x45e1703e, + 0x7b6da797, 0x2f417ce8, 0x370805fb, 0x10d71f7d, + 0x939e57b1, 0x660658bf, 0xb0578eff, 0x83c92004, + 0x82d2e830, 0x6a069ede, 0x37bff328, 0xcfc11964, + 0xc1551e3b, 0x43f5f81d, 0x993a4c70, 0xb5368f5c, + 0xcdfd6ab1, 0x33fb820b, 0x8982c211, 0x658c9d3d, + 0x03d94fea, 0x9d14461e, 0xf6054c0b, 0x23505ea9, + 0x767bc220, 0x2ae3ca31, 0xf3994369, 0x60c3f27e, + 0x4b9b0489, 0x44cc2326, 0x8c6f6753, 0x92905384, + 0x4aa90362, 0x5fb075a6, 0x2e61e8bb, 0x46cd1270, + 0xe72c6c9d, 0x83111ee4, 0xccd8f5c5, 0x5103ec2f, + 0x6e851815, 0x947f246e, 0xde86ad18, 0x9760a987, + 0x059e48e2, 0x58a79e93, 0x6aa5b31a, 0x35aabcd5, + 0x71f4d3e7, 0x1ae1f425, 0xecce2950, 0x6253dc95, + 0xd91f8ddc, 0x214a4a07, 0xb4d299ad, 0x13ef8d8e, + 0xbed7b47f, 0x4a12a7eb, 0xeb0963ab, 0xdf0f3b8f, + 0x2aa6845d, 0x80881430, 0xd615c63d, 0x4d244696, + 0xf627cc27, 0xe03210af, 0x2bc55248, 0xf16867e9, + 0x1e065d75, 0xc2b362cd, 0xd9751d64, 0xc2949adf, + 0x53415252, 0x00000000, 0x061a07d9, 0x000006f3, + 0x08074e5a, 0x00000001, 0xffffffff, 0x00000390, + 0x000003c0, 0x46363030, 0x32315033, 0x00000000, + 0xb07f7392, 0x535a690e, 0xb60295df, 0xfaff25b9, + 0x4f4609e6, 0x9fe6ac72, 0x879663b0, 0xab25c96a, + 0x65e5e671, 0x5cd611f8, 0xf39e82bd, 0x931d23de, + 0x4504a04c, 0x2ba455fb, 0x2fc1034c, 0xbd47d87e, + 0xdeb4d91c, 0x33e88111, 0xf1521b6d, 0xa0f8cb0f, + 0x013166c3, 0xa784e786, 0xb564c335, 0x826dca49, + 0xda84b5e5, 0x63b0da88, 0xd15fd3b3, 0x501590bf, + 0x9efa91a7, 0x5f8b7591, 0x97710227, 0xf162ab61, + 0x76ec62b9, 0xa8bbba48, 0x5be51483, 0xb84fdb38, + 0x933f9758, 0x8616b6b7, 0xc0b405c4, 0xcdbd4e00, + 0x254c6488, 0x907dc541, 0x90edf61d, 0x5beef31e, + 0x782de3cf, 0x158500d4, 0x9cee8612, 0xdebe1f64, + 0xce9d7aa3, 0x0b968a79, 0x520ae716, 0x3dc74a69, + 0xb2393da8, 0x6a9f4ec0, 0x7e609890, 0x07121f6b, + 0xb318c3f8, 0x52db78bd, 0x2530e9fe, 0xae1a1b72, + 0xef55426d, 0x462b9823, 0x9b5fcc9f, 0x46b525ee, + 0x5284a388, 0xc1ce0d78, 0xf9e86226, 0xaad31a00, + 0xb183aeb0, 0xa75f6593, 0xffa6705a, 0x1d43b713, + 0x644424eb, 0x1f9cc20e, 0xa096550f, 0x3497cebd, + 0x1941af1f, 0xcf205da8, 0xb3996a90, 0xa08cd793, + 0xe1021d21, 0xaa80086e, 0x30e29788, 0xd35458e5, + 0x6d5b50cf, 0xc5aaa0f0, 0xd8dceac7, 0x096d6e2a, + 0x10b245dc, 0xba5c77c1, 0x2970e03b, 0x4b742ff2, + 0x6a2ffbf5, 0x42d4cdbc, 0xeb2744c1, 0xf49eb6f5, + 0x806e288c, 0x608e6ad8, 0x9fa0d47f, 0xb40e1ae4, + 0x0e63b495, 0x6b1b1fbd, 0x8f1dcda5, 0xff0f7888, + 0xeb425a16, 0x1eee7e0a, 0x69c202bc, 0x04020726, + 0xbbc62de3, 0x6ebbd54b, 0x22be95c7, 0xe37298e9, + 0x309bd861, 0xb04b8d33, 0x63b1e9dd, 0xa27459a1, + 0x1f7f69eb, 0xb4cfda0b, 0x226d81a3, 0xaef54cc2, + 0xfdb2af55, 0x8f40bd55, 0x7c75fc1b, 0x1ea27f79, + 0x7d4775a3, 0x49b65d08, 0xbd9afb11, 0x9c54c786, + 0x01fe71ea, 0x9bfc7e9a, 0xe8dca094, 0x416dd13c, + 0xc160dfe5, 0x737538f7, 0x6e4a1a3b, 0x3e6dafc7, + 0x6d72e2ce, 0x12e54b8a, 0x7035f549, 0xb072e1d4, + 0x3b38588f, 0xe026e230, 0xeb224bf0, 0xe37f21c9, + 0x9a36fef9, 0x5d82682d, 0x11e5edc2, 0x3442a202, + 0x5072abc3, 0xe544eb7e, 0x578bde22, 0x295f8584, + 0x02c23076, 0x35476376, 0x9f135eb8, 0x0613fe0f, + 0x5ff04afc, 0xd3e1053f, 0x23b58392, 0xc4a0f77a, + 0xb87814d6, 0x3a8c17f4, 0xb5efab44, 0x3fe2c21e, + 0xcbe0efb6, 0x12997b25, 0x5b18b44e, 0x6b849d21, + 0x580f84e4, 0x99a964d0, 0x3fa892a9, 0xd4b01144, + 0x6d54c83b, 0x31659593, 0xd7596e21, 0x642c0e11, + 0x7403ea9c, 0x47719512, 0x33a86634, 0x8ae60597, + 0xb94e5df6, 0x5cf4e917, 0xe438f361, 0x8f5d4d13, + 0x00f3d7b7, 0xb9b15305, 0x8e9e1537, 0x350c32f9, + 0x31d5f77f, 0xdb7ae793, 0x70094efd, 0xca83ff65, + 0xa7f487dc, 0xb15ddccc, 0x99609635, 0xf06787f3, + 0x8bc4b4e1, 0x6ebc77e2, 0xf55f780b, 0x4a3b9c96, + 0x91860f8a, 0x75827196, 0xb5948530, 0xc7152cb7, + 0xec776fea, 0x55c73d21, 0xc4b036c5, 0x69af8697, + 0x1d80bc77, 0x91eea8a8, 0xd1ba9808, 0x5a0a812f, + 0xc2a14b33, 0x351a2801, 0xc0b41870, 0x3241a4f9, + 0xa09fe4b5, 0x407aae2b, 0x394b6e00, 0x323a0b88, + 0xa01681d5, 0xda56a382, 0x216d8f3d, 0x7b8e0b61, + 0xfb4aa26e, 0x6e5c4623, 0xdc082e4c, 0xe9ea397c, + 0x53415252, 0x00000000, 0x061907da, 0x000006f8, + 0xd4f1b587, 0x00000001, 0xffffffff, 0x00000220, + 0x00000250, 0x46363030, 0x46325438, 0x00000000, + 0x3299b452, 0x689711fa, 0xee4c84d4, 0xba1598f3, + 0x1b403653, 0x2798a70b, 0x224e13ad, 0xc328665d, + 0x19f33bc3, 0x54e1be26, 0xe8128c3f, 0x06f9f27f, + 0x6fb344ff, 0x36bd410e, 0x229793f2, 0x4d5bc18d, + 0xc4f03970, 0xfc7234d0, 0x1856eb5d, 0xcb3a0ed7, + 0x524e9de9, 0x1f6cde76, 0x1affdd49, 0xadd2bab5, + 0x9c472670, 0x84553d4e, 0x7c8124e1, 0xaddd4ac0, + 0xf3588d7c, 0x4642a4be, 0xb1eaa4e5, 0x9069602a, + 0x44118af3, 0x3c4c0dbc, 0xacfafeca, 0xa6c708be, + 0x4610f501, 0x91f4aabe, 0x0fa3cddf, 0xc64761a7, + 0x22022ece, 0xa4d589bc, 0x237de460, 0x60067a6c, + 0xf4cff750, 0xd7f5f8c5, 0x9ce2a52a, 0x5653e820, + 0x139344a8, 0xc1203a30, 0x4e7f9226, 0xf562836d, + 0x0280a4f9, 0x6f23eb5e, 0x3a0e7684, 0x23281e3e, + 0xb3c7c258, 0x216d2392, 0xba5f0c35, 0x4e82b0fc, + 0xf4e4b3ab, 0x1cd124b7, 0xe1a3261c, 0x5972c999, + 0x9575d310, 0x58c81253, 0xc24d1f17, 0xd224c5f7, + 0x1205ac8a, 0x2a0fccee, 0x3017b59b, 0x8caf9c22, + 0x9e2a470c, 0x3a217bfb, 0xafc9c401, 0x8f278be9, + 0xedcc7fce, 0x293cfb52, 0x2fbcf8f5, 0x2470a1df, + 0xc8fa046e, 0x58315fcb, 0xfc7c7834, 0xcab53bdd, + 0xf3615edf, 0x65f5df91, 0xb145ec86, 0x246bb495, + 0x6a71f1e8, 0xc01d50cf, 0x6768cb06, 0x835912be, + 0x884a8f0b, 0xafa8c8c0, 0xfa37d361, 0x8026f64e, + 0x8c755c89, 0x4c412800, 0x94f8c215, 0xcee50ecd, + 0xe4098f72, 0xe932bccd, 0xf0d2a3b0, 0xe3cbfd25, + 0xecc7ce41, 0x501b9db9, 0x160ef756, 0x35e97342, + 0xc1de34a6, 0xb9f30ca2, 0x1e5018a7, 0xcc6ed6c3, + 0x84698919, 0x8e1337e2, 0x299b3d65, 0x401339a2, + 0x437d0911, 0xa0baf2cc, 0xe23713b1, 0x814cde1a, + 0x18977d01, 0x22a6a5fd, 0x75eba689, 0x586ecb90, + 0x9a5b37e3, 0x3d3da0f1, 0xed63599a, 0x40dba6cc, + 0xa8a920a7, 0x9b548faf, 0x7562d2ca, 0xd69ac4e0, + 0x59ef1bfc, 0x08787853, 0x82844a28, 0x2cd823e5, + 0x53415252, 0x00000000, 0x051a07da, 0x000006f8, + 0x5d1a2de5, 0x00000001, 0xffffffff, 0x00000c20, + 0x00000c50, 0x46363030, 0x64325038, 0x00000000, + 0x1239d07e, 0x691e32e0, 0xd205e5c0, 0xdfc570de, + 0x278e4479, 0x4bca3390, 0x6e7e9b71, 0xd4a85a32, + 0x99af2c5e, 0xb452d0a5, 0x4bec4f39, 0x045a8308, + 0x09639159, 0xe5ee7bd3, 0x1f49d8ef, 0x3a72c6ce, + 0x9a299074, 0xf7a294c2, 0xf88ad4e9, 0x99a46faf, + 0xd106a8e9, 0x1c1c978b, 0x22c43cc1, 0x4af01738, + 0x1f0d51e1, 0x43976497, 0xd59b7f7c, 0x77879a05, + 0xe8e89fed, 0x93e1b538, 0x9d3855ef, 0x7ea23c17, + 0xe550e1f6, 0x17613f73, 0x0783fc18, 0x81980e9d, + 0x107dc8df, 0xe620b143, 0x48236b44, 0xabf1efb9, + 0x7100c5c7, 0xd2245ace, 0x8c859d0b, 0x563a71b7, + 0x697dc982, 0xc34a7399, 0x84fea92f, 0xfe6fae64, + 0x5e053930, 0xf3de4ab5, 0xc9924782, 0xa4509166, + 0x96780cbb, 0xf9008bb1, 0x4d9f7e1b, 0x0e117f75, + 0x01c28c4a, 0xe4321ae6, 0xfb340eab, 0x666247a1, + 0xa8a5a4a8, 0xe47a3486, 0x94b71bff, 0xeb6d4841, + 0x51b7dbbf, 0xcf6bdc3e, 0xae0c68a0, 0xd28c8e55, + 0x170435d7, 0x9ee8dcb5, 0xcd2de33e, 0xd13ac2de, + 0xa15478d6, 0x226485e7, 0xff7ab105, 0xa0c4ae78, + 0x4a8c6cd6, 0xbe4008ab, 0x1037e1e5, 0x5eeb7789, + 0x9811fe9c, 0xde44c9ed, 0xa2ffd6d1, 0xecc9f0da, + 0x00a460e2, 0x44767b1a, 0xe854e585, 0xc70d0131, + 0x3f519a63, 0x468d4386, 0xbbd9c826, 0xa8de428a, + 0x0015b96d, 0x17221e10, 0x514e719e, 0x62398cee, + 0xb67bb642, 0x0b552de8, 0xe2b2d2f6, 0x22be5083, + 0x5ab773ae, 0x46cf2603, 0x86d62320, 0xa0748945, + 0x5493221a, 0xa783c1ba, 0x622660e8, 0xb6dc2449, + 0xc1897743, 0xfd20c8b4, 0xe14c135f, 0x4e811706, + 0xdfdd2b7d, 0x3c16ffa5, 0xd0905f28, 0xc823bef5, + 0xd862aa3b, 0x31365fb9, 0x7bd9c7ab, 0xbcf2d6c4, + 0xbfc18909, 0xe26312ca, 0x5a68d937, 0x6d250f9b, + 0x0781914d, 0xabe54ba9, 0x85d894e6, 0x8c825963, + 0xc6e50f72, 0x538ea5a1, 0x861a4623, 0x2bffc2de, + 0xe28ae4a2, 0x397d6007, 0xa861f13d, 0xdba785be, + 0xc11c37e5, 0xc41a74d7, 0x0f1485c5, 0x1e477a67, + 0x8c3d8f46, 0xf7ed4dc8, 0xe99bc25a, 0x1900b0b0, + 0xe5cb1b0e, 0x86d18bbf, 0x06ce255c, 0xa762a311, + 0x721137c7, 0x26770edd, 0x41839b2c, 0x4bd33366, + 0x53836b63, 0xfdc9ed92, 0x5a5145cd, 0xb389fb44, + 0x2314ff6d, 0x3b6f0c95, 0x3b201e62, 0xbc5c0994, + 0xc620809b, 0x2d9cfacb, 0xe7ed2028, 0x43ecd1c1, + 0x13586475, 0x4a720fd7, 0x402f351d, 0xb9781bf9, + 0x730e46b4, 0x6810e052, 0xf1dd1b73, 0x8c93e152, + 0xb668f9a8, 0x387ee173, 0x41b84b1a, 0xfccfcd68, + 0x6047f011, 0xaec6155a, 0x29e0273b, 0x3c9d935e, + 0xcb98f03e, 0x4fb51e6f, 0x3ad9b929, 0x6569a278, + 0x09b3f6a5, 0x722e9d27, 0x3d4e7da7, 0x11eb3728, + 0x076d703d, 0xdca1cf88, 0x2bfad541, 0xcb82293b, + 0x99c39f16, 0x6bcb6cbb, 0x1ed41582, 0xcc9be6f0, + 0x11f00eb4, 0x1ba055d1, 0xe9a43853, 0x5c055bbe, + 0x1ba8500c, 0x70430fd4, 0x45583d82, 0xfc41ef87, + 0x3e513205, 0xfd65386c, 0x8a814402, 0x14117437, + 0x8a486978, 0xb49cc14d, 0x9c22a9e9, 0x746c15ae, + 0xcab3486f, 0x3989de53, 0xd7e237cb, 0x5feb4d98, + 0x5c56cbc2, 0x841b5e44, 0x09c9a118, 0xf1f2d529, + 0x4fb098fc, 0x1cb3e1ea, 0x9f25bb78, 0xd56f9469, + 0x38b08d7a, 0x19b0e914, 0x86311f65, 0x7069459d, + 0x711daf17, 0x09738673, 0x53e9bedb, 0x043032e5, + 0x32058bd4, 0x22b1a50f, 0xc66b2642, 0x2a7c553c, + 0xe7da476d, 0xdfbcc19a, 0x538b5822, 0x3bca007f, + 0x082d45fc, 0x78bfcdcb, 0x98e554c4, 0x9ec8e392, + 0xebf5ed7c, 0x3b154db7, 0xacf59ef8, 0x8443d4a5, + 0xd90a6e4d, 0x486d9807, 0xfd4bab17, 0x76628450, + 0xc73b007e, 0x9397abc5, 0x63f035c8, 0x92c4603b, + 0xe5807fd2, 0xd305a2ae, 0x65d2c231, 0xdf35bd23, + 0xaae754fe, 0x46b9de20, 0x699fd249, 0xa38ddaf0, + 0xb3dbf2df, 0x151c7094, 0x7bf864b9, 0x65aff002, + 0x7d8d621b, 0xce073aa8, 0x6086f5b5, 0xfd4d8243, + 0x791482c3, 0x0df0d01d, 0x6ad8e4ba, 0x6ad0d3f7, + 0x2b77d92b, 0x6d68d02d, 0x4a43d822, 0xfef3b1a1, + 0x54e96282, 0xdb7ab5b3, 0x72aac1d9, 0xfb4f83ad, + 0x1e51747c, 0x36fea058, 0x1e715a12, 0xf3aa6639, + 0xfd1a3a64, 0xf173bee2, 0x6a382ad0, 0x48435821, + 0x31b90284, 0x3b9ba0c1, 0xf2329444, 0x323f7d8d, + 0x8c72dc74, 0xce9301e1, 0x8cb5cd91, 0x124f7dcd, + 0xcac6a0f6, 0xe487f261, 0x88e05297, 0x49074df2, + 0x1c4c72ea, 0xbf37e900, 0x09103656, 0x723f13f7, + 0x454b06c2, 0xe35eaf5f, 0x8879aaa4, 0x78c5ef10, + 0xe5895238, 0x749df405, 0x0ce57fec, 0x6da90247, + 0xea013e94, 0x6c907d03, 0x1b2f69b5, 0xb2744c73, + 0xad1fa97c, 0xca641bb7, 0x10af012e, 0x0c922243, + 0xa35519c2, 0xcc3067e7, 0x1064d47d, 0x087e9aa6, + 0x803b5642, 0x9936d3c1, 0x3336db24, 0x2c3ccdec, + 0xe5b6be8a, 0xe69dea99, 0x4a6f9632, 0xa9a945ca, + 0xe7ba26df, 0xb2dae8a0, 0xde770e47, 0x91138e00, + 0x3895be22, 0xd0b5f9b5, 0x834c3f69, 0xf75d5f75, + 0x90468761, 0x009f6475, 0x73fe55e6, 0x73a00e1c, + 0xddaaa0c5, 0xeb3ab712, 0x15d4c070, 0x1cdafd9f, + 0x67831b13, 0xef666e8c, 0xc28c36a6, 0x42e5e1f4, + 0xd5eb66b7, 0x388f50b3, 0x048c56ed, 0x2f4f9415, + 0x435785a6, 0x9d42dc6f, 0x4273b34e, 0x3c3595e8, + 0x15f938b4, 0xe2dd91ca, 0x83336b59, 0x4fd6fb7c, + 0xbb696bdf, 0x27ce9bd3, 0xdbb85616, 0xf9d9fb6a, + 0xb2f0eff5, 0x9216697f, 0x8f51ff6c, 0x99aa370b, + 0x2acda31f, 0xd6a36d34, 0xd8475f8d, 0x00c6db0e, + 0xfb5db914, 0xeccd35a5, 0x9de84e78, 0x11c242a3, + 0xae3788e1, 0xc3f11ed6, 0xdb7da54d, 0xf9c24298, + 0x2d1ddec5, 0x180df86c, 0x32fd5b37, 0x82e762ba, + 0x19c464f9, 0x0b746141, 0x7069dd69, 0xd509970c, + 0xdd325119, 0xe6195b0d, 0xf56796e7, 0xa0d7b2c9, + 0xe392698d, 0x3d72adeb, 0x40e9eff3, 0xdf27aa62, + 0xfbe9b1bb, 0x3eaf1333, 0x32d9cba9, 0xa90704aa, + 0x2de9b422, 0x50f4c07c, 0xb63b4b7e, 0xa34313ca, + 0x981dedfd, 0xeab79e01, 0x8900d971, 0x54ecd36d, + 0x09146d31, 0x232c3d8b, 0x724b0f3f, 0x27beaf1b, + 0x6380dce1, 0xf345f0c1, 0xa6cd4fb7, 0x5412699f, + 0x0ebceac3, 0x92a5d843, 0x6c47d876, 0x34db9582, + 0xf0159db3, 0x1e08b349, 0x8858102d, 0x24109519, + 0xbcb7cae4, 0x84cf5852, 0x9e052e13, 0xb81c27bf, + 0xd2750406, 0x5a35b818, 0xfb2c4908, 0xa4972bf0, + 0x89296d16, 0xa7d13b99, 0xd74fa892, 0x1a9de940, + 0xf2f439d9, 0x81eae6cd, 0x964f0918, 0x20c1f8bc, + 0x415977f4, 0x85a775dd, 0xac52244e, 0x8fcc423c, + 0x2d29104d, 0xbc61c01a, 0xf9675ac5, 0x90b773d2, + 0x54d53eea, 0x1a9f081c, 0xa052d353, 0x9813df28, + 0x3b2f5310, 0x0e771c09, 0xf4fedb01, 0x3e8efd60, + 0x278d845d, 0xde7f42ba, 0x2345f3ac, 0xbebef98c, + 0xe8adcba5, 0xdcd1e4ad, 0xf83bc609, 0x9a2fa38f, + 0x2ac6482f, 0xa20cf438, 0x1a56ccc9, 0x79f1ed26, + 0xd16c090c, 0x3c4d43ba, 0x3b2face9, 0x8f2a121a, + 0x23bff2f3, 0xc05f634e, 0x7abcaff3, 0x8f640674, + 0x91c1718a, 0xafed69e8, 0x5045ac4a, 0x1305672c, + 0x50d9e2e3, 0xcc009820, 0xcf623411, 0x383811a7, + 0xc1803f0f, 0x20cee852, 0xa5954ac9, 0x930e486f, + 0xb6381088, 0x8c5f599b, 0x7c36f62d, 0x603132d6, + 0xe79e0289, 0x23e6bbcb, 0xf36d61c5, 0xa188ccb4, + 0x8138aea8, 0xa93c9f62, 0x68450a57, 0xedf82eca, + 0x7e930a05, 0xc368bf51, 0xb92feb10, 0x17f95ccf, + 0x6f15cfea, 0x0c6734c4, 0x7c86850d, 0x01ed6dbd, + 0x1db961a7, 0x50d369c2, 0x81fe1af0, 0x598b6b2a, + 0x42a3a9cf, 0x6e05e662, 0xf5b6a456, 0x2748aeb0, + 0xc4645796, 0x5d9c489b, 0xbd6c830e, 0x1c161f9c, + 0x476deedd, 0x269b3eec, 0xc602402d, 0x4b6fc409, + 0x9f068add, 0xda7e60b9, 0xd8348fcb, 0x73d2b0d1, + 0xa5959497, 0xeef9eca7, 0x4e32cb40, 0xec36b3ec, + 0x4f1b132a, 0x662d5a69, 0xa6a019d6, 0x5c463ceb, + 0x7d41e303, 0x59014126, 0x00fa882c, 0x4b1364b2, + 0xcf0fabda, 0x2b1c9268, 0xb43c1b3f, 0xa684737b, + 0x47f06aac, 0xcb04b166, 0x2af950ee, 0x216d324e, + 0x9a9fbbbe, 0x33a47d17, 0x76f86457, 0xd93c3cd2, + 0x20db26d9, 0xd49946dc, 0x6d95f662, 0x937c535a, + 0x096e0a00, 0x62c05258, 0xe21c3f63, 0xbd267ef9, + 0xc8c98b92, 0xb3e7880a, 0x528d53d3, 0x1d33fd8a, + 0xf94c986f, 0xa8e57165, 0xac413d88, 0x34f19e3b, + 0x50a3d8b7, 0x58fb8676, 0x54769514, 0xbde066cb, + 0x2f764378, 0xea725550, 0x0a8da2f2, 0xca2eb43e, + 0xdb390910, 0x99912ba4, 0x684a13a0, 0xf9dfce0c, + 0x892a9f9a, 0xae224458, 0x18711cf0, 0x65c356ec, + 0x381439ef, 0xd464bd27, 0x35de3dff, 0xaaa4df24, + 0x10d24190, 0x3928a9cc, 0x0c825daa, 0x478c90a3, + 0x5e6e78ca, 0x74f376d9, 0xd956af27, 0x063de8ca, + 0x2f01ee2a, 0x6bc4cf28, 0x3e34901c, 0xd32a57ee, + 0x213685b6, 0x75d5440a, 0x10695179, 0xded4b2b0, + 0x7061436d, 0xbf4ea54e, 0xbd2ddcd5, 0xcfcc7995, + 0xbc811e36, 0xcf6b17a3, 0x2bb295b6, 0xd3c0e8f2, + 0xf8d0f7d6, 0x185a221b, 0x25006d43, 0xffbb6a42, + 0x519c1a07, 0xe1e1024e, 0x5061c863, 0x4b0ba1ea, + 0x5f86a8cb, 0x9a141d40, 0x65ed1bbb, 0x59aaccdc, + 0xc301f198, 0xfc80d362, 0x5a837e5a, 0xe0cfb2e5, + 0xc260a4dd, 0x31eff844, 0xfa7a0250, 0xff916b6a, + 0x532e7112, 0xec3d9fb3, 0x67eadd71, 0x5d035008, + 0x1031f03e, 0x10bc1eb0, 0xa4ffda78, 0x3fc90618, + 0x069d00fd, 0x55e1a1a2, 0x0a989734, 0x5e710bde, + 0x014971ee, 0x4da810b6, 0x81bc117d, 0x4c1ef7ce, + 0x3b1700d3, 0x71384ebd, 0xdd61e7e8, 0x289950f1, + 0xd07180c8, 0xb2e515cc, 0x997acc95, 0x5be0c088, + 0x1d8158dc, 0xf0a69511, 0xb956f917, 0x9b5d5862, + 0x0d6465b6, 0xce06697f, 0xfe1c0e62, 0xa4580f33, + 0x2eeb88b5, 0x681dac6a, 0x9cfc3e9b, 0xa6ac8962, + 0xf3881c23, 0x20e2f490, 0xc2537859, 0xed893623, + 0xf425531f, 0x318333b7, 0x3256ae11, 0xd7a21e7a, + 0x878f5dea, 0x863f99d8, 0x6a0aff4b, 0xad9ef05f, + 0x2e0b2622, 0x328ee279, 0x9d78deba, 0x098fb6b4, + 0xfd55c005, 0x09f38311, 0xaf043a10, 0x5beef91b, + 0x49003cd2, 0x9131085f, 0x6fa720d9, 0x478eba08, + 0x1ebd8a6c, 0x70a5de24, 0xf3381bd1, 0x0cd7e36e, + 0xb8a700a0, 0x2e9c5742, 0x9b09100e, 0x57c7e936, + 0xf9505650, 0x3e0aeb75, 0x48bb9648, 0xdafe191a, + 0x0dcfc0eb, 0x99959593, 0x23215288, 0xd094cb50, + 0xd5e7fbb2, 0xc891856d, 0x9e5939fd, 0xd394ea44, + 0xf9657de6, 0xa2a2775b, 0x9926805d, 0xd8ac5f16, + 0x5c86f714, 0x00d46245, 0x1303e8ea, 0xc98bb0e2, + 0x3417f3ee, 0xe75bfce0, 0xeadd8c71, 0xc17a4930, + 0x5f29da29, 0xe807c6d0, 0xbed5247f, 0xbf731759, + 0xf9787556, 0x3a476c20, 0xd85972b5, 0x1ec03708, + 0xa0690f12, 0x2fc6ed76, 0x014aa07c, 0x3725e608, + 0x31adaeb9, 0x2d1a12bf, 0xc97eed8c, 0xe55bb6f0, + 0xc6e2c259, 0xa09811a2, 0x8dae432c, 0x969602b5, + 0xf389d691, 0x32d9dc61, 0x43758e7b, 0x7c4b2cf6, + 0x97945f6c, 0x59c54e8a, 0x6262fbb0, 0x677b4c79, + 0x7a1f6899, 0x17298ee9, 0x6b0cd48f, 0xe38037cc, + 0x3c210d43, 0xe5239986, 0x15140d7f, 0x6be997b4, + 0x34e54608, 0x896736ef, 0x6f719086, 0x1c946889, + 0x8c02a0a5, 0x530d2d15, 0x76afe26b, 0xbec240c8, + 0x53415252, 0x00000000, 0x0a0507da, 0x000006fa, + 0xc28eb1c2, 0x00000001, 0xffffffff, 0x00000300, + 0x00000330, 0x46363030, 0x37335441, 0x00000000, + 0x0d31346a, 0xeb2ca8ec, 0xc65a3981, 0x28ddcdcc, + 0xf3a8fae5, 0x19d731f5, 0xdf863966, 0x7635b5f2, + 0x36d4f0b2, 0xbe24024e, 0x51f57cda, 0x9241c870, + 0x68895578, 0x74f59766, 0x5fbda11c, 0xb818f7d7, + 0xf35d31b8, 0xe4e576ee, 0xbe1a8a54, 0xe6c59c9c, + 0x54d5b539, 0xdca35f5b, 0x19eba0ec, 0x4fba2f04, + 0x0df76dfc, 0x05d5b057, 0x36784885, 0x5b43e337, + 0x14285276, 0x4561194e, 0x103a82ae, 0x9c7b625a, + 0x9d96b6f3, 0xa4fd5883, 0x20585c48, 0x94c67d0d, + 0x9ce050d2, 0xd0b5165e, 0x63a0bd8e, 0xf9cd1ece, + 0x1584115a, 0x5a662320, 0x63e96e07, 0x7818aac2, + 0x6e71233d, 0x1fd178d4, 0x79f16ec9, 0x82f84202, + 0x39d8be98, 0x15723245, 0x48ce0075, 0x801ead46, + 0x69e8dd35, 0xe5d94c2a, 0x6abb1b97, 0x20762ad6, + 0x5e0df657, 0xf7f9a887, 0x20ffb759, 0xbb52002c, + 0xa488ebeb, 0xac4eb608, 0x2dd6fc64, 0x67763775, + 0x31961884, 0xcd2edeb2, 0x275aed6f, 0x90d87287, + 0x2e0f651a, 0xf14b5cac, 0x6bc86e79, 0xcd5ea86c, + 0x322ae237, 0x7ece1ef2, 0x45abb79e, 0x5a1b6a68, + 0xe3aa633f, 0x9f471388, 0x73ac0258, 0x32ef97ee, + 0xe7a98b7a, 0x3feb205f, 0x5466aca4, 0xbf65921c, + 0x977da54a, 0xeb27e06f, 0x44bd2376, 0x78e9dd9b, + 0x0c426ef0, 0x6ba253ff, 0x1ea0144d, 0x6099a85b, + 0x1f0de3db, 0x15e925f7, 0x1e172b91, 0x8a9d83ab, + 0x0948df11, 0xc4338ceb, 0x3d13d77b, 0xc4ba859e, + 0x601c45a4, 0x2b7a4cfd, 0xd6f42cb0, 0x03827c56, + 0xcbe180ef, 0x8ac33028, 0xdd3a5aea, 0x772c2d5d, + 0x44884fa7, 0xb37de9c0, 0x9e7fba9d, 0x761f99f1, + 0x118f7fcc, 0x7bd6346d, 0xa5c85359, 0xe09d8dae, + 0x6034a867, 0x4af20a35, 0xe213d5b5, 0x83678e65, + 0x7fa12f26, 0x881bf834, 0xd7a898f9, 0x2e00d34d, + 0xadfd0f9f, 0x64f62e57, 0xeb94a4e6, 0x2741735d, + 0xfdd7bf3d, 0x0bb5d428, 0x04c6cf8e, 0x7c91f2e2, + 0x862dafe0, 0xe2bc5ef5, 0x1cf8983f, 0x48fb28fb, + 0xf3725287, 0xfceacf3c, 0x9c97d1b6, 0x244aa0f2, + 0x74cd0c3d, 0x62def4c1, 0x5389a927, 0x9213a193, + 0xfbccaf62, 0xe0c52a28, 0x2f960d1e, 0x261fdc3a, + 0xa4011e50, 0x8cba98a3, 0xc1ee67fd, 0x8bdc9bd1, + 0xd2ba1d9a, 0x2ff19168, 0x2c893f34, 0x465b9763, + 0xac4a2241, 0xdabab40a, 0x848d8ed7, 0x32e0c7db, + 0xe037749b, 0xa806fe6d, 0xfd392283, 0x54c23f8b, + 0xddff2a30, 0xbc3cf4b2, 0xfa60ba33, 0xa9bba869, + 0x0ab138e4, 0xd0a75765, 0x83a03739, 0xed1e0b96, + 0x7b2a9c07, 0x21d68bd2, 0x1c74b719, 0x63eaac88, + 0xea824a44, 0x3f1e946d, 0xaa660153, 0x30d73746, + 0x25019ec8, 0x93a60137, 0xebd12222, 0x2a97f7a8, + 0xca0d18f0, 0x60a7b913, 0xe208502f, 0xf7f99b2e, + 0xa111ffab, 0x17977781, 0xa1d5ac7b, 0xdeb44610, + 0x53415252, 0x00000000, 0x091807da, 0x000006fa, + 0x0bd03d37, 0x00000001, 0xffffffff, 0x00000c10, + 0x00000c40, 0x46363030, 0x36335041, 0x00000000, + 0xa8502cf0, 0x6b8ae36f, 0xcc201a00, 0xf99bd698, + 0xbaa54ce5, 0xd26c6c64, 0x6586a335, 0xdf114ce6, + 0x65768732, 0x0c9fff59, 0xf0c87c99, 0x3cb93d44, + 0x776f6f6a, 0x4cd46553, 0x3b5548de, 0xba94bd6d, + 0xacfdae04, 0x01d0ed9a, 0x2b51dcbb, 0x0e88b2c0, + 0x0a87b9bd, 0x7fdafd01, 0x2b2114a4, 0x094f0a66, + 0xa19ef4ff, 0xf00fc22f, 0x0a791589, 0x14b0605b, + 0x65c880ce, 0x98a25bd3, 0xc46bcf0f, 0x23b28754, + 0x9d5b0d0a, 0xc7b95ff1, 0x4b559af5, 0x2c972fb7, + 0x24c7393a, 0x50953092, 0xcdfbb400, 0xd8b74e66, + 0x167c8540, 0xe5f33cf3, 0x6f06bece, 0x67853c91, + 0xec256024, 0x4321a8d7, 0xdf8db159, 0xb3c4ea19, + 0x49c55dbb, 0x6cd0893f, 0x24926b88, 0x8b6d8c1e, + 0xcbc1ca74, 0x0d97abf7, 0xbd0683e5, 0xfbd070ae, + 0x2d86f2ba, 0xdf2d5df1, 0x1c94ac1d, 0xce105cc6, + 0x707d966a, 0x425adf11, 0xd5437db4, 0x9439e46c, + 0xf491c327, 0xa264301e, 0x74f59c4c, 0x4fd8cd7d, + 0x4d2ee13b, 0xeedc9b07, 0xb48c496e, 0x0a9a158b, + 0xe2aa1f80, 0xe56e1be4, 0x601147a5, 0x9e8e1a67, + 0xe311dea5, 0x0e787f57, 0xe6d48d91, 0xfc5efa36, + 0x8d740ced, 0x626aa6ec, 0xfa47f6c6, 0x78236dbc, + 0xac414eda, 0xbe9b7c3f, 0x922aa24c, 0xe824c36b, + 0x4bf0a6ea, 0x4650f510, 0xe14ea433, 0x8a863587, + 0x99f2e00c, 0xace2241e, 0x673a6a21, 0xeacd0611, + 0x1d5d9f26, 0x63542bdc, 0x19769443, 0x83fb04f6, + 0xd2dba174, 0x41fc8e8e, 0xb753a248, 0xbe7f5d53, + 0x97bd16c8, 0xb6e3ea74, 0x10a04714, 0x678ba0fe, + 0x41903bb6, 0xdc3f69f5, 0x69c0e20e, 0xa3857a0e, + 0xa66aec62, 0x4f1129d4, 0x39bf5e5c, 0x6566814d, + 0x6ebc5d8d, 0x74fab02e, 0x6ce9ff42, 0x20dd4b0d, + 0x89a915bc, 0xdb86b288, 0xe6a2f5c0, 0xd26fa8d8, + 0x8ce2b6ef, 0xb38cb16c, 0x7e187321, 0xe9057cf7, + 0xfeff6963, 0xafcbd93d, 0x1ac7600e, 0xf953ad97, + 0xdd8daaa5, 0x24ffd3a3, 0x6a87f2e0, 0xa5a876ae, + 0xbe7ec94d, 0x630e9bdd, 0x14cf97ff, 0x0ad023f8, + 0xafc7d6b6, 0x01d9c914, 0xcaa89ce8, 0xb87471ee, + 0xf7a6722f, 0x37e1c449, 0x16efc69c, 0x6b5fd873, + 0x0cb4dbf5, 0xd7e3e2fc, 0x1b980086, 0x3fcc2b9b, + 0xef724017, 0x6ab5078a, 0x9c469135, 0xda49a6d8, + 0x94bd4cd4, 0x5ee98e66, 0x4bb9cd31, 0x96bb17de, + 0x3796eef6, 0x0a0cdc6f, 0x5855dd79, 0x21f4df2a, + 0x70fcf480, 0x1e408673, 0x2c9a1e7c, 0xd8281ab2, + 0xd2251523, 0xc207118f, 0xb520e691, 0xf7be5cd0, + 0xae7af3ad, 0xd8bd2853, 0xed06f5e7, 0x70e4318d, + 0xd949fff5, 0x84a7dca6, 0x54116bcb, 0xe38fab7c, + 0x41f88f1a, 0x148f2a61, 0x6598203c, 0xf3df679c, + 0xa47d2d48, 0x6ebd84aa, 0xca409338, 0x5ea735c7, + 0x8f5902a3, 0x486b9a72, 0x2a6c9f7a, 0x4f58af16, + 0x8e589cbd, 0x847b026e, 0xeb883553, 0x9bd04361, + 0xdf75294b, 0x5701b848, 0x8e4c290e, 0x84ae09a2, + 0x7c2e5310, 0x1f1e3351, 0x57464eba, 0x2f2bd882, + 0x55312151, 0xd699d4a8, 0x86c0cb2a, 0xc18625d5, + 0x01e34f5f, 0xdd71a9b5, 0x00d1404c, 0x478a8fdd, + 0xaca315cd, 0x08c2bb61, 0xe1e95f74, 0x5c0f2e74, + 0xc5b86ecd, 0x5efba52e, 0x27162c32, 0x2cd364e0, + 0x7c2ff4dd, 0x20afee39, 0x01f06c32, 0x5705321c, + 0x721e9a19, 0x0406919f, 0x793ddfdb, 0x34ad2684, + 0xb870a1c0, 0x12723655, 0x8f3a0553, 0x1eb77d55, + 0x31777ded, 0x80d06c75, 0x9e0f8431, 0x289bd541, + 0x742e6c03, 0xd9d32028, 0xb7891977, 0xaddc8f96, + 0x1815c705, 0x7c50fb3f, 0x72e1a6d5, 0x58a49102, + 0x94734a5a, 0xf1431853, 0xcb403be0, 0x80ff034c, + 0x1cca1d4c, 0xa451b20a, 0xcfff97a1, 0x6897d11a, + 0x153fe0f9, 0x6747b5df, 0x3a88bcef, 0x6648176b, + 0x7986c1d7, 0x3f2d7a08, 0x8ea0db0e, 0xf0f57877, + 0x0ed1edbf, 0x95158803, 0x0425f867, 0x79237bc3, + 0x28ce7bcc, 0x60f311a5, 0xc7ba09fb, 0x55596285, + 0xc724ebe4, 0xeac78d31, 0x3e6c778e, 0x05252503, + 0x3dcdcb51, 0x78c59d5c, 0xa3dee354, 0x52b19d1a, + 0xfca398b0, 0x63f65f9d, 0xc9fc4fa4, 0xd35ebec9, + 0xa3698241, 0x05d0e962, 0xf7526d10, 0x7777b4e4, + 0x72482300, 0x96d42113, 0xce18adb9, 0x0f6fae9b, + 0xbd737b23, 0x2f327586, 0x456e2db2, 0xe8bacf5c, + 0xa3333916, 0xb1045776, 0xe831b66b, 0x28c002f1, + 0x6907e87b, 0xd44c8009, 0xb8bfbd22, 0x5f11a712, + 0xb99ed38c, 0xf14ef1bf, 0xa50cffec, 0x3ac7cc61, + 0x967864d6, 0x0f4dd3f2, 0x9a52c6e0, 0x4622af4c, + 0x8c5fe79d, 0x1f5aaf51, 0xb379d3fc, 0x06f5485c, + 0xb46f53fc, 0xfb7b867e, 0x4fd79268, 0xb426ba21, + 0x3bd32579, 0xeccf15e1, 0xdbf2585f, 0x38dc054a, + 0xf66e29ce, 0x93d218ef, 0x38a61bee, 0x5d764b3b, + 0x698c1bee, 0xd1f1dcca, 0xcb4d774f, 0x7ae6113e, + 0xbc46ab5d, 0x7cea59f7, 0xef726f3c, 0x86e552c8, + 0x54b5c263, 0xbb9f213c, 0xb0ec7aee, 0xae412550, + 0x7d672e4c, 0x479482d1, 0xbe984fd4, 0xbb40b4e9, + 0xce460f5b, 0xc25d2d8e, 0x14d43871, 0xc622459e, + 0xd25cdf24, 0x4cfc08fe, 0x6e66c76d, 0x6163f5e5, + 0x590ef352, 0x38dd5eee, 0x5b56b3c0, 0xbf7a708f, + 0xd11ce5b9, 0x46fe1639, 0x87e53fae, 0x52b6d358, + 0x32d6eb0b, 0x2c8d0693, 0x7b823fba, 0x1743a83d, + 0x89ec17f7, 0x74679c91, 0x14768344, 0xf27ab26f, + 0xcafbebd7, 0xb996128f, 0xef5940d8, 0xf3d2817c, + 0xbfa77515, 0x223a22a1, 0xc301ff17, 0xfb63edb7, + 0x4d0b235a, 0x9dbd7318, 0xf165ef57, 0x872805e4, + 0x78fbcb1b, 0x8715e546, 0x909b519b, 0x073ebe68, + 0x520c18f5, 0x75d543ef, 0xfffd247f, 0xc51faa72, + 0xc3ff9c28, 0x05d95767, 0xf8a8ce29, 0x6c3100df, + 0x9602b7b5, 0xf1df9514, 0xdfbde49a, 0x63f347c3, + 0xa3fedee4, 0x5ab74220, 0x9e3ab0fb, 0x6024aa18, + 0x941b54f2, 0xaf740c6b, 0x07278738, 0xdc9f9f70, + 0x528d7eb4, 0xb78b4da4, 0x7e0859ca, 0x4d7f2f34, + 0x4cce084c, 0x1e1eaa38, 0xe237324d, 0x096f11bc, + 0x8b040823, 0x2a1c921a, 0x13df560f, 0x8d6f9621, + 0x34ed0c9c, 0x8f52c968, 0x8c079396, 0x5c2d78c5, + 0xba61f0ba, 0x0d6737a7, 0xc7ac90b5, 0x40711497, + 0xc610777e, 0x1baf3ab6, 0x2a509778, 0xb64267ae, + 0xf0292472, 0x316c99d9, 0x2773d52f, 0x31de412b, + 0x7d7c33d9, 0x5418cbd7, 0x779a60f5, 0x2b6635a1, + 0x4a7480ad, 0xa91700ed, 0xdd719d72, 0xf4ef7bfa, + 0xf292f4a7, 0xe20a154c, 0x6980673e, 0xd087d272, + 0x3f62947c, 0xcf82e629, 0x998f72d1, 0x181537ec, + 0xec99111e, 0x9ff94a7e, 0x5838ed56, 0x652e00ad, + 0x63d2e127, 0x291b39ed, 0xe8874f1f, 0x9fcea857, + 0x4b44e4d7, 0x79facf6b, 0xfa97248d, 0xabf1b436, + 0x44bf8ca3, 0xa2342483, 0x27b39aae, 0x54ad61e8, + 0x62aaf9c8, 0xcf1f0e5f, 0x57727cb9, 0x2bbe1a27, + 0xad813e18, 0xade7e54a, 0x6d9ae354, 0x7dda6e41, + 0x6b503615, 0xe539a489, 0xacd4cf0c, 0x50b5ee9b, + 0xe12cd634, 0xdaa2358a, 0xf3ed5c3c, 0xd7bf1749, + 0xc8953072, 0x8e5cebe6, 0xa89070ea, 0xb8978ab1, + 0x9bb10556, 0x14552e00, 0x5e3254e6, 0x3749eeca, + 0xdafe140d, 0xe7ed3e04, 0x5bed7ee9, 0xf9f2b6d0, + 0x78958f75, 0xe5e5677a, 0x6bd77819, 0x802ca29a, + 0x90bbda35, 0x1ed94bcc, 0x04d5fd91, 0xb23898df, + 0xef508485, 0xc2db56db, 0x335a3555, 0xafd667b7, + 0x2e41b466, 0xd17eb896, 0x98ba5a85, 0x7205a0cd, + 0xa89f5fe5, 0xbc8082bf, 0x0ea9336d, 0xd5f7695f, + 0x3df7ae79, 0x0c16a95b, 0x872eca3f, 0x6565c3c6, + 0xa7c70d84, 0x5a9cfc9d, 0xf9d365e1, 0x83b41c41, + 0xa361972f, 0xcedd50d9, 0x0dd0ffaf, 0x33beb660, + 0x6e5f8aae, 0x39d89272, 0x59a2dd37, 0x46b32dd6, + 0x23d1b438, 0xaed8f126, 0xf56c2494, 0x1be3e72a, + 0x49559bde, 0x651f3b68, 0xa77ee774, 0xf6ee86d2, + 0xd6958a8b, 0x12ba080f, 0xce76bd3b, 0xafad53b0, + 0xe5fb067a, 0x4f4b6149, 0x54215017, 0xad0378e2, + 0x482d9f3f, 0xfb953d72, 0xd078f21d, 0x8b91bcd0, + 0xd5eff898, 0x2d47c13a, 0xfc918304, 0x6569bbdd, + 0xdfccdc07, 0x3f6c1171, 0x0aa3e691, 0x22b945c6, + 0x123c08b9, 0x3c61ad47, 0xf3684a46, 0x6ddf05df, + 0x45587657, 0x65d93c69, 0x3028c52a, 0x0f0bc6f9, + 0x9686fdc6, 0x50c758fe, 0x4fb30ed1, 0xfbc1e704, + 0xfdb31f63, 0x593a7512, 0x316393b2, 0xc9f4832b, + 0x4f1a5a37, 0xb1b47d4d, 0x5fcc8ccd, 0xe8069867, + 0x0e3709c9, 0x09e4cb6d, 0x7a5db9a9, 0x64a714d4, + 0xbec5c79a, 0x16bea0a5, 0x81666c3d, 0x35f96dea, + 0x9b6405f0, 0x3ad8a387, 0x8672e95e, 0xf6b43b37, + 0x8c2a03e8, 0x454073e1, 0x2dcec42d, 0xf78c7e73, + 0x082676e2, 0x0350e3fb, 0xd8221bde, 0x825a4d19, + 0xb9fa4b07, 0xb107ffac, 0x2a4b6eea, 0x3e642e4b, + 0xa7585a91, 0x84610e89, 0x63238347, 0xbbc51fd3, + 0xfe022393, 0x5ca78d29, 0x817b9406, 0x4e56ceb6, + 0x41675640, 0x2e7ce351, 0x97409f25, 0xf723c6ec, + 0x0392c2de, 0xd6a28f3a, 0x78de0130, 0xae0a3790, + 0xee61980d, 0x7f1bb7b8, 0x1e09abde, 0x978c8936, + 0x3f389b96, 0xec790b39, 0xf822a35b, 0x8a1d3592, + 0xdebdb41d, 0x133b9d1a, 0x5883447b, 0xbcf8bb09, + 0x8fe79675, 0xaa8f1d7b, 0xd017c7b7, 0xcd06e94f, + 0x8755fc1a, 0xffaa89fa, 0x29be8e81, 0x6fcf52a5, + 0x55725694, 0x02573e0b, 0x233e87cc, 0x4ef6c107, + 0x6f903aec, 0xe71d60d1, 0xa043f83c, 0xe5899344, + 0x40d5ea27, 0xde3a6bd4, 0x22cffa9b, 0xb70a3a9d, + 0xee1e1fc1, 0x9f304bcf, 0x9a00125e, 0x4fdce973, + 0x81cfc376, 0xba14685c, 0x1307212d, 0x9d3cb67c, + 0xcf5174a2, 0xce2df038, 0x3d98a9bb, 0x1e4e0289, + 0x70370e7a, 0xab7f5a12, 0xd9a73509, 0x84073ecd, + 0x1640aed1, 0xb129a7e9, 0xfd8d50b7, 0xaa97ef05, + 0xa398d289, 0x3d0445b0, 0x2a063516, 0x0ac49d0e, + 0x273b8e5e, 0xad1c3b0a, 0x59c61b56, 0xdf16f4b2, + 0x55710d7c, 0x4f8a9a78, 0xe9a3e9cc, 0x96c33642, + 0xc1711c0b, 0x453e85a7, 0x36cb0791, 0xd052b65f, + 0xd9745f46, 0x720f96c6, 0x112e753a, 0x8e487589, + 0x040c3d65, 0x1c642c49, 0x59cebaef, 0x3c44c71d, + 0x416fe930, 0xa2092f52, 0x8b89f343, 0xf44f9656, + 0x2fe20f9e, 0xbc5acf24, 0x43238ee6, 0x247a5997, + 0x2f0e3771, 0xc03e76d9, 0xdef328ee, 0xed802543, + 0x2a32c194, 0x4cd92940, 0x3d9eccbc, 0x9fb7ac0e, + 0x23e4acff, 0x0f6ef7cd, 0xdfb588d0, 0x2aa0b794, + 0x7a5d022a, 0x4356c9b3, 0x97281179, 0x41337e53, + 0x76790819, 0xb9a5ca77, 0xaf1a9b2a, 0x1a655dfb, + 0x6b106bc8, 0xee6fcab5, 0xe16c7aac, 0x45cb5be6, + 0x280d9a95, 0xf2ddc81b, 0x9e1f01e0, 0x1148cf1d, + 0xf483fc39, 0x3a66021c, 0x1057a22c, 0xa0685244, + 0x1e8a55bc, 0x0390fe02, 0x76c29392, 0x53c53e08, + 0xa733d7a2, 0xcb877f82, 0x4fd82ea5, 0x53cb96f3, + 0x4547075d, 0x41c477e8, 0xb0912c69, 0x57ed6e48, + 0x3e743d6c, 0x882451c7, 0xc868cedd, 0xb3fae605, + 0xd81848cb, 0xf3b16ab0, 0x5f3c7494, 0x4fca84d3, + 0x621cafcb, 0xa7225d72, 0x83596120, 0xc8f57258, + 0x5b443741, 0x0858ebb9, 0xa7392619, 0x26c71263, + 0xdfac85c7, 0x95929d75, 0x2a082fe4, 0xb91c4054, + 0x2b1a13b2, 0x717e3a2c, 0xfe2165ed, 0x1c5b1653, + 0x9ab498cd, 0x3b3d437a, 0xe9c737d3, 0xfd071595, + 0x638c4625, 0x997ec96b, 0xa4b0d070, 0xe459568c, + 0x53415252, 0x00000000, 0x091807da, 0x000006fa, + 0xd43a9824, 0x00000001, 0xffffffff, 0x00000940, + 0x00000970, 0x46363030, 0x36335041, 0x00000000, + 0x302b7fb9, 0x51c322f3, 0x1481e6b5, 0x9950f1a5, + 0x27048310, 0xb3895c51, 0x5a93c4a9, 0xeb6c4601, + 0x95b0f2ff, 0x99ff6dc9, 0x83843695, 0xb687e255, + 0xa3efa9f1, 0x23d98810, 0x846ac2d3, 0x1c9d6010, + 0x6715bfdc, 0xa789fab9, 0xe56a1d09, 0x0eeb0427, + 0x9ed0a3a7, 0x45ec7559, 0x0c2eb033, 0x17f146dc, + 0x30c35795, 0x37a56765, 0x66b11205, 0x5471a208, + 0x5a0049b8, 0xc008aca5, 0x29ee84fb, 0x66e3303d, + 0x101656d6, 0x2e7de920, 0x673cabfd, 0xf05d1c06, + 0x64c507f6, 0xd823cbe0, 0x7e7f4183, 0x04cad122, + 0x747e3ba9, 0x3226c602, 0x7dc01760, 0xce634320, + 0x84f55355, 0x1c411f23, 0x6972e335, 0x06f74042, + 0xa8006f71, 0xfeed7d7e, 0x3f09abbf, 0x6a1a8c7f, + 0x0d1b730c, 0x5c73a586, 0x9d73ed26, 0xe43c786a, + 0x1da597e3, 0x34c8f323, 0x447d5fb3, 0x9976957d, + 0x2c5df47b, 0xf19a1bc3, 0xe53b3cbe, 0xf0a8e170, + 0x11f0f112, 0x60e00900, 0xc4014477, 0xcbbda9cf, + 0x478c7d43, 0x0c76da66, 0x54f59535, 0x3a310af5, + 0x81a2e87b, 0xae577790, 0xc610b904, 0xaa7afec7, + 0x0ba491df, 0xc44ac7ea, 0x055551b0, 0x967834ff, + 0x46075ceb, 0x3f0d8a90, 0x6336f1f4, 0x638e85be, + 0xdbc8df61, 0x0112c46c, 0x94aa12ed, 0xe1814406, + 0xcb48defa, 0x4c5543ca, 0x756f2306, 0xd7a66dd7, + 0x48262543, 0xece84d6d, 0x6addde77, 0x8e5045a5, + 0x94761706, 0x2a8f98ff, 0x14898b09, 0xc5111544, + 0x60c93fc7, 0x6bea5ad2, 0x81282ca0, 0xe34f2730, + 0x9013ce09, 0xebe061d9, 0x975eb536, 0xadcd9034, + 0x257fc5a9, 0xffc3bd52, 0x1eadf9ba, 0x0bd81a5c, + 0xea0c52f9, 0x8347a620, 0x78663976, 0xccaa6aec, + 0x2bd641d4, 0xc3dcc4dc, 0x55e5296d, 0x9e94bfe1, + 0x746c3a01, 0x99f0dcea, 0xf52657aa, 0x3622ceb3, + 0xa95f8c65, 0x8eaaee04, 0xd71aea04, 0xfcfd6e78, + 0x7984686c, 0xe40a8dbf, 0xf50ee2e9, 0x93eb96c1, + 0xe834ee5b, 0x5d05b60b, 0x20c10cea, 0x0a8c2645, + 0x155a6187, 0xde1aedae, 0x7204cf15, 0xe85373e4, + 0xe9f93d4a, 0xc7531d3a, 0x5c535875, 0x46ec1ae6, + 0x6aeea9bd, 0x871bb354, 0x1ab2be63, 0xf8dad26c, + 0x7b04e772, 0x48564a81, 0x742d28ba, 0x6e698de4, + 0xa0779db3, 0x1ce0c3d7, 0x237cb6b0, 0xf286fe37, + 0x781af9aa, 0xf4d61b0b, 0xe26b7572, 0x51f38cb3, + 0x604873cb, 0x693a158f, 0xb2a0b427, 0xa6cf762b, + 0xe91831d4, 0x0376bf4b, 0x0ea5b667, 0x830b103e, + 0x25a8dd84, 0x21e82db9, 0x6d4c0e5e, 0xfb767d16, + 0x4b883e4b, 0x3de33b14, 0xc9490454, 0x33d61eb4, + 0xd0197448, 0x940e34a4, 0x8c48a3b1, 0x3456c76f, + 0x92535ef7, 0x95328e66, 0x8882cce2, 0xce2b761b, + 0x729cf0e7, 0xa892dd65, 0x804de33d, 0x1549715e, + 0x8c819f7a, 0x982d9d26, 0x05314c31, 0x2ea19906, + 0xf48db2da, 0xd1b20b93, 0x2bbaea99, 0x4289b538, + 0x1352afb3, 0x15aa3a0a, 0x3b80f3f5, 0xc1a1719c, + 0x132c9711, 0x46fd6ca8, 0x771b91c5, 0x09414702, + 0x9a9fb8d6, 0xff2bc606, 0xb6214f8a, 0x74dacacf, + 0x513c4dd5, 0x137fa66c, 0x503d5d37, 0xe024c0da, + 0x793e186f, 0x31c2bf95, 0x320c616a, 0x83719c1d, + 0xde0d6e00, 0x9409b2a0, 0xe213fae2, 0x21731821, + 0x83f51eb3, 0x3cb2eab5, 0xd9c401d3, 0x8d5379ac, + 0x624189bb, 0x5233e883, 0x1f3d0c02, 0x3b46edc3, + 0xb47d4661, 0xff867384, 0xf4daa252, 0xfc55fa25, + 0xb465352e, 0xe1ff2a20, 0x438427df, 0x8cd561f1, + 0x8c2debb1, 0xf89d5e68, 0x74015f75, 0xa5ea69fa, + 0x0197a406, 0xbc60439a, 0x32244a3c, 0x4c0b5007, + 0x61d1138d, 0x024a59f1, 0x305fe9cc, 0x724833dc, + 0xcbae0bea, 0x8de58519, 0x62968adc, 0xadd0011c, + 0xc5b23595, 0x5b3990c9, 0xd3c64ecc, 0xb5d33759, + 0x054c797b, 0xc172220c, 0xda29fe07, 0x7f450ebf, + 0xec12a33e, 0x86d9bbb3, 0x78bffba7, 0x6a183c16, + 0x3cdb717b, 0x601e0c7f, 0xcf945c26, 0x073e7331, + 0xdebd7ad0, 0x62879d5c, 0xe0273347, 0xa2ff18e4, + 0x78a14f44, 0x20728f07, 0x25cfa3d5, 0xd699e2a7, + 0xc729bf4e, 0x9250bd92, 0xbabf3a88, 0xf69d91ac, + 0x0de005b2, 0xee6c6551, 0xf3ec51af, 0x0d4ab84f, + 0x85b7f548, 0xa0dcf7ae, 0x55efb6a5, 0xbcc9fdb5, + 0xe789546e, 0x8a209948, 0xb49fc3dd, 0x945fd8f7, + 0x9c2ab04e, 0x17625832, 0x18253aab, 0x26e3b5fe, + 0xd03ebf0d, 0xe5f8b8e4, 0xcdf3ef2f, 0x4024ca62, + 0xd3436616, 0xd19b1010, 0x7e53746c, 0xbaea2597, + 0xdd72726c, 0xb5a6a4c4, 0x348efd94, 0xba4d3a94, + 0x3d736b7c, 0xd32fd9e8, 0x98624886, 0xeaab1e7d, + 0xeec8edc6, 0x51dacdff, 0xf7359960, 0x221caa31, + 0x34fb3350, 0x794d034c, 0x6aef3d76, 0xc925c505, + 0xf752c1ad, 0x04b61fde, 0x7b42ef68, 0x1a119091, + 0xe21077a2, 0xc0c21dfb, 0x480cee09, 0x70144e31, + 0x49d345b9, 0xb3fe6f47, 0x11d12867, 0xe99898c6, + 0x6e54b4fd, 0x5f8d169c, 0x93e707b9, 0x1a90974c, + 0xd6a685e4, 0x6c20c321, 0x29f12f73, 0x12e54190, + 0x04de2470, 0x6dbb24bb, 0x7f0fd71c, 0xd5e2c954, + 0x7d93c73a, 0xd2a2c48d, 0x61e2db8d, 0x1a192d47, + 0xc2d8d438, 0x5e779066, 0xc4bcc619, 0x06f872ef, + 0xf3401439, 0x573ebd1b, 0x61896e22, 0xde431aef, + 0xbad386d8, 0xf54ca23b, 0x57d8016f, 0xd98e33ac, + 0xc5f29f61, 0x85217cb1, 0x250a23ef, 0x16c2d7ce, + 0x8b8b0207, 0xaeaf1661, 0x8c645ab3, 0x10692f9a, + 0x84845cb2, 0x3809ed87, 0x958b72cf, 0xfdc465f9, + 0x167924f4, 0x79b72fd3, 0xd53e01b8, 0x878c0bc7, + 0x444d821d, 0xb2329171, 0x68dae31b, 0x6dd25eb0, + 0x876262cc, 0x600fcaf3, 0xa26397e5, 0xab3b5cd5, + 0x11f6df26, 0x3b503f54, 0xfd28517b, 0xac2c6723, + 0xf189feec, 0x6c0eabe7, 0xc3b57dd3, 0x9383ffbc, + 0xaff39d18, 0x4dae936e, 0x8806e540, 0xd956dfe9, + 0x7726c523, 0xe20d141f, 0x75249f0c, 0x641c7ecf, + 0x4d75cad2, 0x5e2097c6, 0xffdba551, 0xf97adab1, + 0x8d86a099, 0x4ce7dafa, 0xc4bf244c, 0xbd5ab78b, + 0x9060c834, 0x4f0533da, 0xeee0c724, 0x39963d31, + 0xcde4a77c, 0xf2222170, 0x00675c98, 0x72b6807a, + 0xfceec299, 0xb4bfd75f, 0x82385beb, 0x8a4fa5e6, + 0x1f4d790b, 0x8cb998f6, 0x5e41077c, 0xbdb77edc, + 0x5b885781, 0xdcd539a0, 0x50f70de2, 0xf72c206e, + 0xd47a8c39, 0xc8c84742, 0x4f5e1cde, 0x8ec26342, + 0x45add698, 0xc0bd2b6d, 0x10096f65, 0xc7e30310, + 0x1c951782, 0x37b5edea, 0xe10aea7f, 0xf40d763c, + 0x01a93a40, 0x197d0a4b, 0x3d41eed5, 0xe9beb9d6, + 0x1d9247a4, 0xeafe224c, 0x2f2578d5, 0x45eb10a4, + 0xb6b22e2b, 0xef55f252, 0xb4e224e4, 0x067dcb26, + 0xb6d0b2a3, 0xfd8a0221, 0x049bbf33, 0x70752994, + 0xf75fd79b, 0x34fcb9d9, 0x90ca2832, 0xf1c767ca, + 0x387d06cd, 0x9d5bfdfc, 0x45fb1391, 0xffbf1a8f, + 0xa7713b73, 0x04b45260, 0x41f7aadf, 0x4e9ab87d, + 0x26cfd8fc, 0x4ae2842a, 0x00b21491, 0x8e41fff9, + 0x931d987b, 0x1780ad94, 0x74d9d450, 0x6b4e7b86, + 0xd290203b, 0x2677caa9, 0x962f8e81, 0x2ed26089, + 0x14e26f42, 0xeb70b144, 0xa095d8c1, 0x6b572c29, + 0x78fbacf2, 0x5cdc5cfb, 0xfae86706, 0xddda5706, + 0xaa767744, 0x7493a4a2, 0x0e9f6b3f, 0x9806a4df, + 0x10e4c5d5, 0x9b49682a, 0xcb1d045c, 0x0b93aa0f, + 0x9204696b, 0x82d18f87, 0x1551957c, 0x5410f2ed, + 0xb937ab2e, 0xaaf40b54, 0x2b9d4857, 0x50231070, + 0x49ee3994, 0xceaa9dbb, 0x9bd8c899, 0xe9605a77, + 0xfd88758b, 0x6464201d, 0xa0605f2c, 0xc54d1473, + 0x30f678bd, 0xe07ade92, 0x315e83b4, 0x9f0e9866, + 0x6861b81f, 0xe3dbc8c2, 0xd67d8c2d, 0x27ffa228, + 0x25727f2b, 0xc6637d9b, 0x455637b4, 0x5aabdb00, + 0xb74a792c, 0x5bc1a7a8, 0xcbb106d8, 0xd7088b31, + 0xefec63ed, 0x5fcb7619, 0x79b5006e, 0x46de8644, + 0xdc61db98, 0x7701dca1, 0x1a9622f6, 0x6d192615, + 0xc380d47a, 0x10685fa3, 0x1f7fc304, 0x06d3796a, + 0x345013f3, 0x4c2db462, 0xddab6807, 0xf2525b65, + 0x086d312b, 0x62df52a6, 0x0903ce35, 0xf526c030, + 0x58ad7ac0, 0xf188c61f, 0x09869aa0, 0x76ae266b, + 0xe352afc2, 0xa5f2f582, 0x5ec4d829, 0x78fbae90, + 0xfb64e6ea, 0x96f43d96, 0x735098d0, 0x45006937, + 0xb8c64d9d, 0xdc1eacc8, 0x48674e13, 0x809f1e57, + 0x3481a112, 0xe97aa223, 0xd9609801, 0x120265b2, + 0x12211b6f, 0x7a930f99, 0x10d1fa9b, 0x69413983, + 0x72c88496, 0xf6bd37de, 0x397c05bf, 0x69cf3d17, + 0x2472b3e5, 0x6534bde0, 0x175c0e03, 0xfd31a289, + 0xe4d5d467, 0x933c0637, 0x14547ff0, 0x63dddc17, + 0x734f0426, 0x1b7d4414, 0x1d61e181, 0xa9bb645b, + 0xe33daddd, 0x0f3fd487, 0xb36f4aef, 0x042e3609 +}; diff --git a/src/include/lib.h b/src/include/lib.h index 1f71d35..2f27149 100644 --- a/src/include/lib.h +++ b/src/include/lib.h @@ -37,6 +37,7 @@ void move_gdt(void); /* Defined in src/lib/ramtest.c */ void ram_check(unsigned long start, unsigned long stop); int ram_check_nodie(unsigned long start, unsigned long stop); +int ram_check_noprint_nodie(unsigned long start, unsigned long stop); void quick_ram_check(void); /* Defined in src/lib/stack.c */ diff --git a/src/lib/ramtest.c b/src/lib/ramtest.c index 3457210..192d573 100644 --- a/src/lib/ramtest.c +++ b/src/lib/ramtest.c @@ -223,6 +223,41 @@ int ram_check_nodie(unsigned long start, unsigned long stop) return ret; } +int ram_check_noprint_nodie(unsigned long start, unsigned long stop) +{ + unsigned long addr, value, value2; + unsigned short int idx; + unsigned char failed, failures; + uint8_t verbose = 0; + + for (idx=0; idx<0x400; idx+=4) { + test_pattern(idx, &addr, &value); + write_phys(start + addr, value); + } + + /* Make sure we don't read before we wrote */ + phys_memory_barrier(); + + failures = 0; + for (idx=0; idx<0x400; idx+=4) { + test_pattern(idx, &addr, &value); + value2 = read_phys(start + addr); + + failed = (value2 != value); + failures |= failed; + if (failed && !verbose) { + } + if (verbose) { + } + } + if (failures) { + return 1; + } + else { + } + return 0; +} + void quick_ram_check(void) { int fail = 0; diff --git a/src/mainboard/via/Kconfig b/src/mainboard/via/Kconfig index 6980548..48f4055 100644 --- a/src/mainboard/via/Kconfig +++ b/src/mainboard/via/Kconfig @@ -9,6 +9,8 @@ config BOARD_VIA_EPIA_CN bool "EPIA-CN" config BOARD_VIA_EPIA_M700 bool "EPIA-M700" +config BOARD_VIA_EPIA_M850 + bool "EPIA-M850" config BOARD_VIA_EPIA_M bool "EPIA-M" config BOARD_VIA_EPIA_N @@ -23,6 +25,7 @@ endchoice source "src/mainboard/via/epia/Kconfig" source "src/mainboard/via/epia-cn/Kconfig" source "src/mainboard/via/epia-m700/Kconfig" +source "src/mainboard/via/epia-m850/Kconfig" source "src/mainboard/via/epia-m/Kconfig" source "src/mainboard/via/epia-n/Kconfig" source "src/mainboard/via/pc2500e/Kconfig" diff --git a/src/mainboard/via/epia-m850/Kconfig b/src/mainboard/via/epia-m850/Kconfig new file mode 100644 index 0000000..6c840a6 --- /dev/null +++ b/src/mainboard/via/epia-m850/Kconfig @@ -0,0 +1,50 @@ +## +## This file is part of the coreboot project. +## +## Copyright (C) 2011-2012 Alexandru Gagniuc <mr.nuke.me(a)gmail.com> +## +## This program is free software: you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation, either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program. If not, see <http://www.gnu.org/licenses/>. +## + +if BOARD_VIA_EPIA_M850 + +config BOARD_SPECIFIC_OPTIONS # dummy + def_bool y + select ARCH_X86 + select CPU_VIA_NANO + select NORTHBRIDGE_VIA_VX900 + select SUPERIO_FINTEK_F81865F + select HAVE_PIRQ_TABLE + select PIRQ_ROUTE + select HAVE_MP_TABLE + #select HAVE_OPTION_TABLE + #select HAVE_ACPI_TABLES + #select HAVE_ACPI_RESUME + #select BOARD_HAS_FADT + select BOARD_ROMSIZE_KB_512 + select DRIVERS_GENERIC_IOAPIC + +config MAINBOARD_DIR + string + default via/epia-m850 + +config MAINBOARD_PART_NUMBER + string + default "EPIA-M850" + +config IRQ_SLOT_COUNT + int + default 13 + +endif # BOARD_VIA_EPIA_M850 diff --git a/src/mainboard/via/epia-m850/Makefile.inc b/src/mainboard/via/epia-m850/Makefile.inc new file mode 100644 index 0000000..9c6d31f --- /dev/null +++ b/src/mainboard/via/epia-m850/Makefile.inc @@ -0,0 +1,21 @@ +## +## This file is part of the coreboot project. +## +## Copyright (C) 2011 Alexandru Gagniuc <mr.nuke.me(a)gmail.com> +## +## This program is free software: you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation, either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program. If not, see <http://www.gnu.org/licenses/>. +## + +#romstage-y += ./../../../superio/fintek/f81865f/f81865f_early_serial.c + diff --git a/src/mainboard/via/epia-m850/devicetree.cb b/src/mainboard/via/epia-m850/devicetree.cb new file mode 100644 index 0000000..3ee56b4 --- /dev/null +++ b/src/mainboard/via/epia-m850/devicetree.cb @@ -0,0 +1,111 @@ +## +## This file is part of the coreboot project. +## +## Copyright (C) 2011 Alexandru Gagniuc <mr.nuke.me(a)gmail.com> +## +## This program is free software: you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation, either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program. If not, see <http://www.gnu.org/licenses/>. +## + +chip northbridge/via/vx900 # Northbridge + register "assign_pex_to_dp" = "0" + register "pcie_port1_2_lane_wide" = "1" + register "ext_int_route_to_pirq" = "'H'" + + device cpu_cluster 0 on # APIC cluster + chip cpu/via/nano # VIA NANO + device lapic 0 on end # APIC + end + end + device domain 0 on + device pci 0.0 on end # [0410] Host controller + device pci 0.1 on end # [1410] Error Reporting + device pci 0.2 on end # [2410] CPU Bus Control + device pci 0.3 on end # [3410] DRAM Bus Control + device pci 0.4 on end # [4410] Power Management + device pci 0.5 on # [5410] APIC+Traffic Control + chip drivers/generic/ioapic + register "have_isa_interrupts" = "0" + register "irq_on_fsb" = "1" + register "enable_virtual_wire" = "1" + register "base" = "0xfecc0000" + device ioapic 2 on end + end + end + device pci 0.6 off end # [6410] Scratch Registers + device pci 0.7 on end # [7410] V4 Link Control + device pci 1.0 on # [7122] VGA Chrome9 HD + ioapic_irq 2 INTA 0x28 + end + device pci 1.1 on # [9170] Audio Device + ioapic_irq 2 INTA 0x29 + end + device pci 3.0 on end # [a410] PEX1 + device pci 3.1 on end # [b410] PEX2 + device pci 3.2 on end # [c410] PEX3 + device pci 3.3 on end # [d410] PEX4 + device pci 3.4 on end # [e410] PCIE bridge + device pci b.0 on end # [a409] USB Device + device pci c.0 off end # [95d0] SDIO Host Controller + device pci d.0 off end # [9530] Memory Card controller + device pci f.0 on # [9001] SATA Controller + ioapic_irq 1 INTA 0x15 + end + device pci 10.0 on end # [3038] USB 1.1 + device pci 10.1 on end # [3038] USB 1.1 + device pci 10.2 on end # [3038] USB 1.1 + device pci 10.3 on end # [3038] USB 1.1 + device pci 10.4 on end # [3104] USB 2.0 + device pci 11.0 on # [8410] LPC Bus Control + chip drivers/generic/ioapic + register "have_isa_interrupts" = "1" + register "irq_on_fsb" = "1" + register "enable_virtual_wire" = "1" + register "base" = "0xfec00000" + device ioapic 1 on end + end + #chip drivers/generic/generic # DIMM 0 channel 1 + # device i2c 50 on end + #end + #chip drivers/generic/generic # DIMM 1 channel 1 + # device i2c 51 on end + #end + chip superio/fintek/f81865f # Super duper IO + device pnp 4e.0 off end # Floppy + device pnp 4e.3 off end # Parallel Port + device pnp 4e.4 off end # Hardware Monitor + device pnp 4e.5 off end # Keyboard not here + device pnp 4e.6 off end # GPIO + device pnp 4e.a off end # PME + device pnp 4e.10 on # COM1 + io 0x60 = 0x3f8 + irq 0x70 = 4 + end + device pnp 4e.11 on # COM2 + io 0x60 = 0x2f8 + irq 0x70 = 3 + end + device pnp 4e.12 on # COM3 + io 0x60 = 0x3e8 + irq 0x70 = 10 + end + device pnp 4e.13 on # COM4 + io 0x60 = 0x2e8 + irq 0x70 = 11 + end + end # superio/fintek/f81865f + end # LPC + device pci 11.7 on end # [a353] North-South control + device pci 14.0 on end # [3288] Azalia HDAC + end +end diff --git a/src/mainboard/via/epia-m850/irq_tables.c b/src/mainboard/via/epia-m850/irq_tables.c new file mode 100644 index 0000000..28fbb4f --- /dev/null +++ b/src/mainboard/via/epia-m850/irq_tables.c @@ -0,0 +1,75 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me(a)gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <arch/pirq_routing.h> +#include <console/console.h> +#include <device/pci_ids.h> +#include <string.h> /* <- For memset */ + +#define _OFF 0x00 +#define ___OFF 0x0000 +#define LNKA 1 +#define LNKB 2 +#define LNKC 3 +#define LNKD 4 +#define LNKE 5 +#define LNKF 6 +#define LNKG 7 +#define LNKH 8 +#define BITMAP 0xdce0 +/* The link that carries the SATA interrupt has its own mask, just in case + * we want to make sure our SATA controller gets mapped to IRQ 14 */ +#define B_SATA BITMAP + +const struct irq_routing_table intel_irq_routing_table = { + PIRQ_SIGNATURE, /* u32 signature */ + PIRQ_VERSION, /* u16 version */ + 32 + 16 * 13, /* Max. number of devices on the bus */ + 0x00, /* Interrupt router bus */ + (0x11 << 3) | 0x0, /* Interrupt router dev */ + 0, /* IRQs devoted exclusively for PCI */ + PCI_VENDOR_ID_VIA, /* Vendor */ + PCI_DEVICE_ID_VIA_VX900_LPC, /* Device */ + 0, /* Miniport */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* u8 rfu[11] */ + 0x19, /* Checksum (has to be set to some value that + * would give 0 after the sum of all bytes + * for this structure (including checksum). */ + { + /* bus, dev | fn, {link, bitmap}, {link, bitmap}, {link, bitmap}, {link, bitmap}, slot, rfu */ + {0x00, (0x01 << 3) | 0x0, {{LNKH, BITMAP}, {LNKH, BITMAP}, {_OFF, ___OFF}, {_OFF, ___OFF}}, 0x0, 0x0}, + {0x00, (0x03 << 3) | 0x0, {{LNKH, BITMAP}, {LNKH, BITMAP}, {LNKH, BITMAP}, {LNKH, BITMAP}}, 0x0, 0x0}, + {0x00, (0x0a << 3) | 0x0, {{LNKA, BITMAP}, {LNKB, B_SATA}, {LNKC, BITMAP}, {LNKD, BITMAP}}, 0x0, 0x0}, + {0x00, (0x0b << 3) | 0x0, {{LNKA, BITMAP}, {_OFF, ___OFF}, {_OFF, ___OFF}, {_OFF, ___OFF}}, 0x0, 0x0}, + {0x00, (0x0c << 3) | 0x0, {{LNKA, BITMAP}, {_OFF, ___OFF}, {_OFF, ___OFF}, {_OFF, ___OFF}}, 0x0, 0x0}, + {0x00, (0x0d << 3) | 0x0, {{LNKA, BITMAP}, {_OFF, ___OFF}, {_OFF, ___OFF}, {_OFF, ___OFF}}, 0x0, 0x0}, + {0x00, (0x0f << 3) | 0x0, {{LNKB, B_SATA}, {_OFF, ___OFF}, {_OFF, ___OFF}, {_OFF, ___OFF}}, 0x0, 0x0}, + {0x00, (0x10 << 3) | 0x0, {{LNKA, BITMAP}, {LNKB, B_SATA}, {LNKC, BITMAP}, {LNKD, BITMAP}}, 0x0, 0x0}, + {0x00, (0x14 << 3) | 0x0, {{LNKB, B_SATA}, {_OFF, ___OFF}, {_OFF, ___OFF}, {_OFF, ___OFF}}, 0x0, 0x0}, + {0x01, (0x00 << 3) | 0x0, {{LNKH, BITMAP}, {LNKH, BITMAP}, {LNKH, BITMAP}, {LNKH, BITMAP}}, 0x1, 0x0}, + {0x02, (0x00 << 3) | 0x0, {{LNKH, BITMAP}, {LNKH, BITMAP}, {LNKH, BITMAP}, {LNKH, BITMAP}}, 0x2, 0x0}, + {0x03, (0x00 << 3) | 0x0, {{LNKH, BITMAP}, {LNKH, BITMAP}, {LNKH, BITMAP}, {LNKH, BITMAP}}, 0x0, 0x0}, + {0x04, (0x00 << 3) | 0x0, {{LNKH, BITMAP}, {LNKH, BITMAP}, {LNKH, BITMAP}, {LNKH, BITMAP}}, 0x0, 0x0}, + } +}; + +unsigned long write_pirq_routing_table(unsigned long addr) +{ + return copy_pirq_routing_table(addr, &intel_irq_routing_table); +} diff --git a/src/mainboard/via/epia-m850/mainboard.c b/src/mainboard/via/epia-m850/mainboard.c new file mode 100644 index 0000000..57b12e1 --- /dev/null +++ b/src/mainboard/via/epia-m850/mainboard.c @@ -0,0 +1,24 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011 Alexandru Gagniuc <mr.nuke.me(a)gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <device/device.h> + +struct chip_operations mainboard_ops = { + CHIP_NAME("VIA EPIA-M850 Mainboard") +}; diff --git a/src/mainboard/via/epia-m850/romstage.c b/src/mainboard/via/epia-m850/romstage.c new file mode 100644 index 0000000..19fca87 --- /dev/null +++ b/src/mainboard/via/epia-m850/romstage.c @@ -0,0 +1,134 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011-2012 Alexandru Gagniuc <mr.nuke.me(a)gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/* + * Inspired from the EPIA-M700 + */ +#undef CONFIG_COLLECT_TIMESTAMPS +#define CONFIG_COLLECT_TIMESTAMPS 1 +#include <stdint.h> +#include <device/pci_def.h> +#include <device/pci_ids.h> +#include <arch/io.h> +#include <device/pnp_def.h> +#include <arch/io.h> +#include <arch/hlt.h> +#include <console/console.h> +#include <lib.h> +#include <cpu/x86/bist.h> +#include <string.h> +#include <timestamp.h> + +#include <console/cbmem_console.h> + +#include "northbridge/via/vx900/early_vx900.h" +#include "northbridge/via/vx900/raminit.h" +#include "superio/fintek/f81865f/f81865f_early_serial.c" + +#define SERIAL_DEV PNP_DEV(0x4e, 0x10) + +static inline u64 tsc2u64(tsc_t tsc) +{ + return ((u64)tsc.hi << 32) | tsc.lo; +} +#define TSC_PER_USEC 1297 +static inline u32 tsc2ms(u64 end, u64 start) +{ + return ((u32)(end-start)/TSC_PER_USEC)/1000; +} +/* cache_as_ram.inc jumps to here. */ +void main(unsigned long bist); +void main(unsigned long bist) +{ + u32 tolm; + tsc_t tsc_at_romstage_start = rdtsc();; + + /* First thing we need to do on the VX900, before anything else */ + vx900_enable_pci_config_space(); + + f81865f_enable_serial(SERIAL_DEV, CONFIG_TTYS0_BASE); + console_init(); + print_debug("Console initialized. \n"); + + vx900_cpu_bus_interface_setup(); + + /* NOT HERE FIXME */ + //pci_write_config8(SNMIC, 0x60, 1 << (30-24)); + + /* Be smart. Get this info */ + vx900_print_strapping_info(); + /* DEVEL helper */ + vx900_disable_auto_reboot(); + /* Halt if there was a built-in self test failure. */ + report_bist_failure(bist); + + /* Oh, almighty, give us the SMBUS */ + enable_smbus(); + + /* If this works, then SMBUS is up and running */ + /* dump_spd_data(); */ + + tsc_t tsc_before_raminit = rdtsc(); + /* Now we can worry about raminit. + * This board only has DDR3, so no need to worry about which DRAM type + * to use */ + dimm_layout dimms = {{0x50, 0x51, SPD_END_LIST}}; + vx900_init_dram_ddr3(&dimms); + tsc_t tsc_after_raminit = rdtsc(); + + ram_check(0, 0x80); + ram_check(512<<10, 0x80); + ram_check((1<<20) - (1<<10), 0x80); + ram_check((1<<24), 0x80); + ram_check((512 + 256 -1)<<20, 0x80); + ram_check(0x80c0000, 0x80); + tolm = ((pci_read_config16(MCU, 0x84) & 0xfff0) >> 4) << 20; + if (tolm > (1 * (u32)GiB)) + ram_check(1024<<10, 0x80); + if (tolm > (2 * (u32)GiB)) + ram_check(2048<<20, 0x80); + + print_debug("We passed RAM verify\n"); +#ifdef GONFIG_EARLY_CBMEM_INIT + /* We got RAM working, now we can write the timestamps to RAM */ + cbmem_initialize(); + timestamp_init(tsc_at_romstage_start); + timestamp_add(TS_START_ROMSTAGE, tsc_at_romstage_start ); + timestamp_add(TS_BEFORE_INITRAM, tsc_before_raminit ); + timestamp_add(TS_AFTER_INITRAM, tsc_after_raminit ); + timestamp_add_now(TS_END_ROMSTAGE); +#endif + /* FIXME: Take this out please */ + /* This disables our USB */ + //pci_write_config8(LPC, 0x50, ~(1<<3)); + /* This eviscerates our VGA out of existence */ + //pci_mod_config16(MCU, 0xa0, (1 << 15), 0); + /* Disable Memcard and SDIO */ + pci_mod_config8(LPC, 0x51, 0, (1<<7) | (1<<4)); + + /* FIXME: They no es belong here */ + u64 start, end; + start = tsc2u64(tsc_at_romstage_start); + end = tsc2u64(tsc_before_raminit); + printk(BIOS_DEBUG, "Before raminit %ums\n", tsc2ms(end, start)); + + start = end; + end = tsc2u64(tsc_after_raminit); + printk(BIOS_DEBUG, "Actual Raminit %ums\n", tsc2ms(end, start)); +} diff --git a/src/northbridge/via/Kconfig b/src/northbridge/via/Kconfig index 2c38acf..8a747b9 100644 --- a/src/northbridge/via/Kconfig +++ b/src/northbridge/via/Kconfig @@ -4,3 +4,4 @@ source src/northbridge/via/cn400/Kconfig source src/northbridge/via/vt8601/Kconfig source src/northbridge/via/vt8623/Kconfig source src/northbridge/via/vx800/Kconfig +source src/northbridge/via/vx900/Kconfig diff --git a/src/northbridge/via/Makefile.inc b/src/northbridge/via/Makefile.inc index 75cb15b..2e74b61 100644 --- a/src/northbridge/via/Makefile.inc +++ b/src/northbridge/via/Makefile.inc @@ -4,4 +4,5 @@ subdirs-$(CONFIG_NORTHBRIDGE_VIA_CN700) += cn700 subdirs-$(CONFIG_NORTHBRIDGE_VIA_CX700) += cx700 subdirs-$(CONFIG_NORTHBRIDGE_VIA_CN400) += cn400 subdirs-$(CONFIG_NORTHBRIDGE_VIA_VX800) += vx800 +subdirs-$(CONFIG_NORTHBRIDGE_VIA_VX900) += vx900 diff --git a/src/northbridge/via/vx900/Kconfig b/src/northbridge/via/vx900/Kconfig new file mode 100644 index 0000000..d8dc05a --- /dev/null +++ b/src/northbridge/via/vx900/Kconfig @@ -0,0 +1,40 @@ +## +## This file is part of the coreboot project. +## +## Copyright (C) 2011 Alexandru Gagniuc <mr.nuke.me(a)gmail.com> +## +## This program is free software: you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation, either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program. If not, see <http://www.gnu.org/licenses/>. +## + +config NORTHBRIDGE_VIA_VX900 + bool + select IOAPIC + select HAVE_DEBUG_RAM_SETUP + select HAVE_DEBUG_SMBUS + select HAVE_HARD_RESET + select MMCONF_SUPPORT + select MMCONF_SUPPORT_DEFAULT + select GFXUMA + +config MAX_PIRQ_LINKS + int + default 8 + +config MMCONF_BASE_ADDRESS + hex + default 0xe0000000 + +config VGA_BIOS_ID + string + default "1106,7122" \ No newline at end of file diff --git a/src/northbridge/via/vx900/Makefile.inc b/src/northbridge/via/vx900/Makefile.inc new file mode 100644 index 0000000..23bbcdc --- /dev/null +++ b/src/northbridge/via/vx900/Makefile.inc @@ -0,0 +1,42 @@ +## +## This file is part of the coreboot project. +## +## Copyright (C) 2011-2013 Alexandru Gagniuc <mr.nuke.me(a)gmail.com> +## +## This program is free software: you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation, either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program. If not, see <http://www.gnu.org/licenses/>. +## + +romstage-y += early_smbus.c +romstage-y += early_vx900.c +romstage-y += early_host_bus_ctl.c +romstage-y += raminit_ddr3.c +romstage-y += ./../../../device/dram/ddr3.c +romstage-y += ./../../../southbridge/via/common/early_smbus.c +romstage-y += ./../../../drivers/pc80/udelay_io.c +romstage-$(CONFIG_COLLECT_TIMESTAMPS) += ./../../../lib/cbmem.c + +ramstage-y += pcie.c +ramstage-y += northbridge.c +ramstage-y += chrome9hd.c +ramstage-y += traf_ctrl.c +ramstage-y += sata.c +ramstage-y += lpc.c + +# The buildsystem only includes this file if CONFIG_VGA is selected. +# We need to do some VGA I/O before the VGA can be initialized. We can make good +# use of some of the functions there, so include them unconditionally +ramstage-y += ./../../../drivers/pc80/vga/vga_io.c + +chipset_bootblock_inc += $(src)/northbridge/via/vx900/romstrap.inc +chipset_bootblock_lds += $(src)/northbridge/via/vx900/romstrap.lds diff --git a/src/northbridge/via/vx900/chip.h b/src/northbridge/via/vx900/chip.h new file mode 100644 index 0000000..6334a8e --- /dev/null +++ b/src/northbridge/via/vx900/chip.h @@ -0,0 +1,52 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me(a)gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +struct northbridge_via_vx900_config { + /** + * \brief PCIe Lane[3:0] Function Select + * + * PCIe Lane3~Lane0 (PEXTX[3:0]P/VCC) can be used by the integrated + * graphic controller to output its display data. The PCIe lanes will + * be used to output DisplayPort data. + */ + u8 assign_pex_to_dp; + + /** + * \brief Lane Width for Root Port 1 + * + * Two PCIe lanes are used for Root port 1. Root port 2 is disabled. + */ + u8 pcie_port1_2_lane_wide; + + /** + * \brief PIRQ line to which to route the external interrupt + * + * The VX900 features an external interrupt which can be routed to any + * of the PIRQA->PIRQH lines. Usually, on-board devices are connected + * to the external interrupt. In some vendor BIOS's pirq table, this + * appears as link 9. + * + * Setting this line only affects the behavior of the integrated PIC. It + * has no effect on the IOAPIC. + * + * The value of this register must be a literal upper-case character + * from 'A' to 'H'. + */ + char ext_int_route_to_pirq; +}; diff --git a/src/northbridge/via/vx900/chrome9hd.c b/src/northbridge/via/vx900/chrome9hd.c new file mode 100644 index 0000000..066df63 --- /dev/null +++ b/src/northbridge/via/vx900/chrome9hd.c @@ -0,0 +1,441 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me(a)gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <arch/io.h> +#include <config.h> +#include <console/console.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <pc80/vga_io.h> + +#include "vx900.h" + +#define CHROME_9_HD_MIN_FB_SIZE 8 +#define CHROME_9_HD_MAX_FB_SIZE 512 + +/** + * @file chrome9hd.c + * + * \brief Initialization for Chrome9HD integrated graphics adapters + * + * This takes care of the initialization we need to do before calling the VGA + * BIOS. The device is not documented in the VX900 datasheet. + * + * The device is documented in: + * + * Open Graphics Programming Manual + * Chrome9GraphicsHD Processor + * VX900 Series System Processor + * Part I: Graphics Core / 2D + * + * This document was released by VIA to the Xorg project, and is available at: + * <http://www.x.org/docs/via/OGPM_Chrome9%20HD%20DX9%20_R100_PartI_Core_2D.pdf> + */ + +/* Helper to determine the framebuffer size */ +u32 chrome9hd_fb_size(void) +{ + static u32 fb_size = 0; + u8 reg8, ranksize; + u32 size_mb, tom_mb, max_size_mb; + int i; + /* We do some PCI and CMOS IO to find our value, so if we've already + * found it, save some time */ + if (fb_size != 0) + return fb_size; + /* FIXME: read fb_size from CMOS, but until that is implemented, start + * from 512MB */ + size_mb = 512; + + /* The minimum framebuffer size is 8MB. */ + size_mb = max(size_mb, CHROME_9_HD_MIN_FB_SIZE); + + const device_t mcu = dev_find_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_VX900_MEMCTRL, + 0); + /* + * We have two limitations on the maximum framebuffer size: + * 1) (Sanity) No more that 1/4 of system RAM + * 2) (Hardware limitation) No larger than DRAM in last rank + * Check both of these limitations and apply them to our framebuffer */ + tom_mb = (pci_read_config16(mcu, 0x88) & 0x07ff) << (24 - 20); + max_size_mb = tom_mb >> 2; + if (size_mb > max_size_mb) { + printk(BIOS_ALERT, "The framebuffer size of of %dMB is larger" + " than 1/4 of available memory.\n" + " Limiting framebuffer to %dMB\n", size_mb, max_size_mb); + size_mb = max_size_mb; + } + + /* Now handle limitation #2 + * Look at the ending address of the memory ranks, from last to first, + * until we find one that is not zero. That is our last rank, and its + * size is the limit of our framebuffer. */ + /* FIXME: This has a bug. If we remap memory above 4G, we consider the + * memory hole as part of our RAM. Thus if we install 3G, with a TOLM of + * 2.5G, our TOM will be at 5G and we'll assume we have 5G RAM instead + * of the actual 3.5G */ + for (i = VX900_MAX_MEM_RANKS - 1; i > -1; i--) { + reg8 = pci_read_config8(mcu, 0x40 + i); + if (reg8 == 0) + continue; + /* We've reached the last populated rank */ + ranksize = reg8 - pci_read_config8(mcu, 0x48 + i); + max_size_mb = ranksize << 6; + /* That's it. We got what we needed. */ + break; + }; + if (size_mb > max_size_mb) { + printk(BIOS_ALERT, "The framebuffer size of %dMB is larger" + " than size of the last DRAM rank.\n" + " Limiting framebuffer to %dMB\n", size_mb, max_size_mb); + size_mb = max_size_mb; + } + + /* Now round the framebuffer size to the closest power of 2 */ + u8 fb_pow = 0; + while (size_mb >> fb_pow) + fb_pow++; + fb_pow--; + size_mb = (1 << fb_pow); + /* We store the framebuffer size in bytes, for simplicity */ + fb_size = size_mb << 20; + return fb_size; +} + +#if CONFIG_PCI_OPTION_ROM_RUN_YABEL || CONFIG_PCI_OPTION_ROM_RUN_REALMODE + +#include <arch/interrupt.h> +#include <x86emu/x86emu.h> + +/** + * \brief INT15 helpers for Chrome9HD IGP + * + * These INT15 callbacks are needed for the VGA BIOS to operate correctly. They + * are described in: + * + * VIA/S3Graphics + * Video BIOS External Interface Specification for Chrome9 Series IGP + * VX900 Series + * + * This document is only available under NDA, however, the callbacks are very + * similar to other VIA/Intel IGP callbacks. + * + * Callback 0x5f18 is the most important one. It informs the VGA BIOS of the + * RAM speed and framebuffer size. The other callbacks seem to be optional. + * + * Note that SeaBIOS will overwrite these callbacks. + */ +static int vx900_int15_handler(void) +{ + int res; + + printk(BIOS_DEBUG, "%s %0x\n", __func__, X86_AX & 0xffff); + /* Set AX return value here so we don't set it every time. Just set it + * to something else if the callback is unsupported */ + res = -1; + switch (X86_AX & 0xffff) { +#if 0 + case 0x5f01: + /* VGA POST - panel type */ + /* FIXME: Don't hardcode panel type */ + M.x86.R_CX = 2; /* Panel Type Number */ + break; + case 0x5f02: + { + /* Boot device selection */ + u8 hw_opt = 1 << 0; /* DVI not, CRT present */ + u8 hdtv_conf2 = 1 << 2; /* Connector type: R/G/B */ + u8 tv_conf2 = 1 << 2; /* Only RGB */ + M.x86.R_EBX = + (hdtv_conf2 << 16) | (tv_conf2 << 8) | hw_opt; + u16 dev_word = 0x2383; /* CRT1/2, LCD1/2, HDMI1/2 */ + u8 tv_conf1 = 0; /* Default RGB NTSC */ + u8 hdtv_conf1 = 0x06; /* 1080P HDTV */ + M.x86.R_ECX = + (hdtv_conf1 << 24) | (tv_conf1 << 16) | dev_word; + M.x86.R_DL = 9; /* Layout I, RGB */ + /* FIXME: zero just make VBIOS autosense */ + M.x86.R_EBX = 0; + M.x86.R_ECX = 0; + M.x86.R_DL = 0; + break; + } +#endif + case 0x5f18: + { + u8 reg8; + /* + * BL Bit[7:4] + * Memory Data Rate (not to be confused with fCLK) + * 0000: 66MHz + * 0001: 100MHz + * 0010: 133MHz + * 0011: 200MHz ( DDR200 ) + * 0100: 266MHz ( DDR266 ) + * 0101: 333MHz ( DDR333 ) + * 0110: 400MHz ( DDR400 ) + * 0111: 533MHz ( DDR I/II 533 + * 1000: 667MHz ( DDR I/II 667) + * 1001: 800MHz + * 1010: 1066MHz + * 1011: 1333MHz + * Bit[3:0] + * N: Frame Buffer Size 2^N MB + */ + device_t dev; + dev = dev_find_slot(0, PCI_DEVFN(0, 3)); + reg8 = pci_read_config8(dev, 0xa1); + X86_BX = (u32) ((reg8 & 0x70) >> 4) + 2; + reg8 = pci_read_config8(dev, 0x90); + reg8 = ((reg8 & 0x07) + 3) << 4; + X86_BX |= (u32) reg8; + res = 0; + break; + } +#if 0 + case 0x5f2a: + /* Get SSC Control Settings */ + /* FIXME: No idea what this does. Just disable this feature + * for now */ + M.x86.R_CX = 0; + break; + case 0x5f2b: + /* Engine clock setting */ + M.x86.R_EBX = 0x0000004; /* FIXME: ECLK fixed 250MHz ? */ + break; +#endif + default: + printk(BIOS_DEBUG, "Unsupported INT15 call %04x!\n", + X86_AX & 0xffff); + X86_AX = 0; + res = -1; + break; + + } + + if (res == 0) + X86_AX = 0x5f; + else + X86_AX = 0; + return res; +} + +static void vx900_vga_set_int15_handler(void) +{ + printk(BIOS_DEBUG, "Our int15 handler is at %p\n", + &vx900_int15_handler); + mainboard_interrupt_handlers(0x15, &vx900_int15_handler); +}; + +#else +static void vx900_vga_set_int15_handler(void) +{ + /* Stub */ +}; +#endif + +static void chrome9hd_set_sid_vid(u16 vendor, u16 device) +{ + vga_sr_write(0x36, vendor >> 8); /* SVID high byte */ + vga_sr_write(0x35, vendor & 0xff); /* SVID low byte */ + vga_sr_write(0x38, device >> 8); /* SID high byte */ + vga_sr_write(0x37, device & 0xff); /* SID low byte */ +} + +static void chrome9hd_handle_uma(device_t dev) +{ + /* Mirror mirror, shiny glass, tell me that is not my ass */ + u32 fb_size = chrome9hd_fb_size() >> 20; + + //uma_resource(dev, 0x18, uma_memory_base>>10, uma_memory_size>>10); + + printk(BIOS_DEBUG, "UMA base 0x%.8llx (%lluMB)\n", uma_memory_base, + uma_memory_base >> 20); + printk(BIOS_DEBUG, "UMA size 0x%.8llx (%lluMB)\n", uma_memory_size, + uma_memory_size >> 20); + u8 fb_pow = 0; + while (fb_size >> fb_pow) + fb_pow++; + fb_pow--; + + /* Step 6 - Let MCU know the framebuffer size */ + device_t mcu = dev_find_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_VX900_MEMCTRL, 0); + pci_mod_config8(mcu, 0xa1, 7 << 4, (fb_pow - 2) << 4); + + /* Step 7 - Let GFX know the framebuffer size (through PCI and IOCTL) + * The size we set here affects the behavior of BAR2, and the amount of + * MMIO space it requests. The default is 512MB, so if we don't set this + * before reading the resources, we could waste space below 4G */ + pci_write_config8(dev, 0xb2, ((0xff << (fb_pow - 2)) & ~(1 << 7))); + vga_sr_write(0x68, (0xff << (fb_pow - 1))); + /* And also that the framebuffer is in the system, RAM */ + pci_mod_config8(dev, 0xb0, 0, 1 << 0); +} + +/** + * \brief Initialization sequence before running the VGA BIOS + * + * This is the initialization sequence described in: + * + * BIOS Porting Guide + * VX900 Series + * All-in-One System Processor + * + * This document is only available under NDA. + */ +static void chrome9hd_biosguide_init_seq(device_t dev) +{ + device_t mcu = dev_find_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_VX900_MEMCTRL, 0); + device_t host = dev_find_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_VX900_HOST_BR, 0); + + /* Step 1 - Enable VGA controller */ + /* FIXME: This is the VGA hole @ 640k-768k, and the vga port io + * We need the port IO, but can we disable the memory hole? */ + pci_mod_config8(mcu, 0xa4, 0, 0x80); /* VGA memory hole */ + + /* Step 2 - Forward MDA cycles to GFX */ + pci_mod_config8(host, 0x4e, 1 << 1, 0); /* FIXME */ + + /* Step 3 - Enable GFX I/O space */ + pci_mod_config8(dev, PCI_COMMAND, 0, PCI_COMMAND_IO); + + /* Step 4 - Enable video subsystem */ + vga_enable_mask(1 << 0, 1 << 0); + + /* Step 5 - Unlock accessing of IO space */ + vga_sr_write(0x10, 0x01); + + chrome9hd_handle_uma(dev); + + /* Step 8 - Enable memory base register on the GFX */ + if (uma_memory_base == 0) + die("uma_memory_base not set. Abandon ship!\n"); + printk(BIOS_DEBUG, "UMA base 0x%.10llx (%lluMB)\n", uma_memory_base, + uma_memory_base >> 20); + vga_sr_write(0x6d, (uma_memory_base >> 21) & 0xff); /* base 28:21 */ + vga_sr_write(0x6e, (uma_memory_base >> 29) & 0xff); /* base 36:29 */ + vga_sr_write(0x6f, 0x00); /* base 43:37 */ + + /* Step 9 - Set SID/VID */ + chrome9hd_set_sid_vid(0x1106, 0x7122); + +} + +static void dump_pci_device(device_t dev) +{ + int i; + for (i = 0; i <= 255; i++) { + unsigned char val; + if ((i & 0x0f) == 0) { + print_debug_hex8(i); + print_debug_char(':'); + } + val = pci_read_config8(dev, i); + if ((i & 7) == 0) + print_debug(" |"); + print_debug_char(' '); + print_debug_hex8(val); + if ((i & 0x0f) == 0x0f) { + print_debug("\n"); + } + } +} + +static void chrome9hd_init(device_t dev) +{ + print_debug("======================================================\n"); + print_debug("== Chrome9 HD INIT\n"); + print_debug("======================================================\n"); + + chrome9hd_biosguide_init_seq(dev); + + /* Prime PLL FIXME: bad comment */ + vga_sr_mask(0x3c, 1 << 2, 1 << 2); + + //VGA IO Address Select. 3B5 or 3D5? + vga_misc_mask(1 << 0, 1 << 0); + + //enable Base VGA 16 Bits Decode + //pci_mod_config8(host, 0x4e, 0, 1<<4); + + vx900_vga_set_int15_handler(); + + u32 fb_address = pci_read_config32(dev, PCI_BASE_ADDRESS_2); + fb_address &= ~0x0F; + if (!fb_address) { + printk(BIOS_WARNING, "Chrome9HD: No FB BAR assigned!\n"); + return; + } + + printk(BIOS_INFO, "Chrome: Using %dMB Framebuffer at 0x%08X.\n", + 256, fb_address); + + printk(BIOS_DEBUG, "Initializing VGA...\n"); + + pci_dev_init(dev); + + printk(BIOS_DEBUG, "Enable VGA console\n"); + + dump_pci_device(dev); +} + +static void chrome9hd_enable(device_t dev) +{ + print_debug("======================================================\n"); + print_debug("== Chrome9 HD ENABLE\n"); + print_debug("======================================================\n"); + + device_t mcu = dev_find_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_VX900_MEMCTRL, 0); + /* FIXME: here? -=- ACLK 250Mhz */ + pci_mod_config8(mcu, 0xbb, 0, 0x01); +} + +static void chrome9hd_disable(device_t dev) +{ + print_debug("======================================================\n"); + print_debug("== Chrome9 HD DISABLE\n"); + print_debug("======================================================\n"); + + device_t mcu = dev_find_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_VX900_MEMCTRL, 0); + /* Disable GFX - This step effectively renders the GFX inert + * It won't even show up as a PCI device during enumeration */ + pci_mod_config8(mcu, 0xa1, 1 << 7, 0); +} + +static struct device_operations chrome9hd_operations = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = chrome9hd_init, + .disable = chrome9hd_disable, + .enable = chrome9hd_enable, + .ops_pci = 0, +}; + +static const struct pci_driver chrome9hd_driver __pci_driver = { + .ops = &chrome9hd_operations, + .vendor = PCI_VENDOR_ID_VIA, + .device = PCI_DEVICE_ID_VIA_VX900_VGA, +}; diff --git a/src/northbridge/via/vx900/ddr3_mrs_util.c b/src/northbridge/via/vx900/ddr3_mrs_util.c new file mode 100644 index 0000000..db90872 --- /dev/null +++ b/src/northbridge/via/vx900/ddr3_mrs_util.c @@ -0,0 +1,214 @@ +#include "ddr3_mrs_util.h" +//#include <../../dram/dram.h> + +/* + * MRS command structure: + * cmd[15:0] = Address pins MA[15:0] + * cmd[18:16] = Bank address BA[2:0] + */ + +static u16 ddr3_twr_to_mr0_map(u8 twr) +{ + if ((twr >= 5) && (twr <= 8)) + return (twr - 4) << 9; + + if ((twr >= 9) && (twr <= 14)) + return (twr >> 1) << 9; + + /* tWR == 16T is [000] */ + return 0; +} + + +/* Map the cas latency to a bitmask for the MR0 cycle */ +static u16 ddr3_cas_to_mr0_map(u8 cas) +{ + u16 mask = 0; + /* A[6:4] are bits [2:0] of (CAS - 4) */ + mask = ((cas - 4) & 0x07) << 4; + + /* A2 is the MSB of (CAS - 4) */ + if ((cas - 4) & (1 << 4)) + mask |= (1 << 2); + + return mask; +} + +mrs_cmd_t ddr3_get_mr0(enum ddr3_mr0_precharge precharge_pd, + u8 write_recovery, + enum ddr3_mr0_dll_reset dll_reset, + enum ddr3_mr0_mode mode, + u8 cas, + enum ddr3_mr0_burst_type burst_type, + enum ddr3_mr0_burst_length burst_lenght) +{ + mrs_cmd_t cmd = 0 << 16; + + if (precharge_pd == DDR3_MR0_PRECHARGE_FAST) + cmd |= (1 << 12); + + cmd |= ddr3_twr_to_mr0_map(write_recovery); + + if (dll_reset == DDR3_MR0_DLL_RESET_YES) + cmd |= (1 << 8); + + if (mode == DDR3_MR0_MODE_TEST) + cmd |= (1 << 7); + + cmd |= ddr3_cas_to_mr0_map(cas); + + if (burst_type == DDR3_MR0_BURST_TYPE_INTERLEAVED) + cmd |= (1 << 3); + + cmd |= (burst_lenght & 0x03) << 0; + + return cmd; +} + +static u16 ddr3_rtt_nom_to_mr1_map(enum ddr3_mr1_rtt_nom rtt_nom) +{ + u16 mask = 0; + /* A9 <-> rtt_nom[2] */ + if (rtt_nom & (1 << 2)) + mask |= (1 << 9); + /* A6 <-> rtt_nom[1] */ + if (rtt_nom & (1 << 1)) + mask |= (1 << 6); + /* A2 <-> rtt_nom[0] */ + if (rtt_nom & (1 << 0)) + mask |= (1 << 2); + + return mask; +} + +static u16 ddr3_ods_to_mr1_map(enum ddr3_mr1_ods ods) +{ + u16 mask = 0; + /* A5 <-> ods[1] */ + if (ods & (1 << 1)) + mask |= (1 << 5); + /* A1 <-> ods[0] */ + if (ods & (1 << 0)) + mask |= (1 << 1); + + return mask; +} + +mrs_cmd_t ddr3_get_mr1(enum ddr3_mr1_qoff qoff, + enum ddr3_mr1_tqds tqds, + enum ddr3_mr1_rtt_nom rtt_nom, + enum ddr3_mr1_write_leveling write_leveling, + enum ddr3_mr1_ods ods, + enum ddr3_mr1_additive_latency additive_latency, + enum ddr3_mr1_dll dll_disable) +{ + mrs_cmd_t cmd = 1 << 16; + + if (qoff == DDR3_MR1_QOFF_DISABLE) + cmd |= (1 << 12); + + if (tqds == DDR3_MR1_TQDS_ENABLE) + cmd |= (1 << 11); + + cmd |= ddr3_rtt_nom_to_mr1_map(rtt_nom); + + if (write_leveling == DDR3_MR1_WRLVL_ENABLE) + cmd |= (1 << 7); + + cmd |= ddr3_ods_to_mr1_map(ods); + + cmd |= (additive_latency & 0x03) << 3; + + if (dll_disable == DDR3_MR1_DLL_DISABLE) + cmd |= (1 << 0); + + return cmd; +} + +mrs_cmd_t ddr3_get_mr2(enum ddr3_mr2_rttwr rtt_wr, + enum ddr3_mr2_srt_range extended_temp, + enum ddr3_mr2_asr self_refresh, + u8 cas_cwl) +{ + mrs_cmd_t cmd = 2 << 16; + + cmd |= (rtt_wr & 0x03) << 9; + + if (extended_temp == DDR3_MR2_SRT_EXTENDED) + cmd |= (1 << 7); + + if (self_refresh == DDR3_MR2_ASR_AUTO) + cmd |= (1 << 6); + + cmd |= ((cas_cwl - 5) & 0x07) << 3; + + return cmd; +} + + +mrs_cmd_t ddr3_get_mr3(char dataflow_from_mpr) +{ + mrs_cmd_t cmd = 3 << 16; + + if(dataflow_from_mpr) + cmd |= (1 << 2); + + return cmd; +} + +mrs_cmd_t ddr3_mrs_swap_pins(mrs_cmd_t cmd); + +/* Swap some bitties titties: + * + * MA3 <-> MA4 + * MA5 <-> MA6 + * MA7 <-> MA8 + * BA0 <-> BA1 + */ +mrs_cmd_t ddr3_mrs_swap_pins(mrs_cmd_t cmd) +{ + u32 downshift, upshift; + /* High bits= A4 | A6 | A8 | BA1 */ + /* Low bits = A3 | A5 | A7 | BA0 */ + u32 lowbits = (1 << 3) | (1 << 5) | (1 << 7) | (1 << 16); + downshift = (cmd & (lowbits << 1)); + upshift = (cmd & lowbits); + cmd &= ~(lowbits | (lowbits << 1)); + cmd |= (downshift >> 1) | (upshift << 1); + return cmd; +} + +/* + * Translate the MRS command into the memory address corresponding to the + * command. This is based on the CPU address to memory address mapping described + * by the initial values of registers 0x52 and 0x53, so do not fuck with them + * until after the MRS commands have been sent to all ranks + */ + +u32 vx900_get_mrs_addr(mrs_cmd_t cmd); +/* + * Translate the MRS command into an address on the CPU bus + * + * Take an MRS command (mrs_cmd_t) and translate it to a read address on the CPU + * bus. Thus, reading from the returned address, will issue the correct MRS + * command. + * + * A read from the returned address will produce the correct MRS command + * provided the following conditions are met: + * - The MA pin mapping is set to VX900_MRS_MA_MAP + * - The memory controller's Fun3_RX6B[2:0] is set to 011b (MSR Enable) + */ +u32 vx900_get_mrs_addr(mrs_cmd_t cmd) +{ + u32 addr = 0; + u8 mrs_type = (cmd >> 16) & 0x07; + /* MA[9:0] <-> A[12:3] */ + addr |= ((cmd & 0x3ff) << 3); + /* MA10 <-> A20 */ + addr |= (((cmd >> 10) & 0x1) << 20); + /* MA[12:11] <-> A[14:13] */ + addr |= (((cmd >> 11) & 0x3) << 13); + /* BA[2:0] <-> A[19:17] */ + addr |= mrs_type << 17; + return addr; +} diff --git a/src/northbridge/via/vx900/ddr3_mrs_util.h b/src/northbridge/via/vx900/ddr3_mrs_util.h new file mode 100644 index 0000000..5d4bd88 --- /dev/null +++ b/src/northbridge/via/vx900/ddr3_mrs_util.h @@ -0,0 +1,113 @@ +#ifndef REDUNDANT_H +#define REDUNDANT_H + +#include <stdint.h> + +typedef u32 mrs_cmd_t; + +enum ddr3_mr0_precharge { + DDR3_MR0_PRECHARGE_SLOW = 0, + DDR3_MR0_PRECHARGE_FAST = 1, +}; +enum ddr3_mr0_mode { + DDR3_MR0_MODE_NORMAL = 0, + DDR3_MR0_MODE_TEST = 1, +}; +enum ddr3_mr0_dll_reset { + DDR3_MR0_DLL_RESET_NO = 0, + DDR3_MR0_DLL_RESET_YES = 1, +}; +enum ddr3_mr0_burst_type { + DDR3_MR0_BURST_TYPE_SEQUENTIAL = 0, + DDR3_MR0_BURST_TYPE_INTERLEAVED = 1, +}; +enum ddr3_mr0_burst_length { + DDR3_MR0_BURST_LENGTH_8 = 0, + DDR3_MR0_BURST_LENGTH_CHOP = 1, + DDR3_MR0_BURST_LENGTH_4 = 2, +}; +/** + * \brief Get command address for a DDR3 MR0 command + */ +mrs_cmd_t ddr3_get_mr0(enum ddr3_mr0_precharge precharge_pd, + u8 write_recovery, + enum ddr3_mr0_dll_reset dll_reset, + enum ddr3_mr0_mode mode, + u8 cas, + enum ddr3_mr0_burst_type interleaved_burst, + enum ddr3_mr0_burst_length burst_lenght +); + +enum ddr3_mr1_qoff { + DDR3_MR1_QOFF_ENABLE = 0, + DDR3_MR1_QOFF_DISABLE = 1, +}; +enum ddr3_mr1_tqds { + DDR3_MR1_TQDS_DISABLE = 0, + DDR3_MR1_TQDS_ENABLE = 1, +}; +enum ddr3_mr1_write_leveling { + DDR3_MR1_WRLVL_DISABLE = 0, + DDR3_MR1_WRLVL_ENABLE = 1, +}; +enum ddr3_mr1_rtt_nom { + DDR3_MR1_RTT_NOM_OFF = 0, + DDR3_MR1_RTT_NOM_RZQ4 = 1, + DDR3_MR1_RTT_NOM_RZQ2 = 2, + DDR3_MR1_RTT_NOM_RZQ6 = 3, + DDR3_MR1_RTT_NOM_RZQ12 = 4, + DDR3_MR1_RTT_NOM_RZQ8 = 5, +}; +enum ddr3_mr1_additive_latency { + DDR3_MR1_AL_DISABLE = 0, + DDR3_MR1_AL_CL_MINUS_1 = 1, + DDR3_MR1_AL_CL_MINUS_2 = 2, +}; +enum ddr3_mr1_ods { + DDR3_MR1_ODS_RZQ6 = 0, + DDR3_MR1_ODS_RZQ7 = 1, +}; +enum ddr3_mr1_dll { + DDR3_MR1_DLL_ENABLE = 0, + DDR3_MR1_DLL_DISABLE = 1, +}; +/** + * \brief Get command address for a DDR3 MR1 command + */ +mrs_cmd_t ddr3_get_mr1(enum ddr3_mr1_qoff qoff, + enum ddr3_mr1_tqds tqds, + enum ddr3_mr1_rtt_nom rtt_nom, + enum ddr3_mr1_write_leveling write_leveling, + enum ddr3_mr1_ods output_drive_strenght, + enum ddr3_mr1_additive_latency additive_latency, + enum ddr3_mr1_dll dll_disable +); + +enum ddr3_mr2_rttwr { + DDR3_MR2_RTTWR_OFF = 0, + DDR3_MR2_RTTWR_RZQ4 = 1, + DDR3_MR2_RTTWR_RZQ2 = 2, +}; +enum ddr3_mr2_srt_range { + DDR3_MR2_SRT_NORMAL = 0, + DDR3_MR2_SRT_EXTENDED = 1, +}; +enum ddr3_mr2_asr { + DDR3_MR2_ASR_MANUAL = 0, + DDR3_MR2_ASR_AUTO = 1, +}; +/** + * \brief Get command address for a DDR3 MR2 command + */ +mrs_cmd_t ddr3_get_mr2(enum ddr3_mr2_rttwr rtt_wr, + enum ddr3_mr2_srt_range extended_temp, + enum ddr3_mr2_asr self_refresh, + u8 cas_cwl +); + +/** + * \brief Get command address for a DDR3 MR3 command + */ +mrs_cmd_t ddr3_get_mr3(char dataflow_from_mpr); + +#endif /* REDUNDANT_H */ \ No newline at end of file diff --git a/src/northbridge/via/vx900/early_host_bus_ctl.c b/src/northbridge/via/vx900/early_host_bus_ctl.c new file mode 100644 index 0000000..761a162 --- /dev/null +++ b/src/northbridge/via/vx900/early_host_bus_ctl.c @@ -0,0 +1,73 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me(a)gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "early_vx900.h" + +static void vx900_cpu_bus_preram_setup(void) +{ + pci_mod_config8(HOST_BUS, 0x50, 0x0f, 0x08); + + /* */ + pci_mod_config8(HOST_BUS, 0x51, 0, (1<<5) | (1<<3) | (1<<2) | (1<<6) ); + + pci_write_config8(HOST_BUS, 0x52, 0xc7); + + /* High priority upstream requests on V4 bus */ + pci_write_config8(HOST_BUS, 0x56, 0x03); + /* CPU to DRAM extra 1T access control */ + pci_mod_config8(HOST_BUS, 0x59, 0x00, 1<<2); + /* Queue reordering */ + pci_mod_config8(HOST_BUS, 0x5f, 0x00, 1<<6); + /* Only Write cycle of CPU->GFXCTL will flush the CPU->Memory FIFO */ + pci_mod_config8(HOST_BUS, 0x98, 0x00, 0x60); + /* 1T delay for data on CPU bus */ + pci_write_config8(HOST_BUS, 0x9e, 0x0e); + /* Arbitrate ownership of DRAM controller a few cycles earlier */ + pci_mod_config8(HOST_BUS, 0x9f, 0x00, 1<<7); + /* Write retire policy */ + pci_write_config8(HOST_BUS, 0x5d, 0xa2); + /* Occupancy timer */ + pci_write_config8(HOST_BUS, 0x53, 0x44); + /* Medium Threshold for Write Retire Policy - 6 requests */ + pci_mod_config8(HOST_BUS, 0x56, 0x00, 0x60); + /* Bandwidth timer */ + pci_write_config8(HOST_BUS, 0x5e, 0x44); +} + +void vx900_cpu_bus_slowest_rdry(void) +{ + /* Disable fast CPU to DRAM cycle, otherwise we might hang on raminit */ + pci_mod_config8(HOST_BUS, 0x51, 1<<7, 0); + /* Memory to CPU synchronous mode */ + pci_mod_config8(HOST_BUS, 0x51, 1<<1, 0); +} + +void vx900_cpu_bus_interface_setup(void) +{ + /* Enable 8QW burst and 4QW request merging [4] and [2] + * and special mode for read cycles bit[3] */ + //pci_mod_config8(HOST_BUS, 0x54, 0, (1<<4) | (1<<2) | (1<<3) ); + + /* This is good practice to do before raminit */ + //vx900_cpu_bus_slowest_rdry(); + + vx900_cpu_bus_preram_setup(); + + dump_pci_device(HOST_BUS); +} \ No newline at end of file diff --git a/src/northbridge/via/vx900/early_smbus.c b/src/northbridge/via/vx900/early_smbus.c new file mode 100644 index 0000000..17bf573 --- /dev/null +++ b/src/northbridge/via/vx900/early_smbus.c @@ -0,0 +1,209 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011 Alexandru Gagniuc <mr.nuke.me(a)gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <device/pci_ids.h> +#include "early_vx900.h" +#include <device/early_smbus.h> + +#include <arch/io.h> +#include <console/console.h> + +/** + * \brief SMBUS IO ports in relation to the base IO port + */ +#define SMBHSTSTAT(base) (u16)(u32)base + 0x0 +#define SMBSLVSTAT(base) (u16)(u32)base + 0x1 +#define SMBHSTCTL(base) (u16)(u32)base + 0x2 +#define SMBHSTCMD(base) (u16)(u32)base + 0x3 +#define SMBXMITADD(base) (u16)(u32)base + 0x4 +#define SMBHSTDAT0(base) (u16)(u32)base + 0x5 +#define SMBHSTDAT1(base) (u16)(u32)base + 0x6 +#define SMBBLKDAT(base) (u16)(u32)base + 0x7 +#define SMBSLVCTL(base) (u16)(u32)base + 0x8 +#define SMBTRNSADD(base) (u16)(u32)base + 0x9 +#define SMBSLVDATA (base) (u16)(u32)base + 0xa + + +__attribute__((unused)) +static void smbus_delays(int delays) +{ + while(delays--) smbus_delay(); +} + + +/** + * Read a byte from the SMBus. + * + * @param dimm The address location of the DIMM on the SMBus. + * @param offset The offset the data is located at. + */ +u8 smbus_read_byte(u32 smbus_dev, u8 addr, u8 offset) +{ + u8 val; + + /* Initialize SMBUS sequence */ + smbus_reset(smbus_dev); + /* Clear host data port. */ + outb(0x00, SMBHSTDAT0(smbus_dev)); + + smbus_wait_until_ready(smbus_dev); + smbus_delays(50); + + /* Actual addr to reg format. */ + addr = (addr << 1); + addr |= 1; /* read command */ + outb(addr, SMBXMITADD(smbus_dev)); + outb(offset, SMBHSTCMD(smbus_dev)); + /* Start transaction, byte data read. */ + outb(0x48, SMBHSTCTL(smbus_dev)); + smbus_wait_until_ready(smbus_dev); + + val = inb(SMBHSTDAT0(smbus_dev)); + return val; +} + +void enable_smbus(void) +{ + device_t dev; + u8 reg8; + u32 smbus_dev = (u32)SMBUS_IO_BASE; + + /* Locate the Power Management control */ + dev = pci_locate_device(PCI_ID(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_VX900_LPC), 0); + + if (dev == PCI_DEV_INVALID) { + die("Power Management Controller not found\n"); + } + + /* + * To use SMBus to manage devices on the system board, it is a must to + * enable SMBus function by setting + * PMU_RXD2[0] (SMBus Controller Enable) to 1. + * And set PMU_RXD0 and PMU_RXD1 (SMBus I/O Base) to an appropriate + * I/O port address, so that all registers in SMBus I/O port can be + * accessed. + */ + + reg8 = pci_read_config8(dev, 0xd2); + /* Enable SMBus controller */ + reg8 |= 1; + /* Set SMBUS clock from 128k source */ + reg8 |= 1<<2; + pci_write_config8(dev, 0xd2, reg8); + + reg8 = pci_read_config8(dev, 0x94); + /* SMBUS clock from divider of 14.318 MHz */ + reg8 &= ~(1<<7); + pci_write_config8(dev, 0x94, reg8); + + /* Set SMBus IO base */ + pci_write_config16(dev, 0xd0, SMBUS_IO_BASE); + + /* + * Initialize the SMBus sequence: + */ + /* Clear SMBus host status register */ + smbus_reset(smbus_dev); + /* Clear SMBus host data 0 register */ + outb(0x00, SMBHSTDAT0(smbus_dev)); + + /* Wait for SMBUS */ + smbus_wait_until_ready(smbus_dev); + +} + +void spd_read(u8 addr, spd_raw_data spd) +{ + u8 reg; + int i, regs; + u32 smbus_dev = SMBUS_IO_BASE; + + reg = smbus_read_byte(smbus_dev, addr, 2); + if(reg != 0x0b) + { + printk(BIOS_DEBUG, "SMBUS device %x not a DDR3 module\n", addr); + spd[2] = 0; + return; + } + + reg = smbus_read_byte(smbus_dev, addr, 0); + reg &= 0xf; + if (reg == 0x3) { + regs = 256; + } else if (reg == 0x2) { + regs = 176; + } else if (reg == 0x1) { + regs = 128; + } else { + printk(BIOS_INFO, "No DIMM present at %x\n", addr); + spd[2] = 0; + return; + } + printk(BIOS_DEBUG, "SPD Data for DIMM %x \n", addr); + for (i = 0; i < regs; i++) { + reg = smbus_read_byte(smbus_dev, addr, i); + //printk(BIOS_DEBUG, " Offset %u = 0x%x \n", i, reg ); + spd[i] = reg; + } +} + +void dump_spd_data(void) +{ + int dimm, offset, regs; + unsigned int reg; + spd_raw_data spd; + dimm_attr dimmx; + u32 smbus_dev = (u32 )SMBUS_IO_BASE; + + for (dimm = 0x50; dimm < 0x52; dimm++) { + reg = smbus_read_byte(smbus_dev, dimm, 2); + if(reg != 0x0b) + { + printk(BIOS_DEBUG, + "SMBUS device %x not a DDR3 module\n", dimm); + continue; + } + + reg = smbus_read_byte(smbus_dev, dimm, 0); + reg &= 0xf; + if (reg == 0x3) { + regs = 256; + } else if (reg == 0x2) { + regs = 176; + } else if (reg == 0x1) { + regs = 128; + } else { + printk(BIOS_INFO, "No DIMM present at %x\n", dimm); + regs = 0; + continue; + } + printk(BIOS_DEBUG, "SPD Data for DIMM %x \n", dimm); + for (offset = 0; offset < regs; offset++) { + reg = smbus_read_byte(smbus_dev, dimm, offset); + //printk(BIOS_DEBUG, " Offset %u = 0x%x \n", offset, reg ); + spd[offset] = reg; + } + + spd_decode_ddr3(&dimmx, spd); + dram_print_spd_ddr3(&dimmx); + + } +} + diff --git a/src/northbridge/via/vx900/early_vx900.c b/src/northbridge/via/vx900/early_vx900.c new file mode 100644 index 0000000..c03a548 --- /dev/null +++ b/src/northbridge/via/vx900/early_vx900.c @@ -0,0 +1,133 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me(a)gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "early_vx900.h" +#include <arch/io.h> +#include <console/console.h> + +unsigned long get_top_of_ram(void) +{ + u16 reg_tom = pci_read_config8(MCU, 0x88); + return (((unsigned long) reg_tom) << 24) - (256<<20); +} + +struct cbmem_entry *get_cbmem_toc(void) +{ + return (struct cbmem_entry *)(get_top_of_ram() - HIGH_MEMORY_SIZE); +} + +void vx900_enable_pci_config_space(void) +{ + /* MMCONF is not yet enabled, so we'll need to specify we want to do + * pci_io. We don't want to do pci_mmio until we enable it */ + /* Enable multifunction bit for northbridge. + * This enables the PCI configuration spaces of D0F1 to D0F7 to be + * accessed */ + pci_io_write_config8(HOST_CTR, 0x4f, 0x01); + +#if CONFIG_MMCONF_SUPPORT + /* COOL, now enable MMCONF */ + u8 reg8 = pci_io_read_config8(TRAF_CTR, 0x60); + reg8 |= 3; + pci_io_write_config8(TRAF_CTR, 0x60, reg8); + reg8 = CONFIG_MMCONF_BASE_ADDRESS >> 28; + pci_io_write_config8(TRAF_CTR, 0x61, reg8); +#endif +} + +/** + *\brief Prints information regarding the hardware strapping on VX900 + * + * Certain features on the VX900 are controlled by strapping pins which are + * hardwired on the mainboard. These values determine whether the ROM is on the + * SPI or LPC bus, or whether auto-reset is enabled. + * \n + * Having a feel for these values is important when trying to fix obscure + * problems found when porting a mainboard based on the VX900. + * \n + * These values are decoded and printed to the terminal. + */ +void vx900_print_strapping_info(void) +{ + u8 strap = pci_read_config8(SNMIC, 0x56); + + print_debug("VX900 strapping pins indicate that:\n"); + printk(BIOS_DEBUG, " ROM is on %s bus\n", + (strap & (1<<0)) ? "SPI" : "LPC" ); + printk(BIOS_DEBUG, " Auto reset is %s\n", + (strap & (1<<1)) ? "disabled" : "enabled" ); + printk(BIOS_DEBUG, " LPC FWH command is %s\n", + (strap & (1<<2)) ? "enabled" : "disabled" ); + printk(BIOS_DEBUG, " Debug link is is %s\n", + (strap & (1<<4)) ? "enabled" : "disabled" ); + printk(BIOS_DEBUG, " PCI master mode is %s\n", + (strap & (1<<5)) ? "enabled" : "disabled" ); +} + +/** + *\brief Disables the auto-reboot mechanism on VX900 + * + * The VX900 has an auto-reboot mechanism that can be enabled by a hardware + * strap. This mechanism can make development annoying, since we don't know if + * the reset was caused by a bug in coreboot, or by this mechanism. + */ +void vx900_disable_auto_reboot(void) +{ + if( pci_read_config8(SNMIC, 0x56) & (1<<1) ) { + print_debug("Auto-reboot is disabled in hardware\n"); + return; + } + /* Disable the GP3 timer, which is the root of all evil */ + pci_write_config8(LPC, 0x98, 0); + /* Yep, that's all it takes */ + print_debug("GP3 timer disabled." + " Auto-reboot should not give you any more trouble.\n"); +} + +void vx900_disable_legacy_rom_shadow(void) +{ + /* Disable shitty 8086 legacy shadows + * This frees the entire 640k-1M range for DRAM + * VGA may still use 640k-768k if enabled later + * Unfortunately, we need to disable these shadows in more than one + * device, and that's why some ranges are disabled more than once */ + pci_write_config8(MCU, 0x80, 0xff); /* ROM 768k - 832k */ + pci_write_config8(MCU, 0x81, 0xff); /* ROM 832k - 896k */ + pci_write_config8(MCU, 0x82, 0xff); /* ROM 896k - 960k */ + /* ROM 960k - 1M * SMRAM: 640k - 768k */ + pci_write_config8(MCU, 0x83, 0x31); + + /* Bits 6:0 are the ROM shadow on top of 4G, so leave those untouched */ + pci_mod_config8(LPC, 0x41, 1<<7, 0);/* 896k - 960k */ + + pci_write_config8(SNMIC, 0x61, 0); /* 768k - 832k */ + pci_write_config8(SNMIC, 0x62, 0); /* 832k - 896k */ + pci_write_config8(SNMIC, 0x63, 0); /* 896k - 1M */ + pci_write_config8(SNMIC, 0x64, 0); /* 896k - 960k */ + + /* Doesn't really belong here, but it is "shitty legacy" + * Enable A20 line */ + outb( inb(0x92)|(1<<1), 0x92); +} + +void vx900_disable_gfx(void) +{ + /* Disable GFX */ + pci_mod_config8(MCU, 0xa1, 1<<7, 0); +} diff --git a/src/northbridge/via/vx900/early_vx900.h b/src/northbridge/via/vx900/early_vx900.h new file mode 100644 index 0000000..7fa41f8 --- /dev/null +++ b/src/northbridge/via/vx900/early_vx900.h @@ -0,0 +1,106 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011-2012 Alexandru Gagniuc <mr.nuke.me(a)gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef EARLY_VX900_H +#define EARLY_VX900_H + +#include "raminit.h" +#include "vx900.h" + +#include <arch/io.h> +#include <cbmem.h> +//#include <devices/smbus/smbus.h> +#include <stdint.h> +#include <arch/io.h> +#include <console/console.h> + +/* North Module devices */ +#define HOST_CTR PCI_DEV(0, 0, 0) +#define ERR_REP PCI_DEV(0, 0, 1) +#define HOST_BUS PCI_DEV(0, 0, 2) +#define MCU PCI_DEV(0, 0, 3) +#define POWERMAN PCI_DEV(0, 0, 4) +#define TRAF_CTR PCI_DEV(0, 0, 5) +#define NSBIC PCI_DEV(0, 0, 7) + +#define GFX PCI_DEV(0, 1, 0) +#define HDMI PCI_DEV(0, 1, 0) + +#define PEXx PCI_DEV(0, 3, x) +#define PEX_CTR PCI_DEV(0, 3, 4) + +/* South Module devices */ +#define UARTx PCI_DEV(0, 0x0a, x) +#define USB_MASS PCI_DEV(0, 0x0b, 0) +#define SDIO PCI_DEV(0, 0x0c, 0) +#define CARD_RD PCI_DEV(0, 0x0d, 0) +#define SATA PCI_DEV(0, 0x0d, 0) +#define USBx PCI_DEV(0, 0x10, x) +#define USB_EHCI PCI_DEV(0, 0x10, 4) +#define LPC PCI_DEV(0, 0x11, 0) +#define PMU LPC +#define SNMIC PCI_DEV(0, 0x11, 7) +#define P2P PCI_DEV(0, 0x13, 0) +#define HDAC PCI_DEV(0, 0x14, 0) + + +unsigned long get_top_of_ram(void); + +void enable_smbus(void); +void dump_spd_data(void); +void spd_read(u8 addr, spd_raw_data spd); + +void vx900_enable_pci_config_space(void); +void vx900_disable_legacy_rom_shadow(void); + +void vx900_print_strapping_info(void); +void vx900_disable_auto_reboot(void); + +void vx900_cpu_bus_slowest_rdry(void); +void vx900_cpu_bus_interface_setup(void); + +void vx900_dram_set_gfx_resources(void); +void vx900_disable_gfx(void); + +static inline void dump_pci_device(device_t dev) +{ + int i; + printram("PCI: %.2x:%.2x.%.2x", + (dev >> 20) & 0xff, (dev >> 15) & 0x1f, (dev >> 12) & 7 ); + printram("\n"); + + for (i = 0; i <= 0xff; i++) { + unsigned char val; + if ((i & 0x0f) == 0) { + printram("%.2x:", i); + } + + if ((i & 0x0f) == 0x08) { + printram(" |"); + } + + val = pci_read_config8(dev, i); + printram(" %.2x", val); + + if ((i & 0x0f) == 0x0f) { + printram("\n"); + } + } +} +#endif /* EARLY_VX900_H */ diff --git a/src/northbridge/via/vx900/lpc.c b/src/northbridge/via/vx900/lpc.c new file mode 100644 index 0000000..6e4eec1 --- /dev/null +++ b/src/northbridge/via/vx900/lpc.c @@ -0,0 +1,220 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me(a)gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <arch/io.h> +#include <arch/pirq_routing.h> +#include <console/console.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <pc80/i8259.h> +#include <pc80/mc146818rtc.h> +#include <drivers/generic/ioapic/chip.h> + +#include "vx900.h" +#include "chip.h" + +static void vx900_lpc_misc_stuff(device_t dev) +{ + char extint; + u8 val; + struct northbridge_via_vx900_config *nb = (void*)dev->chip_info; + + /* GPIO 11,10 to SATALED [1,0] */ + pci_mod_config8(dev, 0xe4, 0 , 1<<0); + + /* Route the external interrupt line */ + extint = nb->ext_int_route_to_pirq; + if (extint < 'A' || extint > 'H') { + printk(BIOS_WARNING, "Invalid PIRQ%c for external interrupt\n", + extint); + } else { + printk(BIOS_INFO, "Routing external interrupt to PIRQ%c\n", + extint); + val = extint - 'A'; + val |= (1 << 3); /* bit3 enables the external int */ + pci_mod_config8(dev, 0x55, 0xf, val); + + } +} + +static void vx900_lpc_dma_setup(device_t dev) +{ + /* These are the steps recommended by VIA in order to get DMA running */ + + /* Enable Positive South Module PCI Cycle Decoding */ + /* FIXME: Setting this seems to hang our system */ + //pci_mod_config8(dev, 0x58, 0, 1<<4); + /* Positive decoding for ROM + APIC + On-board IO ports */ + pci_mod_config8(dev, 0x6c, 0, (1<<2) | (1<<3) | (1<<7)); + /* Enable DMA channels. BIOS guide recommends DMA channel 2 off */ + pci_write_config8(dev, 0x53, 0xfb); + /* Disable PCI/DMA Memory Cycles Output to PCI Bus */ + pci_mod_config8(dev, 0x5b, (1<<5), 0); + /* DMA bandwidth control - Improved bandwidth */ + pci_write_config8(dev, 0x53, 0xff); + /* ISA Positive Decoding control */ + pci_write_config8(dev, 0x6d, 0xdf); + pci_write_config8(dev, 0x6e, 0x98); + pci_write_config8(dev, 0x6f, 0x30); +} + +/** + *\brief VX900: Set up the south module IOAPIC (for the ISA/LPC bus) + * + * Enable the IOAPIC in the south module, and properly set it up. + * \n + * This is the hardware specific initialization for the IOAPIC, and complements + * the setup done by the generic IOAPIC driver. In order for the IOAPIC to work + * properly, it _must_ be declared in devicetree.cb . + * \n + * We are assuming this is called before the drivers/generic/ioapic code, + * which should be the case if devicetree.cb is set up properly. + */ +static void vx900_lpc_ioapic_setup(device_t dev) +{ + /* Find the IOAPIC, and make sure it's set up correctly in devicetree.cb + * If it's not, then the generic ioapic driver will not set it up + * correctly, and the MP table will not be correctly generated */ + device_t ioapic; + for(ioapic = dev->next; ioapic; ioapic = ioapic->next) + { + if(ioapic->path.type == DEVICE_PATH_IOAPIC) + break; + } + + /* You did put an IOAPIC in devicetree.cb, didn't you? */ + if(ioapic == 0) { + /* We don't have enough info to set up the IOAPIC */ + printk(BIOS_ERR, "ERROR: South module IOAPIC not found. " + "Check your devicetree.cb\n"); + return; + } + + /* Found an IOAPIC, now we need to make sure it's the right one */ + ioapic_config_t *config = (ioapic_config_t*)ioapic->chip_info; + if(!config->have_isa_interrupts) { + /* Umh, is this the right IOAPIC ? */ + printk(BIOS_ERR, "ERROR: South module IOAPIC not carrying ISA " + "interrupts. Check your devicetree.cb\n"); + printk(BIOS_ERR, "Will not initialize this IOAPIC.\n"); + return; + } + + /* The base address of this IOAPIC _must_ be at 0xfec00000. + * Don't move this value to a #define, as people might think it's + * configurable. It is not. */ + const u32 base = config->base; + if(base != 0xfec00000) { + printk(BIOS_ERR, "ERROR: South module IOAPIC base should be at " + "0xfec00000\n but we found it at 0x%.8x\n", + base); + return; + } + + print_debug("VX900 LPC: Setting up the south module IOAPIC.\n"); + /* Enable IOAPIC + * So much work for one line of code. Talk about bloat :) + * The 8259 PIC should still work even if the IOAPIC is enabled, so + * there's no crime in enabling the IOAPIC here. */ + pci_mod_config8(dev, 0x58, 0, 1<<6); +} + +static void vx900_lpc_interrupt_stuff(device_t dev) +{ + /* Enable setting trigger mode through 0x4d0, and 0x4d1 ports + * And enable I/O recovery time */ + pci_mod_config8(dev, 0x40, 0, (1<<2)|(1<<6)); + /* Set serial IRQ frame width to 6 PCI cycles (recommended by VIA) + * And enable serial IRQ */ + pci_mod_config8(dev, 0x52, 3<<0, (1<<3)|(1<<0) ); + + /* Disable IRQ12 storm FIXME: bad comment */ + pci_mod_config8(dev, 0x51, (1<<2), 0); + + pci_write_config8(dev, 0x4c, (1<<6) ); + + /* Get the IRQs up and running. SeaBIOS/linux needs these to boot */ + setup_i8259(); + + vx900_lpc_dma_setup(dev); + + /* The IOAPIC is special, and we treat it separately */ + vx900_lpc_ioapic_setup(dev); +} + +static void dump_pci_device(device_t dev) +{ + int i; + for (i = 0; i <= 255; i++) { + unsigned char val; + if ((i & 0x0f) == 0) { + print_debug_hex8(i); + print_debug_char(':'); + } + val = pci_read_config8(dev, i); + if((i & 7) == 0) print_debug(" |"); + print_debug_char(' '); + print_debug_hex8(val); + if ((i & 0x0f) == 0x0f) { + print_debug("\n"); + } + } +} + +static void vx900_lpc_init(device_t dev) +{ + vx900_lpc_interrupt_stuff(dev); + vx900_lpc_misc_stuff(dev); + dump_pci_device(dev); +} + +static struct device_operations vx900_lpc_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = vx900_lpc_init, + .scan_bus = scan_static_bus, +}; + +static const struct pci_driver lpc_driver __pci_driver = { + .ops = &vx900_lpc_ops, + .vendor = PCI_VENDOR_ID_VIA, + .device = PCI_DEVICE_ID_VIA_VX900_LPC, +}; + +#if CONFIG_PIRQ_ROUTE +void pirq_assign_irqs(const u8* pirq) +{ + device_t lpc; + + lpc = dev_find_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_VX900_LPC, 0); + + /* Take care of INTA -> INTD */ + pci_mod_config8(lpc, 0x55, (0xf << 4), pirq[0] << 4); + pci_write_config8(lpc, 0x56, pirq[1] | (pirq[2] << 4) ); + pci_write_config8(lpc, 0x57, pirq[3] << 4); + + /* Enable INTE -> INTH to be on separate IRQs */ + pci_mod_config8(lpc, 0x46, 0, 1<<4); + /* Now do INTE -> INTH */ + pci_write_config8(lpc, 0x44, pirq[4] | (pirq[5] << 4) ); + pci_write_config8(lpc, 0x45, pirq[6] | (pirq[7] << 4) ); +} +#endif diff --git a/src/northbridge/via/vx900/northbridge.c b/src/northbridge/via/vx900/northbridge.c new file mode 100644 index 0000000..6e6f50c --- /dev/null +++ b/src/northbridge/via/vx900/northbridge.c @@ -0,0 +1,188 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me(a)gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "vx900.h" +#include "chip.h" + +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <cpu/cpu.h> +#include <cbmem.h> +#include <lib.h> +#include <reset.h> +#include <string.h> + +void hard_reset(void) +{ + outb((1 << 2) | (1 << 1), 0xcf9); +} + +static void vx900_set_resources(device_t dev) +{ + u32 pci_tolm, vx900_tom, tomk, vx900_tolm, full_tolmk, fbufk, tolmk; + + print_debug("========================================" + "========================================\n"); + print_debug("============= VX900 memory sizing & Co. " + "========================================\n"); + print_debug("========================================" + "========================================\n"); + + int idx = 10; + const device_t mcu = dev_find_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_VX900_MEMCTRL, + 0); + if (!mcu) { + die("Something is terribly wrong.\n" + " We tried locating the MCU on the PCI bus, " + "but couldn't find it. Halting.\n"); + } + + pci_tolm = find_pci_tolm(dev->link_list); + printk(BIOS_SPEW, "Found PCI tolm at %.8x\n", pci_tolm); + printk(BIOS_SPEW, "Found PCI tolm at %dMB\n", pci_tolm >> 20); + + /* The last valid DRAM address is computed by the MCU + * One issue might be if we have a hole in the rank mappings, so that + * virtual ranks are not mapped successively in the linear address space + * (Ex: rank 0 mapped 0-1G, rank 1 mapped 2G-3G) + * We don't do this awkward mapping in RAM init, so we don't worry about + * it here, but it is something to keep in mind if having RAM issues */ + vx900_tom = pci_read_config16(mcu, 0x88) & 0x07ff; + tomk = vx900_tom << (24 - 10); + printk(BIOS_SPEW, "Found top of memory at %dMB\n", tomk >> 10); + + /* Do the same for top of low RAM */ + vx900_tolm = (pci_read_config16(mcu, 0x84) & 0xfff0) >> 4; + full_tolmk = vx900_tolm << (20 - 10); + /* FIXME: Remap above 4G */ + full_tolmk = min(full_tolmk, pci_tolm >> 10); + printk(BIOS_SPEW, "Found top of low memory at %dMB\n", + full_tolmk >> 10); + + /* What about the framebuffer for the integrated GPU? */ + fbufk = chrome9hd_fb_size() >> 10; + printk(BIOS_SPEW, "Integrated graphics buffer: %dMB\n", fbufk >> 10); + + /* Can't use the framebuffer as system RAM, sorry */ + tomk -= fbufk; + tolmk = min(full_tolmk, tomk); + tolmk -= fbufk; + ram_resource(dev, idx++, 0, 640); + printk(BIOS_SPEW, "System ram left: %dMB\n", tolmk >> 10); + /* FIXME: how can we avoid leaving this hole? + * Leave a hole for VGA, 0xa0000 - 0xc0000 ?? */ + /* TODO: VGA Memory hole can be disabled in SNMIC. Upper 64k of ROM seem + * to be always mapped to the top of 1M, but this can be overcome with + * some smart positive/subtractive resource decoding */ + ram_resource(dev, idx++, 768, (tolmk - 768)); + uma_memory_size = fbufk << 10; + uma_memory_base = tolmk << 10; + ////uma_memory_base = (u64)tomk << 10; + + printk(BIOS_DEBUG, "UMA @ %lldMB + %lldMB\n", uma_memory_base >> 20, + uma_memory_size >> 20); + /* FIXME: How do we handle remapping above 4G? */ + ////if (tomk > tolmk) + //// ram_resource(dev, idx++, 1<<22, tomk - (1 << 22)); + + /* Leave some space for ACPI, PIRQ and MP tables */ + high_tables_base = (tolmk << 10) - HIGH_MEMORY_SIZE; + high_tables_size = HIGH_MEMORY_SIZE; + printk(BIOS_DEBUG, "high_tables_base: %08llx, size %lld\n", + high_tables_base, high_tables_size); + /* Because of the video framebuffer, the high tables may be in a + * different location than in romstage, so we need to copy them over */ +/* void* old_tables = (void*)((full_tolmk<<10) - HIGH_MEMORY_SIZE); + void* new_tables = (void*)((u32)high_tables_base); + printk(BIOS_DEBUG, "Moving CBMEM from %p to %p\n", + old_tables, new_tables); + memcpy(new_tables, old_tables, HIGH_MEMORY_SIZE); + cbmem_reinit(high_tables_base);*/ + + print_debug("======================================================\n"); + assign_resources(dev->link_list); +} + +static void vx900_read_resources(device_t dev) +{ + /* Our fixed resources start at 0 */ + int idx = 0; + /* Reserve our ROM mapped space */ + struct resource *res; + res = new_resource(dev, idx++); + res->size = 512 * KiB; + res->base = 0xffffffff - (res->size - 1); + res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED; + + /* Now do the same for our MMCONF */ + res = new_resource(dev, idx++); + res->size = 256 * MiB; + res->base = CONFIG_MMCONF_BASE_ADDRESS; + res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED; + + pci_domain_read_resources(dev); +} + +static struct device_operations pci_domain_ops = { + .read_resources = vx900_read_resources, + .set_resources = vx900_set_resources, + .enable_resources = NULL, + .init = NULL, + .scan_bus = pci_domain_scan_bus, +#if CONFIG_MMCONF_SUPPORT_DEFAULT + .ops_pci_bus = &pci_ops_mmconf, +#else + .ops_pci_bus = &pci_cf8_conf1, +#endif +}; + +static void cpu_bus_init(device_t dev) +{ + initialize_cpus(dev->link_list); +} + +static void cpu_bus_noop(device_t dev) +{ +} + +static struct device_operations cpu_bus_ops = { + .read_resources = cpu_bus_noop, + .set_resources = cpu_bus_noop, + .enable_resources = cpu_bus_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_via_vx900_ops = { + CHIP_NAME("VIA VX900 Chipset") + .enable_dev = enable_dev, +}; diff --git a/src/northbridge/via/vx900/pcie.c b/src/northbridge/via/vx900/pcie.c new file mode 100644 index 0000000..c9b04eb --- /dev/null +++ b/src/northbridge/via/vx900/pcie.c @@ -0,0 +1,142 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me(a)gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <arch/io.h> +#include <console/console.h> +#include <device/pci.h> +#include <device/pciexp.h> +#include <device/pci_ids.h> + +static void dump_pci_device(device_t dev) +{ + int i; + for (i = 0; i <= 255; i++) { + unsigned char val; + if ((i & 0x0f) == 0) { + print_debug_hex8(i); + print_debug_char(':'); + } + val = pci_read_config8(dev, i); + if ((i & 7) == 0) + print_debug(" |"); + print_debug_char(' '); + print_debug_hex8(val); + if ((i & 0x0f) == 0x0f) { + print_debug("\n"); + } + } +} + +static void vx900_pcie_link_init(device_t dev) +{ + u8 reg8; + u32 reg32; + + u8 fn = dev->path.pci.devfn & 0x07; + + /* Step 1 : Check for presence of PCIE device */ + reg8 = pci_read_config8(dev, 0x5a); + + if (reg8 & (1 << 6) ) + printk(BIOS_DEBUG, "Card detected in PEX%i\n", fn); + else + return; + + /* Step 2: Wait for device to enter L0 state */ + while (0x8a != pci_read_config8(dev, 0x1c3)); + + /* Step 3: Clear PCIe error status, then check for failures */ + pci_write_config32(dev, 0x104, 0xffffffff); + reg32 = pci_read_config32(dev, 0x104); + if (0 != reg32) { + printk(BIOS_DEBUG, "PEX init error. flags 0x%.8x\n", reg32); + return; + } + + pci_write_config32(dev, 0x110, 0xffffffff); + reg32 = pci_read_config32(dev, 0x110); + if (0 != reg32) + printk(BIOS_DEBUG, "PEX errors. flags 0x%.8x\n", reg32); + + pci_write_config8(dev, 0xa4, 0xff); + if (pci_read_config8(dev, 0x4a) & (1 << 3)) + print_debug("Unsupported request detected.\n"); + + pci_write_config8(dev, 0x15a, 0xff); + if (pci_read_config8(dev, 0x15a) & (1 << 1)) + print_debug("Negotiation pending.\n"); + + /* Step 4: Read vendor ID */ + +} + +static void vx900_pex_dev_set_resources(device_t dev) +{ + //print_debug("======================================================\n"); + //print_debug("== PEX set\n"); + //print_debug("======================================================\n"); + + assign_resources(dev->link_list); +} + +static void vx900_pex_init(device_t dev) +{ + //print_debug("======================================================\n"); + //print_debug("== PEX init\n"); + //print_debug("======================================================\n"); + + if ((dev->path.pci.devfn & 0x7) == 0) + return; + vx900_pcie_link_init(dev); + + if (0) dump_pci_device(dev); +} + +static struct device_operations vx900_pex_ops = { + .read_resources = pci_bus_read_resources, + .set_resources = vx900_pex_dev_set_resources, + .enable_resources = pci_bus_enable_resources, + .init = vx900_pex_init, + .scan_bus = pciexp_scan_bridge, + .reset_bus = pci_bus_reset, +}; + +static const struct pci_driver pex1_driver __pci_driver = { + .ops = &vx900_pex_ops, + .vendor = PCI_VENDOR_ID_VIA, + .device = PCI_DEVICE_ID_VIA_VX900_PEX1, +}; + +static const struct pci_driver pex2_driver __pci_driver = { + .ops = &vx900_pex_ops, + .vendor = PCI_VENDOR_ID_VIA, + .device = PCI_DEVICE_ID_VIA_VX900_PEX2, +}; + +static const struct pci_driver pex3_driver __pci_driver = { + .ops = &vx900_pex_ops, + .vendor = PCI_VENDOR_ID_VIA, + .device = PCI_DEVICE_ID_VIA_VX900_PEX3, +}; + +static const struct pci_driver pex4_driver __pci_driver = { + .ops = &vx900_pex_ops, + .vendor = PCI_VENDOR_ID_VIA, + .device = PCI_DEVICE_ID_VIA_VX900_PEX4, +}; diff --git a/src/northbridge/via/vx900/raminit.h b/src/northbridge/via/vx900/raminit.h new file mode 100644 index 0000000..c599c0f --- /dev/null +++ b/src/northbridge/via/vx900/raminit.h @@ -0,0 +1,100 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011 Alexandru Gagniuc <mr.nuke.me(a)gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef RAMINIT_VX900_H +#define RAMINIT_VX900_H + +#include <device/dram/ddr3.h> +#include "vx900.h" + +#define SPD_END_LIST 0xff + +typedef struct dimm_layout_st +{ + /* The address of the DIMM on the SMBUS * + * 0xFF to terminate the array*/ + u8 spd_addr[VX900_MAX_DIMM_SLOTS + 1]; +} dimm_layout; + +typedef struct dimm_info_st +{ + dimm_attr dimm[VX900_MAX_DIMM_SLOTS]; +} dimm_info; + +typedef struct mem_rank_st { + u16 start_addr; + u16 end_addr; +} mem_rank; + +typedef struct rank_layout_st { + u32 phys_rank_size_mb[VX900_MAX_MEM_RANKS]; + mem_rank virt[VX900_MAX_MEM_RANKS]; + dimm_flags_t flags[VX900_MAX_MEM_RANKS]; +} rank_layout; + +typedef struct pci_reg8_st { + u8 addr; + u8 val; +} pci_reg8; + +typedef u8 timing_dly[8]; + +typedef struct delay_range_st { + timing_dly low; + timing_dly avg; + timing_dly high; +} delay_range; + +typedef struct vx900_delay_calib_st { + delay_range rx_dq_cr; + delay_range rx_dqs; + /* Transmit delays are calibrated for each dimm */ + delay_range tx_dq[VX900_MAX_DIMM_SLOTS]; + delay_range tx_dqs[VX900_MAX_DIMM_SLOTS]; +} vx900_delay_calib; + +typedef struct ramctr_timing_st { + enum spd_memory_type dram_type; + u16 cas_supported; + /* tLatencies are in units of ns, scaled by x256 */ + u32 tCK; + u32 tAA; + u32 tWR; + u32 tRCD; + u32 tRRD; + u32 tRP; + u32 tRAS; + u32 tRC; + u32 tRFC; + u32 tWTR; + u32 tRTP; + u32 tFAW; + /* Latencies in terms of clock cycles + * They are saved separately as they are needed for DRAM MRS commands*/ + u8 CAS; /* CAS read latency */ + u8 CWL; /* CAS write latency */ + u8 WR; /* write recovery time */ + /* Number of dimms currently connected */ + u8 n_dimms; + +} ramctr_timing; + +void vx900_init_dram_ddr3(const dimm_layout *dimms); + +#endif /* RAMINIT_VX900_H */ diff --git a/src/northbridge/via/vx900/raminit_ddr3.c b/src/northbridge/via/vx900/raminit_ddr3.c new file mode 100644 index 0000000..796f25d --- /dev/null +++ b/src/northbridge/via/vx900/raminit_ddr3.c @@ -0,0 +1,1536 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011-2012 Alexandru Gagniuc <mr.nuke.me(a)gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "early_vx900.h" +#include "raminit.h" +#include <arch/io.h> +#include <arch/io.h> +#include <console/console.h> +#include <device/pci_ids.h> +#include <delay.h> +#include <lib.h> +#include <string.h> + +/* Map BA0 <-> A17, BA1 <-> A18 */ +/* Map BA2 <-> A19, RA0/RA1 must not overlap BA[0:2] */ +#define VX900_MRS_MA_MAP 0x4b33 /* MA Pin Mapping for MRS commands */ +#define VX900_CALIB_MA_MAP 0x5911 /* MA Pin mapping for calibrations */ + +/* Registers 0x78 -> 0x7f contain calibration the settings for DRAM IO timing + * The dataset in these registers is selected from 0x70. + * Once the correct dataset is selected the delays can be altered. + * delay_type refers to TxDQS, TxDQ, RxDQS, or RxCR + * bound refers to either manual, average, upper bound, or lower bound + */ +#define CALIB_TxDQS 0 +#define CALIB_TxDQ 1 +#define CALIB_RxDQS 2 +#define CALIB_RxDQ_CR 3 + +#define CALIB_AVERAGE 0 +#define CALIB_LOWER 1 +#define CALIB_UPPER 2 +#define CALIB_MANUAL 4 + +static void vx900_delay_calib_mode_select(u8 delay_type, u8 bound) +{ + /* Which calibration setting */ + u8 reg8 = (delay_type & 0x03) << 2; + /* Upper, lower, average, or manual setting */ + reg8 |= (bound & 0x03); + pci_write_config8(MCU, 0x70, reg8); +} + +static void vx900_read_0x78_0x7f(timing_dly dly) +{ + *((u32 *) (&(dly[0]))) = pci_read_config32(MCU, 0x78); + *((u32 *) (&(dly[4]))) = pci_read_config32(MCU, 0x7c); +} + +static void vx900_write_0x78_0x7f(const timing_dly dly) +{ + pci_write_config32(MCU, 0x78, *((u32 *) (&(dly[0])))); + pci_write_config32(MCU, 0x7c, *((u32 *) (&(dly[4])))); +} + +static void vx900_read_delay_range(delay_range * d_range, u8 mode) +{ + vx900_delay_calib_mode_select(mode, CALIB_LOWER); + vx900_read_0x78_0x7f(d_range->low); + vx900_delay_calib_mode_select(mode, CALIB_AVERAGE); + vx900_read_0x78_0x7f(d_range->avg); + vx900_delay_calib_mode_select(mode, CALIB_UPPER); + vx900_read_0x78_0x7f(d_range->high); +} + +static void dump_delay(const timing_dly dly) +{ + u8 i; + for (i = 0; i < 8; i++) { + printram(" %.2x", dly[i]); + } + printram("\n"); +} + +static void dump_delay_range(const delay_range d_range) +{ + printram("Lower limit: "); + dump_delay(d_range.low); + printram("Average: "); + dump_delay(d_range.avg); + printram("Upper limit: "); + dump_delay(d_range.high); +} + +/* These are some "safe" values that can be used for memory initialization. + * Some will stay untouched, and others will be overwritten later on + * YOU REALLY NEED THE DATASHEET TO UNDERSTAND THESE !!! */ +static pci_reg8 mcu_init_config[] = { + {0x40, 0x01}, /* Virtual rank 0 ending address = 64M - 1 */ + {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00}, /* Virtual Ranks ending */ + {0x48, 0x00}, /* Virtual rank 0 starting address = 0 */ + {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00}, /* Virtual Ranks beginning */ + {0x50, 0xd8}, /* Set ranks 0-3 to 11 col bits, 16 row bits */ + /* Disable all virtual ranks */ + {0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00}, + /* Disable rank interleaving in ranks 0-3 */ + {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00}, + {0x6c, 0xA0}, /* Memory type: DDR3, VDIMM: 1.5V, 64-bit DRAM */ + {0xc4, 0x80}, /* Enable 8 memory banks */ + {0xc6, 0x80}, /* Minimum latency from self-refresh. Bit [7] must be 1 */ + /* FIXME: do it here or in Final config? */ + {0xc8, 0x80}, /* Enable automatic triggering of short ZQ calibration */ + {0x99, 0xf0}, /* Power Management and Bypass Reorder Queue */ + /* Enable differential DQS; MODT assertion values suggested in DS */ + {0x9e, 0xa1}, {0x9f, 0x51}, + /* DQ/DQM Duty Control - Do not put any extra delays */ + {0xe9, 0x00}, {0xea, 0x00}, {0xeb, 0x00}, {0xec, 0x00}, + {0xed, 0x00}, {0xee, 0x00}, {0xef, 0x00}, + {0xfc, 0x00}, {0xfd, 0x00}, {0xfe, 0x00}, {0xff, 0x00}, + /* The following parameters we may or may not change */ + {0x61, 0x2e}, /* DRAMC Pipeline Control */ + {0x77, 0x10}, /* MDQS Output Control */ + + /* The following are parameters we'll most likely never change again */ + {0x60, 0xf4}, /* DRAM Pipeline Turn-Around Setting */ + {0x65, 0x49}, /* DRAM Arbitration Bandwidth Timer - I */ + {0x66, 0x80}, /* DRAM Queue / Arbitration */ + {0x69, 0xc6}, /* Bank Control: 8 banks, high priority refresh */ + {0x6a, 0xfc}, /* DRAMC Request Reorder Control */ + {0x6e, 0x38}, /* Burst lenght: 8, burst-chop: enable */ + {0x73, 0x04}, /* Close All Pages Threshold */ + + /* The following need to be dynamically asserted */ + /* See: check_special_registers.c */ + {0x74, 0xa0}, /* Yes, same 0x74; add one more T */ + {0x76, 0x60}, /* Write Data Phase Control */ + +}; + +/* This table keeps the driving strength control setting that we can safely use + * doring initialization. */ +static pci_reg8 mcu_drv_ctrl_config[] = { + {0xd3, 0x03}, /* Enable auto-compensation circuit for ODT strength */ + {0xd4, 0x80}, /* Set internal ODT to dynamically turn on or off */ + {0xd6, 0x20}, /* Enable strong driving for MA and DRAM commands */ + {0xd0, 0x88}, /* (ODT) Strength ?has effect? */ + {0xe0, 0x88}, /* DRAM Driving – Group DQS (MDQS) */ + {0xe1, 0x00}, /* Disable offset mode for driving strength control */ + {0xe2, 0x88}, /* DRAM Driving – Group DQ (MD, MDQM) */ + {0xe4, 0xcc}, /* DRAM Driving – Group CSA (MCS, MCKE, MODT) */ + {0xe8, 0x88}, /* DRAM Driving – Group MA (MA, MBA, MSRAS, MSCAS, MSWE) */ + {0xe6, 0xff}, /* DRAM Driving – Group DCLK0 (DCLK[2:0] for DIMM0) */ + {0xe7, 0xff}, /* DRAM Driving – Group DCLK1 (DCLK[5:3] for DIMM1) */ + {0xe4, 0xcc}, /* DRAM Driving – Group CSA (MCS, MCKE, MODT) */ + {0x91, 0x08}, /* MCLKO Output Phase Delay - I */ + {0x92, 0x08}, /* MCLKO Output Phase Delay - II */ + {0x93, 0x16}, /* CS/CKE Output Phase Delay */ + {0x95, 0x16}, /* SCMD/MA Output Phase Delay */ + {0x9b, 0x3f}, /* Memory Clock Output Enable */ +}; + +static void vx900_dram_set_ma_pin_map(u16 map) +{ + pci_write_config16(MCU, 0x52, map); +} + +static void vx900_dram_map_pins(u8 ba0, u8 ba1, u8 ba2, u8 ra0, u8 ra1) +{ + u16 map = 0; + + printram("Mapping address pins to DRAM pins:\n"); + printram(" BA0 -> A%u\n", ba0); + printram(" BA1 -> A%u\n", ba1); + printram(" BA2 -> A%u\n", ba2); + printram(" RA0 -> A%u\n", ra0); + printram(" RA1 -> A%u\n", ra1); + /* Make sure BA2 is enabled */ + map |= (1 << 11); + + /* + * Find RA1 (15:14) + * 00: A14 + * 01: A16 + * 10: A18 + * 11: A20 + */ + if ((ra1 & 0x01) || (ra1 < 14) || (ra1 > 20)) { + printram("Illegal mapping RA1 -> A%u\n", ra1); + return; + } + map |= (((ra1 - 14) >> 1) & 0x03) << 14; + + /* + * Find RA0 (13:12) + * 00: A15 + * 01: A17 + * 10: A19 + * 11: A21 + */ + if ((!(ra0 & 0x01)) || (ra0 < 15) || (ra0 > 21)) { + printram("Illegal mapping RA0 -> A%u\n", ra0); + return; + } + map |= (((ra0 - 15) >> 1) & 0x03) << 12; + + /* + * Find BA2 (10:8) + * x00: A14 + * x01: A15 + * x10: A18 + * x11: A19 + */ + switch (ba2) { + case 14: + map |= (0 << 8); + break; + case 15: + map |= (1 << 8); + break; + case 18: + map |= (2 << 8); + break; + case 19: + map |= (3 << 8); + break; + default: + printram("Illegal mapping BA2 -> A%u\n", ba2); + break; + } + + /* + * Find BA1 (6:4) + * 000: A12 + * 001: A14 + * 010: A16 + * 011: A18 + * 1xx: A20 + */ + if (((ba1 & 0x01)) || (ba1 < 12) || (ba1 > 20)) { + printram("Illegal mapping BA1 -> A%u\n", ba1); + return; + } + map |= (((ba1 - 12) >> 1) & 0x07) << 4; + + /* + * Find BA0 (2:0) + * 000: A11 + * 001: A13 + * 010: A15 + * 011: A17 + * 1xx: A19 + */ + if ((!(ba0 & 0x01)) || (ba0 < 11) || (ba0 > 19)) { + printram("Illegal mapping BA0 -> A%u\n", ba0); + return; + } + map |= (((ba0 - 11) >> 1) & 0x07) << 0; + + printram("Setting map mask (rx52) to %.4x\n", map); + vx900_dram_set_ma_pin_map(map); +} + +static void vx900_dram_write_init_config(void) +{ + /* Keep our RAM space free of legacy stuff */ + vx900_disable_legacy_rom_shadow(); + + /* Now worry about the real RAM init */ + size_t i; + for (i = 0; i < (sizeof(mcu_init_config) / sizeof(pci_reg8)); i++) { + pci_write_config8(MCU, mcu_init_config[i].addr, + mcu_init_config[i].val); + } + vx900_dram_set_ma_pin_map(VX900_CALIB_MA_MAP); + + /* FIXME: Slowing stuff down. Does this really help? */ + + //Fast cycle control for CPU-to-DRAM Read Cycle 0:Disabled. This CPU bus controller will wait for all data + //pci_mod_config8(HOST_BUS, 0x51, (1 << 7), 0); + //Memory to CPU bus Controller Conversion Mode 1: Synchronous mode + //pci_mod_config8(HOST_BUS, 0x54, 0, (1 << 1)); +} + +static void dram_find_spds_ddr3(const dimm_layout * addr, dimm_info * dimm) +{ + size_t i = 0; + int dimms = 0; + do { + spd_raw_data spd; + spd_read(addr->spd_addr[i], spd); + spd_decode_ddr3(&dimm->dimm[i], spd); + if (dimm->dimm[i].dram_type != SPD_MEMORY_TYPE_SDRAM_DDR3) + continue; + dimms++; + dram_print_spd_ddr3(&dimm->dimm[i]); + } while (addr->spd_addr[++i] != SPD_END_LIST + && i < VX900_MAX_DIMM_SLOTS); + + if (!dimms) + die("No DIMMs were found"); +} + +static void dram_find_common_params(const dimm_info * dimms, + ramctr_timing * ctrl) +{ + size_t i, valid_dimms; + memset(ctrl, 0, sizeof(ramctr_timing)); + ctrl->cas_supported = 0xff; + valid_dimms = 0; + for (i = 0; i < VX900_MAX_DIMM_SLOTS; i++) { + const dimm_attr *dimm = &dimms->dimm[i]; + if (dimm->dram_type == SPD_MEMORY_TYPE_UNDEFINED) + continue; + valid_dimms++; + + if (valid_dimms == 1) { + /* First DIMM defines the type of DIMM */ + ctrl->dram_type = dimm->dram_type; + } else { + /* Check if we have mismatched DIMMs */ + if (ctrl->dram_type != dimm->dram_type) + die("Mismatched DIMM Types"); + } + /* Find all possible CAS combinations */ + ctrl->cas_supported &= dimm->cas_supported; + + /* Find the smallest common latencies supported by all DIMMs */ + ctrl->tCK = max(ctrl->tCK, dimm->tCK); + ctrl->tAA = max(ctrl->tAA, dimm->tAA); + ctrl->tWR = max(ctrl->tWR, dimm->tWR); + ctrl->tRCD = max(ctrl->tRCD, dimm->tRCD); + ctrl->tRRD = max(ctrl->tRRD, dimm->tRRD); + ctrl->tRP = max(ctrl->tRP, dimm->tRP); + ctrl->tRAS = max(ctrl->tRAS, dimm->tRAS); + ctrl->tRC = max(ctrl->tRC, dimm->tRC); + ctrl->tRFC = max(ctrl->tRFC, dimm->tRFC); + ctrl->tWTR = max(ctrl->tWTR, dimm->tWTR); + ctrl->tRTP = max(ctrl->tRTP, dimm->tRTP); + ctrl->tFAW = max(ctrl->tFAW, dimm->tFAW); + + } + + ctrl->n_dimms = valid_dimms; + if (!ctrl->cas_supported) + die("Unsupported DIMM combination. " + "DIMMS do not support common CAS latency"); + if (!valid_dimms) + die("No valid DIMMs found"); +} + +static void vx900_dram_phys_bank_range(const dimm_info * dimms, + rank_layout * ranks) +{ + size_t i; + for (i = 0; i < VX900_MAX_DIMM_SLOTS; i++) { + if (dimms->dimm[i].dram_type == SPD_MEMORY_TYPE_UNDEFINED) + continue; + u8 nranks = dimms->dimm[i].ranks; + /* Make sure we save the flags */ + ranks->flags[i * 2 + 1] = ranks->flags[i * 2] = + dimms->dimm[i].flags; + /* Only Rank1 has a mirrored pin mapping */ + ranks->flags[i * 2].pins_mirrored = 0; + if (nranks > 2) + die("Found DIMM with more than two ranks, which is not " + "supported by this chipset"); + u32 size = dimms->dimm[i].size_mb; + if (nranks == 2) { + /* Each rank holds half the capacity of the DIMM */ + size >>= 1; + ranks->phys_rank_size_mb[i << 1] = size; + ranks->phys_rank_size_mb[(i << 1) | 1] = size; + } else { + /* Otherwise, everything is held in the first bank */ + ranks->phys_rank_size_mb[i << 1] = size; + ranks->phys_rank_size_mb[(i << 1) | 1] = 0;; + } + } +} + +#define Rank0_ODT 0 +#define Rank1_ODT 1 +#define Rank2_ODT 2 +#define Rank3_ODT 3 +/* + * This is the table that tells us which ODT pin to map to which rank. + * + * This table is taken from code provided by VIA, but no explanation was + * provided as to why it is done this way. It may be possible that this table is + * not suitable for the way we map ranks later on. + */ +static const u8 odt_lookup_table[][2] = { + /* RankMAP Rank 3 Rank 2 Rank 1 Rank 0 */ + { 0x01, (Rank3_ODT << 6) | (Rank2_ODT << 4) | (Rank1_ODT << 2) | Rank0_ODT}, + { 0x03, (Rank3_ODT << 6) | (Rank2_ODT << 4) | (Rank0_ODT << 2) | Rank1_ODT}, + { 0x04, (Rank3_ODT << 6) | (Rank2_ODT << 4) | (Rank1_ODT << 2) | Rank0_ODT}, + { 0x05, (Rank3_ODT << 6) | (Rank0_ODT << 4) | (Rank1_ODT << 2) | Rank2_ODT}, + { 0x07, (Rank3_ODT << 6) | (Rank0_ODT << 4) | (Rank2_ODT << 2) | Rank2_ODT}, + { 0x0c, (Rank2_ODT << 6) | (Rank3_ODT << 4) | (Rank1_ODT << 2) | Rank0_ODT}, + { 0x0d, (Rank0_ODT << 6) | (Rank0_ODT << 4) | (Rank1_ODT << 2) | Rank2_ODT}, + { 0x0f, (Rank0_ODT << 6) | (Rank0_ODT << 4) | (Rank2_ODT << 2) | Rank2_ODT}, + { 0, 0}, +}; + +static void vx900_dram_driving_ctrl(const dimm_info * dimm) +{ + size_t i, ndimms; + u8 reg8, regxd5, rank_mask; + + rank_mask = 0; + /* For ODT range selection, datasheet recommends + * when 1 DIMM present: 60 Ohm + * when 2 DIMMs present: 120 Ohm */ + ndimms = 0; + for (i = 0; i < VX900_MAX_DIMM_SLOTS; i++) { + if (dimm->dimm[i].dram_type != SPD_MEMORY_TYPE_SDRAM_DDR3) + continue; + ndimms++; + rank_mask |= (1 << (i * 2)); + if (dimm->dimm[i].ranks > 1) + rank_mask |= (2 << (i * 2)); + } + /* ODT strength and MD/MDQM/MDQS driving strength */ + if (ndimms > 1) { + /* Enable 1 ODT block (120 Ohm ODT) */ + regxd5 = 0 << 2; + /* Enable strong driving for MD/MDQM/MDQS */ + regxd5 |= (1 << 7); + } else { + /* Enable 2 ODT blocks (60 Ohm ODT) */ + regxd5 = 1 << 2; + /* Leave MD/MDQM/MDQS driving weak */ + } + pci_write_config8(MCU, 0xd5, regxd5); + + /* Enable strong CLK driving for DIMMs with more than one rank */ + if (dimm->dimm[0].ranks > 1) + pci_mod_config8(MCU, 0xd6, 0, (1 << 7)); + if (dimm->dimm[1].ranks > 1) + pci_mod_config8(MCU, 0xd6, 0, (1 << 6)); + + /* DRAM ODT Lookup Table */ + for (i = 0; ; i++) + { + if (odt_lookup_table[i][0] == 0) { + printram("No ODT entry for rank mask %x\n", rank_mask); + die("Aborting"); + } + if (odt_lookup_table[i][0] != rank_mask) + continue; + + reg8 = odt_lookup_table[i][1]; + break; + } + + printram("Mapping rank mask %x to ODT entry %.2x\n", rank_mask, reg8); + pci_write_config8(MCU, 0x9c, reg8); + + + for (i = 0; i < (sizeof(mcu_drv_ctrl_config) / sizeof(pci_reg8)); i++) { + pci_write_config8(MCU, mcu_drv_ctrl_config[i].addr, + mcu_drv_ctrl_config[i].val); + } +} + +static void vx900_pr_map_all_vr3(void) +{ + /* Enable all ranks and set them to VR3 */ + pci_write_config16(MCU, 0x54, 0xbbbb); +} + +/* Map physical rank pr to virtual rank vr */ +static void vx900_map_pr_vr(u8 pr, u8 vr) +{ + u16 val; + + pr &= 0x3; + vr &= 0x3; + /* Enable rank (bit [3], and set the VR number bits [1:0] */ + val = 0x8 | vr; + /* Now move the value to the appropriate PR */ + val <<= (pr * 4); + pci_mod_config16(MCU, 0x54, 0xf << (pr * 4), val); + printram("Mapping PR %u to VR %u\n", pr, vr); +} + +static u8 vx900_get_CWL(u8 CAS) +{ + /* Get CWL based on CAS using the following rule: + * _________________________________________ + * CAS: | 4T | 5T | 6T | 7T | 8T | 9T | 10T | 11T | + * CWL: | 5T | 5T | 5T | 6T | 6T | 7T | 7T | 8T | + */ + static const u8 cas_cwl_map[] = { 5, 5, 5, 6, 6, 7, 7, 8 }; + if (CAS > 11) + return 8; + return cas_cwl_map[CAS - 4]; +} + +static void vx900_dram_timing(ramctr_timing * ctrl) +{ + /* Here we are calculating latencies, and writing them to the appropiate + * registers. Some registers do not take latencies from 0T, for example: + * CAS: 000 = 4T, 001 = 5T, 010 = 6T, etc + * In this example we subtract 4T from the result for CAS: (val - 4) + * The & 0x07 after (val - T0) just makes sure that, no matter what + * crazy thing may happen, we do not write outside the bits allocated + * in the register */ + u8 reg8, val, tFAW, tRRD; + u32 val32; + + /* Maximum supported DDR3 frequency is 533MHz (DDR3 1066) so make sure + * we cap it if we have faster DIMMs. + * Then, align it to the closest JEDEC standard frequency */ + if (ctrl->tCK <= TCK_533MHZ) { + ctrl->tCK = TCK_533MHZ; + } else if (ctrl->tCK <= TCK_400MHZ) { + ctrl->tCK = TCK_400MHZ; + } else if (ctrl->tCK <= TCK_333MHZ) { + ctrl->tCK = TCK_333MHZ; + } else { + ctrl->tCK = TCK_266MHZ; + } + + val32 = (1000 << 8) / ctrl->tCK; + printram("Selected DRAM frequency: %u MHz\n", val32); + + /* Find CAS and CWL latencies */ + val = (ctrl->tAA + ctrl->tCK - 1) / ctrl->tCK; + printram("Minimum CAS latency : %uT\n", val); + /* Find lowest supported CAS latency that satisfies the minimum value */ + while (!((ctrl->cas_supported >> (val - 4)) & 1) + && (ctrl->cas_supported >> (val - 4))) { + val++; + } + /* Is CAS supported */ + if (!(ctrl->cas_supported & (1 << (val - 4)))) + printram("CAS not supported\n"); + printram("Selected CAS latency : %uT\n", val); + ctrl->CAS = val; + ctrl->CWL = vx900_get_CWL(ctrl->CAS); + printram("Selected CWL latency : %uT\n", ctrl->CWL); + /* Write CAS and CWL */ + reg8 = (((ctrl->CWL - 4) & 0x07) << 4) | ((ctrl->CAS - 4) & 0x07); + pci_write_config8(MCU, 0xc0, reg8); + + /* Find tRCD */ + val = (ctrl->tRCD + ctrl->tCK - 1) / ctrl->tCK; + printram("Selected tRCD : %uT\n", val); + reg8 = ((val - 4) & 0x7) << 4; + /* Find tRP */ + val = (ctrl->tRP + ctrl->tCK - 1) / ctrl->tCK; + printram("Selected tRP : %uT\n", val); + reg8 |= ((val - 4) & 0x7); + pci_write_config8(MCU, 0xc1, reg8); + + /* Find tRAS */ + val = (ctrl->tRAS + ctrl->tCK - 1) / ctrl->tCK; + printram("Selected tRAS : %uT\n", val); + reg8 = ((val - 15) & 0x7) << 4; + /* Find tWR */ + ctrl->WR = (ctrl->tWR + ctrl->tCK - 1) / ctrl->tCK; + printram("Selected tWR : %uT\n", ctrl->WR); + reg8 |= ((ctrl->WR - 4) & 0x7); + pci_write_config8(MCU, 0xc2, reg8); + + /* Find tFAW */ + tFAW = (ctrl->tFAW + ctrl->tCK - 1) / ctrl->tCK; + printram("Selected tFAW : %uT\n", tFAW); + /* Find tRRD */ + tRRD = (ctrl->tRRD + ctrl->tCK - 1) / ctrl->tCK; + printram("Selected tRRD : %uT\n", tRRD); + val = tFAW - 4 * tRRD; /* number of cycles above 4*tRRD */ + reg8 = ((val - 0) & 0x7) << 4; + reg8 |= ((tRRD - 2) & 0x7); + pci_write_config8(MCU, 0xc3, reg8); + + /* Find tRTP */ + val = (ctrl->tRTP + ctrl->tCK - 1) / ctrl->tCK; + printram("Selected tRTP : %uT\n", val); + reg8 = ((val & 0x3) << 4); + /* Find tWTR */ + val = (ctrl->tWTR + ctrl->tCK - 1) / ctrl->tCK; + printram("Selected tWTR : %uT\n", val); + reg8 |= ((val - 2) & 0x7); + pci_mod_config8(MCU, 0xc4, 0x3f, reg8); + + /* DRAM Timing for All Ranks - VI + * [7:6] CKE Assertion Minimum Pulse Width + * We probably don't want to mess with this just yet. + * [5:0] Refresh-to-Active or Refresh-to-Refresh (tRFC) + * tRFC = (30 + 2 * [5:0])T + * Since we previously set RxC4[7] + */ + reg8 = pci_read_config8(MCU, 0xc5); + val = (ctrl->tRFC + ctrl->tCK - 1) / ctrl->tCK; + printram("Minimum tRFC : %uT\n", val); + if (val < 30) { + val = 0; + } else { + val = (val - 30 + 1) / 2; + } + ; + printram("Selected tRFC : %uT\n", 30 + 2 * val); + reg8 |= (val & 0x3f); + pci_write_config8(MCU, 0xc5, reg8); + + /* Where does this go??? */ + val = (ctrl->tRC + ctrl->tCK - 1) / ctrl->tCK; + printram("Required tRC : %uT\n", val); +} + +static void vx900_dram_freq(ramctr_timing * ctrl) +{ + u8 val; + + /* Program the DRAM frequency */ + + /* Step 1 - Reset the PLL */ + pci_mod_config8(MCU, 0x90, 0x00, 0x0f); + /* Wait at least 10 ns; VIA code delays by 640us */ + udelay(640); + + /* Step 2 - Set target frequency */ + if (ctrl->tCK <= TCK_533MHZ) { + val = 0x07; + ctrl->tCK = TCK_533MHZ; + } else if (ctrl->tCK <= TCK_400MHZ) { + val = 0x06; + ctrl->tCK = TCK_400MHZ; + } else if (ctrl->tCK <= TCK_333MHZ) { + val = 0x05; + ctrl->tCK = TCK_333MHZ; + } else { /*ctrl->tCK <= TCK_266MHZ */ + val = 0x04; + ctrl->tCK = TCK_266MHZ; + } + /* Restart the PLL with the desired frequency */ + pci_mod_config8(MCU, 0x90, 0x0f, val); + + /* Step 3 - Wait for PLL to stabilize */ + udelay(2000); + + /* Step 4 - Reset the DLL - Clear [7,4] */ + pci_mod_config8(MCU, 0x6b, 0x90, 0x00); + udelay(2000); + + /* Step 5 - Enable the DLL - Set bits [7,4] to 01b */ + pci_mod_config8(MCU, 0x6b, 0x00, 0x10); + udelay(2000); + + /* Step 6 - Start DLL Calibration - Set bit [7] */ + pci_mod_config8(MCU, 0x6b, 0x00, 0x80); + udelay(5); + + /* Step 7 - Finish DLL Calibration - Clear bit [7] */ + pci_mod_config8(MCU, 0x6b, 0x80, 0x00); + + /* Step 8 - If we have registered DIMMs, we need to set bit[0] */ + if (dimm_is_registered(ctrl->dram_type)) { + printram("Enabling RDIMM support in memory controller\n"); + pci_mod_config8(MCU, 0x6c, 0x00, 0x01); + } +} + +static void vx900_dram_ddr3_do_hw_mrs(u8 ma_swap, u8 rtt_nom, + u8 ods, u8 rtt_wr, u8 srt, u8 asr) +{ + /* The VX900 can send the MRS commands directly through hardware + * It does the MR2->MR3->MR1->MR0->LongZQ dance */ + u16 reg16 = 0; + + printram("Using Hardware method for DRAM MRS commands.\n"); + + if (asr) + reg16 |= (1 << 8); + if (srt) + reg16 |= (1 << 9); + reg16 |= ((rtt_wr & 0x03) << 12); + if (ma_swap) + reg16 |= (1 << 1); + reg16 |= ((ods & 0x03) << 2); + reg16 |= ((rtt_nom & 0x7) << 4); + reg16 |= 1; /* This is the trigger bit */ + printram("Hw MRS set is 0x%4x\n", reg16); + pci_write_config16(MCU, 0xcc, reg16); + /* Wait for MRS commands to be sent */ + while (pci_read_config8(MCU, 0xcc) & 1) ; +} + +#include "ddr3_mrs_util.h" +#include "ddr3_mrs_util.c" + +static void vx900_dram_ddr3_do_sw_mrs(u8 ma_swap, enum ddr3_mr1_rtt_nom rtt_nom, + enum ddr3_mr1_ods ods, + enum ddr3_mr2_rttwr rtt_wr, + enum ddr3_mr2_srt_range srt, + enum ddr3_mr2_asr asr) +{ + mrs_cmd_t mrs; + u8 reg8, cas, cwl, twr; + + printram("Using Software method for DRAM MRS commands.\n"); + + /* Get CAS, CWL, and tWR that we programmed earlier */ + reg8 = pci_read_config8(MCU, 0xc0); + cas = (reg8 & 0x07) + 4; + cwl = ((reg8 >> 4) & 0x07) + 4; + reg8 = pci_read_config8(MCU, 0xc2); + twr = (reg8 & 0x07) + 4; + + /* Step 06 - Set Fun3_RX6B[2:0] to 001b (NOP Command Enable). */ + /* Was already done for us before calling us */ + + /* Step 07 - Read a double word from any address of the DIMM. */ + /* Was already done for us before calling us */ + + /* Step 08 - Set Fun3_RX6B[2:0] to 011b (MSR Enable). */ + pci_mod_config8(MCU, 0x6b, 0x07, 0x03); /* MSR Enable */ + + /* Step 09 – Issue MR2 cycle. Read a double word from the address + * depended on DRAM’s Rtt_WR and CWL settings. */ + mrs = ddr3_get_mr2(rtt_wr, srt, asr, cwl); + if (ma_swap) + mrs = ddr3_mrs_swap_pins(mrs); + volatile_read(vx900_get_mrs_addr(mrs)); + printram("MR2: %.5x\n", mrs); + + /* Step 10 – Issue MR3 cycle. Read a double word from the address 60000h + * to set DRAM to normal operation mode. */ + mrs = ddr3_get_mr3(0); + if (ma_swap) + mrs = ddr3_mrs_swap_pins(mrs); + volatile_read(vx900_get_mrs_addr(mrs)); + printram("MR3: %.5x\n", mrs); + + /* Step 11 –Issue MR1 cycle. Read a double word from the address + * depended on DRAM’s output driver impedance and Rtt_Nom settings. + * The DLL enable field, TDQS field, write leveling enable field, + * additive latency field and Qoff field should be set to 0. */ + mrs = ddr3_get_mr1(DDR3_MR1_QOFF_ENABLE, DDR3_MR1_TQDS_DISABLE, rtt_nom, + DDR3_MR1_WRLVL_DISABLE, ods, DDR3_MR1_AL_DISABLE, + DDR3_MR1_DLL_ENABLE); + if (ma_swap) + mrs = ddr3_mrs_swap_pins(mrs); + volatile_read(vx900_get_mrs_addr(mrs)); + printram("MR1: %.5x\n", mrs); + + /* Step 12 - Issue MR0 cycle. Read a double word from the address + * depended on DRAM’s burst length, CAS latency and write recovery time + * settings. + * The read burst type field should be set to interleave. + * The mode field should be set to normal mode. + * The DLL reset field should be set to No. + * The DLL control for precharge PD field should be set to Fast exit. + */ + mrs = ddr3_get_mr0(DDR3_MR0_PRECHARGE_FAST, twr, + DDR3_MR0_DLL_RESET_NO, DDR3_MR0_MODE_NORMAL, cas, + DDR3_MR0_BURST_TYPE_INTERLEAVED, + DDR3_MR0_BURST_LENGTH_CHOP); + volatile_read(vx900_get_mrs_addr(mrs)); + printram("MR0: %.5x\n", mrs); + + /* Step 13 - Set Fun3_RX6B[2:0] to 110b (Long ZQ calibration cmd) */ + pci_mod_config8(MCU, 0x6b, 0x07, 0x06); /* Long ZQ */ + /* Step 14 - Read a double word from any address of the DIMM. */ + volatile_read(0); + udelay(1000); +} + +static void vx900_dram_send_soft_mrs(mrs_cmd_t cmd, u8 pin_swap) +{ + u32 addr; + /* Set Fun3_RX6B[2:0] to 011b (MSR Enable). */ + pci_mod_config8(MCU, 0x6b, 0x07, (3 << 0)); + /* Is this a funky rank with Address pins swapped? */ + if (pin_swap) + cmd = ddr3_mrs_swap_pins(cmd); + /* Find the address corresponding to the MRS */ + addr = vx900_get_mrs_addr(cmd); + /* Execute the MRS */ + volatile_read(addr); + /* Set Fun3_Rx6B[2:0] to 000b (Normal SDRAM Mode). */ + pci_mod_config8(MCU, 0x6b, 0x07, 0x00); +} + +static void vx900_dram_ddr3_dimm_init(const ramctr_timing * ctrl, + const rank_layout * ranks) +{ + size_t i; + u8 rtt_nom, rtt_wr, ods, pinswap; + + /* Set BA[0/1/2] to [A17/18/19] */ + vx900_dram_set_ma_pin_map(VX900_MRS_MA_MAP); + + /* Step 01 - Set Fun3_Rx6E[5] to 1b to support burst length. */ + pci_mod_config8(MCU, 0x6e, 0, 1 << 5); + /* Step 02 - Set Fun3_RX69[0] to 0b (Disable Multiple Page Mode). */ + pci_mod_config8(MCU, 0x69, (1 << 0), 0x00); + /* And set [7:6] to 10b ? */ + pci_write_config8(MCU, 0x69, 0x87); + + /* Step 03 - Set the target physical rank to virtual rank0 and other + * ranks to virtual rank3. */ + vx900_pr_map_all_vr3(); + + /* Step 04 - Set Fun3_Rx50 to D8h. */ + pci_write_config8(MCU, 0x50, 0xd8); + /* Step 05 - Set Fun3_RX6B[5] to 1b to de-assert RESET# and wait for at + * least 500 us. */ + pci_mod_config8(MCU, 0x6b, 0x00, (1 << 5)); + udelay(500); + + /* Step 6 -> 15 - Set the target physical rank to virtual rank 0 and + * other ranks to virtual rank 3. + * Repeat Step 6 to 14 for every rank present, then jump to Step 16. */ + for (i = 0; i < VX900_MAX_MEM_RANKS; i++) { + if (ranks->phys_rank_size_mb[i] == 0) + continue; + printram("Initializing rank %lu\n", i); + + /* Set target physical rank to virtual rank 0 + * other ranks to virtual rank 3*/ + vx900_map_pr_vr(i, 0); + + /* FIXME: Is this needed on HW init? */ + pci_mod_config8(MCU, 0x6b, 0x07, 0x01); /* Enable NOP */ + volatile_read(0x0); /* Do NOP */ + pci_mod_config8(MCU, 0x6b, 0x07, 0x03); /* MSR Enable */ + + /* See init_dram_by_rank.c and get_basic_information.c + * in the VIA provided code */ + if (ctrl->n_dimms == 1) { + rtt_nom = DDR3_MR1_RTT_NOM_RZQ2; + rtt_wr = DDR3_MR2_RTTWR_OFF; + } else { + rtt_nom = DDR3_MR1_RTT_NOM_RZQ8; + rtt_wr = DDR3_MR2_RTTWR_RZQ2; + } + ods = ranks->flags[i].rzq7_supported ? + DDR3_MR1_ODS_RZQ7 : DDR3_MR1_ODS_RZQ6; + + pinswap = (ranks->flags[i].pins_mirrored); + if (pinswap) + printram("Pins mirrored\n"); + printram(" Swap : %x\n", pinswap); + printram(" rtt_nom : %x\n", rtt_nom); + printram(" ods : %x\n", ods); + printram(" rtt_wr : %x\n", rtt_wr); + if (0) + vx900_dram_ddr3_do_hw_mrs(pinswap, rtt_nom, ods, rtt_wr, 0, 0); + else + vx900_dram_ddr3_do_sw_mrs(pinswap, rtt_nom, ods, rtt_wr, 0, 0); + + /* Normal SDRAM Mode */ + pci_mod_config8(MCU, 0x6b, 0x07, 0x00); + + /* Step 15, set the rank to virtual rank 3 */ + vx900_map_pr_vr(i, 3); + } + + /* Step 16 – Set Fun3_Rx6B[2:0] to 000b (Normal SDRAM Mode). */ + pci_mod_config8(MCU, 0x6b, 0x07, 0x00); + + /* Set BA[0/1/2] to [A13/14/15] */ + vx900_dram_set_ma_pin_map(VX900_CALIB_MA_MAP); + + /* Step 17 – Set Fun3_Rx69[0] to 1b (Enable Multiple Page Mode). */ + pci_mod_config8(MCU, 0x69, 0x00, (1 << 0)); + + printram("DIMM initialization sequence complete\n"); +} + +static void vx900_dram_enter_read_leveling(u8 pinswap) +{ + /* Precharge all before issuing read leveling MRS to DRAM */ + pci_mod_config8(MCU, 0x06b, 0x07, 0x02); + volatile_read(0x0); + udelay(1000); + + /* Enable read leveling: Set D0F3Rx71[7]=1 */ + pci_mod_config8(MCU, 0x71, 0, (1 << 7)); + + /* Put DRAM in read leveling mode */ + mrs_cmd_t cmd = ddr3_get_mr3(1); + vx900_dram_send_soft_mrs(cmd, pinswap); +} + +static void vx900_dram_exit_read_leveling(u8 pinswap) +{ + /* Disable read leveling, and put dram in normal operation mode */ + mrs_cmd_t cmd = ddr3_get_mr3(0); + vx900_dram_send_soft_mrs(cmd, pinswap); + + /* Disable read leveling: Set D0F3Rx71[7]=0 */ + pci_mod_config8(MCU, 0x71, (1 << 7), 0); +} + +/* We need to see if the window (difference between minimum and maximum) is + * large enough so that we actually have a valid window. The signal should be + * valid for at least 1T in general. If the window is significantly smaller, + * then chances are our widow does not latch at the correct time, and the + * calibration will not work */ +#define DQSI_THRESHOLD 0x10 +#define DQO_THRESHOLD 0x09 +#define DQSO_THRESHOLD 0x12 +#define DELAY_RANGE_GOOD 0 +#define DELAY_RANGE_BAD -1 +static u8 vx900_dram_check_calib_range(const delay_range * dly, u8 window) +{ + size_t i; + for (i = 0; i < 8; i++) { + if (dly->high[i] - dly->low[i] < window) + return DELAY_RANGE_BAD; + /* When our maximum value is lower than our min, both values + * have overshot, and the window is definitely invalid */ + if (dly->high[i] < dly->low[i]) + return DELAY_RANGE_BAD; + } + return DELAY_RANGE_GOOD; +} + +static void vx900_dram_find_avg_delays(vx900_delay_calib * delays) +{ + size_t i; + u16 dq_low, dq_high, dqs_low, dqs_high, dq_final, dqs_final; + /* At this point, we have transmit delays for both DIMMA and DIMMB, each + * with a slightly different window We want to find the intersection of + * those windows, so that we have a constrained window which both + * DIMMA and DIMMB can use. The center of our constrained window will + * also be the safest setting for the transmit delays + * + * DIMMA window t:|xxxxxxxxxxxxxx---------------xxxxxxxxxxxxxxxxxxxxxxx| + * DIMMB window t:|xxxxxxxxxxxxxxxxxxx---------------xxxxxxxxxxxxxxxxxx| + * Safe window t:|xxxxxxxxxxxxxxxxxxx----------xxxxxxxxxxxxxxxxxxxxxxx| + */ + delay_range *tx_dq_a = &(delays->tx_dq[0]); + delay_range *tx_dq_b = &(delays->tx_dq[1]); + delay_range *tx_dqs_a = &(delays->tx_dqs[0]); + delay_range *tx_dqs_b = &(delays->tx_dqs[1]); + + for (i = 0; i < 8; i++) { + dq_low = max(tx_dq_a->low[i], tx_dq_b->low[i]); + dq_high = min(tx_dq_a->high[i], tx_dq_b->high[i]); + dqs_low = max(tx_dqs_a->low[i], tx_dqs_b->low[i]); + dqs_high = min(tx_dqs_a->high[i], tx_dqs_b->high[i]); + + /* Find the average */ + dq_final = ((dq_low + dq_high) / 2); + dqs_final = ((dqs_low + dqs_high) / 2); + + /* + * These adjustments are done in code provided by VIA. + * There is no explanation as to why this is done. + * + * We can get away without doing the DQS adjustment, but doing + * it, brings the values closer to what the vendor BIOS + * calibrates to. + */ + if ((dqs_final & 0x1f) >= 0x1c) + dqs_final -= 0x1c; + else + dqs_final += 0x04; + /* + * The DQ adjustment is more critical. If we don't do this + * adjustment our MCU won't be configured properly, and + * ram_check() will fail. + */ + if ((dq_final & 0x1f) >= 0x14) + dq_final -= 0x14; + else + dq_final += 0x0c; + + /* Store our values in the first delay */ + delays->tx_dq[0].avg[i] = dq_final; + delays->tx_dqs[0].avg[i] = dqs_final; + + } +} + +static void vx900_rx_capture_range_calib(u8 pinswap) +{ + u8 reg8; + const u32 cal_addr = 0x20; + + /* Set IO calibration address */ + pci_mod_config16(MCU, 0x8c, 0xfff0, cal_addr & (0xfff0)); + /* Data pattern must be 0x00 for this calibration + * See paragraph describing Rx8e */ + pci_write_config8(MCU, 0x8e, 0x00); + + /* Need to put DRAM and MCU in read leveling */ + vx900_dram_enter_read_leveling(pinswap); + + /* Data pattern must be 0x00 for this calibration + * See paragraph describing Rx8e */ + pci_write_config8(MCU, 0x8e, 0x00); + /* Trigger calibration */ + reg8 = 0xa0; + pci_write_config8(MCU, 0x71, reg8); + + /* Wait for it */ + while (pci_read_config8(MCU, 0x71) & 0x10) ; + vx900_dram_exit_read_leveling(pinswap); +} + +static void vx900_rx_dqs_delay_calib(u8 pinswap) +{ + const u32 cal_addr = 0x30; + + /* We need to disable refresh commands so that they don't interfere */ + const u8 ref_cnt = pci_read_config8(MCU, 0xc7); + pci_write_config8(MCU, 0xc7, 0); + /* Set IO calibration address */ + pci_mod_config16(MCU, 0x8c, 0xfff0, cal_addr & (0xfff0)); + /* Data pattern must be 0x00 for this calibration + * See paragraph describing Rx8e */ + pci_write_config8(MCU, 0x8e, 0x00); + + /* Need to put DRAM and MCU in read leveling */ + vx900_dram_enter_read_leveling(pinswap); + + /* From VIA code; Undocumented + * In theory this enables MODT[3:0] to be asserted */ + pci_mod_config8(MCU, 0x9e, 0, 0x80); + + /* Trigger calibration: Set D0F3Rx71[1:0]=10b */ + pci_mod_config8(MCU, 0x71, 0x03, 0x02); + + /* Wait for calibration to complete */ + while (pci_read_config8(MCU, 0x71) & 0x02) ; + vx900_dram_exit_read_leveling(pinswap); + + /* Restore the refresh counter */ + pci_write_config8(MCU, 0xc7, ref_cnt); + + /* FIXME: should we save it before, or should we just set it as is */ + vx900_dram_set_ma_pin_map(VX900_CALIB_MA_MAP); +} + +static void vx900_tx_dqs_trigger_calib(u8 pattern) +{ + /* Data pattern for calibration */ + pci_write_config8(MCU, 0x8e, pattern); + /* Trigger calibration */ + pci_mod_config8(MCU, 0x75, 0, 0x20); + /* Wait for calibration */ + while (pci_read_config8(MCU, 0x75) & 0x20) ; +} + +static void vx900_tx_dqs_delay_calib(void) +{ + const u32 cal_addr = 0x00; + /* Set IO calibration address */ + pci_mod_config16(MCU, 0x8c, 0xfff0, cal_addr & (0xfff0)); + /* Set circuit to use calibration results - Clear Rx75[0] */ + pci_mod_config8(MCU, 0x75, 0x01, 0); + /* Run calibration with first data pattern */ + vx900_tx_dqs_trigger_calib(0x5a); + /* Run again with different pattern */ + vx900_tx_dqs_trigger_calib(0xa5); +} + +static void vx900_tx_dq_delay_calib(void) +{ + /* Data pattern for calibration */ + pci_write_config8(MCU, 0x8e, 0x5a); + /* Trigger calibration */ + pci_mod_config8(MCU, 0x75, 0, 0x02); + /* Wait for calibration */ + while (pci_read_config8(MCU, 0x75) & 0x02) ; +} + +static void vx900_rxdqs_adjust(delay_range * dly) +{ + /* Adjust Rx DQS delay after calibration has been run. This is + * recommended by VIA, but no explanation was provided as to why */ + size_t i; + for (i = 0; i < 8; i++) { + if (dly->low[i] < 3) { + if (i == 2 || i == 4) + dly->avg[i] += 4; + else + dly->avg[i] += 3; + + } + + if (dly->high[i] > 0x38) + dly->avg[i] -= 6; + else if (dly->high[i] > 0x30) + dly->avg[i] -= 4; + + if (dly->avg[i] > 0x20) + dly->avg[i] = 0x20; + } + + /* Put Rx DQS delay into manual mode (Set Rx[2,0] to 01) */ + pci_mod_config8(MCU, 0x71, 0x05, 0x01); + /* Now write the new settings */ + vx900_delay_calib_mode_select(CALIB_RxDQS, CALIB_MANUAL); + vx900_write_0x78_0x7f(dly->avg); +} + +static void vx900_dram_calibrate_recieve_delays(vx900_delay_calib * delays, + u8 pinswap) +{ + size_t n_tries = 0; + delay_range *rx_dq_cr = &(delays->rx_dq_cr); + delay_range *rx_dqs = &(delays->rx_dqs); + /* We really should be able to finish this in a single pass, but it may + * in very rare circumstances not work the first time. We define a limit + * on the number of tries so that we have a way of warning the user */ + const size_t max_tries = 100; + for (;;) { + if (n_tries++ >= max_tries) { + die("Could not calibrate receive delays. Giving up"); + } + u8 result; + /* Run calibrations */ + if (0) { + /* If we run this if(0) block, everything else may fail + * putting a huge delay after this block sometimes fixes + * the issue. + * I kept this code in because the long-term plan is to + * figure out how to get this calibration mechanism + * running */ + vx900_rx_capture_range_calib(pinswap); + vx900_read_delay_range(rx_dq_cr, CALIB_RxDQ_CR); + dump_delay_range(*rx_dq_cr); + + } else { + /*FIXME: Cheating with Rx CR setting\ + * We need to either use Rx CR calibration + * or set up a table for the calibration */ + u8 *override = &(rx_dq_cr->avg[0]); + override[0] = 0x28; + override[1] = 0x1c; + override[2] = 0x28; + override[3] = 0x28; + override[4] = 0x2c; + override[5] = 0x30; + override[6] = 0x30; + override[7] = 0x34; + printram("Bypassing RxCR 78-7f calibration with:\n"); + dump_delay(rx_dq_cr->avg); + } + /* We need to put the setting on manual mode */ + pci_mod_config8(MCU, 0x71, 0, 1 << 4); + vx900_delay_calib_mode_select(CALIB_RxDQ_CR, CALIB_MANUAL); + vx900_write_0x78_0x7f(rx_dq_cr->avg); + + /************* RxDQS *************/ + vx900_rx_dqs_delay_calib(pinswap); + vx900_read_delay_range(rx_dqs, CALIB_RxDQS); + vx900_rxdqs_adjust(rx_dqs); + + result = vx900_dram_check_calib_range(rx_dqs, DQSI_THRESHOLD); + if (result != DELAY_RANGE_GOOD) + continue; + + /* We're good to go. Switch to manual and write the manual + * setting */ + pci_mod_config8(MCU, 0x71, 0, 1 << 0); + vx900_delay_calib_mode_select(CALIB_RxDQS, CALIB_MANUAL); + vx900_write_0x78_0x7f(rx_dqs->avg); + break; + } + if (n_tries > 1) + printram("Hmm, we had to try %lu times before our calibration " + "was good.\n", n_tries); +} + +static void vx900_dram_calibrate_transmit_delays(delay_range * tx_dq, + delay_range * tx_dqs) +{ + /* Same timeout reasoning as in receive delays */ + size_t n_tries = 0; + int dq_tries = 0, dqs_tries = 0;; + const size_t max_tries = 100; + for (;;) { + if (n_tries++ >= max_tries) { + printram("Tried DQS %i times and DQ %i times\n", + dqs_tries, dq_tries); + printram("Tx DQS calibration results\n"); + dump_delay_range(*tx_dqs); + printram("TX DQ delay calibration results:\n"); + dump_delay_range(*tx_dq); + die("Could not calibrate transmit delays. Giving up"); + } + u8 result; + /************* TxDQS *************/ + dqs_tries ++; + vx900_tx_dqs_delay_calib(); + vx900_read_delay_range(tx_dqs, CALIB_TxDQS); + + result = vx900_dram_check_calib_range(tx_dqs, DQSO_THRESHOLD); + if (result != DELAY_RANGE_GOOD) + continue; + + /************* TxDQ *************/ + /* FIXME: not sure if multiple page mode should be enabled here + * Vendor BIOS does it */ + pci_mod_config8(MCU, 0x69, 0, 0x01); + + dq_tries ++; + vx900_tx_dq_delay_calib(); + vx900_read_delay_range(tx_dq, CALIB_TxDQ); + + result = vx900_dram_check_calib_range(tx_dq, DQO_THRESHOLD); + if (result != DELAY_RANGE_GOOD) + continue; + + /* At this point, our RAM should give correct read-backs for + * addresses under 64 MB. If it doesn't, it won't work */ + if (ram_check_noprint_nodie(1 << 20, 1 << 20)) { + /* No, our RAM is not working, try again */ + //continue; + } + /* Good. We should be able to use this DIMM */ + /* That's it. We're done */ + break; + } + if (n_tries > 1) + printram("Hmm, we had to try %lu times before our calibration " + "was good.\n", n_tries); +} + +static void vx900_dram_calibrate_delays(const ramctr_timing * ctrl, + const rank_layout * ranks) +{ + size_t i; + u8 val; + u8 dimm; + vx900_delay_calib delay_cal; + memset(&delay_cal, 0, sizeof(delay_cal)); + printram("Starting delay calibration\n"); + + /**** Read delay control ****/ + /* MD Input Data Push Timing Control; + * use values recommended in datasheet + * Setting this too low causes the Rx window to move below the range we + * need it so we can capture it with Rx_78_7f + * This causes Rx calibrations to be too close to 0, and Tx + * calibrations will fail. + * Setting this too high causes the window to move above the range. + */ + if (ctrl->tCK <= TCK_533MHZ) + val = 2; + else if (ctrl->tCK <= TCK_333MHZ) + val = 1; + else + val = 0; + val++; /* FIXME: vendor BIOS sets this to 3 */ + pci_mod_config8(MCU, 0x74, (0x03 << 1), ((val & 0x03) << 1)); + + /* FIXME: The vendor BIOS increases the MD input delay - WHY ? */ + pci_mod_config8(MCU, 0xef, (3 << 4), 3 << 4); + + /**** Write delay control ****/ + /* FIXME: The vendor BIOS does this, but WHY? + * See check_special_registers in VIA provided code. This value seems + * to depend on the DRAM frequency. + */ + /* Early DQ/DQS for write cycles */ + pci_mod_config8(MCU, 0x76, (3 << 2), 2 << 2); + /* FIXME: The vendor BIOS does this - Output preamble ? */ + pci_write_config8(MCU, 0x77, 0x10); + + /* Set BA[0/1/2] to [A17/18/19] */ + vx900_dram_set_ma_pin_map(VX900_MRS_MA_MAP); + /* Disable Multiple Page Mode - Set Rx69[0] to 0 */ + pci_mod_config8(MCU, 0x69, (1 << 0), 0x00); + + /* It's very important that we keep all ranks which are not calibrated + * mapped to VR3. Even if we disable them, if they are mapped to VR0 + * (the rank we use for calibrations), the calibrations may fail in + * unexpected ways. */ + vx900_pr_map_all_vr3(); + + /* We only really need to run the receive calibrations once. They are + * meant to account for signal travel differences in the internal paths + * of the MCU, so it doesn't really matter which rank we use for this. + * Differences between ranks will be accounted for in the transmit + * calibration. */ + for (i = 0; i < VX900_MAX_DIMM_SLOTS; i += 2) { + /* Do we have a valid DIMM? */ + if (ranks->phys_rank_size_mb[i] + + ranks->phys_rank_size_mb[i + 1] == 0) + continue; + /* Map the first rank of the DIMM to VR0 */ + vx900_map_pr_vr(2 * i, 0); + /* Only run on first rank, remember? */ + break; + } + vx900_dram_calibrate_recieve_delays(&delay_cal, + ranks->flags[i].pins_mirrored); + printram("RX DQS calibration results\n"); + dump_delay_range(delay_cal.rx_dqs); + + /* Enable multiple page mode for when calibrating transmit delays */ + pci_mod_config8(MCU, 0x69, 0, 1 << 1); + + /* + * Unlike the receive delays, we need to run the transmit calibration + * for each DIMM (not rank). We run the calibration on the even rank. + * The odd rank may have memory pins swapped, and this, it seems, + * confuses the calibration circuit. + */ + dimm = 0; + for (i = 0; i < VX900_MAX_DIMM_SLOTS; i++) { + /* Do we have a valid DIMM? */ + u32 dimm_size_mb = ranks->phys_rank_size_mb[2 * i] + + ranks->phys_rank_size_mb[2 * i + 1]; + if (dimm_size_mb == 0) + continue; + /* Map the first rank of the DIMM to VR0 */ + vx900_map_pr_vr(2 * i, 0); + vx900_dram_calibrate_transmit_delays(&(delay_cal.tx_dq[dimm]), + &(delay_cal.tx_dqs[dimm])); + /* We run this more than once, so dump delays for each DIMM */ + printram("Tx DQS calibration results\n"); + dump_delay_range(delay_cal.tx_dqs[dimm]); + printram("TX DQ delay calibration results:\n"); + dump_delay_range(delay_cal.tx_dq[dimm]); + /* Now move the DIMM back to VR3 */ + vx900_map_pr_vr(2 * i, 3); + /* We use dimm as a counter so that we fill tx_dq[] and tx_dqs[] + * results in order from 0, and do not leave any gaps */ + dimm++; + } + + /* When we have more dimms, we need to find a tx window with which all + * dimms can safely work */ + if (dimm > 1) { + vx900_dram_find_avg_delays(&delay_cal); + printram("Final delay values\n"); + printram("Tx DQS: "); + dump_delay(delay_cal.tx_dqs[0].avg); + printram("Tx DQ: "); + dump_delay(delay_cal.tx_dq[0].avg); + } + /* Write manual settings */ + pci_mod_config8(MCU, 0x75, 0, 0x01); + vx900_delay_calib_mode_select(CALIB_TxDQS, CALIB_MANUAL); + vx900_write_0x78_0x7f(delay_cal.tx_dqs[0].avg); + vx900_delay_calib_mode_select(CALIB_TxDQ, CALIB_MANUAL); + vx900_write_0x78_0x7f(delay_cal.tx_dq[0].avg); +} + +static void vx900_dram_set_refresh_counter(ramctr_timing * ctrl) +{ + u8 reg8; + /* Set DRAM refresh counter + * Based on a refresh counter of 0x61 at 400MHz */ + reg8 = (TCK_400MHZ * 0x61) / ctrl->tCK; + pci_write_config8(MCU, 0xc7, reg8); +} + +static void vx900_dram_range(ramctr_timing * ctrl, rank_layout * ranks) +{ + size_t i, vrank = 0; + u8 reg8; + u32 ramsize_mb = 0, tolm_mb; + const u32 TOLM_3_5G = (7 << 29); + /* All unused physical ranks go to VR3. Otherwise, the MCU might be + * trying to read or write from unused ranks, or even worse, write some + * bits to the rank we want, and some to the unused ranks, even though + * they are disabled. Since VR3 is the last virtual rank to be used, we + * eliminate any ambiguities that the MCU may face. */ + vx900_pr_map_all_vr3(); + for (i = 0; i < VX900_MAX_MEM_RANKS; i++) { + u32 rank_size_mb = ranks->phys_rank_size_mb[i]; + if (!rank_size_mb) + continue; + + /* vvvvvvvvvv FIXME: Fix odd rank init vvvvvvvvvv */ + if ((i & 1)) { + printram("Skippy the yppie rank %li\n", i); + continue; + } + /* ^^^^^^^^^^ FIXME: Fix odd rank init ^^^^^^^^^^ */ + + ranks->virt[vrank].start_addr = ramsize_mb; + ramsize_mb += rank_size_mb; + ranks->virt[vrank].end_addr = ramsize_mb; + + /* Rank memory range */ + reg8 = (ranks->virt[vrank].start_addr >> 6); + pci_write_config8(MCU, 0x48 + vrank, reg8); + reg8 = (ranks->virt[vrank].end_addr >> 6); + pci_write_config8(MCU, 0x40 + vrank, reg8); + + vx900_map_pr_vr(i, vrank); + + printram("Mapped Physical rank %u, to virtual rank %u\n" + " Start address: 0x%.10llx\n" + " End address: 0x%.10llx\n", + (int)i, (int)vrank, + (u64)ranks->virt[vrank].start_addr << 20, + (u64)ranks->virt[vrank].end_addr << 20); + /* Move on to next virtual rank */ + vrank++; + } + + /* Limit the Top of Low memory at 3.5G + * Not to worry, we'll set tolm in ramstage, once we have initialized + * all devices and know pci_tolm. */ + tolm_mb = min(ramsize_mb, TOLM_3_5G >> 20); + u16 reg_tolm = (tolm_mb << 4) & 0xfff0; + pci_mod_config16(MCU, 0x84, 0xfff0, reg_tolm); + + printram("Initialized %u virtual ranks, with a total size of %u MB\n", + (int)vrank, ramsize_mb); +} +static void vx900_dram_map_row_col_bank(dimm_info * dimms) +{ + u8 reg8, rcb_val, col_bits, max_row_bits; + size_t i; + /* Do we have 4Gbit chips? */ + /* FIXME: Implement this */ + + /* Do we have 8Gbit chips? */ + /* FIXME: Implement this */ + + max_row_bits = rcb_val = reg8 = 0; + for (i = 0; i < VX900_MAX_DIMM_SLOTS; i++) { + if (dimms->dimm[i].dram_type == SPD_MEMORY_TYPE_UNDEFINED) + continue; + + col_bits = dimms->dimm[i].col_bits; + + /* + * DDR3 always uses 3 bank address bits, and MA type 111b cannot + * be used due to chipset limitation. We are left with only two + * options, which we can choose based solely on the number of + * column address bits. + */ + if ((col_bits < 10) || (col_bits > 11)) { + printram("DIMM %ld has %d column address bits.\n", + i, col_bits); + die("Unsupported DIMM. Try booting without this DIMM"); + } + + rcb_val = col_bits - 5; + reg8 |= (rcb_val << ((i * 3) + 2)); + + /* */ + max_row_bits = max(max_row_bits, dimms->dimm[i].row_bits); + } + + printram("RCBA map (rx50) <- %.2x\n", reg8); + pci_write_config8(MCU, 0x50, reg8); + + printram("Houston, we have %d row address bits\n", max_row_bits); + /* FIXME: Do this properly */ + vx900_dram_map_pins(13, 14, 15, 17, 16); + +} + +static void vx900_dram_write_final_config(ramctr_timing * ctrl) +{ + /* FIXME: These are quick cheats */ + + /* FIXME: Why are we doing this? */ + /* Tri-state MCSi# when rank is in self-refresh */ + pci_mod_config8(MCU, 0x99, 0, 0x0f); + + //pci_write_config8(MCU, 0x69, 0xe7); + /* Enable paging mode and 8 page registers */ + pci_mod_config8(MCU, 0x69, 0, 0xe5); + //pci_write_config8(MCU, 0x72, 0x0f); + + //pci_write_config8(MCU, 0x97, 0xa4); /* self-refresh */ + //pci_write_config8(MCU, 0x98, 0xba); /* self-refresh II */ + //pci_write_config8(MCU, 0x9a, 0x80); /* self-refresh III */ + + /* Enable automatic triggering of short ZQ calibration */ + pci_write_config8(MCU, 0xc8, 0x80); +} + +void vx900_init_dram_ddr3(const dimm_layout * dimm_addr) +{ + dimm_info dimm_prop; + ramctr_timing ctrl_prop; + rank_layout ranks; + device_t mcu; + + if (!ram_check_noprint_nodie(1 << 20, 1 << 20)) { + printram("RAM is already initialized. Skipping init\n"); + return; + } + /* Locate the Memory controller */ + mcu = pci_locate_device(PCI_ID(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_VX900_MEMCTRL), 0); + + if (mcu == PCI_DEV_INVALID) { + die("Memory Controller not found\n"); + } + memset(&dimm_prop, 0, sizeof(dimm_prop)); + memset(&ctrl_prop, 0, sizeof(ctrl_prop)); + memset(&ranks, 0, sizeof(ranks)); + /* 1) Write some initial "safe" parameters */ + vx900_dram_write_init_config(); + /* 2) Get timing information from SPDs */ + dram_find_spds_ddr3(dimm_addr, &dimm_prop); + /* 3) Find lowest common denominator for all modules */ + dram_find_common_params(&dimm_prop, &ctrl_prop); + /* 4) Find the size of each memory rank */ + vx900_dram_phys_bank_range(&dimm_prop, &ranks); + /* 5) Set DRAM driving strength */ + vx900_dram_driving_ctrl(&dimm_prop); + /* 6) Set DRAM frequency and latencies */ + vx900_dram_timing(&ctrl_prop); + vx900_dram_freq(&ctrl_prop); + /* 7) Initialize the modules themselves */ + vx900_dram_ddr3_dimm_init(&ctrl_prop, &ranks); + /* 8) Set refresh counter based on DRAM frequency */ + vx900_dram_set_refresh_counter(&ctrl_prop); + /* 9) Calibrate receive and transmit delays */ + vx900_dram_calibrate_delays(&ctrl_prop, &ranks); + /* 10) Enable Physical to Virtual Rank mapping */ + vx900_dram_range(&ctrl_prop, &ranks); + /* 11) Map address bits to DRAM pins */ + vx900_dram_map_row_col_bank(&dimm_prop); + /* 99) Some final adjustments */ + vx900_dram_write_final_config(&ctrl_prop); + /* Take a dump */ + dump_pci_device(mcu); + +} diff --git a/src/northbridge/via/vx900/romstrap.inc b/src/northbridge/via/vx900/romstrap.inc new file mode 100644 index 0000000..e4ce677 --- /dev/null +++ b/src/northbridge/via/vx900/romstrap.inc @@ -0,0 +1,60 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2004 Tyan Computer + * (Written by Yinghai Lu <yhlu(a)tyan.com> for Tyan Computer) + * Copyright (C) 2007 Rudolf Marek <r.marek(a)assembler.cz> + * Copyright (C) 2009 One Laptop per Child, Association, Inc. + * Copyright (C) 2011-2012 Alexandru Gagniuc <mr.nuke.me(a)gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* As extracted from the manufacturer's ROM, the romstrap table looks like: + * .long 0x77886047 .long 0x00777777 + * .long 0x00000000 .long 0x00000000 + * .long 0x00888888 .long 0x00AA1111 + * .long 0x00000000 .long 0x00000000 + * + * The vendor BIOS then adjusts some of these settings very early on. Instead of + * adjusting those settings in code, we work them in the romstrap table. + * + */ +/* This file constructs the ROM strap table for VX900 */ + + .section ".romstrap", "a", @progbits + + .globl __romstrap_start +__romstrap_start: +tblpointer: + .long 0x77886047 + .long 0x00777777 + .long 0x00000000 + .long 0x00000000 + .long 0x00888888 + .long 0x00AA1111 + .long 0x00000000 + .long 0x00000000 + +/* + * The pointer to above table should be at 0xffffffd0, + * the table itself MUST be aligned to 128B it seems! + */ +rspointers: + .long tblpointer // It will be 0xffffffd0 + + .globl __romstrap_end + +__romstrap_end: +.previous diff --git a/src/northbridge/via/vx900/romstrap.lds b/src/northbridge/via/vx900/romstrap.lds new file mode 100644 index 0000000..fc63c05 --- /dev/null +++ b/src/northbridge/via/vx900/romstrap.lds @@ -0,0 +1,27 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007 AMD + * (Written by Yinghai Lu <yinghai.lu(a)amd.com> for AMD) + * Copyright (C) 2011 Alexandru Gagniuc <mr.nuke.me(a)gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/> + */ + +SECTIONS { + . = (0x100000000 - 0x2c) - (__romstrap_end - __romstrap_start); + .romstrap (.): { + *(.romstrap) + } +} diff --git a/src/northbridge/via/vx900/sata.c b/src/northbridge/via/vx900/sata.c new file mode 100644 index 0000000..d0b70ff --- /dev/null +++ b/src/northbridge/via/vx900/sata.c @@ -0,0 +1,295 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me(a)gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <console/console.h> +#include <device/pci.h> +#include <device/pci_ids.h> + +#include "vx900.h" + +static void dump_pci_device(device_t dev) +{ + int i; + for (i = 0; i <= 255; i++) { + unsigned char val; + if ((i & 0x0f) == 0) { + print_debug_hex8(i); + print_debug_char(':'); + } + val = pci_read_config8(dev, i); + if((i & 7) == 0) print_debug(" |"); + print_debug_char(' '); + print_debug_hex8(val); + if ((i & 0x0f) == 0x0f) { + print_debug("\n"); + } + } +} + +static void vx900_print_sata_errors(u32 flags) +{ + /* Status flags */ + printk(BIOS_DEBUG, "\tPhyRdy %s\n", + (flags&(1<<16)) ? "changed" : "not changed"); + printk(BIOS_DEBUG, "\tCOMWAKE %s\n", + (flags&(1<<16)) ? "detected" : "not detected"); + printk(BIOS_DEBUG, "\tExchange as determined by COMINIT %s\n", + (flags&(1<<26)) ? "occured" : "not occured"); + printk(BIOS_DEBUG, "\tPort selector presence %s\n", + (flags&(1<<27)) ? "detected" : "not detected"); + /* Errors */ + if(flags&(1<<0)) + print_debug("\tRecovered data integrity ERROR\n"); + if(flags&(1<<1)) + print_debug("\tRecovered data communication ERROR\n"); + if(flags&(1<<8)) + print_debug("\tNon-recovered Transient Data Integrity ERROR\n"); + if(flags&(1<<9)) + print_debug("\tNon-recovered Persistent Communication or" + "\tData Integrity ERROR\n"); + if(flags&(1<<10)) + print_debug("\tProtocol ERROR\n"); + if(flags&(1<<11)) + print_debug("\tInternal ERROR\n"); + if(flags&(1<<17)) + print_debug("\tPHY Internal ERROR\n"); + if(flags&(1<<19)) + print_debug("\t10B to 8B Decode ERROR\n"); + if(flags&(1<<20)) + print_debug("\tDisparity ERROR\n"); + if(flags&(1<<21)) + print_debug("\tCRC ERROR\n"); + if(flags&(1<<22)) + print_debug("\tHandshake ERROR\n"); + if(flags&(1<<23)) + print_debug("\tLink Sequence ERROR\n"); + if(flags&(1<<24)) + print_debug("\tTransport State Transition ERROR\n"); + if(flags&(1<<25)) + print_debug("\tUNRECOGNIZED FIS type\n"); +} + +static void vx900_dbg_sata_errors(device_t dev) +{ + /* Port 0 */ + if (pci_read_config8(dev, 0xa0) & (1<<0) ) { + print_debug("Device detected in SATA port 0.\n"); + u32 flags = pci_read_config32(dev, 0xa8); + vx900_print_sata_errors(flags); + }; + /* Port 1 */ + if (pci_read_config8(dev, 0xa1) & (1<<0) ) { + print_debug("Device detected in SATA port 1.\n"); + u32 flags = pci_read_config32(dev, 0xac); + vx900_print_sata_errors(flags); + }; +} + +typedef u8 sata_phy_config[64]; + +static sata_phy_config reference_ephy = { + 0x80, 0xb8, 0xf0, 0xfe, 0x40, 0x7e, 0xf6, 0xdd, + 0x1a, 0x22, 0xa0, 0x10, 0x02, 0xa9, 0x7c, 0x7e, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x30, 0x84, 0x8c, + 0x75, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x40, 0xd0, 0x41, 0x40, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x40, 0x50, 0x41, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static u32 sata_phy_read32(device_t dev, u8 index) +{ + /* The SATA PHY control registers are accessed by a funny index/value + * scheme. Each byte (0,1,2,3) has its own 4-bit index */ + index = (index >> 2) & 0xf; + u16 i16 = index | (index<<4) | (index<<8)| (index<<12); + /* The index */ + pci_write_config16(dev, 0x68, i16); + /* The value */ + return pci_read_config32(dev, 0x64); +} + +static void sata_phy_write32(device_t dev, u8 index, u32 val) +{ + /* The SATA PHY control registers are accessed by a funny index/value + * scheme. Each byte (0,1,2,3) has its own 4-bit index */ + index = (index >> 2) & 0xf; + u16 i16 = index | (index<<4) | (index<<8)| (index<<12); + /* The index */ + pci_write_config16(dev, 0x68, i16); + /* The value */ + pci_write_config32(dev, 0x64, val); +} + +static void vx900_sata_read_phy_config(device_t dev, sata_phy_config cfg) +{ + size_t i; + u32* data = (u32*)cfg; + for(i = 0; i < (sizeof(sata_phy_config) ) >> 2; i++) { + data[i] = sata_phy_read32(dev, i<<2); + } +} + +static void vx900_sata_write_phy_config(device_t dev, sata_phy_config cfg) +{ + size_t i; + u32* data = (u32*)cfg; + for(i = 0; i < (sizeof(sata_phy_config) ) >> 2; i++) { + sata_phy_write32(dev, i<<2, data[i]); + } +} + +static void vx900_sata_dump_phy_config(sata_phy_config cfg) +{ + print_debug("SATA PHY config:\n"); + int i; + for (i = 0; i < sizeof(sata_phy_config); i++) { + unsigned char val; + if ((i & 0x0f) == 0) { + print_debug_hex8(i); + print_debug_char(':'); + } + val = cfg[i]; + if((i & 7) == 0) print_debug(" |"); + print_debug_char(' '); + print_debug_hex8(val); + if ((i & 0x0f) == 0x0f) { + print_debug("\n"); + } + } +} + +/** + * \brief VX900: Place the onboard SATA controller in Native IDE mode + * + * AHCI mode requires a sub-class of 0x06, and Interface of 0x0 + * SATA mode requires a sub-class of 0x06, and Interface of 0x00 + * Unfortunately, setting the class to SATA, will prevent us from modyfing the + * interface register to an AHCI/SATA compliant value. Thus, payloads or OS may + * not properly identify this as a SATA controller. + * We could set the class code to 0x04, which would cause the interface register + * to become 0x00, which represents a RAID controller. Unfortunately, when we do + * this, SeaBIOS will skip this as a storage device, and we will not be able to + * boot. + * Our only option is to operate in IDE mode. We choose native IDE so that we + * can freely assign an IRQ, and are not forced to use IRQ14 + */ +static void vx900_native_ide_mode(device_t dev) +{ + /* Disable subclass write protect */ + pci_mod_config8(dev, 0x45, 1<<7, 0); + /* Change the device class to IDE */ + pci_write_config16(dev, PCI_CLASS_DEVICE, PCI_CLASS_STORAGE_IDE); + /* Re-enable subclass write protect */ + pci_mod_config8(dev, 0x45, 0, 1<<7); + /* Put it in native IDE mode */ + pci_write_config8(dev, PCI_CLASS_PROG, 0x8f); +} + +static void vx900_sata_init(device_t dev) +{ + print_debug("======================================================\n"); + print_debug("== SATA init \n"); + print_debug("======================================================\n"); + + /* Enable SATA primary channel IO access */ + pci_mod_config8(dev, 0x40, 0, 1<<1); + /* Just SATA, so it makes sense to be in native SATA mode */ + vx900_native_ide_mode(dev); + + /* TP Layer Idle at least 20us before the Following Command */ + pci_mod_config8(dev, 0x53, 0, 1<<7); + /* Resend COMRESET When Recovering SATA Gen2 Device Error */ + pci_mod_config8(dev, 0x62, 1<<1, 1<<7); + + /* Fix "PMP Device Can’t Detect HDD Normally" (VIA Porting Guide) + * SATA device detection will not work unless we clear these bits. + * Without doing this, SeaBIOS (and potentially other payloads) will + * timeout when detecting SATA devices */ + pci_mod_config8(dev, 0x89, (1<<3) | (1<<6), 0); + + /* 12.7 Two Software Resets May Affect the System + * When the software does the second reset before the first reset + * finishes, it may cause the system hang. It would do one software + * reset and check the BSY bit of one port only, and the BSY bit of + * other port would be 1, then it does another software reset + * immediately and causes the system hang. + * This is because the first software reset doesn’t finish, and the + * state machine of the host controller conflicts, it can’t finish the + * second one anymore. The BSY bit of slave port would be always 1 after + * the second software reset issues. BIOS should set the following + * bit to avoid this issue. */ + pci_mod_config8(dev, 0x80, 0, 1<<6); + + /* We need to set the EPHY values before doing anything with the link */ + sata_phy_config ephy; + vx900_sata_read_phy_config(dev, ephy); + if(1) { + vx900_sata_dump_phy_config(ephy); + vx900_sata_write_phy_config(dev, reference_ephy); + } else { + /* Enable TX and RX driving resistance */ + /* TX - 50 Ohm */ + ephy[1] &= ~(0x1f<<3); + ephy[1] |= (1<<7) | (8<<3); + /* RX - 50 Ohm */ + ephy[2] &= ~(0x1f<<3); + ephy[2] |= (1<<7) | (8<<3); + vx900_sata_write_phy_config(dev, ephy); + } + + vx900_sata_read_phy_config(dev, ephy); + vx900_sata_dump_phy_config(ephy); + + /* Clear error flags */ + pci_write_config32(dev, 0xa8, 0xffffffff); + pci_write_config32(dev, 0xac, 0xffffffff); + + /* Start OOB link negotiation sequence */ + pci_mod_config8(dev, 0xb9, 0, 3<<4); + + /* FIXME: From now on, we are just doing DEBUG stuff + * Wait until PHY communication is enabled */ + u32 wloops = 0; + while(! (pci_read_config8(dev, 0xa0) & (1<<1)) ) wloops ++; + printk(BIOS_SPEW, "wloops: %u\n", wloops); + + print_debug("And finally, the dump you've all been waiting for\n"); + dump_pci_device(dev); + vx900_dbg_sata_errors(dev); +} + +static void vx900_sata_read_resources(device_t dev) +{ + pci_dev_read_resources(dev); +} + +static struct device_operations vga_operations = { + .read_resources = vx900_sata_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = vx900_sata_init, +}; + +static const struct pci_driver chrome9hd_driver __pci_driver = { + .ops = &vga_operations, + .vendor = PCI_VENDOR_ID_VIA, + .device = PCI_DEVICE_ID_VIA_VX900_SATA, +}; \ No newline at end of file diff --git a/src/northbridge/via/vx900/traf_ctrl.c b/src/northbridge/via/vx900/traf_ctrl.c new file mode 100644 index 0000000..daed241 --- /dev/null +++ b/src/northbridge/via/vx900/traf_ctrl.c @@ -0,0 +1,156 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me(a)gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <device/pci.h> +#include <device/pci_ids.h> +#include <console/console.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <drivers/generic/ioapic/chip.h> + +#include "vx900.h" +#include "chip.h" + +/** + * \brief VX900: Set up the north module IOAPIC (for PCIE and VGA) + * + * Enable the IOAPIC in the south module, and properly set it up. + * \n + * This is the hardware specific initialization for the IOAPIC, and complements + * the setup done by the generic IOAPIC driver. In order for the IOAPIC to work + * properly, it _must_ be declared in devicetree.cb . + * \n + * We are assuming this is called before the drivers/generic/ioapic code, + * which should be the case if devicetree.cb is set up properly. + */ +static void vx900_north_ioapic_setup(device_t dev) +{ + u8 base_val; + device_t ioapic; + ioapic_config_t *config; + /* Find the IOAPIC, and make sure it's set up correctly in devicetree.cb + * If it's not, then the generic ioapic driver will not set it up + * correctly, and the MP table will not be correctly generated */ + for(ioapic = dev->next; ioapic; ioapic = ioapic->next) + { + if(ioapic->path.type == DEVICE_PATH_IOAPIC) + break; + } + /* You did put an IOAPIC in devicetree.cb, didn't you? */ + if(ioapic == 0) { + /* We don't have enough info to set up the IOAPIC */ + printk(BIOS_ERR, "ERROR: North module IOAPIC not found. " + "Check your devicetree.cb\n"); + return; + } + /* Found our IOAPIC, and it should not carry ISA interrupts */ + config = (ioapic_config_t*)ioapic->chip_info; + if(config->have_isa_interrupts) { + /* Umh, is this the right IOAPIC ? */ + printk(BIOS_ERR, "ERROR: North module IOAPIC should not carry " + "ISA interrupts.\n" + "Check your devicetree.cb\n"); + printk(BIOS_ERR, "Will not initialize this IOAPIC.\n"); + return; + } + /* The base address of this IOAPIC _must_ + * be between 0xfec00000 and 0xfecfff00 + * be 256-byte aligned + */ + if( (config->base < 0xfec0000 || config->base > 0xfecfff00) + || (( config->base & 0xff ) != 0) ) + { + printk(BIOS_ERR, "ERROR: North module IOAPIC base should be " + "between 0xfec00000 and 0xfecfff00\n" + "and must be aligned to a 256-byte boundary, " + "but we found it at 0x%.8x\n", config->base); + return; + } + + printk(BIOS_DEBUG, "VX900 TRAF_CTR: Setting up the north module IOAPIC " + "at 0%.8x\n", config->base); + + /* First register of the IOAPIC base */ + base_val = (config->base >> 8) & 0xff; + pci_write_config8(dev, 0x41, base_val); + /* Second register of the base. + * Bit[7] also enables the IOAPIC and bit[5] enables MSI cycles */ + base_val = (config->base >> 16) & 0xf; + pci_mod_config8(dev, 0x40, 0, base_val | (1<<7) | (1<<5) ); +} + +/* + * Configures the PCI-express ports + * + * FIXME: implement this + */ +static void vx900_pex_link_setup(device_t dev) +{ + u8 reg8; + struct northbridge_via_vx900_config *nb = (void*)dev->chip_info; + + print_debug("======================================================\n"); + print_debug("== PEX link setup\n"); + print_debug("======================================================\n"); + + /* FIXME: We print this before modifying the default values */ + /* Check the default boot config */ + reg8 = pci_read_config8(dev, 0xb0); + if (reg8 && (1 << 7) ) + print_debug("PCIE lanes 3:0 used as DP interface\n"); + else + print_debug("PCIE lanes 3:0 used for Root Port 0\n"); + + if (reg8 && (1 << 3)) + print_debug("Root Port 0 is 1 lane wide\n"); + else + print_debug("Root Port 0 is 2 lanes wide\n"); + + reg8 &= ~( (1 << 7) | (1 << 3)); + + if (nb->assign_pex_to_dp) + reg8 |= (1 << 7); + + if (!nb->pcie_port1_2_lane_wide) + reg8 |= (1 << 3); + + pci_write_config8(dev, 0xb0, reg8); +} + +static void vx900_traf_ctr_init(device_t dev) +{ + vx900_north_ioapic_setup(dev); + vx900_pex_link_setup(dev); +} + + +static struct device_operations traf_ctrl_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = vx900_traf_ctr_init, + /* Need this here, or the IOAPIC driver won't be called */ + .scan_bus = scan_static_bus, +}; + +static const struct pci_driver traf_ctrl_driver __pci_driver = { + .ops = &traf_ctrl_ops, + .vendor = PCI_VENDOR_ID_VIA, + .device = PCI_DEVICE_ID_VIA_VX900_TRAF, +}; \ No newline at end of file diff --git a/src/northbridge/via/vx900/vx900.h b/src/northbridge/via/vx900/vx900.h new file mode 100644 index 0000000..001d10f --- /dev/null +++ b/src/northbridge/via/vx900/vx900.h @@ -0,0 +1,78 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011 Alexandru Gagniuc <mr.nuke.me(a)gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef __VX900_H +#define __VX900_H + +#define VX900_ACPI_IO_BASE 0x0400 + +#define VX900_NB_IOAPIC_ID 0x2 +#define VX900_NB_IOAPIC_BASE 0xfecc000 + +#define VX900_SB_IOAPIC_ID 0x1 +#define VX900_SB_IOAPIC_BASE 0xfec0000 + +#define SMBUS_IO_BASE 0x500 + +/* The maximum number of DIMM slots that the VX900 supports */ +#define VX900_MAX_DIMM_SLOTS 2 +#define VX900_MAX_MEM_RANKS 4 + +#define min(a,b) a<b?a:b +#define max(a,b) a>b?a:b + +#include <arch/io.h> +#ifndef __PRE_RAM__ +#include <device/pci.h> +#else +//#include <arch/romcc_io.h> +#endif /* __PRE_RAM__ */ + + +/* We use these throughout the code. They really belong in a generic part of + * coreboot, but until beuraucracy gets them there, we still need them */ +static inline __attribute__((always_inline)) +void pci_mod_config8(device_t dev, unsigned int where, + uint8_t clr_mask, uint8_t set_mask) +{ + uint8_t reg8 = pci_read_config8(dev, where); + reg8 &= ~clr_mask; + reg8 |= set_mask; + pci_write_config8(dev, where, reg8); +} +static inline __attribute__((always_inline)) +void pci_mod_config16(device_t dev, unsigned int where, + uint16_t clr_mask, uint16_t set_mask) +{ + uint16_t reg16 = pci_read_config16(dev, where); + reg16 &= ~clr_mask; + reg16 |= set_mask; + pci_write_config16(dev, where, reg16); +} +static inline __attribute__((always_inline)) +void pci_mod_config32(device_t dev, unsigned int where, + uint32_t clr_mask, uint32_t set_mask) +{ + uint32_t reg32 = pci_read_config32(dev, where); + reg32 &= ~clr_mask; + reg32 |= set_mask; + pci_write_config32(dev, where, reg32); +} + +u32 chrome9hd_fb_size(void); +#endif /* __VX900_H */
1 0
0 0
Patch set updated for coreboot: 9a83e69 early_smbus: Add early SMBus implementation for VIA chipsets
by Alexandru Gagniuc June 3, 2013

June 3, 2013
Alexandru Gagniuc (mr.nuke.me(a)gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/144 -gerrit commit 9a83e69d82cf00087e750576c77c667abd2b7842 Author: Alexandru Gagniuc <mr.nuke.me(a)gmail.com> Date: Tue May 21 12:35:08 2013 -0500 early_smbus: Add early SMBus implementation for VIA chipsets Add a common implementation of SMBus functionality for early chipsets. Note however, that existing via chipsets are not ported to this code. Porting will require hardware testing to make sure everything is fine. This code is used in the VIA VX900 branch. Change-Id: If5ad8cd0942ac02d358a0139967e7d85d395660f Signed-off-by: Alexandru Gagniuc <mr.nuke.me(a)gmail.com> --- src/southbridge/via/common/early_smbus.c | 176 +++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) diff --git a/src/southbridge/via/common/early_smbus.c b/src/southbridge/via/common/early_smbus.c new file mode 100644 index 0000000..262d641 --- /dev/null +++ b/src/southbridge/via/common/early_smbus.c @@ -0,0 +1,176 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011-2013 Alexandru Gagniuc <mr.nuke.me(a)gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/** + * @file via_early_sambus.c + * + * This file defines the implementations for the functions defined in + * device/early/smbus.h + * + * These implementations work with most via chipsets. Any VIA port should try + * to use these. Makefile.inc needs to be adapted to link against this file + * during romstage: + * @code + * romstage-y += ./../../../southbridge/via/common/early_smbus.c + * @endcode + * + * These functions are marked weak in the event that one or more might need to + * be overridden. This may be the case when, for example, a chipset needs a + * longer delay for a specific operation. + */ + +#include <device/early_smbus.h> + +#include <arch/io.h> + +/** + * \brief SMBus IO ports in relation to the base IO port + */ +#define SMBHSTSTAT(base) (u16)(u32)base + 0x0 +#define SMBSLVSTAT(base) (u16)(u32)base + 0x1 +#define SMBHSTCTL(base) (u16)(u32)base + 0x2 +#define SMBHSTCMD(base) (u16)(u32)base + 0x3 +#define SMBXMITADD(base) (u16)(u32)base + 0x4 +#define SMBHSTDAT0(base) (u16)(u32)base + 0x5 +#define SMBHSTDAT1(base) (u16)(u32)base + 0x6 +#define SMBBLKDAT(base) (u16)(u32)base + 0x7 +#define SMBSLVCTL(base) (u16)(u32)base + 0x8 +#define SMBTRNSADD(base) (u16)(u32)base + 0x9 +#define SMBSLVDATA (base) (u16)(u32)base + 0xa + +#define SMBUS_TIMEOUT (100*1000*10) + +/** + * \brief Brief delay for SMBus transactions + */ +void smbus_delay(void) +{ + inb(0x80); +} + +/** + * \brief Clear the SMBus host status register + * + * @param smbus_dev The base SMBus IO port + */ +__attribute__ ((weak)) +void smbus_reset(u32 smbus_dev) +{ + outb(0xdf, SMBHSTSTAT(smbus_dev)); +} + +/** + * \brief Print an error, should it occur. If no error, just exit. + * + * @param smbus_dev The base SMBus IO port + * @param host_status The data returned on the host status register after + * a transaction is processed. + * @param loops The number of times a transaction was attempted. + * @return 0 if no error occurred + * 1 if an error was detected + */ +__attribute__ ((weak)) +int smbus_print_error(u32 smbus_dev, u8 host_status, int loops) +{ + /* Check if there actually was an error. */ + if ((host_status == 0x00 || host_status == 0x40 || + host_status == 0x42) && (loops < SMBUS_TIMEOUT)) + return 0; + + if (loops >= SMBUS_TIMEOUT) + printsmbus("SMBus timeout\n"); + if (host_status & (1 << 4)) + printsmbus("Interrupt/SMI# was Failed Bus Transaction\n"); + if (host_status & (1 << 3)) + printsmbus("Bus error\n"); + if (host_status & (1 << 2)) + printsmbus("Device error\n"); + if (host_status & (1 << 1)) + printsmbus("Interrupt/SMI# completed successfully\n"); + if (host_status & (1 << 0)) + printsmbus("Host busy\n"); + return 1; +} + +/** + * \brief Checks if the SMBus is currently busy with a transaction + * + * @param smbus_dev The base SMBus IO port + */ +__attribute__ ((weak)) +int smbus_is_busy(u32 smbus_dev) +{ + /* Check if bit 0 of the status register is 1 (busy) or 0 (ready) */ + return ((inb(SMBHSTSTAT(smbus_dev)) & (1 << 0)) == 1); +} + +/** + * \brief Wait for the SMBus to become ready to process a new transaction. + * + * @param smbus_dev The base SMBus IO port + */ +__attribute__ ((weak)) +int smbus_wait_until_ready(u32 smbus_dev) +{ + int loops; + + printsmbus("Waiting until SMBus ready\n"); + + /* Loop up to SMBUS_TIMEOUT times, waiting for bit 0 of the + * SMBus Host Status register to go to 0, indicating the operation + * was completed successfully. I don't remember why I did it this way, + * but I think it was because ROMCC was running low on registers */ + loops = 0; + while (smbus_is_busy(smbus_dev) && loops < SMBUS_TIMEOUT) + ++loops; + + return smbus_print_error(smbus_dev, inb(SMBHSTSTAT(smbus_dev)), loops); +} + +/** + * \brief Read a byte from the SMBus. + * + * @param smbus_dev The base SMBus IO port + * @param addr The address location of the DIMM on the SMBus. + * @param offset The offset the data is located at. + */ +__attribute__ ((weak)) +u8 smbus_read_byte(u32 smbus_dev, u8 addr, u8 offset) +{ + u8 val; + + /* Initialize SMBus sequence */ + smbus_reset(smbus_dev); + /* Clear host data port. */ + outb(0x00, SMBHSTDAT0(smbus_dev)); + + smbus_wait_until_ready(smbus_dev); + + /* Actual addr to reg format. */ + addr = (addr << 1); + addr |= 1; /* read command */ + outb(addr, SMBXMITADD(smbus_dev)); + outb(offset, SMBHSTCMD(smbus_dev)); + /* Start transaction, byte data read. */ + outb(0x48, SMBHSTCTL(smbus_dev)); + smbus_wait_until_ready(smbus_dev); + + val = inb(SMBHSTDAT0(smbus_dev)); + return val; +}
1 0
0 0
Patch set updated for coreboot: 171796e dram: Add utilities for decoding DDR3 SPDs
by Alexandru Gagniuc June 3, 2013

June 3, 2013
Alexandru Gagniuc (mr.nuke.me(a)gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/3267 -gerrit commit 171796e3efce3f8042347dd4174619769edf9523 Author: Alexandru Gagniuc <mr.nuke.me(a)gmail.com> Date: Tue May 21 14:43:45 2013 -0500 dram: Add utilities for decoding DDR3 SPDs Add convenience utilities for decoding DDR3 SPDs and printing the information to the console. These have proven invaluable when writing the VX900 memory initialization. These are used in the VX900 branch Information printed has the following format: > SPD Data for DIMM 51 > Revision: 10 > Type : b > Key : 2 > Banks : 8 > Capacity: 1 Gb > Supported voltages: 1.5V > SDRAM width : 8 > Bus extension : 0 bits > Bus width : 64 > Optional features : DLL-Off_mode RZQ/7 RZQ/6 > Thermal features : ASR ext_temp_range > Thermal sensor : no > Standard SDRAM : no > Row addr bits : 13 > Column addr bits : 10 > Number of ranks : 1 > DIMM Capacity : 1024 MB > CAS latencies : 6 7 8 9 > tCKmin : 1.500 ns > tAAmin : 13.125 ns > tWRmin : 15.000 ns > tRCDmin : 13.125 ns > tRRDmin : 6.000 ns > tRPmin : 13.125 ns > tRASmin : 36.000 ns > tRCmin : 49.125 ns > tRFCmin : 110.000 ns > tWTRmin : 7.500 ns > tRTPmin : 7.500 ns > tFAWmin : 30.000 ns Change-Id: I30725a75caf74ac637db0a143344562bd9910466 Signed-off-by: Alexandru Gagniuc <mr.nuke.me(a)gmail.com> --- src/device/dram/ddr3.c | 372 +++++++++++++++++++++++++++++++++++++++++ src/include/device/dram/ddr3.h | 189 +++++++++++++++++++++ 2 files changed, 561 insertions(+) diff --git a/src/device/dram/ddr3.c b/src/device/dram/ddr3.c new file mode 100644 index 0000000..c745bd7 --- /dev/null +++ b/src/device/dram/ddr3.c @@ -0,0 +1,372 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011-2013 Alexandru Gagniuc <mr.nuke.me(a)gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/** + * @file ddr3_util.h + * + * \brief Utilities for decoding DDR3 SPDs + */ + +#include <console/console.h> +#include <device/device.h> +#include <device/dram/ddr3.h> + +/** + * \brief Checks if the DIMM is Registered based on byte[3] of the SPD + * + * Tells if the DIMM type is registered or not. + * + * @param type DIMM type. This is byte[3] of the SPD. + */ +int dimm_is_registered(enum spd_dimm_type type) +{ + if ((type == SPD_DIMM_TYPE_RDIMM) + | (type == SPD_DIMM_TYPE_MINI_RDIMM) + | (type == SPD_DIMM_TYPE_72B_SO_RDIMM)) + return 1; + + return 0; +} + +/** + * \brief Decode the raw SPD data + * + * Decodes a raw SPD data from a DDR3 DIMM, and organizes it into a + * @ref dimm_attr structure. The SPD data must first be read in a contiguous + * array, and passed to this function. + * + * @param dimm pointer to @ref dimm_attr stucture where the decoded data is to + * be stored + * @param spd array of raw data previously read from the SPD. + * + * @return @ref spd_status enumerator + * SPD_STATUS_OK -- decoding was successful + * SPD_STATUS_INVALID -- invalid SPD or not a DDR3 SPD + * SPD_STATUS_CRC_ERROR -- CRC did not verify + * SPD_STATUS_INVALID_FIELD -- A field with an invalid value was + * detected. + */ +int spd_decode_ddr3(dimm_attr * dimm, spd_raw_data spd) +{ + int nCRC, i, ret; + u16 crc, spd_crc; + u8 *ptr = spd; + u8 ftb_divisor, ftb_dividend, capacity_shift, bus_width, sdram_width; + u8 reg8; + u32 mtb; /* medium time base */ + unsigned int val, param; + + ret = SPD_STATUS_OK; + + /* Don't assume we memset 0 dimm struct. Clear all our flags */ + dimm->flags.raw = 0; + /* Make sure that the SPD dump is indeed from a DDR3 module */ + if (spd[2] != SPD_MEMORY_TYPE_SDRAM_DDR3) { + printram("Not a DDR3 SPD!\n"); + dimm->dram_type = SPD_MEMORY_TYPE_UNDEFINED; + return SPD_STATUS_INVALID; + } + dimm->dram_type = SPD_MEMORY_TYPE_SDRAM_DDR3; + + /* Find the number of bytes covered by CRC */ + if (spd[0] & 0x80) { + nCRC = 117; + } else { + nCRC = 126; + } + + /* Compute the CRC */ + crc = 0; + while (--nCRC >= 0) { + crc = crc ^ (int)*ptr++ << 8; + for (i = 0; i < 8; ++i) + if (crc & 0x8000) { + crc = crc << 1 ^ 0x1021; + } else { + crc = crc << 1; + } + } + /* Compare with the CRC in the SPD */ + spd_crc = (spd[127] << 8) + spd[126]; + /* Verify the CRC is correct */ + if (crc != spd_crc) { + printram("ERROR: SPD CRC failed!!!"); + ret = SPD_STATUS_CRC_ERROR; + }; + + printram(" Revision: %x\n", spd[1]); + printram(" Type : %x\n", spd[2]); + printram(" Key : %x\n", spd[3]); + + reg8 = spd[4]; + /* Number of memory banks */ + val = (reg8 >> 4) & 0x07; + if (val > 0x03) { + printram(" Invalid number of memory banks\n"); + ret = SPD_STATUS_INVALID_FIELD; + } + param = 1 << (val + 3); + printram(" Banks : %u\n", param); + /* SDRAM capacity */ + capacity_shift = reg8 & 0x0f; + if (capacity_shift > 0x06) { + printram(" Invalid module capacity\n"); + ret = SPD_STATUS_INVALID_FIELD; + } + if (capacity_shift < 0x02) { + printram(" Capacity: %u Mb\n", 256 << capacity_shift); + } else { + printram(" Capacity: %u Gb\n", 1 << (capacity_shift - 2)); + } + + reg8 = spd[5]; + /* Row address bits */ + val = (reg8 >> 3) & 0x07; + if (val > 0x04) { + printram(" Invalid row address bits\n"); + ret = SPD_STATUS_INVALID_FIELD; + } + dimm->row_bits = val + 12; + /* Column address bits */ + val = reg8 & 0x07; + if (val > 0x03) { + printram(" Invalid column address bits\n"); + ret = SPD_STATUS_INVALID_FIELD; + } + dimm->col_bits = val + 9; + + /* Module nominal voltage */ + reg8 = spd[6]; + printram(" Supported voltages:"); + if (reg8 & (1 << 2)) { + dimm->flags.operable_1_25V = 1; + printram(" 1.25V"); + } + if (reg8 & (1 << 1)) { + dimm->flags.operable_1_35V = 1; + printram(" 1.35V"); + } + if (!(reg8 & (1 << 0))) { + dimm->flags.operable_1_50V = 1; + printram(" 1.5V"); + } + printram("\n"); + + /* Module organization */ + reg8 = spd[7]; + /* Number of ranks */ + val = (reg8 >> 3) & 0x07; + if (val > 3) { + printram(" Invalid number of ranks\n"); + ret = SPD_STATUS_INVALID_FIELD; + } + dimm->ranks = val + 1; + /* SDRAM device width */ + val = (reg8 & 0x07); + if (val > 3) { + printram(" Invalid SDRAM width\n"); + ret = SPD_STATUS_INVALID_FIELD; + } + sdram_width = (4 << val); + printram(" SDRAM width : %u\n", sdram_width); + + /* Memory bus width */ + reg8 = spd[8]; + /* Bus extension */ + val = (reg8 >> 3) & 0x03; + if (val > 1) { + printram(" Invalid bus extension\n"); + ret = SPD_STATUS_INVALID_FIELD; + } + dimm->flags.is_ecc = val ? 1 : 0; + printram(" Bus extension : %u bits\n", val ? 8 : 0); + /* Bus width */ + val = reg8 & 0x07; + if (val > 3) { + printram(" Invalid bus width\n"); + ret = SPD_STATUS_INVALID_FIELD; + } + bus_width = 8 << val; + printram(" Bus width : %u\n", bus_width); + + /* We have all the info we need to compute the dimm size */ + /* Capacity is 256Mbit multiplied by the power of 2 specified in + * capacity_shift + * The rest is the JEDEC formula */ + dimm->size_mb = ((1 << (capacity_shift + (25 - 20))) * bus_width + * dimm->ranks) / sdram_width; + + /* Fine Timebase (FTB) Dividend/Divisor */ + /* Dividend */ + ftb_dividend = (spd[9] >> 4) & 0x0f; + /* Divisor */ + ftb_divisor = spd[9] & 0x0f; + + /* Medium Timebase = + * Medium Timebase (MTB) Dividend / + * Medium Timebase (MTB) Divisor */ + mtb = (((u32) spd[10]) << 8) / spd[11]; + + /* SDRAM Minimum Cycle Time (tCKmin) */ + dimm->tCK = spd[12] * mtb; + /* CAS Latencies Supported */ + dimm->cas_supported = (spd[15] << 8) + spd[14]; + /* Minimum CAS Latency Time (tAAmin) */ + dimm->tAA = spd[16] * mtb; + /* Minimum Write Recovery Time (tWRmin) */ + dimm->tWR = spd[17] * mtb; + /* Minimum RAS# to CAS# Delay Time (tRCDmin) */ + dimm->tRCD = spd[18] * mtb; + /* Minimum Row Active to Row Active Delay Time (tRRDmin) */ + dimm->tRRD = spd[19] * mtb; + /* Minimum Row Precharge Delay Time (tRPmin) */ + dimm->tRP = spd[20] * mtb; + /* Minimum Active to Precharge Delay Time (tRASmin) */ + dimm->tRAS = (((spd[21] & 0x0f) << 8) + spd[22]) * mtb; + /* Minimum Active to Active/Refresh Delay Time (tRCmin) */ + dimm->tRC = (((spd[21] & 0xf0) << 4) + spd[23]) * mtb; + /* Minimum Refresh Recovery Delay Time (tRFCmin) */ + dimm->tRFC = ((spd[25] << 8) + spd[24]) * mtb; + /* Minimum Internal Write to Read Command Delay Time (tWTRmin) */ + dimm->tWTR = spd[26] * mtb; + /* Minimum Internal Read to Precharge Command Delay Time (tRTPmin) */ + dimm->tRTP = spd[27] * mtb; + /* Minimum Four Activate Window Delay Time (tFAWmin) */ + dimm->tFAW = (((spd[28] & 0x0f) << 8) + spd[29]) * mtb; + + /* SDRAM Optional Features */ + reg8 = spd[30]; + printram(" Optional features :"); + if (reg8 & 0x80) { + dimm->flags.dll_off_mode = 1; + printram(" DLL-Off_mode"); + } + if (reg8 & 0x02) { + dimm->flags.rzq7_supported = 1; + printram(" RZQ/7"); + } + if (reg8 & 0x01) { + dimm->flags.rzq6_supported = 1; + printram(" RZQ/6"); + } + printram("\n"); + + /* SDRAM Thermal and Refresh Options */ + reg8 = spd[31]; + printram(" Thermal features :"); + if (reg8 & 0x80) { + dimm->flags.pasr = 1; + printram(" PASR"); + } + if (reg8 & 0x08) { + dimm->flags.odts = 1; + printram(" ODTS"); + } + if (reg8 & 0x04) { + dimm->flags.asr = 1; + printram(" ASR"); + } + if (reg8 & 0x02) { + dimm->flags.ext_temp_range = 1; + printram(" ext_temp_refresh"); + } + if (reg8 & 0x01) { + dimm->flags.ext_temp_refresh = 1; + printram(" ext_temp_range"); + } + printram("\n"); + + /* Module Thermal Sensor */ + reg8 = spd[32]; + if (reg8 & 0x80) + dimm->flags.therm_sensor = 1; + printram(" Thermal sensor : %s\n", + dimm->flags.therm_sensor ? "yes" : "no"); + + /* SDRAM Device Type */ + reg8 = spd[33]; + printram(" Standard SDRAM : %s\n", (reg8 & 0x80) ? "no" : "yes"); + + if (spd[63] & 0x01) { + dimm->flags.pins_mirrored = 1; + printram(" DIMM Rank1 Address bits mirrorred!!!\n"); + } + + return ret; +} + +/* + * The information printed below has a more informational character, and is not + * necessarily tied in to RAM init debugging. Hence, we stop using printram(), + * and use the standard printk()'s below. + */ + +static void print_ns(const char *msg, u32 val) +{ + u32 mant, fp; + mant = val / 256; + fp = (val % 256) * 1000 / 256; + + printk(BIOS_INFO, "%s%3u.%.3u ns\n", msg, mant, fp); +} + +/** +* \brief Print the info in DIMM +* +* Print info about the DIMM. Useful to use when CONFIG_DEBUG_RAM_SETUP is +* selected, or for a purely informative output. +* +* @param dimm pointer to already decoded @ref dimm_attr stucture +*/ +void dram_print_spd_ddr3(const dimm_attr * dimm) +{ + u16 val16; + int i; + + printk(BIOS_INFO, " Row addr bits : %u\n", dimm->row_bits); + printk(BIOS_INFO, " Column addr bits : %u\n", dimm->col_bits); + printk(BIOS_INFO, " Number of ranks : %u\n", dimm->ranks); + printk(BIOS_INFO, " DIMM Capacity : %u MB\n", dimm->size_mb); + + /* CAS Latencies Supported */ + val16 = dimm->cas_supported; + printk(BIOS_INFO, " CAS latencies :"); + i = 0; + do { + if (val16 & 1) + printk(BIOS_INFO, " %u", i + 4); + i++; + val16 >>= 1; + } while (val16); + printk(BIOS_INFO, "\n"); + + print_ns(" tCKmin : ", dimm->tCK); + print_ns(" tAAmin : ", dimm->tAA); + print_ns(" tWRmin : ", dimm->tWR); + print_ns(" tRCDmin : ", dimm->tRCD); + print_ns(" tRRDmin : ", dimm->tRRD); + print_ns(" tRPmin : ", dimm->tRP); + print_ns(" tRASmin : ", dimm->tRAS); + print_ns(" tRCmin : ", dimm->tRC); + print_ns(" tRFCmin : ", dimm->tRFC); + print_ns(" tWTRmin : ", dimm->tWTR); + print_ns(" tRTPmin : ", dimm->tRTP); + print_ns(" tFAWmin : ", dimm->tFAW); + +} diff --git a/src/include/device/dram/ddr3.h b/src/include/device/dram/ddr3.h new file mode 100644 index 0000000..926f7b9 --- /dev/null +++ b/src/include/device/dram/ddr3.h @@ -0,0 +1,189 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me(a)gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef DEVICE_DRAM_DDR3L_H +#define DEVICE_DRAM_DDR3L_H + +/** + * @file ddr3.h + * + * \brief Utilities for decoding DDR3 SPDs + */ + +#include <stdint.h> +#include <spd.h> + +/** + * \brief Convenience definitions for TCK values + * + * Different values for tCK, representing standard DDR3 frequencies. + * These values are in 1/256 ns units. + * @{ + */ +#define TCK_1066MHZ 240 +#define TCK_800MHZ 320 +#define TCK_666MHZ 384 +#define TCK_533MHZ 480 +#define TCK_400MHZ 640 +#define TCK_333MHZ 768 +#define TCK_266MHZ 960 +#define TCK_200MHZ 1280 +/** @} */ + +/** + * \brief Convenience macro for enabling printk with CONFIG_DEBUG_RAM_SETUP + * + * Use this macro instead of printk(); for verbose RAM initialization messages. + * When CONFIG_DEBUG_RAM_SETUP is not selected, these messages are automatically + * disabled. + * @{ + */ +#if defined(CONFIG_DEBUG_RAM_SETUP) && (CONFIG_DEBUG_RAM_SETUP) +#define printram(x, ...) printk(BIOS_DEBUG, x, ##__VA_ARGS__) +#else +#define printram(x, ...) +#endif +/** @} */ + +/* + * Module type (byte 3, bits 3:0) of SPD + * This definition is specific to DDR3. DDR2 SPDs have a diferent structure. + */ +enum spd_dimm_type { + SPD_DIMM_TYPE_UNDEFINED = 0x00, + SPD_DIMM_TYPE_RDIMM = 0x01, + SPD_DIMM_TYPE_UDIMM = 0x02, + SPD_DIMM_TYPE_SO_DIMM = 0x03, + SPD_DIMM_TYPE_MICRO_DIMM = 0x04, + SPD_DIMM_TYPE_MINI_RDIMM = 0x05, + SPD_DIMM_TYPE_MINI_UDIMM = 0x06, + SPD_DIMM_TYPE_MINI_CDIMM = 0x07, + SPD_DIMM_TYPE_72B_SO_UDIMM = 0x08, + SPD_DIMM_TYPE_72B_SO_RDIMM = 0x09, + SPD_DIMM_TYPE_72B_SO_CDIMM = 0x0a, + SPD_DIMM_TYPE_LRDIMM = 0x0b, + SPD_DIMM_TYPE_16B_SO_DIMM = 0x0d, + SPD_DIMM_TYPE_32B_SO_DIMM = 0x0e, + /* Masks to bits 3:0 to give the dimm type */ + SPD_DIMM_TYPE_MASK = 0x0f, +}; + +/** + * \brief DIMM flags + * + * Characteristic flags for the DIMM, as presented by the SPD + */ +typedef union dimm_flags_st { + /* The whole point of the union/struct construct is to allow us to clear + * all the bits with one line: flags.raw = 0. + * We do not care how these bits are ordered */ + struct { + /* Indicates if rank 1 of DIMM uses a mirrored pin mapping. See: + * Annex K: Serial Presence Detect (SPD) for DDR3 SDRAM */ + unsigned pins_mirrored:1; + /* Module can work at 1.50V - All DIMMS must be 1.5V operable */ + unsigned operable_1_50V:1; + /* Module can work at 1.35V */ + unsigned operable_1_35V:1; + /* Module can work at 1.20V */ + unsigned operable_1_25V:1; + /* Has an 8-bit bus extension, meaning the DIMM supports ECC */ + unsigned is_ecc:1; + /* DLL-Off Mode Support */ + unsigned dll_off_mode:1; + /* Indicates a drive strength of RZQ/6 (40 Ohm) is supported */ + unsigned rzq6_supported:1; + /* Indicates a drive strength of RZQ/7 (35 Ohm) is supported */ + unsigned rzq7_supported:1; + /* Partial Array Self Refresh */ + unsigned pasr:1; + /* On-die Thermal Sensor Readout */ + unsigned odts:1; + /* Auto Self Refresh */ + unsigned asr:1; + /* Extended temperature range supported */ + unsigned ext_temp_range:1; + /* Operating at extended temperature requires 2X refresh rate */ + unsigned ext_temp_refresh:1; + /* Thermal sensor incorporated */ + unsigned therm_sensor:1; + }; + unsigned raw; +} dimm_flags_t; + +/** + * \brief DIMM characteristics + * + * The characteristics of each DIMM, as presented by the SPD + */ +typedef struct dimm_attr_st { + enum spd_memory_type dram_type; + u16 cas_supported; + /* Flags extracted from SPD */ + dimm_flags_t flags; + /* Number of ranks */ + u8 ranks; + /* Number or row address bits */ + u8 row_bits; + /* Number or column address bits */ + u8 col_bits; + /* Size of module in MiB */ + u32 size_mb; + /* Latencies are in units of 1/256 ns */ + u32 tCK; + u32 tAA; + u32 tWR; + u32 tRCD; + u32 tRRD; + u32 tRP; + u32 tRAS; + u32 tRC; + u32 tRFC; + u32 tWTR; + u32 tRTP; + u32 tFAW; +} dimm_attr; + +/** Result of the SPD decoding process */ +enum spd_status { + SPD_STATUS_OK = 0, + SPD_STATUS_INVALID, + SPD_STATUS_CRC_ERROR, + SPD_STATUS_INVALID_FIELD, +}; + +typedef u8 spd_raw_data[256]; + +int spd_decode_ddr3(dimm_attr * dimm, spd_raw_data spd_data); +int dimm_is_registered(enum spd_dimm_type type); +void dram_print_spd_ddr3(const dimm_attr * dimm); + +/** + * \brief Read double word from specified address + * + * Should be useful when doing an MRS to the DIMM + */ +static inline u32 volatile_read(volatile u32 addr) +{ + volatile u32 result; + result = *(volatile u32 *)addr; + return result; +} + +#endif /* DEVICE_DRAM_DDR3_H */
1 0
0 0
Patch set updated for coreboot: 1428f39 coreboot: Add generic early SMBus API
by Alexandru Gagniuc June 3, 2013

June 3, 2013
Alexandru Gagniuc (mr.nuke.me(a)gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/143 -gerrit commit 1428f396d900f3c86a4c1a9eec43ed66efefb702 Author: Alexandru Gagniuc <mr.nuke.me(a)gmail.com> Date: Tue May 21 12:17:58 2013 -0500 coreboot: Add generic early SMBus API Early SMBUS code with similar functionality is duplicated for all southbridges. Add a generic SMBus API (function declarations) designed to unify the early SMBus structure. This patch only adds the API. It does not implement any hardware-specific bits. Change-Id: I0861b7a3f098115182ae6de9f016dd671c500bad Signed-off-by: Alexandru Gagniuc <mr.nuke.me(a)gmail.com> --- src/include/device/early_smbus.h | 73 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/src/include/device/early_smbus.h b/src/include/device/early_smbus.h new file mode 100644 index 0000000..77c9078 --- /dev/null +++ b/src/include/device/early_smbus.h @@ -0,0 +1,73 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011 Alexandru Gagniuc <mr.nuke.me(a)gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/** + * @file early_smbus.h + * + * This file defines a common API for accessing the SMBus during early + * initialization. It defines the prototypes for common SMBus functions. The + * actual implementations are hardware-dependent. + * + * The first parameter of all SMBus functions take a u32 value smbus_dev which + * represents some information on how to access the device, and is + * implementation defined. Usually, it just contains the IO base for the smbus. + * To get this argument @ref smbus_get_device() can be used. + * + * The header only defines the prototypes. Several steps are needed to use + * these: + * + * 1. Include this header + * @code{.c} + * #include <device/early_smbus.h> + * @endcode + * + * 2. Implement early_smbus.c for the hardware, or find a compatible + * implementation. + * + * 3. Link against the file that implements these functions. In the Makefile.inc + * of the chipset, add: + * @code + * romstage-y += ./path/to/early_smbus.c + * @endcode + */ + +#ifndef DEVICE_EARLY_SMBUS_H +#define DEVICE_EARLY_SMBUS_H + +#include <stdint.h> + +/** + * \brief printk macro for SMBus debugging + */ +#if defined(CONFIG_DEBUG_SMBUS_SETUP) && (CONFIG_DEBUG_SMBUS_SETUP) +#define printsmbus(x, ...) printk(BIOS_DEBUG, x, ##__VA_ARGS__) +#else +#define printsmbus(x, ...) +#endif + +u32 smbus_get_device(void); +void smbus_reset(u32 smbus_dev); +int smbus_print_error(u32 smbus_dev, u8 host_status, int loops); +int smbus_is_busy(u32 smbus_dev); +int smbus_wait_until_ready(u32 smbus_dev); +u8 smbus_read_byte(u32 smbus_dev, u8 addr, u8 offset); + +void smbus_delay(void); + +#endif /* DEVICE_EARLY_SMBUS_H */
1 0
0 0
Patch set updated for coreboot: 78ea169 spd.h: Add all known SPD_MEMORY_TYPE definitions.
by Alexandru Gagniuc June 3, 2013

June 3, 2013
Alexandru Gagniuc (mr.nuke.me(a)gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/3266 -gerrit commit 78ea16964ed165da3967270ee7b059e9773526f5 Author: Alexandru Gagniuc <mr.nuke.me(a)gmail.com> Date: Tue May 21 14:07:41 2013 -0500 spd.h: Add all known SPD_MEMORY_TYPE definitions. This file was missing some definitions, so add them. Also turn the defines into an enum. The reason for doing this is that functions can now explicitly take an spd_memory_type as a parameter: > int do_something_with_dram(enum spd_memory_type type, ...) Which is a lot more explicit and readable than: > int do_something_with_dram(u8 type, ...) These are used in the VX900 branch. Change-Id: Ic7871e82c2523a94eac8e07979a8e34e0b459b46 Signed-off-by: Alexandru Gagniuc <mr.nuke.me(a)gmail.com> --- src/include/spd.h | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/include/spd.h b/src/include/spd.h index e8d35cf..2b07fb1 100644 --- a/src/include/spd.h +++ b/src/include/spd.h @@ -108,15 +108,20 @@ /* SPD_MEMORY_TYPE values. */ -#define SPD_MEMORY_TYPE_FPM_DRAM 1 -#define SPD_MEMORY_TYPE_EDO 2 -#define SPD_MEMORY_TYPE_PIPELINED_NIBBLE 3 -#define SPD_MEMORY_TYPE_SDRAM 4 -#define SPD_MEMORY_TYPE_MULTIPLEXED_ROM 5 -#define SPD_MEMORY_TYPE_SGRAM_DDR 6 -#define SPD_MEMORY_TYPE_SDRAM_DDR 7 -#define SPD_MEMORY_TYPE_SDRAM_DDR2 8 -#define SPD_MEMORY_TYPE_SDRAM_DDR3 0xb +enum spd_memory_type { + SPD_MEMORY_TYPE_UNDEFINED = 0x00, + SPD_MEMORY_TYPE_FPM_DRAM = 0x01, + SPD_MEMORY_TYPE_EDO = 0x02, + SPD_MEMORY_TYPE_PIPELINED_NIBBLE = 0x03, + SPD_MEMORY_TYPE_SDRAM = 0x04, + SPD_MEMORY_TYPE_MULTIPLEXED_ROM = 0x05, + SPD_MEMORY_TYPE_SGRAM_DDR = 0x06, + SPD_MEMORY_TYPE_SDRAM_DDR = 0x07, + SPD_MEMORY_TYPE_SDRAM_DDR2 = 0x08, + SPD_MEMORY_TYPE_FBDIMM_DDR2 = 0x09, + SPD_MEMORY_TYPE_FB_PROBE_DDR2 = 0x0a, + SPD_MEMORY_TYPE_SDRAM_DDR3 = 0x0b, +}; /* SPD_MODULE_VOLTAGE values. */ #define SPD_VOLTAGE_TTL 0 /* 5.0 Volt/TTL */
1 0
0 0
Patch set updated for coreboot: 70cb273 pci_ids.h: Add PCI IDs for VIA VX900 chipset
by Alexandru Gagniuc June 3, 2013

June 3, 2013
Alexandru Gagniuc (mr.nuke.me(a)gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/3268 -gerrit commit 70cb273df55938fc546bc86189f27711734d2572 Author: Alexandru Gagniuc <mr.nuke.me(a)gmail.com> Date: Tue May 21 14:50:19 2013 -0500 pci_ids.h: Add PCI IDs for VIA VX900 chipset Change-Id: I4a75326fef0a10a6290cdd4b1b93d9af8e3ab23d Signed-off-by: Alexandru Gagniuc <mr.nuke.me(a)gmail.com> --- src/include/device/pci_ids.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/include/device/pci_ids.h b/src/include/device/pci_ids.h index e9e5ab7..6fd44ea 100644 --- a/src/include/device/pci_ids.h +++ b/src/include/device/pci_ids.h @@ -1337,6 +1337,29 @@ #define PCI_DEVICE_ID_VIA_VX855_VGA 0x5122 #define PCI_DEVICE_ID_VIA_VX855_VLINK 0x7409 #define PCI_DEVICE_ID_VIA_VX855_MEMCTRL 0x3409 +/* VIA VX900 PCI IDs */ +#define PCI_DEVICE_ID_VIA_VX900_HOST_BR 0x0410 +#define PCI_DEVICE_ID_VIA_VX900_ERR 0x1410 +#define PCI_DEVICE_ID_VIA_VX900_CPU_CTR 0x2410 +#define PCI_DEVICE_ID_VIA_VX900_MEMCTRL 0x3410 +#define PCI_DEVICE_ID_VIA_VX900_PM 0x4410 +#define PCI_DEVICE_ID_VIA_VX900_TRAF 0x5410 +#define PCI_DEVICE_ID_VIA_VX900_SCRATCH 0x6410 +#define PCI_DEVICE_ID_VIA_VX900_NBRIDGE 0x7410 +#define PCI_DEVICE_ID_VIA_VX900_LPC 0x8410 +#define PCI_DEVICE_ID_VIA_VX900_PEX1 0xa410 +#define PCI_DEVICE_ID_VIA_VX900_PEX2 0xb410 +#define PCI_DEVICE_ID_VIA_VX900_PEX3 0xc410 +#define PCI_DEVICE_ID_VIA_VX900_PEX4 0xd410 +#define PCI_DEVICE_ID_VIA_VX900_PEX_CTR 0xe410 +#define PCI_DEVICE_ID_VIA_VX900_SNMIC 0xa353 +#define PCI_DEVICE_ID_VIA_VX900_PCI_BR 0xb353 +#define PCI_DEVICE_ID_VIA_VX900_VGA 0x7122 +#define PCI_DEVICE_ID_VIA_VX900_VID_DEC 0x9170 +#define PCI_DEVICE_ID_VIA_VX900_HDAC 0x3288 +#define PCI_DEVICE_ID_VIA_VX900_ETH 0x3119 +#define PCI_DEVICE_ID_VIA_VX900_SATA 0x9001 +/* VIA CN700 */ #define PCI_DEVICE_ID_VIA_CN700_AGP 0x0314 #define PCI_DEVICE_ID_VIA_CN700_ERR 0x1314 #define PCI_DEVICE_ID_VIA_CN700_HOST 0x2314
1 0
0 0
Patch merged into coreboot/master: 373a20c Intel Lynx Point: LPC: Unify I/O APIC setup
by gerrit@coreboot.org June 2, 2013

June 2, 2013
the following patch was just integrated into master: commit 373a20c335bdd747d7a2553f0e72e2b3a46f86e8 Author: Paul Menzel <paulepanter(a)users.sourceforge.net> Date: Fri May 3 12:17:02 2013 +0200 Intel Lynx Point: LPC: Unify I/O APIC setup Remove local copies of reading and writing I/O APIC registers by using already available functions. This change is similar to commit db4f875a412e6c41f48a86a79b72465f6cd81635 Author: Kyösti Mälkki <kyosti.malkki(a)gmail.com> Date: Tue Jan 31 17:24:12 2012 +0200 IOAPIC: Divide setup_ioapic() in two parts. Reviewed-on: http://review.coreboot.org/300 and commit e614353194c712a40aa8444a530b2062876eabe3 Author: Kyösti Mälkki <kyosti.malkki(a)gmail.com> Date: Tue Feb 26 17:24:41 2013 +0200 Unify setting 82801a/b/c/d IOAPIC ID Reviewed-on: http://review.coreboot.org/2532 and uses `io_apic_read()` and `io_apic_write()` too. Define `ACPI_EN` in the header file `pch.h`. As commented by Aaron Durbin, a separate `pch_enable_acpi()` is not needed: “The existing code path *in this file* is about enabling the io apic.” [1]. [1] http://review.coreboot.org/#/c/3182/4/src/southbridge/intel/lynxpoint/lpc.c Change-Id: I6f2559f1d134590f781bd2cb325a9560512285dc Signed-off-by: Paul Menzel <paulepanter(a)users.sourceforge.net> Reviewed-on: http://review.coreboot.org/3182 Tested-by: build bot (Jenkins) Reviewed-by: Aaron Durbin <adurbin(a)google.com> See http://review.coreboot.org/3182 for details. -gerrit
1 0
0 0
  • ← Newer
  • 1
  • ...
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • Older →

HyperKitty Powered by HyperKitty version 1.3.12.