Alexandru Gagniuc (mr.nuke.me@gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/1228
-gerrit
commit 41007e3b4e147d62c8576bee747ebbb6722f3bef Author: Alexandru Gagniuc mr.nuke.me@gmail.com Date: Mon Aug 1 05:16:20 2011 -0500
NOTFORMERGE: VX900 early init, Nano CPU init, and EPIA M850 board
Early initialization for VIA VX900:
SMBUS is functional. Raminit works with 1 rank, but untested with several ranks. DRAM calibration when more than one DIMM is present is not fully implemented. Correct MRS command mapping not implemented for DIMMS which swap address pins.
The delay calibration strategy is to put some predefined delays for the MD 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 MD input. Unfortunately, according to my testing, the MD input delay calibration does not work reliably.
VIA nano CPU init:
Microcode updating works. Attempting to change the voltage or frequency of the CPU without applying the microcode update will hang the CPU, so we only do transitions if we can verify the microcode has been updated. A few microcode verification utilities were added in anticipation of loading the microcode entirely from CBFS.
VX900 + VX800 related changes:
Added LPC driver struct in VX800 code. The LPCs seem to be similar enough that the VX800 LPC code works on the VX900
VIA EPIA M850 board: Minimum infrastructure to compile a coreboot image for this board is added; most PCI devices are switched off in devicetree.cb
Other Changes:
Moved UPDATE_CPU_MICROCODE to src/cpu/Kconfig to make it a more "global" option, and made it depend on RESPECT_UPDATE_CPU_MICROCODE_OPTION I will submit this as a separate patch once I figure out how to only push this part of my branch
Change-Id: I7624944dbc05fbf3019897a116954d71dfda0031 Signed-off-by: Alexandru Gagniuc mr.nuke.me@gmail.com --- src/arch/x86/include/arch/romcc_io.h | 28 + src/cpu/Kconfig | 37 + src/cpu/amd/model_10xxx/Kconfig | 33 +- src/cpu/via/Kconfig | 1 + src/cpu/via/Makefile.inc | 5 +- src/cpu/via/nano/Kconfig | 41 ++ src/cpu/via/nano/Makefile.inc | 30 + src/cpu/via/nano/nano_init.c | 168 +++++ src/cpu/via/nano/nano_ucode_010f07d9.h | 963 ++++++++++++++++++++++++++ src/cpu/via/nano/update_ucode.c | 161 +++++ src/cpu/via/nano/update_ucode.h | 79 +++ src/devices/dram/dram.h | 154 +++++ src/devices/dram/dram_util.c | 297 ++++++++ src/devices/smbus/early_smbus.c | 141 ++++ src/devices/smbus/smbus.h | 99 +++ src/include/device/pci_ids.h | 22 + src/mainboard/asus/Kconfig | 2 +- src/mainboard/via/Kconfig | 3 + src/mainboard/via/epia-m850/Kconfig | 47 ++ src/mainboard/via/epia-m850/Makefile.inc | 21 + src/mainboard/via/epia-m850/chip.h | 21 + src/mainboard/via/epia-m850/devicetree.cb | 63 ++ src/mainboard/via/epia-m850/mainboard.c | 25 + src/mainboard/via/epia-m850/romstage.c | 78 +++ src/northbridge/via/Kconfig | 1 + src/northbridge/via/Makefile.inc | 1 + src/northbridge/via/vx800/lpc.c | 6 + src/northbridge/via/vx900/Kconfig | 23 + src/northbridge/via/vx900/Makefile.inc | 34 + src/northbridge/via/vx900/chip.h | 23 + src/northbridge/via/vx900/early_smbus.c | 191 ++++++ src/northbridge/via/vx900/early_vx900.h | 35 + src/northbridge/via/vx900/forgotten.c | 192 ++++++ src/northbridge/via/vx900/forgotten.h | 78 +++ src/northbridge/via/vx900/northbridge.c | 91 +++ src/northbridge/via/vx900/raminit.h | 77 +++ src/northbridge/via/vx900/raminit_ddr3.c | 1053 +++++++++++++++++++++++++++++ src/northbridge/via/vx900/romstrap.inc | 50 ++ src/northbridge/via/vx900/romstrap.lds | 27 + src/northbridge/via/vx900/vx900.h | 26 + 40 files changed, 4392 insertions(+), 35 deletions(-)
diff --git a/src/arch/x86/include/arch/romcc_io.h b/src/arch/x86/include/arch/romcc_io.h index 37fb7ab..8876b28 100644 --- a/src/arch/x86/include/arch/romcc_io.h +++ b/src/arch/x86/include/arch/romcc_io.h @@ -244,6 +244,34 @@ static inline __attribute__((always_inline)) void pci_write_config32(device_t de #endif }
+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); +} + #define PCI_DEV_INVALID (0xffffffffU) static inline device_t pci_io_locate_device(unsigned pci_id, device_t dev) { diff --git a/src/cpu/Kconfig b/src/cpu/Kconfig index 85e83d4..dbeed9d 100644 --- a/src/cpu/Kconfig +++ b/src/cpu/Kconfig @@ -62,3 +62,40 @@ config SSE2 with more efficient code if SSE2 instructions are available.
endif # ARCH_X86 + +# The following option lets us know that the CPU initialization code will check +# for UPDATE_CPU_MICROCODE, and will not include any microcode updates in the +# image if it detects this option. +# This must only be selected by CPUs whose microcode update has been adjusted +# to respect UPDATE_CPU_MICROCODE option. +config RESPECTS_UPDATE_CPU_MICROCODE_OPTION + bool + default n + +config UPDATE_CPU_MICROCODE + bool "Update CPU microcode" + default y + depends on EXPERT && HAS_OPTION_NO_MICROCODE_UPDATE + help + Select this to apply patches to the CPU microcode provided by the + vendor (without source), and distributed with coreboot, to address + issues in the CPU post production. + + Microcode updates distributed with coreboot are not necessarily the + latest version available. Updates are only applied if they are newer + than the microcode already in the CPU. + + Unselect this to let CPUs run with microcode as shipped from factory. + No binary microcode patches will be included in the coreboot image in + that case, which can help with creating an image for which complete + source code is available, which in turn might simplify license + compliance. + + Microcode updates intend to solve issues that have been discovered + after CPU production. The common case is that systems work as intended + with updated microcode, but we have also seen cases where issues were + solved by not applying the microcode updates. + + Note that some operating system include these same microcode patches, + so you may need to also disable microcode updates in your operating + system in order for this option to matter. diff --git a/src/cpu/amd/model_10xxx/Kconfig b/src/cpu/amd/model_10xxx/Kconfig index 221d044..64ac850 100644 --- a/src/cpu/amd/model_10xxx/Kconfig +++ b/src/cpu/amd/model_10xxx/Kconfig @@ -3,6 +3,7 @@ config CPU_AMD_MODEL_10XXX select SSE select SSE2 select MMCONF_SUPPORT_DEFAULT + select RESPECTS_UPDATE_CPU_MICROCODE_OPTION
if CPU_AMD_MODEL_10XXX config CPU_ADDR_BITS @@ -51,36 +52,4 @@ config SET_FIDVID_CORE_RANGE
endif # SET_FIDVID
-config UPDATE_CPU_MICROCODE - bool - default y - -config UPDATE_CPU_MICROCODE - bool "Update CPU microcode" - default y - depends on EXPERT && CPU_AMD_MODEL_10XXX - help - Select this to apply patches to the CPU microcode provided by - AMD without source, and distributed with coreboot, to address - issues in the CPU post production. - - Microcode updates distributed with coreboot are not necessarily - the latest version available from AMD. Updates are only applied - if they are newer than the microcode already in your CPU. - - Unselect this to let Fam10h CPUs run with microcode as shipped - from factory. No binary microcode patches will be included in the - coreboot image in that case, which can help with creating an image - for which complete source code is available, which in turn might - simplify license compliance. - - Microcode updates intend to solve issues that have been discovered - after CPU production. The common case is that systems work as - intended with updated microcode, but we have also seen cases where - issues were solved by not applying the microcode updates. - - Note that some operating system include these same microcode - patches, so you may need to also disable microcode updates in - your operating system in order for this option to matter. - endif # CPU_AMD_MODEL_10XXX diff --git a/src/cpu/via/Kconfig b/src/cpu/via/Kconfig index 570d408..5c38c91 100644 --- a/src/cpu/via/Kconfig +++ b/src/cpu/via/Kconfig @@ -1,2 +1,3 @@ source src/cpu/via/c3/Kconfig source src/cpu/via/c7/Kconfig +source src/cpu/via/nano/Kconfig diff --git a/src/cpu/via/Makefile.inc b/src/cpu/via/Makefile.inc index 2616111..bdfef0e 100644 --- a/src/cpu/via/Makefile.inc +++ b/src/cpu/via/Makefile.inc @@ -1,3 +1,4 @@ -subdirs-$(CONFIG_CPU_VIA_C7) += c7 -subdirs-$(CONFIG_CPU_VIA_C3) += c3 +subdirs-$(CONFIG_CPU_VIA_C7) += c7 +subdirs-$(CONFIG_CPU_VIA_C3) += c3 +subdirs-$(CONFIG_CPU_VIA_NANO) += nano
diff --git a/src/cpu/via/nano/Kconfig b/src/cpu/via/nano/Kconfig new file mode 100644 index 0000000..5601f6a --- /dev/null +++ b/src/cpu/via/nano/Kconfig @@ -0,0 +1,41 @@ +## +## This file is part of the coreboot project. +## +## Copyright (C) 2011 Alexandru Gagniuc mr.nuke.me@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 CPU_VIA_NANO + bool + +if CPU_VIA_NANO + +config CPU_SPECIFIC_OPTIONS + def_bool y + select UDELAY_TSC + select MMX + select SSE2 + select CACHE_AS_RAM + select RESPECTS_UPDATE_CPU_MICROCODE_OPTION + +config DCACHE_RAM_BASE + hex + default 0xffef0000 + +config DCACHE_RAM_SIZE + hex + default 0x8000 + +endif # CPU_VIA_C7 diff --git a/src/cpu/via/nano/Makefile.inc b/src/cpu/via/nano/Makefile.inc new file mode 100644 index 0000000..d167eac --- /dev/null +++ b/src/cpu/via/nano/Makefile.inc @@ -0,0 +1,30 @@ +## +## This file is part of the coreboot project. +## +## Copyright (C) 2012 Alexandru Gagniuc mr.nuke.me@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/. +## + +subdirs-y += ../../x86/tsc +subdirs-y += ../../x86/mtrr +subdirs-y += ../../x86/lapic +subdirs-y += ../../x86/cache +subdirs-y += ../../x86/smm +subdirs-y += ../../intel/microcode + +driver-y += nano_init.c +ramstage-$(CONFIG_UPDATE_CPU_MICROCODE) += update_ucode.c + +cpu_incs += $(src)/cpu/via/car/cache_as_ram.inc diff --git a/src/cpu/via/nano/nano_init.c b/src/cpu/via/nano/nano_init.c new file mode 100644 index 0000000..96ae599 --- /dev/null +++ b/src/cpu/via/nano/nano_init.c @@ -0,0 +1,168 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 Alexandru Gagniuc mr.nuke.me@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 "update_ucode.h" +#include <console/console.h> +#include <device/device.h> +#include <cpu/cpu.h> +#include <cpu/x86/mtrr.h> +#include <cpu/x86/msr.h> +#include <cpu/x86/lapic.h> +#include <cpu/x86/cache.h> +#include <delay.h> + +#define MODEL_NANO 0x3 +#define MODEL_NANO_3000_B0 0x8 +#define MODEL_NANO_3000_B2 0xa + +#define MSR_IA32_PERF_STATUS 0x00000198 +#define MSR_IA32_PERF_CTL 0x00000199 +#define MSR_IA32_MISC_ENABLE 0x000001a0 + + +static u16 nano_vid_to_mv(u8 vid) +{ + return (15000 - 125 * vid) / 10; +} + +static void nano_power(void) +{ + msr_t msr; + /* Enable Powersaver */ + msr = rdmsr(MSR_IA32_MISC_ENABLE); + msr.lo |= (1 << 16); + wrmsr(MSR_IA32_MISC_ENABLE, msr); + + /* Enable 6 bit or 7-bit VRM support + * If we don't do this, then trying to change the VID or FID will hang + * the CPU. This MSR is not documented in VIA docs*/ + msr = rdmsr(0x120e); + msr.lo |= ( (1<<7) | (1<<4) ); + /* FIXME: set bit 5 for 7-bit, or don't set for 6 bit + * This will probably require a config option */ + msr.lo |= (1<<5); + wrmsr(0x120e, msr); + + /* Get voltage and frequency info */ + msr = rdmsr(MSR_IA32_PERF_STATUS); + u8 min_fid = (msr.hi >> 24); + u8 max_fid = (msr.hi >> 8) & 0xff; + u8 min_vid = (msr.hi >> 16) & 0xff; + u8 max_vid = (msr.hi >> 0) & 0xff; + u8 cur_vid = (msr.lo >> 0) & 0xff; + u8 cur_fid = (msr.lo >> 8) & 0xff; + + printk(BIOS_DEBUG, "MSR %.8x:%.8x\n", msr.hi, msr.lo); + printk(BIOS_INFO, "FID: %dx (min %dx; max %dx)\n", + cur_fid, min_fid, max_fid); + printk(BIOS_INFO, "VID: %dx (min %dx; max %dx)\n", + cur_vid, min_vid, max_vid); + + printk(BIOS_INFO, "Voltage: %dmV (min %dmV; max %dmV)\n", + nano_vid_to_mv(cur_vid), + nano_vid_to_mv(min_vid), + nano_vid_to_mv(max_vid)); + + printk(BIOS_INFO, "CPU multiplier: %dx (min %dx; max %dx)\n", + (int)((msr.lo >> 8) & 0xff), + (int)((msr.hi >> 24) & 0xff), (int)((msr.hi >> 8) & 0xff)); + + /* Set highest frequency and VID*/ + msr.lo = msr.hi; + msr.hi = 0; + wrmsr(MSR_IA32_PERF_CTL, msr); + + /* We could wait while CPU is executing the frequency transition, but + * the Nano has 2 PLLs, and will instantly switch once the second PLL + * is locked and ready. + * As a side note, if we didn't update the microcode by this point, the + * second PLL will not lock correctly. The clock will still be provided + * by the first PLL, and execution will continue normally, ___until___ + * the CPU switches PLL. Once that happens we will no longer have a + * working clock source, and the CPU will hang + * Moral of the story: update the microcode, or don't change FID */ + + printk(BIOS_DEBUG, "MSR 01a0 hi: 0x%.8x lo: 0x%.8x\n", msr.hi, msr.lo); + + msr = rdmsr(0x120e); + printk(BIOS_DEBUG, "MSR 120e hi: 0x%.8x lo: 0x%.8x\n", msr.hi, msr.lo); +} + +static void nano_init(device_t dev) +{ + print_debug(" Nano POWER:\n"); + struct cpuinfo_x86 c; + + get_fms(&c, dev->device); + + switch (c.x86_mask) { + case MODEL_NANO: + printk(BIOS_INFO, "VIA Nano"); + break; + case MODEL_NANO_3000_B0: + printk(BIOS_INFO, "VIA Nano 3000 rev B0"); + break; + case MODEL_NANO_3000_B2: + printk(BIOS_INFO, "VIA Nano 3000 rev B2"); + break; + default: + printk(BIOS_EMERG, "CPU not recognized: %x\n", c.x86_mask); + } + printk(BIOS_INFO, "\n"); + + /* This will have been defined as an empty function if microcode + * updates were disabled in Kconfig, and no ucode binary will have + * been included in the ROM */ + unsigned int n_updates = nano_update_ucode(); + + if(n_updates != 0){ + nano_power(); + } else { + /* Changing the frequency or voltage without first updating the + * microcode will hang the CPU, so just don't do it */ + printk(BIOS_EMERG, "WARNING: CPU Microcode not updated.\n" + " Will not change frequency, as this may hang the CPU.\n"); + } + + /* Turn on cache */ + x86_enable_cache(); + + /* Set up Memory Type Range Registers */ + x86_setup_mtrrs(); + x86_mtrr_check(); + + /* Enable the local cpu apics */ + setup_lapic(); +} + +static struct device_operations cpu_dev_ops = { + .init = nano_init, +}; + +static struct cpu_device_id cpu_table[] = { + {X86_VENDOR_CENTAUR, 0x06f2}, // VIA NANO 1000/2000 Series + {X86_VENDOR_CENTAUR, 0x06f8}, // VIA NANO 3000 rev B0 + {X86_VENDOR_CENTAUR, 0x06fa}, // VIA NANO 3000 rev B2 + {0, 0}, +}; + +static const struct cpu_driver driver __cpu_driver = { + .ops = &cpu_dev_ops, + .id_table = cpu_table, +}; \ No newline at end of file diff --git a/src/cpu/via/nano/nano_ucode_010f07d9.h b/src/cpu/via/nano/nano_ucode_010f07d9.h new file mode 100644 index 0000000..41bb394 --- /dev/null +++ b/src/cpu/via/nano/nano_ucode_010f07d9.h @@ -0,0 +1,963 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 Alexandru Gagniuc mr.nuke.me@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 defined(CONFIG_UPDATE_CPU_MICROCODE) && (CONFIG_UPDATE_CPU_MICROCODE != 0) + +static const unsigned int ucode_6f2_0[] __attribute__ ((aligned(32))) = +{ + 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, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, +}; + +static const unsigned int ucode_6f3_0[] __attribute__ ((aligned(32))) = +{ + 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, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, +}; + +static const unsigned int ucode_6f8_0[] __attribute__ ((aligned(32))) = +{ + 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, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, +}; + +static const unsigned int ucode_6f8_1[] __attribute__ ((aligned(32))) = +{ + 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, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, +}; + +static const unsigned int ucode_6fa_0[] __attribute__ ((aligned(32))) = +{ + 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, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, +}; + +static const unsigned int ucode_6fa_1[] __attribute__ ((aligned(32))) = +{ + 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, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, +}; + +static const unsigned int ucode_6fa_2[] __attribute__ ((aligned(32))) = +{ + 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, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, +}; + + +const u32* microcode_updates[] = +{ + ucode_6f2_0, + ucode_6f3_0, + ucode_6f8_0, ucode_6f8_1, + ucode_6fa_0, ucode_6fa_1, ucode_6fa_2, + 0x00000000 +}; +#endif diff --git a/src/cpu/via/nano/update_ucode.c b/src/cpu/via/nano/update_ucode.c new file mode 100644 index 0000000..dc896f5 --- /dev/null +++ b/src/cpu/via/nano/update_ucode.c @@ -0,0 +1,161 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 Alexandru Gagniuc mr.nuke.me@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 "update_ucode.h" +#include "nano_ucode_010f07d9.h" +#include <cpu/x86/msr.h> +#include <console/console.h> +#include <stddef.h> +#include <cpu/cpu.h> +#include <arch/cpu.h> + +static ucode_update_status nano_apply_ucode(const u32* location) +{ + printk(BIOS_INFO, "Attempting to apply microcode update\n"); + + msr_t msr; + const nano_ucode_header * head = (void *)location; + + /* FIXME: We are not sure this is needed, but we are doing it anyway */ + msr.hi = msr.lo = 0; + //wrmsr(MSR_IA32_BIOS_SIGN_ID, msr); + + /* Address of ucode block goes in msr.lo for 32-bit mode + * Now remember, we need to pass the address of the actual microcode, + * not the header. The header is just there to help us. + */ + msr.lo = (unsigned int)(&(head->ucode_start)); + msr.hi = 0; + wrmsr(MSR_IA32_BIOS_UPDT_TRIG, msr); + + /* Let's see if we updated succesfully */ + msr = rdmsr(MSR_UCODE_UPDATE_STATUS); + + return msr.lo & 0x07; +} + +static void nano_print_ucode_info(const u32* location) +{ + const nano_ucode_header * head = (void *)location; + printk(BIOS_SPEW, "Microcode update information:\n"); + printk(BIOS_SPEW, "Name: %8s\n", + head->name + ); + printk(BIOS_SPEW, "Date: %u/%u/%u\n", head->month, + head->day, head->year ); +} + +static ucode_validity nano_ucode_is_valid(const u32* location) +{ + const nano_ucode_header * head = (void *)location; + /* We must have a valid signature */ + if(head->signature != NANO_UCODE_SIGNATURE) + return NANO_UCODE_SIGNATURE_ERROR; + /* The size of the head must be exactly 12 double words */ + if(( head->total_size - head->payload_size) != NANO_UCODE_HEADER_SIZE) + return NANO_UCODE_WRONG_SIZE; + + /* How about a checksum ? Checksum must be 0 + * Two's complement done over the entire file, including the header */ + int i; u32 check = 0; + for(i = 0 ; i < ((head->total_size) >> 2); i++) { + check += location[i]; + } + if(check != 0) + return NANO_UCODE_CHECKSUM_FAIL; + /* Made it here huh? + * If there's anything else wrong, the CPU will reject the update */ + return NANO_UCODE_VALID; +} + +static void nano_print_ucode_invalid_reason(ucode_validity why) +{ + switch(why) { + case NANO_UCODE_VALID: + break; /* No error */ + case NANO_UCODE_SIGNATURE_ERROR: + printk(BIOS_SPEW, "Microcode signature is invalid.\n"); + break; + case NANO_UCODE_WRONG_SIZE: + printk(BIOS_SPEW, "Microcode header has wrong size.\n"); + break; + case NANO_UCODE_CHECKSUM_FAIL: + printk(BIOS_SPEW, "Microcode checksum verification failed.\n"); + break; + default: + /* We should _never get this */ + printk(BIOS_SPEW, "Microcode check failed with unknown code." + "Please report this issue.\n" ); + } +} + +static void nano_print_ucode_status(ucode_update_status stat) +{ + switch(stat) + { + case UCODE_UPDATE_SUCCESS: + printk(BIOS_INFO, "Microcode update succesful.\n"); + break; + case UCODE_UPDATE_FAIL: + printk(BIOS_ALERT, "Microcode update failed, bad environment." + "Update was not applied.\n"); + break; + case UCODE_UPDATE_WRONG_CPU: + printk(BIOS_ALERT, "Update not applicable to this CPU.\n"); + break; + case UCODE_INVALID_UPDATE_BLOCK: + printk(BIOS_ALERT, "Microcode block invalid." + "Update was not applied.\n"); + break; + default: + printk(BIOS_ALERT, "Unknown status. No update applied.\n"); + } +} + +unsigned int nano_update_ucode(void) +{ + unsigned int n_updates = 0; + u32 fms = cpuid_eax(0x1); + const nano_ucode_header * head; + /* Nano CPUs are able to combine multiple concurrent microcode updates, + * Thus, we may have more than one update to apply */ + size_t i; + for(i = 0; microcode_updates[i] != 0; i++) + { + ucode_update_status stat; + const u32* current = microcode_updates[i]; + head = (void *)current; + /* Check if update matches our CPU */ + if(head->applicable_fms != fms) continue; + /* HA!!!! Update found, but is it valid */ + ucode_validity is_valid = nano_ucode_is_valid(current); + if(is_valid != NANO_UCODE_VALID) { + nano_print_ucode_invalid_reason(is_valid); + continue; + } + nano_print_ucode_info(current); + stat = nano_apply_ucode(current); + /* The user might want to know how the update went */ + nano_print_ucode_status(stat); + if(stat == UCODE_UPDATE_SUCCESS) n_updates++; + } + + return n_updates; + +} \ No newline at end of file diff --git a/src/cpu/via/nano/update_ucode.h b/src/cpu/via/nano/update_ucode.h new file mode 100644 index 0000000..b9c6a00 --- /dev/null +++ b/src/cpu/via/nano/update_ucode.h @@ -0,0 +1,79 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 Alexandru Gagniuc mr.nuke.me@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 __UPDATE_UCODE_C +#define __UPDATE_UCODE_C + +#include <console/console.h> +#include <cpu/cpu.h> + +#define MSR_IA32_BIOS_UPDT_TRIG 0x00000079 +#define MSR_IA32_BIOS_SIGN_ID 0x0000008b +#define MSR_UCODE_UPDATE_STATUS 0x00001205 + +#define NANO_UCODE_SIGNATURE 0x53415252 +#define NANO_UCODE_HEADER_SIZE 0x30 + +/* We care what these values are exactly, so we define them to be sure */ +typedef enum ucode_update_status_enum { + UCODE_UPDATE_NOT_ATTEMPTED = 0x0, + UCODE_UPDATE_SUCCESS = 0x1, + UCODE_UPDATE_FAIL = 0x2, + UCODE_UPDATE_WRONG_CPU = 0x3, + UCODE_INVALID_UPDATE_BLOCK = 0x4, +} ucode_update_status; + + +typedef enum ucode_validity_enum { + NANO_UCODE_VALID = 0, /* We only care that valid == 0 */ + NANO_UCODE_SIGNATURE_ERROR, + NANO_UCODE_WRONG_SIZE, + NANO_UCODE_CHECKSUM_FAIL, +} ucode_validity; + +typedef struct nano_ucode_header_st { + u32 signature; /* NANO_UCODE_SIGNATURE */ + u32 update_revision; /* Revision of the update header */ + u16 year; /* Year of patch release */ + u8 day; /* Day of patch release */ + u8 month; /* Month of patch release */ + u32 applicable_fms; /* Fam/model/stepping to which ucode applies */ + u32 checksum; /* Two's complement checksum of ucode+header */ + u32 loader_revision; /* Revision of hardware ucode update loader*/ + u32 rfu_1; /* Reservod for future use */ + u32 payload_size; /* Size of the ucode payload only */ + u32 total_size; /* Size of the ucode, including header */ + char name[8]; /* ASCII string of ucode filename */ + u32 rfu_2; /* Reservod for future use */ + /* First double-word of the ucode payload + * Its address represents the beginning of the ucode update we need to + * send to the CPU */ + u32 ucode_start; + +}nano_ucode_header; + +#if defined(CONFIG_UPDATE_CPU_MICROCODE) && CONFIG_UPDATE_CPU_MICROCODE != 0 +unsigned int nano_update_ucode(void); +#else +static unsigned int nano_update_ucode(void) +{ + printk(BIOS_INFO, "CPU Microcode updating disabled.\n"); + return 0; +} +#endif +#endif /* __UPDATE_UCODE_C */ \ No newline at end of file diff --git a/src/devices/dram/dram.h b/src/devices/dram/dram.h new file mode 100644 index 0000000..d79cc52 --- /dev/null +++ b/src/devices/dram/dram.h @@ -0,0 +1,154 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011 Alexandru Gagniuc mr.nuke.me@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 DRAM_H +#define DRAM_H + +#include <stdint.h> + +/* DRAM type, byte 2 of spd */ +#define DRAM_TYPE_UNDEFINED 0x00 +#define DRAM_TYPE_FPM_DRAM 0x01 +#define DRAM_TYPE_EDO 0x02 +#define DRAM_TYPE_PIPELINED_NIBBLE 0x03 +#define DRAM_TYPE_SDRAM 0x04 +#define DRAM_TYPE_ROM 0x05 +#define DRAM_TYPE_DDR_SGRAM 0x06 +#define DRAM_TYPE_DDR 0x07 +#define DRAM_TYPE_DDR2 0x08 +#define DRAM_TYPE_DDR2_FBDIMM 0x09 +#define DRAM_TYPE_DDR2_FB_PROBE 0x0a +#define DRAM_TYPE_DDR3 0x0b + +/* Module type (byte 3, bits 3:0) of SPD */ +#define DIMM_TYPE_UNDEFINED 0 +#define DIMM_TYPE_RDIMM 1 +#define DIMM_TYPE_UDIMM 2 +#define DIMM_TYPE_SO_DIMM 3 +#define DIMM_TYPE_MICRO_DIMM 4 +#define DIMM_TYPE_MINI_RDIMM 5 +#define DIMM_TYPE_MINI_UDIMM 6 +#define DIMM_TYPE_MINI_CDIMM 7 +#define DIMM_TYPE_72B_SO_UDIMM 8 +#define DIMM_TYPE_72B_SO_RDIMM 9 +#define DIMM_TYPE_72B_SO_CDIMM 10 + +#if defined(CONFIG_DEBUG_RAM_SETUP) && (CONFIG_DEBUG_RAM_SETUP) +#define printram(x, ...) printk(BIOS_DEBUG, x, ##__VA_ARGS__) +#else +#define printram(x, ...) +#endif + +/* Different values for tCK, representing standard DDR3 frequencies + * As always, 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 + +#define RAM_UNIT (1<<24) + +#include <stdint.h> + +/** + *\brief DIMM characteristics + * + * The characteristics of each DIMM, as presented by the SPD + */ +typedef struct dimm_attr_st { + u8 dram_type; + u16 cas_supported; + /* 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 (1 << 24) bytes (16MB) */ + u16 size; + /* Latencies 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; + +} dimm_attr; + +typedef struct ramctr_timing_st { + u8 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 */ + +} ramctr_timing; + + +typedef u8 spd_raw_data[256]; + +/** + * \brief Decode the raw spd data + */ +void spd_decode_ddr3(dimm_attr *dimm, spd_raw_data spd_data); + +/** + * \brief Checks if the DIMM is Registered based on byte[3] of the spd + */ +int dimm_is_registered(u8 spd_byte3); + +/** + * \brief Print the info in dimm + */ +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 + */ +u32 volatile_read(u32 addr); + +#endif /* DRAM_H */ diff --git a/src/devices/dram/dram_util.c b/src/devices/dram/dram_util.c new file mode 100644 index 0000000..75913e4 --- /dev/null +++ b/src/devices/dram/dram_util.c @@ -0,0 +1,297 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011 Alexandru Gagniuc mr.nuke.me@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 "dram.h" +#include <console/console.h> +#include <device/device.h> + +u32 volatile_read(volatile u32 addr) +{ + volatile u32 result; + result = *(volatile u32*)addr; + return result; +} + +int dimm_is_registered(u8 spd_byte3) +{ + spd_byte3 &= 0x0f; + if( (spd_byte3 == DIMM_TYPE_RDIMM) + | (spd_byte3 == DIMM_TYPE_MINI_RDIMM) + | (spd_byte3 == DIMM_TYPE_72B_SO_RDIMM) ) + return 1; + + return 0; +} + +void spd_decode_ddr3(dimm_attr *dimm, spd_raw_data spd) +{ + int nCRC, i; + u16 crc, spd_crc; + u8 * ptr = spd; + u8 ftb_divisor; + u8 ftb_dividend; + u8 capacity_shift, bus_width, sdram_width; + u32 mtb; /* medium time base */ + /* Make sure that the spd dump is indeed from a DDR3 module */ + if(spd[2] != DRAM_TYPE_DDR3) + { + printram("Not a DDR3 SPD!\n"); + dimm->dram_type = DRAM_TYPE_UNDEFINED; + return; + } + dimm->dram_type = DRAM_TYPE_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("SPD CRC failed!!!"); + + + unsigned int reg, val, param; + printram(" Revision: %x \n", spd[1] ); + printram(" Type : %x \n", spd[2] ); + printram(" Key : %x \n", spd[3] ); + + reg = spd[4]; + /* Number of memory banks */ + val = (reg >> 4) & 0x07; + if (val > 0x03) printram(" Invalid number of memory banks\n"); + param = 1 << (val + 3); + printram(" Banks : %u \n", param ); + /* SDRAM capacity */ + capacity_shift = reg & 0x0f; + if (capacity_shift > 0x06) printram(" Invalid module capacity\n"); + if (capacity_shift < 0x02) { + printram(" Capacity: %u Mb\n", 256 << capacity_shift); + } else { + printram(" Capacity: %u Gb\n", 1 << (capacity_shift - 2)); + } + + reg = spd[5]; + /* Row address bits */ + val = (reg >> 4) & 0x07; + if(val > 0x04) printram(" Invalid row address bits\n"); + dimm->row_bits = val + 12; + /* Column address bits */ + val = reg & 0x07; + if(val > 0x03) printram(" Invalid column address bits\n"); + dimm->col_bits = val + 9; + + /* Module nominal voltage */ + reg = spd[6]; + print_debug(" Supported voltages: "); + if(reg & (1<<2) ) print_debug("1.2V "); + if(reg & (1<<1) ) print_debug("1.35V "); + if( !(reg & (1<<0)) ) print_debug("1.5V "); + print_debug("\n"); + + /* Module organization */ + reg = spd[7]; + /* Number of ranks*/ + val = (reg >> 3) & 0x07; + if(val > 3) printram(" Invalid number of ranks\n"); + dimm->ranks = val + 1; + /* SDRAM device width */ + val = (reg & 0x07); + if(val > 3) printram(" Invalid SDRAM width\n"); + sdram_width = (4 << val); + printram(" SDRAM width : %u \n", sdram_width); + + /* Memory bus width */ + reg = spd[8]; + /* Bus extension */ + val = (reg >> 3) & 0x03; + if(val > 1) printram(" Invalid bus extension\n"); + printram(" Bus extension : %u bits\n", val?8:0); + /* Bus width */ + val = reg & 0x07; + if(val > 3) printram(" Invalid bus width\n"); + 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 */ + /* I am certain it will fit in 16 bits + * Remember, It's in units of 2^24 bytes*/ + dimm->size = ( (1 << (capacity_shift + (25-24)) ) * 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 */ + reg = spd[30]; + print_debug(" Optional features :"); + if(reg & 0x80) print_debug(" DLL-Off_mode"); + if(reg & 0x02) print_debug(" RZQ/7"); + if(reg & 0x01) print_debug(" RZQ/6"); + print_debug("\n"); + + /* SDRAM Thermal and Refresh Options */ + reg = spd[31]; + print_debug(" Thermal features :"); + if(reg & 0x80) print_debug(" PASR"); + if(reg & 0x08) print_debug(" ODTS"); + if(reg & 0x04) print_debug(" ASR"); + if(reg & 0x02) print_debug(" ext_temp_refresh"); + if(reg & 0x01) print_debug(" ext_temp_range"); + print_debug("\n"); + + /* Module Thermal Sensor */ + reg = spd[32]; + print_debug(" Thermal sensor : "); + if(reg & 0x80) print_debug("yes"); + else print_debug("no"); + print_debug("\n"); + + /* SDRAM Device Type */ + reg = spd[33]; + print_debug(" Standard SDRAM : "); + if(reg & 0x80) print_debug("no"); + else print_debug("yes"); + print_debug("\n"); + + /* Fine Offset for SDRAM Minimum Cycle Time (tCKmin) */ + //printram(" tCKmin FTB : %i \n", spd[34]); + /* Fine Offset for Minimum CAS Latency Time (tAAmin) */ + //printram(" tAAmin FTB : %i \n", spd[35]); + /* Fine Offset for Minimum RAS# to CAS# Delay Time (tRCDmin) */ + //printram(" tRCDmin FTB : %i \n", spd[36]); + /* Fine Offset for Minimum Row Precharge Delay Time (tRPmin) */ + //printram(" tRPmin FTB : %i \n", spd[37]); + /* Fine Offset for Minimum Active to Active/Refresh Delay Time (tRCmin) */ + //printram(" tRCmin FTB : %i \n", spd[38]); + + if(spd[60] & 0x01) + printram(" DIMM Address bits mirrorred!!!\n"); + +} + +static void print_ns(const char * msg, u32 val) +{ + u32 mant, fp; + mant = val/256; + fp = (val % 256) * 1000/256; + + printram("%s%3u.%.3u ns\n", msg, mant, fp); +} + +void dram_print_spd_ddr3(const dimm_attr *dimm) +{ + u16 val16; + int i; + + printram(" Row addr bits : %u \n", dimm->row_bits); + printram(" Column addr bits : %u \n", dimm->col_bits); + printram(" Number of ranks : %u \n", dimm->ranks); + printram(" DIMM Capacity : %u MB\n", dimm->size << 4); + + /* CAS Latencies Supported */ + val16 = dimm->cas_supported; + print_debug(" CAS latencies :"); + i = 0; + do{ + if(val16 & 1) printram(" %u", i + 4); + i++; + val16 >>= 1; + } while(val16); + print_debug("\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/devices/smbus/early_smbus.c b/src/devices/smbus/early_smbus.c new file mode 100644 index 0000000..4583aca --- /dev/null +++ b/src/devices/smbus/early_smbus.c @@ -0,0 +1,141 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011 Alexandru Gagniuc mr.nuke.me@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 post_codes.h + * + * This file defines the implementations for the functions defined in smbus.h + * These are a generic SMBUS implementation, which should work with a majority + * of chipsets. + * They are marked weak so that they can be overridden by the chipset code if + * necessary. + */ + +#include "smbus.h" + +/** + * \brief Brief delay for SMBUS transactions + */ +__attribute__((weak)) +void __smbus_delay(void) +{ + inb(0x80); +} + +/** + * \brief Clear the SMBUS host status register + */ +__attribute__((weak)) +void __smbus_reset(u16 __smbus_io_base) +{ + outb(0xdf, SMBHSTSTAT); +} + +/** + * \brief Print an error, should it occur. If no error, just exit. + * + * @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(u8 host_status, int loops, u16 __smbus_io_base) +{ + /* 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 + */ +__attribute__((weak)) +int __smbus_is_busy(u16 __smbus_io_base) +{ + /* Check if bit 0 of the status register is 1 (busy) or 0 (ready) */ + return ( (inb(SMBHSTSTAT) & (1 << 0)) == 1); +} + +/** + * \brief Wait for the SMBUS to become ready to process a new transaction. + */ +__attribute__((weak)) +int __smbus_wait_until_ready(u16 __smbus_io_base) +{ + 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_io_base) && loops < SMBUS_TIMEOUT) + ++loops; + + return __smbus_print_error(inb(SMBHSTSTAT), loops, __smbus_io_base); +} + +/** + * \brief 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. + */ +__attribute__((weak)) +u8 __smbus_read_byte(u8 dimm, u8 offset, u16 __smbus_io_base) +{ + u8 val; + + /* Initialize SMBUS sequence */ + __smbus_reset(__smbus_io_base); + /* Clear host data port. */ + outb(0x00, SMBHSTDAT0); + + __smbus_wait_until_ready(__smbus_io_base); + + /* Actual addr to reg format. */ + dimm = (dimm << 1); + dimm |= 1; /* read command */ + outb(dimm, SMBXMITADD); + outb(offset, SMBHSTCMD); + /* Start transaction, byte data read. */ + outb(0x48, SMBHSTCTL); + __smbus_wait_until_ready(__smbus_io_base); + + val = inb(SMBHSTDAT0); + return val; +} \ No newline at end of file diff --git a/src/devices/smbus/smbus.h b/src/devices/smbus/smbus.h new file mode 100644 index 0000000..820a0dd --- /dev/null +++ b/src/devices/smbus/smbus.h @@ -0,0 +1,99 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011 Alexandru Gagniuc mr.nuke.me@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 post_codes.h + * + * This file defines the prototypes for several common SMBUS functions + * These functions are prefixed with __smbus_ so that they do not conflict with + * the dozens of similar (duplicated) implementations in many southbridges. + * + * As a last parameter, the SMBUS functions take a u16 value __smbus_io_base, + * which represents the base IO port for smbus transactions + */ + +#include <arch/io.h> + +/** + * \brief SMBUS IO ports in relation to the base IO port + */ +#define SMBHSTSTAT __smbus_io_base + 0x0 +#define SMBSLVSTAT __smbus_io_base + 0x1 +#define SMBHSTCTL __smbus_io_base + 0x2 +#define SMBHSTCMD __smbus_io_base + 0x3 +#define SMBXMITADD __smbus_io_base + 0x4 +#define SMBHSTDAT0 __smbus_io_base + 0x5 +#define SMBHSTDAT1 __smbus_io_base + 0x6 +#define SMBBLKDAT __smbus_io_base + 0x7 +#define SMBSLVCTL __smbus_io_base + 0x8 +#define SMBTRNSADD __smbus_io_base + 0x9 +#define SMBSLVDATA __smbus_io_base + 0xa + +#define SMBUS_TIMEOUT (100*1000*10) + +/** + * \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 + +void __smbus_reset(u16 __smbus_io_base); +int __smbus_print_error(u8 host_status, int loops, u16 __smbus_io_base); +int __smbus_is_busy(u16 __smbus_io_base); +int __smbus_wait_until_ready(u16 __smbus_io_base); +u8 __smbus_read_byte(u8 dimm, u8 offset, u16 __smbus_io_base); + +void __smbus_delay(void); + +#if defined(SMBUS_IO_BASE) && (SMBUS_IO_BASE != 0) + +__attribute__((always_inline, unused)) +static void smbus_reset(void) +{ + __smbus_reset(SMBUS_IO_BASE); +} + +__attribute__((always_inline, unused)) +static int smbus_is_busy(void) +{ + return __smbus_is_busy(SMBUS_IO_BASE); +} + +__attribute__((always_inline, unused)) +static int smbus_wait_until_ready(void) +{ + return __smbus_wait_until_ready(SMBUS_IO_BASE); +} + +__attribute__((always_inline, unused)) +static int smbus_print_error(u8 host_status, int loops) +{ + return __smbus_print_error(host_status, loops, SMBUS_IO_BASE); +} + +__attribute__((always_inline, unused)) +static u8 smbus_read_byte(u8 dimm, u8 offset) +{ + return __smbus_read_byte(dimm, offset, SMBUS_IO_BASE); +} + +#endif \ No newline at end of file diff --git a/src/include/device/pci_ids.h b/src/include/device/pci_ids.h index fd886da..ff70fa3 100644 --- a/src/include/device/pci_ids.h +++ b/src/include/device/pci_ids.h @@ -1337,6 +1337,28 @@ #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_APIC 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_SBRIDGE 0xa535 +#define PCI_DEVICE_ID_VIA_VX900_PCI_BR 0xb535 +#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 +/* 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 diff --git a/src/mainboard/asus/Kconfig b/src/mainboard/asus/Kconfig index 1ca1278..318761d 100644 --- a/src/mainboard/asus/Kconfig +++ b/src/mainboard/asus/Kconfig @@ -82,7 +82,7 @@ source "src/mainboard/asus/p2b-ds/Kconfig" source "src/mainboard/asus/p2b-f/Kconfig" source "src/mainboard/asus/p2b-ls/Kconfig" source "src/mainboard/asus/p3b-f/Kconfig" -source "src/mainboard/asus/dsbf/Kconfig +source "src/mainboard/asus/dsbf/Kconfig"
config MAINBOARD_VENDOR string 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..1309e87 --- /dev/null +++ b/src/mainboard/via/epia-m850/Kconfig @@ -0,0 +1,47 @@ +## +## This file is part of the coreboot project. +## +## Copyright (C) 2011-2012 Alexandru Gagniuc mr.nuke.me@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 BOARD_HAS_FADT + #select HAVE_PIRQ_TABLE + #select HAVE_ACPI_TABLES + #select HAVE_OPTION_TABLE + select BOARD_ROMSIZE_KB_512 + select RAMINIT_SYSINFO + +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@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/chip.h b/src/mainboard/via/epia-m850/chip.h new file mode 100644 index 0000000..7872fde --- /dev/null +++ b/src/mainboard/via/epia-m850/chip.h @@ -0,0 +1,21 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011 Alexandru Gagniuc mr.nuke.me@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/. + */ +extern struct chip_operations mainboard_ops; + +struct mainboard_config {}; diff --git a/src/mainboard/via/epia-m850/devicetree.cb b/src/mainboard/via/epia-m850/devicetree.cb new file mode 100644 index 0000000..b3418a2 --- /dev/null +++ b/src/mainboard/via/epia-m850/devicetree.cb @@ -0,0 +1,63 @@ +## +## This file is part of the coreboot project. +## +## Copyright (C) 2011 Alexandru Gagniuc mr.nuke.me@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 + device lapic_cluster 0 on # APIC cluster + chip cpu/via/nano # VIA NANO + device lapic 0 on end # APIC + end + end + device pci_domain 0 on + device pci 0.0 off end # AGP Bridge + device pci 0.1 off end # Error Reporting + device pci 0.2 off end # Host Bus Control + device pci 0.3 off end # Memory Controller + device pci 0.4 off end # Power Management + device pci 0.5 off end # Power Management + device pci 0.6 off end # Power Management + device pci 0.7 off end # V-Link Controller + device pci 1.0 off end # PCI Bridge + device pci 1.1 off end # Audio + device pci 3.0 off end # PCIE control + device pci 3.1 off end # PEX1 + device pci 3.2 off end # PEX2 + device pci 3.3 off end # PEX3 + device pci 3.4 off end # PEX4 + device pci c.0 off end + device pci d.0 off end + device pci f.0 off end # IDE/SATA + device pci 10.0 off end # USB 1.1 + device pci 10.1 off end # USB 1.1 + device pci 10.2 off end # USB 1.1 + device pci 10.3 off end # USB 1.1 + device pci 10.4 off end # USB 2.0 + device pci 11.0 on end # LPC +# chip drivers/generic/generic # DIMM 0 channel 1 +# device i2c 50 off end +# end +# chip drivers/generic/generic # DIMM 1 channel 1 +# device i2c 51 off end +# end + chip superio/fintek/f81865f # Super duper IO + end + device pci 11.7 off end # NB/SB control + device pci 13.0 off end # PCI Bridge + device pci 14.0 off end # HD Audio + end +end diff --git a/src/mainboard/via/epia-m850/mainboard.c b/src/mainboard/via/epia-m850/mainboard.c new file mode 100644 index 0000000..df72a0c --- /dev/null +++ b/src/mainboard/via/epia-m850/mainboard.c @@ -0,0 +1,25 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011 Alexandru Gagniuc mr.nuke.me@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> +#include "chip.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..043afc3 --- /dev/null +++ b/src/mainboard/via/epia-m850/romstage.c @@ -0,0 +1,78 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011-2012 Alexandru Gagniuc mr.nuke.me@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 + */ + +#include <stdint.h> +#include <device/pci_def.h> +#include <device/pci_ids.h> +#include <arch/io.h> +#include <device/pnp_def.h> +#include <arch/romcc_io.h> +#include <arch/hlt.h> +#include <console/console.h> +#include <lib.h> +#include "cpu/x86/bist.h" +#include <string.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) + +/* cache_as_ram.inc jumps to here. */ +void main(unsigned long bist) +{ + /* Enable multifunction bit for northbridge. + * This enables the PCI configuration spaces of D0F1 to D0F7 to be + * accessed */ + pci_write_config8(PCI_DEV(0, 0, 0), 0x4f, 0x01); + + f81865f_enable_serial(SERIAL_DEV, CONFIG_TTYS0_BASE); + console_init(); + print_debug("Console initialized. \n"); + + /* Halt if there was a built-in self test failure. */ + report_bist_failure(bist); + + /* x86 cold boot I/O cmd. */ + enable_smbus(); + + /* If this works, then SMBUS is up and running */ + //dump_spd_data(); + + /* 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); + + //ram_check(0, 0x80); + ram_check((1<<20), 0x80); + ram_check((1<<26), 0x80); + + + print_debug("We passed RAM verify\n"); + + return; + +} 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/vx800/lpc.c b/src/northbridge/via/vx800/lpc.c index b9941d1..144ede0 100644 --- a/src/northbridge/via/vx800/lpc.c +++ b/src/northbridge/via/vx800/lpc.c @@ -375,3 +375,9 @@ static const struct pci_driver lpc_driver __pci_driver = { .vendor = PCI_VENDOR_ID_VIA, .device = PCI_DEVICE_ID_VIA_VX855_LPC, }; + +static const struct pci_driver lpc_driver_900 __pci_driver = { + .ops = &vx800_lpc_ops, + .vendor = PCI_VENDOR_ID_VIA, + .device = PCI_DEVICE_ID_VIA_VX900_LPC, +}; \ No newline at end of file diff --git a/src/northbridge/via/vx900/Kconfig b/src/northbridge/via/vx900/Kconfig new file mode 100644 index 0000000..d1c7a48 --- /dev/null +++ b/src/northbridge/via/vx900/Kconfig @@ -0,0 +1,23 @@ +## +## This file is part of the coreboot project. +## +## Copyright (C) 2011 Alexandru Gagniuc mr.nuke.me@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 HAVE_DEBUG_RAM_SETUP + select HAVE_DEBUG_SMBUS \ 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..614c663 --- /dev/null +++ b/src/northbridge/via/vx900/Makefile.inc @@ -0,0 +1,34 @@ +## +## This file is part of the coreboot project. +## +## Copyright (C) 2011 Alexandru Gagniuc mr.nuke.me@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 += raminit_ddr3.c +romstage-y += ./../../../devices/dram/dram_util.c +romstage-y += ./../../../devices/smbus/early_smbus.c +#romstage-y += ./../../../cpu/x86/lapic/apic_timer.c + + +driver-y += northbridge.c +# Drivers for these devices already exist with the vx800 +# Use those instead of duplicating code +#driver-y += ./../vx800/vga.c +driver-y += ./../vx800/lpc.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..15c9744 --- /dev/null +++ b/src/northbridge/via/vx900/chip.h @@ -0,0 +1,23 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 Alexandru Gagniuc mr.nuke.me@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 { +}; + +extern struct chip_operations northbridge_via_vx900_ops; diff --git a/src/northbridge/via/vx900/early_smbus.c b/src/northbridge/via/vx900/early_smbus.c new file mode 100644 index 0000000..aa6cec0 --- /dev/null +++ b/src/northbridge/via/vx900/early_smbus.c @@ -0,0 +1,191 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011 Alexandru Gagniuc mr.nuke.me@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 <arch/io.h> +#include <arch/romcc_io.h> +#include <console/console.h> +#include <devices/dram/dram.h> + +__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(u8 dimm, u8 offset, u16 __smbus_io_base) +{ + u8 val; + + /* Initialize SMBUS sequence */ + smbus_reset(); + /* Clear host data port. */ + outb(0x00, SMBHSTDAT0); + + smbus_wait_until_ready(); + smbus_delays(50); + + /* Actual addr to reg format. */ + dimm = (dimm << 1); + dimm |= 1; /* read command */ + outb(dimm, SMBXMITADD); + outb(offset, SMBHSTCMD); + /* Start transaction, byte data read. */ + outb(0x48, SMBHSTCTL); + smbus_wait_until_ready(); + + val = inb(SMBHSTDAT0); + return val; +} + +void enable_smbus(void) +{ + device_t dev; + u8 reg8; + u16 __smbus_io_base = 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 Managment 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(); + /* Clear SMBus host data 0 register */ + outb(0x00, SMBHSTDAT0); + + /* Wait for SMBUS */ + smbus_wait_until_ready(); + +} + +void spd_read(u8 addr, spd_raw_data spd) +{ + u8 reg; + int i, regs; + reg = smbus_read_byte(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(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(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; + + for (dimm = 0x50; dimm < 0x52; dimm++) { + reg = smbus_read_byte(dimm, 2); + if(reg != 0x0b) + { + printk(BIOS_DEBUG, + "SMBUS device %x not a DDR3 module\n", dimm); + continue; + } + + reg = smbus_read_byte(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(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.h b/src/northbridge/via/vx900/early_vx900.h new file mode 100644 index 0000000..6b33077 --- /dev/null +++ b/src/northbridge/via/vx900/early_vx900.h @@ -0,0 +1,35 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011 Alexandru Gagniuc mr.nuke.me@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 <stdint.h> + +#define SMBUS_IO_BASE 0x500 +#include <devices/smbus/smbus.h> + + +#include "raminit.h" + +void enable_smbus(void); +void dump_spd_data(void); +void spd_read(u8 addr, spd_raw_data spd); + +#endif /* EARLY_VX900_H */ diff --git a/src/northbridge/via/vx900/forgotten.c b/src/northbridge/via/vx900/forgotten.c new file mode 100644 index 0000000..37aae81 --- /dev/null +++ b/src/northbridge/via/vx900/forgotten.c @@ -0,0 +1,192 @@ +#include "forgotten.h" +#include <../../dram/dram.h> + +u16 ddr3_get_mr0( + char precharge_pd, + u8 write_recovery, + char dll_reset, + char mode, + u8 cas, + char interleaved_burst, + u8 burst_lenght +){ + u32 cmd = 0; + if(precharge_pd) cmd |= (1 << 12); + /* Write recovery */ + cmd |= ( ((write_recovery - 4) & 0x7) << 9); + if(dll_reset) cmd |= (1 << 8); + if(mode) cmd |= (1<<7); + /* CAS latency) */ + cmd |= ( ((cas - 4) & 0x7) << 4); + if(interleaved_burst) cmd |= (1 << 3); + /* Burst lenght */ + cmd |= (burst_lenght & 0x3); + return cmd; +} + +u16 ddr3_get_mr1( + char q_off_disable, + char tdqs, + u8 rtt_nom, + char write_leveling, + u8 output_drive_strenght, + u8 additive_latency, + u8 dll_disable +){ + u32 cmd = 0; + if(q_off_disable) cmd |= (1 << 12); + if(tdqs) cmd |= (1 << 11); + /* rtt_nom */ + cmd |= ( ((rtt_nom & 4) << (9-2)) | ((rtt_nom & 2) << (6-1)) + | ((rtt_nom & 1) << 2)); + if(write_leveling) cmd |= (1 << 7); + /* output drive strenght */ + cmd |= ( ((output_drive_strenght & 2) << (5-1)) + | ((output_drive_strenght & 1) << 1) ); + /* Additive latency */ + cmd |= ((additive_latency & 0x3) << 3); + if(dll_disable) cmd |= (1 << 0); + return cmd; +} + +u16 ddr3_get_mr2( + u8 rtt_wr, + char extended_temp, + char auto_self_refresh, + u8 cas_write +){ + u32 cmd = 0; + /* Rtt_wr */ + cmd |= ( (rtt_wr & 0x3) << 9); + if(extended_temp) cmd |= (1 << 7); + if(auto_self_refresh) cmd |= (1 << 6); + /* CAS write latency */ + cmd |= ( ((cas_write - 5) & 0x7) << 3); + return cmd; +} + +u16 ddr3_get_mr3(char dataflow_from_mpr) +{ + u32 cmd = 0; + if(dataflow_from_mpr) cmd |= (1<<2); + 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(u8 mrs_type, u16 cmd); + +u32 vx900_get_mrs_addr(u8 mrs_type, u16 cmd) +{ + u32 addr = 0; + /* A3 <-> MA0, A4 <-> MA1, ... A12 <-> MA9 */ + addr |= ((cmd &0x3ff)<< 3); + /* A20 <-> MA10 */ + addr |= (((cmd >> 10) & 0x1) << 20); + /* A13 <-> MA11, A14 <-> MA12 */ + addr |= (((cmd >> 11) & 0x3) << 13); + + /* Do not fuck with registers 0x52 and 0x53 if you want the following + * mappings to work for you: + * A17 <-> BA0, A18 <-> BA1, A19 <-> BA2 */ + addr |= ((mrs_type & 0x7) << 17); + return addr; +} +void vx900_dram_ddr3_init_rank(device_t mcu, const ramctr_timing *ctrl, + int rank); +void vx900_dram_ddr3_init_rank(device_t mcu, const ramctr_timing *ctrl, + int rank) +{ + u8 reg8; + u32 reg32, cmd, res, addr; + int i; + + printram("Initializing rank %u\n", rank); + + /* Step 06 - Set Fun3_RX6B[2:0] to 001b (NOP Command Enable). */ + reg8 = pci_read_config8(mcu, 0x6b); + reg8 &= ~(0x07); + reg8 |= (1<<0); + pci_write_config8(mcu, 0x6b, reg8); + /* Step 07 - Read a double word from any address of the DIMM. */ + reg32 = volatile_read(0x0); + udelay(10); + printram("We just read 0x%x\n", reg32); + /* Step 08 - Set Fun3_RX6B[2:0] to 011b (MSR Enable). */ + reg8 = pci_read_config8(mcu, 0x6b); + reg8 &= ~(0x07); + reg8 |= (3<<0); + pci_write_config8(mcu, 0x6b, reg8); + + /* Step 09 – Issue MR2 cycle. Read a double word from the address depended + * on DRAM’s Rtt_WR and CWL settings. + * (Check the byte 63 of SPD. If memory address lines of target physical + * rank is mirrored, MA3~MA8 and BA0~BA1 should be swapped.) */ + cmd = ddr3_get_mr2(DDR3_MR2_RTT_WR_OFF,0,0,ctrl->CWL); + addr = vx900_get_mrs_addr(2, cmd); + if(addr != 0x00040040){ + printram("MR2 needed at addr 0x%.8x, but done at 0x%.8x\n", 0x00040040, addr); + } + res = volatile_read(addr); + udelay(10); + printram("MR2 cycle 0x%.4x @ addr 0x%.8x read 0x%.8x\n", cmd, addr, res); + + /* Step 10 – Issue MR3 cycle - set DRAM to normal operation mode. + */ + cmd = ddr3_get_mr3(0); + addr = vx900_get_mrs_addr(3, cmd); + res = volatile_read(addr); + udelay(10); + printram("MR3 cycle 0x%.4x @ addr 0x%.8x read 0x%.8x\n", cmd, addr, res); + + /* Step 11 –Issue MR1 cycle + * Set 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. + */ + cmd = ddr3_get_mr1(DDR3_MR1_QOFF_ENABLE, DDR3_MR1_TQDS_DISABLE, + DDR3_MR1_RTT_NOM_RZQ2, + DDR3_MR1_WRITE_LEVELING_DISABLE, DDR3_MR1_ODS_RZQ7, + DDR3_MR1_AL_DISABLE, DDR3_MR1_DLL_ENABLE); + addr = vx900_get_mrs_addr(1, cmd); + res = volatile_read(addr); + udelay(10); + printram("MR1 cycle 0x%.4x @ addr 0x%.8x read 0x%.8x\n", cmd, addr, res); + + /* Step 12 - Issue MR0 cycle. + * Set DRAM’s burst length, CAS latency and write recovery 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. + */ + cmd = ddr3_get_mr0(DDR3_MR0_PRECHARGE_FAST, ctrl->WR, + DDR3_MR0_DLL_RESET_NO, DDR3_MR0_MODE_NORMAL, + ctrl->CAS, DDR3_MR0_BURST_TYPE_INTERLEAVED, + DDR3_MR0_BURST_LENGTH_CHOP); + addr = vx900_get_mrs_addr(0, cmd); + if(addr != 0x000069c8){ + printram("MR0 needed at addr 0x%.8x, but done at 0x%.8x\n", 0x000069c8, addr); + addr = 0x000069c8; + } + res = volatile_read(addr); + printram("MR0 cycle 0x%.4x @ addr 0x%.8x read 0x%.8x\n", cmd, addr, res); + + /* Step 13 - Set Rx6B[2:0] to 110b (Long ZQ calibration command). */ + reg8 = pci_read_config8(mcu, 0x6b); + reg8 &= ~(0x07); + reg8 |= (3<<1); + pci_write_config8(mcu, 0x6b, reg8); + for(i = 0; i < 1000; i++) inb(0x80); + + + /* Step 14 - Read a double word from any address of the DIMM. */ + reg32 = volatile_read(0x0); + printram("We just read 0x%x\n", reg32); +} + diff --git a/src/northbridge/via/vx900/forgotten.h b/src/northbridge/via/vx900/forgotten.h new file mode 100644 index 0000000..43641f7 --- /dev/null +++ b/src/northbridge/via/vx900/forgotten.h @@ -0,0 +1,78 @@ +#ifndef REDUNDANT_H +#define REDUNDANT_H + +#define DDR3_MR0_PRECHARGE_SLOW 0 +#define DDR3_MR0_PRECHARGE_FAST 1 +#define DDR3_MR0_MODE_NORMAL 0 +#define DDR3_MR0_MODE_TEST 1 +#define DDR3_MR0_DLL_RESET_NO 0 +#define DDR3_MR0_DLL_RESET_YES 1 +#define DDR3_MR0_BURST_TYPE_SEQUENTIAL 0 +#define DDR3_MR0_BURST_TYPE_INTERLEAVED 1 +#define DDR3_MR0_BURST_LENGTH_FIXED_8 0 +#define DDR3_MR0_BURST_LENGTH_CHOP 1 +#define DDR3_MR0_BURST_LENGTH_FIXED_4 2 +/** + * \brief Get command address for a DDR3 MR0 command + */ +u16 ddr3_get_mr0( + char precharge_pd, + u8 write_recovery, + char dll_reset, + char mode, + u8 cas, + char interleaved_burst, + u8 burst_lenght +); + +#define DDR3_MR1_TQDS_DISABLE 0 +#define DDR3_MR1_TQDS_ENABLE 1 +#define DDR3_MR1_QOFF_ENABLE 0 +#define DDR3_MR1_QOFF_DISABLE 1 +#define DDR3_MR1_WRITE_LEVELING_DISABLE 0 +#define DDR3_MR1_WRITE_LEVELING_ENABLE 1 +#define DDR3_MR1_RTT_NOM_OFF 0 +#define DDR3_MR1_RTT_NOM_RZQ4 1 +#define DDR3_MR1_RTT_NOM_RZQ2 2 +#define DDR3_MR1_RTT_NOM_RZQ6 3 +#define DDR3_MR1_RTT_NOM_RZQ12 4 +#define DDR3_MR1_RTT_NOM_RZQ8 5 +#define DDR3_MR1_AL_DISABLE 0 +#define DDR3_MR1_AL_CL_MINUS_1 1 +#define DDR3_MR1_AL_CL_MINUS_2 2 +#define DDR3_MR1_ODS_RZQ6 0 +#define DDR3_MR1_ODS_RZQ7 1 +#define DDR3_MR1_DLL_ENABLE 0 +#define DDR3_MR1_DLL_DISABLE 1 +/** + * \brief Get command address for a DDR3 MR1 command + */ +u16 ddr3_get_mr1( + char q_off, + char tdqs, + u8 rtt_nom, + char write_leveling, + u8 output_drive_strenght, + u8 additive_latency, + u8 dll_disable +); + +#define DDR3_MR2_RTT_WR_OFF 0 +#define DDR3_MR2_RTT_WR_RZQ4 1 +#define DDR3_MR2_RTT_WR_RZQ2 2 +/** + * \brief Get command address for a DDR3 MR2 command + */ +u16 ddr3_get_mr2( + u8 rtt_wr, + char extended_temp, + char auto_self_refresh, + u8 cas_write +); + +/** + * \brief Get command address for a DDR3 MR3 command + */ +u16 ddr3_get_mr3(char dataflow_from_mpr); + +#endif /* REDUNDANT_H */ \ No newline at end of file diff --git a/src/northbridge/via/vx900/northbridge.c b/src/northbridge/via/vx900/northbridge.c new file mode 100644 index 0000000..afdd208 --- /dev/null +++ b/src/northbridge/via/vx900/northbridge.c @@ -0,0 +1,91 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 Alexandru Gagniuc mr.nuke.me@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> + +static void vx900_read_resources(device_t dev) +{ + print_debug("========= VX900 memory sizing & Co. ==========\n"); + int idx = 0; + /* FIXME: just a quick memory sizing. fix me later */ + unsigned long tolm = (1<<29); + ram_resource(dev, idx++, 0, 640); + /* Leave a hole for vga, 0xa0000 - 0xc0000 */ + ram_resource(dev, idx++, 768, ((tolm >> 10) - 768)); + #if CONFIG_WRITE_HIGH_TABLES + /* Leave some space for ACPI, PIRQ and MP tables */ + high_tables_base = tolm - 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); + #endif +} + +static void pci_domain_set_resources(device_t dev) +{ + assign_resources(dev->link_list); +} + +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 struct device_operations pci_domain_ops = { + .read_resources = vx900_read_resources, + .set_resources = pci_domain_set_resources, + .enable_resources = NULL, + .init = NULL, + .scan_bus = pci_domain_scan_bus, +}; + +static void enable_dev(device_t dev) +{ + /* Set the operations if it is a special bus type */ + if (dev->path.type == DEVICE_PATH_PCI_DOMAIN) { + dev->ops = &pci_domain_ops; + } else if (dev->path.type == DEVICE_PATH_APIC_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/raminit.h b/src/northbridge/via/vx900/raminit.h new file mode 100644 index 0000000..6268070 --- /dev/null +++ b/src/northbridge/via/vx900/raminit.h @@ -0,0 +1,77 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011 Alexandru Gagniuc mr.nuke.me@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 <devices/dram/dram.h> + +/* The maximum number of DIMM slots that the VX900 supports */ +#define VX900_MAX_DIMM_SLOTS 2 + +#define VX900_MAX_MEM_RANKS 4 + + +#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[VX900_MAX_MEM_RANKS]; + mem_rank virt[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; + delay_range tx_dq; + delay_range tx_dqs; +} vx900_delay_calib; + +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..fb1618f --- /dev/null +++ b/src/northbridge/via/vx900/raminit_ddr3.c @@ -0,0 +1,1053 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011-2012 Alexandru Gagniuc mr.nuke.me@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/romcc_io.h> + +#include "early_vx900.h" +#include "raminit.h" + +#include <string.h> +#include <console/console.h> +#include <device/pci_ids.h> + +#include <delay.h> + +#define min(a,b) a<b?a:b +#define max(a,b) a>b?a:b + +#define MCU PCI_DEV(0, 0, 3) + + +/* FIXME: Really Alex, is this all you can come up with? */ +void udelay(unsigned usecs) +{ + int i; + for(i = 0; i < usecs; i++) + inb(0x80); +} + +/* 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. + * mode refers to TxDQS, TxDQ, RxDQS, or RxCR + * setting refers to either manual, average, upper bound, or lower bound + */ +#define VX900_CALIB_TxDQS 0 +#define VX900_CALIB_TxDQ 1 +#define VX900_CALIB_RxDQS 2 +#define VX900_CALIB_RxDQ_CR 3 + +#define VX900_CALIB_AVERAGE 0 +#define VX900_CALIB_LOWER 1 +#define VX900_CALIB_UPPER 2 +#define VX900_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, VX900_CALIB_LOWER); + vx900_read_0x78_0x7f(d_range->low); + vx900_delay_calib_mode_select(mode, VX900_CALIB_AVERAGE); + vx900_read_0x78_0x7f(d_range->avg); + vx900_delay_calib_mode_select(mode, VX900_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 */ + {0x52, 0x33}, /* Map BA0 to A17, BA1 to A18 */ + {0x53, 0x5b}, /* Map BA2 to A19, FIXME: check RA0/RA1 */ + /* 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 */ + //{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 Interleave Control */ + {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_write_init_config(void) +{ + 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); + } +} + +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 != DRAM_TYPE_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 == DRAM_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); + + } + + 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; + //u8 reg8; + for(i = 0; i < VX900_MAX_DIMM_SLOTS; i ++) + { + if(dimms->dimm[i].dram_type == DRAM_TYPE_UNDEFINED) + continue; + u8 nranks = dimms->dimm[i].ranks; + if(nranks > 2) + die("Found DIMM with more than two ranks, which is not " + "supported by this chipset"); + u32 size = dimms->dimm[i].size; + if(nranks == 2) { + /* Each rank holds half the capacity of the DIMM */ + size >>= 1; + ranks->phys_rank_size[i<<1] = size; + ranks->phys_rank_size[(i<<1) | 1] = size; + } else { + /* Otherwise, everything is held in the first bank */ + ranks->phys_rank_size[i<<1] = size; + ranks->phys_rank_size[(i<<1) | 1] = 0;; + } + } +} + +static void vx900_dram_driving_ctrl(const dimm_info *dimm) +{ + size_t i, ndimms; + u8 val; + + /* 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 == DRAM_TYPE_DDR3) ndimms++; + } + val = (ndimms > 1) ? 0x0 : 0x1; + pci_write_config8(MCU, 0xd5, val << 2); + + + /* FIXME: Assert dynamically based on dimm config */ + /* DRAM ODT Lookup Table*/ + pci_write_config8(MCU, 0x9c, 0xe4); + + 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_clear_vr_map(void) +{ + /* Disable all ranks */ + pci_write_config16(MCU, 0x54, 0x0000); +} + +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) +{ + pr &= 0x3; vr &= 0x3; + /* Enable rank (bit [3], and set the VR number bits [1:0] */ + u16 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 */ + if(ctrl->tCK < TCK_533MHZ) ctrl->tCK = TCK_533MHZ; + val32 = (1000 << 8) / ctrl->tCK; + printram("Selected DRAM frequency: %u MHz\n", val32); + + /* Now find the right DRAM frequency setting, + * and align it to the closest JEDEC standard 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 if(ctrl->tCK <= TCK_266MHZ) {val = 0x04; ctrl->tCK = TCK_266MHZ;} + + /* 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); + } +} + +/* The VX900 can send the MRS commands directly through hardware */ +void vx900_dram_ddr3_do_hw_mrs(u8 ma_swap, u8 rtt_nom, + u8 ods, u8 rtt_wr, u8 srt, u8 asr); +/*static*/ void vx900_dram_ddr3_do_hw_mrs(u8 ma_swap, u8 rtt_nom, + u8 ods, u8 rtt_wr, u8 srt, u8 asr) +{ + u8 reg8 = 0; + u32 reg32; + if(asr) reg8 |= (1 << 0); + if(srt) reg8 |= (1 << 1); + reg8 |= ((rtt_wr & 0x03) << 4); + pci_write_config8(MCU, 0xcd, reg8); + reg8 = 1; + if(ma_swap) reg8 |= (1 << 1); + reg8 |= ((ods & 0x03) << 2); + reg8 |= ((rtt_nom & 0x7) << 4); + pci_write_config8(MCU, 0xcc, reg8); + reg32=0; + while(pci_read_config8(MCU, 0xcc) & 1) reg32++; + printram(" Waited %u PCI cycles for HW MRS\n", reg32); +} +#include "forgotten.h" +#include "forgotten.c" + +static void vx900_dram_send_soft_mrs(u8 type, u16 cmd) +{ + u32 addr; + /* Set Fun3_RX6B[2:0] to 011b (MSR Enable). */ + pci_mod_config8(MCU, 0x6b, 0x07, (3<<0)); + /* Find the address corresponding to the MRS */ + addr = vx900_get_mrs_addr(type, cmd); + //printram("MRS CPU addr: %.8x\n", addr); + /* 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; + + /* Set BA[0/1/2] to [A17/18/19] */ + pci_write_config16(MCU, 0x52, 0x5b33); + + /* 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[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); + +#define USE_HW_INIT_SEQUENCE 1 +#if USE_HW_INIT_SEQUENCE + + /* 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 */ + + /* FIXME: Values dependent on DIMM setup + * This works for 1 DIMM + * See init_dram_by_rank.c and get_basic_information.c + * in the VIA provided code */ + const u8 rtt_nom = DDR3_MR1_RTT_NOM_RZQ2; + const u8 ods = DDR3_MR1_ODS_RZQ6; + const u8 rtt_wr = DDR3_MR2_RTT_WR_OFF; + + printram("Using Hardware method\n"); + /* FIXME: MA swap dependent on module */ + vx900_dram_ddr3_do_hw_mrs(0, rtt_nom, ods, rtt_wr, 0, 0); + + /* Normal SDRAM Mode */ + pci_mod_config8(MCU, 0x6b, 0x07, 0x00); + +#else /* USE_HW_INIT_SEQUENCE */ + printram("Using software method\n"); + vx900_dram_ddr3_init_rank(MCU, ctrl, i); +#endif /* USE_HW_INIT_SEQUENCE */ + /* 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] */ + pci_mod_config16(MCU, 0x52, 0x0fff, 0x0911); + + /* 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_rx_capture_range_calib(void) +{ + u8 reg8; + u16 cmd; + 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); + + /* Precharge all */ + pci_mod_config8(MCU, 0x06b, 0x07, 0x02); + volatile_read(0x0); + udelay(1000); + + /* Enable read leveling: Set D0F3Rx71[7]=1 + * Set return data format: Clear D0F3Rx71[6]=0 */ + pci_mod_config8(MCU, 0x71, 0x40, 0x80); + + /* Put DRAM in read leveling mode */ + cmd = ddr3_get_mr3(1); + vx900_dram_send_soft_mrs(3, cmd); + + /* 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) cmd++; + printram("RX capture range calibration took %u PCI cycles\n", cmd); + + /* Disable read leveling, and put dram in normal operation mode */ + cmd = ddr3_get_mr3(0); + vx900_dram_send_soft_mrs(3, cmd); + + /* Disable read leveling: Set D0F3Rx71[7]=0 */ + pci_mod_config8(MCU, 0x71, 1<<7, 0); +} + +static void vx900_rx_dqs_delay_calib(void) +{ + u16 cmd; + 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); + + /* Precharge all */ + pci_mod_config8(MCU, 0x06b, 0x07, 0x02); + volatile_read(0x0); + udelay(1000); + + /* Enable read leveling: Set D0F3Rx71[7]=1 + * Set return data format: Clear D0F3Rx71[6]=0 + * Set RxDQS to use calibration setting - Clear Rx71[2] and Rx71[0] */ + pci_mod_config8(MCU, 0x71, 0x45, 0x80); + + /* Put DRAM in read leveling mode (enable MPR flow) */ + cmd = ddr3_get_mr3(1); + vx900_dram_send_soft_mrs(3, cmd); + + /* 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 ); + + /* Put DRAM in normal mode (disable MPR flow) */ + cmd = ddr3_get_mr3(0); + vx900_dram_send_soft_mrs(3, cmd); + + /* Disable read leveling: Set D0F3Rx71[7]=0 */ + pci_mod_config8(MCU, 0x71, 1<<7, 0); + + /* Restore the refresh counter*/ + //pci_write_config8(MCU, 0xc7, ref_cnt); + if(ref_cnt); + + /* FIXME: should we save it before, or should we just set it as is */ + pci_write_config16(MCU, 0x52, 0x5911); +} + +static void vx900_tx_dqs_trigger_calib(u8 pattern) +{ + u32 i; + /* Data pattern for calibration */ + pci_write_config8(MCU, 0x8e, pattern); + /* Trigger calibration */ + pci_mod_config8(MCU, 0x75, 0, 0x20); + /* Wait for calibration */ + i = 0; + while(pci_read_config8(MCU, 0x75) & 0x20) i++; + printram(" Tx DQS calib took %u PCI cycles\n", i); +} +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) +{ + int i = 0; + /* 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) i++; + printram("TX DQ calibration took %u PCI cycles\n", i); +} + +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->low[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_write_0x78_0x7f(dly->avg); +} + +static void vx900_dram_calibrate_delays(const ramctr_timing *ctrl, + const rank_layout *ranks) +{ + timing_dly dly; + size_t i; + u8 val; + 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? + * 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); + + /* FIXME: Vendor BIOS goes in with + * 8 page registers + * multiple page mode + * High Priority Refresh request + * -- WHY?*/ + pci_write_config8(MCU, 0x69, 0xc7); + + /* Set BA[0/1/2] to [A17/18/19] */ + pci_write_config16(MCU, 0x52, 0x5b33); + /* 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(); + + for(i = 0; i < VX900_MAX_DIMM_SLOTS; i++) + { + /* Do we have a valid DIMM? */ + if(ranks->phys_rank_size[i] + ranks->phys_rank_size[i+1] == 0 ) + continue; + + /* Map the first rank of the DIMM to VR0 */ + vx900_map_pr_vr(2*i, 0); + + /* Run calibrations */if(1){ + vx900_rx_capture_range_calib(); + vx900_read_delay_range(&(delay_cal.rx_dq_cr), + VX900_CALIB_RxDQ_CR); + dump_delay_range(delay_cal.rx_dq_cr);} + + /*FIXME: Cheating with Rx CR setting + * We need to either use Rx CR calibration + * or set up a table for the calibration */ + dly[0] = 0x28; dly[1] = 0x1c; dly[2] = 0x28; dly[3] = 0x28; + dly[4] = 0x2c; dly[5] = 0x30; dly[6] = 0x30; dly[7] = 0x34; + printram("Bypassing RxCR 78-7f calibration with:\n"); + dump_delay(dly); + /* We need to put the setting on manual mode */ + pci_mod_config8(MCU, 0x71, 0, 0x10); + vx900_delay_calib_mode_select(VX900_CALIB_RxDQ_CR, VX900_CALIB_MANUAL); + vx900_write_0x78_0x7f(dly); + + /************* RxDQS *************/ + vx900_rx_dqs_delay_calib(); + vx900_read_delay_range(&(delay_cal.rx_dqs), VX900_CALIB_RxDQS); + printram("RX DQS calibration results\n"); + dump_delay_range(delay_cal.rx_dqs); + + vx900_rxdqs_adjust(&(delay_cal.rx_dqs)); + + vx900_read_delay_range(&(delay_cal.rx_dqs), VX900_CALIB_RxDQS); + printram("RX DQS calibration results after adjustment\n"); + dump_delay_range(delay_cal.rx_dqs); + + /* FIXME: Vendor BIOS does it again (enable auto-precharge) - WHY? */ + pci_write_config8(MCU, 0x69, 0xce); + + /* FIXME: this is done by vendor BIOS, and recommended by VIA + * However, datasheet says that bit[7] is reserved, and + * calibration works just as well if we don't set this to 1b . + * Should we really do this, or can we drop it ? */ + if(ctrl->tCK <= TCK_533MHZ){ + for( i = 0; i< 8; i++) dly[i] = 0x80; + pci_mod_config8(MCU, 0x75, 0x00, 0x01); /* manual Tx DQ DQS */ + vx900_delay_calib_mode_select(VX900_CALIB_TxDQ, VX900_CALIB_MANUAL); + vx900_write_0x78_0x7f(dly); + vx900_delay_calib_mode_select(VX900_CALIB_TxDQS, VX900_CALIB_MANUAL); + vx900_write_0x78_0x7f(dly); + } + + /************* TxDQS *************/ + vx900_tx_dqs_delay_calib(); + + vx900_read_delay_range(&(delay_cal.tx_dqs), VX900_CALIB_TxDQS); + printram("Tx DQS calibration results\n"); + dump_delay_range(delay_cal.tx_dqs); + /************* TxDQ *************/ + /* FIXME: not sure if multiple page mode should be enabled here + * Vendor BIOS does it */ + pci_mod_config8(MCU, 0x69, 0 , 0x01); + + vx900_tx_dq_delay_calib(); + vx900_read_delay_range(&(delay_cal.tx_dq), VX900_CALIB_TxDQ); + printram("TX DQ delay calibration results:\n"); + dump_delay_range(delay_cal.tx_dq); + + /* write manual settings */ + pci_mod_config8(MCU, 0x75, 0, 0x01); + vx900_delay_calib_mode_select(VX900_CALIB_TxDQS, VX900_CALIB_MANUAL); + vx900_write_0x78_0x7f(delay_cal.tx_dqs.avg); + vx900_delay_calib_mode_select(VX900_CALIB_TxDQ, VX900_CALIB_MANUAL); + vx900_write_0x78_0x7f(delay_cal.tx_dq.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 = 0; + vx900_clear_vr_map(); + for(i = 0; i < VX900_MAX_MEM_RANKS; i++) + { + u32 rank_size = ranks->phys_rank_size[i]; + if(!rank_size) continue; + ranks->virt[vrank].start_addr = ramsize; + ramsize += rank_size; + ranks->virt[vrank].end_addr = ramsize; + + /* Rank memory range */ + reg8 = (ranks->virt[vrank].start_addr >> 2); + pci_write_config8(MCU, 0x48 + vrank, reg8); + reg8 = (ranks->virt[vrank].end_addr >> 2); + 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%.8x000000\n" + " End address: 0x%.8x000000\n", + (int) i, (int) vrank, + ranks->virt[vrank].start_addr, + ranks->virt[vrank].end_addr); + + /* Move on to next virtual rank */ + vrank++; + } + + printram("Initialized %u virtual ranks, with a total size of %u MB\n", + (int) vrank, ramsize << 4); +} + +static void vx900_dram_write_final_config(ramctr_timing *ctrl) +{ + + /* FIXME: These are quick cheats */ + pci_write_config8(MCU, 0x50, 0xa0); /* DRAM MA map */ + pci_write_config16(MCU, 0x52, 0x5911); /* Rank interleave */ + + //pci_write_config8(MCU, 0x69, 0xe7); + //pci_write_config8(MCU, 0x72, 0x0f); + + //pci_write_config8(MCU, 0x97, 0xa4); /* self-refresh */ + + /* Enable automatic triggering of short ZQ calibration */ + pci_write_config8(MCU, 0xc8, 0x80); + +} + +static void print_debug_pci_dev(device_t dev) +{ + print_debug("PCI: "); + print_debug_hex8((dev >> 20) & 0xff); + print_debug_char(':'); + print_debug_hex8((dev >> 15) & 0x1f); + print_debug_char('.'); + print_debug_hex8((dev >> 12) & 7); +} + +static void dump_pci_device(device_t dev) +{ + int i; + print_debug_pci_dev(dev); + print_debug("\n"); + + for (i = 0; i <= 0xff; i++) { + unsigned char val; + if ((i & 0x0f) == 0) { + print_debug_hex8(i); + print_debug_char(':'); + } + + if ((i & 0x0f) == 0x08) { + print_debug(" |"); + } + + val = pci_read_config8(dev, i); + print_debug_char(' '); + print_debug_hex8(val); + + if ((i & 0x0f) == 0x0f) { + print_debug("\n"); + } + } +} + +void vx900_init_dram_ddr3(const dimm_layout *dimm_addr) +{ + dimm_info dimm_prop; + ramctr_timing ctrl_prop; + rank_layout ranks; + device_t mcu; + + /* 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"); + } + dump_pci_device(mcu); + 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); + /* 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..2eb2de5 --- /dev/null +++ b/src/northbridge/via/vx900/romstrap.inc @@ -0,0 +1,50 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2004 Tyan Computer + * (Written by Yinghai Lu yhlu@tyan.com for Tyan Computer) + * Copyright (C) 2007 Rudolf Marek r.marek@assembler.cz + * Copyright (C) 2009 One Laptop per Child, Association, Inc. + * Copyright (C) 2011-2012 Alexandru Gagniuc mr.nuke.me@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 + */ + +/* 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@amd.com for AMD) + * Copyright (C) 2011 Alexandru Gagniuc mr.nuke.me@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/vx900.h b/src/northbridge/via/vx900/vx900.h new file mode 100644 index 0000000..2137daf --- /dev/null +++ b/src/northbridge/via/vx900/vx900.h @@ -0,0 +1,26 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011 Alexandru Gagniuc mr.nuke.me@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 3 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/. + */ + +#define VX800_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 \ No newline at end of file