mail.coreboot.org
Sign In
Sign Up
Sign In
Sign Up
Manage this list
×
Keyboard Shortcuts
Thread View
j
: Next unread message
k
: Previous unread message
j a
: Jump to all threads
j l
: Jump to MailingList overview
2024
November
October
September
August
July
June
May
April
March
February
January
2023
December
November
October
September
August
July
June
May
April
March
February
January
2022
December
November
October
September
August
July
June
May
April
March
February
January
2021
December
November
October
September
August
July
June
May
April
March
February
January
2020
December
November
October
September
August
July
June
May
April
March
February
January
2019
December
November
October
September
August
July
June
May
April
March
February
January
2018
December
November
October
September
August
July
June
May
April
March
February
January
2017
December
November
October
September
August
July
June
May
April
March
February
January
2016
December
November
October
September
August
July
June
May
April
March
February
January
2015
December
November
October
September
August
July
June
May
April
March
February
January
2014
December
November
October
September
August
July
June
May
April
March
February
January
2013
December
November
October
September
August
July
June
May
April
March
List overview
Download
coreboot-gerrit
July 2014
----- 2024 -----
November 2024
October 2024
September 2024
August 2024
July 2024
June 2024
May 2024
April 2024
March 2024
February 2024
January 2024
----- 2023 -----
December 2023
November 2023
October 2023
September 2023
August 2023
July 2023
June 2023
May 2023
April 2023
March 2023
February 2023
January 2023
----- 2022 -----
December 2022
November 2022
October 2022
September 2022
August 2022
July 2022
June 2022
May 2022
April 2022
March 2022
February 2022
January 2022
----- 2021 -----
December 2021
November 2021
October 2021
September 2021
August 2021
July 2021
June 2021
May 2021
April 2021
March 2021
February 2021
January 2021
----- 2020 -----
December 2020
November 2020
October 2020
September 2020
August 2020
July 2020
June 2020
May 2020
April 2020
March 2020
February 2020
January 2020
----- 2019 -----
December 2019
November 2019
October 2019
September 2019
August 2019
July 2019
June 2019
May 2019
April 2019
March 2019
February 2019
January 2019
----- 2018 -----
December 2018
November 2018
October 2018
September 2018
August 2018
July 2018
June 2018
May 2018
April 2018
March 2018
February 2018
January 2018
----- 2017 -----
December 2017
November 2017
October 2017
September 2017
August 2017
July 2017
June 2017
May 2017
April 2017
March 2017
February 2017
January 2017
----- 2016 -----
December 2016
November 2016
October 2016
September 2016
August 2016
July 2016
June 2016
May 2016
April 2016
March 2016
February 2016
January 2016
----- 2015 -----
December 2015
November 2015
October 2015
September 2015
August 2015
July 2015
June 2015
May 2015
April 2015
March 2015
February 2015
January 2015
----- 2014 -----
December 2014
November 2014
October 2014
September 2014
August 2014
July 2014
June 2014
May 2014
April 2014
March 2014
February 2014
January 2014
----- 2013 -----
December 2013
November 2013
October 2013
September 2013
August 2013
July 2013
June 2013
May 2013
April 2013
March 2013
coreboot-gerrit@coreboot.org
1 participants
861 discussions
Start a n
N
ew thread
New patch to review for coreboot: cf12d9b sandy/ivybridge: Native raminit.
by Vladimir Serbinenko
29 Jul '14
29 Jul '14
Vladimir Serbinenko (phcoder(a)gmail.com) just uploaded a new patch set to gerrit, which you can find at
http://review.coreboot.org/6391
-gerrit commit cf12d9bcf002e118460edbbb8dd928e0af1dd026 Author: Vladimir Serbinenko <phcoder(a)gmail.com> Date: Sun May 18 11:05:56 2014 +0200 sandy/ivybridge: Native raminit. Based on damo22's work and my X230 tracing. Works for my X230 in a variety of RAM configs. Change-Id: Ia435716ec1fc873e563070ac9af3bac4e8db1a96 Also-By: Damien Zammit <damien(a)zamaudio.com> Signed-off-by: Vladimir Serbinenko <phcoder(a)gmail.com> Signed-off-by: Damien Zammit <damien(a)zamaudio.com> --- src/cpu/intel/Makefile.inc | 1 + src/cpu/x86/smm/smmhandler_tseg.S | 2 +- src/cpu/x86/smm/smmrelocate.S | 4 +- src/device/dram/ddr3.c | 11 +- src/include/device/dram/ddr3.h | 5 + src/mainboard/lenovo/x230/Kconfig | 12 +- src/mainboard/lenovo/x230/romstage.c | 135 +- src/northbridge/intel/Makefile.inc | 1 + src/northbridge/intel/sandybridge/Kconfig | 13 +- src/northbridge/intel/sandybridge/Makefile.inc | 10 +- src/northbridge/intel/sandybridge/gma.c | 4 +- src/northbridge/intel/sandybridge/raminit_native.c | 3893 ++++++++++++++++++++ src/northbridge/intel/sandybridge/raminit_native.h | 29 + .../intel/sandybridge/raminit_patterns.h | 639 ++++ src/southbridge/intel/bd82x6x/Makefile.inc | 6 +- src/southbridge/intel/bd82x6x/early_me_native.c | 272 ++ src/southbridge/intel/bd82x6x/early_pch_native.c | 375 ++ src/southbridge/intel/bd82x6x/early_thermal.c | 70 + src/southbridge/intel/bd82x6x/pch.h | 2 + src/southbridge/intel/bd82x6x/smi.c | 3 - src/southbridge/intel/bd82x6x/usb_ehci.c | 33 + 21 files changed, 5411 insertions(+), 109 deletions(-) diff --git a/src/cpu/intel/Makefile.inc b/src/cpu/intel/Makefile.inc index 0392f69..68ea05d 100644 --- a/src/cpu/intel/Makefile.inc +++ b/src/cpu/intel/Makefile.inc @@ -19,6 +19,7 @@ subdirs-$(CONFIG_CPU_INTEL_SOCKET_RPGA989) += socket_rPGA989 subdirs-$(CONFIG_NORTHBRIDGE_INTEL_NEHALEM) += model_2065x subdirs-$(CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE) += model_206ax subdirs-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE) += model_206ax +subdirs-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE) += model_206ax subdirs-$(CONFIG_NORTHBRIDGE_INTEL_HASWELL) += haswell subdirs-$(CONFIG_NORTHBRIDGE_INTEL_FSP_SANDYBRIDGE) += fsp_model_206ax subdirs-$(CONFIG_NORTHBRIDGE_INTEL_FSP_IVYBRIDGE) += fsp_model_206ax diff --git a/src/cpu/x86/smm/smmhandler_tseg.S b/src/cpu/x86/smm/smmhandler_tseg.S index b33fcdf..380935a 100644 --- a/src/cpu/x86/smm/smmhandler_tseg.S +++ b/src/cpu/x86/smm/smmhandler_tseg.S @@ -57,7 +57,7 @@ #define SMI_UNLOCKED 1 #define __PRE_RAM__ -#if CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE || CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE +#if CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE || CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE || CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE #include <northbridge/intel/sandybridge/sandybridge.h> #define TSEG_BAR (DEFAULT_PCIEXBAR | TSEG) #elif CONFIG_NORTHBRIDGE_INTEL_NEHALEM diff --git a/src/cpu/x86/smm/smmrelocate.S b/src/cpu/x86/smm/smmrelocate.S index bdc9771..bc90fab 100644 --- a/src/cpu/x86/smm/smmrelocate.S +++ b/src/cpu/x86/smm/smmrelocate.S @@ -48,7 +48,7 @@ #if CONFIG_SMM_TSEG -#if CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE || CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE +#if CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE || CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE || CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE #include <northbridge/intel/sandybridge/sandybridge.h> #define TSEG_BAR (DEFAULT_PCIEXBAR | TSEG) #elif CONFIG_NORTHBRIDGE_INTEL_NEHALEM @@ -195,7 +195,7 @@ smm_relocate: xorl %edx, %edx wrmsr -#if CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE || CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE +#if CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE || CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE || CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE /* * IED base is top 4M of TSEG */ diff --git a/src/device/dram/ddr3.c b/src/device/dram/ddr3.c index 9b4f490..a43caed 100644 --- a/src/device/dram/ddr3.c +++ b/src/device/dram/ddr3.c @@ -110,7 +110,7 @@ int spd_decode_ddr3(dimm_attr * dimm, spd_raw_data spd) { int ret; u16 crc, spd_crc; - u8 ftb_divisor, ftb_dividend, capacity_shift, bus_width, sdram_width; + u8 ftb_divisor, ftb_dividend, capacity_shift, bus_width; u8 reg8; u32 mtb; /* medium time base */ unsigned int val, param; @@ -209,8 +209,8 @@ int spd_decode_ddr3(dimm_attr * dimm, spd_raw_data spd) printram(" Invalid SDRAM width\n"); ret = SPD_STATUS_INVALID_FIELD; } - sdram_width = (4 << val); - printram(" SDRAM width : %u\n", sdram_width); + dimm->width = (4 << val); + printram(" SDRAM width : %u\n", dimm->width); /* Memory bus width */ reg8 = spd[8]; @@ -236,7 +236,7 @@ int spd_decode_ddr3(dimm_attr * dimm, spd_raw_data spd) * capacity_shift * The rest is the JEDEC formula */ dimm->size_mb = ((1 << (capacity_shift + (25 - 20))) * bus_width - * dimm->ranks) / sdram_width; + * dimm->ranks) / dimm->width; /* Fine Timebase (FTB) Dividend/Divisor */ /* Dividend */ @@ -334,6 +334,9 @@ int spd_decode_ddr3(dimm_attr * dimm, spd_raw_data spd) printram(" DIMM Rank1 Address bits mirrored!!!\n"); } + dimm->reference_card = spd[62] & 0x1f; + printram(" DIMM Reference card %c\n", 'A' + dimm->reference_card); + return ret; } diff --git a/src/include/device/dram/ddr3.h b/src/include/device/dram/ddr3.h index b19c51c..ef0d0ec 100644 --- a/src/include/device/dram/ddr3.h +++ b/src/include/device/dram/ddr3.h @@ -37,6 +37,7 @@ * @{ */ #define TCK_1066MHZ 240 +#define TCK_933MHZ 275 #define TCK_800MHZ 320 #define TCK_666MHZ 384 #define TCK_533MHZ 480 @@ -137,6 +138,8 @@ typedef struct dimm_attr_st { u16 cas_supported; /* Flags extracted from SPD */ dimm_flags_t flags; + /* SDRAM width */ + u8 width; /* Number of ranks */ u8 ranks; /* Number or row address bits */ @@ -158,6 +161,8 @@ typedef struct dimm_attr_st { u32 tWTR; u32 tRTP; u32 tFAW; + + u8 reference_card; } dimm_attr; /** Result of the SPD decoding process */ diff --git a/src/mainboard/lenovo/x230/Kconfig b/src/mainboard/lenovo/x230/Kconfig index eb9cadc..cc6228d 100644 --- a/src/mainboard/lenovo/x230/Kconfig +++ b/src/mainboard/lenovo/x230/Kconfig @@ -3,7 +3,7 @@ if BOARD_LENOVO_X230 config BOARD_SPECIFIC_OPTIONS # dummy def_bool y select CPU_INTEL_SOCKET_RPGA989 - select NORTHBRIDGE_INTEL_IVYBRIDGE + select NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE select SOUTHBRIDGE_INTEL_C216 select EC_LENOVO_PMH7 select EC_LENOVO_H8 @@ -18,8 +18,8 @@ config BOARD_SPECIFIC_OPTIONS # dummy select SERIRQ_CONTINUOUS_MODE config HAVE_MRC_CACHE - bool - default n + bool + default y config HAVE_IFD_BIN bool @@ -41,10 +41,6 @@ config MMCONF_BASE_ADDRESS hex default 0xf0000000 -config CACHE_ROM_SIZE_OVERRIDE - hex - default 0x800000 - config IRQ_SLOT_COUNT int default 18 @@ -57,7 +53,7 @@ config USBDEBUG_HCD_INDEX int default 2 -config DRAM_GATE_GPIO +config DRAM_RESET_GATE_GPIO int default 10 diff --git a/src/mainboard/lenovo/x230/romstage.c b/src/mainboard/lenovo/x230/romstage.c index 8441db3..8c82e61 100644 --- a/src/mainboard/lenovo/x230/romstage.c +++ b/src/mainboard/lenovo/x230/romstage.c @@ -33,7 +33,7 @@ #include <cbmem.h> #include <console/console.h> #include "northbridge/intel/sandybridge/sandybridge.h" -#include "northbridge/intel/sandybridge/raminit.h" +#include "northbridge/intel/sandybridge/raminit_native.h" #include "southbridge/intel/bd82x6x/pch.h" #include "southbridge/intel/bd82x6x/gpio.h" #include <arch/cpu.h> @@ -109,66 +109,58 @@ static void rcba_config(void) RCBA32(BUC) = 0; } +static void +init_usb (void) +{ + const u32 rcba_dump[64] = { + /* 3500 */ 0x20000153, 0x20000153, 0x20000f57, 0x20000f57, + /* 3510 */ 0x20000f57, 0x20000f57, 0x20000153, 0x2000055b, + /* 3520 */ 0x20000153, 0x2000055b, 0x20000f57, 0x20000f57, + /* 3530 */ 0x20000f57, 0x20000f57, 0x00000000, 0x00000000, + /* 3540 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000, + /* 3550 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000, + /* 3560 */ 0x024c8001, 0x000024a3, 0x00040002, 0x01000050, + /* 3570 */ 0x02000772, 0x16000f9f, 0x1800ff4f, 0x0001d630, + /* 3580 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000, + /* 3590 */ 0x00000000, 0x00000000, 0x00000000, 0x00000040, + /* 35a0 */ 0x04000201, 0x00000200, 0x00000000, 0x00000000, + /* 35b0 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000, + /* 35c0 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000, + /* 35d0 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000, + /* 35e0 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000, + /* 35f0 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000, + }; + int i; + /* Activate PMBAR. */ + pci_write_config32(PCI_DEV(0, 0x1f, 0), PMBASE, DEFAULT_PMBASE | 1); + pci_write_config32(PCI_DEV(0, 0x1f, 0), PMBASE + 4, 0); + pci_write_config8(PCI_DEV(0, 0x1f, 0), 0x44 /* ACPI_CNTL */ , 0x80); /* Enable ACPI BAR */ + + /* Unlock registers. */ + outw (inw (DEFAULT_PMBASE | 0x003c) | 2, DEFAULT_PMBASE | 0x003c); + + for (i = 0; i < 64; i++) + write32 (DEFAULT_RCBABASE | (0x3500 + 4 * i), rcba_dump[i]); + + pcie_write_config32 (PCI_DEV (0, 0x14, 0), 0xe4, 0x00000000); + + /* Relock registers. */ + outw (0x0000, DEFAULT_PMBASE | 0x003c); +} + + void main(unsigned long bist) { - int boot_mode = 0; - int cbmem_was_initted; + int s3resume = 0; u32 pm1_cnt; u16 pm1_sts; + spd_raw_data spd[4]; if (MCHBAR16(SSKPD) == 0xCAFE) { outb(0x6, 0xcf9); hlt (); } - struct pei_data pei_data = { - .pei_version = PEI_VERSION, - .mchbar = DEFAULT_MCHBAR, - .dmibar = DEFAULT_DMIBAR, - .epbar = DEFAULT_EPBAR, - .pciexbar = CONFIG_MMCONF_BASE_ADDRESS, - .smbusbar = SMBUS_IO_BASE, - .wdbbar = 0x4000000, - .wdbsize = 0x1000, - .hpet_address = CONFIG_HPET_ADDRESS, - .rcba = DEFAULT_RCBABASE, - .pmbase = DEFAULT_PMBASE, - .gpiobase = DEFAULT_GPIOBASE, - .thermalbase = 0xfed08000, - .system_type = 0, // 0 Mobile, 1 Desktop/Server - .tseg_size = CONFIG_SMM_TSEG_SIZE, - .spd_addresses = { 0xA0, 0x00,0xA2,0x00 }, - .ts_addresses = { 0x00, 0x00, 0x00, 0x00 }, - .ec_present = 1, - .gbe_enable = 1, - .ddr3lv_support = 0, - // 0 = leave channel enabled - // 1 = disable dimm 0 on channel - // 2 = disable dimm 1 on channel - // 3 = disable dimm 0+1 on channel - .dimm_channel0_disabled = 2, - .dimm_channel1_disabled = 2, - .max_ddr3_freq = 1600, - .usb_port_config = { - /* enabled usb oc pin length */ - { 1, 0, 0x0080 }, /* P0 (left, fan side), OC 0 */ - { 1, 1, 0x0080 }, /* P1 (left touchpad side), OC 1 */ - { 1, 3, 0x0080 }, /* P2: dock, OC 3 */ - { 1, 0, 0x0040 }, /* P3: wwan, no OC */ - { 1, 0, 0x0080 }, /* P4: Wacom tablet on X230t, otherwise empty */ - { 1, 0, 0x0080 }, /* P5: Expresscard, no OC */ - { 0, 0, 0x0000 }, /* P6: Empty */ - { 1, 0, 0x0080 }, /* P7: dock, no OC */ - { 0, 0, 0x0000 }, /* P8: Empty */ - { 1, 5, 0x0080 }, /* P9: Right (EHCI debug), OC 5 */ - { 1, 0, 0x0040 }, /* P10: fingerprint reader, no OC */ - { 1, 0, 0x0040 }, /* P11: bluetooth, no OC. */ - { 1, 0, 0x0040 }, /* P12: wlan, no OC */ - { 1, 0, 0x0080 }, /* P13: webcam, no OC */ - }, - .ddr_refresh_rate_config = 2, /* Force double refresh rate */ - }; - timestamp_init(get_initial_timestamp()); timestamp_add_now(TS_START_ROMSTAGE); @@ -183,6 +175,8 @@ void main(unsigned long bist) setup_pch_gpios(&x230_gpio_map); + init_usb(); + /* Initialize console device(s) */ console_init(); @@ -204,7 +198,7 @@ void main(unsigned long bist) if ((pm1_sts & WAK_STS) && ((pm1_cnt >> 10) & 7) == 5) { if (acpi_s3_resume_allowed()) { printk(BIOS_DEBUG, "Resume from S3 detected.\n"); - boot_mode = 2; + s3resume = 1; /* Clear SLP_TYPE. This will break stage2 but * we care for that when we get there. */ @@ -218,31 +212,16 @@ void main(unsigned long bist) /* Enable SPD ROMs and DDR-III DRAM */ enable_smbus(); - /* Prepare USB controller early in S3 resume */ - if (boot_mode == 2) - enable_usb_bar(); - post_code(0x39); post_code(0x3a); - pei_data.boot_mode = boot_mode; timestamp_add_now(TS_BEFORE_INITRAM); - /* MRC.bin has a bug and sometimes halts (instead of reboot?). - */ - if (boot_mode != 2) - { - RCBA32(GCS) = RCBA32(GCS) & ~(1 << 5); /* reset */ - outw((0 << 11), DEFAULT_PMBASE | 0x60 | 0x08); /* let timer go */ - } - - sdram_initialize(&pei_data); + memset (spd, 0, sizeof (spd)); + read_spd (&spd[0], 0x50); + read_spd (&spd[2], 0x51); - if (boot_mode != 2) - { - RCBA32(GCS) = RCBA32(GCS) | (1 << 5); /* No reset */ - outw((1 << 11), DEFAULT_PMBASE | 0x60 | 0x08); /* halt timer */ - } + init_dram_ddr3 (spd, 1, TCK_800MHZ, s3resume); timestamp_add_now(TS_AFTER_INITRAM); post_code(0x3c); @@ -250,13 +229,7 @@ void main(unsigned long bist) rcba_config(); post_code(0x3d); - quick_ram_check(); - post_code(0x3e); - MCHBAR16(SSKPD) = 0xCAFE; - cbmem_was_initted = !cbmem_recovery(boot_mode==2); - if (boot_mode!=2) - save_mrc_data(&pei_data); #if CONFIG_HAVE_ACPI_RESUME /* If there is no high memory area, we didn't boot before, so @@ -266,18 +239,14 @@ void main(unsigned long bist) *(u32 *)CBMEM_BOOT_MODE = 0; *(u32 *)CBMEM_RESUME_BACKUP = 0; - if ((boot_mode == 2) && cbmem_was_initted) { + if (s3resume) { void *resume_backup_memory = cbmem_find(CBMEM_ID_RESUME); if (resume_backup_memory) { - *(u32 *)CBMEM_BOOT_MODE = boot_mode; + *(u32 *)CBMEM_BOOT_MODE = 2; *(u32 *)CBMEM_RESUME_BACKUP = (u32)resume_backup_memory; } /* Magic for S3 resume */ pci_write_config32(PCI_DEV(0, 0x00, 0), SKPAD, 0xcafed00d); - } else if (boot_mode == 2) { - /* Failed S3 resume, reset to come up cleanly */ - outb(0x6, 0xcf9); - hlt(); } else { pci_write_config32(PCI_DEV(0, 0x00, 0), SKPAD, 0xcafebabe); } diff --git a/src/northbridge/intel/Makefile.inc b/src/northbridge/intel/Makefile.inc index 808a1b2..f1c2540 100644 --- a/src/northbridge/intel/Makefile.inc +++ b/src/northbridge/intel/Makefile.inc @@ -15,6 +15,7 @@ subdirs-$(CONFIG_NORTHBRIDGE_INTEL_I5000) += i5000 subdirs-$(CONFIG_NORTHBRIDGE_INTEL_NEHALEM) += nehalem subdirs-$(CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE) += sandybridge subdirs-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE) += sandybridge +subdirs-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE) += sandybridge subdirs-$(CONFIG_NORTHBRIDGE_INTEL_HASWELL) += haswell subdirs-$(CONFIG_NORTHBRIDGE_INTEL_FSP_SANDYBRIDGE) += fsp_sandybridge subdirs-$(CONFIG_NORTHBRIDGE_INTEL_FSP_IVYBRIDGE) += fsp_sandybridge diff --git a/src/northbridge/intel/sandybridge/Kconfig b/src/northbridge/intel/sandybridge/Kconfig index f13b58d..2ceb945 100644 --- a/src/northbridge/intel/sandybridge/Kconfig +++ b/src/northbridge/intel/sandybridge/Kconfig @@ -33,7 +33,15 @@ config NORTHBRIDGE_INTEL_IVYBRIDGE select DYNAMIC_CBMEM select CPU_INTEL_MODEL_306AX -if NORTHBRIDGE_INTEL_SANDYBRIDGE || NORTHBRIDGE_INTEL_IVYBRIDGE +config NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE + bool + select CACHE_MRC_BIN + select MMCONF_SUPPORT + select MMCONF_SUPPORT_DEFAULT + select CPU_INTEL_MODEL_306AX + select HAVE_DEBUG_RAM_SETUP + +if NORTHBRIDGE_INTEL_SANDYBRIDGE || NORTHBRIDGE_INTEL_IVYBRIDGE || NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE config VGA_BIOS_ID string @@ -50,7 +58,8 @@ config MRC_CACHE_SIZE config DCACHE_RAM_BASE hex - default 0xff7e0000 + default 0xff7e0000 if !NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE + default 0xfefe0000 if NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE config DCACHE_RAM_SIZE hex diff --git a/src/northbridge/intel/sandybridge/Makefile.inc b/src/northbridge/intel/sandybridge/Makefile.inc index a201745..536656b 100644 --- a/src/northbridge/intel/sandybridge/Makefile.inc +++ b/src/northbridge/intel/sandybridge/Makefile.inc @@ -25,7 +25,10 @@ ramstage-$(CONFIG_GENERATE_ACPI_TABLES) += acpi.c ramstage-y += mrccache.c romstage-y += ram_calc.c -romstage-y += raminit.c +romstage-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE) += raminit.c +romstage-$(CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE) += raminit.c +romstage-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE) += raminit_native.c +romstage-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE) += ../../../device/dram/ddr3.c romstage-y += mrccache.c romstage-y += early_init.c romstage-y += report_platform.c @@ -48,7 +51,10 @@ $(obj)/mrc.cache: $(obj)/config.h cbfs-files-$(CONFIG_HAVE_MRC_CACHE) += mrc.cache mrc.cache-file := $(obj)/mrc.cache -mrc.cache-position := 0xfffd0000 +mrc-cache-position-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE) := 0xfffd0000 +mrc-cache-position-$(CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE) := 0xfffd0000 +mrc-cache-position-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE) := 0xfffe0000 +mrc.cache-position := $(mrc-cache-position-y) mrc.cache-type := 0xac endif diff --git a/src/northbridge/intel/sandybridge/gma.c b/src/northbridge/intel/sandybridge/gma.c index d271a1a..a82a284 100644 --- a/src/northbridge/intel/sandybridge/gma.c +++ b/src/northbridge/intel/sandybridge/gma.c @@ -650,9 +650,7 @@ static void gma_func0_init(struct device *dev) physbase = pci_read_config32(dev, 0x5c) & ~0xf; graphics_base = dev->resource_list[1].base; - int lightup_ok = i915lightup(conf, physbase, iobase, mmiobase, graphics_base); - if (lightup_ok) - gfx_set_init_done(1); + i915lightup(conf, physbase, iobase, mmiobase, graphics_base); #endif } diff --git a/src/northbridge/intel/sandybridge/raminit_native.c b/src/northbridge/intel/sandybridge/raminit_native.c new file mode 100644 index 0000000..b1e29a2 --- /dev/null +++ b/src/northbridge/intel/sandybridge/raminit_native.c @@ -0,0 +1,3893 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2014 Damien Zammit <damien(a)zamaudio.com> + * Copyright (C) 2014 Vladimir Serbinenko <phcoder(a)gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <console/console.h> +#include <console/usb.h> +#include <bootmode.h> +#include <string.h> +#include <arch/hlt.h> +#include <arch/io.h> +#include <cbmem.h> +#include <arch/cbfs.h> +#include <cbfs.h> +#include <ip_checksum.h> +#include <pc80/mc146818rtc.h> +#include <device/pci_def.h> +#include "raminit_native.h" +#include "sandybridge.h" +#include <delay.h> +#include <lib.h> + +/* Management Engine is in the southbridge */ +#include "southbridge/intel/bd82x6x/me.h" +/* For SPD. */ +#include "southbridge/intel/bd82x6x/smbus.h" +#include "arch/cpu.h" +#include "cpu/x86/msr.h" + +/* FIXME: no ECC support. */ +/* FIXME: no support for 3-channel chipsets. */ +/* FIXME: no S3. */ + +#define BASEFREQ 133 +#define tDLLK 512 + +#define IS_SANDY_CPU(x) ((x & 0xffff0) == 0x206a0) +#define IS_SANDY_CPU_C(x) ((x & 0xf) == 4) +#define IS_SANDY_CPU_D0(x) ((x & 0xf) == 5) +#define IS_SANDY_CPU_D1(x) ((x & 0xf) == 6) +#define IS_SANDY_CPU_D2(x) ((x & 0xf) == 7) + +#define IS_IVY_CPU(x) ((x & 0xffff0) == 0x306a0) +#define IS_IVY_CPU_C(x) ((x & 0xf) == 4) +#define IS_IVY_CPU_K(x) ((x & 0xf) == 5) +#define IS_IVY_CPU_D(x) ((x & 0xf) == 6) +#define IS_IVY_CPU_E(x) ((x & 0xf) >= 8) + +#define NUM_CHANNELS 2 +#define NUM_SLOTRANKS 4 +#define NUM_SLOTS 2 +#define NUM_LANES 8 + +/* FIXME: Vendor BIOS uses 64 but our algorithms are less + performant and even 1 seems to be enough in practice. */ +#define NUM_PATTERNS 4 + +typedef struct odtmap_st { + u16 rttwr; + u16 rttnom; +} odtmap; + +typedef struct dimm_info_st { + dimm_attr dimm[NUM_CHANNELS][NUM_SLOTS]; +} dimm_info; + +struct ram_rank_timings { + /* Register 4024. One byte per slotrank. */ + u8 val_4024; + /* Register 4028. One nibble per slotrank. */ + u8 val_4028; + + int val_320c; + + struct ram_lane_timings { + /* lane register offset 0x10. */ + u16 timA; /* bits 0 - 5, bits 16 - 18 */ + u8 rising; /* bits 8 - 14 */ + u8 falling; /* bits 20 - 26. */ + + /* lane register offset 0x20. */ + int timC; /* bit 0 - 5, 19. */ + u16 timB; /* bits 8 - 13, 15 - 17. */ + } lanes[NUM_LANES]; +}; + +struct ramctr_timing_st; + +typedef struct ramctr_timing_st { + int mobile; + + 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 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 */ + + u32 tREFI; + u32 tMOD; + u32 tXSOffset; + u32 tWLO; + u32 tCKE; + u32 tXPDLL; + u32 tXP; + u32 tAONPD; + + u16 reg_5064b0; /* bits 0-11. */ + + u8 rankmap[NUM_CHANNELS]; + int ref_card_offset[NUM_CHANNELS]; + u32 mad_dimm[NUM_CHANNELS]; + int channel_size_mb[NUM_CHANNELS]; + u32 reg_4004_b30[NUM_CHANNELS]; + + int reg_c14_offset; + int reg_320c_range_threshold; + + int edge_offset[3]; + int timC_offset[3]; + + int extended_temperature_range; + int auto_self_refresh; + + int rank_mirror[NUM_CHANNELS][NUM_SLOTRANKS]; + + struct ram_rank_timings timings[NUM_CHANNELS][NUM_SLOTRANKS]; +} ramctr_timing; + +#define SOUTHBRIDGE PCI_DEV(0, 0x1f, 0) +#define NORTHBRIDGE PCI_DEV(0, 0x0, 0) +#define FOR_ALL_LANES for (lane = 0; lane < NUM_LANES; lane++) +#define FOR_ALL_CHANNELS for (channel = 0; channel < NUM_CHANNELS; channel++) +#define FOR_ALL_POPULATED_RANKS for (slotrank = 0; slotrank < NUM_SLOTRANKS; slotrank++) if (ctrl->rankmap[channel] & (1 << slotrank)) +#define FOR_ALL_POPULATED_CHANNELS for (channel = 0; channel < NUM_CHANNELS; channel++) if (ctrl->rankmap[channel]) +#define MAX_EDGE_TIMING 71 +#define MAX_TIMC 127 +#define MAX_TIMB 511 +#define MAX_TIMA 127 + +static void program_timings(ramctr_timing * ctrl, int channel); + +static const char *ecc_decoder[] = { + "inactive", + "active on IO", + "disabled on IO", + "active" +}; + +static void wait_txt_clear(void) +{ + struct cpuid_result cp; + + cp = cpuid_ext(0x1, 0x0); + /* Check if TXT is supported? */ + if (!(cp.ecx & 0x40)) + return; + /* Some TXT public bit. */ + if (!(read32(0xfed30010) & 1)) + return; + /* Wait for TXT clear. */ + while (!(read8(0xfed40000) & (1 << 7))) ; +} + +static void sfence(void) +{ + asm volatile ("sfence"); +} + +/* + * Dump in the log memory controller configuration as read from the memory + * controller registers. + */ +static void report_memory_config(void) +{ + u32 addr_decoder_common, addr_decode_ch[NUM_CHANNELS]; + int i; + + addr_decoder_common = MCHBAR32(0x5000); + addr_decode_ch[0] = MCHBAR32(0x5004); + addr_decode_ch[1] = MCHBAR32(0x5008); + + printk(BIOS_DEBUG, "memcfg DDR3 clock %d MHz\n", + (MCHBAR32(0x5e04) * 13333 * 2 + 50) / 100); + printk(BIOS_DEBUG, "memcfg channel assignment: A: %d, B % d, C % d\n", + addr_decoder_common & 3, (addr_decoder_common >> 2) & 3, + (addr_decoder_common >> 4) & 3); + + for (i = 0; i < ARRAY_SIZE(addr_decode_ch); i++) { + u32 ch_conf = addr_decode_ch[i]; + printk(BIOS_DEBUG, "memcfg channel[%d] config (%8.8x):\n", i, + ch_conf); + printk(BIOS_DEBUG, " ECC %s\n", + ecc_decoder[(ch_conf >> 24) & 3]); + printk(BIOS_DEBUG, " enhanced interleave mode %s\n", + ((ch_conf >> 22) & 1) ? "on" : "off"); + printk(BIOS_DEBUG, " rank interleave %s\n", + ((ch_conf >> 21) & 1) ? "on" : "off"); + printk(BIOS_DEBUG, " DIMMA %d MB width x%d %s rank%s\n", + ((ch_conf >> 0) & 0xff) * 256, + ((ch_conf >> 19) & 1) ? 16 : 8, + ((ch_conf >> 17) & 1) ? "dual" : "single", + ((ch_conf >> 16) & 1) ? "" : ", selected"); + printk(BIOS_DEBUG, " DIMMB %d MB width x%d %s rank%s\n", + ((ch_conf >> 8) & 0xff) * 256, + ((ch_conf >> 20) & 1) ? 16 : 8, + ((ch_conf >> 18) & 1) ? "dual" : "single", + ((ch_conf >> 16) & 1) ? ", selected" : ""); + } +} + +static void post_system_agent_init(void) +{ + /* If PCIe init is skipped, set the PEG clock gating */ + MCHBAR32(0x7010) = MCHBAR32(0x7010) | 0x01; +} + +void read_spd(spd_raw_data * spd, u8 addr) +{ + int j; + for (j = 0; j < 256; j++) + (*spd)[j] = do_smbus_read_byte(SMBUS_IO_BASE, addr, j); +} + +static void dram_find_spds_ddr3(spd_raw_data * spd, dimm_info * dimm, + ramctr_timing * ctrl) +{ + int dimms = 0; + int channel, slot, spd_slot; + + memset (ctrl->rankmap, 0, sizeof (ctrl->rankmap)); + + ctrl->extended_temperature_range = 1; + ctrl->auto_self_refresh = 1; + + FOR_ALL_CHANNELS { + ctrl->channel_size_mb[channel] = 0; + + for (slot = 0; slot < NUM_SLOTS; slot++) { + spd_slot = 2 * channel + slot; + spd_decode_ddr3(&dimm->dimm[channel][slot], spd[spd_slot]); + if (dimm->dimm[channel][slot].dram_type != SPD_MEMORY_TYPE_SDRAM_DDR3) { + // set dimm invalid + dimm->dimm[channel][slot].ranks = 0; + dimm->dimm[channel][slot].size_mb = 0; + continue; + } + + dram_print_spd_ddr3(&dimm->dimm[channel][slot]); + dimms++; + ctrl->rank_mirror[channel][slot * 2] = 0; + ctrl->rank_mirror[channel][slot * 2 + 1] = dimm->dimm[channel][slot].flags.pins_mirrored; + ctrl->channel_size_mb[channel] += dimm->dimm[channel][slot].size_mb; + + ctrl->auto_self_refresh &= dimm->dimm[channel][slot].flags.asr; + ctrl->extended_temperature_range &= dimm->dimm[channel][slot].flags.ext_temp_refresh; + + ctrl->rankmap[channel] = ((1 << dimm->dimm[channel][slot].ranks) - 1) << (2 * slot); + printk(BIOS_DEBUG, "rankmap[%d] = 0x%x\n", channel, ctrl->rankmap[channel]); + } + if ((ctrl->rankmap[channel] & 3) && (ctrl->rankmap[channel] & 0xc) + && dimm->dimm[channel][0].reference_card <= 5 && dimm->dimm[channel][1].reference_card <= 5) { + const int ref_card_offset_table[6][6] = { + { 0, 0, 0, 0, 2, 2, }, + { 0, 0, 0, 0, 2, 2, }, + { 0, 0, 0, 0, 2, 2, }, + { 0, 0, 0, 0, 1, 1, }, + { 2, 2, 2, 1, 0, 0, }, + { 2, 2, 2, 1, 0, 0, }, + }; + ctrl->ref_card_offset[channel] = ref_card_offset_table[dimm->dimm[channel][0].reference_card] + [dimm->dimm[channel][1].reference_card]; + } else + ctrl->ref_card_offset[channel] = 0; + } + + if (!dimms) + die("No DIMMs were found"); +} + +static void dram_find_common_params(const dimm_info * dimms, + ramctr_timing * ctrl) +{ + size_t valid_dimms; + int channel, slot; + ctrl->cas_supported = 0xff; + valid_dimms = 0; + FOR_ALL_CHANNELS for (slot = 0; slot < 2; slot++) { + const dimm_attr *dimm = &dimms->dimm[channel][slot]; + if (dimm->dram_type != SPD_MEMORY_TYPE_SDRAM_DDR3) + continue; + valid_dimms++; + + /* 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->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 u8 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]; +} + +/* Frequency multiplier. */ +static u32 get_FRQ(u32 tCK) +{ + u32 FRQ; + FRQ = 256000 / (tCK * BASEFREQ); + if (FRQ > 8) + return 8; + if (FRQ < 3) + return 3; + return FRQ; +} + +static u32 get_REFI(u32 tCK) +{ + /* Get REFI based on MCU frequency using the following rule: + * _________________________________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * REFI: | 3120 | 4160 | 5200 | 6240 | 7280 | 8320 | + */ + static const u32 frq_refi_map[] = + { 3120, 4160, 5200, 6240, 7280, 8320 }; + return frq_refi_map[get_FRQ(tCK) - 3]; +} + +static u8 get_XSOffset(u32 tCK) +{ + /* Get XSOffset based on MCU frequency using the following rule: + * _________________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * XSOffset : | 4 | 6 | 7 | 8 | 10 | 11 | + */ + static const u8 frq_xs_map[] = { 4, 6, 7, 8, 10, 11 }; + return frq_xs_map[get_FRQ(tCK) - 3]; +} + +static u8 get_MOD(u32 tCK) +{ + /* Get MOD based on MCU frequency using the following rule: + * _____________________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * MOD : | 12 | 12 | 12 | 12 | 15 | 16 | + */ + static const u8 frq_mod_map[] = { 12, 12, 12, 12, 15, 16 }; + return frq_mod_map[get_FRQ(tCK) - 3]; +} + +static u8 get_WLO(u32 tCK) +{ + /* Get WLO based on MCU frequency using the following rule: + * _______________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * WLO : | 4 | 5 | 6 | 6 | 8 | 8 | + */ + static const u8 frq_wlo_map[] = { 4, 5, 6, 6, 8, 8 }; + return frq_wlo_map[get_FRQ(tCK) - 3]; +} + +static u8 get_CKE(u32 tCK) +{ + /* Get CKE based on MCU frequency using the following rule: + * _______________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * CKE : | 3 | 3 | 4 | 4 | 5 | 6 | + */ + static const u8 frq_cke_map[] = { 3, 3, 4, 4, 5, 6 }; + return frq_cke_map[get_FRQ(tCK) - 3]; +} + +static u8 get_XPDLL(u32 tCK) +{ + /* Get XPDLL based on MCU frequency using the following rule: + * _____________________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * XPDLL : | 10 | 13 | 16 | 20 | 23 | 26 | + */ + static const u8 frq_xpdll_map[] = { 10, 13, 16, 20, 23, 26 }; + return frq_xpdll_map[get_FRQ(tCK) - 3]; +} + +static u8 get_XP(u32 tCK) +{ + /* Get XP based on MCU frequency using the following rule: + * _______________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * XP : | 3 | 4 | 4 | 5 | 6 | 7 | + */ + static const u8 frq_xp_map[] = { 3, 4, 4, 5, 6, 7 }; + return frq_xp_map[get_FRQ(tCK) - 3]; +} + +static u8 get_AONPD(u32 tCK) +{ + /* Get AONPD based on MCU frequency using the following rule: + * ________________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * AONPD : | 4 | 5 | 6 | 8 | 8 | 10 | + */ + static const u8 frq_aonpd_map[] = { 4, 5, 6, 8, 8, 10 }; + return frq_aonpd_map[get_FRQ(tCK) - 3]; +} + +static u32 get_COMP2(u32 tCK) +{ + /* Get COMP2 based on MCU frequency using the following rule: + * ___________________________________________________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * COMP : | D6BEDCC | CE7C34C | CA57A4C | C6369CC | C42514C | C21410C | + */ + static const u32 frq_comp2_map[] = { 0xD6BEDCC, 0xCE7C34C, 0xCA57A4C, + 0xC6369CC, 0xC42514C, 0xC21410C + }; + return frq_comp2_map[get_FRQ(tCK) - 3]; +} + +static void dram_timing(ramctr_timing * ctrl) +{ + u8 val; + u32 val32; + + /* Maximum supported DDR3 frequency is 1066MHz (DDR3 2133) so make sure + * we cap it if we have faster DIMMs. + * Then, align it to the closest JEDEC standard frequency */ + if (ctrl->tCK <= TCK_1066MHZ) { + ctrl->tCK = TCK_1066MHZ; + ctrl->edge_offset[0] = 16; + ctrl->edge_offset[1] = 7; + ctrl->edge_offset[2] = 7; + ctrl->timC_offset[0] = 18; + ctrl->timC_offset[1] = 7; + ctrl->timC_offset[2] = 7; + ctrl->reg_c14_offset = 16; + ctrl->reg_5064b0 = 0x218; + ctrl->reg_320c_range_threshold = 13; + } else if (ctrl->tCK <= TCK_933MHZ) { + ctrl->tCK = TCK_933MHZ; + ctrl->edge_offset[0] = 14; + ctrl->edge_offset[1] = 6; + ctrl->edge_offset[2] = 6; + ctrl->timC_offset[0] = 15; + ctrl->timC_offset[1] = 6; + ctrl->timC_offset[2] = 6; + ctrl->reg_c14_offset = 14; + ctrl->reg_5064b0 = 0x1d5; + ctrl->reg_320c_range_threshold = 15; + } else if (ctrl->tCK <= TCK_800MHZ) { + ctrl->tCK = TCK_800MHZ; + ctrl->edge_offset[0] = 13; + ctrl->edge_offset[1] = 5; + ctrl->edge_offset[2] = 5; + ctrl->timC_offset[0] = 14; + ctrl->timC_offset[1] = 5; + ctrl->timC_offset[2] = 5; + ctrl->reg_c14_offset = 12; + ctrl->reg_5064b0 = 0x193; + ctrl->reg_320c_range_threshold = 15; + } else if (ctrl->tCK <= TCK_666MHZ) { + ctrl->tCK = TCK_666MHZ; + ctrl->edge_offset[0] = 10; + ctrl->edge_offset[1] = 4; + ctrl->edge_offset[2] = 4; + ctrl->timC_offset[0] = 11; + ctrl->timC_offset[1] = 4; + ctrl->timC_offset[2] = 4; + ctrl->reg_c14_offset = 10; + ctrl->reg_5064b0 = 0x150; + ctrl->reg_320c_range_threshold = 16; + } else if (ctrl->tCK <= TCK_533MHZ) { + ctrl->tCK = TCK_533MHZ; + ctrl->edge_offset[0] = 8; + ctrl->edge_offset[1] = 3; + ctrl->edge_offset[2] = 3; + ctrl->timC_offset[0] = 9; + ctrl->timC_offset[1] = 3; + ctrl->timC_offset[2] = 3; + ctrl->reg_c14_offset = 8; + ctrl->reg_5064b0 = 0x10d; + ctrl->reg_320c_range_threshold = 17; + } else { + ctrl->tCK = TCK_400MHZ; + ctrl->edge_offset[0] = 6; + ctrl->edge_offset[1] = 2; + ctrl->edge_offset[2] = 2; + ctrl->timC_offset[0] = 6; + ctrl->timC_offset[1] = 2; + ctrl->timC_offset[2] = 2; + ctrl->reg_c14_offset = 8; + ctrl->reg_5064b0 = 0xcd; + ctrl->reg_320c_range_threshold = 17; + } + + val32 = (1000 << 8) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected DRAM frequency: %u MHz\n", val32); + + /* Find CAS and CWL latencies */ + val = (ctrl->tAA + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "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)))) + printk(BIOS_DEBUG, "CAS not supported\n"); + printk(BIOS_DEBUG, "Selected CAS latency : %uT\n", val); + ctrl->CAS = val; + ctrl->CWL = get_CWL(ctrl->CAS); + printk(BIOS_DEBUG, "Selected CWL latency : %uT\n", ctrl->CWL); + + /* Find tRCD */ + ctrl->tRCD = (ctrl->tRCD + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected tRCD : %uT\n", ctrl->tRCD); + + ctrl->tRP = (ctrl->tRP + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected tRP : %uT\n", ctrl->tRP); + + /* Find tRAS */ + ctrl->tRAS = (ctrl->tRAS + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected tRAS : %uT\n", ctrl->tRAS); + + /* Find tWR */ + ctrl->tWR = (ctrl->tWR + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected tWR : %uT\n", ctrl->tWR); + + /* Find tFAW */ + ctrl->tFAW = (ctrl->tFAW + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected tFAW : %uT\n", ctrl->tFAW); + + /* Find tRRD */ + ctrl->tRRD = (ctrl->tRRD + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected tRRD : %uT\n", ctrl->tRRD); + + /* Find tRTP */ + ctrl->tRTP = (ctrl->tRTP + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected tRTP : %uT\n", ctrl->tRTP); + + /* Find tWTR */ + ctrl->tWTR = (ctrl->tWTR + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected tWTR : %uT\n", ctrl->tWTR); + + /* Refresh-to-Active or Refresh-to-Refresh (tRFC) */ + ctrl->tRFC = (ctrl->tRFC + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected tRFC : %uT\n", ctrl->tRFC); + + ctrl->tREFI = get_REFI(ctrl->tCK); + ctrl->tMOD = get_MOD(ctrl->tCK); + ctrl->tXSOffset = get_XSOffset(ctrl->tCK); + ctrl->tWLO = get_WLO(ctrl->tCK); + ctrl->tCKE = get_CKE(ctrl->tCK); + ctrl->tXPDLL = get_XPDLL(ctrl->tCK); + ctrl->tXP = get_XP(ctrl->tCK); + ctrl->tAONPD = get_AONPD(ctrl->tCK); +} + +static void dram_freq(ramctr_timing * ctrl) +{ + u8 val2; + u32 reg1 = 0; + + /* Step 1 - Set target PCU frequency */ + + if (ctrl->tCK <= TCK_1066MHZ) { + ctrl->tCK = TCK_1066MHZ; + } else if (ctrl->tCK <= TCK_933MHZ) { + ctrl->tCK = TCK_933MHZ; + } else if (ctrl->tCK <= TCK_800MHZ) { + ctrl->tCK = TCK_800MHZ; + } else if (ctrl->tCK <= TCK_666MHZ) { + ctrl->tCK = TCK_666MHZ; + } else if (ctrl->tCK <= TCK_533MHZ) { + ctrl->tCK = TCK_533MHZ; + } else { + ctrl->tCK = TCK_400MHZ; + } + + /* Frequency mulitplier. */ + u32 FRQ = get_FRQ(ctrl->tCK); + + /* Step 2 - Select frequency in the MCU */ + reg1 = FRQ; + reg1 |= 0x80000000; // set running bit + MCHBAR32(0x5e00) = reg1; + while (reg1 & 0x80000000) { + printk(BIOS_DEBUG, " PLL busy..."); + reg1 = MCHBAR32(0x5e00); + } + printk(BIOS_DEBUG, "done\n"); + + /* Step 3 - Verify lock frequency */ + reg1 = MCHBAR32(0x5e04); + val2 = (u8) reg1; + if (val2 < FRQ) { + printk(BIOS_DEBUG, "Lock frequency is lower, recalculating\n"); + ctrl->tCK = 256000 / (val2 * BASEFREQ); + } + printk(BIOS_DEBUG, "MCU frequency is set at : %d MHz\n", + (1000 << 8) / ctrl->tCK); +} + +static void dram_xover(ramctr_timing * ctrl) +{ + u32 reg; + int channel; + + FOR_ALL_CHANNELS { + // enable xover clk + printk(BIOS_DEBUG, "[%x] = %x\n", channel * 0x100 + 0xc14, + (ctrl->rankmap[channel] << 24)); + MCHBAR32(channel * 0x100 + 0xc14) = (ctrl->rankmap[channel] << 24); + + // enable xover ctl + reg = 0; + if (ctrl->rankmap[channel] & 0x5) { + reg |= 0x20000; + } + if (ctrl->rankmap[channel] & 0xa) { + reg |= 0x4000000; + } + // enable xover cmd + reg |= 0x4000; + printk(BIOS_DEBUG, "[%x] = %x\n", 0x100 * channel + 0x320c, + reg); + MCHBAR32(0x100 * channel + 0x320c) = reg; + } +} + +static void dram_timing_regs(ramctr_timing * ctrl) +{ + u32 reg, addr, val32, cpu, stretch; + struct cpuid_result cpures; + int channel; + + FOR_ALL_CHANNELS { + // DBP + reg = 0; + reg |= ctrl->tRCD; + reg |= (ctrl->tRP << 4); + reg |= (ctrl->CAS << 8); + reg |= (ctrl->CWL << 12); + reg |= (ctrl->tRAS << 16); + printk(BIOS_DEBUG, "[%x] = %x\n", 0x400 * channel + 0x4000, + reg); + MCHBAR32(0x400 * channel + 0x4000) = reg; + + // RAP + reg = 0; + reg |= ctrl->tRRD; + reg |= (ctrl->tRTP << 4); + reg |= (ctrl->tCKE << 8); + reg |= (ctrl->tWTR << 12); + reg |= (ctrl->tFAW << 16); + reg |= (ctrl->tWR << 24); + reg |= (3 << 30); + printk(BIOS_DEBUG, "[%x] = %x\n", 0x400 * channel + 0x4004, + reg); + MCHBAR32(0x400 * channel + 0x4004) = reg; + + // OTHP + addr = 0x400 * channel + 0x400c; + reg = 0; + reg |= ctrl->tXPDLL; + reg |= (ctrl->tXP << 5); + reg |= (ctrl->tAONPD << 8); + reg |= 0xa0000; + printk(BIOS_DEBUG, "[%x] = %x\n", addr, reg); + MCHBAR32(addr) = reg; + + MCHBAR32(0x400 * channel + 0x4014) = 0; + + MCHBAR32(addr) |= 0x00020000; + + // ODT stretch + reg = 0; + + cpures = cpuid(0); + cpu = cpures.eax; + if (IS_IVY_CPU(cpu) + || (IS_SANDY_CPU(cpu) && IS_SANDY_CPU_D2(cpu))) { + stretch = 2; + addr = 0x400 * channel + 0x400c; + printk(BIOS_DEBUG, "[%x] = %x\n", + 0x400 * channel + 0x400c, reg); + reg = MCHBAR32(addr); + + if (((ctrl->rankmap[channel] & 3) == 0) + || (ctrl->rankmap[channel] & 0xc) == 0) { + + // Rank 0 - operate on rank 2 + reg = (reg & ~0xc0000) | (stretch << 18); + + // Rank 2 - operate on rank 0 + reg = (reg & ~0x30000) | (stretch << 16); + + printk(BIOS_DEBUG, "[%x] = %x\n", addr, reg); + MCHBAR32(addr) = reg; + } + + } else if (IS_SANDY_CPU(cpu) && IS_SANDY_CPU_C(cpu)) { + stretch = 3; + addr = 0x400 * channel + 0x401c; + reg = MCHBAR32(addr); + + if (((ctrl->rankmap[channel] & 3) == 0) + || (ctrl->rankmap[channel] & 0xc) == 0) { + + // Rank 0 - operate on rank 2 + reg = (reg & ~0x3000) | (stretch << 12); + + // Rank 2 - operate on rank 0 + reg = (reg & ~0xc00) | (stretch << 10); + + printk(BIOS_DEBUG, "[%x] = %x\n", addr, reg); + MCHBAR32(addr) = reg; + } + } else { + stretch = 0; + } + + // REFI + reg = 0; + val32 = ctrl->tREFI; + reg = (reg & ~0xffff) | val32; + val32 = ctrl->tRFC; + reg = (reg & ~0x1ff0000) | (val32 << 16); + val32 = (u32) (ctrl->tREFI * 9) / 1024; + reg = (reg & ~0xfe000000) | (val32 << 25); + printk(BIOS_DEBUG, "[%x] = %x\n", 0x400 * channel + 0x4298, + reg); + MCHBAR32(0x400 * channel + 0x4298) = reg; + + MCHBAR32(0x400 * channel + 0x4294) |= 0xff; + + // SRFTP + reg = 0; + val32 = tDLLK; + reg = (reg & ~0xfff) | val32; + val32 = ctrl->tXSOffset; + reg = (reg & ~0xf000) | (val32 << 12); + val32 = tDLLK - ctrl->tXSOffset; + reg = (reg & ~0x3ff0000) | (val32 << 16); + val32 = ctrl->tMOD - 8; + reg = (reg & ~0xf0000000) | (val32 << 28); + printk(BIOS_DEBUG, "[%x] = %x\n", 0x400 * channel + 0x42a4, + reg); + MCHBAR32(0x400 * channel + 0x42a4) = reg; + } +} + +static void dram_dimm_mapping(dimm_info * info, ramctr_timing * ctrl) +{ + int t; + u32 reg, val32; + int channel; + + FOR_ALL_CHANNELS { + dimm_attr *dimmA = 0; + dimm_attr *dimmB = 0; + reg = 0; + val32 = 0; + if (info->dimm[channel][0].size_mb >= + info->dimm[channel][1].size_mb) { + // dimm 0 is bigger, set it to dimmA + dimmA = &info->dimm[channel][0]; + dimmB = &info->dimm[channel][1]; + reg |= (0 << 16); + } else { + // dimm 1 is bigger, set it to dimmA + dimmA = &info->dimm[channel][1]; + dimmB = &info->dimm[channel][0]; + reg |= (1 << 16); + // swap dimm info + t = ctrl->rank_mirror[channel][1]; + ctrl->rank_mirror[channel][1] = + ctrl->rank_mirror[channel][3]; + ctrl->rank_mirror[channel][3] = t; + } + // dimmA + if (dimmA && (dimmA->ranks > 0)) { + val32 = dimmA->size_mb / 256; + reg = (reg & ~0xff) | val32; + val32 = dimmA->ranks - 1; + reg = (reg & ~0x20000) | (val32 << 17); + val32 = (dimmA->width / 8) - 1; + reg = (reg & ~0x80000) | (val32 << 19); + } + // dimmB + if (dimmB && (dimmB->ranks > 0)) { + val32 = dimmB->size_mb / 256; + reg = (reg & ~0xff00) | (val32 << 8); + val32 = dimmB->ranks - 1; + reg = (reg & ~0x40000) | (val32 << 18); + val32 = (dimmB->width / 8) - 1; + reg = (reg & ~0x100000) | (val32 << 20); + } + reg = (reg & ~0x200000) | (1 << 21); // rank interleave + reg = (reg & ~0x400000) | (1 << 22); // enhanced interleave + + // Save MAD-DIMM register + if ((dimmA && (dimmA->ranks > 0)) + || (dimmB && (dimmB->ranks > 0))) { + ctrl->mad_dimm[channel] = reg; + } else { + ctrl->mad_dimm[channel] = 0; + } + } +} + +static void dram_dimm_set_mapping(ramctr_timing * ctrl) +{ + int channel; + FOR_ALL_CHANNELS { + MCHBAR32(0x5004 + channel * 4) = ctrl->mad_dimm[channel]; + } +} + +static void dram_zones(ramctr_timing * ctrl, int training) +{ + u32 reg, ch0size, ch1size; + u8 val; + reg = 0; + val = 0; + if (training) { + ch0size = ctrl->channel_size_mb[0] ? 256 : 0; + ch1size = ctrl->channel_size_mb[1] ? 256 : 0; + } else { + ch0size = ctrl->channel_size_mb[0]; + ch1size = ctrl->channel_size_mb[1]; + } + + if (ch0size >= ch1size) { + reg = MCHBAR32(0x5014); + val = ch1size / 256; + reg = (reg & ~0xff000000) | val << 24; + reg = (reg & ~0xff0000) | (2 * val) << 16; + MCHBAR32(0x5014) = reg; + MCHBAR32(0x5000) = 0x24; + } else { + reg = MCHBAR32(0x5014); + val = ch0size / 256; + reg = (reg & ~0xff000000) | val << 24; + reg = (reg & ~0xff0000) | (2 * val) << 16; + MCHBAR32(0x5014) = reg; + MCHBAR32(0x5000) = 0x21; + } +} + +static void dram_memorymap(ramctr_timing * ctrl, int me_uma_size) +{ + u32 reg, val, reclaim; + u32 tom, gfxstolen, gttsize; + size_t tsegsize, mmiosize, toludbase, touudbase, gfxstolenbase, gttbase, + tsegbase, mestolenbase; + size_t tsegbasedelta, remapbase, remaplimit; + uint16_t ggc; + + mmiosize = 0x400; + + ggc = pci_read_config16(NORTHBRIDGE, GGC); + if (!(ggc & 2)) { + gfxstolen = ((ggc >> 3) & 0x1f) * 32; + gttsize = ((ggc >> 8) & 0x3); + } else { + gfxstolen = 0; + gttsize = 0; + } + + tsegsize = CONFIG_SMM_TSEG_SIZE >> 20; + + tom = ctrl->channel_size_mb[0] + ctrl->channel_size_mb[1]; + + mestolenbase = tom - me_uma_size; + + toludbase = MIN(4096 - mmiosize + gfxstolen + gttsize + tsegsize, + tom - me_uma_size); + gfxstolenbase = toludbase - gfxstolen; + gttbase = gfxstolenbase - gttsize; + + tsegbase = gttbase - tsegsize; + + // Round tsegbase down to nearest address aligned to tsegsize + tsegbasedelta = tsegbase & (tsegsize - 1); + tsegbase &= ~(tsegsize - 1); + + gttbase -= tsegbasedelta; + gfxstolenbase -= tsegbasedelta; + toludbase -= tsegbasedelta; + + // Test if it is possible to reclaim a hole in the ram addressing + if (tom - me_uma_size > toludbase) { + // Reclaim is possible + reclaim = 1; + remapbase = MAX(4096, tom - me_uma_size); + remaplimit = + remapbase + MIN(4096, tom - me_uma_size) - toludbase - 1; + touudbase = remaplimit + 1; + } else { + // Reclaim not possible + reclaim = 0; + touudbase = tom - me_uma_size; + } + + // Update memory map in pci-e configuration space + + // TOM (top of memory) + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xa0); + val = tom & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + printk(BIOS_DEBUG, "PCI:[%x] = %x\n", 0xa0, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xa0, reg); + + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xa4); + val = tom & 0xfffff000; + reg = (reg & ~0x000fffff) | (val >> 12); + printk(BIOS_DEBUG, "PCI:[%x] = %x\n", 0xa4, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xa4, reg); + + // TOLUD (top of low used dram) + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xbc); + val = toludbase & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + printk(BIOS_DEBUG, "PCI:[%x] = %x\n", 0xbc, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xbc, reg); + + // TOUUD LSB (top of upper usable dram) + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xa8); + val = touudbase & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + printk(BIOS_DEBUG, "PCI:[%x] = %x\n", 0xa8, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xa8, reg); + + // TOUUD MSB + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xac); + val = touudbase & 0xfffff000; + reg = (reg & ~0x000fffff) | (val >> 12); + printk(BIOS_DEBUG, "PCI:[%x] = %x\n", 0xac, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xac, reg); + + if (reclaim) { + // REMAP BASE + pcie_write_config32(PCI_DEV(0, 0, 0), 0x90, remapbase << 20); + pcie_write_config32(PCI_DEV(0, 0, 0), 0x94, remapbase >> 12); + + // REMAP LIMIT + pcie_write_config32(PCI_DEV(0, 0, 0), 0x98, remaplimit << 20); + pcie_write_config32(PCI_DEV(0, 0, 0), 0x9c, remaplimit >> 12); + } + // TSEG + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xb8); + val = tsegbase & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + printk(BIOS_DEBUG, "PCI:[%x] = %x\n", 0xb8, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xb8, reg); + + // GFX stolen memory + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xb0); + val = gfxstolenbase & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + printk(BIOS_DEBUG, "PCI:[%x] = %x\n", 0xb0, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xb0, reg); + + // GTT stolen memory + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xb4); + val = gttbase & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + printk(BIOS_DEBUG, "PCI:[%x] = %x\n", 0xb4, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xb4, reg); + + if (me_uma_size) { + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0x7c); + val = (0x80000 - me_uma_size) & 0xfffff000; + reg = (reg & ~0x000fffff) | (val >> 12); + printk(BIOS_DEBUG, "PCI:[%x] = %x\n", 0x7c, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0x7c, reg); + + // ME base + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0x70); + val = mestolenbase & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + printk(BIOS_DEBUG, "PCI:[%x] = %x\n", 0x70, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0x70, reg); + + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0x74); + val = mestolenbase & 0xfffff000; + reg = (reg & ~0x000fffff) | (val >> 12); + printk(BIOS_DEBUG, "PCI:[%x] = %x\n", 0x74, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0x74, reg); + + // ME mask + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0x78); + val = (0x80000 - me_uma_size) & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + reg = (reg & ~0x400) | (1 << 10); // set lockbit on ME mem + + reg = (reg & ~0x800) | (1 << 11); // set ME memory enable + printk(BIOS_DEBUG, "PCI:[%x] = %x\n", 0x78, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0x78, reg); + } +} + +static void dram_ioregs(ramctr_timing * ctrl) +{ + u32 reg, comp2; + + int channel; + + // IO clock + FOR_ALL_CHANNELS { + MCHBAR32(0xc00 + 0x100 * channel) = ctrl->rankmap[channel]; + } + + // IO command + FOR_ALL_CHANNELS { + MCHBAR32(0x3200 + 0x100 * channel) = ctrl->rankmap[channel]; + } + + // IO control + FOR_ALL_POPULATED_CHANNELS { + program_timings(ctrl, channel); + } + + // Rcomp + printk(BIOS_DEBUG, "RCOMP..."); + reg = 0; + while (reg == 0) { + reg = MCHBAR32(0x5084) & 0x10000; + } + printk(BIOS_DEBUG, "done\n"); + + // Set comp2 + comp2 = get_COMP2(ctrl->tCK); + MCHBAR32(0x3714) = comp2; + printk(BIOS_DEBUG, "COMP2 done\n"); + + // Set comp1 + FOR_ALL_POPULATED_CHANNELS { + reg = MCHBAR32(0x1810 + channel * 0x100); //ch0 + reg = (reg & ~0xe00) | (1 << 9); //odt + reg = (reg & ~0xe00000) | (1 << 21); //clk drive up + reg = (reg & ~0x38000000) | (1 << 27); //ctl drive up + MCHBAR32(0x1810 + channel * 0x100) = reg; + } + printk(BIOS_DEBUG, "COMP1 done\n"); + + printk(BIOS_DEBUG, "FORCE RCOMP and wait 20us..."); + MCHBAR32(0x5f08) |= 0x100; + udelay(20); + printk(BIOS_DEBUG, "done\n"); +} + +static void wait_428c(int channel) +{ + while (1) { + if (read32(DEFAULT_MCHBAR | 0x428c | (channel << 10)) & 0x50) + return; + } +} + +static void write_reset(ramctr_timing * ctrl) +{ + int channel, slotrank; + + /* choose a populated channel. */ + channel = (ctrl->rankmap[0]) ? 0 : 1; + + wait_428c(channel); + + /* choose a populated rank. */ + slotrank = (ctrl->rankmap[channel] & 1) ? 0 : 2; + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x0f003); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0x80c01); + + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x60000); + + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0x400001); + wait_428c(channel); +} + +static void dram_jedecreset(ramctr_timing * ctrl) +{ + u32 reg, addr; + int channel; + + while (!(MCHBAR32(0x5084) & 0x10000)) ; + do { + reg = MCHBAR32(0x428c); + } while ((reg & 0x14) == 0); + + // Set state of memory controller + reg = 0x112; + MCHBAR32(0x5030) = reg; + MCHBAR32(0x4ea0) = 0; + reg |= 2; //ddr reset + MCHBAR32(0x5030) = reg; + + // Assert dimm reset signal + reg = MCHBAR32(0x5030); + reg &= ~0x2; + MCHBAR32(0x5030) = reg; + + // Wait 200us + udelay(200); + + // Deassert dimm reset signal + MCHBAR32(0x5030) |= 2; + + // Wait 500us + udelay(500); + + // Enable DCLK + MCHBAR32(0x5030) |= 4; + + // XXX Wait 20ns + udelay(1); + + FOR_ALL_CHANNELS { + // Set valid rank CKE + reg = 0; + reg = (reg & ~0xf) | ctrl->rankmap[channel]; + addr = 0x400 * channel + 0x42a0; + MCHBAR32(addr) = reg; + + // Wait 10ns for ranks to settle + //udelay(0.01); + + reg = (reg & ~0xf0) | (ctrl->rankmap[channel] << 4); + MCHBAR32(addr) = reg; + + // Write reset using a NOP + write_reset(ctrl); + } +} + +static odtmap get_ODT(ramctr_timing * ctrl, u8 rank) +{ + /* Get ODT based on rankmap: */ + int dimms_per_ch = 0; + int channel; + + FOR_ALL_CHANNELS { + dimms_per_ch = max ((ctrl->rankmap[channel] & 1) + + ((ctrl->rankmap[channel] >> 2) & 1), + dimms_per_ch); + } + + if (dimms_per_ch == 1) { + return (const odtmap){60, 60}; + } else if (dimms_per_ch == 2) { + return (const odtmap){120, 30}; + } else { + printk(BIOS_DEBUG, + "Huh, no dimms? m0 = %d m1 = %d dpc = %d\n", + ctrl->rankmap[0], + ctrl->rankmap[1], dimms_per_ch); + die(""); + } +} + +static void write_mrreg(ramctr_timing * ctrl, int channel, int slotrank, + int reg, u32 val) +{ + wait_428c(channel); + + printk(BIOS_SPEW, "MRd: %x <= %x\n", reg, val); + + if (ctrl->rank_mirror[channel][slotrank]) { + reg = ((reg >> 1) & 1) | ((reg << 1) & 2); + val = (val & ~0x1f8) | ((val >> 1) & 0xa8) + | ((val & 0xa8) << 1); + } + + printk(BIOS_SPEW, "MRd: %x <= %x\n", reg, val); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x0f000); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0x41001); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | (reg << 20) | val | 0x60000); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f000); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, 0x41001); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24) | (reg << 20) | val | 0x60000); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, 0x0f000); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, + 0x1001 | (ctrl->tMOD << 16)); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, + (slotrank << 24) | (reg << 20) | val | 0x60000); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, 0); + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0x80001); +} + +static u32 make_mr0(ramctr_timing * ctrl, u8 rank) +{ + u16 mr0reg, mch_cas, mch_wr; + static const u8 mch_wr_t[12] = { 1, 2, 3, 4, 0, 5, 0, 6, 0, 7, 0, 0 }; + mr0reg = 0x100; + + // Convert CAS to MCH register friendly + if (ctrl->CAS < 12) { + mch_cas = (u16) ((ctrl->CAS - 4) << 1); + } else { + mch_cas = (u16) (ctrl->CAS - 12); + mch_cas = ((mch_cas << 1) | 0x1); + } + + // Convert tWR to MCH register friendly + mch_wr = mch_wr_t[ctrl->tWR - 5]; + + mr0reg = (mr0reg & ~0x4) | (mch_cas & 0x1); + mr0reg = (mr0reg & ~0x70) | ((mch_cas & 0xe) << 3); + mr0reg = (mr0reg & ~0xe00) | (mch_wr << 9); + // Fast (desktop) 0x1 or slow (mobile) 0x0 + mr0reg = (mr0reg & ~0x1000) | (!ctrl->mobile << 12); + return mr0reg; +} + +static void dram_mr0(ramctr_timing * ctrl, u8 rank) +{ + int channel; + + FOR_ALL_POPULATED_CHANNELS write_mrreg(ctrl, channel, rank, 0, + make_mr0(ctrl, rank)); +} + +static u32 encode_odt(u32 odt) +{ + switch (odt) { + case 30: + return (1 << 9) | (1 << 2); // RZQ/8, RZQ/4 + case 60: + return (1 << 2); // RZQ/4 + case 120: + return (1 << 6); // RZQ/2 + default: + case 0: + return 0; + } +} + +static u32 make_mr1(ramctr_timing * ctrl, u8 rank) +{ + odtmap odt; + u32 mr1reg; + + odt = get_ODT(ctrl, rank); + mr1reg = 0x2; + + mr1reg |= encode_odt(odt.rttnom); + + return mr1reg; +} + +static void dram_mr1(ramctr_timing * ctrl, u8 rank) +{ + u16 mr1reg; + int channel; + + mr1reg = make_mr1(ctrl, rank); + + FOR_ALL_CHANNELS { + write_mrreg(ctrl, channel, rank, 1, mr1reg); + } +} + +static void dram_mr2(ramctr_timing * ctrl, u8 rank) +{ + u16 pasr, cwl, mr2reg; + odtmap odt; + int channel; + int srt; + + pasr = 0; + cwl = ctrl->CWL - 5; + odt = get_ODT(ctrl, rank); + + srt = ctrl->extended_temperature_range && !ctrl->auto_self_refresh; + + mr2reg = 0; + mr2reg = (mr2reg & ~0x7) | pasr; + mr2reg = (mr2reg & ~0x38) | (cwl << 3); + mr2reg = (mr2reg & ~0x40) | (ctrl->auto_self_refresh << 6); + mr2reg = (mr2reg & ~0x80) | (srt << 7); + mr2reg |= (odt.rttwr / 60) << 9; + + FOR_ALL_CHANNELS { + write_mrreg(ctrl, channel, rank, 2, mr2reg); + } +} + +static void dram_mr3(ramctr_timing * ctrl, u8 rank) +{ + int channel; + + FOR_ALL_CHANNELS { + write_mrreg(ctrl, channel, rank, 3, 0); + } +} + +static void dram_mrscommands(ramctr_timing * ctrl) +{ + u8 rank; + u32 reg, addr; + int channel; + + for (rank = 0; rank < 4; rank++) { + // MR2 + printk(BIOS_SPEW, "MR2 rank %d...", rank); + dram_mr2(ctrl, rank); + printk(BIOS_SPEW, "done\n"); + + // MR3 + printk(BIOS_SPEW, "MR3 rank %d...", rank); + dram_mr3(ctrl, rank); + printk(BIOS_SPEW, "done\n"); + + // MR1 + printk(BIOS_SPEW, "MR1 rank %d...", rank); + dram_mr1(ctrl, rank); + printk(BIOS_SPEW, "done\n"); + + // MR0 + printk(BIOS_SPEW, "MR0 rank %d...", rank); + dram_mr0(ctrl, rank); + printk(BIOS_SPEW, "done\n"); + } + + write32(DEFAULT_MCHBAR + 0x4e20, 0x7); + write32(DEFAULT_MCHBAR + 0x4e30, 0xf1001); + write32(DEFAULT_MCHBAR + 0x4e00, 0x60002); + write32(DEFAULT_MCHBAR + 0x4e10, 0); + write32(DEFAULT_MCHBAR + 0x4e24, 0x1f003); + write32(DEFAULT_MCHBAR + 0x4e34, 0x1901001); + write32(DEFAULT_MCHBAR + 0x4e04, 0x60400); + write32(DEFAULT_MCHBAR + 0x4e14, 0x288); + write32(DEFAULT_MCHBAR + 0x4e84, 0x40004); + + // Drain + FOR_ALL_CHANNELS { + // Wait for ref drained + wait_428c(channel); + } + + // Refresh enable + MCHBAR32(0x5030) |= 8; + + FOR_ALL_POPULATED_CHANNELS { + addr = 0x400 * channel + 0x4020; + reg = MCHBAR32(addr); + reg &= ~0x200000; + MCHBAR32(addr) = reg; + + wait_428c(channel); + + rank = (ctrl->rankmap[channel] & 1) ? 0 : 2; + + // Drain + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x0f003); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0x659001); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (rank << 24) | 0x60000); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0x3e0); + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0x1); + + // Drain + wait_428c(channel); + } +} + +const u32 lane_registers[] = { + 0x0000, 0x0200, 0x0400, 0x0600, + 0x1000, 0x1200, 0x1400, 0x1600, + 0x0800 +}; + +static void program_timings(ramctr_timing * ctrl, int channel) +{ + u32 reg32, reg_4024, reg_c14, reg_c18, reg_4028; + int lane; + int slotrank, slot; + int full_shift = 0; + u16 slot320c[NUM_SLOTS]; + + FOR_ALL_POPULATED_RANKS { + if (full_shift < -ctrl->timings[channel][slotrank].val_320c) + full_shift = -ctrl->timings[channel][slotrank].val_320c; + } + + for (slot = 0; slot < NUM_SLOTS; slot++) + switch ((ctrl->rankmap[channel] >> (2 * slot)) & 3) { + case 0: + default: + slot320c[slot] = 0x7f; + break; + case 1: + slot320c[slot] = + ctrl->timings[channel][2 * slot + 0].val_320c + + full_shift; + break; + case 2: + slot320c[slot] = + ctrl->timings[channel][2 * slot + 1].val_320c + + full_shift; + break; + case 3: + slot320c[slot] = + (ctrl->timings[channel][2 * slot].val_320c + + ctrl->timings[channel][2 * slot + + 1].val_320c) / 2 + + full_shift; + break; + } + + reg32 = (1 << 17) | (1 << 14); + reg32 |= ((slot320c[0] & 0x3f) << 6) | ((slot320c[0] & 0x40) << 9); + reg32 |= (slot320c[1] & 0x7f) << 18; + reg32 |= (full_shift & 0x3f) | ((full_shift & 0x40) << 6); + + MCHBAR32(0x320c + 0x100 * channel) = reg32; + + reg_c14 = ctrl->rankmap[channel] << 24; + reg_c18 = 0; + + FOR_ALL_POPULATED_RANKS { + int shift = + ctrl->timings[channel][slotrank].val_320c + full_shift; + int offset_val_c14; + if (shift < 0) + shift = 0; + offset_val_c14 = ctrl->reg_c14_offset + shift; + reg_c14 |= (offset_val_c14 & 0x3f) << (6 * slotrank); + reg_c18 |= ((offset_val_c14 >> 6) & 1) << slotrank; + } + + MCHBAR32(0xc14 + channel * 0x100) = reg_c14; + MCHBAR32(0xc18 + channel * 0x100) = reg_c18; + + reg_4028 = MCHBAR32(0x4028 + 0x400 * channel); + reg_4028 &= 0xffff0000; + + reg_4024 = 0; + + FOR_ALL_POPULATED_RANKS { + int post_timA_min_high = 7, post_timA_max_high = 0; + int pre_timA_min_high = 7, pre_timA_max_high = 0; + int shift_402x = 0; + int shift = + ctrl->timings[channel][slotrank].val_320c + full_shift; + + if (shift < 0) + shift = 0; + + FOR_ALL_LANES { + if (post_timA_min_high > + ((ctrl->timings[channel][slotrank].lanes[lane]. + timA + shift) >> 6)) + post_timA_min_high = + ((ctrl->timings[channel][slotrank]. + lanes[lane].timA + shift) >> 6); + if (pre_timA_min_high > + (ctrl->timings[channel][slotrank].lanes[lane]. + timA >> 6)) + pre_timA_min_high = + (ctrl->timings[channel][slotrank]. + lanes[lane].timA >> 6); + if (post_timA_max_high < + ((ctrl->timings[channel][slotrank].lanes[lane]. + timA + shift) >> 6)) + post_timA_max_high = + ((ctrl->timings[channel][slotrank]. + lanes[lane].timA + shift) >> 6); + if (pre_timA_max_high < + (ctrl->timings[channel][slotrank].lanes[lane]. + timA >> 6)) + pre_timA_max_high = + (ctrl->timings[channel][slotrank]. + lanes[lane].timA >> 6); + } + + if (pre_timA_max_high - pre_timA_min_high < + post_timA_max_high - post_timA_min_high) + shift_402x = +1; + else if (pre_timA_max_high - pre_timA_min_high > + post_timA_max_high - post_timA_min_high) + shift_402x = -1; + + reg_4028 |= + (ctrl->timings[channel][slotrank].val_4028 + shift_402x - + post_timA_min_high) << (4 * slotrank); + reg_4024 |= + (ctrl->timings[channel][slotrank].val_4024 + + shift_402x) << (8 * slotrank); + + FOR_ALL_LANES { + MCHBAR32(lane_registers[lane] + 0x10 + 0x100 * channel + + 4 * slotrank) + = + (((ctrl->timings[channel][slotrank].lanes[lane]. + timA + shift) & 0x3f) + | + ((ctrl->timings[channel][slotrank].lanes[lane]. + rising + shift) << 8) + | + (((ctrl->timings[channel][slotrank].lanes[lane]. + timA + shift - + (post_timA_min_high << 6)) & 0x1c0) << 10) + | (ctrl->timings[channel][slotrank].lanes[lane]. + falling << 20)); + + MCHBAR32(lane_registers[lane] + 0x20 + 0x100 * channel + + 4 * slotrank) + = + (((ctrl->timings[channel][slotrank].lanes[lane]. + timC + shift) & 0x3f) + | + (((ctrl->timings[channel][slotrank].lanes[lane]. + timB + shift) & 0x3f) << 8) + | + (((ctrl->timings[channel][slotrank].lanes[lane]. + timB + shift) & 0x1c0) << 9) + | + (((ctrl->timings[channel][slotrank].lanes[lane]. + timC + shift) & 0x40) << 13)); + } + } + MCHBAR32(0x4024 + 0x400 * channel) = reg_4024; + MCHBAR32(0x4028 + 0x400 * channel) = reg_4028; +} + +static void test_timA(ramctr_timing * ctrl, int channel, int slotrank) +{ + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f000); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + (0xc01 | (ctrl->tMOD << 16))); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x360004); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f105); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, 0x4040c01); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, (slotrank << 24)); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, 0x1f105); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, + 0x100f | ((ctrl->CAS + 36) << 16)); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, + (slotrank << 24) | 0x60000); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x422c + 0x400 * channel, 0x1f000); + write32(DEFAULT_MCHBAR + 0x423c + 0x400 * channel, + (0xc01 | (ctrl->tMOD << 16))); + write32(DEFAULT_MCHBAR + 0x420c + 0x400 * channel, + (slotrank << 24) | 0x360000); + write32(DEFAULT_MCHBAR + 0x421c + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0xc0001); + + wait_428c(channel); +} + +static int does_lane_work(ramctr_timing * ctrl, int channel, int slotrank, + int lane) +{ + u32 timA = ctrl->timings[channel][slotrank].lanes[lane].timA; + return ((read32 + (DEFAULT_MCHBAR + lane_registers[lane] + channel * 0x100 + 4 + + ((timA / 32) & 1) * 4) + >> (timA % 32)) & 1); +} + +struct run { + int middle; + int end; + int start; + int all; + int length; +}; + +static struct run get_longest_zero_run(int *seq, int sz) +{ + int i, ls; + int bl = 0, bs = 0; + struct run ret; + + ls = 0; + for (i = 0; i < 2 * sz; i++) + if (seq[i % sz]) { + if (i - ls > bl) { + bl = i - ls; + bs = ls; + } + ls = i + 1; + } + if (bl == 0) { + ret.middle = sz / 2; + ret.start = 0; + ret.end = sz; + ret.all = 1; + return ret; + } + + ret.start = bs % sz; + ret.end = (bs + bl - 1) % sz; + ret.middle = (bs + (bl - 1) / 2) % sz; + ret.length = bl; + ret.all = 0; + + return ret; +} + +static void discover_timA_coarse(ramctr_timing * ctrl, int channel, + int slotrank, int *upperA) +{ + int timA; + int statistics[NUM_LANES][128]; + int lane; + + for (timA = 0; timA < 128; timA++) { + FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane].timA = timA; + } + program_timings(ctrl, channel); + + test_timA(ctrl, channel, slotrank); + + FOR_ALL_LANES { + statistics[lane][timA] = + !does_lane_work(ctrl, channel, slotrank, lane); + printk(BIOS_SPEW, "Astat: %d, %d, %d, %x, %x\n", + channel, slotrank, lane, timA, + statistics[lane][timA]); + } + } + FOR_ALL_LANES { + struct run rn = get_longest_zero_run(statistics[lane], 128); + ctrl->timings[channel][slotrank].lanes[lane].timA = rn.middle; + upperA[lane] = rn.end; + if (upperA[lane] < rn.middle) + upperA[lane] += 128; + printk(BIOS_SPEW, "Aval: %d, %d, %d, %x\n", channel, slotrank, + lane, ctrl->timings[channel][slotrank].lanes[lane].timA); + printk(BIOS_SPEW, "Aend: %d, %d, %d, %x\n", channel, slotrank, + lane, upperA[lane]); + } +} + +static void discover_timA_fine(ramctr_timing * ctrl, int channel, int slotrank, + int *upperA) +{ + int timA_delta; + int statistics[NUM_LANES][51]; + int lane, i; + + memset(statistics, 0, sizeof(statistics)); + + for (timA_delta = -25; timA_delta <= 25; timA_delta++) { + FOR_ALL_LANES ctrl->timings[channel][slotrank].lanes[lane]. + timA = upperA[lane] + timA_delta + 0x40; + program_timings(ctrl, channel); + + for (i = 0; i < 100; i++) { + test_timA(ctrl, channel, slotrank); + FOR_ALL_LANES { + statistics[lane][timA_delta + 25] += + does_lane_work(ctrl, channel, slotrank, + lane); + } + } + } + FOR_ALL_LANES { + int last_zero, first_all; + + for (last_zero = -25; last_zero <= 25; last_zero++) + if (statistics[lane][last_zero + 25]) + break; + last_zero--; + for (first_all = -25; first_all <= 25; first_all++) + if (statistics[lane][first_all + 25] == 100) + break; + + printk(BIOS_SPEW, "lane %d: %d, %d\n", lane, last_zero, + first_all); + + ctrl->timings[channel][slotrank].lanes[lane].timA = + (last_zero + first_all) / 2 + upperA[lane]; + printk(BIOS_SPEW, "Aval: %d, %d, %d, %x\n", channel, slotrank, + lane, ctrl->timings[channel][slotrank].lanes[lane].timA); + } +} + +static void discover_402x(ramctr_timing * ctrl, int channel, int slotrank, + int *upperA) +{ + int works[NUM_LANES]; + int lane; + while (1) { + int all_works = 1, some_works = 0; + program_timings(ctrl, channel); + test_timA(ctrl, channel, slotrank); + FOR_ALL_LANES { + works[lane] = + !does_lane_work(ctrl, channel, slotrank, lane); + if (works[lane]) + some_works = 1; + else + all_works = 0; + } + if (all_works) + return; + if (!some_works) { + if (ctrl->timings[channel][slotrank].val_4024 < 2) + die("402x discovery failed"); + ctrl->timings[channel][slotrank].val_4024 -= 2; + printk(BIOS_SPEW, "4024 -= 2;\n"); + continue; + } + ctrl->timings[channel][slotrank].val_4028 += 2; + printk(BIOS_SPEW, "4028 += 2;\n"); + if (ctrl->timings[channel][slotrank].val_4028 >= 0x10) + die("402x discovery failed"); + FOR_ALL_LANES if (works[lane]) { + ctrl->timings[channel][slotrank].lanes[lane].timA += + 128; + upperA[lane] += 128; + printk(BIOS_SPEW, "increment %d, %d, %d\n", channel, + slotrank, lane); + } + } +} + +struct timA_minmax { + int timA_min_high, timA_max_high; +}; + +static void pre_timA_change(ramctr_timing * ctrl, int channel, int slotrank, + struct timA_minmax *mnmx) +{ + int lane; + mnmx->timA_min_high = 7; + mnmx->timA_max_high = 0; + + FOR_ALL_LANES { + if (mnmx->timA_min_high > + (ctrl->timings[channel][slotrank].lanes[lane].timA >> 6)) + mnmx->timA_min_high = + (ctrl->timings[channel][slotrank].lanes[lane]. + timA >> 6); + if (mnmx->timA_max_high < + (ctrl->timings[channel][slotrank].lanes[lane].timA >> 6)) + mnmx->timA_max_high = + (ctrl->timings[channel][slotrank].lanes[lane]. + timA >> 6); + } +} + +static void post_timA_change(ramctr_timing * ctrl, int channel, int slotrank, + struct timA_minmax *mnmx) +{ + struct timA_minmax post; + int shift_402x = 0; + + /* Get changed maxima. */ + pre_timA_change(ctrl, channel, slotrank, &post); + + if (mnmx->timA_max_high - mnmx->timA_min_high < + post.timA_max_high - post.timA_min_high) + shift_402x = +1; + else if (mnmx->timA_max_high - mnmx->timA_min_high > + post.timA_max_high - post.timA_min_high) + shift_402x = -1; + else + shift_402x = 0; + + ctrl->timings[channel][slotrank].val_4028 += shift_402x; + ctrl->timings[channel][slotrank].val_4024 += shift_402x; + printk(BIOS_SPEW, "4024 += %d;\n", shift_402x); + printk(BIOS_SPEW, "4028 += %d;\n", shift_402x); +} + +static void read_training(ramctr_timing * ctrl) +{ + int channel, slotrank, lane; + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS { + u32 r32; + int all_high, some_high; + int upperA[NUM_LANES]; + struct timA_minmax mnmx; + + wait_428c(channel); + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f002); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + 0xc01 | (ctrl->tRP << 16)); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x60400); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0); + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 1); + + write32(DEFAULT_MCHBAR + 0x3400, (slotrank << 2) | 0x8001); + + ctrl->timings[channel][slotrank].val_4028 = 4; + ctrl->timings[channel][slotrank].val_4024 = 55; + program_timings(ctrl, channel); + + discover_timA_coarse(ctrl, channel, slotrank, upperA); + + all_high = 1; + some_high = 0; + FOR_ALL_LANES { + if (ctrl->timings[channel][slotrank].lanes[lane]. + timA >= 0x40) + some_high = 1; + else + all_high = 0; + } + + if (all_high) { + ctrl->timings[channel][slotrank].val_4028--; + printk(BIOS_SPEW, "4028--;\n"); + FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane]. + timA -= 0x40; + upperA[lane] -= 0x40; + + } + } else if (some_high) { + ctrl->timings[channel][slotrank].val_4024++; + ctrl->timings[channel][slotrank].val_4028++; + printk(BIOS_SPEW, "4024++;\n"); + printk(BIOS_SPEW, "4028++;\n"); + } + + program_timings(ctrl, channel); + + pre_timA_change(ctrl, channel, slotrank, &mnmx); + + discover_402x(ctrl, channel, slotrank, upperA); + + post_timA_change(ctrl, channel, slotrank, &mnmx); + pre_timA_change(ctrl, channel, slotrank, &mnmx); + + discover_timA_fine(ctrl, channel, slotrank, upperA); + + post_timA_change(ctrl, channel, slotrank, &mnmx); + pre_timA_change(ctrl, channel, slotrank, &mnmx); + + FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane].timA -= mnmx.timA_min_high * 0x40; + } + ctrl->timings[channel][slotrank].val_4028 -= mnmx.timA_min_high; + printk(BIOS_SPEW, "4028 -= %d;\n", mnmx.timA_min_high); + + post_timA_change(ctrl, channel, slotrank, &mnmx); + + printk(BIOS_SPEW, "4/8: %d, %d, %x, %x\n", channel, slotrank, + ctrl->timings[channel][slotrank].val_4024, + ctrl->timings[channel][slotrank].val_4028); + + FOR_ALL_LANES + printk(BIOS_SPEW, "%d, %d, %d, %x\n", channel, slotrank, + lane, + ctrl->timings[channel][slotrank].lanes[lane].timA); + + write32(DEFAULT_MCHBAR + 0x3400, 0); + + r32 = read32(DEFAULT_MCHBAR + 0x5030); + write32(DEFAULT_MCHBAR + 0x5030, r32 | 0x20); + udelay(1); + + write32(DEFAULT_MCHBAR + 0x5030, r32 & ~0x20); + + udelay(1); + } + + FOR_ALL_POPULATED_CHANNELS { + program_timings(ctrl, channel); + } + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + write32(DEFAULT_MCHBAR + 0x4080 + 0x400 * channel + + 4 * lane, 0); + } +} + +static void test_timC(ramctr_timing * ctrl, int channel, int slotrank) +{ + int lane; + + FOR_ALL_LANES { + write32(DEFAULT_MCHBAR + 0x4340 + 0x400 * channel + 4 * lane, 0); + read32(DEFAULT_MCHBAR + 0x4140 + 0x400 * channel + 4 * lane); + } + + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f006); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + (max((ctrl->tFAW >> 2) + 1, ctrl->tRRD) << 10) + | 4 | (ctrl->tRCD << 16)); + + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | (6 << 16)); + + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0x244); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f207); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, 0x8041001); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24) | 8); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0x3e0); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, 0x1f201); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, 0x80411f4); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, (slotrank << 24)); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, 0x242); + + write32(DEFAULT_MCHBAR + 0x422c + 0x400 * channel, 0x1f207); + write32(DEFAULT_MCHBAR + 0x423c + 0x400 * channel, + 0x8000c01 | ((ctrl->CWL + ctrl->tWTR + 5) << 16)); + write32(DEFAULT_MCHBAR + 0x420c + 0x400 * channel, + (slotrank << 24) | 8); + write32(DEFAULT_MCHBAR + 0x421c + 0x400 * channel, 0x3e0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0xc0001); + + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f002); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + 0xc01 | (ctrl->tRP << 16)); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x60400); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0x240); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f006); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, + (max(ctrl->tRRD, (ctrl->tFAW >> 2) + 1) << 10) + | 8 | (ctrl->CAS << 16)); + + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24) | 0x60000); + + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0x244); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, 0x1f105); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, + 0x40011f4 | (max(ctrl->tRTP, 8) << 16)); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, (slotrank << 24)); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, 0x242); + + write32(DEFAULT_MCHBAR + 0x422c + 0x400 * channel, 0x1f002); + write32(DEFAULT_MCHBAR + 0x423c + 0x400 * channel, + 0xc01 | (ctrl->tRP << 16)); + write32(DEFAULT_MCHBAR + 0x420c + 0x400 * channel, + (slotrank << 24) | 0x60400); + write32(DEFAULT_MCHBAR + 0x421c + 0x400 * channel, 0x240); + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0xc0001); + wait_428c(channel); +} + +static void discover_timC(ramctr_timing * ctrl, int channel, int slotrank) +{ + int timC; + int statistics[NUM_LANES][MAX_TIMC + 1]; + int lane; + + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f002); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + 0xc01 | (ctrl->tRP << 16)); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x60400); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0x240); + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 1); + + for (timC = 0; timC <= MAX_TIMC; timC++) { + FOR_ALL_LANES ctrl->timings[channel][slotrank].lanes[lane]. + timC = timC; + program_timings(ctrl, channel); + + test_timC(ctrl, channel, slotrank); + + FOR_ALL_LANES { + statistics[lane][timC] = + read32(DEFAULT_MCHBAR + 0x4340 + 4 * lane + + 0x400 * channel); + printk(BIOS_SPEW, "Cstat: %d, %d, %d, %x, %x\n", + channel, slotrank, lane, timC, + statistics[lane][timC]); + } + } + FOR_ALL_LANES { + struct run rn = + get_longest_zero_run(statistics[lane], MAX_TIMC + 1); + ctrl->timings[channel][slotrank].lanes[lane].timC = rn.middle; + if (rn.all) + die("timC discovery failed"); + printk(BIOS_SPEW, "Cval: %d, %d, %d, %x\n", channel, slotrank, + lane, ctrl->timings[channel][slotrank].lanes[lane].timC); + } +} + +static int get_precedening_channels(ramctr_timing * ctrl, int target_channel) +{ + int channel, ret = 0; + FOR_ALL_POPULATED_CHANNELS if (channel < target_channel) + ret++; + return ret; +} + +static void fill_pattern0(ramctr_timing * ctrl, int channel, u32 a, u32 b) +{ + unsigned j; + unsigned channel_offset = + get_precedening_channels(ctrl, channel) * 0x40; + printk(BIOS_SPEW, "channel_offset=%x\n", channel_offset); + for (j = 0; j < 16; j++) + write32(0x04000000 + channel_offset + 4 * j, j & 2 ? b : a); + sfence(); +} + +static int num_of_channels(const ramctr_timing * ctrl) +{ + int ret = 0; + int channel; + FOR_ALL_POPULATED_CHANNELS ret++; + return ret; +} + +static void fill_pattern1(ramctr_timing * ctrl, int channel) +{ + unsigned j; + unsigned channel_offset = + get_precedening_channels(ctrl, channel) * 0x40; + unsigned channel_step = 0x40 * num_of_channels(ctrl); + for (j = 0; j < 16; j++) + write32(0x04000000 + channel_offset + j * 4, 0xffffffff); + for (j = 0; j < 16; j++) + write32(0x04000000 + channel_offset + channel_step + j * 4, 0); + sfence(); +} + +static void precharge(ramctr_timing * ctrl) +{ + int channel, slotrank, lane; + + FOR_ALL_POPULATED_CHANNELS { + FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane].falling = + 16; + ctrl->timings[channel][slotrank].lanes[lane].rising = + 16; + } program_timings(ctrl, channel); + + FOR_ALL_POPULATED_RANKS { + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, + 0x1f000); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + 0xc01 | (ctrl->tMOD << 16)); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x360004); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, + 0x1f105); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, + 0x4041003); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24) | 0); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, + 0x1f105); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, + 0x1001 | ((ctrl->CAS + 8) << 16)); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, + (slotrank << 24) | 0x60000); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x422c + 0x400 * channel, + 0x1f000); + write32(DEFAULT_MCHBAR + 0x423c + 0x400 * channel, + 0xc01 | (ctrl->tMOD << 16)); + write32(DEFAULT_MCHBAR + 0x420c + 0x400 * channel, + (slotrank << 24) | 0x360000); + write32(DEFAULT_MCHBAR + 0x421c + 0x400 * channel, 0); + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, + 0xc0001); + + wait_428c(channel); + } + + FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane].falling = + 48; + ctrl->timings[channel][slotrank].lanes[lane].rising = + 48; + } + + program_timings(ctrl, channel); + + FOR_ALL_POPULATED_RANKS { + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, + 0x1f000); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + 0xc01 | (ctrl->tMOD << 16)); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x360004); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, + 0x1f105); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, + 0x4041003); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24) | 0); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, + 0x1f105); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, + 0x1001 | ((ctrl->CAS + 8) << 16)); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, + (slotrank << 24) | 0x60000); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x422c + 0x400 * channel, + 0x1f000); + write32(DEFAULT_MCHBAR + 0x423c + 0x400 * channel, + 0xc01 | (ctrl->tMOD << 16)); + + write32(DEFAULT_MCHBAR + 0x420c + 0x400 * channel, + (slotrank << 24) | 0x360000); + write32(DEFAULT_MCHBAR + 0x421c + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, + 0xc0001); + wait_428c(channel); + } + } +} + +static void test_timB(ramctr_timing * ctrl, int channel, int slotrank) +{ + write_mrreg(ctrl, channel, slotrank, 1, + 0x80 | make_mr1(ctrl, slotrank)); + + wait_428c(channel); + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f207); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + 0x8000c01 | ((ctrl->CWL + ctrl->tWLO) << 16)); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + 8 | (slotrank << 24)); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f107); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, + 0x4000c01 | ((ctrl->CAS + 38) << 16)); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24) | 4); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x400 * channel + 0x4284, 0x40001); + wait_428c(channel); + + write_mrreg(ctrl, channel, slotrank, 1, + 0x1080 | make_mr1(ctrl, slotrank)); +} + +static void discover_timB(ramctr_timing * ctrl, int channel, int slotrank) +{ + int timB; + int statistics[NUM_LANES][128]; + int lane; + + write32(DEFAULT_MCHBAR + 0x3400, 0x108052 | (slotrank << 2)); + + for (timB = 0; timB < 128; timB++) { + FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane].timB = timB; + } + program_timings(ctrl, channel); + + test_timB(ctrl, channel, slotrank); + + FOR_ALL_LANES { + statistics[lane][timB] = + !((read32 + (DEFAULT_MCHBAR + lane_registers[lane] + + channel * 0x100 + 4 + ((timB / 32) & 1) * 4) + >> (timB % 32)) & 1); + printk(BIOS_SPEW, "Bstat: %d, %d, %d, %x, %x\n", + channel, slotrank, lane, timB, + statistics[lane][timB]); + } + } + FOR_ALL_LANES { + struct run rn = get_longest_zero_run(statistics[lane], 128); + ctrl->timings[channel][slotrank].lanes[lane].timB = rn.start; + if (rn.all) + die("timB discovery failed"); + printk(BIOS_SPEW, "Bval: %d, %d, %d, %x\n", channel, slotrank, + lane, ctrl->timings[channel][slotrank].lanes[lane].timB); + } +} + +static int get_timB_high_adjust(u64 val) +{ + int i; + if (val >= 0xfffffffffffff000LL) + return 3; + if (val >= 0xfffffffffff00000LL) + return -1; + if (val >= 0xfffffff000000000LL) + return -2; + if (val >= 0xfff0000000000000LL) + return -3; + + for (i = 0; i < 8; i++) + if (val >> (8 * (7 - i) + 4)) + return i; + return 8; +} + +static void adjust_high_timB(ramctr_timing * ctrl) +{ + int channel, slotrank, lane; + write32(DEFAULT_MCHBAR + 0x3400, 0x200); + FOR_ALL_POPULATED_CHANNELS { + fill_pattern1(ctrl, channel); + write32(DEFAULT_MCHBAR | 0x4288 | (channel << 10), 1); + } + FOR_ALL_POPULATED_CHANNELS FOR_ALL_POPULATED_RANKS { + + write32(DEFAULT_MCHBAR + 0x4288 + 0x400 * channel, 0x10001); + + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f006); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + 0xc01 | (ctrl->tRCD << 16)); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x60000); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f207); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, 0x8040c01); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24) | 0x8); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0x3e0); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, 0x1f201); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, 0x8041003); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, + (slotrank << 24)); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, 0x3e2); + + write32(DEFAULT_MCHBAR + 0x422c + 0x400 * channel, 0x1f207); + write32(DEFAULT_MCHBAR + 0x423c + 0x400 * channel, + 0x8000c01 | ((ctrl->CWL + ctrl->tWTR + 5) << 16)); + write32(DEFAULT_MCHBAR + 0x420c + 0x400 * channel, + (slotrank << 24) | 0x8); + write32(DEFAULT_MCHBAR + 0x421c + 0x400 * channel, 0x3e0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0xc0001); + + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f002); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + 0xc01 | ((ctrl->tRP) << 16)); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x60400); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0x240); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f006); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, + 0xc01 | ((ctrl->tRCD) << 16)); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24) | 0x60000); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, 0x3f105); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, + 0x4000c01 | + ((ctrl->tRP + + ctrl->timings[channel][slotrank].val_4024 + + ctrl->timings[channel][slotrank].val_4028) << 16)); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, + (slotrank << 24) | 0x60008); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0x80001); + wait_428c(channel); + FOR_ALL_LANES { + u64 res = + read32(DEFAULT_MCHBAR + lane_registers[lane] + + 0x100 * channel + 4); + res |= + ((u64) read32(DEFAULT_MCHBAR + lane_registers[lane] + + 0x100 * channel + 8)) << 32; + ctrl->timings[channel][slotrank].lanes[lane].timB += + get_timB_high_adjust(res) * 64; + + printk(BIOS_DEBUG, "High adjust %d:%016llx\n", lane, res); + printk(BIOS_SPEW, "Bval+: %d, %d, %d, %x\n", channel, + slotrank, lane, + ctrl->timings[channel][slotrank].lanes[lane]. + timB); + } + } + write32(DEFAULT_MCHBAR + 0x3400, 0); +} + +static void write_op(ramctr_timing * ctrl, int channel) +{ + int slotrank; + + wait_428c(channel); + + /* choose an existing rank. */ + slotrank = !(ctrl->rankmap[channel] & 1) ? 2 : 0; + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x0f003); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0x41001); + + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x60000); + + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0x3e0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 1); + wait_428c(channel); +} + +static void write_training(ramctr_timing * ctrl) +{ + int channel, slotrank, lane; + u32 r32; + + FOR_ALL_POPULATED_CHANNELS + write32(DEFAULT_MCHBAR + 0x4008 + 0x400 * channel, + read32(DEFAULT_MCHBAR + 0x4008 + + 0x400 * channel) | 0x8000000); + + FOR_ALL_POPULATED_CHANNELS { + write_op(ctrl, channel); + write32(DEFAULT_MCHBAR + 0x4020 + 0x400 * channel, + read32(DEFAULT_MCHBAR + 0x4020 + + 0x400 * channel) | 0x200000); + } + write32(DEFAULT_MCHBAR + 0x5030, read32(DEFAULT_MCHBAR + 0x5030) & ~8); + FOR_ALL_POPULATED_CHANNELS { + write_op(ctrl, channel); + } + + FOR_ALL_CHANNELS + FOR_ALL_POPULATED_RANKS + write_mrreg(ctrl, channel, slotrank, 1, + make_mr1(ctrl, slotrank) | 0x1080); + + write32(DEFAULT_MCHBAR + 0x3400, 0x108052); + + r32 = read32(DEFAULT_MCHBAR + 0x5030); + write32(DEFAULT_MCHBAR + 0x5030, r32 | 0x20); + udelay(1); + + write32(DEFAULT_MCHBAR + 0x5030, r32 & ~0x20); + + udelay(1); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS + discover_timB(ctrl, channel, slotrank); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS + write_mrreg(ctrl, channel, + slotrank, 1, make_mr1(ctrl, slotrank)); + + write32(DEFAULT_MCHBAR + 0x3400, 0); + + FOR_ALL_POPULATED_CHANNELS + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x5030, read32(DEFAULT_MCHBAR + 0x5030) | 8); + + FOR_ALL_POPULATED_CHANNELS { + write32(DEFAULT_MCHBAR + 0x4020 + 0x400 * channel, + ~0x00200000 & read32(DEFAULT_MCHBAR + 0x4020 + + 0x400 * channel)); + read32(DEFAULT_MCHBAR + 0x428c + 0x400 * channel); + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x0f003); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0x659001); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, 0x60000); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0x3e0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 1); + wait_428c(channel); + } + + r32 = read32(DEFAULT_MCHBAR + 0x5030); + write32(DEFAULT_MCHBAR + 0x5030, r32 | 0x20); + udelay(1); + + write32(DEFAULT_MCHBAR + 0x5030, r32 & ~0x20); + + udelay(1); + + printk(BIOS_SPEW, "CPE\n"); + precharge(ctrl); + printk(BIOS_SPEW, "CPF\n"); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + read32(DEFAULT_MCHBAR + 0x4080 + 0x400 * channel + 4 * lane); + write32(DEFAULT_MCHBAR + 0x4080 + 0x400 * channel + 4 * lane, + 0); + } + + FOR_ALL_POPULATED_CHANNELS { + fill_pattern0(ctrl, channel, 0xaaaaaaaa, 0x55555555); + write32(DEFAULT_MCHBAR | 0x4288 | (channel << 10), 0); + } + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS + discover_timC(ctrl, channel, slotrank); + + FOR_ALL_POPULATED_CHANNELS + program_timings(ctrl, channel); + + adjust_high_timB(ctrl); + + FOR_ALL_POPULATED_CHANNELS + program_timings(ctrl, channel); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + read32(DEFAULT_MCHBAR + 0x4080 + 0x400 * channel + 4 * lane); + write32(DEFAULT_MCHBAR + 0x4080 + 0x400 * channel + 4 * lane, + 0); + } +} + +static int test_320c(ramctr_timing * ctrl, int channel, int slotrank) +{ + struct ram_rank_timings saved_rt = ctrl->timings[channel][slotrank]; + int timC_delta; + int lanes_ok = 0; + int ctr = 0; + int lane; + + for (timC_delta = -5; timC_delta <= 5; timC_delta++) { + FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane].timC = + saved_rt.lanes[lane].timC + timC_delta; + } + program_timings(ctrl, channel); + FOR_ALL_LANES { + write32(DEFAULT_MCHBAR + 4 * lane + 0x4f40, 0); + } + + write32(DEFAULT_MCHBAR + 0x4288 + 0x400 * channel, 0x1f); + + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f006); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + ((max(ctrl->tRRD, (ctrl->tFAW >> 2) + 1)) << 10) + | 8 | (ctrl->tRCD << 16)); + + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | ctr | 0x60000); + + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0x244); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f201); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, + 0x8001020 | ((ctrl->CWL + ctrl->tWTR + 8) << 16)); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24)); + write32(DEFAULT_MCHBAR + 0x4244 + 0x400 * channel, 0x389abcd); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0x20e42); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, 0x1f105); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, + 0x4001020 | (max(ctrl->tRTP, 8) << 16)); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, + (slotrank << 24)); + write32(DEFAULT_MCHBAR + 0x4248 + 0x400 * channel, 0x389abcd); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, 0x20e42); + + write32(DEFAULT_MCHBAR + 0x422c + 0x400 * channel, 0x1f002); + write32(DEFAULT_MCHBAR + 0x423c + 0x400 * channel, 0xf1001); + write32(DEFAULT_MCHBAR + 0x420c + 0x400 * channel, + (slotrank << 24) | 0x60400); + write32(DEFAULT_MCHBAR + 0x421c + 0x400 * channel, 0x240); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0xc0001); + wait_428c(channel); + FOR_ALL_LANES { + u32 r32 = + read32(DEFAULT_MCHBAR + 0x4340 + 4 * lane + + 0x400 * channel); + + if (r32 == 0) + lanes_ok |= 1 << lane; + } + ctr++; + if (lanes_ok == ((1 << NUM_LANES) - 1)) + break; + } + + ctrl->timings[channel][slotrank] = saved_rt; + + printk(BIOS_SPEW, "3lanes: %x\n", lanes_ok); + return lanes_ok != ((1 << NUM_LANES) - 1); +} + +#include "raminit_patterns.h" + +static void fill_pattern5(ramctr_timing * ctrl, int channel, int patno) +{ + unsigned i, j; + unsigned channel_offset = + get_precedening_channels(ctrl, channel) * 0x40; + unsigned channel_step = 0x40 * num_of_channels(ctrl); + + if (patno) { + u8 base8 = 0x80 >> ((patno - 1) % 8); + u32 base = base8 | (base8 << 8) | (base8 << 16) | (base8 << 24); + for (i = 0; i < 32; i++) { + for (j = 0; j < 16; j++) { + u32 val = use_base[patno - 1][i] & (1 << (j / 2)) ? base : 0; + if (invert[patno - 1][i] & (1 << (j / 2))) + val = ~val; + write32(0x04000000 + channel_offset + i * channel_step + + j * 4, val); + } + } + + } else { + for (i = 0; i < sizeof(pattern) / sizeof(pattern[0]); i++) { + for (j = 0; j < 16; j++) + write32(0x04000000 + channel_offset + i * channel_step + + j * 4, pattern[i][j]); + } + sfence(); + } +} + +static void reprogram_320c(ramctr_timing * ctrl) +{ + int channel, slotrank; + u32 r32; + + FOR_ALL_POPULATED_CHANNELS { + wait_428c(channel); + + /* choose an existing rank. */ + slotrank = !(ctrl->rankmap[channel] & 1) ? 2 : 0; + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x0f003); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0x41001); + + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x60000); + + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0x3e0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 1); + wait_428c(channel); + write32(DEFAULT_MCHBAR + 0x4020 + 0x400 * channel, + read32(DEFAULT_MCHBAR + 0x4020 + + 0x400 * channel) | 0x200000); + } + write32(DEFAULT_MCHBAR + 0x5030, read32(DEFAULT_MCHBAR + 0x5030) & ~8); + FOR_ALL_POPULATED_CHANNELS { + wait_428c(channel); + + /* choose an existing rank. */ + slotrank = !(ctrl->rankmap[channel] & 1) ? 2 : 0; + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x0f003); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0x41001); + + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x60000); + + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0x3e0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 1); + wait_428c(channel); + } + + /* jedec reset */ + dram_jedecreset(ctrl); + /* mrs commands. */ + dram_mrscommands(ctrl); + + r32 = read32(DEFAULT_MCHBAR + 0x5030); + write32(DEFAULT_MCHBAR + 0x5030, r32 | 0x20); + udelay(1); + + write32(DEFAULT_MCHBAR + 0x5030, r32 & ~0x20); + + udelay(1); +} + +#define MIN_C320C_LEN 13 + +static int try_reg_4004_b30(ramctr_timing * ctrl, int r4004b30) +{ + struct ram_rank_timings saved_timings[NUM_CHANNELS][NUM_SLOTRANKS]; + int channel, slotrank; + int c320c; + int stat[NUM_SLOTRANKS][256]; + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS { + saved_timings[channel][slotrank] = ctrl->timings[channel][slotrank]; + } + + FOR_ALL_POPULATED_CHANNELS { + ctrl->reg_4004_b30[channel] = r4004b30; + } + + FOR_ALL_POPULATED_CHANNELS + MCHBAR32(0x4004 + 0x400 * channel) = + ctrl->tRRD + | (ctrl->tRTP << 4) + | (ctrl->tCKE << 8) + | (ctrl->tWTR << 12) + | (ctrl->tFAW << 16) + | (ctrl->tWR << 24) + | (ctrl->reg_4004_b30[channel] << 30); + + + FOR_ALL_CHANNELS { + int delta = 0; + if (ctrl->reg_4004_b30[channel] == 2) + delta = 2; + else if (ctrl->reg_4004_b30[channel] == 0) + delta = 4; + + FOR_ALL_POPULATED_RANKS { + ctrl->timings[channel][slotrank].val_4024 -= delta; + } + } + + FOR_ALL_POPULATED_CHANNELS { + for (c320c = -127; c320c <= 127; c320c++) { + FOR_ALL_POPULATED_RANKS { + ctrl->timings[channel][slotrank].val_320c = c320c; + } + program_timings(ctrl, channel); + reprogram_320c(ctrl); + FOR_ALL_POPULATED_RANKS { + stat[slotrank][c320c + 127] = + test_320c(ctrl, channel, slotrank); + printk(BIOS_SPEW, "3stat: %d, %d, %d: %d\n", + channel, slotrank, c320c, + stat[slotrank][c320c + 127]); + } + } + FOR_ALL_POPULATED_RANKS { + struct run rn = + get_longest_zero_run(stat[slotrank], 255); + ctrl->timings[channel][slotrank].val_320c = + rn.middle - 127; + printk(BIOS_SPEW, "3val: %d, %d: %d\n", channel, + slotrank, + ctrl->timings[channel][slotrank].val_320c); + if (rn.all || rn.length < MIN_C320C_LEN) { + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS { + ctrl->timings[channel][slotrank] = saved_timings[channel][slotrank]; + } + return 0; + } + } + } + return 1; +} + +static void command_training(ramctr_timing * ctrl) +{ + int channel; + + FOR_ALL_POPULATED_CHANNELS { + fill_pattern5(ctrl, channel, 0); + write32(DEFAULT_MCHBAR + 0x4288 + 0x400 * channel, 0x1f); + } + + if (!try_reg_4004_b30(ctrl, 0) && !try_reg_4004_b30(ctrl, 2)) + die("c320c discovery failed"); + + FOR_ALL_POPULATED_CHANNELS { + program_timings(ctrl, channel); + } + + reprogram_320c(ctrl); +} + +static void discover_edges_real(ramctr_timing * ctrl, int channel, int slotrank, + int *edges) +{ + int edge; + int statistics[NUM_LANES][MAX_EDGE_TIMING + 1]; + int lane; + + for (edge = 0; edge <= MAX_EDGE_TIMING; edge++) { + FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane].rising = + edge; + ctrl->timings[channel][slotrank].lanes[lane].falling = + edge; + } + printk(BIOS_SPEW, "edge %02x\n", edge); + program_timings(ctrl, channel); + + FOR_ALL_LANES { + write32(DEFAULT_MCHBAR + 0x4340 + 0x400 * channel + + 4 * lane, 0); + read32(DEFAULT_MCHBAR + 0x400 * channel + 4 * lane + + 0x4140); + } + + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f000); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + (0xc01 | (ctrl->tMOD << 16))); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x360004); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f105); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, 0x40411f4); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24)); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, 0x1f105); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, + 0x1001 | ((ctrl->CAS + 8) << 16)); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, + (slotrank << 24) | 0x60000); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x422c + 0x400 * channel, 0x1f000); + write32(DEFAULT_MCHBAR + 0x423c + 0x400 * channel, + (0xc01 | (ctrl->tMOD << 16))); + write32(DEFAULT_MCHBAR + 0x420c + 0x400 * channel, + (slotrank << 24) | 0x360000); + write32(DEFAULT_MCHBAR + 0x421c + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0xc0001); + + wait_428c(channel); + + FOR_ALL_LANES { + statistics[lane][edge] = + read32(DEFAULT_MCHBAR + 0x4340 + 0x400 * channel + + lane * 4); + } + } + FOR_ALL_LANES { + struct run rn = + get_longest_zero_run(statistics[lane], MAX_EDGE_TIMING + 1); + edges[lane] = rn.middle; + if (rn.all) + die("edge discovery failed"); + printk(BIOS_SPEW, "eval %d, %d, %d, %02x\n", channel, slotrank, + lane, edges[lane]); + } +} + +static void discover_edges(ramctr_timing * ctrl) +{ + int falling_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES]; + int rising_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES]; + int channel, slotrank, lane; + u32 r32; + + write32(DEFAULT_MCHBAR + 0x3400, 0); + + r32 = read32(DEFAULT_MCHBAR + 0x5030); + write32(DEFAULT_MCHBAR + 0x5030, r32 | 0x20); + udelay(1); + + write32(DEFAULT_MCHBAR + 0x5030, r32 & ~0x20); + + udelay(1); + + FOR_ALL_POPULATED_CHANNELS FOR_ALL_LANES { + write32(DEFAULT_MCHBAR + 4 * lane + + 0x400 * channel + 0x4080, 0); + } + + FOR_ALL_POPULATED_CHANNELS { + fill_pattern0(ctrl, channel, 0, 0); + write32(DEFAULT_MCHBAR | 0x4288 | (channel << 10), 0); + FOR_ALL_LANES { + read32(DEFAULT_MCHBAR + 0x400 * channel + + lane * 4 + 0x4140); + } + + FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane].falling = + 16; + ctrl->timings[channel][slotrank].lanes[lane].rising = + 16; + } + + program_timings(ctrl, channel); + + FOR_ALL_POPULATED_RANKS { + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, + 0x1f000); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + 0xc01 | (ctrl->tMOD << 16)); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x360004); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, + 0x1f105); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, + 0x4041003); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24) | 0); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, + 0x1f105); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, + 0x1001 | ((ctrl->CAS + 8) << 16)); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, + (slotrank << 24) | 0x60000); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x422c + 0x400 * channel, + 0x1f000); + write32(DEFAULT_MCHBAR + 0x423c + 0x400 * channel, + 0xc01 | (ctrl->tMOD << 16)); + write32(DEFAULT_MCHBAR + 0x420c + 0x400 * channel, + (slotrank << 24) | 0x360000); + write32(DEFAULT_MCHBAR + 0x421c + 0x400 * channel, 0); + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, + 0xc0001); + + wait_428c(channel); + } + + FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane].falling = + 48; + ctrl->timings[channel][slotrank].lanes[lane].rising = + 48; + } + + program_timings(ctrl, channel); + + FOR_ALL_POPULATED_RANKS { + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, + 0x1f000); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + 0xc01 | (ctrl->tMOD << 16)); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x360004); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, + 0x1f105); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, + 0x4041003); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24) | 0); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, + 0x1f105); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, + 0x1001 | ((ctrl->CAS + 8) << 16)); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, + (slotrank << 24) | 0x60000); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x422c + 0x400 * channel, + 0x1f000); + write32(DEFAULT_MCHBAR + 0x423c + 0x400 * channel, + 0xc01 | (ctrl->tMOD << 16)); + write32(DEFAULT_MCHBAR + 0x420c + 0x400 * channel, + (slotrank << 24) | 0x360000); + write32(DEFAULT_MCHBAR + 0x421c + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, + 0xc0001); + wait_428c(channel); + } + + FOR_ALL_LANES { + write32(DEFAULT_MCHBAR + 0x4080 + 0x400 * channel + + lane * 4, + ~read32(DEFAULT_MCHBAR + 0x4040 + + 0x400 * channel + lane * 4) & 0xff); + } + + fill_pattern0(ctrl, channel, 0, 0xffffffff); + write32(DEFAULT_MCHBAR | 0x4288 | (channel << 10), 0); + } + + /* FIXME: under some conditions (older chipsets?) vendor BIOS sets both edges to the same value. */ + write32(DEFAULT_MCHBAR + 0x4eb0, 0x300); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS { + discover_edges_real(ctrl, channel, slotrank, + falling_edges[channel][slotrank]); + } + + write32(DEFAULT_MCHBAR + 0x4eb0, 0x200); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS { + discover_edges_real(ctrl, channel, slotrank, + rising_edges[channel][slotrank]); + } + + write32(DEFAULT_MCHBAR + 0x4eb0, 0); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane].falling = + falling_edges[channel][slotrank][lane]; + ctrl->timings[channel][slotrank].lanes[lane].rising = + rising_edges[channel][slotrank][lane]; + } + + FOR_ALL_POPULATED_CHANNELS { + program_timings(ctrl, channel); + } + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + write32(DEFAULT_MCHBAR + 0x4080 + 0x400 * channel + 4 * lane, + 0); + } +} + +static void discover_edges_write_real(ramctr_timing * ctrl, int channel, + int slotrank, int *edges) +{ + int edge; + u32 raw_statistics[MAX_EDGE_TIMING + 1]; + int statistics[MAX_EDGE_TIMING + 1]; + const int reg3000b24[] = { 0, 0xc, 0x2c }; + int lane, i; + int lower[NUM_LANES]; + int upper[NUM_LANES]; + int pat; + + FOR_ALL_LANES { + lower[lane] = 0; + upper[lane] = MAX_EDGE_TIMING; + } + + for (i = 0; i < 3; i++) { + write32(DEFAULT_MCHBAR + 0x3000 + 0x100 * channel, + reg3000b24[i] << 24); + for (pat = 0; pat < NUM_PATTERNS; pat++) { + fill_pattern5(ctrl, channel, pat); + write32(DEFAULT_MCHBAR + 0x4288 + 0x400 * channel, 0x1f); + printk(BIOS_SPEW, "patterned\n"); + printk(BIOS_SPEW, "[%x] = 0x%08x\n(%d, %d)\n", + 0x3000 + 0x100 * channel, reg3000b24[i] << 24, channel, + slotrank); + for (edge = 0; edge <= MAX_EDGE_TIMING; edge++) { + FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane]. + rising = edge; + ctrl->timings[channel][slotrank].lanes[lane]. + falling = edge; + } + program_timings(ctrl, channel); + + FOR_ALL_LANES { + write32(DEFAULT_MCHBAR + 0x4340 + + 0x400 * channel + 4 * lane, 0); + read32(DEFAULT_MCHBAR + 0x400 * channel + + 4 * lane + 0x4140); + } + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, + 0x1f006); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + 0x4 | (ctrl->tRCD << 16) + | (max(ctrl->tRRD, (ctrl->tFAW >> 2) + 1) << + 10)); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x60000); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, + 0x240); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, + 0x1f201); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, + 0x8005020 | ((ctrl->tWTR + ctrl->CWL + 8) << + 16)); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24)); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, + 0x242); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, + 0x1f105); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, + 0x4005020 | (max(ctrl->tRTP, 8) << 16)); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, + (slotrank << 24)); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, + 0x242); + + write32(DEFAULT_MCHBAR + 0x422c + 0x400 * channel, + 0x1f002); + write32(DEFAULT_MCHBAR + 0x423c + 0x400 * channel, + 0xc01 | (ctrl->tRP << 16)); + write32(DEFAULT_MCHBAR + 0x420c + 0x400 * channel, + (slotrank << 24) | 0x60400); + write32(DEFAULT_MCHBAR + 0x421c + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, + 0xc0001); + wait_428c(channel); + FOR_ALL_LANES { + read32(DEFAULT_MCHBAR + 0x4340 + + 0x400 * channel + lane * 4); + } + + raw_statistics[edge] = + MCHBAR32(0x436c + 0x400 * channel); + } + FOR_ALL_LANES { + struct run rn; + for (edge = 0; edge <= MAX_EDGE_TIMING; edge++) + statistics[edge] = + ! !(raw_statistics[edge] & (1 << lane)); + rn = get_longest_zero_run(statistics, + MAX_EDGE_TIMING + 1); + printk(BIOS_SPEW, + "edges: %d, %d, %d: 0x%x-0x%x-0x%x, 0x%x-0x%x\n", + channel, slotrank, i, rn.start, rn.middle, + rn.end, rn.start + ctrl->edge_offset[i], + rn.end - ctrl->edge_offset[i]); + lower[lane] = + max(rn.start + ctrl->edge_offset[i], lower[lane]); + upper[lane] = + min(rn.end - ctrl->edge_offset[i], upper[lane]); + edges[lane] = (lower[lane] + upper[lane]) / 2; + + } + } + } + + write32(DEFAULT_MCHBAR + 0x3000, 0); + printk(BIOS_SPEW, "CPA\n"); +} + +static void discover_edges_write(ramctr_timing * ctrl) +{ + int falling_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES]; + int rising_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES]; + int channel, slotrank, lane; + + /* FIXME: under some conditions (older chipsets?) vendor BIOS sets both edges to the same value. */ + write32(DEFAULT_MCHBAR + 0x4eb0, 0x300); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS { + discover_edges_write_real(ctrl, channel, slotrank, + falling_edges[channel][slotrank]); + } + + write32(DEFAULT_MCHBAR + 0x4eb0, 0x200); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS { + discover_edges_write_real(ctrl, channel, slotrank, + rising_edges[channel][slotrank]); + } + + write32(DEFAULT_MCHBAR + 0x4eb0, 0); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane].falling = + falling_edges[channel][slotrank][lane]; + ctrl->timings[channel][slotrank].lanes[lane].rising = + rising_edges[channel][slotrank][lane]; + } + + FOR_ALL_POPULATED_CHANNELS + program_timings(ctrl, channel); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + write32(DEFAULT_MCHBAR + 0x4080 + 0x400 * channel + 4 * lane, + 0); + } +} + +static void test_timC_write(ramctr_timing *ctrl, int channel, int slotrank) +{ + wait_428c(channel); + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f006); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + (max((ctrl->tFAW >> 2) + 1, ctrl->tRRD) + << 10) | (ctrl->tRCD << 16) | 4); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x60000); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0x244); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f201); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, + 0x80011e0 | + ((ctrl->tWTR + ctrl->CWL + 8) << 16)); + write32(DEFAULT_MCHBAR + 0x4204 + + 0x400 * channel, (slotrank << 24)); + write32(DEFAULT_MCHBAR + 0x4214 + + 0x400 * channel, 0x242); + + write32(DEFAULT_MCHBAR + 0x4228 + + 0x400 * channel, 0x1f105); + write32(DEFAULT_MCHBAR + 0x4238 + + 0x400 * channel, + 0x40011e0 | (max(ctrl->tRTP, 8) << 16)); + write32(DEFAULT_MCHBAR + 0x4208 + + 0x400 * channel, (slotrank << 24)); + write32(DEFAULT_MCHBAR + 0x4218 + + 0x400 * channel, 0x242); + + write32(DEFAULT_MCHBAR + 0x422c + + 0x400 * channel, 0x1f002); + write32(DEFAULT_MCHBAR + 0x423c + + 0x400 * channel, + 0x1001 | (ctrl->tRP << 16)); + write32(DEFAULT_MCHBAR + 0x420c + + 0x400 * channel, + (slotrank << 24) | 0x60400); + write32(DEFAULT_MCHBAR + 0x421c + + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4284 + + 0x400 * channel, 0xc0001); + wait_428c(channel); +} + +static void discover_timC_write(ramctr_timing * ctrl) +{ + const u8 rege3c_b24[3] = { 0, 0xf, 0x2f }; + int i, pat; + + int lower[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES]; + int upper[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES]; + int channel, slotrank, lane; + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + lower[channel][slotrank][lane] = 0; + upper[channel][slotrank][lane] = MAX_TIMC; + } + + write32(DEFAULT_MCHBAR + 0x4ea8, 1); + + for (i = 0; i < 3; i++) + FOR_ALL_POPULATED_CHANNELS { + write32(DEFAULT_MCHBAR + 0xe3c + (channel * 0x100), + (rege3c_b24[i] << 24) + | (read32(DEFAULT_MCHBAR + 0xe3c + (channel * 0x100)) + & ~0x3f000000)); + udelay(2); + for (pat = 0; pat < NUM_PATTERNS; pat++) { + FOR_ALL_POPULATED_RANKS { + int timC; + u32 raw_statistics[MAX_TIMC + 1]; + int statistics[MAX_TIMC + 1]; + + fill_pattern5(ctrl, channel, pat); + write32(DEFAULT_MCHBAR + 0x4288 + 0x400 * channel, 0x1f); + for (timC = 0; timC < MAX_TIMC + 1; timC++) { + FOR_ALL_LANES + ctrl->timings[channel][slotrank].lanes[lane].timC = timC; + program_timings(ctrl, channel); + + test_timC_write (ctrl, channel, slotrank); + + raw_statistics[timC] = + MCHBAR32(0x436c + 0x400 * channel); + } + FOR_ALL_LANES { + struct run rn; + for (timC = 0; timC <= MAX_TIMC; timC++) + statistics[timC] = + !!(raw_statistics[timC] & + (1 << lane)); + rn = get_longest_zero_run(statistics, + MAX_TIMC + 1); + if (rn.all) + die("timC write discovery failed"); + printk(BIOS_SPEW, + "timC: %d, %d, %d: 0x%x-0x%x-0x%x, 0x%x-0x%x\n", + channel, slotrank, i, rn.start, + rn.middle, rn.end, + rn.start + ctrl->timC_offset[i], + rn.end - ctrl->timC_offset[i]); + lower[channel][slotrank][lane] = + max(rn.start + ctrl->timC_offset[i], + lower[channel][slotrank][lane]); + upper[channel][slotrank][lane] = + min(rn.end - ctrl->timC_offset[i], + upper[channel][slotrank][lane]); + + } + } + } + } + + FOR_ALL_CHANNELS { + write32(DEFAULT_MCHBAR + (channel * 0x100) + 0xe3c, + 0 | (read32(DEFAULT_MCHBAR + (channel * 0x100) + 0xe3c) & + ~0x3f000000)); + udelay(2); + } + + write32(DEFAULT_MCHBAR + 0x4ea8, 0); + + printk(BIOS_SPEW, "CPB\n"); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + printk(BIOS_SPEW, "timC [%d, %d, %d] = 0x%x\n", channel, + slotrank, lane, + (lower[channel][slotrank][lane] + + upper[channel][slotrank][lane]) / 2); + ctrl->timings[channel][slotrank].lanes[lane].timC = + (lower[channel][slotrank][lane] + + upper[channel][slotrank][lane]) / 2; + } + FOR_ALL_POPULATED_CHANNELS { + program_timings(ctrl, channel); + } +} + +static void normalize_training(ramctr_timing * ctrl) +{ + int channel, slotrank, lane; + int mat = 0; + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS { + int delta; + FOR_ALL_LANES mat = + max(ctrl->timings[channel][slotrank].lanes[lane].timA, mat); + delta = (mat >> 6) - ctrl->timings[channel][slotrank].val_4028; + ctrl->timings[channel][slotrank].val_4024 += delta; + ctrl->timings[channel][slotrank].val_4028 += delta; + } + + FOR_ALL_POPULATED_CHANNELS { + program_timings(ctrl, channel); + } +} + +static void write_controller_mr(ramctr_timing * ctrl) +{ + int channel, slotrank; + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS { + write32(DEFAULT_MCHBAR | 0x0004 | (channel << 8) | + lane_registers[slotrank], make_mr0(ctrl, slotrank)); + write32(DEFAULT_MCHBAR | 0x0008 | (channel << 8) | + lane_registers[slotrank], make_mr1(ctrl, slotrank)); + } +} + +static void channel_test(ramctr_timing * ctrl) +{ + int channel, slotrank, lane; + + FOR_ALL_POPULATED_CHANNELS + if (read32(DEFAULT_MCHBAR | 0x42a0 | (channel << 10)) & 0xa000) + die("Mini channel test failed (1)\n"); + FOR_ALL_POPULATED_CHANNELS { + fill_pattern0(ctrl, channel, 0x12345678, 0x98765432); + + write32(DEFAULT_MCHBAR | 0x4288 | (channel << 10), 0); + } + + for (slotrank = 0; slotrank < 4; slotrank++) + FOR_ALL_CHANNELS + if (ctrl->rankmap[channel] & (1 << slotrank)) { + FOR_ALL_LANES { + write32(DEFAULT_MCHBAR | (0x4f40 + 4 * lane), 0); + write32(DEFAULT_MCHBAR | (0x4d40 + 4 * lane), 0); + } + wait_428c(channel); + write32(DEFAULT_MCHBAR | 0x4220 | (channel << 10), 0x0001f006); + write32(DEFAULT_MCHBAR | 0x4230 | (channel << 10), 0x0028a004); + write32(DEFAULT_MCHBAR | 0x4200 | (channel << 10), + 0x00060000 | (slotrank << 24)); + write32(DEFAULT_MCHBAR | 0x4210 | (channel << 10), 0x00000244); + write32(DEFAULT_MCHBAR | 0x4224 | (channel << 10), 0x0001f201); + write32(DEFAULT_MCHBAR | 0x4234 | (channel << 10), 0x08281064); + write32(DEFAULT_MCHBAR | 0x4204 | (channel << 10), + 0x00000000 | (slotrank << 24)); + write32(DEFAULT_MCHBAR | 0x4214 | (channel << 10), 0x00000242); + write32(DEFAULT_MCHBAR | 0x4228 | (channel << 10), 0x0001f105); + write32(DEFAULT_MCHBAR | 0x4238 | (channel << 10), 0x04281064); + write32(DEFAULT_MCHBAR | 0x4208 | (channel << 10), + 0x00000000 | (slotrank << 24)); + write32(DEFAULT_MCHBAR | 0x4218 | (channel << 10), 0x00000242); + write32(DEFAULT_MCHBAR | 0x422c | (channel << 10), 0x0001f002); + write32(DEFAULT_MCHBAR | 0x423c | (channel << 10), 0x00280c01); + write32(DEFAULT_MCHBAR | 0x420c | (channel << 10), + 0x00060400 | (slotrank << 24)); + write32(DEFAULT_MCHBAR | 0x421c | (channel << 10), 0x00000240); + write32(DEFAULT_MCHBAR | 0x4284 | (channel << 10), 0x000c0001); + wait_428c(channel); + FOR_ALL_LANES + if (read32(DEFAULT_MCHBAR | 0x4340 | (channel << 10))) + die("Mini channel test failed (2)\n"); + } +} + +static void set_scrambling_seed(ramctr_timing * ctrl) +{ + int channel; + + /* FIXME: we hardcode seeds. Do we need to use some PRNG for them? + I don't think so. */ + static u32 seeds[NUM_CHANNELS][3] = { + {0x00009a36, 0xbafcfdcf, 0x46d1ab68}, + {0x00028bfa, 0x53fe4b49, 0x19ed5483} + }; + FOR_ALL_POPULATED_CHANNELS { + MCHBAR32(0x4020 + 0x400 * channel) &= ~0x10000000; + write32(DEFAULT_MCHBAR | 0x4034, seeds[channel][0]); + write32(DEFAULT_MCHBAR | 0x403c, seeds[channel][1]); + write32(DEFAULT_MCHBAR | 0x4038, seeds[channel][2]); + } +} + +static void set_4f8c(void) +{ + struct cpuid_result cpures; + u32 cpu; + + cpures = cpuid(0); + cpu = (cpures.eax); + if (IS_SANDY_CPU(cpu) && (IS_SANDY_CPU_D0(cpu) || IS_SANDY_CPU_D1(cpu))) { + MCHBAR32(0x4f8c) = 0x141D1519; + } else { + MCHBAR32(0x4f8c) = 0x551D1519; + } +} + +static void prepare_training(ramctr_timing * ctrl) +{ + int channel; + + FOR_ALL_POPULATED_CHANNELS { + // Always drive command bus + MCHBAR32(0x4004 + 0x400 * channel) |= 0x20000000; + } + + udelay(1); + + FOR_ALL_POPULATED_CHANNELS { + wait_428c(channel); + } +} + +static void set_4008c(ramctr_timing * ctrl) +{ + int channel, slotrank; + u32 reg; + FOR_ALL_POPULATED_CHANNELS { + u32 b20, b4_8_12; + int min_320c = 10000; + int max_320c = -10000; + + FOR_ALL_POPULATED_RANKS { + max_320c = max(ctrl->timings[channel][slotrank].val_320c, max_320c); + min_320c = min(ctrl->timings[channel][slotrank].val_320c, min_320c); + } + + if (max_320c - min_320c > 51) + b20 = 0; + else + b20 = ctrl->ref_card_offset[channel]; + + if (ctrl->reg_320c_range_threshold < max_320c - min_320c) + b4_8_12 = 0x3330; + else + b4_8_12 = 0x2220; + + reg = read32(DEFAULT_MCHBAR | 0x400c | (channel << 10)); + write32(DEFAULT_MCHBAR | 0x400c | (channel << 10), + (reg & 0xFFF0FFFF) + | (ctrl->ref_card_offset[channel] << 16) + | (ctrl->ref_card_offset[channel] << 18)); + write32(DEFAULT_MCHBAR | 0x4008 | (channel << 10), + 0x0a000000 + | (b20 << 20) + | ((ctrl->ref_card_offset[channel] + 2) << 16) + | b4_8_12); + } +} + +static void set_42a0(ramctr_timing * ctrl) +{ + int channel; + FOR_ALL_POPULATED_CHANNELS { + write32(DEFAULT_MCHBAR | (0x42a0 + 0x400 * channel), + 0x00001000 | ctrl->rankmap[channel]); + MCHBAR32(0x4004 + 0x400 * channel) &= ~0x20000000; // OK + } +} + +static int encode_5d10(int ns) +{ + return (ns + 499) / 500; +} + +/* FIXME: values in this function should be hardware revision-dependent. */ +static void final_registers(ramctr_timing * ctrl) +{ + int channel; + int t1_cycles = 0, t1_ns = 0, t2_ns; + int t3_ns; + u32 r32; + + write32(DEFAULT_MCHBAR | 0x4cd4, 0x00000046); + + write32(DEFAULT_MCHBAR | 0x400c, (read32(DEFAULT_MCHBAR | 0x400c) & 0xFFFFCFFF) | 0x1000); // OK + write32(DEFAULT_MCHBAR | 0x440c, (read32(DEFAULT_MCHBAR | 0x440c) & 0xFFFFCFFF) | 0x1000); // OK + write32(DEFAULT_MCHBAR | 0x4cb0, 0x00000740); + write32(DEFAULT_MCHBAR | 0x4380, 0x00000aaa); // OK + write32(DEFAULT_MCHBAR | 0x4780, 0x00000aaa); // OK + write32(DEFAULT_MCHBAR | 0x4f88, 0x5f7003ff); // OK + write32(DEFAULT_MCHBAR | 0x5064, 0x00073000 | ctrl->reg_5064b0); // OK + + FOR_ALL_CHANNELS { + switch (ctrl->rankmap[channel]) { + /* Unpopulated channel. */ + case 0: + write32(DEFAULT_MCHBAR + 0x4384 + channel * 0x400, 0); + break; + /* Only single-ranked dimms. */ + case 1: + case 4: + case 5: + write32(DEFAULT_MCHBAR + 0x4384 + channel * 0x400, 0x373131); + break; + /* Dual-ranked dimms present. */ + default: + write32(DEFAULT_MCHBAR + 0x4384 + channel * 0x400, 0x9b6ea1); + break; + } + } + + write32 (DEFAULT_MCHBAR | 0x5880, 0xca9171e5); + write32 (DEFAULT_MCHBAR | 0x5888, + (read32 (DEFAULT_MCHBAR | 0x5888) & ~0xffffff) | 0xe4d5d0); + write32 (DEFAULT_MCHBAR | 0x58a8, read32 (DEFAULT_MCHBAR | 0x58a8) & ~0x1f); + write32 (DEFAULT_MCHBAR | 0x4294, + (read32 (DEFAULT_MCHBAR | 0x4294) & ~0x30000) + | (1 << 16)); + write32 (DEFAULT_MCHBAR | 0x4694, + (read32 (DEFAULT_MCHBAR | 0x4694) & ~0x30000) + | (1 << 16)); + + MCHBAR32(0x5030) |= 1; // OK + MCHBAR32(0x5030) |= 0x80; // OK + MCHBAR32(0x5f18) = 0xfa; // OK + + /* Find a populated channel. */ + FOR_ALL_POPULATED_CHANNELS + break; + + t1_cycles = ((read32(DEFAULT_MCHBAR + 0x4290 + channel * 0x400) >> 8) & 0xff); + r32 = read32(DEFAULT_MCHBAR + 0x5064); + if (r32 & 0x20000) + t1_cycles += (r32 & 0xfff); + t1_cycles += (read32(DEFAULT_MCHBAR + channel * 0x400 + 0x42a4) & 0xfff); + t1_ns = t1_cycles * ctrl->tCK / 256 + 544; + if (!(r32 & 0x20000)) + t1_ns += 500; + + t2_ns = 10 * ((read32(DEFAULT_MCHBAR + 0x5f10) >> 8) & 0xfff); + if ( read32(DEFAULT_MCHBAR + 0x5f00) & 8 ) + { + t3_ns = 10 * ((read32(DEFAULT_MCHBAR + 0x5f20) >> 8) & 0xfff); + t3_ns += 10 * (read32(DEFAULT_MCHBAR + 0x5f18) & 0xff); + } + else + { + t3_ns = 500; + } + printk(BIOS_DEBUG, "t123: %d, %d, %d\n", + t1_ns, t2_ns, t3_ns); + write32 (DEFAULT_MCHBAR + 0x5d10, + ((encode_5d10(t1_ns) + encode_5d10(t2_ns)) << 16) + | (encode_5d10(t1_ns) << 8) + | ((encode_5d10(t3_ns) + encode_5d10(t2_ns) + encode_5d10(t1_ns)) << 24) + | (read32(DEFAULT_MCHBAR + 0x5d10) & 0xC0C0C0C0) + | 0xc); +} + +static void save_timings(ramctr_timing * ctrl) +{ + struct mrc_data_container *mrcdata; + int output_len = ALIGN(sizeof (*ctrl), 16); + + /* Save the MRC S3 restore data to cbmem */ + mrcdata = cbmem_add + (CBMEM_ID_MRCDATA, + output_len + sizeof(struct mrc_data_container)); + + printk(BIOS_DEBUG, "Relocate MRC DATA from %p to %p (%u bytes)\n", + ctrl, mrcdata, output_len); + + mrcdata->mrc_signature = MRC_DATA_SIGNATURE; + mrcdata->mrc_data_size = output_len; + mrcdata->reserved = 0; + memcpy(mrcdata->mrc_data, ctrl, sizeof (*ctrl)); + + /* Zero the unused space in aligned buffer. */ + if (output_len > sizeof (*ctrl)) + memset(mrcdata->mrc_data+sizeof (*ctrl), 0, + output_len - sizeof (*ctrl)); + + mrcdata->mrc_checksum = compute_ip_checksum(mrcdata->mrc_data, + mrcdata->mrc_data_size); +} + +static void restore_timings(ramctr_timing * ctrl) +{ + int channel, slotrank, lane; + + FOR_ALL_POPULATED_CHANNELS + MCHBAR32(0x4004 + 0x400 * channel) = + ctrl->tRRD + | (ctrl->tRTP << 4) + | (ctrl->tCKE << 8) + | (ctrl->tWTR << 12) + | (ctrl->tFAW << 16) + | (ctrl->tWR << 24) + | (ctrl->reg_4004_b30[channel] << 30); + + udelay(1); + + FOR_ALL_POPULATED_CHANNELS { + wait_428c(channel); + } + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + write32(DEFAULT_MCHBAR + 0x4080 + 0x400 * channel + + 4 * lane, 0); + } + + FOR_ALL_POPULATED_CHANNELS + write32(DEFAULT_MCHBAR + 0x4008 + 0x400 * channel, + read32(DEFAULT_MCHBAR + 0x4008 + + 0x400 * channel) | 0x8000000); + + FOR_ALL_POPULATED_CHANNELS { + udelay (1); + write32(DEFAULT_MCHBAR + 0x4020 + 0x400 * channel, + read32(DEFAULT_MCHBAR + 0x4020 + + 0x400 * channel) | 0x200000); + } + + printk(BIOS_SPEW, "CPE\n"); + + write32(DEFAULT_MCHBAR + 0x3400, 0); + write32(DEFAULT_MCHBAR + 0x4eb0, 0); + + printk(BIOS_SPEW, "CP5b\n"); + + FOR_ALL_POPULATED_CHANNELS { + program_timings(ctrl, channel); + } + + u32 reg, addr; + + while (!(MCHBAR32(0x5084) & 0x10000)) ; + do { + reg = MCHBAR32(0x428c); + } while ((reg & 0x14) == 0); + + // Set state of memory controller + MCHBAR32(0x5030) = 0x116; + MCHBAR32(0x4ea0) = 0; + + // Wait 500us + udelay(500); + + FOR_ALL_CHANNELS { + // Set valid rank CKE + reg = 0; + reg = (reg & ~0xf) | ctrl->rankmap[channel]; + addr = 0x400 * channel + 0x42a0; + MCHBAR32(addr) = reg; + + // Wait 10ns for ranks to settle + //udelay(0.01); + + reg = (reg & ~0xf0) | (ctrl->rankmap[channel] << 4); + MCHBAR32(addr) = reg; + + // Write reset using a NOP + write_reset(ctrl); + } + + /* mrs commands. */ + dram_mrscommands(ctrl); + + printk(BIOS_SPEW, "CP5c\n"); + + write32(DEFAULT_MCHBAR + 0x3000, 0); + + FOR_ALL_CHANNELS { + write32(DEFAULT_MCHBAR + (channel * 0x100) + 0xe3c, + 0 | (read32(DEFAULT_MCHBAR + (channel * 0x100) + 0xe3c) & + ~0x3f000000)); + udelay(2); + } + + write32(DEFAULT_MCHBAR + 0x4ea8, 0); +} + +void init_dram_ddr3(spd_raw_data * spds, int mobile, int min_tck, + int s3resume) +{ + int me_uma_size; + int cbmem_was_inited; + + MCHBAR32(0x5f00) |= 1; + + report_platform_info(); + + /* Wait for ME to be ready */ + intel_early_me_init(); + me_uma_size = intel_early_me_uma_size(); + + printk(BIOS_DEBUG, "Starting native Platform init\n"); + + u32 reg_5d10; + + wait_txt_clear(); + + wrmsr(0x000002e6, (msr_t) { .lo = 0, .hi = 0 }); + + reg_5d10 = read32(DEFAULT_MCHBAR | 0x5d10); // !!! = 0x00000000 + if ((pcie_read_config16(SOUTHBRIDGE, 0xa2) & 0xa0) == 0x20 /* 0x0004 */ + && reg_5d10 && !s3resume) { + write32(DEFAULT_MCHBAR | 0x5d10, 0); + /* Need reset. */ + outb(0x6, 0xcf9); + + hlt(); + } + + ramctr_timing ctrl; + + memset(&ctrl, 0, sizeof (ctrl)); + + early_pch_init_native(); + early_thermal_init(); + + ctrl.mobile = mobile; + ctrl.tCK = min_tck; + + /* FIXME: for non-S3 we should be able to use timing caching with + proper verification. Right now we use timings only for S3 case. + */ + if (s3resume) { + struct mrc_data_container *mrc_cache; + + mrc_cache = find_current_mrc_cache(); + if (!mrc_cache || mrc_cache->mrc_data_size < sizeof (ctrl)) { + /* Failed S3 resume, reset to come up cleanly */ + outb(0x6, 0xcf9); + hlt(); + } + memcpy(&ctrl, mrc_cache->mrc_data, sizeof (ctrl)); + } + + if (!s3resume) { + dimm_info info; + + /* Get DDR3 SPD data */ + dram_find_spds_ddr3(spds, &info, &ctrl); + + /* Find fastest common supported parameters */ + dram_find_common_params(&info, &ctrl); + + dram_dimm_mapping(&info, &ctrl); + } + + /* Set MCU frequency */ + dram_freq(&ctrl); + + if (!s3resume) { + /* Calculate timings */ + dram_timing(&ctrl); + } + + /* Set version register */ + MCHBAR32(0x5034) = 0xC04EB002; + + /* Enable crossover */ + dram_xover(&ctrl); + + /* Set timing and refresh registers */ + dram_timing_regs(&ctrl); + + /* Power mode preset */ + MCHBAR32(0x4e80) = 0x5500; + + /* Set scheduler parameters */ + MCHBAR32(0x4c20) = 0x10100005; + + /* Set cpu specific register */ + set_4f8c(); + + /* Clear IO reset bit */ + MCHBAR32(0x5030) &= ~0x20; + + /* Set MAD-DIMM registers */ + dram_dimm_set_mapping(&ctrl); + printk(BIOS_DEBUG, "Done dimm mapping\n"); + + /* Zone config */ + dram_zones(&ctrl, 1); + + /* Set memory map */ + dram_memorymap(&ctrl, me_uma_size); + printk(BIOS_DEBUG, "Done memory map\n"); + + /* Set IO registers */ + dram_ioregs(&ctrl); + printk(BIOS_DEBUG, "Done io registers\n"); + + udelay(1); + + if (s3resume) { + restore_timings(&ctrl); + } else { + /* Do jedec ddr3 reset sequence */ + dram_jedecreset(&ctrl); + printk(BIOS_DEBUG, "Done jedec reset\n"); + + /* MRS commands */ + dram_mrscommands(&ctrl); + printk(BIOS_DEBUG, "Done MRS commands\n"); + dram_mrscommands(&ctrl); + + /* Prepare for memory training */ + prepare_training(&ctrl); + + read_training(&ctrl); + write_training(&ctrl); + + printk(BIOS_SPEW, "CP5a\n"); + + discover_edges(&ctrl); + + printk(BIOS_SPEW, "CP5b\n"); + + command_training(&ctrl); + + printk(BIOS_SPEW, "CP5c\n"); + + discover_edges_write(&ctrl); + + discover_timC_write(&ctrl); + + normalize_training(&ctrl); + } + + set_4008c(&ctrl); + + write_controller_mr(&ctrl); + + if (!s3resume) { + channel_test(&ctrl); + } + + /* FIXME: should be hardware revision-dependent. */ + write32(DEFAULT_MCHBAR | 0x5024, 0x00a030ce); + + set_scrambling_seed(&ctrl); + + set_42a0(&ctrl); + + final_registers(&ctrl); + + /* Zone config */ + dram_zones(&ctrl, 0); + + if (!s3resume) + quick_ram_check(); + + intel_early_me_status(); + intel_early_me_init_done(ME_INIT_STATUS_SUCCESS); + intel_early_me_status(); + + post_system_agent_init(); + report_memory_config(); + + cbmem_was_inited = !cbmem_recovery(s3resume); + if (!s3resume) + save_timings(&ctrl); + if (s3resume && !cbmem_was_inited) { + /* Failed S3 resume, reset to come up cleanly */ + outb(0x6, 0xcf9); + hlt(); + } +} diff --git a/src/northbridge/intel/sandybridge/raminit_native.h b/src/northbridge/intel/sandybridge/raminit_native.h new file mode 100644 index 0000000..7ed75ff --- /dev/null +++ b/src/northbridge/intel/sandybridge/raminit_native.h @@ -0,0 +1,29 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2010 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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 + */ + +#ifndef RAMINIT_H +#define RAMINIT_H + +#include <device/dram/ddr3.h> + +/* The order is ch0dimmA, ch0dimmB, ch1dimmA, ch1dimmB. */ +void init_dram_ddr3(spd_raw_data *spds, int mobile, int min_tck, int s3resume); +void read_spd(spd_raw_data *spd, u8 addr); + +#endif /* RAMINIT_H */ diff --git a/src/northbridge/intel/sandybridge/raminit_patterns.h b/src/northbridge/intel/sandybridge/raminit_patterns.h new file mode 100644 index 0000000..61c67b4 --- /dev/null +++ b/src/northbridge/intel/sandybridge/raminit_patterns.h @@ -0,0 +1,639 @@ +const u32 pattern[][16] = { + {0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff}, + {0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000}, + {0xe62d6424, 0x9277e09e, 0x8f43dc3f, 0x76eae589, + 0x0010fdc6, 0xdc55e01c, 0x5effb0ab, 0x6cba5d29, + 0xa43d1e64, 0xab5c2e0f, 0x7796ed16, 0x96023bf4, + 0xa74c831d, 0x90f138c0, 0x17830a8a, 0x5ac17c47}, + {0x359ebbeb, 0x2b9b4512, 0xef584d98, 0x106bf7cb, + 0x363525ad, 0xb3a4dfdc, 0xa6b9fcd8, 0xd21689ec, + 0x84a3695b, 0xbd9c2e27, 0xdb3d0f44, 0x988158f1, + 0xcca91d3f, 0xb62a6d12, 0xe905e4cf, 0x7f1fa626}, + {0xe58efeae, 0xcd006081, 0xa9119403, 0xbcfbd35f, + 0x213b3bf7, 0x7bfcb773, 0xc85143f9, 0x0bdbff50, + 0xa3053c90, 0x51d66cb7, 0x296f4387, 0xb715f99e, + 0xfaddc989, 0xbb1de8a7, 0x39206b4d, 0x80174a57}, + {0xa1622ac1, 0xb4f4a5f0, 0x16dc2bc3, 0x50fb0954, + 0x2e261721, 0x52b82c3c, 0x821902b8, 0x0d4b6c38, + 0x1f618631, 0x047956f3, 0xd4337f5a, 0x591f8002, + 0x27f28db2, 0xfae37369, 0xb3f27580, 0x3cdb6397}, + {0x3dee23be, 0x19f36408, 0x227f4a6a, 0x024603c5, + 0xd5e062db, 0x6d8d4c5c, 0x7ff693b0, 0x76641be9, + 0x9e74f41c, 0xe7bc7f33, 0x2636f2e9, 0x70279750, + 0xce2355aa, 0x32d230ef, 0x22f9b468, 0xadd4e7a2}, + {0x936c0fed, 0xba0612d5, 0xa97c1ea7, 0x10e29d67, + 0x1c4c5dc8, 0x83645621, 0xcd8b521c, 0xb8301817, + 0xac7d6571, 0xcc41d200, 0x4ebdefdd, 0xd2917bde, + 0x60f75acc, 0x7791534b, 0x26ea2a83, 0x6b74513a}, + {0xd1957b85, 0xc6f8f9ca, 0xf04fb4be, 0xfeb786fb, + 0xa1dea3aa, 0x67fe7db6, 0x25d49c87, 0xe3d54870, + 0x93dc1f86, 0x7d0c1a18, 0x9272e128, 0x68e1b876, + 0xce284c9e, 0x8fa18792, 0x5785a340, 0xb6fcf198}, + {0xff7d8e4a, 0x0c21ee43, 0xe820b388, 0xb4443c0e, + 0xa1e6e498, 0x5c426110, 0x1b434ef3, 0xbef05b91, + 0xa6907968, 0x53662ac3, 0x6defac32, 0x2c11c29c, + 0x6175cced, 0xb17dd3ad, 0x6e6a1076, 0x1372b1fa}, + {0x4408ed06, 0x49460ffd, 0xb49d26cb, 0x6a3662a5, + 0x5e857047, 0xa387cd4a, 0x04edc81e, 0xfd94d8d4, + 0x2fe48d91, 0x9d2356bc, 0x96131878, 0xaca3fce4, + 0xbb312c6c, 0x5023b090, 0x3614be70, 0xa14dfabb}, + {0xd4cc1e83, 0x757a1930, 0xc3d16a61, 0x9e0d6681, + 0x8a081fa9, 0xbd11c888, 0x1672f010, 0xa083f71c, + 0x1ec02eef, 0xc4586ca8, 0x6d322b35, 0x56054679, + 0x1552a0ff, 0x5cb7707e, 0xdfb55d4a, 0xcc76cc07}, + {0x507cf71f, 0x2166421a, 0x54be4af0, 0xfd42158c, + 0x417b1f7f, 0x9466860b, 0x3a0075bf, 0x2055575c, + 0xcedfe7ab, 0xbe85aa5f, 0x39d0c2e3, 0x851c19df, + 0x39a35a3f, 0x3fb10d7d, 0x20b14899, 0x703b7f08}, + {0x8a7d9dd1, 0x33235565, 0xbd3d2e57, 0xa48c2726, + 0x0d5e2e13, 0xae421ff9, 0x8784a224, 0xf66c1510, + 0x057627aa, 0x8fb0cb41, 0x4289975a, 0xb181adfa, + 0x59f2059a, 0xe86feb05, 0x84222fc1, 0x319b3ce9}, + {0xe1e243b8, 0x3b0bcc1a, 0x70396f00, 0x5caff44d, + 0xe96961b3, 0xad73f692, 0x8b841a2d, 0xf5838839, + 0xec9c9d04, 0xcc2b5562, 0xf8ca2549, 0xa9c52ff8, + 0x3b2fde68, 0x3d4dc7f0, 0xa57387d0, 0x051199ad}, + {0x5f0ce4fc, 0xd830fbb7, 0x90abeb8f, 0x96d9cdbb, + 0x58f80a80, 0x0baaca36, 0x81a23623, 0x77127614, + 0xaa8382cd, 0x0922fbca, 0xd84d37e1, 0x721297df, + 0x160f3b3a, 0x10a1ecdc, 0x151c92f4, 0xc1fdcdab}, + {0x261c45cc, 0xfeddd2da, 0xfc3cb1c1, 0x6639641f, + 0x2c011892, 0x7108bee2, 0x8545e0b9, 0x7dd36dab, + 0x07d91950, 0x1520adcb, 0xf84aa939, 0x07d9bb2d, + 0xdf1ed826, 0xaee3c814, 0x1dca1e81, 0xc8e9f486}, + {0x933d306a, 0xaab7103d, 0xa8be37be, 0x49612f3a, + 0xb0cf28e5, 0xf9648902, 0x106d7c11, 0xf32e1813, + 0x21af36ef, 0xe695e4c4, 0x7ee1831d, 0x2aeda467, + 0x99d0c655, 0x3f0691ab, 0xcd68f7c1, 0xb469a20e}, + {0x8557aef0, 0x3eb0e373, 0x0853ac31, 0xe5bded62, + 0x3eddb0dd, 0x6bbf1caf, 0x2119c3d9, 0xe1732350, + 0x55456c75, 0xf6119375, 0x498dd1ad, 0x13f80916, + 0xb97f9f5e, 0x921d9f4c, 0xabdee367, 0x1d6bb8bf}, + {0xd165a3be, 0xd8b41598, 0xa20e1809, 0xefd5c8ce, + 0x18935c80, 0xdf1911f9, 0xc9e449eb, 0xb887a4d7, + 0x4a324f6f, 0x533e8031, 0x1c21c074, 0xa95f1ea5, + 0x765b320a, 0x839d7dfb, 0xc7d3aa93, 0xe534ae3d}, + {0xbe8592c8, 0x068457e6, 0x89b94fa3, 0xd522ad02, + 0x7e7db0b7, 0x2c5b896f, 0x9f8ecb37, 0x05b983ff, + 0x3fe9b25f, 0x34a6215b, 0x0592ba34, 0xd564f85a, + 0x156c426d, 0x25ad5460, 0xe7b5e8b7, 0xa73285c6}, + {0x5ad8d838, 0x27b42d36, 0xcc806ad1, 0x157a058a, + 0x7297735a, 0xffd6df8d, 0xff96f7a2, 0x155b27ea, + 0x84708101, 0x979fd78b, 0x49797d0c, 0x0dc93e3c, + 0x20287332, 0xed759f88, 0xe5068529, 0xb83aa781}, + {0xc38b302c, 0x57b54075, 0xac810692, 0xb0d493e7, + 0x4adda486, 0x0665ce2e, 0xb2a9c003, 0xafacc4ce, + 0x4d5e906d, 0xb3d52fab, 0xe6962c6b, 0x850f4dd1, + 0x5021656c, 0x5df6c06b, 0x9255125b, 0x2363c478}, + {0x188b715c, 0xe8b884b0, 0x5e6d0b9a, 0x1f0051e1, + 0xd2d35d4c, 0xbfeaecbe, 0xc84bb0ad, 0x67a232d6, + 0x99001587, 0xbf4313e1, 0x74f64061, 0x2c1fc562, + 0xb6fe8ca6, 0x5226a239, 0xf5198574, 0x61b51dca}, + {0x51dcecd3, 0xbadbe596, 0xebe3e84a, 0x772bfdfc, + 0x03656ac5, 0xa7c36e91, 0x6cd32cf0, 0xc3f699dd, + 0x7d5aba01, 0x51e38e82, 0x23103a98, 0x20298b9d, + 0x19436510, 0x63ad7e6c, 0x8bc2b33f, 0x27079917}, + {0x8bd5be78, 0xf2403bfa, 0x780ebdb6, 0x94c53b64, + 0x6241c2e2, 0x5bfb081e, 0x6799e88f, 0xc997b7d1, + 0x466ac8b1, 0xbf5909da, 0x497ea39f, 0x402ffb48, + 0xd7470c2d, 0x8510aba9, 0x6c52a1c9, 0x812ca967}, + {0x031f7ab4, 0xd32fe890, 0x36ae6de5, 0x083dcde4, + 0x99a7f12f, 0xe44864a7, 0x02b75fff, 0xf25dda35, + 0x7679ff4f, 0xed421e01, 0xd9c2cfa1, 0xd36b4e82, + 0x5315d908, 0xc7ebcb2a, 0xb6f3e4c1, 0xf5bfbae9}, + {0x3f4a2a96, 0x64d8bd5a, 0x19acd70d, 0xf62fcdd9, + 0x5de99cdf, 0x32f3b7cb, 0x2c020578, 0x4e9bafb8, + 0x74919a08, 0xaba33e91, 0xa6bd2254, 0x2435a9b9, + 0x47e2a1b4, 0xe837a28e, 0xe113f1b0, 0x7654bd79}, + {0x05537a6c, 0x77be1a5c, 0x4c7492c9, 0x9086bfb0, + 0x257adc18, 0xf4787fc1, 0xe3fb6d53, 0x9525e589, + 0x445a65bc, 0x833f7d08, 0x69cf1f7e, 0x9a6372e1, + 0xceedb52e, 0x31032997, 0xd1c36828, 0x132772d6}, + {0x0a166972, 0x89beaf3b, 0x8d780fbc, 0x8aea5392, + 0x58347a41, 0x1e381ec2, 0xcc6280c8, 0xee0863e1, + 0x976e2dd2, 0x8c6ee6e2, 0xa0ca57cd, 0x95114a7d, + 0x3c096704, 0xa941769d, 0x2de20c05, 0x0bf8f812}, + {0x22779d6c, 0x94e12e8f, 0x5ce40299, 0xea1b55b0, + 0x9ebec05d, 0xe076cd2b, 0x8fef5648, 0x6a284c65, + 0xa790b705, 0xf0b19997, 0x0d8ca8af, 0x17440419, + 0xef4f702f, 0x33cbcbb1, 0x83d60f26, 0x48988397}, + {0x0fed7f53, 0xb5acbb67, 0xc031c73f, 0x5364d9ef, + 0xa6dbd12d, 0x82174a6c, 0xccf8e7ab, 0xc473c036, + 0xcff493d8, 0xad9afc3b, 0x316a24e8, 0x1842bea4, + 0x4cc0c82e, 0x28ccd91e, 0xd7311b5d, 0x50a89860}, +}; + +static const u8 use_base[63][32] = { + { + 0x0e, 0x9e, 0xa1, 0x39, 0x06, 0x26, 0xc5, 0xe9, 0xed, 0x07, 0x49, 0x3b, 0x34, 0x7f, 0x1c, 0xa8, + 0xdf, 0x7b, 0xb7, 0xb8, 0x28, 0xbe, 0x8a, 0x70, 0x17, 0xe5, 0xc0, 0x44, 0x4a, 0x8e, 0x61, 0x3b, + }, + { + 0x42, 0xe6, 0xe0, 0x6a, 0xb3, 0x08, 0x28, 0xaf, 0xfa, 0xb9, 0xb7, 0x32, 0x83, 0x5c, 0xef, 0x3d, + 0x90, 0x91, 0x64, 0x31, 0xe9, 0x3c, 0x92, 0xe6, 0xa3, 0xd4, 0x6a, 0xc6, 0x01, 0xa6, 0xeb, 0xe6, + }, + { + 0x39, 0x7f, 0x6f, 0x81, 0xb4, 0x33, 0x4a, 0xde, 0x4f, 0x77, 0x28, 0x47, 0x08, 0xf9, 0x3a, 0x55, + 0x21, 0x57, 0x27, 0x59, 0xf5, 0x96, 0xad, 0xc1, 0x10, 0x33, 0xe0, 0xe2, 0xf8, 0xb6, 0x49, 0xbd, + }, + { + 0xdf, 0x57, 0x60, 0x27, 0x95, 0x50, 0x3a, 0x8c, 0x34, 0x8b, 0xae, 0xc5, 0x69, 0x26, 0xca, 0x39, + 0x55, 0x98, 0xfb, 0x05, 0x3c, 0x1c, 0x8d, 0xf8, 0xb9, 0x99, 0x05, 0x40, 0xe5, 0x5e, 0x2f, 0xf6, + }, + { + 0xc1, 0x6a, 0xea, 0xd6, 0x39, 0x56, 0x08, 0x89, 0x83, 0x4c, 0xef, 0xda, 0xb2, 0x69, 0x76, 0xe4, + 0x75, 0x3f, 0x39, 0x13, 0x96, 0xb5, 0x41, 0x84, 0x00, 0x64, 0x79, 0x47, 0xe4, 0xcb, 0xc3, 0xd0, + }, + { + 0xf8, 0xb1, 0x19, 0x76, 0x51, 0x99, 0xd7, 0x45, 0x38, 0x40, 0xbf, 0x10, 0x4c, 0x89, 0x43, 0xa9, + 0x89, 0xe2, 0x85, 0x3f, 0xb4, 0xe8, 0xbf, 0x5e, 0xc2, 0xb4, 0x16, 0x6d, 0x1c, 0x61, 0xca, 0x40, + }, + { + 0x1c, 0xdc, 0xa6, 0xdb, 0x71, 0x8b, 0xf9, 0xbb, 0xee, 0xc2, 0xa5, 0x66, 0xa4, 0xbc, 0xb6, 0x89, + 0x58, 0xb9, 0x6f, 0x57, 0x71, 0x57, 0x5c, 0xf0, 0xed, 0xcf, 0x2c, 0x2e, 0x1d, 0x34, 0xc3, 0x00, + }, + { + 0x1d, 0x30, 0x03, 0xb9, 0x15, 0x8e, 0x47, 0x8c, 0xf2, 0x4e, 0x2d, 0xf1, 0xbf, 0x96, 0xa7, 0xa1, + 0x3f, 0x26, 0xc3, 0xc9, 0x08, 0x0b, 0xa8, 0xdd, 0x9b, 0xeb, 0xbc, 0x77, 0x1c, 0x10, 0x03, 0x77, + }, + { + 0x50, 0x7e, 0x62, 0x26, 0xcb, 0x49, 0x7b, 0x1a, 0xd4, 0x54, 0xf1, 0x25, 0x3d, 0xa2, 0xe6, 0x8a, + 0xb3, 0x62, 0xf1, 0x7e, 0x03, 0xef, 0x1b, 0x27, 0x21, 0xcc, 0xfc, 0x72, 0x30, 0x0c, 0x69, 0xad, + }, + { + 0x11, 0xf5, 0xb2, 0xfa, 0x2d, 0xbc, 0xa1, 0xd9, 0x74, 0x15, 0x59, 0xf2, 0xc6, 0x66, 0x4f, 0xde, + 0x84, 0x82, 0x4f, 0xe8, 0x33, 0xd5, 0xc5, 0xdd, 0xba, 0x0c, 0xc7, 0x51, 0x1f, 0x3c, 0x6d, 0x44, + }, + { + 0xcf, 0xf5, 0x3b, 0xc1, 0xbd, 0x5f, 0x9c, 0xad, 0x57, 0xfb, 0xfc, 0xbe, 0x95, 0xa0, 0x48, 0x58, + 0x8a, 0x68, 0x97, 0x71, 0xf3, 0xc0, 0xd1, 0x31, 0x33, 0xb9, 0x3c, 0xe9, 0x4f, 0xbb, 0x8d, 0xeb, + }, + { + 0x29, 0x0c, 0xa1, 0xc8, 0x04, 0xdc, 0xf9, 0x25, 0x85, 0x7e, 0xea, 0x6d, 0x75, 0x28, 0x69, 0x3f, + 0x3a, 0x83, 0xe4, 0x33, 0x31, 0x77, 0x57, 0x2e, 0xa9, 0xa8, 0x05, 0xfe, 0x19, 0xb7, 0xc4, 0xd1, + }, + { + 0x6d, 0x5d, 0x3f, 0x4f, 0x8a, 0x6a, 0x77, 0x2d, 0xf7, 0x9f, 0x73, 0xab, 0x40, 0xd9, 0x89, 0x57, + 0x69, 0xd7, 0xc8, 0xc3, 0x69, 0x54, 0x93, 0x7c, 0x9f, 0x4a, 0xcc, 0xaf, 0xcc, 0x0e, 0xe0, 0xb8, + }, + { + 0xb6, 0xd5, 0x36, 0x3f, 0x1c, 0x34, 0x54, 0x9b, 0xfc, 0xec, 0x5b, 0xb0, 0x26, 0xa6, 0xc0, 0x61, + 0x6d, 0x4c, 0x4f, 0x86, 0x2a, 0xbd, 0x34, 0x35, 0x52, 0x2c, 0x82, 0x01, 0x66, 0x0e, 0x80, 0x01, + }, + { + 0x48, 0x39, 0x43, 0xb8, 0xf9, 0x2b, 0x25, 0xe8, 0xf7, 0xf0, 0x1a, 0xed, 0x33, 0x1e, 0x30, 0xba, + 0x15, 0x37, 0xeb, 0xae, 0x97, 0xa7, 0x36, 0xa4, 0xc7, 0x1f, 0x91, 0x01, 0x38, 0x80, 0x5a, 0x76, + }, + { + 0x74, 0xbe, 0x15, 0x6b, 0x85, 0x28, 0xe4, 0xc4, 0x13, 0x68, 0x67, 0x03, 0x27, 0x7e, 0x32, 0x08, + 0x87, 0x23, 0xda, 0xf2, 0x47, 0xdd, 0xac, 0x2c, 0xc5, 0x7f, 0x06, 0xc8, 0x17, 0x4c, 0x6c, 0x81, + }, + { + 0x0d, 0x9f, 0x68, 0xbb, 0xa6, 0x6c, 0x7d, 0x3f, 0x81, 0xcf, 0x9a, 0x52, 0x87, 0xce, 0x98, 0x25, + 0x40, 0x2b, 0x1b, 0xdf, 0xd3, 0x6b, 0x53, 0xed, 0x80, 0xd2, 0x3d, 0xca, 0xdf, 0x07, 0x4e, 0x6b, + }, + { + 0xff, 0xf1, 0xd2, 0x1f, 0xbd, 0xd6, 0xa7, 0x3d, 0xb4, 0xc6, 0x88, 0x9d, 0x7b, 0x05, 0x04, 0x0b, + 0x4c, 0x6f, 0x11, 0x7f, 0x19, 0x18, 0x48, 0xf1, 0x26, 0xad, 0xd0, 0x60, 0xfa, 0x40, 0x35, 0xbb, + }, + { + 0xae, 0xec, 0x0e, 0x2e, 0xfd, 0x46, 0xf0, 0x9c, 0x06, 0x1b, 0x62, 0xbf, 0xf0, 0x3e, 0xba, 0xdf, + 0xb2, 0xa2, 0x83, 0x83, 0xda, 0x04, 0x15, 0xec, 0x1e, 0x2e, 0x1a, 0x64, 0x08, 0x8e, 0xd3, 0x87, + }, + { + 0x61, 0x14, 0x05, 0x0b, 0xdb, 0xf4, 0xf0, 0xa3, 0x41, 0x11, 0x7b, 0xd9, 0xa1, 0x40, 0x4f, 0x62, + 0x98, 0x37, 0xa0, 0x90, 0x3d, 0x78, 0x63, 0x24, 0xbc, 0x8e, 0x9e, 0x99, 0x2e, 0xc7, 0xb1, 0x6d, + }, + { + 0x0f, 0xf1, 0x5f, 0xe4, 0x94, 0x3d, 0x24, 0x0d, 0xa2, 0xcf, 0xed, 0xbb, 0x55, 0x8e, 0xdb, 0x07, + 0x12, 0x05, 0x79, 0x82, 0xb1, 0x3a, 0x71, 0x76, 0xbb, 0x8b, 0xcb, 0xcc, 0x00, 0x40, 0x2e, 0xab, + }, + { + 0x48, 0x59, 0xfa, 0x46, 0x15, 0x5e, 0xa2, 0x0d, 0xe8, 0x81, 0x69, 0xe6, 0x2f, 0x5f, 0x6d, 0xaf, + 0xad, 0xc7, 0x30, 0xd6, 0xec, 0x03, 0x1e, 0x19, 0xdd, 0x1d, 0x00, 0x94, 0x0b, 0x93, 0x5a, 0x28, + }, + { + 0xfa, 0x64, 0x62, 0x57, 0x02, 0x7e, 0x37, 0xb8, 0x10, 0xa9, 0x4b, 0xe7, 0xbf, 0x03, 0xdc, 0x1c, + 0xe7, 0x21, 0x68, 0x60, 0x53, 0xec, 0xf0, 0xfc, 0xbf, 0xe5, 0x8e, 0xca, 0x77, 0xdb, 0xa5, 0xae, + }, + { + 0xc1, 0xa9, 0x9f, 0xc2, 0x87, 0x11, 0xad, 0x1c, 0xc5, 0x56, 0x61, 0xc0, 0x20, 0x33, 0xc9, 0x85, + 0xf0, 0x81, 0x36, 0x18, 0xdb, 0xaa, 0x7e, 0x79, 0x36, 0x2d, 0xfc, 0x8f, 0x72, 0x3c, 0x4c, 0xa3, + }, + { + 0xb4, 0xd3, 0x38, 0xed, 0xd3, 0x6c, 0x03, 0x26, 0x0e, 0x1c, 0x8a, 0xa8, 0x72, 0x17, 0xcb, 0xf7, + 0x87, 0xf3, 0x3f, 0x73, 0x5d, 0x12, 0xe8, 0x3b, 0x55, 0xb6, 0xcc, 0xc6, 0x85, 0xad, 0x9f, 0x9e, + }, + { + 0xe9, 0x97, 0xde, 0x7f, 0xe0, 0x9a, 0xc1, 0xdc, 0x96, 0x4c, 0xc3, 0x0d, 0x2d, 0xd4, 0x98, 0x54, + 0x89, 0x1c, 0x57, 0x7d, 0x17, 0x96, 0xe9, 0x2f, 0x02, 0x73, 0x07, 0x5c, 0x8b, 0x44, 0xd7, 0x75, + }, + { + 0xaf, 0xf2, 0x39, 0xc4, 0x23, 0xff, 0xd5, 0x85, 0xf3, 0x11, 0x44, 0x9e, 0xab, 0x59, 0x29, 0x33, + 0xe6, 0xc2, 0x1d, 0xba, 0xa8, 0x5b, 0x70, 0xc3, 0xc0, 0xf8, 0x56, 0x3b, 0x8e, 0x43, 0x4c, 0x4b, + }, + { + 0x46, 0x93, 0xb5, 0x8a, 0x71, 0x67, 0xcb, 0x42, 0x6b, 0x1b, 0x43, 0x58, 0x8b, 0x18, 0xb9, 0xf3, + 0xdc, 0x91, 0x1c, 0x08, 0x83, 0xe3, 0x63, 0xfa, 0xf9, 0x99, 0x99, 0xcb, 0x05, 0x15, 0x7b, 0x85, + }, + { + 0xcf, 0xc6, 0x3c, 0x01, 0xbd, 0xfb, 0x00, 0x8c, 0x8b, 0x07, 0x69, 0xac, 0x61, 0xdb, 0x30, 0xd5, + 0x7c, 0x71, 0x98, 0x69, 0x2e, 0x4a, 0x4a, 0x44, 0xe4, 0x72, 0x6f, 0xf2, 0x9d, 0x58, 0x02, 0x23, + }, + { + 0x29, 0x10, 0xe1, 0xe5, 0x3f, 0xe6, 0x26, 0xaf, 0x30, 0x3c, 0xfe, 0x1f, 0x97, 0x21, 0xdd, 0x8c, + 0xbb, 0x90, 0xdb, 0x2a, 0xb5, 0xb4, 0x46, 0x43, 0x50, 0x0b, 0x6b, 0xa8, 0x8f, 0x55, 0xfb, 0xd2, + }, + { + 0x89, 0x56, 0x19, 0xf9, 0x4a, 0xec, 0x38, 0x99, 0xaa, 0xcc, 0xc5, 0x15, 0xdf, 0x19, 0xee, 0x1a, + 0xc0, 0x94, 0xaf, 0x0f, 0x7b, 0xf4, 0x06, 0xf1, 0x70, 0xa3, 0x79, 0x06, 0xba, 0x4e, 0x09, 0xa6, + }, + { + 0x53, 0x3a, 0x35, 0x98, 0xa9, 0xcb, 0x2c, 0x72, 0x73, 0xb2, 0xb0, 0x63, 0x38, 0xfc, 0xa3, 0xa5, + 0xa3, 0xf1, 0x4d, 0x04, 0x2f, 0x1b, 0x83, 0xbd, 0xed, 0x20, 0x8e, 0xa5, 0x1e, 0x9d, 0xd6, 0x69, + }, + { + 0x78, 0x44, 0xe3, 0x22, 0xa4, 0x7c, 0x53, 0xef, 0x60, 0x8e, 0x39, 0x95, 0x7d, 0x9d, 0x3d, 0x0b, + 0x4a, 0x4f, 0xf4, 0x73, 0xf8, 0xfe, 0xe7, 0x65, 0x86, 0x72, 0x13, 0x0b, 0x4e, 0x8f, 0x4d, 0x7b, + }, + { + 0x46, 0xba, 0xd2, 0x82, 0x46, 0x18, 0x6e, 0x46, 0x96, 0x05, 0x1d, 0xfb, 0xf6, 0xde, 0xba, 0xb5, + 0x6b, 0x73, 0x7a, 0xd5, 0x76, 0x11, 0xb7, 0x7c, 0x0d, 0x61, 0xba, 0xf9, 0x05, 0x12, 0x2b, 0x4e, + }, + { + 0x41, 0x08, 0x8b, 0x63, 0x10, 0xeb, 0x85, 0x10, 0xf3, 0x05, 0x84, 0xc0, 0x81, 0x1f, 0x7f, 0xd3, + 0x9d, 0x01, 0xdc, 0x32, 0xd0, 0xe2, 0xd1, 0xd1, 0x41, 0x8a, 0xa0, 0xf2, 0x64, 0xda, 0x8b, 0x0e, + }, + { + 0x99, 0xf1, 0xf2, 0x88, 0xe8, 0x72, 0x8b, 0x40, 0x17, 0xcc, 0xa7, 0x4c, 0x7d, 0xf1, 0xc4, 0x3f, + 0xbf, 0xf8, 0xbe, 0xc9, 0xce, 0xce, 0x2b, 0xe9, 0x4d, 0x5b, 0xd1, 0xef, 0x76, 0xae, 0x3b, 0xbb, + }, + { + 0x64, 0x69, 0x47, 0x03, 0xe9, 0x3b, 0xc2, 0x2d, 0x2d, 0x1a, 0xdd, 0xa4, 0xac, 0xb6, 0x6e, 0x7a, + 0x41, 0x7d, 0x82, 0xed, 0x54, 0xf7, 0x05, 0xd8, 0xae, 0x07, 0x6c, 0x1c, 0xf6, 0x51, 0xa1, 0xc0, + }, + { + 0x84, 0xaf, 0xe8, 0x59, 0x0c, 0x14, 0x24, 0xec, 0xa0, 0xd2, 0xf3, 0x8f, 0x2f, 0x22, 0xe4, 0x52, + 0xf8, 0xa7, 0x39, 0x74, 0x7f, 0x80, 0x23, 0x3f, 0x30, 0xe3, 0xcb, 0x26, 0x12, 0x5c, 0xa7, 0x93, + }, + { + 0x48, 0xc8, 0x41, 0x42, 0xc5, 0xe7, 0x4d, 0x91, 0x54, 0xa6, 0x5b, 0xba, 0x46, 0x89, 0xd5, 0x42, + 0x46, 0xbc, 0xf2, 0x67, 0x4a, 0xf9, 0x88, 0xe9, 0x02, 0xa5, 0xc2, 0x38, 0x9d, 0x6a, 0x75, 0xcd, + }, + { + 0xab, 0x9b, 0x2c, 0x09, 0xda, 0xaa, 0xe9, 0xe2, 0xd7, 0xf1, 0xa4, 0x86, 0x41, 0x14, 0xcb, 0x4e, + 0x2b, 0xd1, 0x5a, 0x9a, 0x46, 0x47, 0x90, 0xb2, 0x63, 0x16, 0xcb, 0x60, 0x1c, 0x12, 0xe3, 0x2b, + }, + { + 0x54, 0x21, 0xc0, 0xbc, 0xb8, 0x29, 0xce, 0xa4, 0xf2, 0x38, 0xb4, 0x0d, 0x7d, 0xfa, 0xd4, 0x3e, + 0x28, 0xf4, 0xc4, 0xf4, 0x4a, 0x9f, 0x11, 0xf2, 0xe2, 0x31, 0xa3, 0x72, 0x16, 0xbb, 0xd9, 0x05, + }, + { + 0xdc, 0x6e, 0xbe, 0x64, 0xa2, 0xb2, 0x64, 0x46, 0x00, 0xee, 0xd2, 0xa5, 0x81, 0x86, 0x44, 0xa4, + 0x5c, 0xc4, 0xba, 0xc4, 0xa2, 0x44, 0x36, 0x77, 0xb2, 0xec, 0x0d, 0xbe, 0x8f, 0xc0, 0x80, 0x6f, + }, + { + 0x51, 0x51, 0xb2, 0x50, 0x11, 0x0b, 0x60, 0xb8, 0x8e, 0xc2, 0xf7, 0xa8, 0xb4, 0xd2, 0x48, 0xc3, + 0x51, 0x43, 0x52, 0xeb, 0x37, 0xac, 0xd0, 0xf7, 0x61, 0xa1, 0xe9, 0xe3, 0xa7, 0xdf, 0x26, 0xa9, + }, + { + 0x10, 0xd9, 0xf2, 0xfe, 0x71, 0x8e, 0x49, 0x2c, 0x64, 0x53, 0xb0, 0x9e, 0x7a, 0xcc, 0x86, 0xab, + 0x06, 0xd7, 0xc7, 0x13, 0xd1, 0xcb, 0x21, 0x42, 0x97, 0x29, 0x5d, 0xff, 0xaa, 0xec, 0x52, 0x40, + }, + { + 0x7b, 0x35, 0x93, 0xb9, 0xca, 0xbb, 0x7e, 0x09, 0x8f, 0x34, 0x32, 0x02, 0xe7, 0x0c, 0xcf, 0xd1, + 0x6c, 0x2d, 0x11, 0xcd, 0xa5, 0x3b, 0xba, 0x14, 0x47, 0xc5, 0x2c, 0xb8, 0xf6, 0xfb, 0x9d, 0x77, + }, + { + 0x45, 0xce, 0x12, 0x8e, 0xa2, 0x4e, 0x56, 0x58, 0xa7, 0xcf, 0x26, 0x4e, 0x32, 0x21, 0xe0, 0x2b, + 0xed, 0x8d, 0xe2, 0xd9, 0x51, 0x32, 0x9b, 0xdc, 0x7b, 0x0e, 0x14, 0x0a, 0xdb, 0x63, 0x6b, 0x42, + }, + { + 0x9d, 0x49, 0x72, 0xea, 0x89, 0xc7, 0xa2, 0xfd, 0x9a, 0x55, 0xd7, 0x05, 0x16, 0xeb, 0xf7, 0x49, + 0xb6, 0xcf, 0x56, 0xf7, 0x2b, 0xef, 0x6d, 0xbe, 0xdd, 0x0e, 0x90, 0x01, 0xaf, 0x1b, 0xbb, 0xaa, + }, + { + 0x2c, 0xb7, 0x26, 0x43, 0x02, 0xc5, 0x7b, 0xc6, 0x71, 0x1f, 0xf2, 0x28, 0xb4, 0xea, 0x5f, 0x02, + 0xc6, 0xeb, 0xb4, 0xf7, 0x6f, 0x01, 0x7f, 0xfe, 0x3a, 0xb0, 0xe3, 0xf3, 0x31, 0xd3, 0xcb, 0x0f, + }, + { + 0x75, 0x54, 0x90, 0xec, 0xed, 0xcc, 0xbc, 0x5c, 0x9b, 0x44, 0x30, 0x57, 0x57, 0xe0, 0xec, 0x58, + 0x20, 0x54, 0x20, 0xb0, 0x92, 0x3a, 0x06, 0x9f, 0x69, 0xcb, 0x88, 0xee, 0x52, 0x6e, 0x4c, 0xf6, + }, + { + 0x2a, 0x08, 0xd8, 0xdd, 0x2e, 0x07, 0x54, 0x0b, 0x37, 0xc6, 0x09, 0x26, 0x98, 0xf7, 0x45, 0xf6, + 0x05, 0x4f, 0x35, 0xe6, 0xb0, 0x44, 0xff, 0x62, 0x89, 0x47, 0x69, 0x30, 0xea, 0x3b, 0x7b, 0x81, + }, + { + 0x0f, 0x7f, 0x34, 0xbf, 0xf9, 0xce, 0xe7, 0x4c, 0xe1, 0x7a, 0x24, 0x74, 0xeb, 0x8b, 0xb0, 0x65, + 0x18, 0x19, 0xaf, 0x44, 0x45, 0x5e, 0xd9, 0xa4, 0xf0, 0xd8, 0xe8, 0x09, 0x22, 0x58, 0x4e, 0x4d, + }, + { + 0x48, 0x41, 0x7a, 0xd2, 0x26, 0xda, 0x39, 0xb2, 0xba, 0x03, 0x17, 0xe9, 0x80, 0x8e, 0x53, 0x4c, + 0xac, 0x64, 0x6b, 0xa7, 0x5f, 0xed, 0x64, 0x60, 0xb7, 0x5e, 0x7a, 0x68, 0x1a, 0x8a, 0xda, 0x2b, + }, + { + 0x52, 0x01, 0x25, 0xb0, 0x59, 0xcf, 0x61, 0x30, 0x52, 0xe7, 0x77, 0x66, 0xc9, 0x35, 0xac, 0xfe, + 0xc0, 0xa2, 0x18, 0x58, 0xf1, 0xc1, 0x8f, 0x28, 0x72, 0x2f, 0xdc, 0x36, 0x10, 0x5b, 0xd9, 0x6f, + }, + { + 0x05, 0xbf, 0x47, 0x32, 0x0e, 0xa7, 0xc6, 0xd6, 0x13, 0xa1, 0x72, 0x38, 0x8c, 0x1a, 0xbc, 0x6d, + 0x7c, 0xd8, 0x34, 0xac, 0x69, 0x5b, 0x43, 0xc4, 0x00, 0xf8, 0xf2, 0xa7, 0xaf, 0x9f, 0xb0, 0xde, + }, + { + 0x54, 0x67, 0xce, 0xf2, 0xfc, 0x91, 0xd2, 0x4d, 0x73, 0xc6, 0xc9, 0xc3, 0xfe, 0xcf, 0x72, 0xa0, + 0xc7, 0x43, 0xff, 0x87, 0x4b, 0xe3, 0x7f, 0xba, 0xd4, 0xa2, 0xa3, 0x14, 0x8f, 0xa0, 0x39, 0x91, + }, + { + 0xbd, 0x24, 0x35, 0xb5, 0x0e, 0x7a, 0x13, 0xb3, 0x92, 0x83, 0xaa, 0xbd, 0x0c, 0x22, 0x93, 0xbb, + 0x2a, 0xe7, 0x7a, 0x56, 0x2d, 0xae, 0x41, 0x62, 0x52, 0xb2, 0xe9, 0xbd, 0x29, 0x05, 0x51, 0x95, + }, + { + 0x97, 0x8f, 0x21, 0x82, 0x72, 0x4f, 0x65, 0xc8, 0xfc, 0x2e, 0x5e, 0x8a, 0x1a, 0xce, 0x34, 0x39, + 0x12, 0xe6, 0x9b, 0xc3, 0xab, 0x51, 0xa9, 0x40, 0xf7, 0xbe, 0x94, 0xd0, 0x66, 0xda, 0xa5, 0x39, + }, + { + 0x5a, 0x48, 0x43, 0x9a, 0x8e, 0x22, 0x85, 0x9b, 0x28, 0xc9, 0x63, 0xa2, 0x57, 0xa6, 0xe2, 0x16, + 0x64, 0xec, 0x3c, 0x59, 0x13, 0xc4, 0x7b, 0x51, 0xea, 0xfe, 0x2e, 0x70, 0xbd, 0xd9, 0x77, 0x85, + }, + { + 0x2b, 0x74, 0xb6, 0x95, 0x18, 0x94, 0x54, 0x6d, 0xae, 0xdd, 0xe9, 0xb2, 0xf9, 0xbd, 0xce, 0x27, + 0xa9, 0x87, 0x42, 0x13, 0x22, 0x29, 0x87, 0x7a, 0x04, 0xe3, 0xbe, 0x2f, 0x9c, 0x18, 0xbb, 0x13, + }, + { + 0x80, 0x95, 0x43, 0xaa, 0x19, 0x90, 0x03, 0x4f, 0x47, 0xbf, 0xf5, 0x8e, 0x2d, 0x55, 0x23, 0xb7, + 0x7b, 0x5d, 0xaa, 0x34, 0x37, 0xb2, 0x70, 0x86, 0x5e, 0xc4, 0x94, 0xf3, 0x61, 0xfd, 0x87, 0x65, + }, + { + 0xd4, 0xbc, 0x03, 0x65, 0xb0, 0xc5, 0x44, 0x81, 0x7b, 0x06, 0x94, 0x79, 0xca, 0x1f, 0xe2, 0x28, + 0x53, 0xc8, 0xa7, 0x10, 0x13, 0x77, 0xb7, 0x5c, 0x9a, 0x34, 0x1e, 0xd5, 0x78, 0xb1, 0x21, 0x61, + }, + { + 0x90, 0x0e, 0x7f, 0xa3, 0x24, 0x18, 0x12, 0xbf, 0x45, 0xd2, 0x52, 0xa3, 0x99, 0x74, 0x89, 0xd2, + 0x12, 0x8d, 0x32, 0x3c, 0xd0, 0x28, 0x54, 0x98, 0x6c, 0x9e, 0xdd, 0xc0, 0xd5, 0xf1, 0x8a, 0xb1, + }, + { + 0x82, 0xad, 0x7a, 0x5c, 0x4d, 0x81, 0x54, 0x41, 0x79, 0x42, 0x54, 0x5c, 0x49, 0x41, 0xed, 0x49, + 0xc7, 0x06, 0x61, 0xbb, 0x89, 0x2b, 0x90, 0x04, 0x1f, 0x8c, 0x31, 0x3b, 0x39, 0x4f, 0xf8, 0x33, + }, +}; +static const u8 invert[63][32] = { + { + 0x95, 0xb2, 0xa8, 0xe3, 0xac, 0xcf, 0x27, 0x3e, 0x1c, 0xa3, 0xcf, 0x7a, 0x20, 0xb4, 0x52, 0x83, + 0x0e, 0x21, 0x2d, 0xfe, 0x6f, 0x2e, 0x38, 0x13, 0x01, 0x2e, 0xa0, 0x58, 0x58, 0x6d, 0x4a, 0x6f, + }, + { + 0x63, 0x26, 0x5c, 0xd2, 0x9a, 0xc6, 0x8c, 0x5d, 0xc2, 0x0d, 0xba, 0x4f, 0x79, 0x88, 0xd1, 0x15, + 0x64, 0x55, 0x90, 0x7b, 0x76, 0x2d, 0x60, 0x04, 0x92, 0x77, 0x18, 0xd0, 0xba, 0x7f, 0xee, 0x3a, + }, + { + 0x57, 0xc1, 0x0b, 0x23, 0x06, 0x57, 0x0c, 0xde, 0xa1, 0xa5, 0x8d, 0xc6, 0x8e, 0xbd, 0x9e, 0x09, + 0xe5, 0xed, 0xe3, 0xfb, 0xb1, 0xa0, 0xda, 0x73, 0xfc, 0x3e, 0x5e, 0x6d, 0x38, 0x36, 0x26, 0xec, + }, + { + 0x8e, 0xe5, 0x30, 0x36, 0x9e, 0x30, 0x82, 0x02, 0xf6, 0x7c, 0x06, 0x71, 0xbb, 0x6e, 0x09, 0x68, + 0x16, 0xca, 0x10, 0x32, 0x90, 0xcc, 0x7a, 0x99, 0x18, 0x70, 0xe6, 0xe7, 0x3a, 0x78, 0x86, 0xe6, + }, + { + 0x18, 0x98, 0x14, 0xa7, 0xb7, 0x1f, 0x24, 0xed, 0xd0, 0xfc, 0x71, 0xa0, 0x7e, 0xef, 0xdd, 0xe2, + 0xa2, 0xf8, 0x2a, 0xc2, 0x5d, 0x94, 0x03, 0x13, 0x29, 0x39, 0x86, 0xed, 0x08, 0x99, 0x83, 0xab, + }, + { + 0xcd, 0x22, 0xa0, 0xbc, 0xea, 0xe7, 0xde, 0xca, 0x0c, 0x72, 0xbd, 0xf7, 0x40, 0x46, 0x92, 0xc5, + 0xa4, 0xf3, 0x48, 0x9a, 0x8f, 0x52, 0xab, 0x19, 0x07, 0x98, 0xae, 0x9b, 0xe7, 0xfc, 0xbd, 0x05, + }, + { + 0xd2, 0xce, 0x28, 0x79, 0x3f, 0xdd, 0xa1, 0x1c, 0x21, 0xe4, 0xeb, 0x54, 0x85, 0x5c, 0x9d, 0x64, + 0xd5, 0x5b, 0xb6, 0x06, 0x43, 0xcc, 0x80, 0x8b, 0xe3, 0xdb, 0x26, 0xf5, 0x7e, 0x5f, 0x81, 0x9d, + }, + { + 0x54, 0x42, 0xe9, 0x30, 0xd2, 0x2c, 0xba, 0x16, 0xa7, 0x99, 0x28, 0xe7, 0x54, 0x61, 0xee, 0x17, + 0xf0, 0x70, 0x34, 0xe2, 0xe7, 0x66, 0x16, 0x00, 0x95, 0x7b, 0xbd, 0xd8, 0x07, 0xab, 0xa9, 0x5b, + }, + { + 0xe7, 0x58, 0x21, 0x24, 0x0e, 0x32, 0xbd, 0x6b, 0xcb, 0xa6, 0xd9, 0x91, 0xd7, 0xfd, 0xe4, 0x4c, + 0x58, 0xd6, 0x06, 0x11, 0x02, 0x90, 0xe5, 0x1d, 0x91, 0x2f, 0x0f, 0x43, 0xe3, 0xc7, 0x66, 0xd8, + }, + { + 0x45, 0x65, 0x5e, 0x17, 0xe1, 0x00, 0xfd, 0x42, 0x30, 0x25, 0x0e, 0xa5, 0x26, 0x8a, 0x17, 0xfe, + 0xd0, 0xa2, 0xff, 0x7a, 0x09, 0xd3, 0x5a, 0xb4, 0x71, 0x84, 0x29, 0x03, 0x71, 0x70, 0x9b, 0x6e, + }, + { + 0xc7, 0x2d, 0xe6, 0xef, 0xba, 0x0b, 0x97, 0x9a, 0x91, 0xf2, 0xda, 0x26, 0x62, 0xe5, 0xbe, 0x5d, + 0xc5, 0x5d, 0x71, 0xc1, 0xb7, 0x3f, 0xb3, 0xb8, 0x74, 0xd0, 0x0c, 0x03, 0x74, 0xc0, 0x0c, 0xe4, + }, + { + 0x56, 0x38, 0x1e, 0x31, 0xca, 0x3b, 0xb5, 0xc4, 0xff, 0x5a, 0x9e, 0x86, 0xfe, 0x98, 0x0c, 0x27, + 0x23, 0x2c, 0xa0, 0x76, 0x6f, 0xae, 0xf3, 0xde, 0x71, 0x40, 0x0c, 0xdc, 0x41, 0xf9, 0x89, 0x99, + }, + { + 0x2c, 0x27, 0xed, 0x69, 0x50, 0x53, 0xc5, 0x97, 0xf4, 0x88, 0x9a, 0x2b, 0xce, 0x8a, 0xc5, 0xfb, + 0x0d, 0xbc, 0x6f, 0x9c, 0x84, 0x30, 0xf3, 0xcb, 0xc1, 0x30, 0xa4, 0xb5, 0x46, 0xd4, 0xcb, 0xea, + }, + { + 0xb7, 0xf0, 0x86, 0x66, 0xd3, 0x55, 0x64, 0xc9, 0x1b, 0x9b, 0x3d, 0x79, 0x13, 0x0a, 0x3e, 0xa1, + 0xcf, 0x54, 0x17, 0x77, 0xeb, 0x32, 0x1c, 0x47, 0x7d, 0xf0, 0xb4, 0x11, 0x3d, 0xd7, 0xef, 0x04, + }, + { + 0xf7, 0x7e, 0x71, 0xb6, 0x5e, 0xed, 0xf3, 0xfb, 0x56, 0x82, 0x22, 0x61, 0x29, 0xa2, 0x5d, 0xc6, + 0xcd, 0x03, 0x47, 0xc7, 0xcc, 0xe4, 0xf2, 0xa4, 0x3f, 0xed, 0x36, 0xae, 0xa7, 0x30, 0x84, 0x22, + }, + { + 0x13, 0x70, 0xe7, 0x97, 0x14, 0xfa, 0xa9, 0xb7, 0xd5, 0xa1, 0xa4, 0xfd, 0xe8, 0x0c, 0x92, 0xcf, + 0xc4, 0xdc, 0x5d, 0xb9, 0xa4, 0xa2, 0x16, 0xf8, 0x67, 0xdc, 0x12, 0x47, 0xb7, 0x75, 0xfd, 0x3c, + }, + { + 0x29, 0xaa, 0xdd, 0xb5, 0xdc, 0x7f, 0xce, 0xad, 0x02, 0x65, 0x27, 0x5e, 0xa5, 0x5d, 0x23, 0x0f, + 0xa7, 0x51, 0x4d, 0xf2, 0x7d, 0x2a, 0x31, 0xbf, 0x32, 0x3b, 0x80, 0xe3, 0xda, 0x56, 0xdb, 0xfc, + }, + { + 0x70, 0xd0, 0x50, 0x6d, 0xf2, 0xb3, 0x6f, 0xc1, 0x9a, 0x98, 0x02, 0x87, 0xb5, 0x31, 0x3d, 0x19, + 0xaa, 0xf4, 0xd2, 0xd4, 0x48, 0xb1, 0x08, 0x06, 0x98, 0x39, 0x00, 0x06, 0x20, 0xe5, 0x0c, 0xe1, + }, + { + 0xe6, 0xaf, 0x94, 0xa0, 0xdf, 0xc3, 0x6b, 0xb4, 0xcf, 0x78, 0xc0, 0xe8, 0x56, 0xdc, 0xac, 0xbb, + 0x5e, 0x9e, 0xda, 0x90, 0x1e, 0x7f, 0x44, 0x06, 0xe0, 0x00, 0x6a, 0xd9, 0xd1, 0xf9, 0x56, 0xac, + }, + { + 0x15, 0xa2, 0x90, 0x13, 0x4f, 0xa0, 0x9d, 0x0d, 0x9c, 0xf8, 0xc9, 0x20, 0x1c, 0x8e, 0x68, 0xcb, + 0x1f, 0x75, 0xb3, 0xb2, 0x14, 0xff, 0x19, 0x20, 0x5f, 0x30, 0xb1, 0x05, 0x36, 0x7c, 0xa2, 0xed, + }, + { + 0x9a, 0xb2, 0xf5, 0xfd, 0x04, 0x3e, 0x6b, 0x4a, 0x1d, 0x3a, 0x63, 0x96, 0x00, 0xad, 0x6c, 0x7c, + 0x4f, 0xaf, 0x4d, 0xb5, 0x03, 0x4a, 0xf7, 0x28, 0x7f, 0x1f, 0x38, 0xad, 0xfd, 0xc7, 0x4b, 0x7f, + }, + { + 0xf4, 0x5a, 0x9f, 0xf6, 0xd0, 0x1a, 0x23, 0x76, 0xee, 0x15, 0x10, 0x2c, 0x30, 0xbd, 0x45, 0xfc, + 0x65, 0x60, 0x20, 0xc5, 0x9b, 0xb4, 0x42, 0x83, 0xe9, 0x03, 0xd5, 0xec, 0xba, 0xb2, 0x3b, 0xb8, + }, + { + 0xf4, 0x1b, 0xc1, 0x73, 0x1a, 0x6c, 0x88, 0xfd, 0xc2, 0xfb, 0xe8, 0x7e, 0xcb, 0x8a, 0x0e, 0x0e, + 0x6a, 0x13, 0x54, 0xb0, 0x7b, 0xb8, 0x68, 0x90, 0x21, 0x38, 0x4e, 0x1f, 0x86, 0x51, 0x14, 0x2c, + }, + { + 0x6c, 0xd3, 0xc3, 0x8f, 0x06, 0x45, 0xec, 0x65, 0x87, 0x02, 0x3d, 0x89, 0x61, 0xde, 0x80, 0x42, + 0xf6, 0xe0, 0x8d, 0x91, 0xf0, 0x3a, 0x7a, 0x66, 0xba, 0x1c, 0xc7, 0xb6, 0x3d, 0xc4, 0x7f, 0x91, + }, + { + 0x53, 0xf6, 0x90, 0x34, 0x88, 0x3e, 0xb7, 0xef, 0x56, 0x39, 0x6e, 0x1f, 0x48, 0x14, 0xe4, 0x09, + 0xc6, 0xea, 0xc4, 0xd9, 0xed, 0x2e, 0x2e, 0x33, 0x03, 0x00, 0xb9, 0xac, 0x22, 0x65, 0xe9, 0x1b, + }, + { + 0x55, 0x78, 0x89, 0x36, 0xa0, 0x07, 0xa6, 0x99, 0xbf, 0x7c, 0xb5, 0xbd, 0xb6, 0x1e, 0xc3, 0x58, + 0xb3, 0x0f, 0x78, 0x64, 0x74, 0x77, 0x00, 0x50, 0x2e, 0x4c, 0x6a, 0xa1, 0xe8, 0x93, 0x89, 0x5d, + }, + { + 0x09, 0xf8, 0xdd, 0xe0, 0x42, 0xa4, 0x2e, 0x9d, 0xff, 0x0e, 0x70, 0x73, 0x9c, 0x87, 0xa0, 0x81, + 0x4d, 0xb1, 0xc3, 0xf3, 0xff, 0x96, 0x3b, 0x2a, 0xdf, 0x6d, 0x97, 0xba, 0x06, 0xa7, 0x7e, 0x0a, + }, + { + 0x1f, 0x46, 0xb4, 0x72, 0x14, 0x5b, 0x85, 0x01, 0x83, 0xcc, 0x24, 0x17, 0xc2, 0x07, 0xda, 0x60, + 0x6c, 0xab, 0xfa, 0xe5, 0xd9, 0xb4, 0xf0, 0x3f, 0xca, 0xf1, 0x30, 0x8d, 0xd2, 0x4e, 0xe3, 0xb4, + }, + { + 0x4f, 0xb3, 0x0d, 0x98, 0x38, 0x70, 0x28, 0xa2, 0xca, 0x5d, 0x2c, 0xdf, 0x1f, 0xce, 0xff, 0xcc, + 0x75, 0x49, 0xa0, 0xef, 0x54, 0xd9, 0x32, 0x1b, 0x17, 0xb6, 0x7e, 0x7a, 0xa6, 0x5f, 0x7a, 0xff, + }, + { + 0x81, 0x6b, 0x06, 0x73, 0x5b, 0x32, 0x0d, 0x37, 0xb4, 0x50, 0x63, 0x52, 0x25, 0x72, 0x5c, 0xf5, + 0x5d, 0x58, 0xa6, 0xbf, 0x08, 0xcc, 0x1d, 0x70, 0x2d, 0x12, 0x5d, 0xd7, 0xbd, 0xca, 0xe7, 0x10, + }, + { + 0x8f, 0xfc, 0x57, 0x17, 0xce, 0x47, 0x10, 0x79, 0xae, 0x66, 0xa5, 0xcc, 0x98, 0x0b, 0x77, 0xe8, + 0xa2, 0x6e, 0xc1, 0x0d, 0x03, 0xe3, 0x5b, 0xed, 0x38, 0x0e, 0x31, 0x2d, 0x19, 0x4d, 0xd6, 0x2a, + }, + { + 0xc6, 0x9d, 0x2d, 0x0b, 0xad, 0x6d, 0x0c, 0x61, 0x2d, 0x62, 0xe4, 0xce, 0x73, 0x47, 0x72, 0x20, + 0x0c, 0x8e, 0x8f, 0xe9, 0xe7, 0x67, 0x66, 0x2e, 0x17, 0x54, 0xec, 0x15, 0x3e, 0x1b, 0xf3, 0x04, + }, + { + 0xf4, 0xee, 0x03, 0x30, 0x2e, 0x1e, 0xa4, 0xb1, 0x86, 0x6d, 0xc3, 0x54, 0xf3, 0xc5, 0x61, 0xa6, + 0xb9, 0x28, 0x29, 0x11, 0x91, 0xcb, 0xbd, 0xc9, 0x77, 0x62, 0x09, 0x8c, 0xa4, 0x40, 0x84, 0x97, + }, + { + 0xff, 0x98, 0x9b, 0xbc, 0xc2, 0xf0, 0xf8, 0x7f, 0x5c, 0x86, 0x74, 0x33, 0xee, 0x42, 0x6e, 0xab, + 0xd4, 0xd2, 0x1a, 0x0d, 0x41, 0x2d, 0xac, 0xa1, 0x3e, 0x56, 0xed, 0x4b, 0x27, 0x5a, 0x65, 0xe4, + }, + { + 0x2b, 0xb1, 0xe3, 0x64, 0xaa, 0x32, 0x17, 0x57, 0x7c, 0x67, 0xb8, 0x6b, 0x00, 0x53, 0xbe, 0x3e, + 0xec, 0xd1, 0x1b, 0xc4, 0xc3, 0x8d, 0xe6, 0x19, 0xe8, 0x3a, 0x25, 0x98, 0x4e, 0xe9, 0xd4, 0x60, + }, + { + 0xa6, 0x2e, 0xb3, 0xc8, 0xcd, 0xc9, 0xc2, 0x8e, 0xe1, 0xf0, 0x8f, 0x96, 0x8e, 0xc6, 0x37, 0x11, + 0xbc, 0x6c, 0x0c, 0xf6, 0xb6, 0x83, 0x38, 0x96, 0x7a, 0x74, 0x5a, 0xa7, 0xe1, 0x11, 0x8d, 0x8b, + }, + { + 0x90, 0xf2, 0x4d, 0xbd, 0x83, 0x39, 0xe6, 0x54, 0xf6, 0x75, 0xf6, 0x2c, 0x28, 0x3d, 0xd1, 0xcf, + 0xe1, 0xfb, 0x9f, 0x97, 0x19, 0xca, 0x4d, 0x2c, 0x38, 0x3d, 0x36, 0xed, 0x19, 0xe9, 0x4a, 0x0b, + }, + { + 0x1a, 0x61, 0xb8, 0x19, 0x59, 0x16, 0x74, 0xec, 0xdb, 0x7b, 0xeb, 0xd6, 0xae, 0xcd, 0xe9, 0x55, + 0xdb, 0x45, 0xdc, 0xf2, 0x35, 0x84, 0xe9, 0xe6, 0x17, 0x48, 0xac, 0x38, 0x05, 0x21, 0x2c, 0x8e, + }, + { + 0x41, 0xac, 0x17, 0x42, 0xcc, 0x17, 0x10, 0x02, 0x07, 0x7e, 0xfc, 0x4d, 0x77, 0x06, 0x70, 0xcb, + 0x40, 0x8b, 0x47, 0x47, 0x07, 0x29, 0x82, 0xca, 0x93, 0x69, 0x2f, 0x3a, 0x64, 0xc6, 0xcb, 0x23, + }, + { + 0xa2, 0xcb, 0x2d, 0x02, 0x5d, 0x30, 0x9f, 0x32, 0xf5, 0xc5, 0x13, 0xff, 0xfc, 0xe2, 0xfb, 0x26, + 0x3b, 0x3b, 0xaf, 0xa4, 0x37, 0x6d, 0x45, 0xbf, 0xdb, 0xb9, 0xee, 0xec, 0x92, 0xa5, 0x1d, 0x0d, + }, + { + 0xa4, 0xef, 0x08, 0xb7, 0xb4, 0x68, 0x74, 0x93, 0xb2, 0xda, 0xba, 0xe9, 0x05, 0xf5, 0x09, 0xb6, + 0x53, 0xdd, 0x17, 0x60, 0xbb, 0x1e, 0xb0, 0x71, 0xd8, 0x47, 0x85, 0x02, 0x13, 0xbe, 0xa2, 0x67, + }, + { + 0x31, 0x50, 0x90, 0xb0, 0x83, 0x4a, 0xcf, 0x3f, 0xbe, 0x88, 0x90, 0x4b, 0xe1, 0x9f, 0xe6, 0xd0, + 0xfd, 0x01, 0x8e, 0xfc, 0xc0, 0x8c, 0x2f, 0x9b, 0x48, 0x70, 0x9d, 0x4e, 0x22, 0x21, 0x07, 0x09, + }, + { + 0x15, 0x9f, 0x37, 0x45, 0x52, 0x99, 0x6e, 0xe9, 0x1a, 0x25, 0x56, 0x0b, 0x19, 0xf1, 0xca, 0x9f, + 0x29, 0xe5, 0x23, 0xa6, 0x0b, 0x94, 0x0a, 0xe3, 0x74, 0xaa, 0xd5, 0x35, 0xaf, 0x6e, 0xb2, 0x24, + }, + { + 0x68, 0xab, 0xa6, 0x8b, 0x5f, 0xc7, 0x93, 0x1a, 0x06, 0x51, 0x2c, 0x3b, 0xad, 0x44, 0x6b, 0x69, + 0x1a, 0x1d, 0x41, 0xca, 0x8e, 0x59, 0x2c, 0x83, 0x71, 0x48, 0x8c, 0xaf, 0x50, 0x85, 0x00, 0xf3, + }, + { + 0xe2, 0xa6, 0x38, 0x93, 0xca, 0xe3, 0xd0, 0x36, 0xf4, 0xe9, 0x53, 0xfb, 0xa0, 0xd0, 0x13, 0xd3, + 0x2b, 0x7d, 0x46, 0xc8, 0x8b, 0xc7, 0x8c, 0xca, 0x59, 0xec, 0x66, 0x17, 0x70, 0xbb, 0xf9, 0x92, + }, + { + 0x89, 0xca, 0x92, 0x19, 0x01, 0xb8, 0x4b, 0x97, 0x06, 0x1a, 0x12, 0x91, 0x72, 0x11, 0xeb, 0x12, + 0x8b, 0x12, 0xd9, 0xdc, 0xc9, 0xb2, 0x37, 0xf8, 0x3e, 0x02, 0x03, 0xbe, 0x45, 0x45, 0xc9, 0x42, + }, + { + 0x45, 0x2c, 0x80, 0xe1, 0x3a, 0x0a, 0xdf, 0xa3, 0xd2, 0x4a, 0x23, 0x0d, 0x47, 0x0d, 0x49, 0xad, + 0xdf, 0xb0, 0x42, 0xdf, 0x87, 0x85, 0xa6, 0x8f, 0x9f, 0x7e, 0x9b, 0xa4, 0x42, 0x64, 0xcb, 0xfb, + }, + { + 0xc7, 0x39, 0x26, 0xb1, 0x90, 0x4d, 0xc1, 0x7a, 0xea, 0x31, 0x1b, 0xae, 0x1a, 0x5c, 0x1f, 0x4f, + 0x44, 0x2f, 0x87, 0x08, 0x5d, 0xa6, 0x74, 0xfd, 0xab, 0xb2, 0x4b, 0x01, 0xed, 0xd5, 0x4c, 0xe6, + }, + { + 0x2a, 0xef, 0xfa, 0x25, 0x3c, 0xd2, 0xc8, 0x08, 0x9c, 0x33, 0x3c, 0x47, 0xb3, 0xb5, 0x44, 0x34, + 0x97, 0xee, 0xe8, 0x52, 0x1c, 0x15, 0xb3, 0xe0, 0xda, 0xef, 0x77, 0xde, 0x15, 0x39, 0x4b, 0x38, + }, + { + 0x8a, 0x3a, 0x59, 0x61, 0x9d, 0x3e, 0x9b, 0x38, 0xc9, 0x84, 0x80, 0xaf, 0xb4, 0x37, 0x8a, 0x67, + 0x47, 0xc9, 0x6c, 0x72, 0xef, 0x39, 0x50, 0x28, 0x6c, 0x8f, 0xad, 0x09, 0x75, 0x26, 0xc9, 0xa9, + }, + { + 0x27, 0x1e, 0x8b, 0xf6, 0x6b, 0x56, 0x5d, 0x17, 0x58, 0xac, 0xdf, 0x27, 0xd9, 0x3e, 0x5b, 0xdd, + 0xaf, 0xbc, 0xb7, 0xf9, 0x76, 0x3b, 0x40, 0x06, 0xbc, 0x6e, 0xec, 0xaa, 0xb2, 0xdc, 0x9a, 0x0c, + }, + { + 0x09, 0x14, 0xef, 0x19, 0xc7, 0x7d, 0xc8, 0xa3, 0xd0, 0xaa, 0x7f, 0x09, 0x18, 0xaf, 0xd3, 0xde, + 0xbf, 0x05, 0xfc, 0xf9, 0xeb, 0xc0, 0x8e, 0xcf, 0xc7, 0x4c, 0x2f, 0x3f, 0xd4, 0x51, 0x41, 0xb2, + }, + { + 0xb7, 0x33, 0xf3, 0x72, 0x6d, 0x12, 0xc1, 0x5c, 0x5d, 0x81, 0xb3, 0x63, 0x81, 0x50, 0x81, 0xc0, + 0x4a, 0xea, 0x18, 0x7c, 0xa6, 0x2d, 0x23, 0xba, 0x4b, 0xb9, 0x31, 0xd9, 0xab, 0x20, 0x60, 0x77, + }, + { + 0xbb, 0x1c, 0x50, 0x2d, 0xdc, 0x18, 0x27, 0x98, 0x60, 0xde, 0x17, 0xd9, 0x17, 0x3c, 0xd5, 0x98, + 0xc3, 0x12, 0xfd, 0x8b, 0x25, 0x1e, 0xa5, 0xc1, 0xa8, 0xef, 0xec, 0x05, 0x3e, 0xfc, 0xd1, 0xfc, + }, + { + 0xe6, 0x3b, 0x9f, 0x33, 0x85, 0xeb, 0x91, 0xd0, 0xad, 0x2f, 0xc2, 0x96, 0x61, 0x64, 0xbc, 0x12, + 0x15, 0x79, 0x65, 0x93, 0xc2, 0x63, 0xa3, 0x27, 0x88, 0x60, 0x39, 0x35, 0x21, 0x05, 0xe9, 0x49, + }, + { + 0x9b, 0x68, 0xe7, 0xc8, 0xea, 0x0e, 0x5c, 0xa4, 0x03, 0x3a, 0x4e, 0x31, 0xb1, 0x92, 0xad, 0x9d, + 0x7e, 0xb5, 0x93, 0x81, 0xdd, 0x7a, 0xe9, 0xa1, 0x69, 0x28, 0x6a, 0xaf, 0x48, 0x05, 0x94, 0xc0, + }, + { + 0x66, 0x3d, 0x87, 0xc1, 0x48, 0x9d, 0xdf, 0x99, 0x25, 0xd7, 0xb0, 0xfa, 0x03, 0x8b, 0x62, 0x60, + 0xc5, 0x07, 0x3f, 0xa2, 0xc8, 0xbd, 0x70, 0xdb, 0x40, 0x6c, 0x65, 0xbf, 0x15, 0xfc, 0x1e, 0xc9, + }, + { + 0x38, 0x9c, 0x1a, 0x5b, 0x4f, 0x84, 0xca, 0xe1, 0x30, 0x6a, 0xf0, 0xb6, 0xf1, 0x61, 0xd3, 0xb0, + 0xa6, 0x6d, 0x0d, 0x11, 0x03, 0xe0, 0xcb, 0x9f, 0xbe, 0x7e, 0xc2, 0x7a, 0x53, 0x9d, 0x39, 0xcb, + }, + { + 0xf3, 0x47, 0x4a, 0x37, 0xcd, 0x19, 0x27, 0x0f, 0xfb, 0x3f, 0xcb, 0x81, 0x1e, 0x0f, 0xfd, 0x1f, + 0x2e, 0x8d, 0xff, 0xe9, 0x52, 0x8b, 0x8e, 0x52, 0x3c, 0x82, 0xe6, 0x44, 0xf6, 0x92, 0xd4, 0xd4, + }, + { + 0x3a, 0xe8, 0x4d, 0xcc, 0x4a, 0x0e, 0xaa, 0xf6, 0x32, 0x88, 0x4c, 0xee, 0xaa, 0x9c, 0xeb, 0x59, + 0xb5, 0xb8, 0x06, 0x89, 0x49, 0xc9, 0xa6, 0xf7, 0xa6, 0x14, 0x44, 0x55, 0x5e, 0x3e, 0x86, 0x08, + }, + { + 0xca, 0x3d, 0x95, 0x21, 0xf3, 0xbb, 0x78, 0x29, 0x6a, 0x38, 0xd3, 0xe4, 0x48, 0x98, 0x6f, 0x0e, + 0xaf, 0x46, 0xa5, 0x02, 0xdd, 0xfb, 0x52, 0x42, 0x9b, 0x69, 0x97, 0xe6, 0x68, 0x21, 0x0d, 0x69, + }, + { + 0x3a, 0x8a, 0x14, 0x6e, 0xa2, 0x24, 0x8f, 0x89, 0x5e, 0x99, 0x8a, 0x5b, 0x90, 0xb1, 0xf3, 0x64, + 0x4d, 0x10, 0xef, 0x45, 0xa9, 0xfb, 0xbb, 0xc0, 0xf5, 0x66, 0xdf, 0x15, 0xae, 0xd0, 0xd9, 0x56, + }, + { + 0x62, 0x50, 0x52, 0xb5, 0xb9, 0x76, 0xa7, 0xcb, 0xe6, 0xf7, 0x3a, 0x9f, 0xa4, 0x1e, 0x0a, 0x4d, + 0x88, 0xa4, 0x1c, 0xea, 0x11, 0x8c, 0xfb, 0xbe, 0x70, 0x62, 0xec, 0x4e, 0x00, 0x56, 0x0e, 0xa9, + }, +}; diff --git a/src/southbridge/intel/bd82x6x/Makefile.inc b/src/southbridge/intel/bd82x6x/Makefile.inc index 64038e5..fa21277 100644 --- a/src/southbridge/intel/bd82x6x/Makefile.inc +++ b/src/southbridge/intel/bd82x6x/Makefile.inc @@ -45,10 +45,14 @@ smm-$(CONFIG_SPI_FLASH_SMM) += ../common/spi.c ramstage-$(CONFIG_HAVE_SMI_HANDLER) += smi.c smm-$(CONFIG_HAVE_SMI_HANDLER) += smihandler.c me.c me_8.x.c finalize.c pch.c -romstage-y += early_usb.c early_smbus.c early_me.c me_status.c gpio.c +romstage-y += early_usb.c early_smbus.c me_status.c gpio.c romstage-y += reset.c romstage-y += early_spi.c early_pch.c +romstage-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE) += early_me.c +romstage-$(CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE) += early_me.c +romstage-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE) += early_thermal.c early_pch_native.c early_me_native.c + ifeq ($(CONFIG_BUILD_WITH_FAKE_IFD),y) IFD_BIN_PATH := $(objgenerated)/ifdfake.bin IFD_SECTIONS := $(addprefix -b ,$(CONFIG_IFD_BIOS_SECTION:"%"=%)) \ diff --git a/src/southbridge/intel/bd82x6x/early_me_native.c b/src/southbridge/intel/bd82x6x/early_me_native.c new file mode 100644 index 0000000..ab54ffd --- /dev/null +++ b/src/southbridge/intel/bd82x6x/early_me_native.c @@ -0,0 +1,272 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011 The Chromium OS Authors. All rights reserved. + * + * 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 + */ + +#include <arch/hlt.h> +#include <arch/io.h> +#include <console/console.h> +#include <delay.h> +#include <device/pci_ids.h> +#include <string.h> +#include "me.h" +#include "pch.h" + +static const char *me_ack_values[] = { + [ME_HFS_ACK_NO_DID] = "No DID Ack received", + [ME_HFS_ACK_RESET] = "Non-power cycle reset", + [ME_HFS_ACK_PWR_CYCLE] = "Power cycle reset", + [ME_HFS_ACK_S3] = "Go to S3", + [ME_HFS_ACK_S4] = "Go to S4", + [ME_HFS_ACK_S5] = "Go to S5", + [ME_HFS_ACK_GBL_RESET] = "Global Reset", + [ME_HFS_ACK_CONTINUE] = "Continue to boot" +}; + +static inline void pci_read_dword_ptr(void *ptr, int offset) +{ + u32 dword = pci_read_config32(PCH_ME_DEV, offset); + memcpy(ptr, &dword, sizeof(dword)); +} + +static inline void pci_write_dword_ptr(void *ptr, int offset) +{ + u32 dword = 0; + memcpy(&dword, ptr, sizeof(dword)); + pci_write_config32(PCH_ME_DEV, offset, dword); +} + +void intel_early_me_status(void) +{ + struct me_hfs hfs; + struct me_gmes gmes; + + pci_read_dword_ptr(&hfs, PCI_ME_HFS); + pci_read_dword_ptr(&gmes, PCI_ME_GMES); + + intel_me_status(&hfs, &gmes); +} + +int intel_early_me_init(void) +{ + int count; + struct me_uma uma; + struct me_hfs hfs; + + printk(BIOS_INFO, "Intel ME early init\n"); + + /* Wait for ME UMA SIZE VALID bit to be set */ + for (count = ME_RETRY; count > 0; --count) { + pci_read_dword_ptr(&uma, PCI_ME_UMA); + if (uma.valid) + break; + udelay(ME_DELAY); + } + if (!count) { + printk(BIOS_ERR, "ERROR: ME is not ready!\n"); + return -1; + } + + /* Check for valid firmware */ + pci_read_dword_ptr(&hfs, PCI_ME_HFS); + if (hfs.fpt_bad) { + printk(BIOS_WARNING, "WARNING: ME has bad firmware\n"); + return -1; + } + + printk(BIOS_INFO, "Intel ME firmware is ready\n"); + return 0; +} + +int intel_early_me_uma_size(void) +{ + struct me_uma uma; + + pci_read_dword_ptr(&uma, PCI_ME_UMA); + if (uma.valid) { + printk(BIOS_DEBUG, "ME: Requested %uMB UMA\n", uma.size); + return uma.size; + } + + printk(BIOS_DEBUG, "ME: Invalid UMA size\n"); + return 0; +} + +static inline void set_global_reset(int enable) +{ + u32 etr3 = pci_read_config32(PCH_LPC_DEV, ETR3); + + /* Clear CF9 Without Resume Well Reset Enable */ + etr3 &= ~ETR3_CWORWRE; + + /* CF9GR indicates a Global Reset */ + if (enable) + etr3 |= ETR3_CF9GR; + else + etr3 &= ~ETR3_CF9GR; + + pci_write_config32(PCH_LPC_DEV, ETR3, etr3); +} + +int intel_early_me_init_done(u8 status) +{ + u8 reset, errorcode, opmode; + u16 reg16; + u32 mebase_l, mebase_h; + u32 millisec; + u32 hfs, me_fws2; + struct me_did did = { + .init_done = ME_INIT_DONE, + .status = status + }; + u32 meDID; + + hfs = (pci_read_config32(PCI_DEV(0, 0x16, 0), PCI_ME_HFS) & 0xff000) >> 12; + + opmode = (hfs & 0xf0) >> 4; + errorcode = hfs & 0xf; + + if (opmode != ME_HFS_MODE_NORMAL) { + printk(BIOS_NOTICE, "ME: Wrong mode : %d\n", opmode); + //return 0; + } + if (errorcode) { + printk(BIOS_NOTICE, "ME: HFS error : %d\n", errorcode); + //return 0; + } + + me_fws2 = pci_read_config32(PCI_DEV(0, 0x16, 0), 0x48); + printk(BIOS_NOTICE, "ME: FWS2: 0x%x\n", me_fws2); + printk(BIOS_NOTICE, "ME: Bist in progress: 0x%x\n", me_fws2 & 0x1); + printk(BIOS_NOTICE, "ME: ICC Status : 0x%x\n", (me_fws2 & 0x6) >> 1); + printk(BIOS_NOTICE, "ME: Invoke MEBx : 0x%x\n", (me_fws2 & 0x8) >> 3); + printk(BIOS_NOTICE, "ME: CPU replaced : 0x%x\n", (me_fws2 & 0x10) >> 4); + printk(BIOS_NOTICE, "ME: MBP ready : 0x%x\n", (me_fws2 & 0x20) >> 5); + printk(BIOS_NOTICE, "ME: MFS failure : 0x%x\n", (me_fws2 & 0x40) >> 6); + printk(BIOS_NOTICE, "ME: Warm reset req : 0x%x\n", (me_fws2 & 0x80) >> 7); + printk(BIOS_NOTICE, "ME: CPU repl valid : 0x%x\n", (me_fws2 & 0x100) >> 8); + printk(BIOS_NOTICE, "ME: (Reserved) : 0x%x\n", (me_fws2 & 0x600) >> 9); + printk(BIOS_NOTICE, "ME: FW update req : 0x%x\n", (me_fws2 & 0x800) >> 11); + printk(BIOS_NOTICE, "ME: (Reserved) : 0x%x\n", (me_fws2 & 0xf000) >> 12); + printk(BIOS_NOTICE, "ME: Current state : 0x%x\n", (me_fws2 & 0xff0000) >> 16); + printk(BIOS_NOTICE, "ME: Current PM event: 0x%x\n", (me_fws2 & 0xf000000) >> 24); + printk(BIOS_NOTICE, "ME: Progress code : 0x%x\n", (me_fws2 & 0xf0000000) >> 28); + + // Poll cpu replaced for 50ms + millisec = 0; + while ((((me_fws2 & 0x100) >> 8) == 0) && millisec < 50) { + udelay(1000); + me_fws2 = pci_read_config32(PCI_DEV(0, 0x16, 0), 0x48); + millisec++; + } + if (millisec >= 50 || ((me_fws2 & 0x100) >> 8) == 0x0) { + printk(BIOS_NOTICE, "Waited long enough, or CPU was not replaced, continue...\n"); + } else if ((me_fws2 & 0x100) == 0x100) { + if ((me_fws2 & 0x80) == 0x80) { + printk(BIOS_NOTICE, "CPU was replaced & warm reset required...\n"); + reg16 = pcie_read_config16(PCI_DEV(0, 31, 0), 0xa2) & ~0x80; + pcie_write_config16(PCI_DEV(0, 31, 0), 0xa2, reg16); + set_global_reset(0); + outb(0x6, 0xcf9); + hlt(); + } + + if (((me_fws2 & 0x10) == 0x10) && (me_fws2 & 0x80) == 0x00) { + printk(BIOS_NOTICE, "Full training required\n"); + } + } + + printk(BIOS_NOTICE, "PASSED! Tell ME that DRAM is ready\n"); + + /* MEBASE from MESEG_BASE[35:20] */ + mebase_l = pci_read_config32(PCI_CPU_DEVICE, PCI_CPU_MEBASE_L); + mebase_h = pci_read_config32(PCI_CPU_DEVICE, PCI_CPU_MEBASE_H) & 0xf; + did.uma_base = (mebase_l >> 20) | (mebase_h << 12); + + meDID = did.uma_base | (1 << 28);// | (1 << 23); + pci_write_config32(PCI_DEV(0, 0x16, 0), PCI_ME_H_GS, meDID); + + udelay(1100); + + /* Must wait for ME acknowledgement */ + millisec = 0; + hfs = (pci_read_config32(PCI_DEV(0, 0x16, 0), PCI_ME_HFS) & 0xfe000000) >> 24; + while ((((hfs & 0xf0) >> 4) != ME_HFS_BIOS_DRAM_ACK) && (millisec < 5000)) { + udelay(1000); + hfs = (pci_read_config32(PCI_DEV(0, 0x16, 0), PCI_ME_HFS) & 0xfe000000) >> 24; + millisec++; + } + + me_fws2 = pci_read_config32(PCI_DEV(0, 0x16, 0), 0x48); + printk(BIOS_NOTICE, "ME: FWS2: 0x%x\n", me_fws2); + printk(BIOS_NOTICE, "ME: Bist in progress: 0x%x\n", me_fws2 & 0x1); + printk(BIOS_NOTICE, "ME: ICC Status : 0x%x\n", (me_fws2 & 0x6) >> 1); + printk(BIOS_NOTICE, "ME: Invoke MEBx : 0x%x\n", (me_fws2 & 0x8) >> 3); + printk(BIOS_NOTICE, "ME: CPU replaced : 0x%x\n", (me_fws2 & 0x10) >> 4); + printk(BIOS_NOTICE, "ME: MBP ready : 0x%x\n", (me_fws2 & 0x20) >> 5); + printk(BIOS_NOTICE, "ME: MFS failure : 0x%x\n", (me_fws2 & 0x40) >> 6); + printk(BIOS_NOTICE, "ME: Warm reset req : 0x%x\n", (me_fws2 & 0x80) >> 7); + printk(BIOS_NOTICE, "ME: CPU repl valid : 0x%x\n", (me_fws2 & 0x100) >> 8); + printk(BIOS_NOTICE, "ME: (Reserved) : 0x%x\n", (me_fws2 & 0x600) >> 9); + printk(BIOS_NOTICE, "ME: FW update req : 0x%x\n", (me_fws2 & 0x800) >> 11); + printk(BIOS_NOTICE, "ME: (Reserved) : 0x%x\n", (me_fws2 & 0xf000) >> 12); + printk(BIOS_NOTICE, "ME: Current state : 0x%x\n", (me_fws2 & 0xff0000) >> 16); + printk(BIOS_NOTICE, "ME: Current PM event: 0x%x\n", (me_fws2 & 0xf000000) >> 24); + printk(BIOS_NOTICE, "ME: Progress code : 0x%x\n", (me_fws2 & 0xf0000000) >> 28); + + + /* Return the requested BIOS action */ + printk(BIOS_NOTICE, "ME: Requested BIOS Action: %s\n", + me_ack_values[(hfs & 0xe) >> 1]); + + reset = inb(0xcf9); + reset &= 0xf1; + switch ((hfs & 0xe) >> 1) { + case ME_HFS_ACK_NO_DID: + case ME_HFS_ACK_CONTINUE: + /* Continue to boot */ + return 0; + case ME_HFS_ACK_RESET: + /* Non-power cycle reset */ + set_global_reset(0); + reset |= 0x06; + break; + case ME_HFS_ACK_PWR_CYCLE: + /* Power cycle reset */ + set_global_reset(0); + reset |= 0x0e; + break; + case ME_HFS_ACK_GBL_RESET: + /* Global reset */ + set_global_reset(1); + reset |= 0x0e; + break; + case ME_HFS_ACK_S3: + case ME_HFS_ACK_S4: + case ME_HFS_ACK_S5: + break; + } + + /* Perform the requested reset */ + if (reset) { + outb(reset, 0xcf9); + hlt(); + } + return -1; +} diff --git a/src/southbridge/intel/bd82x6x/early_pch_native.c b/src/southbridge/intel/bd82x6x/early_pch_native.c new file mode 100644 index 0000000..5cd6315 --- /dev/null +++ b/src/southbridge/intel/bd82x6x/early_pch_native.c @@ -0,0 +1,375 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2014 Vladimir Serbinenko <phcoder(a)gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <console/console.h> +#include <string.h> +#include <arch/hlt.h> +#include <arch/io.h> +#include <cbmem.h> +#include <arch/cbfs.h> +#include <cbfs.h> +#include <ip_checksum.h> +#include <pc80/mc146818rtc.h> +#include <device/pci_def.h> +#include <delay.h> + +#include "pch.h" +/* For DMI bar. */ +#include "northbridge/intel/sandybridge/sandybridge.h" + +#define SOUTHBRIDGE PCI_DEV(0, 0x1f, 0) + +static void +wait_2338 (void) +{ + while (read8 (DEFAULT_RCBA | 0x2338) & 1); +} + +static u32 +read_2338 (u32 edx) +{ + u32 ret; + + write32 (DEFAULT_RCBA | 0x2330, edx); + write16 (DEFAULT_RCBA | 0x2338, (read16 (DEFAULT_RCBA | 0x2338) + & 0x1ff) | 0x600); + wait_2338 (); + ret = read32 (DEFAULT_RCBA | 0x2334); + wait_2338 (); + read8 (DEFAULT_RCBA | 0x2338); + return ret; +} + +static void +write_2338 (u32 edx, u32 val) +{ + read_2338 (edx); + write16 (DEFAULT_RCBA | 0x2338, (read16 (DEFAULT_RCBA | 0x2338) + & 0x1ff) | 0x600); + wait_2338 (); + + write32 (DEFAULT_RCBA | 0x2334, val); + wait_2338 (); + write16 (DEFAULT_RCBA | 0x2338, + (read16 (DEFAULT_RCBA | 0x2338) & 0x1ff) | 0x600); + read8 (DEFAULT_RCBA | 0x2338); +} + + +static void +init_dmi (void) +{ + int i; + + write32 (DEFAULT_DMIBAR | 0x0914, + read32 (DEFAULT_DMIBAR | 0x0914) | 0x80000000); + write32 (DEFAULT_DMIBAR | 0x0934, + read32 (DEFAULT_DMIBAR | 0x0934) | 0x80000000); + for (i = 0; i < 4; i++) + { + write32 (DEFAULT_DMIBAR | 0x0a00 | (i << 4), + read32 (DEFAULT_DMIBAR | 0x0a00 | (i << 4)) & 0xf3ffffff); + write32 (DEFAULT_DMIBAR | 0x0a04 | (i << 4), + read32 (DEFAULT_DMIBAR | 0x0a04 | (i << 4)) | 0x800); + } + write32 (DEFAULT_DMIBAR | 0x0c30, (read32 (DEFAULT_DMIBAR | 0x0c30) + & 0xfffffff) | 0x40000000); + for (i = 0; i < 2; i++) + { + write32 (DEFAULT_DMIBAR | 0x0904 | (i << 5), + read32 (DEFAULT_DMIBAR | 0x0904 | (i << 5)) & 0xfe3fffff); + write32 (DEFAULT_DMIBAR | 0x090c | (i << 5), + read32 (DEFAULT_DMIBAR | 0x090c | (i << 5)) & 0xfff1ffff); + } + write32 (DEFAULT_DMIBAR | 0x090c, + read32 (DEFAULT_DMIBAR | 0x090c) & 0xfe1fffff); + write32 (DEFAULT_DMIBAR | 0x092c, + read32 (DEFAULT_DMIBAR | 0x092c) & 0xfe1fffff); + read32 (DEFAULT_DMIBAR | 0x0904); // !!! = 0x7a1842ec + write32 (DEFAULT_DMIBAR | 0x0904, 0x7a1842ec); + read32 (DEFAULT_DMIBAR | 0x090c); // !!! = 0x00000208 + write32 (DEFAULT_DMIBAR | 0x090c, 0x00000128); + read32 (DEFAULT_DMIBAR | 0x0924); // !!! = 0x7a1842ec + write32 (DEFAULT_DMIBAR | 0x0924, 0x7a1842ec); + read32 (DEFAULT_DMIBAR | 0x092c); // !!! = 0x00000208 + write32 (DEFAULT_DMIBAR | 0x092c, 0x00000128); + read32 (DEFAULT_DMIBAR | 0x0700); // !!! = 0x46139008 + write32 (DEFAULT_DMIBAR | 0x0700, 0x46139008); + read32 (DEFAULT_DMIBAR | 0x0720); // !!! = 0x46139008 + write32 (DEFAULT_DMIBAR | 0x0720, 0x46139008); + read32 (DEFAULT_DMIBAR | 0x0c04); // !!! = 0x2e680008 + write32 (DEFAULT_DMIBAR | 0x0c04, 0x2e680008); + read32 (DEFAULT_DMIBAR | 0x0904); // !!! = 0x7a1842ec + write32 (DEFAULT_DMIBAR | 0x0904, 0x3a1842ec); + read32 (DEFAULT_DMIBAR | 0x0924); // !!! = 0x7a1842ec + write32 (DEFAULT_DMIBAR | 0x0924, 0x3a1842ec); + read32 (DEFAULT_DMIBAR | 0x0910); // !!! = 0x00006300 + write32 (DEFAULT_DMIBAR | 0x0910, 0x00004300); + read32 (DEFAULT_DMIBAR | 0x0930); // !!! = 0x00006300 + write32 (DEFAULT_DMIBAR | 0x0930, 0x00004300); + read32 (DEFAULT_DMIBAR | 0x0a00); // !!! = 0x03042010 + write32 (DEFAULT_DMIBAR | 0x0a00, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a10); // !!! = 0x03042010 + write32 (DEFAULT_DMIBAR | 0x0a10, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a20); // !!! = 0x03042010 + write32 (DEFAULT_DMIBAR | 0x0a20, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a30); // !!! = 0x03042010 + write32 (DEFAULT_DMIBAR | 0x0a30, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0c00); // !!! = 0x29700c08 + write32 (DEFAULT_DMIBAR | 0x0c00, 0x29700c08); + read32 (DEFAULT_DMIBAR | 0x0a04); // !!! = 0x0c0708f0 + write32 (DEFAULT_DMIBAR | 0x0a04, 0x0c0718f0); + read32 (DEFAULT_DMIBAR | 0x0a14); // !!! = 0x0c0708f0 + write32 (DEFAULT_DMIBAR | 0x0a14, 0x0c0718f0); + read32 (DEFAULT_DMIBAR | 0x0a24); // !!! = 0x0c0708f0 + write32 (DEFAULT_DMIBAR | 0x0a24, 0x0c0718f0); + read32 (DEFAULT_DMIBAR | 0x0a34); // !!! = 0x0c0708f0 + write32 (DEFAULT_DMIBAR | 0x0a34, 0x0c0718f0); + read32 (DEFAULT_DMIBAR | 0x0900); // !!! = 0x50000000 + write32 (DEFAULT_DMIBAR | 0x0900, 0x50000000); + read32 (DEFAULT_DMIBAR | 0x0920); // !!! = 0x50000000 + write32 (DEFAULT_DMIBAR | 0x0920, 0x50000000); + read32 (DEFAULT_DMIBAR | 0x0908); // !!! = 0x51ffffff + write32 (DEFAULT_DMIBAR | 0x0908, 0x51ffffff); + read32 (DEFAULT_DMIBAR | 0x0928); // !!! = 0x51ffffff + write32 (DEFAULT_DMIBAR | 0x0928, 0x51ffffff); + read32 (DEFAULT_DMIBAR | 0x0a00); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a00, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a10); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a10, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a20); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a20, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a30); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a30, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0700); // !!! = 0x46139008 + write32 (DEFAULT_DMIBAR | 0x0700, 0x46139008); + read32 (DEFAULT_DMIBAR | 0x0720); // !!! = 0x46139008 + write32 (DEFAULT_DMIBAR | 0x0720, 0x46139008); + read32 (DEFAULT_DMIBAR | 0x0904); // !!! = 0x3a1842ec + write32 (DEFAULT_DMIBAR | 0x0904, 0x3a1846ec); + read32 (DEFAULT_DMIBAR | 0x0924); // !!! = 0x3a1842ec + write32 (DEFAULT_DMIBAR | 0x0924, 0x3a1846ec); + read32 (DEFAULT_DMIBAR | 0x0a00); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a00, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a10); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a10, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a20); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a20, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a30); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a30, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0908); // !!! = 0x51ffffff + write32 (DEFAULT_DMIBAR | 0x0908, 0x51ffffff); + read32 (DEFAULT_DMIBAR | 0x0928); // !!! = 0x51ffffff + write32 (DEFAULT_DMIBAR | 0x0928, 0x51ffffff); + read32 (DEFAULT_DMIBAR | 0x0c00); // !!! = 0x29700c08 + write32 (DEFAULT_DMIBAR | 0x0c00, 0x29700c08); + read32 (DEFAULT_DMIBAR | 0x0c0c); // !!! = 0x16063400 + write32 (DEFAULT_DMIBAR | 0x0c0c, 0x00063400); + read32 (DEFAULT_DMIBAR | 0x0700); // !!! = 0x46139008 + write32 (DEFAULT_DMIBAR | 0x0700, 0x46339008); + read32 (DEFAULT_DMIBAR | 0x0720); // !!! = 0x46139008 + write32 (DEFAULT_DMIBAR | 0x0720, 0x46339008); + read32 (DEFAULT_DMIBAR | 0x0700); // !!! = 0x46339008 + write32 (DEFAULT_DMIBAR | 0x0700, 0x45339008); + read32 (DEFAULT_DMIBAR | 0x0720); // !!! = 0x46339008 + write32 (DEFAULT_DMIBAR | 0x0720, 0x45339008); + read32 (DEFAULT_DMIBAR | 0x0700); // !!! = 0x45339008 + write32 (DEFAULT_DMIBAR | 0x0700, 0x453b9008); + read32 (DEFAULT_DMIBAR | 0x0720); // !!! = 0x45339008 + write32 (DEFAULT_DMIBAR | 0x0720, 0x453b9008); + read32 (DEFAULT_DMIBAR | 0x0700); // !!! = 0x453b9008 + write32 (DEFAULT_DMIBAR | 0x0700, 0x45bb9008); + read32 (DEFAULT_DMIBAR | 0x0720); // !!! = 0x453b9008 + write32 (DEFAULT_DMIBAR | 0x0720, 0x45bb9008); + read32 (DEFAULT_DMIBAR | 0x0700); // !!! = 0x45bb9008 + write32 (DEFAULT_DMIBAR | 0x0700, 0x45fb9008); + read32 (DEFAULT_DMIBAR | 0x0720); // !!! = 0x45bb9008 + write32 (DEFAULT_DMIBAR | 0x0720, 0x45fb9008); + read32 (DEFAULT_DMIBAR | 0x0914); // !!! = 0x9021a080 + write32 (DEFAULT_DMIBAR | 0x0914, 0x9021a280); + read32 (DEFAULT_DMIBAR | 0x0934); // !!! = 0x9021a080 + write32 (DEFAULT_DMIBAR | 0x0934, 0x9021a280); + read32 (DEFAULT_DMIBAR | 0x0914); // !!! = 0x9021a280 + write32 (DEFAULT_DMIBAR | 0x0914, 0x9821a280); + read32 (DEFAULT_DMIBAR | 0x0934); // !!! = 0x9021a280 + write32 (DEFAULT_DMIBAR | 0x0934, 0x9821a280); + read32 (DEFAULT_DMIBAR | 0x0a00); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a00, 0x03242018); + read32 (DEFAULT_DMIBAR | 0x0a10); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a10, 0x03242018); + read32 (DEFAULT_DMIBAR | 0x0a20); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a20, 0x03242018); + read32 (DEFAULT_DMIBAR | 0x0a30); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a30, 0x03242018); + read32 (DEFAULT_DMIBAR | 0x0258); // !!! = 0x40000600 + write32 (DEFAULT_DMIBAR | 0x0258, 0x60000600); + read32 (DEFAULT_DMIBAR | 0x0904); // !!! = 0x3a1846ec + write32 (DEFAULT_DMIBAR | 0x0904, 0x2a1846ec); + read32 (DEFAULT_DMIBAR | 0x0914); // !!! = 0x9821a280 + write32 (DEFAULT_DMIBAR | 0x0914, 0x98200280); + read32 (DEFAULT_DMIBAR | 0x0924); // !!! = 0x3a1846ec + write32 (DEFAULT_DMIBAR | 0x0924, 0x2a1846ec); + read32 (DEFAULT_DMIBAR | 0x0934); // !!! = 0x9821a280 + write32 (DEFAULT_DMIBAR | 0x0934, 0x98200280); + read32 (DEFAULT_DMIBAR | 0x022c); // !!! = 0x00c26460 + write32 (DEFAULT_DMIBAR | 0x022c, 0x00c2403c); + read8 (DEFAULT_RCBA | 0x21a4); // !!! = 0x42 + + read32 (DEFAULT_RCBA | 0x21a4); // !!! = 0x00012c42 + read32 (DEFAULT_RCBA | 0x2340); // !!! = 0x0013001b + write32 (DEFAULT_RCBA | 0x2340, 0x003a001b); + read8 (DEFAULT_RCBA | 0x21b0); // !!! = 0x01 + write8 (DEFAULT_RCBA | 0x21b0, 0x02); + read32 (DEFAULT_DMIBAR | 0x0084); // !!! = 0x0041ac41 + write32 (DEFAULT_DMIBAR | 0x0084, 0x0041ac42); + read8 (DEFAULT_DMIBAR | 0x0088); // !!! = 0x00 + write8 (DEFAULT_DMIBAR | 0x0088, 0x20); + read16 (DEFAULT_DMIBAR | 0x008a); // !!! = 0x0041 + read8 (DEFAULT_DMIBAR | 0x0088); // !!! = 0x00 + write8 (DEFAULT_DMIBAR | 0x0088, 0x20); + read16 (DEFAULT_DMIBAR | 0x008a); // !!! = 0x0042 + read16 (DEFAULT_DMIBAR | 0x008a); // !!! = 0x0042 + + read32 (DEFAULT_DMIBAR | 0x0014); // !!! = 0x8000007f + write32 (DEFAULT_DMIBAR | 0x0014, 0x80000019); + read32 (DEFAULT_DMIBAR | 0x0020); // !!! = 0x01000000 + write32 (DEFAULT_DMIBAR | 0x0020, 0x81000022); + read32 (DEFAULT_DMIBAR | 0x002c); // !!! = 0x02000000 + write32 (DEFAULT_DMIBAR | 0x002c, 0x82000044); + read32 (DEFAULT_DMIBAR | 0x0038); // !!! = 0x07000080 + write32 (DEFAULT_DMIBAR | 0x0038, 0x87000080); + read8 (DEFAULT_DMIBAR | 0x0004); // !!! = 0x00 + write8 (DEFAULT_DMIBAR | 0x0004, 0x01); + + read32 (DEFAULT_RCBA | 0x0050); // !!! = 0x01200654 + write32 (DEFAULT_RCBA | 0x0050, 0x01200654); + read32 (DEFAULT_RCBA | 0x0050); // !!! = 0x01200654 + write32 (DEFAULT_RCBA | 0x0050, 0x012a0654); + read32 (DEFAULT_RCBA | 0x0050); // !!! = 0x012a0654 + read8 (DEFAULT_RCBA | 0x1114); // !!! = 0x00 + write8 (DEFAULT_RCBA | 0x1114, 0x05); + read32 (DEFAULT_RCBA | 0x2014); // !!! = 0x80000011 + write32 (DEFAULT_RCBA | 0x2014, 0x80000019); + read32 (DEFAULT_RCBA | 0x2020); // !!! = 0x00000000 + write32 (DEFAULT_RCBA | 0x2020, 0x81000022); + read32 (DEFAULT_RCBA | 0x2020); // !!! = 0x81000022 + read32 (DEFAULT_RCBA | 0x2030); // !!! = 0x00000000 + write32 (DEFAULT_RCBA | 0x2030, 0x82000044); + read32 (DEFAULT_RCBA | 0x2030); // !!! = 0x82000044 + read32 (DEFAULT_RCBA | 0x2040); // !!! = 0x00000000 + write32 (DEFAULT_RCBA | 0x2040, 0x87000080); + read32 (DEFAULT_RCBA | 0x0050); // !!! = 0x012a0654 + write32 (DEFAULT_RCBA | 0x0050, 0x812a0654); + read32 (DEFAULT_RCBA | 0x0050); // !!! = 0x812a0654 + read16 (DEFAULT_RCBA | 0x201a); // !!! = 0x0000 + read16 (DEFAULT_RCBA | 0x2026); // !!! = 0x0000 + read16 (DEFAULT_RCBA | 0x2036); // !!! = 0x0000 + read16 (DEFAULT_RCBA | 0x2046); // !!! = 0x0000 + read16 (DEFAULT_DMIBAR | 0x001a); // !!! = 0x0000 + read16 (DEFAULT_DMIBAR | 0x0026); // !!! = 0x0000 + read16 (DEFAULT_DMIBAR | 0x0032); // !!! = 0x0000 + read16 (DEFAULT_DMIBAR | 0x003e); // !!! = 0x0000 +} + +void +early_pch_init_native (void) +{ + pcie_write_config8 (SOUTHBRIDGE, 0xa6, + pcie_read_config8 (SOUTHBRIDGE, 0xa6) | 2); + + write32 (DEFAULT_RCBA | 0x2088, 0x00109000); + read32 (DEFAULT_RCBA | 0x20ac); // !!! = 0x00000000 + write32 (DEFAULT_RCBA | 0x20ac, 0x40000000); + write32 (DEFAULT_RCBA | 0x100c, 0x01110000); + write8 (DEFAULT_RCBA | 0x2340, 0x1b); + read32 (DEFAULT_RCBA | 0x2314); // !!! = 0x0a080000 + write32 (DEFAULT_RCBA | 0x2314, 0x0a280000); + read32 (DEFAULT_RCBA | 0x2310); // !!! = 0xc809605b + write32 (DEFAULT_RCBA | 0x2310, 0xa809605b); + write32 (DEFAULT_RCBA | 0x2324, 0x00854c74); + read8 (DEFAULT_RCBA | 0x0400); // !!! = 0x00 + read32 (DEFAULT_RCBA | 0x2310); // !!! = 0xa809605b + write32 (DEFAULT_RCBA | 0x2310, 0xa809605b); + read32 (DEFAULT_RCBA | 0x2310); // !!! = 0xa809605b + write32 (DEFAULT_RCBA | 0x2310, 0xa809605b); + + write_2338 (0xea007f62, 0x00590133); + write_2338 (0xec007f62, 0x00590133); + write_2338 (0xec007f64, 0x59555588); + write_2338 (0xea0040b9, 0x0001051c); + write_2338 (0xeb0040a1, 0x800084ff); + write_2338 (0xec0040a1, 0x800084ff); + write_2338 (0xea004001, 0x00008400); + write_2338 (0xeb004002, 0x40201758); + write_2338 (0xec004002, 0x40201758); + write_2338 (0xea004002, 0x00601758); + write_2338 (0xea0040a1, 0x810084ff); + write_2338 (0xeb0040b1, 0x0001c598); + write_2338 (0xec0040b1, 0x0001c598); + write_2338 (0xeb0040b6, 0x0001c598); + write_2338 (0xea0000a9, 0x80ff969f); + write_2338 (0xea0001a9, 0x80ff969f); + write_2338 (0xeb0040b2, 0x0001c396); + write_2338 (0xeb0040b3, 0x0001c396); + write_2338 (0xec0040b2, 0x0001c396); + write_2338 (0xea0001a9, 0x80ff94ff); + write_2338 (0xea000151, 0x0088037f); + write_2338 (0xea0000a9, 0x80ff94ff); + write_2338 (0xea000051, 0x0088037f); + + write_2338 (0xea007f05, 0x00010642); + write_2338 (0xea0040b7, 0x0001c91c); + write_2338 (0xea0040b8, 0x0001c91c); + write_2338 (0xeb0040a1, 0x820084ff); + write_2338 (0xec0040a1, 0x820084ff); + write_2338 (0xea007f0a, 0xc2480000); + + write_2338 (0xec00404d, 0x1ff177f); + write_2338 (0xec000084, 0x5a600000); + write_2338 (0xec000184, 0x5a600000); + write_2338 (0xec000284, 0x5a600000); + write_2338 (0xec000384, 0x5a600000); + write_2338 (0xec000094, 0x000f0501); + write_2338 (0xec000194, 0x000f0501); + write_2338 (0xec000294, 0x000f0501); + write_2338 (0xec000394, 0x000f0501); + write_2338 (0xec000096, 0x00000001); + write_2338 (0xec000196, 0x00000001); + write_2338 (0xec000296, 0x00000001); + write_2338 (0xec000396, 0x00000001); + write_2338 (0xec000001, 0x00008c08); + write_2338 (0xec000101, 0x00008c08); + write_2338 (0xec000201, 0x00008c08); + write_2338 (0xec000301, 0x00008c08); + write_2338 (0xec0040b5, 0x0001c518); + write_2338 (0xec000087, 0x06077597); + write_2338 (0xec000187, 0x06077597); + write_2338 (0xec000287, 0x06077597); + write_2338 (0xec000387, 0x06077597); + write_2338 (0xea000050, 0x00bb0157); + write_2338 (0xea000150, 0x00bb0157); + write_2338 (0xec007f60, 0x77777d77); + write_2338 (0xea00008d, 0x01320000); + write_2338 (0xea00018d, 0x01320000); + write_2338 (0xec0007b2, 0x04514b5e); + write_2338 (0xec00078c, 0x40000200); + write_2338 (0xec000780, 0x02000020); + + init_dmi(); +} diff --git a/src/southbridge/intel/bd82x6x/early_thermal.c b/src/southbridge/intel/bd82x6x/early_thermal.c new file mode 100644 index 0000000..02ec9a7 --- /dev/null +++ b/src/southbridge/intel/bd82x6x/early_thermal.c @@ -0,0 +1,70 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2014 Vladimir Serbinenko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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 + */ + +#include <arch/io.h> +#include "pch.h" +#include "cpu/intel/model_206ax/model_206ax.h" +#include <cpu/x86/msr.h> + +/* Early thermal init, must be done prior to giving ME its memory + which is done at the end of raminit. */ +void early_thermal_init(void) +{ + device_t dev; + msr_t msr; + + dev = PCI_DEV(0x0, 0x1f, 0x6); + + /* Program address for temporary BAR. */ + pci_write_config32(dev, 0x40, 0x40000000); + pci_write_config32(dev, 0x44, 0x0); + + /* Activate temporary BAR. */ + pci_write_config32(dev, 0x40, + pci_read_config32(dev, 0x40) | 5); + + + write16 (0x40000004, 0x3a2b); + write8 (0x4000000c, 0xff); + write8 (0x4000000d, 0x00); + write8 (0x4000000e, 0x40); + write8 (0x40000082, 0x00); + write8 (0x40000001, 0xba); + + /* Perform init. */ + /* Configure TJmax. */ + msr = rdmsr(MSR_TEMPERATURE_TARGET); + write16(0x40000012, ((msr.lo >> 16) & 0xff) << 6); + /* Northbridge temperature slope and offset. */ + write16(0x40000016, 0x808c); + + write16 (0x40000014, 0xde87); + + /* Enable thermal data reporting, processor, PCH and northbridge. */ + write16(0x4000001a, (read16(0x4000001a) & ~0xf) | 0x10f0); + + /* Disable temporary BAR. */ + pci_write_config32(dev, 0x40, + pci_read_config32(dev, 0x40) & ~1); + pci_write_config32(dev, 0x40, 0); + + write32 (DEFAULT_RCBA | 0x38b0, + (read32 (DEFAULT_RCBA | 0x38b0) & 0xffff8003) | 0x403c); +} diff --git a/src/southbridge/intel/bd82x6x/pch.h b/src/southbridge/intel/bd82x6x/pch.h index 90de855..83128e2 100644 --- a/src/southbridge/intel/bd82x6x/pch.h +++ b/src/southbridge/intel/bd82x6x/pch.h @@ -74,6 +74,8 @@ void enable_smbus(void); void enable_usb_bar(void); int smbus_read_byte(unsigned device, unsigned address); int early_spi_read(u32 offset, u32 size, u8 *buffer); +void early_thermal_init(void); +void early_pch_init_native(void); #endif #endif diff --git a/src/southbridge/intel/bd82x6x/smi.c b/src/southbridge/intel/bd82x6x/smi.c index 0166edf..a20232e 100644 --- a/src/southbridge/intel/bd82x6x/smi.c +++ b/src/southbridge/intel/bd82x6x/smi.c @@ -29,10 +29,7 @@ #include <cpu/x86/smm.h> #include <string.h> #include "pch.h" - -#if CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE || CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE #include "northbridge/intel/sandybridge/sandybridge.h" -#endif extern unsigned char _binary_smm_start; extern unsigned char _binary_smm_end; diff --git a/src/southbridge/intel/bd82x6x/usb_ehci.c b/src/southbridge/intel/bd82x6x/usb_ehci.c index 78f92d9..97f20bd 100644 --- a/src/southbridge/intel/bd82x6x/usb_ehci.c +++ b/src/southbridge/intel/bd82x6x/usb_ehci.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <kconfig.h> #include <console/console.h> #include <device/device.h> #include <device/pci.h> @@ -36,11 +37,43 @@ static void usb_ehci_init(struct device *dev) RCBA32(0x35b0) = reg32; printk(BIOS_DEBUG, "EHCI: Setting up controller.. "); + + /* For others, done in MRC. */ +#if IS_ENABLED(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE) + pci_write_config32(dev, 0x84, 0x930c8811); + pci_write_config32(dev, 0x88, 0x24000d30); + pci_write_config32(dev, 0xf4, 0x80408588); + pci_write_config32(dev, 0xf4, 0x80808588); + pci_write_config32(dev, 0xf4, 0x00808588); + pci_write_config32(dev, 0xfc, 0x205b1708); +#endif + reg32 = pci_read_config32(dev, PCI_COMMAND); reg32 |= PCI_COMMAND_MASTER; //reg32 |= PCI_COMMAND_SERR; pci_write_config32(dev, PCI_COMMAND, reg32); + /* For others, done in MRC. */ +#if IS_ENABLED(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE) + struct resource *res; + u8 access_cntl; + + access_cntl = pci_read_config8(dev, 0x80); + + /* Enable writes to protected registers. */ + pci_write_config8(dev, 0x80, access_cntl | 1); + + res = find_resource(dev, PCI_BASE_ADDRESS_0); + if (res) { + /* Number of ports and companion controllers. */ + reg32 = read32(res->base + 4); + write32(res->base + 4, (reg32 & 0xfff00000) | 3); + } + + /* Restore protection. */ + pci_write_config8(dev, 0x80, access_cntl); +#endif + printk(BIOS_DEBUG, "done.\n"); }
1
0
0
0
Patch set updated for coreboot: 56d33ed x230: Deploy VBT
by Vladimir Serbinenko
29 Jul '14
29 Jul '14
Vladimir Serbinenko (phcoder(a)gmail.com) just uploaded a new patch set to gerrit, which you can find at
http://review.coreboot.org/5396
-gerrit commit 56d33ed671a987a00a6bcc440edb740f5c696224 Author: Vladimir Serbinenko <phcoder(a)gmail.com> Date: Sun Feb 23 00:13:56 2014 +0100 x230: Deploy VBT Change-Id: Ide31a56bfdbc31cd3b87993dfb4ed8ef0107cdba Signed-off-by: Vladimir Serbinenko <phcoder(a)gmail.com> --- src/drivers/intel/gma/intel_bios.h | 733 +++++++++++++++++++++ src/northbridge/intel/sandybridge/gma.c | 1 + .../intel/sandybridge/gma_ivybridge_lvds.c | 82 +++ 3 files changed, 816 insertions(+) diff --git a/src/drivers/intel/gma/intel_bios.h b/src/drivers/intel/gma/intel_bios.h new file mode 100644 index 0000000..36426d8 --- /dev/null +++ b/src/drivers/intel/gma/intel_bios.h @@ -0,0 +1,733 @@ +/* + * Copyright © 2006 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + * Eric Anholt <eric(a)anholt.net> + * + */ + +#ifndef _I830_BIOS_H_ +#define _I830_BIOS_H_ + +struct vbt_header { + u8 signature[20]; /**< Always starts with 'VBT$' */ + u16 version; /**< decimal */ + u16 header_size; /**< in bytes */ + u16 vbt_size; /**< in bytes */ + u8 vbt_checksum; + u8 reserved0; + u32 bdb_offset; /**< from beginning of VBT */ + u32 aim_offset[4]; /**< from beginning of VBT */ +} __attribute__((packed)); + +struct bdb_header { + u8 signature[16]; /**< Always 'BIOS_DATA_BLOCK' */ + u16 version; /**< decimal */ + u16 header_size; /**< in bytes */ + u16 bdb_size; /**< in bytes */ +}; + +/* strictly speaking, this is a "skip" block, but it has interesting info */ +struct vbios_data { + u8 type; /* 0 == desktop, 1 == mobile */ + u8 relstage; + u8 chipset; + u8 lvds_present:1; + u8 tv_present:1; + u8 rsvd2:6; /* finish byte */ + u8 rsvd3[4]; + u8 signon[155]; + u8 copyright[61]; + u16 code_segment; + u8 dos_boot_mode; + u8 bandwidth_percent; + u8 rsvd4; /* popup memory size */ + u8 resize_pci_bios; + u8 rsvd5; /* is crt already on ddc2 */ +} __attribute__((packed)); + +/* + * There are several types of BIOS data blocks (BDBs), each block has + * an ID and size in the first 3 bytes (ID in first, size in next 2). + * Known types are listed below. + */ +#define BDB_GENERAL_FEATURES 1 +#define BDB_GENERAL_DEFINITIONS 2 +#define BDB_OLD_TOGGLE_LIST 3 +#define BDB_MODE_SUPPORT_LIST 4 +#define BDB_GENERIC_MODE_TABLE 5 +#define BDB_EXT_MMIO_REGS 6 +#define BDB_SWF_IO 7 +#define BDB_SWF_MMIO 8 +#define BDB_DOT_CLOCK_TABLE 9 +#define BDB_MODE_REMOVAL_TABLE 10 +#define BDB_CHILD_DEVICE_TABLE 11 +#define BDB_DRIVER_FEATURES 12 +#define BDB_DRIVER_PERSISTENCE 13 +#define BDB_EXT_TABLE_PTRS 14 +#define BDB_DOT_CLOCK_OVERRIDE 15 +#define BDB_DISPLAY_SELECT 16 +/* 17 rsvd */ +#define BDB_DRIVER_ROTATION 18 +#define BDB_DISPLAY_REMOVE 19 +#define BDB_OEM_CUSTOM 20 +#define BDB_EFP_LIST 21 /* workarounds for VGA hsync/vsync */ +#define BDB_SDVO_LVDS_OPTIONS 22 +#define BDB_SDVO_PANEL_DTDS 23 +#define BDB_SDVO_LVDS_PNP_IDS 24 +#define BDB_SDVO_LVDS_POWER_SEQ 25 +#define BDB_TV_OPTIONS 26 +#define BDB_EDP 27 +#define BDB_LVDS_OPTIONS 40 +#define BDB_LVDS_LFP_DATA_PTRS 41 +#define BDB_LVDS_LFP_DATA 42 +#define BDB_LVDS_BACKLIGHT 43 +#define BDB_LVDS_POWER 44 +#define BDB_MIPI 50 +#define BDB_SKIP 254 /* VBIOS private block, ignore */ + +struct bdb_general_features { + /* bits 1 */ + u8 panel_fitting:2; + u8 flexaim:1; + u8 msg_enable:1; + u8 clear_screen:3; + u8 color_flip:1; + + /* bits 2 */ + u8 download_ext_vbt:1; + u8 enable_ssc:1; + u8 ssc_freq:1; + u8 enable_lfp_on_override:1; + u8 disable_ssc_ddt:1; + u8 rsvd7:1; + u8 display_clock_mode:1; + u8 rsvd8:1; /* finish byte */ + + /* bits 3 */ + u8 disable_smooth_vision:1; + u8 single_dvi:1; + u8 rsvd9:1; + u8 fdi_rx_polarity_inverted:1; + u8 rsvd10:4; /* finish byte */ + + /* bits 4 */ + u8 legacy_monitor_detect; + + /* bits 5 */ + u8 int_crt_support:1; + u8 int_tv_support:1; + u8 int_efp_support:1; + u8 dp_ssc_enb:1; /* PCH attached eDP supports SSC */ + u8 dp_ssc_freq:1; /* SSC freq for PCH attached eDP */ + u8 rsvd11:3; /* finish byte */ +} __attribute__((packed)); + +/* pre-915 */ +#define GPIO_PIN_DVI_LVDS 0x03 /* "DVI/LVDS DDC GPIO pins" */ +#define GPIO_PIN_ADD_I2C 0x05 /* "ADDCARD I2C GPIO pins" */ +#define GPIO_PIN_ADD_DDC 0x04 /* "ADDCARD DDC GPIO pins" */ +#define GPIO_PIN_ADD_DDC_I2C 0x06 /* "ADDCARD DDC/I2C GPIO pins" */ + +/* Pre 915 */ +#define DEVICE_TYPE_NONE 0x00 +#define DEVICE_TYPE_CRT 0x01 +#define DEVICE_TYPE_TV 0x09 +#define DEVICE_TYPE_EFP 0x12 +#define DEVICE_TYPE_LFP 0x22 +/* On 915+ */ +#define DEVICE_TYPE_CRT_DPMS 0x6001 +#define DEVICE_TYPE_CRT_DPMS_HOTPLUG 0x4001 +#define DEVICE_TYPE_TV_COMPOSITE 0x0209 +#define DEVICE_TYPE_TV_MACROVISION 0x0289 +#define DEVICE_TYPE_TV_RF_COMPOSITE 0x020c +#define DEVICE_TYPE_TV_SVIDEO_COMPOSITE 0x0609 +#define DEVICE_TYPE_TV_SCART 0x0209 +#define DEVICE_TYPE_TV_CODEC_HOTPLUG_PWR 0x6009 +#define DEVICE_TYPE_EFP_HOTPLUG_PWR 0x6012 +#define DEVICE_TYPE_EFP_DVI_HOTPLUG_PWR 0x6052 +#define DEVICE_TYPE_EFP_DVI_I 0x6053 +#define DEVICE_TYPE_EFP_DVI_D_DUAL 0x6152 +#define DEVICE_TYPE_EFP_DVI_D_HDCP 0x60d2 +#define DEVICE_TYPE_OPENLDI_HOTPLUG_PWR 0x6062 +#define DEVICE_TYPE_OPENLDI_DUALPIX 0x6162 +#define DEVICE_TYPE_LFP_PANELLINK 0x5012 +#define DEVICE_TYPE_LFP_CMOS_PWR 0x5042 +#define DEVICE_TYPE_LFP_LVDS_PWR 0x5062 +#define DEVICE_TYPE_LFP_LVDS_DUAL 0x5162 +#define DEVICE_TYPE_LFP_LVDS_DUAL_HDCP 0x51e2 + +#define DEVICE_CFG_NONE 0x00 +#define DEVICE_CFG_12BIT_DVOB 0x01 +#define DEVICE_CFG_12BIT_DVOC 0x02 +#define DEVICE_CFG_24BIT_DVOBC 0x09 +#define DEVICE_CFG_24BIT_DVOCB 0x0a +#define DEVICE_CFG_DUAL_DVOB 0x11 +#define DEVICE_CFG_DUAL_DVOC 0x12 +#define DEVICE_CFG_DUAL_DVOBC 0x13 +#define DEVICE_CFG_DUAL_LINK_DVOBC 0x19 +#define DEVICE_CFG_DUAL_LINK_DVOCB 0x1a + +#define DEVICE_WIRE_NONE 0x00 +#define DEVICE_WIRE_DVOB 0x01 +#define DEVICE_WIRE_DVOC 0x02 +#define DEVICE_WIRE_DVOBC 0x03 +#define DEVICE_WIRE_DVOBB 0x05 +#define DEVICE_WIRE_DVOCC 0x06 +#define DEVICE_WIRE_DVOB_MASTER 0x0d +#define DEVICE_WIRE_DVOC_MASTER 0x0e + +#define DEVICE_PORT_DVOA 0x00 /* none on 845+ */ +#define DEVICE_PORT_DVOB 0x01 +#define DEVICE_PORT_DVOC 0x02 + +/* We used to keep this struct but without any version control. We should avoid + * using it in the future, but it should be safe to keep using it in the old + * code. */ +struct old_child_dev_config { + u16 handle; + u16 device_type; + u8 device_id[10]; /* ascii string */ + u16 addin_offset; + u8 dvo_port; /* See Device_PORT_* above */ + u8 i2c_pin; + u8 slave_addr; + u8 ddc_pin; + u16 edid_ptr; + u8 dvo_cfg; /* See DEVICE_CFG_* above */ + u8 dvo2_port; + u8 i2c2_pin; + u8 slave2_addr; + u8 ddc2_pin; + u8 capabilities; + u8 dvo_wiring;/* See DEVICE_WIRE_* above */ + u8 dvo2_wiring; + u16 extended_type; + u8 dvo_function; +} __attribute__((packed)); + +/* This one contains field offsets that are known to be common for all BDB + * versions. Notice that the meaning of the contents contents may still change, + * but at least the offsets are consistent. */ +struct common_child_dev_config { + u16 handle; + u16 device_type; + u8 not_common1[12]; + u8 dvo_port; + u8 not_common2[2]; + u8 ddc_pin; + u16 edid_ptr; +} __attribute__((packed)); + +/* This field changes depending on the BDB version, so the most reliable way to + * read it is by checking the BDB version and reading the raw pointer. */ +union child_device_config { + /* This one is safe to be used anywhere, but the code should still check + * the BDB version. */ + u8 raw[33]; + /* This one should only be kept for legacy code. */ + struct old_child_dev_config old; + /* This one should also be safe to use anywhere, even without version + * checks. */ + struct common_child_dev_config common; +}; + +struct bdb_general_definitions { + /* DDC GPIO */ + u8 crt_ddc_gmbus_pin; + + /* DPMS bits */ + u8 dpms_acpi:1; + u8 skip_boot_crt_detect:1; + u8 dpms_aim:1; + u8 rsvd1:5; /* finish byte */ + + /* boot device bits */ + u8 boot_display[2]; + u8 child_dev_size; + + /* + * Device info: + * If TV is present, it'll be at devices[0]. + * LVDS will be next, either devices[0] or [1], if present. + * On some platforms the number of device is 6. But could be as few as + * 4 if both TV and LVDS are missing. + * And the device num is related with the size of general definition + * block. It is obtained by using the following formula: + * number = (block_size - sizeof(bdb_general_definitions))/ + * sizeof(child_device_config); + */ + union child_device_config devices[0]; +} __attribute__((packed)); + +struct bdb_lvds_options { + u8 panel_type; + u8 rsvd1; + /* LVDS capabilities, stored in a dword */ + u8 pfit_mode:2; + u8 pfit_text_mode_enhanced:1; + u8 pfit_gfx_mode_enhanced:1; + u8 pfit_ratio_auto:1; + u8 pixel_dither:1; + u8 lvds_edid:1; + u8 rsvd2:1; + u8 rsvd4; +} __attribute__((packed)); + +/* LFP pointer table contains entries to the struct below */ +struct bdb_lvds_lfp_data_ptr { + u16 fp_timing_offset; /* offsets are from start of bdb */ + u8 fp_table_size; + u16 dvo_timing_offset; + u8 dvo_table_size; + u16 panel_pnp_id_offset; + u8 pnp_table_size; +} __attribute__((packed)); + +struct bdb_lvds_lfp_data_ptrs { + u8 lvds_entries; /* followed by one or more lvds_data_ptr structs */ + struct bdb_lvds_lfp_data_ptr ptr[16]; +} __attribute__((packed)); + +/* LFP data has 3 blocks per entry */ +struct lvds_fp_timing { + u16 x_res; + u16 y_res; + u32 lvds_reg; + u32 lvds_reg_val; + u32 pp_on_reg; + u32 pp_on_reg_val; + u32 pp_off_reg; + u32 pp_off_reg_val; + u32 pp_cycle_reg; + u32 pp_cycle_reg_val; + u32 pfit_reg; + u32 pfit_reg_val; + u16 terminator; +} __attribute__((packed)); + +struct lvds_dvo_timing { + u16 clock; /**< In 10khz */ + u8 hactive_lo; + u8 hblank_lo; + u8 hblank_hi:4; + u8 hactive_hi:4; + u8 vactive_lo; + u8 vblank_lo; + u8 vblank_hi:4; + u8 vactive_hi:4; + u8 hsync_off_lo; + u8 hsync_pulse_width; + u8 vsync_pulse_width:4; + u8 vsync_off:4; + u8 rsvd0:6; + u8 hsync_off_hi:2; + u8 h_image; + u8 v_image; + u8 max_hv; + u8 h_border; + u8 v_border; + u8 rsvd1:3; + u8 digital:2; + u8 vsync_positive:1; + u8 hsync_positive:1; + u8 rsvd2:1; +} __attribute__((packed)); + +struct lvds_pnp_id { + u16 mfg_name; + u16 product_code; + u32 serial; + u8 mfg_week; + u8 mfg_year; +} __attribute__((packed)); + +struct bdb_lvds_lfp_data_entry { + struct lvds_fp_timing fp_timing; + struct lvds_dvo_timing dvo_timing; + struct lvds_pnp_id pnp_id; +} __attribute__((packed)); + +struct bdb_lvds_lfp_data { + struct bdb_lvds_lfp_data_entry data[16]; +} __attribute__((packed)); + +struct aimdb_header { + char signature[16]; + char oem_device[20]; + u16 aimdb_version; + u16 aimdb_header_size; + u16 aimdb_size; +} __attribute__((packed)); + +struct aimdb_block { + u8 aimdb_id; + u16 aimdb_size; +} __attribute__((packed)); + +struct vch_panel_data { + u16 fp_timing_offset; + u8 fp_timing_size; + u16 dvo_timing_offset; + u8 dvo_timing_size; + u16 text_fitting_offset; + u8 text_fitting_size; + u16 graphics_fitting_offset; + u8 graphics_fitting_size; +} __attribute__((packed)); + +struct vch_bdb_22 { + struct aimdb_block aimdb_block; + struct vch_panel_data panels[16]; +} __attribute__((packed)); + +struct bdb_sdvo_lvds_options { + u8 panel_backlight; + u8 h40_set_panel_type; + u8 panel_type; + u8 ssc_clk_freq; + u16 als_low_trip; + u16 als_high_trip; + u8 sclalarcoeff_tab_row_num; + u8 sclalarcoeff_tab_row_size; + u8 coefficient[8]; + u8 panel_misc_bits_1; + u8 panel_misc_bits_2; + u8 panel_misc_bits_3; + u8 panel_misc_bits_4; +} __attribute__((packed)); + + +#define BDB_DRIVER_FEATURE_NO_LVDS 0 +#define BDB_DRIVER_FEATURE_INT_LVDS 1 +#define BDB_DRIVER_FEATURE_SDVO_LVDS 2 +#define BDB_DRIVER_FEATURE_EDP 3 + +struct bdb_driver_features { + u8 boot_dev_algorithm:1; + u8 block_display_switch:1; + u8 allow_display_switch:1; + u8 hotplug_dvo:1; + u8 dual_view_zoom:1; + u8 int15h_hook:1; + u8 sprite_in_clone:1; + u8 primary_lfp_id:1; + + u16 boot_mode_x; + u16 boot_mode_y; + u8 boot_mode_bpp; + u8 boot_mode_refresh; + + u16 enable_lfp_primary:1; + u16 selective_mode_pruning:1; + u16 dual_frequency:1; + u16 render_clock_freq:1; /* 0: high freq; 1: low freq */ + u16 nt_clone_support:1; + u16 power_scheme_ui:1; /* 0: CUI; 1: 3rd party */ + u16 sprite_display_assign:1; /* 0: secondary; 1: primary */ + u16 cui_aspect_scaling:1; + u16 preserve_aspect_ratio:1; + u16 sdvo_device_power_down:1; + u16 crt_hotplug:1; + u16 lvds_config:2; + u16 tv_hotplug:1; + u16 hdmi_config:2; + + u8 static_display:1; + u8 reserved2:7; + u16 legacy_crt_max_x; + u16 legacy_crt_max_y; + u8 legacy_crt_max_refresh; + + u8 hdmi_termination; + u8 custom_vbt_version; +} __attribute__((packed)); + +#define EDP_18BPP 0 +#define EDP_24BPP 1 +#define EDP_30BPP 2 +#define EDP_RATE_1_62 0 +#define EDP_RATE_2_7 1 +#define EDP_LANE_1 0 +#define EDP_LANE_2 1 +#define EDP_LANE_4 3 +#define EDP_PREEMPHASIS_NONE 0 +#define EDP_PREEMPHASIS_3_5dB 1 +#define EDP_PREEMPHASIS_6dB 2 +#define EDP_PREEMPHASIS_9_5dB 3 +#define EDP_VSWING_0_4V 0 +#define EDP_VSWING_0_6V 1 +#define EDP_VSWING_0_8V 2 +#define EDP_VSWING_1_2V 3 + +struct edp_power_seq { + u16 t1_t3; + u16 t8; + u16 t9; + u16 t10; + u16 t11_t12; +} __attribute__ ((packed)); + +struct edp_link_params { + u8 rate:4; + u8 lanes:4; + u8 preemphasis:4; + u8 vswing:4; +} __attribute__ ((packed)); + +struct bdb_edp { + struct edp_power_seq power_seqs[16]; + u32 color_depth; + struct edp_link_params link_params[16]; + u32 sdrrs_msa_timing_delay; + + /* ith bit indicates enabled/disabled for (i+1)th panel */ + u16 edp_s3d_feature; + u16 edp_t3_optimization; +} __attribute__ ((packed)); + +/* + * Driver<->VBIOS interaction occurs through scratch bits in + * GR18 & SWF*. + */ + +/* GR18 bits are set on display switch and hotkey events */ +#define GR18_DRIVER_SWITCH_EN (1<<7) /* 0: VBIOS control, 1: driver control */ +#define GR18_HOTKEY_MASK 0x78 /* See also SWF4 15:0 */ +#define GR18_HK_NONE (0x0<<3) +#define GR18_HK_LFP_STRETCH (0x1<<3) +#define GR18_HK_TOGGLE_DISP (0x2<<3) +#define GR18_HK_DISP_SWITCH (0x4<<3) /* see SWF14 15:0 for what to enable */ +#define GR18_HK_POPUP_DISABLED (0x6<<3) +#define GR18_HK_POPUP_ENABLED (0x7<<3) +#define GR18_HK_PFIT (0x8<<3) +#define GR18_HK_APM_CHANGE (0xa<<3) +#define GR18_HK_MULTIPLE (0xc<<3) +#define GR18_USER_INT_EN (1<<2) +#define GR18_A0000_FLUSH_EN (1<<1) +#define GR18_SMM_EN (1<<0) + +/* Set by driver, cleared by VBIOS */ +#define SWF00_YRES_SHIFT 16 +#define SWF00_XRES_SHIFT 0 +#define SWF00_RES_MASK 0xffff + +/* Set by VBIOS at boot time and driver at runtime */ +#define SWF01_TV2_FORMAT_SHIFT 8 +#define SWF01_TV1_FORMAT_SHIFT 0 +#define SWF01_TV_FORMAT_MASK 0xffff + +#define SWF10_VBIOS_BLC_I2C_EN (1<<29) +#define SWF10_GTT_OVERRIDE_EN (1<<28) +#define SWF10_LFP_DPMS_OVR (1<<27) /* override DPMS on display switch */ +#define SWF10_ACTIVE_TOGGLE_LIST_MASK (7<<24) +#define SWF10_OLD_TOGGLE 0x0 +#define SWF10_TOGGLE_LIST_1 0x1 +#define SWF10_TOGGLE_LIST_2 0x2 +#define SWF10_TOGGLE_LIST_3 0x3 +#define SWF10_TOGGLE_LIST_4 0x4 +#define SWF10_PANNING_EN (1<<23) +#define SWF10_DRIVER_LOADED (1<<22) +#define SWF10_EXTENDED_DESKTOP (1<<21) +#define SWF10_EXCLUSIVE_MODE (1<<20) +#define SWF10_OVERLAY_EN (1<<19) +#define SWF10_PLANEB_HOLDOFF (1<<18) +#define SWF10_PLANEA_HOLDOFF (1<<17) +#define SWF10_VGA_HOLDOFF (1<<16) +#define SWF10_ACTIVE_DISP_MASK 0xffff +#define SWF10_PIPEB_LFP2 (1<<15) +#define SWF10_PIPEB_EFP2 (1<<14) +#define SWF10_PIPEB_TV2 (1<<13) +#define SWF10_PIPEB_CRT2 (1<<12) +#define SWF10_PIPEB_LFP (1<<11) +#define SWF10_PIPEB_EFP (1<<10) +#define SWF10_PIPEB_TV (1<<9) +#define SWF10_PIPEB_CRT (1<<8) +#define SWF10_PIPEA_LFP2 (1<<7) +#define SWF10_PIPEA_EFP2 (1<<6) +#define SWF10_PIPEA_TV2 (1<<5) +#define SWF10_PIPEA_CRT2 (1<<4) +#define SWF10_PIPEA_LFP (1<<3) +#define SWF10_PIPEA_EFP (1<<2) +#define SWF10_PIPEA_TV (1<<1) +#define SWF10_PIPEA_CRT (1<<0) + +#define SWF11_MEMORY_SIZE_SHIFT 16 +#define SWF11_SV_TEST_EN (1<<15) +#define SWF11_IS_AGP (1<<14) +#define SWF11_DISPLAY_HOLDOFF (1<<13) +#define SWF11_DPMS_REDUCED (1<<12) +#define SWF11_IS_VBE_MODE (1<<11) +#define SWF11_PIPEB_ACCESS (1<<10) /* 0 here means pipe a */ +#define SWF11_DPMS_MASK 0x07 +#define SWF11_DPMS_OFF (1<<2) +#define SWF11_DPMS_SUSPEND (1<<1) +#define SWF11_DPMS_STANDBY (1<<0) +#define SWF11_DPMS_ON 0 + +#define SWF14_GFX_PFIT_EN (1<<31) +#define SWF14_TEXT_PFIT_EN (1<<30) +#define SWF14_LID_STATUS_CLOSED (1<<29) /* 0 here means open */ +#define SWF14_POPUP_EN (1<<28) +#define SWF14_DISPLAY_HOLDOFF (1<<27) +#define SWF14_DISP_DETECT_EN (1<<26) +#define SWF14_DOCKING_STATUS_DOCKED (1<<25) /* 0 here means undocked */ +#define SWF14_DRIVER_STATUS (1<<24) +#define SWF14_OS_TYPE_WIN9X (1<<23) +#define SWF14_OS_TYPE_WINNT (1<<22) +/* 21:19 rsvd */ +#define SWF14_PM_TYPE_MASK 0x00070000 +#define SWF14_PM_ACPI_VIDEO (0x4 << 16) +#define SWF14_PM_ACPI (0x3 << 16) +#define SWF14_PM_APM_12 (0x2 << 16) +#define SWF14_PM_APM_11 (0x1 << 16) +#define SWF14_HK_REQUEST_MASK 0x0000ffff /* see GR18 6:3 for event type */ + /* if GR18 indicates a display switch */ +#define SWF14_DS_PIPEB_LFP2_EN (1<<15) +#define SWF14_DS_PIPEB_EFP2_EN (1<<14) +#define SWF14_DS_PIPEB_TV2_EN (1<<13) +#define SWF14_DS_PIPEB_CRT2_EN (1<<12) +#define SWF14_DS_PIPEB_LFP_EN (1<<11) +#define SWF14_DS_PIPEB_EFP_EN (1<<10) +#define SWF14_DS_PIPEB_TV_EN (1<<9) +#define SWF14_DS_PIPEB_CRT_EN (1<<8) +#define SWF14_DS_PIPEA_LFP2_EN (1<<7) +#define SWF14_DS_PIPEA_EFP2_EN (1<<6) +#define SWF14_DS_PIPEA_TV2_EN (1<<5) +#define SWF14_DS_PIPEA_CRT2_EN (1<<4) +#define SWF14_DS_PIPEA_LFP_EN (1<<3) +#define SWF14_DS_PIPEA_EFP_EN (1<<2) +#define SWF14_DS_PIPEA_TV_EN (1<<1) +#define SWF14_DS_PIPEA_CRT_EN (1<<0) + /* if GR18 indicates a panel fitting request */ +#define SWF14_PFIT_EN (1<<0) /* 0 means disable */ + /* if GR18 indicates an APM change request */ +#define SWF14_APM_HIBERNATE 0x4 +#define SWF14_APM_SUSPEND 0x3 +#define SWF14_APM_STANDBY 0x1 +#define SWF14_APM_RESTORE 0x0 + +/* Add the device class for LFP, TV, HDMI */ +#define DEVICE_TYPE_INT_LFP 0x1022 +#define DEVICE_TYPE_INT_TV 0x1009 +#define DEVICE_TYPE_HDMI 0x60D2 +#define DEVICE_TYPE_DP 0x68C6 +#define DEVICE_TYPE_eDP 0x78C6 + +#define DEVICE_TYPE_CLASS_EXTENSION (1 << 15) +#define DEVICE_TYPE_POWER_MANAGEMENT (1 << 14) +#define DEVICE_TYPE_HOTPLUG_SIGNALING (1 << 13) +#define DEVICE_TYPE_INTERNAL_CONNECTOR (1 << 12) +#define DEVICE_TYPE_NOT_HDMI_OUTPUT (1 << 11) +#define DEVICE_TYPE_MIPI_OUTPUT (1 << 10) +#define DEVICE_TYPE_COMPOSITE_OUTPUT (1 << 9) +#define DEVICE_TYPE_DUAL_CHANNEL (1 << 8) +#define DEVICE_TYPE_HIGH_SPEED_LINK (1 << 6) +#define DEVICE_TYPE_LVDS_SINGALING (1 << 5) +#define DEVICE_TYPE_TMDS_DVI_SIGNALING (1 << 4) +#define DEVICE_TYPE_VIDEO_SIGNALING (1 << 3) +#define DEVICE_TYPE_DISPLAYPORT_OUTPUT (1 << 2) +#define DEVICE_TYPE_DIGITAL_OUTPUT (1 << 1) +#define DEVICE_TYPE_ANALOG_OUTPUT (1 << 0) + +/* + * Bits we care about when checking for DEVICE_TYPE_eDP + * Depending on the system, the other bits may or may not + * be set for eDP outputs. + */ +#define DEVICE_TYPE_eDP_BITS \ + (DEVICE_TYPE_INTERNAL_CONNECTOR | \ + DEVICE_TYPE_NOT_HDMI_OUTPUT | \ + DEVICE_TYPE_MIPI_OUTPUT | \ + DEVICE_TYPE_COMPOSITE_OUTPUT | \ + DEVICE_TYPE_DUAL_CHANNEL | \ + DEVICE_TYPE_LVDS_SINGALING | \ + DEVICE_TYPE_TMDS_DVI_SIGNALING | \ + DEVICE_TYPE_VIDEO_SIGNALING | \ + DEVICE_TYPE_DISPLAYPORT_OUTPUT | \ + DEVICE_TYPE_DIGITAL_OUTPUT | \ + DEVICE_TYPE_ANALOG_OUTPUT) + +/* define the DVO port for HDMI output type */ +#define DVO_B 1 +#define DVO_C 2 +#define DVO_D 3 + +/* define the PORT for DP output type */ +#define PORT_IDPB 7 +#define PORT_IDPC 8 +#define PORT_IDPD 9 + +/* Possible values for the "DVO Port" field for versions >= 155: */ +#define DVO_PORT_HDMIA 0 +#define DVO_PORT_HDMIB 1 +#define DVO_PORT_HDMIC 2 +#define DVO_PORT_HDMID 3 +#define DVO_PORT_LVDS 4 +#define DVO_PORT_TV 5 +#define DVO_PORT_CRT 6 +#define DVO_PORT_DPB 7 +#define DVO_PORT_DPC 8 +#define DVO_PORT_DPD 9 +#define DVO_PORT_DPA 10 + +/* MIPI DSI panel info */ +struct bdb_mipi { + u16 panel_id; + u16 bridge_revision; + + /* General params */ + u32 dithering:1; + u32 bpp_pixel_format:1; + u32 rsvd1:1; + u32 dphy_valid:1; + u32 resvd2:28; + + u16 port_info; + u16 rsvd3:2; + u16 num_lanes:2; + u16 rsvd4:12; + + /* DSI config */ + u16 virt_ch_num:2; + u16 vtm:2; + u16 rsvd5:12; + + u32 dsi_clock; + u32 bridge_ref_clk; + u16 rsvd_pwr; + + /* Dphy Params */ + u32 prepare_cnt:5; + u32 rsvd6:3; + u32 clk_zero_cnt:8; + u32 trail_cnt:5; + u32 rsvd7:3; + u32 exit_zero_cnt:6; + u32 rsvd8:2; + + u32 hl_switch_cnt; + u32 lp_byte_clk; + u32 clk_lane_switch_cnt; +} __attribute__((packed)); + +#endif /* _I830_BIOS_H_ */ diff --git a/src/northbridge/intel/sandybridge/gma.c b/src/northbridge/intel/sandybridge/gma.c index d271a1a..a01fe9f 100644 --- a/src/northbridge/intel/sandybridge/gma.c +++ b/src/northbridge/intel/sandybridge/gma.c @@ -21,6 +21,7 @@ #include <console/console.h> #include <bootmode.h> #include <delay.h> +#include <string.h> #include <device/device.h> #include <device/pci.h> #include <device/pci_ids.h> diff --git a/src/northbridge/intel/sandybridge/gma_ivybridge_lvds.c b/src/northbridge/intel/sandybridge/gma_ivybridge_lvds.c index 1f53a74..ff877ff 100644 --- a/src/northbridge/intel/sandybridge/gma_ivybridge_lvds.c +++ b/src/northbridge/intel/sandybridge/gma_ivybridge_lvds.c @@ -26,13 +26,64 @@ #include <drivers/intel/gma/edid.h> #include <drivers/intel/gma/i915.h> +#include <drivers/intel/gma/intel_bios.h> #include "gma.h" #include "chip.h" #include <pc80/vga.h> #include <pc80/vga_io.h> +#include <device/pci_def.h> +#include <device/pci_rom.h> #if IS_ENABLED(CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT) +static size_t generate_vbt(const struct northbridge_intel_sandybridge_config *conf, + void *vbt) +{ + struct vbt_header *head = vbt; + struct bdb_header *bdb_head; + struct bdb_general_features *genfeat; + u8 *ptr; + + memset(head, 0, sizeof (*head)); + + memcpy(head->signature, "$VBT SNB/IVB-MOBILE ", 20); + head->version = 100; + head->header_size = sizeof (*head); + head->bdb_offset = sizeof (*head); + + bdb_head = (struct bdb_header *) (head + 1); + memset(bdb_head, 0, sizeof (*bdb_head)); + memcpy(bdb_head->signature, "BIOS_DATA_BLOCK ", 16); + bdb_head->version = 0xa8; + bdb_head->header_size = sizeof (*bdb_head); + + ptr = (u8 *) (bdb_head + 1); + + ptr[0] = BDB_GENERAL_FEATURES; + ptr[1] = sizeof (*genfeat); + ptr[2] = sizeof (*genfeat) >> 8; + ptr += 3; + + genfeat = (struct bdb_general_features *) ptr; + memset(genfeat, 0, sizeof (*genfeat)); + genfeat->panel_fitting = 3; + genfeat->flexaim = 1; + genfeat->download_ext_vbt = 1; + genfeat->enable_ssc = conf->gpu_use_spread_spectrum_clock; + genfeat->ssc_freq = !conf->gpu_link_frequency_270_mhz; + genfeat->rsvd10 = 0x4; + genfeat->legacy_monitor_detect = 1; + genfeat->int_crt_support = 1; + genfeat->dp_ssc_enb = 1; + + ptr += sizeof (*genfeat); + + bdb_head->bdb_size = ptr - (u8 *)bdb_head; + head->vbt_size = ptr - (u8 *)head; + head->vbt_checksum = 0; + return ptr - (u8 *)head; +} + static void link_train(u32 mmio) { write32(mmio+0xf000c,0x40); @@ -509,6 +560,37 @@ int i915lightup(const struct northbridge_intel_sandybridge_config *info, memset ((void *) lfb, 0, edid.x_resolution * edid.y_resolution * 4); set_vbe_mode_info_valid(&edid, lfb); #endif + + /* Linux relies on VBT for panel info. */ + optionrom_header_t *oh = (void *)PCI_VGA_RAM_IMAGE_START; + optionrom_pcir_t *pcir; + size_t vbt_size; + size_t fake_oprom_size; + struct device *dev; + + dev = dev_find_slot(0, PCI_DEVFN(2, 0)); + + memset(oh, 0, 8192); + + oh->signature = OPROM_SIGNATURE; + oh->pcir_offset = 0x40; + oh->vbt_offset = 0x80; + + pcir = (void *)(PCI_VGA_RAM_IMAGE_START + 0x40); + pcir->signature = 0x52494350; // PCIR + pcir->vendor = dev->vendor; + pcir->device = dev->device; + pcir->length = sizeof(*pcir); + pcir->revision = dev->class; + pcir->classcode[0] = dev->class >> 8; + pcir->classcode[1] = dev->class >> 16; + pcir->classcode[2] = dev->class >> 24; + pcir->indicator = 0x80; + + vbt_size = generate_vbt (info, (void *)(PCI_VGA_RAM_IMAGE_START + 0x80)); + fake_oprom_size = (0x80 + vbt_size + 511) / 512; + oh->size = fake_oprom_size; + pcir->imagelength = fake_oprom_size; return 1; }
1
0
0
0
Patch set updated for coreboot: f1691ca nehalem: Remove fake_vbt copying.
by Vladimir Serbinenko
29 Jul '14
29 Jul '14
Vladimir Serbinenko (phcoder(a)gmail.com) just uploaded a new patch set to gerrit, which you can find at
http://review.coreboot.org/5895
-gerrit commit f1691ca8f6236a72d4be69ebea58a40bfee82538 Author: Vladimir Serbinenko <phcoder(a)gmail.com> Date: Sat May 31 22:26:42 2014 +0200 nehalem: Remove fake_vbt copying. Instead generate simple VBT in code. Tested on X201. Change-Id: I2244053edd24c22694161d9bf5f7f2f3eb4e2f57 Signed-off-by: Vladimir Serbinenko <phcoder(a)gmail.com> --- src/mainboard/lenovo/x201/Makefile.inc | 1 - src/mainboard/lenovo/x201/gma.c | 514 -------------------------- src/mainboard/packardbell/ms2290/Makefile.inc | 1 - src/mainboard/packardbell/ms2290/gma.c | 272 -------------- src/northbridge/intel/nehalem/gma.c | 73 +++- 5 files changed, 60 insertions(+), 801 deletions(-) diff --git a/src/mainboard/lenovo/x201/Makefile.inc b/src/mainboard/lenovo/x201/Makefile.inc index c6574c5..eb099f3 100644 --- a/src/mainboard/lenovo/x201/Makefile.inc +++ b/src/mainboard/lenovo/x201/Makefile.inc @@ -21,4 +21,3 @@ smm-$(CONFIG_HAVE_SMI_HANDLER) += dock.c smm-$(CONFIG_HAVE_SMI_HANDLER) += smihandler.c romstage-y += dock.c ramstage-y += dock.c -ramstage-y += gma.c diff --git a/src/mainboard/lenovo/x201/gma.c b/src/mainboard/lenovo/x201/gma.c deleted file mode 100644 index f417905..0000000 --- a/src/mainboard/lenovo/x201/gma.c +++ /dev/null @@ -1,514 +0,0 @@ -#include <arch/io.h> -#include <device/device.h> -#include <device/pci.h> -#include <device/pci_ids.h> -#include <device/pci_ops.h> - -#include "northbridge/intel/nehalem/nehalem.h" - -/* This array contains the information on flat panel. When using native - graphics init coreboot copies it to where VGA Option ROM would be so - that OS can find it and able to use internal display. This contains no - executable code and is just information on the panel. - */ - -unsigned char fake_vbt[] = { - 0x24, 0x56, 0x42, 0x54, 0x20, 0x49, 0x52, 0x4f, 0x4e, 0x4c, 0x41, 0x4b, - 0x45, 0x2d, 0x4d, 0x4f, - 0x42, 0x49, 0x4c, 0x45, 0x64, 0x00, 0x30, 0x00, 0x8e, 0x0f, 0x48, 0x00, - 0x30, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x42, 0x49, 0x4f, 0x53, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x42, 0x4c, - 0x4f, 0x43, 0x4b, 0x20, - 0x9c, 0x00, 0x16, 0x00, 0x5e, 0x0f, 0xfe, 0xea, 0x00, 0x00, 0x64, 0x01, - 0x01, 0x0f, 0x0d, 0x32, - 0x30, 0x32, 0x36, 0x44, 0x43, 0x49, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x6c, - 0x28, 0x52, 0x29, 0x49, - 0x72, 0x6f, 0x6e, 0x6c, 0x61, 0x6b, 0x65, 0x20, 0x4d, 0x6f, 0x62, 0x69, - 0x6c, 0x65, 0x20, 0x50, - 0x43, 0x49, 0x20, 0x41, 0x63, 0x63, 0x65, 0x6c, 0x65, 0x72, 0x61, 0x74, - 0x65, 0x64, 0x20, 0x53, - 0x56, 0x47, 0x41, 0x20, 0x42, 0x49, 0x4f, 0x53, 0x0d, 0x0a, 0x42, 0x75, - 0x69, 0x6c, 0x64, 0x20, - 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x3a, 0x20, 0x32, 0x30, 0x32, 0x36, - 0x20, 0x50, 0x43, 0x20, - 0x31, 0x34, 0x2e, 0x33, 0x34, 0x20, 0x20, 0x30, 0x39, 0x2f, 0x32, 0x38, - 0x20, 0x2f, 0x32, 0x30, - 0x31, 0x30, 0x20, 0x20, 0x32, 0x32, 0x3a, 0x32, 0x30, 0x3a, 0x35, 0x32, - 0x0d, 0x0a, 0x44, 0x45, - 0x43, 0x4f, 0x4d, 0x50, 0x49, 0x4c, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x20, - 0x4f, 0x52, 0x20, 0x44, - 0x49, 0x53, 0x41, 0x53, 0x53, 0x45, 0x4d, 0x42, 0x4c, 0x59, 0x20, 0x50, - 0x52, 0x4f, 0x48, 0x49, - 0x42, 0x49, 0x54, 0x45, 0x44, 0x0d, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x43, 0x6f, - 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x43, 0x29, 0x20, - 0x32, 0x30, 0x30, 0x30, - 0x2d, 0x32, 0x30, 0x30, 0x33, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x6c, 0x20, - 0x43, 0x6f, 0x72, 0x70, - 0x2e, 0x20, 0x41, 0x6c, 0x6c, 0x20, 0x52, 0x69, 0x67, 0x68, 0x74, 0x73, - 0x20, 0x52, 0x65, 0x73, - 0x65, 0x72, 0x76, 0x65, 0x64, 0x2e, 0x0d, 0x0a, 0x0d, 0x0a, 0x00, 0x00, - 0xc0, 0x03, 0x08, 0x04, - 0x00, 0x00, 0x00, 0x01, 0x05, 0x00, 0x07, 0x03, 0x00, 0x01, 0x19, 0xfe, - 0x32, 0x00, 0x44, 0x04, - 0x40, 0x06, 0x04, 0x02, 0x09, 0x01, 0x08, 0x0a, 0x02, 0x08, 0x0c, 0x04, - 0x08, 0x03, 0x01, 0x02, - 0x05, 0x01, 0x04, 0x0d, 0x01, 0x04, 0x0b, 0x01, 0x02, 0x07, 0x01, 0x04, - 0x15, 0x01, 0x04, 0x45, - 0x01, 0x04, 0x0e, 0x04, 0x08, 0x46, 0x04, 0x40, 0x28, 0x20, 0x08, 0x48, - 0x40, 0x08, 0x10, 0x00, - 0x02, 0x0d, 0x01, 0x02, 0x04, 0x00, 0x00, 0x21, 0x08, 0x00, 0x22, 0x10, - 0x00, 0x20, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xcd, 0x04, 0x00, 0x00, 0x03, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xc6, - 0x68, 0x00, 0x20, 0x00, - 0x01, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xe3, 0x08, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, - 0x00, 0x07, 0x20, 0x01, 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x20, - 0x00, 0x01, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x01, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x03, 0x01, 0x00, 0x00, 0x04, 0x1c, 0x00, 0x30, 0x32, 0x34, 0x36, 0x38, - 0x3a, 0x3c, 0x40, 0x42, - 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, - 0x80, 0x81, 0x82, 0x83, - 0x84, 0x1a, 0x00, 0xfe, 0xad, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x01, 0x30, 0x00, 0xbf, - 0x06, 0x1e, 0x00, 0x59, - 0x03, 0x28, 0x00, 0x86, 0x03, 0x02, 0x00, 0x90, 0x03, 0x38, 0x00, 0xd1, - 0x03, 0xc8, 0x00, 0x1f, - 0x06, 0x30, 0x00, 0x52, 0x06, 0x18, 0x00, 0x6d, 0x06, 0x18, 0x00, 0x88, - 0x06, 0x18, 0x00, 0x8b, - 0x07, 0x08, 0x00, 0xcf, 0x07, 0x12, 0x00, 0xe1, 0x07, 0x12, 0x00, 0xf3, - 0x07, 0x12, 0x00, 0x05, - 0x08, 0x12, 0x00, 0x1a, 0x08, 0x0a, 0x00, 0x24, 0x08, 0x0a, 0x00, 0x2e, - 0x08, 0x0a, 0x00, 0x38, - 0x08, 0x0a, 0x00, 0x45, 0x08, 0x0a, 0x00, 0x4f, 0x08, 0x0a, 0x00, 0x59, - 0x08, 0x0a, 0x00, 0x63, - 0x08, 0x0a, 0x00, 0x75, 0x08, 0x0a, 0x00, 0x7f, 0x08, 0x0a, 0x00, 0x89, - 0x08, 0x0a, 0x00, 0x93, - 0x08, 0x0a, 0x00, 0x9d, 0x08, 0x0a, 0x00, 0xa7, 0x08, 0x0a, 0x00, 0xb1, - 0x08, 0x0a, 0x00, 0xbb, - 0x08, 0x0a, 0x00, 0xc5, 0x08, 0x0a, 0x00, 0xcf, 0x08, 0x0a, 0x00, 0xd9, - 0x08, 0x0a, 0x00, 0xe3, - 0x08, 0x0a, 0x00, 0xed, 0x08, 0x0a, 0x00, 0xf7, 0x08, 0x0a, 0x00, 0x01, - 0x09, 0x0a, 0x00, 0x0b, - 0x09, 0x0a, 0x00, 0x06, 0x5d, 0x00, 0xfc, 0xff, 0x02, 0x80, 0x00, 0x07, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x80, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x11, 0x07, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x10, 0x04, 0x00, 0x8e, 0x29, 0x00, 0x80, 0x9c, 0x01, 0x07, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x9c, 0x11, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0xff, 0xff, 0x07, 0x07, 0x00, 0xfe, 0xff, 0xce, 0x18, 0x00, 0xff, - 0xff, 0x08, 0x3d, 0x00, - 0xfc, 0xff, 0x02, 0x40, 0xf0, 0x04, 0x00, 0x01, 0x00, 0x00, 0x01, 0x44, - 0xf0, 0x04, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x48, 0xf0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, - 0xf0, 0x04, 0x00, 0x00, - 0x00, 0x03, 0x03, 0x50, 0xf0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, - 0xf0, 0x04, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x58, 0xf0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0x0a, 0xcb, 0x00, - 0x0a, 0x80, 0x04, 0x60, 0x03, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0x00, - 0x05, 0x58, 0x02, 0xff, - 0xff, 0xff, 0xbf, 0xff, 0xff, 0x00, 0x05, 0xc0, 0x03, 0xff, 0xff, 0xff, - 0xbf, 0xff, 0xff, 0x80, - 0x07, 0xa0, 0x05, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0xff, 0xff, 0x40, 0x07, 0x70, 0x05, 0xff, 0xff, 0xff, 0xbf, 0xff, - 0xff, 0x00, 0x07, 0x40, - 0x05, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0x80, 0x02, 0xe0, 0x01, 0xff, - 0x1b, 0xfe, 0x07, 0xff, - 0xff, 0x20, 0x03, 0x58, 0x02, 0xff, 0x1b, 0xfe, 0x07, 0xff, 0xff, 0x00, - 0x04, 0x00, 0x03, 0xff, - 0x1b, 0xfe, 0x07, 0xff, 0xff, 0x40, 0x06, 0xb0, 0x04, 0xff, 0x1b, 0xff, - 0x07, 0xff, 0xff, 0x00, - 0x08, 0x00, 0x06, 0xff, 0xdb, 0xff, 0x07, 0xff, 0xff, 0x00, 0x05, 0x00, - 0x04, 0xff, 0x1b, 0xfe, - 0x07, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xff, 0xff, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x0b, - 0xc7, 0x00, 0x21, 0x40, - 0x00, 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, - 0x05, 0x70, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x02, 0x05, 0x72, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x50, 0x00, 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x20, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x20, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x11, 0x00, 0x4a, 0x00, 0x04, 0x00, - 0x03, 0x08, 0x3c, 0x84, - 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x0d, 0x03, 0x00, - 0xf7, 0x03, 0xc8, 0x0e, - 0x09, 0x00, 0x01, 0x90, 0x05, 0x5a, 0x00, 0xec, 0x05, 0x2d, 0x00, 0x0f, - 0x8b, 0x00, 0x09, 0x0a, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x05, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x84, 0x00, - 0x10, 0x00, 0x03, 0x08, - 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x08, 0x00, 0x04, 0x00, 0x00, 0x04, - 0x08, 0x00, 0x40, 0x00, - 0x00, 0x40, 0x08, 0x00, 0x20, 0x00, 0x00, 0x20, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x08, - 0x00, 0x03, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x08, 0x00, 0x04, - 0x00, 0x00, 0x04, 0x08, - 0x00, 0x40, 0x00, 0x00, 0x40, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, - 0x03, 0x01, 0x00, 0x00, - 0x01, 0x08, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0x01, 0x04, 0x00, - 0x04, 0x00, 0x00, 0x04, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x01, 0x00, 0x00, 0x01, - 0x08, 0x00, 0x00, 0x08, - 0x00, 0x02, 0x00, 0x00, 0x01, 0x04, 0x00, 0x04, 0x00, 0x00, 0x04, 0x08, - 0x00, 0x00, 0x00, 0x00, - 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, - 0x0c, 0x00, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x20, - 0x00, 0x0f, 0x02, 0x09, - 0x00, 0x05, 0x00, 0x03, 0x00, 0x00, 0x09, 0x00, 0x05, 0x00, 0x03, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x14, 0x9e, 0x00, - 0x06, 0x1a, 0x03, 0xff, 0x00, 0x03, 0xe0, 0x01, 0x07, 0x3c, 0x40, 0x0b, - 0x00, 0xc0, 0x30, 0xe0, - 0x14, 0x10, 0x18, 0x48, 0x36, 0x00, 0x05, 0xa3, 0x10, 0x00, 0x00, 0x18, - 0x03, 0xff, 0xc0, 0x03, - 0x58, 0x02, 0x07, 0x3c, 0xc8, 0x11, 0xc0, 0x00, 0x31, 0x58, 0x18, 0x20, - 0x20, 0x60, 0x36, 0x00, - 0x05, 0xa3, 0x10, 0x00, 0x00, 0x18, 0x03, 0xff, 0x00, 0x05, 0x20, 0x03, - 0x07, 0x3c, 0x9e, 0x20, - 0x00, 0x90, 0x51, 0x20, 0x1f, 0x30, 0x48, 0x80, 0x36, 0x00, 0x05, 0xa3, - 0x10, 0x00, 0x00, 0x18, - 0x03, 0xff, 0x00, 0x03, 0xe0, 0x01, 0x07, 0x32, 0x2c, 0x09, 0x00, 0xa0, - 0x30, 0xe0, 0x1a, 0x10, - 0x18, 0x10, 0x36, 0x00, 0x05, 0xa3, 0x10, 0x00, 0x00, 0x18, 0x03, 0xff, - 0xc0, 0x03, 0x58, 0x02, - 0x07, 0x32, 0xb2, 0x0d, 0xc0, 0xa0, 0x30, 0x58, 0x1a, 0x20, 0x18, 0x10, - 0x36, 0x00, 0x05, 0xa3, - 0x10, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3c, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x16, 0x4b, - 0x00, 0x00, 0x00, 0x03, 0x07, 0x00, 0x00, 0x00, 0x00, 0x08, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x30, 0x84, 0x0e, 0x00, 0x00, 0x4c, 0x46, 0x50, 0x5f, - 0x50, 0x61, 0x6e, 0x65, - 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x4c, 0x46, 0x50, 0x5f, 0x50, 0x61, 0x6e, - 0x65, 0x6c, 0x4e, 0x61, - 0x6d, 0x65, 0x4c, 0x46, 0x50, 0x5f, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x4e, - 0x61, 0x6d, 0x65, 0x4c, - 0x46, 0x50, 0x5f, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, - 0x17, 0x48, 0x00, 0x64, - 0x19, 0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x18, 0x88, 0x36, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x18, 0x30, 0x2a, 0x00, 0x98, 0x51, 0x00, 0x30, 0x40, 0x30, 0x70, 0x13, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x1e, 0xa8, 0x2f, 0x78, 0xe0, 0x51, 0x1a, 0x26, 0x40, 0x58, - 0x98, 0x13, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1e, 0x48, 0x3f, 0x40, 0x30, 0x62, 0xb0, 0x32, - 0x40, 0x40, 0xc0, 0x13, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x18, 0x28, 0x00, 0x36, 0x7f, - 0x03, 0x00, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x0c, 0x36, 0x7f, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x0c, 0x36, 0x7f, - 0x01, 0x90, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x36, 0x7f, 0x06, 0x00, - 0x04, 0x00, 0x00, 0x00, - 0x00, 0x0c, 0x19, 0x28, 0x00, 0x19, 0x00, 0xfa, 0x00, 0xfa, 0x00, 0x19, - 0x00, 0x90, 0x01, 0x20, - 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0xc8, 0x00, 0x40, 0x00, 0x40, - 0x00, 0x40, 0x00, 0x40, - 0x00, 0x2c, 0x01, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x2c, - 0x01, 0x1a, 0x02, 0x00, - 0x00, 0x40, 0x1b, 0xc8, 0x00, 0xd0, 0x07, 0x0a, 0x00, 0xd0, 0x07, 0xf4, - 0x01, 0x88, 0x13, 0xd0, - 0x07, 0x0a, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x88, 0x13, 0xd0, 0x07, 0x0a, - 0x00, 0xd0, 0x07, 0xf4, - 0x01, 0x88, 0x13, 0xd0, 0x07, 0x0a, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x88, - 0x13, 0xd0, 0x07, 0x0a, - 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x88, 0x13, 0xd0, 0x07, 0x0a, 0x00, 0xd0, - 0x07, 0xf4, 0x01, 0x88, - 0x13, 0xd0, 0x07, 0x0a, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x88, 0x13, 0xd0, - 0x07, 0x0a, 0x00, 0xd0, - 0x07, 0xf4, 0x01, 0x88, 0x13, 0xd0, 0x07, 0x0a, 0x00, 0xd0, 0x07, 0xf4, - 0x01, 0x88, 0x13, 0xd0, - 0x07, 0x0a, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x88, 0x13, 0xd0, 0x07, 0x0a, - 0x00, 0xd0, 0x07, 0xf4, - 0x01, 0x88, 0x13, 0xd0, 0x07, 0x0a, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x88, - 0x13, 0xd0, 0x07, 0x0a, - 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x88, 0x13, 0xd0, 0x07, 0x0a, 0x00, 0xd0, - 0x07, 0xf4, 0x01, 0x88, - 0x13, 0xd0, 0x07, 0x0a, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x88, 0x13, 0xd0, - 0x07, 0x0a, 0x00, 0xd0, - 0x07, 0xf4, 0x01, 0x88, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x28, 0x18, 0x00, - 0x01, 0x00, 0x73, 0x00, 0x54, 0x05, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xa8, 0x0a, 0x00, 0x00, 0x29, 0x94, 0x00, 0x03, - 0xf2, 0x09, 0x20, 0x18, - 0x0a, 0x12, 0x2a, 0x0a, 0x0a, 0x34, 0x0a, 0x20, 0x5a, 0x0a, 0x12, 0x6c, - 0x0a, 0x0a, 0x76, 0x0a, - 0x20, 0x9c, 0x0a, 0x12, 0xae, 0x0a, 0x0a, 0xb8, 0x0a, 0x20, 0xde, 0x0a, - 0x12, 0xf0, 0x0a, 0x0a, - 0xfa, 0x0a, 0x20, 0x20, 0x0b, 0x12, 0x32, 0x0b, 0x0a, 0x3c, 0x0b, 0x20, - 0x62, 0x0b, 0x12, 0x74, - 0x0b, 0x0a, 0x7e, 0x0b, 0x20, 0xa4, 0x0b, 0x12, 0xb6, 0x0b, 0x0a, 0xc0, - 0x0b, 0x20, 0xe6, 0x0b, - 0x12, 0xf8, 0x0b, 0x0a, 0x02, 0x0c, 0x20, 0x28, 0x0c, 0x12, 0x3a, 0x0c, - 0x0a, 0x44, 0x0c, 0x20, - 0x6a, 0x0c, 0x12, 0x7c, 0x0c, 0x0a, 0x86, 0x0c, 0x20, 0xac, 0x0c, 0x12, - 0xbe, 0x0c, 0x0a, 0xc8, - 0x0c, 0x20, 0xee, 0x0c, 0x12, 0x00, 0x0d, 0x0a, 0x0a, 0x0d, 0x20, 0x30, - 0x0d, 0x12, 0x42, 0x0d, - 0x0a, 0x4c, 0x0d, 0x20, 0x72, 0x0d, 0x12, 0x84, 0x0d, 0x0a, 0x8e, 0x0d, - 0x20, 0xb4, 0x0d, 0x12, - 0xc6, 0x0d, 0x0a, 0xd0, 0x0d, 0x20, 0xf6, 0x0d, 0x12, 0x08, 0x0e, 0x0a, - 0x12, 0x0e, 0x0d, 0x2a, - 0xf0, 0x04, 0x80, 0x02, 0xe0, 0x01, 0x80, 0x11, 0x0e, 0x00, 0x00, 0x03, - 0x00, 0x00, 0x08, 0x72, - 0x0c, 0x00, 0xc4, 0x09, 0xfa, 0x00, 0x0c, 0x72, 0x0c, 0x00, 0xc4, 0x09, - 0xfa, 0x00, 0x10, 0x72, - 0x0c, 0x00, 0x05, 0x0f, 0x27, 0x00, 0xff, 0xff, 0xd6, 0x09, 0x80, 0x90, - 0x20, 0xe0, 0x1d, 0x10, - 0x08, 0x60, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x36, 0x7f, - 0x01, 0x00, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x0c, 0x00, 0x05, 0x20, 0x03, 0x80, 0x11, 0x0e, 0x00, - 0x00, 0x03, 0x00, 0x00, - 0x08, 0x72, 0x0c, 0x00, 0xc4, 0x09, 0xfa, 0x00, 0x0c, 0x72, 0x0c, 0x00, - 0xc4, 0x09, 0xfa, 0x00, - 0x10, 0x72, 0x0c, 0x00, 0x03, 0x0f, 0x27, 0x00, 0xff, 0xff, 0x12, 0x1b, - 0x00, 0x80, 0x50, 0x20, - 0x14, 0x30, 0x18, 0x20, 0x44, 0x00, 0x05, 0xa3, 0x10, 0x00, 0x00, 0x1f, - 0x30, 0xae, 0x11, 0x40, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xa0, 0x05, 0x84, 0x03, 0x80, 0x11, - 0x0e, 0x00, 0x00, 0x03, - 0x00, 0x00, 0x08, 0x72, 0x0c, 0x00, 0xc4, 0x09, 0xfa, 0x00, 0x0c, 0x72, - 0x0c, 0x00, 0xc4, 0x09, - 0xfa, 0x00, 0x10, 0x72, 0x0c, 0x00, 0x03, 0x0f, 0x27, 0x00, 0xff, 0xff, - 0xf0, 0x1c, 0xa0, 0xa0, - 0x50, 0x84, 0x1a, 0x30, 0x18, 0x10, 0x36, 0x00, 0x05, 0xa3, 0x10, 0x00, - 0x00, 0x18, 0x30, 0xae, - 0x14, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x05, 0x20, 0x03, - 0x80, 0x11, 0x0e, 0x00, - 0x3c, 0x03, 0x00, 0x00, 0x08, 0x72, 0x0c, 0x00, 0xc4, 0x09, 0xfa, 0x00, - 0x0c, 0x72, 0x0c, 0x00, - 0xc4, 0x09, 0xfa, 0x00, 0x10, 0x72, 0x0c, 0x00, 0x03, 0x0f, 0x27, 0x00, - 0xff, 0xff, 0x64, 0x19, - 0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x18, 0x88, 0x36, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x18, - 0x30, 0xae, 0x31, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x05, - 0x20, 0x03, 0x80, 0x11, - 0x0e, 0x00, 0x3c, 0x03, 0x00, 0x00, 0x08, 0x72, 0x0c, 0x00, 0xc4, 0x09, - 0xfa, 0x00, 0x0c, 0x72, - 0x0c, 0x00, 0xc4, 0x09, 0xfa, 0x00, 0x10, 0x72, 0x0c, 0x00, 0x03, 0x0f, - 0x27, 0x00, 0xff, 0xff, - 0xc7, 0x1b, 0x00, 0xa0, 0x50, 0x20, 0x17, 0x30, 0x30, 0x20, 0x36, 0x00, - 0x05, 0xa3, 0x10, 0x00, - 0x00, 0x18, 0x30, 0xae, 0x11, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, - 0x00, 0x05, 0x20, 0x03, - 0x80, 0x11, 0x0e, 0x00, 0x3c, 0x03, 0x00, 0x00, 0x08, 0x72, 0x0c, 0x00, - 0xc4, 0x09, 0xfa, 0x00, - 0x0c, 0x72, 0x0c, 0x00, 0xc4, 0x09, 0xfa, 0x00, 0x10, 0x72, 0x0c, 0x00, - 0x03, 0x0f, 0x27, 0x00, - 0xff, 0xff, 0xc0, 0x1b, 0x00, 0xab, 0x50, 0x20, 0x10, 0x30, 0x34, 0x40, - 0x33, 0x00, 0x05, 0xa3, - 0x10, 0x00, 0x00, 0x19, 0x30, 0xae, 0x11, 0x40, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x13, 0x00, 0x05, - 0x20, 0x03, 0x80, 0x11, 0x0e, 0x00, 0x3c, 0x03, 0x00, 0x00, 0x08, 0x72, - 0x0c, 0x00, 0xc4, 0x09, - 0xfa, 0x00, 0x0c, 0x72, 0x0c, 0x00, 0xc4, 0x09, 0xfa, 0x00, 0x10, 0x72, - 0x0c, 0x00, 0x03, 0x0f, - 0x27, 0x00, 0xff, 0xff, 0xcc, 0x1b, 0x00, 0xa1, 0x50, 0x20, 0x17, 0x30, - 0x31, 0x20, 0x36, 0x00, - 0x05, 0xa3, 0x10, 0x00, 0x00, 0x19, 0x30, 0xae, 0x10, 0x40, 0x00, 0x00, - 0x00, 0x00, 0x2d, 0x12, - 0x00, 0x05, 0x00, 0x03, 0x80, 0x11, 0x0e, 0x00, 0x00, 0x03, 0x00, 0x00, - 0x08, 0x72, 0x0c, 0x00, - 0xc4, 0x09, 0xfa, 0x00, 0x0c, 0x72, 0x0c, 0x00, 0xc4, 0x09, 0xfa, 0x00, - 0x10, 0x72, 0x0c, 0x00, - 0x03, 0x0f, 0x27, 0x00, 0xff, 0xff, 0xa9, 0x1a, 0x00, 0xa0, 0x50, 0x00, - 0x0a, 0x30, 0x30, 0x20, - 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x36, 0x7f, 0x03, 0x90, - 0x08, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x90, 0x06, 0x1a, 0x04, 0x80, 0x11, 0x0e, 0x00, 0x3c, 0x03, - 0x00, 0x00, 0x08, 0x72, - 0x0c, 0x00, 0xc4, 0x09, 0xfa, 0x00, 0x0c, 0x72, 0x0c, 0x00, 0xc4, 0x09, - 0xfa, 0x00, 0x10, 0x72, - 0x0c, 0x00, 0x03, 0x0f, 0x27, 0x00, 0xff, 0xff, 0x7c, 0x2e, 0x90, 0xa0, - 0x60, 0x1a, 0x1e, 0x40, - 0x30, 0x20, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x36, 0x7f, - 0x04, 0x90, 0x09, 0x00, - 0x00, 0x00, 0x00, 0x0c, 0x80, 0x07, 0xb0, 0x04, 0x80, 0x11, 0x0e, 0x00, - 0x3c, 0x03, 0x00, 0x00, - 0x08, 0x72, 0x0c, 0x00, 0xc4, 0x09, 0xfa, 0x00, 0x0c, 0x72, 0x0c, 0x00, - 0xc4, 0x09, 0xfa, 0x00, - 0x10, 0x72, 0x0c, 0x00, 0x05, 0x0f, 0x27, 0x00, 0xff, 0xff, 0x28, 0x3c, - 0x80, 0xa0, 0x70, 0xb0, - 0x23, 0x40, 0x30, 0x20, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, - 0x36, 0x7f, 0x05, 0x90, - 0x0a, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x04, 0x00, 0x03, 0x80, 0x11, - 0x0e, 0x00, 0x00, 0x03, - 0x00, 0x00, 0x08, 0x72, 0x0c, 0x00, 0xc4, 0x09, 0xfa, 0x00, 0x0c, 0x72, - 0x0c, 0x00, 0xc4, 0x09, - 0xfa, 0x00, 0x10, 0x72, 0x0c, 0x00, 0x05, 0x0f, 0x27, 0x00, 0xff, 0xff, - 0x64, 0x19, 0x00, 0x40, - 0x41, 0x00, 0x26, 0x30, 0x18, 0x88, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x1e, 0x36, 0x7f, - 0x03, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x04, 0x00, 0x03, - 0x80, 0x11, 0x0e, 0x00, - 0x00, 0x03, 0x00, 0x00, 0x08, 0x72, 0x0c, 0x00, 0xc4, 0x09, 0xfa, 0x00, - 0x0c, 0x72, 0x0c, 0x00, - 0xc4, 0x09, 0xfa, 0x00, 0x10, 0x72, 0x0c, 0x00, 0x03, 0x0f, 0x27, 0x00, - 0xff, 0xff, 0x64, 0x19, - 0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x18, 0x88, 0x36, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x1e, - 0x36, 0x7f, 0x03, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x04, - 0x00, 0x03, 0x80, 0x11, - 0x0e, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08, 0x72, 0x0c, 0x00, 0xc4, 0x09, - 0xfa, 0x00, 0x0c, 0x72, - 0x0c, 0x00, 0xc4, 0x09, 0xfa, 0x00, 0x10, 0x72, 0x0c, 0x00, 0x03, 0x0f, - 0x27, 0x00, 0xff, 0xff, - 0x64, 0x19, 0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x18, 0x88, 0x36, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x1e, 0x36, 0x7f, 0x03, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x0c, - 0x00, 0x05, 0x20, 0x03, - 0x80, 0x11, 0x0e, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08, 0x72, 0x0c, 0x00, - 0xc4, 0x09, 0xfa, 0x00, - 0x0c, 0x72, 0x0c, 0x00, 0xc4, 0x09, 0xfa, 0x00, 0x10, 0x72, 0x0c, 0x00, - 0x03, 0x0f, 0x27, 0x00, - 0xff, 0xff, 0xea, 0x1a, 0x00, 0xa0, 0x50, 0x20, 0x17, 0x30, 0x0c, 0x30, - 0x43, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x1e, 0x36, 0x7f, 0x03, 0x00, 0x0e, 0x00, 0x00, 0x00, - 0x00, 0x0c, 0x00, 0x05, - 0x58, 0x02, 0x80, 0x11, 0x0e, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08, 0x72, - 0x0c, 0x00, 0xc4, 0x09, - 0xfa, 0x00, 0x0c, 0x72, 0x0c, 0x00, 0xc4, 0x09, 0xfa, 0x00, 0x10, 0x72, - 0x0c, 0x00, 0x03, 0x0f, - 0x27, 0x00, 0xff, 0xff, 0x06, 0x18, 0x00, 0x70, 0x51, 0x58, 0x15, 0x20, - 0x38, 0x80, 0x13, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x36, 0x7f, 0x03, 0x00, 0x0f, 0x00, - 0x00, 0x00, 0x00, 0x0c, - 0x00, 0x08, 0x00, 0x06, 0x80, 0x11, 0x0e, 0x00, 0x3c, 0x03, 0x00, 0x00, - 0x08, 0x72, 0x0c, 0x00, - 0xc4, 0x09, 0xfa, 0x00, 0x0c, 0x72, 0x0c, 0x00, 0xc4, 0x09, 0xfa, 0x00, - 0x10, 0x72, 0x0c, 0x00, - 0x03, 0x0f, 0x27, 0x00, 0xff, 0xff, 0x29, 0x40, 0x00, 0x60, 0x80, 0x00, - 0x13, 0x60, 0x10, 0x10, - 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x36, 0x7f, 0x03, 0x00, - 0x10, 0x00, 0x00, 0x00, - 0x00, 0x0c, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x4d, - 0x50, 0x57, 0x58, 0x47, 0x41, 0x32, 0x32, 0x30, 0x4e, 0x49, 0x54, 0x00, - 0x4d, 0x50, 0x57, 0x58, - 0x47, 0x41, 0x2b, 0x32, 0x35, 0x30, 0x4e, 0x49, 0x54, 0x43, 0x5f, 0x44, - 0x42, 0x34, 0x30, 0x30, - 0x4e, 0x49, 0x54, 0x00, 0x00, 0x00, 0x43, 0x5f, 0x4d, 0x54, 0x50, 0x33, - 0x30, 0x30, 0x4e, 0x49, - 0x54, 0x00, 0x00, 0x43, 0x5f, 0x50, 0x50, 0x32, 0x32, 0x30, 0x4e, 0x49, - 0x54, 0x00, 0x00, 0x00, - 0x4d, 0x50, 0x43, 0x5f, 0x43, 0x43, 0x46, 0x4c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x70, 0x61, 0x6e, - 0x65, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x61, - 0x6e, 0x65, 0x6c, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x61, 0x6e, 0x65, 0x6c, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x70, 0x61, - 0x6e, 0x65, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, - 0x61, 0x6e, 0x65, 0x6c, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x61, 0x6e, 0x65, - 0x6c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x2b, 0x61, 0x00, 0x06, 0x4e, 0xdc, 0x00, 0x00, 0x58, 0xaa, - 0x4a, 0x71, 0x02, 0x04, - 0x58, 0xaa, 0x4a, 0xa5, 0x00, 0x04, 0x58, 0xaa, 0x4a, 0x96, 0x00, 0x02, - 0x58, 0xaa, 0x4a, 0x5a, - 0x00, 0x04, 0x58, 0xaa, 0x4a, 0xff, 0x00, 0x05, 0x58, 0xaa, 0x4a, 0xa5, - 0x00, 0x16, 0x58, 0xaa, - 0x4e, 0xdc, 0x00, 0x00, 0x58, 0xaa, 0x4e, 0xdc, 0x00, 0x00, 0x58, 0xaa, - 0x4e, 0xdc, 0x00, 0x00, - 0x58, 0xaa, 0x4e, 0xdc, 0x00, 0x00, 0x58, 0xaa, 0x4e, 0xdc, 0x00, 0x00, - 0x58, 0xaa, 0x4e, 0xdc, - 0x00, 0x00, 0x58, 0xaa, 0x4e, 0xdc, 0x00, 0x00, 0x58, 0xaa, 0x4e, 0xdc, - 0x00, 0x00, 0x58, 0xaa, - 0x4e, 0xdc, 0x00, 0x00, 0x58, 0xaa, 0x2c, 0x15, 0x00, 0x09, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, -}; diff --git a/src/mainboard/packardbell/ms2290/Makefile.inc b/src/mainboard/packardbell/ms2290/Makefile.inc index a9db8d8..b47ace2 100644 --- a/src/mainboard/packardbell/ms2290/Makefile.inc +++ b/src/mainboard/packardbell/ms2290/Makefile.inc @@ -18,4 +18,3 @@ ## smm-$(CONFIG_HAVE_SMI_HANDLER) += smihandler.c -ramstage-y += gma.c diff --git a/src/mainboard/packardbell/ms2290/gma.c b/src/mainboard/packardbell/ms2290/gma.c deleted file mode 100644 index 540d858..0000000 --- a/src/mainboard/packardbell/ms2290/gma.c +++ /dev/null @@ -1,272 +0,0 @@ -#include <arch/io.h> -#include <device/device.h> -#include <device/pci.h> -#include <device/pci_ids.h> -#include <device/pci_ops.h> - -#include "northbridge/intel/nehalem/nehalem.h" - -/* This array contains the information on flat panel. When using native - graphics init coreboot copies it to where VGA Option ROM would be so - that OS can find it and able to use internal display. This contains no - executable code and is just information on the panel. - */ - -unsigned char fake_vbt[] = { -0x24, 0x56, 0x42, 0x54, 0x20, 0x49, 0x52, 0x4f, 0x4e, 0x4c, 0x41, 0x4b, 0x45, 0x2d, 0x4d, 0x4f, -0x42, 0x49, 0x4c, 0x45, 0x64, 0x00, 0x30, 0x00, 0xc3, 0x10, 0xa4, 0x00, 0x30, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x42, 0x49, 0x4f, 0x53, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x20, -0x9b, 0x00, 0x16, 0x00, 0x93, 0x10, 0xfe, 0xea, 0x00, 0x00, 0x64, 0x01, 0x01, 0x0f, 0x0d, 0x31, -0x39, 0x39, 0x34, 0x49, 0x6e, 0x74, 0x65, 0x6c, 0x28, 0x52, 0x29, 0x49, 0x72, 0x6f, 0x6e, 0x6c, -0x61, 0x6b, 0x65, 0x20, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x20, 0x50, 0x43, 0x49, 0x20, 0x41, -0x63, 0x63, 0x65, 0x6c, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x20, 0x53, 0x56, 0x47, 0x41, 0x20, -0x42, 0x49, 0x4f, 0x53, 0x0d, 0x0a, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x20, 0x4e, 0x75, 0x6d, 0x62, -0x65, 0x72, 0x3a, 0x20, 0x69, 0x6c, 0x6d, 0x31, 0x39, 0x39, 0x34, 0x31, 0x2e, 0x6a, 0x76, 0x37, -0x20, 0x50, 0x43, 0x20, 0x31, 0x34, 0x2e, 0x33, 0x34, 0x20, 0x20, 0x30, 0x35, 0x2f, 0x32, 0x36, -0x2f, 0x32, 0x30, 0x31, 0x30, 0x20, 0x20, 0x31, 0x39, 0x3a, 0x32, 0x32, 0x3a, 0x30, 0x33, 0x0d, -0x0a, 0x44, 0x45, 0x43, 0x4f, 0x4d, 0x50, 0x49, 0x4c, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x20, 0x4f, -0x52, 0x20, 0x44, 0x49, 0x53, 0x41, 0x53, 0x53, 0x45, 0x4d, 0x42, 0x4c, 0x59, 0x20, 0x50, 0x52, -0x4f, 0x48, 0x49, 0x42, 0x49, 0x54, 0x45, 0x44, 0x0d, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x43, 0x6f, -0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x43, 0x29, 0x20, 0x32, 0x30, 0x30, 0x30, -0x2d, 0x32, 0x30, 0x30, 0x33, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x6c, 0x20, 0x43, 0x6f, 0x72, 0x70, -0x2e, 0x20, 0x41, 0x6c, 0x6c, 0x20, 0x52, 0x69, 0x67, 0x68, 0x74, 0x73, 0x20, 0x52, 0x65, 0x73, -0x65, 0x72, 0x76, 0x65, 0x64, 0x2e, 0x0d, 0x0a, 0x0d, 0x0a, 0x00, 0x00, 0xc0, 0x03, 0x08, 0x04, -0x01, 0x00, 0x00, 0x01, 0x05, 0x00, 0x07, 0x01, 0x00, 0x01, 0x01, 0xfe, 0x20, 0x00, 0x01, 0x01, -0x08, 0x08, 0x04, 0x04, 0x09, 0x08, 0x0c, 0x08, 0x05, 0x04, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0d, -0x01, 0x02, 0x04, 0x00, 0x00, 0x21, 0x08, 0x00, 0x22, 0x10, 0x00, 0x4c, 0x46, 0x50, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xc0, 0xd1, 0x04, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xd2, 0x60, 0x00, 0x20, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xe4, 0x01, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x05, -0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x20, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, -0x00, 0x00, 0x04, 0x1c, 0x00, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x40, 0x42, 0x44, 0x46, -0x48, 0x4a, 0x4c, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x80, 0x81, 0x82, 0x83, 0x84, 0x1a, -0x00, 0xfe, 0xac, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, -0x01, 0x00, 0x00, 0x00, 0x0e, 0x01, 0x20, 0x00, 0xf4, 0x07, 0x1e, 0x00, 0x8e, 0x04, 0x28, 0x00, -0xbb, 0x04, 0x02, 0x00, 0xc5, 0x04, 0x38, 0x00, 0x06, 0x05, 0xc8, 0x00, 0x54, 0x07, 0x30, 0x00, -0x87, 0x07, 0x18, 0x00, 0xa2, 0x07, 0x18, 0x00, 0xbd, 0x07, 0x18, 0x00, 0xc0, 0x08, 0x08, 0x00, -0x04, 0x09, 0x12, 0x00, 0x16, 0x09, 0x12, 0x00, 0x28, 0x09, 0x12, 0x00, 0x3a, 0x09, 0x12, 0x00, -0x4f, 0x09, 0x0a, 0x00, 0x59, 0x09, 0x0a, 0x00, 0x63, 0x09, 0x0a, 0x00, 0x6d, 0x09, 0x0a, 0x00, -0x7a, 0x09, 0x0a, 0x00, 0x84, 0x09, 0x0a, 0x00, 0x8e, 0x09, 0x0a, 0x00, 0x98, 0x09, 0x0a, 0x00, -0xaa, 0x09, 0x0a, 0x00, 0xb4, 0x09, 0x0a, 0x00, 0xbe, 0x09, 0x0a, 0x00, 0xc8, 0x09, 0x0a, 0x00, -0xd2, 0x09, 0x0a, 0x00, 0xdc, 0x09, 0x0a, 0x00, 0xe6, 0x09, 0x0a, 0x00, 0xf0, 0x09, 0x0a, 0x00, -0xfa, 0x09, 0x0a, 0x00, 0x04, 0x0a, 0x0a, 0x00, 0x0e, 0x0a, 0x0a, 0x00, 0x18, 0x0a, 0x0a, 0x00, -0x22, 0x0a, 0x0a, 0x00, 0x2c, 0x0a, 0x0a, 0x00, 0x36, 0x0a, 0x0a, 0x00, 0x40, 0x0a, 0x0a, 0x00, -0x06, 0xa5, 0x01, 0xfc, 0xff, 0x02, 0x14, 0x60, 0x0c, 0x00, 0x80, 0x00, 0x80, 0x04, 0x40, 0x60, -0x0c, 0x00, 0x07, 0x0d, 0x03, 0x00, 0x44, 0x60, 0x0c, 0x00, 0x07, 0x0d, 0x03, 0x00, 0x18, 0x60, -0x0c, 0x00, 0x80, 0x00, 0x80, 0x04, 0x48, 0x60, 0x0c, 0x00, 0x07, 0x0d, 0x03, 0x00, 0x4c, 0x60, -0x0c, 0x00, 0x07, 0x0d, 0x03, 0x00, 0x80, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, -0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x11, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, -0x04, 0x00, 0x00, 0x00, 0x00, 0x80, 0x9c, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x11, -0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x7f, 0x02, 0x1f, 0x03, 0x04, 0x00, -0x06, 0x00, 0x87, 0x02, 0x17, 0x03, 0x08, 0x00, 0x06, 0x00, 0x8f, 0x02, 0xef, 0x02, 0x0c, 0x00, -0x06, 0x00, 0xdf, 0x01, 0x0c, 0x02, 0x10, 0x00, 0x06, 0x00, 0xe7, 0x01, 0x04, 0x02, 0x14, 0x00, -0x06, 0x00, 0xe9, 0x01, 0xeb, 0x01, 0x1c, 0x00, 0x06, 0x00, 0xdf, 0x01, 0x7f, 0x02, 0x00, 0x10, -0x06, 0x00, 0x7f, 0x02, 0x1f, 0x03, 0x04, 0x10, 0x06, 0x00, 0x87, 0x02, 0x17, 0x03, 0x08, 0x10, -0x06, 0x00, 0x8f, 0x02, 0xef, 0x02, 0x0c, 0x10, 0x06, 0x00, 0xdf, 0x01, 0x0c, 0x02, 0x10, 0x10, -0x06, 0x00, 0xe7, 0x01, 0x04, 0x02, 0x14, 0x10, 0x06, 0x00, 0xe9, 0x01, 0xeb, 0x01, 0x1c, 0x10, -0x06, 0x00, 0xdf, 0x01, 0x7f, 0x02, 0x00, 0x00, 0x0e, 0x00, 0x7f, 0x02, 0x1f, 0x03, 0x04, 0x00, -0x0e, 0x00, 0x87, 0x02, 0x17, 0x03, 0x08, 0x00, 0x0e, 0x00, 0x8f, 0x02, 0xef, 0x02, 0x0c, 0x00, -0x0e, 0x00, 0xdf, 0x01, 0x0c, 0x02, 0x10, 0x00, 0x0e, 0x00, 0xe7, 0x01, 0x04, 0x02, 0x14, 0x00, -0x0e, 0x00, 0xe9, 0x01, 0xeb, 0x01, 0x00, 0x10, 0x0e, 0x00, 0x7f, 0x02, 0x1f, 0x03, 0x04, 0x10, -0x0e, 0x00, 0x87, 0x02, 0x17, 0x03, 0x08, 0x10, 0x0e, 0x00, 0x8f, 0x02, 0xef, 0x02, 0x0c, 0x10, -0x0e, 0x00, 0xdf, 0x01, 0x0c, 0x02, 0x10, 0x10, 0x0e, 0x00, 0xe7, 0x01, 0x04, 0x02, 0x14, 0x10, -0x0e, 0x00, 0xe9, 0x01, 0xeb, 0x01, 0x00, 0x50, 0x04, 0x00, 0x22, 0x06, 0x24, 0xc2, 0x08, 0x00, -0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, -0x04, 0x00, 0x8e, 0x29, 0x00, 0x80, 0x00, 0x11, 0x0e, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x40, -0x06, 0x00, 0x18, 0x00, 0x00, 0x00, 0x40, 0x11, 0x0e, 0x00, 0x18, 0x00, 0x00, 0x00, 0x50, 0x11, -0x0e, 0x00, 0x18, 0x00, 0x00, 0x00, 0x60, 0x11, 0x0e, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x07, 0x07, 0x00, 0xfe, 0xff, 0xce, 0x18, 0x00, -0xff, 0xff, 0x08, 0x3d, 0x00, 0xfc, 0xff, 0x02, 0x40, 0xf0, 0x04, 0x00, 0x01, 0x00, 0x00, 0x01, -0x44, 0xf0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0xf0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -0x4c, 0xf0, 0x04, 0x00, 0x00, 0x00, 0x03, 0x03, 0x50, 0xf0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -0x54, 0xf0, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x58, 0xf0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -0xff, 0xff, 0x0a, 0xcb, 0x00, 0x0a, 0x80, 0x02, 0xe0, 0x01, 0xff, 0xff, 0xff, 0xda, 0xff, 0xff, -0x20, 0x03, 0x58, 0x02, 0xff, 0x03, 0xfe, 0x07, 0xff, 0xff, 0x00, 0x04, 0x00, 0x03, 0xff, 0x1b, -0xfe, 0x07, 0xff, 0xff, 0x80, 0x04, 0x60, 0x03, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0x00, 0x05, -0x58, 0x02, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0x00, 0x05, 0xd0, 0x02, 0xff, 0x1b, 0xff, 0xbf, -0xff, 0xff, 0x00, 0x05, 0x00, 0x03, 0xff, 0x9b, 0xff, 0xbf, 0xff, 0xff, 0x00, 0x05, 0xc0, 0x03, -0xff, 0x9b, 0xff, 0x07, 0xff, 0xff, 0x00, 0x05, 0x00, 0x04, 0xff, 0x1b, 0xfe, 0x07, 0xff, 0xff, -0x56, 0x05, 0x00, 0x03, 0xff, 0x9b, 0xff, 0x07, 0xff, 0xff, 0x40, 0x06, 0x84, 0x03, 0xff, 0x1b, -0xfe, 0x07, 0xff, 0xff, 0x40, 0x06, 0xb0, 0x04, 0xff, 0x1b, 0xfe, 0x07, 0xff, 0xff, 0x00, 0x07, -0x40, 0x05, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0x40, 0x07, 0x70, 0x05, 0xff, 0xff, 0xff, 0x07, -0xff, 0xff, 0x80, 0x07, 0x38, 0x04, 0xff, 0x1b, 0xff, 0x07, 0xff, 0xff, 0x80, 0x07, 0xb0, 0x04, -0xff, 0xdb, 0xff, 0x07, 0xff, 0xff, 0x80, 0x07, 0xa0, 0x05, 0xff, 0x9b, 0xff, 0x07, 0xff, 0xff, -0x00, 0x08, 0x00, 0x06, 0xff, 0xdb, 0xff, 0x07, 0xff, 0xff, 0x78, 0x05, 0x1a, 0x04, 0xff, 0x9b, -0xff, 0x07, 0xff, 0xff, 0x90, 0x06, 0xb1, 0x03, 0xff, 0x1b, 0xff, 0x07, 0xff, 0xff, 0x00, 0x00, -0x0b, 0xc7, 0x00, 0x21, 0x40, 0x00, 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x09, 0x06, 0x03, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x05, 0x72, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x20, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x11, 0x00, 0x4e, 0x56, 0x05, -0x00, 0x03, 0x10, 0x3c, 0x84, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x00, 0x01, 0x0d, 0x03, -0x00, 0x78, 0x01, 0x0a, 0x0e, 0x09, 0x00, 0x01, 0xc5, 0x06, 0x5a, 0x00, 0x21, 0x07, 0x2d, 0x00, -0x0f, 0x8b, 0x00, 0x09, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, -0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x84, -0x00, 0x10, 0x00, 0x03, 0x01, 0x08, 0x00, 0x04, 0x08, 0x00, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, -0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x01, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x08, 0x00, -0x02, 0x00, 0x00, 0x01, 0x04, 0x00, 0x04, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, -0x00, 0x03, 0x01, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0x01, 0x04, -0x00, 0x04, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x01, 0x00, 0x00, -0x01, 0x08, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0x01, 0x04, 0x00, 0x04, 0x00, 0x00, 0x04, -0x08, 0x00, 0x00, 0x00, 0x00, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x12, 0x0c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, -0x20, 0x00, 0x0f, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x14, 0x9e, 0x00, 0x06, 0x1a, 0x03, 0x99, 0x00, 0x05, 0x20, 0x03, 0x07, 0x3c, 0xa9, -0x20, 0x00, 0x90, 0x51, 0x20, 0x1c, 0x30, 0x08, 0x88, 0x93, 0x00, 0x00, 0x20, 0x53, 0x00, 0x00, -0x00, 0x01, 0x99, 0xa0, 0x05, 0x84, 0x03, 0x07, 0x3c, 0xab, 0x22, 0xa0, 0xa0, 0x50, 0x84, 0x1a, -0x30, 0x30, 0x20, 0x36, 0x00, 0x2f, 0xbe, 0x10, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x07, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3c, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, -0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x16, 0x4b, 0x00, 0x00, 0x00, 0x03, 0x07, 0x00, 0x00, 0x00, 0x00, 0x08, 0x01, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x84, 0x0e, 0x00, 0x00, 0x4c, 0x46, 0x50, -0x5f, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x4c, 0x46, 0x50, 0x5f, 0x50, 0x61, -0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x4c, 0x46, 0x50, 0x5f, 0x50, 0x61, 0x6e, 0x65, 0x6c, -0x4e, 0x61, 0x6d, 0x65, 0x4c, 0x46, 0x50, 0x5f, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, -0x65, 0x17, 0x48, 0x00, 0x64, 0x19, 0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x18, 0x88, 0x36, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x2a, 0x00, 0x98, 0x51, 0x00, 0x30, 0x40, 0x30, 0x70, -0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xa8, 0x2f, 0x78, 0xe0, 0x51, 0x1a, 0x26, 0x40, -0x58, 0x98, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x48, 0x3f, 0x40, 0x30, 0x62, 0xb0, -0x32, 0x40, 0x40, 0xc0, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x18, 0x28, 0x00, 0x36, -0x7f, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x36, 0x7f, 0x05, 0x00, 0x02, 0x00, 0x00, -0x00, 0x00, 0x0c, 0x36, 0x7f, 0x01, 0x90, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x36, 0x7f, 0x06, -0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x19, 0x28, 0x00, 0x19, 0x00, 0xfa, 0x00, 0xfa, 0x00, -0x19, 0x00, 0x90, 0x01, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0xc8, 0x00, 0x40, 0x00, -0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x2c, 0x01, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, -0x2c, 0x01, 0x1a, 0x02, 0x00, 0x00, 0x00, 0x1b, 0xc8, 0x00, 0xd0, 0x07, 0x0a, 0x00, 0xd0, 0x07, -0xf4, 0x01, 0x88, 0x13, 0xd0, 0x07, 0x0a, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x88, 0x13, 0xd0, 0x07, -0x0a, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x88, 0x13, 0xd0, 0x07, 0x0a, 0x00, 0xd0, 0x07, 0xf4, 0x01, -0x88, 0x13, 0xd0, 0x07, 0x0a, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x88, 0x13, 0xd0, 0x07, 0x0a, 0x00, -0xd0, 0x07, 0xf4, 0x01, 0x88, 0x13, 0xd0, 0x07, 0x0a, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x88, 0x13, -0xd0, 0x07, 0x0a, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x88, 0x13, 0xd0, 0x07, 0x0a, 0x00, 0xd0, 0x07, -0xf4, 0x01, 0x88, 0x13, 0xd0, 0x07, 0x0a, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x88, 0x13, 0xd0, 0x07, -0x0a, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x88, 0x13, 0xd0, 0x07, 0x0a, 0x00, 0xd0, 0x07, 0xf4, 0x01, -0x88, 0x13, 0xd0, 0x07, 0x0a, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x88, 0x13, 0xd0, 0x07, 0x0a, 0x00, -0xd0, 0x07, 0xf4, 0x01, 0x88, 0x13, 0xd0, 0x07, 0x0a, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x88, 0x13, -0xd0, 0x07, 0x0a, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x88, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x28, 0x18, 0x00, 0x02, 0x00, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x94, 0x00, -0x03, 0x27, 0x0b, 0x20, 0x4d, 0x0b, 0x12, 0x5f, 0x0b, 0x0a, 0x69, 0x0b, 0x20, 0x8f, 0x0b, 0x12, -0xa1, 0x0b, 0x0a, 0xab, 0x0b, 0x20, 0xd1, 0x0b, 0x12, 0xe3, 0x0b, 0x0a, 0xed, 0x0b, 0x20, 0x13, -0x0c, 0x12, 0x25, 0x0c, 0x0a, 0x2f, 0x0c, 0x20, 0x55, 0x0c, 0x12, 0x67, 0x0c, 0x0a, 0x71, 0x0c, -0x20, 0x97, 0x0c, 0x12, 0xa9, 0x0c, 0x0a, 0xb3, 0x0c, 0x20, 0xd9, 0x0c, 0x12, 0xeb, 0x0c, 0x0a, -0xf5, 0x0c, 0x20, 0x1b, 0x0d, 0x12, 0x2d, 0x0d, 0x0a, 0x37, 0x0d, 0x20, 0x5d, 0x0d, 0x12, 0x6f, -0x0d, 0x0a, 0x79, 0x0d, 0x20, 0x9f, 0x0d, 0x12, 0xb1, 0x0d, 0x0a, 0xbb, 0x0d, 0x20, 0xe1, 0x0d, -0x12, 0xf3, 0x0d, 0x0a, 0xfd, 0x0d, 0x20, 0x23, 0x0e, 0x12, 0x35, 0x0e, 0x0a, 0x3f, 0x0e, 0x20, -0x65, 0x0e, 0x12, 0x77, 0x0e, 0x0a, 0x81, 0x0e, 0x20, 0xa7, 0x0e, 0x12, 0xb9, 0x0e, 0x0a, 0xc3, -0x0e, 0x20, 0xe9, 0x0e, 0x12, 0xfb, 0x0e, 0x0a, 0x05, 0x0f, 0x20, 0x2b, 0x0f, 0x12, 0x3d, 0x0f, -0x0a, 0x47, 0x0f, 0x0d, 0x2a, 0xf0, 0x04, 0x80, 0x02, 0xe0, 0x01, 0x80, 0x11, 0x0e, 0x00, 0x00, -0x03, 0x00, 0x00, 0x08, 0x72, 0x0c, 0x00, 0xd0, 0x07, 0x58, 0x02, 0x0c, 0x72, 0x0c, 0x00, 0xd0, -0x07, 0xf4, 0x01, 0x10, 0x72, 0x0c, 0x00, 0x05, 0x0f, 0x27, 0x00, 0xff, 0xff, 0xd6, 0x09, 0x80, -0x90, 0x20, 0xe0, 0x1d, 0x10, 0x08, 0x60, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x36, -0x7f, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x20, 0x03, 0x58, 0x02, 0x80, 0x11, 0x0e, -0x00, 0x00, 0x03, 0x00, 0x00, 0x08, 0x72, 0x0c, 0x00, 0xd0, 0x07, 0x58, 0x02, 0x0c, 0x72, 0x0c, -0x00, 0xd0, 0x07, 0xf4, 0x01, 0x10, 0x72, 0x0c, 0x00, 0x05, 0x0f, 0x27, 0x00, 0xff, 0xff, 0xa0, -0x0f, 0x20, 0x00, 0x31, 0x58, 0x1c, 0x20, 0x28, 0x80, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x1e, 0x36, 0x7f, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x40, 0x06, 0x84, 0x03, 0x80, -0x11, 0x0e, 0x00, 0x3c, 0x03, 0x30, 0x00, 0x08, 0x72, 0x0c, 0x00, 0xb8, 0x0b, 0x2c, 0x01, 0x0c, -0x72, 0x0c, 0x00, 0xb8, 0x0b, 0x2c, 0x01, 0x10, 0x72, 0x0c, 0x00, 0x06, 0x0f, 0x27, 0x00, 0xff, -0xff, 0x2f, 0x26, 0x40, 0xb8, 0x60, 0x84, 0x0c, 0x30, 0x30, 0x30, 0x23, 0x00, 0x7e, 0xd7, 0x10, -0x00, 0x00, 0x19, 0x30, 0xe4, 0x89, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x05, 0x00, -0x04, 0x80, 0x11, 0x0e, 0x00, 0x3c, 0x03, 0x00, 0x00, 0x08, 0x72, 0x0c, 0x00, 0xd0, 0x07, 0x58, -0x02, 0x0c, 0x72, 0x0c, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x10, 0x72, 0x0c, 0x00, 0x05, 0x0f, 0x27, -0x00, 0xff, 0xff, 0x30, 0x2a, 0x00, 0x98, 0x51, 0x00, 0x30, 0x40, 0x30, 0x70, 0x13, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x1e, 0x36, 0x7f, 0x05, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x78, -0x05, 0x1a, 0x04, 0x80, 0x11, 0x0e, 0x00, 0x3c, 0x03, 0x00, 0x00, 0x08, 0x72, 0x0c, 0x00, 0xd0, -0x07, 0x58, 0x02, 0x0c, 0x72, 0x0c, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x10, 0x72, 0x0c, 0x00, 0x05, -0x0f, 0x27, 0x00, 0xff, 0xff, 0x30, 0x2a, 0x78, 0x20, 0x51, 0x1a, 0x10, 0x40, 0x10, 0x70, 0x13, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x36, 0x7f, 0x01, 0x90, 0x05, 0x00, 0x00, 0x00, 0x00, -0x0c, 0x78, 0x05, 0x1a, 0x04, 0x80, 0x11, 0x0e, 0x00, 0x3c, 0x03, 0x00, 0x00, 0x08, 0x72, 0x0c, -0x00, 0xd0, 0x07, 0x58, 0x02, 0x0c, 0x72, 0x0c, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x10, 0x72, 0x0c, -0x00, 0x05, 0x0f, 0x27, 0x00, 0xff, 0xff, 0xa8, 0x2f, 0x78, 0xe0, 0x51, 0x1a, 0x26, 0x40, 0x58, -0x98, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x36, 0x7f, 0x01, 0x90, 0x06, 0x00, 0x00, -0x00, 0x00, 0x0c, 0x40, 0x06, 0xb0, 0x04, 0x80, 0x11, 0x0e, 0x00, 0x3c, 0x03, 0x00, 0x00, 0x08, -0x72, 0x0c, 0x00, 0xd0, 0x07, 0x58, 0x02, 0x0c, 0x72, 0x0c, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x10, -0x72, 0x0c, 0x00, 0x05, 0x0f, 0x27, 0x00, 0xff, 0xff, 0x48, 0x3f, 0x40, 0x30, 0x62, 0xb0, 0x32, -0x40, 0x40, 0xc0, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x36, 0x7f, 0x06, 0x00, 0x07, -0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x05, 0x00, 0x03, 0x80, 0x11, 0x0e, 0x00, 0x00, 0x03, 0x00, -0x00, 0x08, 0x72, 0x0c, 0x00, 0xd0, 0x07, 0x58, 0x02, 0x0c, 0x72, 0x0c, 0x00, 0xd0, 0x07, 0xf4, -0x01, 0x10, 0x72, 0x0c, 0x00, 0x05, 0x0f, 0x27, 0x00, 0xff, 0xff, 0xa9, 0x1a, 0x00, 0xa0, 0x50, -0x00, 0x0a, 0x30, 0x30, 0x20, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x36, 0x7f, 0x03, -0x90, 0x08, 0x00, 0x00, 0x00, 0x00, 0x01, 0x90, 0x06, 0x1a, 0x04, 0x80, 0x11, 0x0e, 0x00, 0x3c, -0x03, 0x00, 0x00, 0x08, 0x72, 0x0c, 0x00, 0xd0, 0x07, 0x58, 0x02, 0x0c, 0x72, 0x0c, 0x00, 0xd0, -0x07, 0xf4, 0x01, 0x10, 0x72, 0x0c, 0x00, 0x05, 0x0f, 0x27, 0x00, 0xff, 0xff, 0x7c, 0x2e, 0x90, -0xa0, 0x60, 0x1a, 0x1e, 0x40, 0x30, 0x20, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x36, -0x7f, 0x04, 0x90, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x80, 0x07, 0xb0, 0x04, 0x80, 0x11, 0x0e, -0x00, 0x3c, 0x03, 0x00, 0x00, 0x08, 0x72, 0x0c, 0x00, 0xd0, 0x07, 0x58, 0x02, 0x0c, 0x72, 0x0c, -0x00, 0xd0, 0x07, 0xf4, 0x01, 0x10, 0x72, 0x0c, 0x00, 0x05, 0x0f, 0x27, 0x00, 0xff, 0xff, 0x28, -0x3c, 0x80, 0xa0, 0x70, 0xb0, 0x23, 0x40, 0x30, 0x20, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x1e, 0x36, 0x7f, 0x05, 0x90, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x04, 0x00, 0x03, 0x80, -0x11, 0x0e, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08, 0x72, 0x0c, 0x00, 0xd0, 0x07, 0x58, 0x02, 0x0c, -0x72, 0x0c, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x10, 0x72, 0x0c, 0x00, 0x05, 0x0f, 0x27, 0x00, 0xff, -0xff, 0x64, 0x19, 0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x18, 0x88, 0x36, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x1e, 0x36, 0x7f, 0x03, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x04, 0x00, -0x03, 0x80, 0x11, 0x0e, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08, 0x72, 0x0c, 0x00, 0xd0, 0x07, 0x58, -0x02, 0x0c, 0x72, 0x0c, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x10, 0x72, 0x0c, 0x00, 0x05, 0x0f, 0x27, -0x00, 0xff, 0xff, 0x64, 0x19, 0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x18, 0x88, 0x36, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x1e, 0x36, 0x7f, 0x03, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, -0x04, 0x00, 0x03, 0x80, 0x11, 0x0e, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08, 0x72, 0x0c, 0x00, 0xd0, -0x07, 0x58, 0x02, 0x0c, 0x72, 0x0c, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x10, 0x72, 0x0c, 0x00, 0x05, -0x0f, 0x27, 0x00, 0xff, 0xff, 0x64, 0x19, 0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x18, 0x88, 0x36, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x36, 0x7f, 0x03, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, -0x0c, 0x00, 0x05, 0x20, 0x03, 0x80, 0x11, 0x0e, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08, 0x72, 0x0c, -0x00, 0xd0, 0x07, 0x58, 0x02, 0x0c, 0x72, 0x0c, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x10, 0x72, 0x0c, -0x00, 0x05, 0x0f, 0x27, 0x00, 0xff, 0xff, 0xea, 0x1a, 0x00, 0xa0, 0x50, 0x20, 0x17, 0x30, 0x0c, -0x30, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x36, 0x7f, 0x03, 0x90, 0x0e, 0x00, 0x00, -0x00, 0x00, 0x0c, 0x00, 0x05, 0x58, 0x02, 0x80, 0x11, 0x0e, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08, -0x72, 0x0c, 0x00, 0xd0, 0x07, 0x58, 0x02, 0x0c, 0x72, 0x0c, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x10, -0x72, 0x0c, 0x00, 0x05, 0x0f, 0x27, 0x00, 0xff, 0xff, 0x06, 0x18, 0x00, 0x70, 0x51, 0x58, 0x15, -0x20, 0x38, 0x80, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x36, 0x7f, 0x03, 0x00, 0x0f, -0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x06, 0x80, 0x11, 0x0e, 0x00, 0x3c, 0x03, 0x00, -0x00, 0x08, 0x72, 0x0c, 0x00, 0xd0, 0x07, 0x58, 0x02, 0x0c, 0x72, 0x0c, 0x00, 0xd0, 0x07, 0xf4, -0x01, 0x10, 0x72, 0x0c, 0x00, 0x05, 0x0f, 0x27, 0x00, 0xff, 0xff, 0x29, 0x40, 0x00, 0x60, 0x80, -0x00, 0x13, 0x60, 0x10, 0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x36, 0x7f, 0x03, -0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x4c, 0x46, 0x50, 0x5f, 0x50, 0x61, 0x6e, 0x65, 0x6c, -0x4e, 0x61, 0x6d, 0x65, 0x4c, 0x46, 0x50, 0x5f, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, -0x65, 0x4c, 0x46, 0x50, 0x5f, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x4c, 0x46, -0x50, 0x5f, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x4c, 0x46, 0x50, 0x5f, 0x50, -0x61, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x4c, 0x46, 0x50, 0x5f, 0x50, 0x61, 0x6e, 0x65, -0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x4c, 0x46, 0x50, 0x5f, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x4e, 0x61, -0x6d, 0x65, 0x4c, 0x46, 0x50, 0x5f, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x4c, -0x46, 0x50, 0x5f, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x4c, 0x46, 0x50, 0x5f, -0x50, 0x61, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x4c, 0x46, 0x50, 0x5f, 0x50, 0x61, 0x6e -}; diff --git a/src/northbridge/intel/nehalem/gma.c b/src/northbridge/intel/nehalem/gma.c index 3a9dcf5..bc4c74d 100644 --- a/src/northbridge/intel/nehalem/gma.c +++ b/src/northbridge/intel/nehalem/gma.c @@ -32,7 +32,7 @@ #include <drivers/intel/gma/i915.h> #include <pc80/vga.h> #include <pc80/vga_io.h> - +#include <drivers/intel/gma/intel_bios.h> #include "chip.h" #include "nehalem.h" @@ -1044,9 +1044,55 @@ static void intel_gma_init(const struct northbridge_intel_nehalem_config *info, #endif } +static size_t generate_vbt(const struct northbridge_intel_nehalem_config *conf, + void *vbt) +{ + struct vbt_header *head = vbt; + struct bdb_header *bdb_head; + struct bdb_general_features *genfeat; + u8 *ptr; + + memset(head, 0, sizeof (*head)); + + memcpy (head->signature, "$VBT IRONLAKE-MOBILE", 20); + head->version = 100; + head->header_size = sizeof (*head); + head->bdb_offset = sizeof (*head); + + bdb_head = (struct bdb_header *) (head + 1); + memset(bdb_head, 0, sizeof (*bdb_head)); + memcpy(bdb_head->signature, "BIOS_DATA_BLOCK ", 16); + bdb_head->version = 0xa8; + bdb_head->header_size = sizeof (*bdb_head); + + ptr = (u8 *) (bdb_head + 1); + + ptr[0] = BDB_GENERAL_FEATURES; + ptr[1] = sizeof (*genfeat); + ptr[2] = sizeof (*genfeat) >> 8; + ptr += 3; + + genfeat = (struct bdb_general_features *) ptr; + memset(genfeat, 0, sizeof (*genfeat)); + genfeat->panel_fitting = 3; + genfeat->flexaim = 1; + genfeat->download_ext_vbt = 1; + genfeat->enable_ssc = conf->gpu_use_spread_spectrum_clock; + genfeat->ssc_freq = !conf->gpu_link_frequency_270_mhz; + genfeat->rsvd10 = 0x4; + genfeat->legacy_monitor_detect = 1; + genfeat->int_crt_support = 1; + genfeat->dp_ssc_enb = 1; + + ptr += sizeof (*genfeat); + + bdb_head->bdb_size = ptr - (u8 *)bdb_head; + head->vbt_size = ptr - (u8 *)head; + head->vbt_checksum = 0; + return ptr - (u8 *)head; +} #endif - static void gma_func0_init(struct device *dev) { u32 reg32; @@ -1080,23 +1126,21 @@ static void gma_func0_init(struct device *dev) intel_gma_init(conf, gtt_res->base, physbase, pio_res->base, lfb_res->base); } -#endif /* Linux relies on VBT for panel info. */ - if (read16(0xc0000) != 0xaa55) { - optionrom_header_t *oh = (void *)0xc0000; + if (read16(PCI_VGA_RAM_IMAGE_START) != OPROM_SIGNATURE) { + optionrom_header_t *oh = (void *)PCI_VGA_RAM_IMAGE_START; optionrom_pcir_t *pcir; - int sz; + size_t vbt_size; + size_t fake_oprom_size; - memset(oh->reserved, 0, 8192); + memset(oh, 0, 8192); - sz = (0x80 + sizeof(fake_vbt) + 511) / 512; - oh->signature = 0xaa55; - oh->size = sz; + oh->signature = OPROM_SIGNATURE; oh->pcir_offset = 0x40; oh->vbt_offset = 0x80; - pcir = (void *)0xc0040; + pcir = (void *)(PCI_VGA_RAM_IMAGE_START + 0x40); pcir->signature = 0x52494350; // PCIR pcir->vendor = dev->vendor; pcir->device = dev->device; @@ -1105,11 +1149,14 @@ static void gma_func0_init(struct device *dev) pcir->classcode[0] = dev->class >> 8; pcir->classcode[1] = dev->class >> 16; pcir->classcode[2] = dev->class >> 24; - pcir->imagelength = sz; pcir->indicator = 0x80; - memcpy((void *)0xc0080, fake_vbt, sizeof(fake_vbt)); + vbt_size = generate_vbt (conf, (void *)(PCI_VGA_RAM_IMAGE_START + 0x80)); + fake_oprom_size = (0x80 + vbt_size + 511) / 512; + oh->size = fake_oprom_size; + pcir->imagelength = fake_oprom_size; } +#endif /* Post VBIOS init */
1
0
0
0
Patch set updated for coreboot: 51935af ivybridge: LVDS gfx init.
by Vladimir Serbinenko
29 Jul '14
29 Jul '14
Vladimir Serbinenko (phcoder(a)gmail.com) just uploaded a new patch set to gerrit, which you can find at
http://review.coreboot.org/5285
-gerrit commit 51935af3abba705d56260ad8abb821a591a5edf4 Author: Vladimir Serbinenko <phcoder(a)gmail.com> Date: Sun Feb 23 00:10:35 2014 +0100 ivybridge: LVDS gfx init. Change-Id: If71e9c94922cd4283d5e175dfd8757d398a72be1 Signed-off-by: Vladimir Serbinenko <phcoder(a)gmail.com> --- src/mainboard/lenovo/x230/Kconfig | 6 + src/mainboard/lenovo/x230/devicetree.cb | 6 + src/northbridge/intel/sandybridge/Kconfig | 4 + src/northbridge/intel/sandybridge/Makefile.inc | 1 + src/northbridge/intel/sandybridge/chip.h | 5 + src/northbridge/intel/sandybridge/gma.c | 4 +- .../intel/sandybridge/gma_ivybridge_lvds.c | 515 +++++++++++++++++++++ 7 files changed, 540 insertions(+), 1 deletion(-) diff --git a/src/mainboard/lenovo/x230/Kconfig b/src/mainboard/lenovo/x230/Kconfig index cc6228d..f835ab4 100644 --- a/src/mainboard/lenovo/x230/Kconfig +++ b/src/mainboard/lenovo/x230/Kconfig @@ -13,6 +13,12 @@ config BOARD_SPECIFIC_OPTIONS # dummy select HAVE_CMOS_DEFAULT select HAVE_ACPI_RESUME select HAVE_SMI_HANDLER + select EARLY_CBMEM_INIT + select VGA + select INTEL_EDID + select MAINBOARD_HAS_NATIVE_VGA_INIT + select MAINBOARD_HAS_NATIVE_VGA_INIT_TEXTMODECFG + select IVYBRIDGE_LVDS # Workaround for EC/KBC IRQ1. select SERIRQ_CONTINUOUS_MODE diff --git a/src/mainboard/lenovo/x230/devicetree.cb b/src/mainboard/lenovo/x230/devicetree.cb index a76de5f..1a93ad8 100644 --- a/src/mainboard/lenovo/x230/devicetree.cb +++ b/src/mainboard/lenovo/x230/devicetree.cb @@ -10,6 +10,12 @@ chip northbridge/intel/sandybridge register "gpu_panel_power_down_delay" = "100" # T5+T6: 10ms register "gpu_panel_power_backlight_on_delay" = "2100" # T3: 210ms register "gpu_panel_power_backlight_off_delay" = "2100" # T4: 210ms + register "gpu_use_spread_spectrum_clock" = "1" + register "gpu_lvds_dual_channel" = "0" + register "gpu_link_frequency_270_mhz" = "1" + register "gpu_lvds_num_lanes" = "1" + register "gpu_cpu_backlight" = "0x1155" + register "gpu_pch_backlight" = "0x11551155" device cpu_cluster 0 on chip cpu/intel/socket_rPGA989 diff --git a/src/northbridge/intel/sandybridge/Kconfig b/src/northbridge/intel/sandybridge/Kconfig index 2ceb945..883d36f 100644 --- a/src/northbridge/intel/sandybridge/Kconfig +++ b/src/northbridge/intel/sandybridge/Kconfig @@ -51,6 +51,10 @@ config CACHE_MRC_SIZE_KB int default 512 +config IVYBRIDGE_LVDS + bool + default n + config MRC_CACHE_SIZE hex depends on !CHROMEOS diff --git a/src/northbridge/intel/sandybridge/Makefile.inc b/src/northbridge/intel/sandybridge/Makefile.inc index 536656b..532a970 100644 --- a/src/northbridge/intel/sandybridge/Makefile.inc +++ b/src/northbridge/intel/sandybridge/Makefile.inc @@ -20,6 +20,7 @@ ramstage-y += ram_calc.c ramstage-y += northbridge.c ramstage-y += gma.c +ramstage-$(CONFIG_IVYBRIDGE_LVDS) += gma_ivybridge_lvds.c ramstage-$(CONFIG_GENERATE_ACPI_TABLES) += acpi.c ramstage-y += mrccache.c diff --git a/src/northbridge/intel/sandybridge/chip.h b/src/northbridge/intel/sandybridge/chip.h index 17bc7e7..cc32c37 100644 --- a/src/northbridge/intel/sandybridge/chip.h +++ b/src/northbridge/intel/sandybridge/chip.h @@ -38,4 +38,9 @@ struct northbridge_intel_sandybridge_config { u32 gpu_cpu_backlight; /* CPU Backlight PWM value */ u32 gpu_pch_backlight; /* PCH Backlight PWM value */ + + int gpu_use_spread_spectrum_clock; + int gpu_lvds_dual_channel; + int gpu_link_frequency_270_mhz; + int gpu_lvds_num_lanes; }; diff --git a/src/northbridge/intel/sandybridge/gma.c b/src/northbridge/intel/sandybridge/gma.c index a82a284..d271a1a 100644 --- a/src/northbridge/intel/sandybridge/gma.c +++ b/src/northbridge/intel/sandybridge/gma.c @@ -650,7 +650,9 @@ static void gma_func0_init(struct device *dev) physbase = pci_read_config32(dev, 0x5c) & ~0xf; graphics_base = dev->resource_list[1].base; - i915lightup(conf, physbase, iobase, mmiobase, graphics_base); + int lightup_ok = i915lightup(conf, physbase, iobase, mmiobase, graphics_base); + if (lightup_ok) + gfx_set_init_done(1); #endif } diff --git a/src/northbridge/intel/sandybridge/gma_ivybridge_lvds.c b/src/northbridge/intel/sandybridge/gma_ivybridge_lvds.c new file mode 100644 index 0000000..1f53a74 --- /dev/null +++ b/src/northbridge/intel/sandybridge/gma_ivybridge_lvds.c @@ -0,0 +1,515 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013, 2014 Vladimir Serbinenko + * + * 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 or (at your option) + * any later version 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 + */ + +#include <arch/io.h> +#include <console/console.h> +#include <delay.h> +#include <device/device.h> +#include <string.h> + +#include <drivers/intel/gma/edid.h> +#include <drivers/intel/gma/i915.h> +#include "gma.h" +#include "chip.h" +#include <pc80/vga.h> +#include <pc80/vga_io.h> + +#if IS_ENABLED(CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT) + +static void link_train(u32 mmio) +{ + write32(mmio+0xf000c,0x40); + write32(mmio+0x60100,0x40000); + write32(mmio+0xf0018,0x8ff); + write32(mmio+0xf1018,0x8ff); + write32(mmio+0xf000c,0x2040); + mdelay(1); + write32(mmio+0xf000c,0x2050); + write32(mmio+0x60100,0x44000); + mdelay(1); + write32(mmio+0x70008,0x40); + write32(mmio+0xe0300,0x60000418); + write32(mmio+0xf000c,0x22050); + write32(mmio+0x70008,0x50); + write32(mmio+0x70008,0x80000050); +} + +static void link_normal_operation(u32 mmio) +{ + write32(mmio + FDI_TX_CTL(0), 0x80044f02); + write32(mmio + FDI_RX_CTL(0), + FDI_RX_ENABLE | FDI_6BPC + | 0x2f50); +} + +static void enable_port(u32 mmio) +{ + write32(mmio + 0xec008, 0x2c010000); + write32(mmio + 0xec020, 0x2c010000); + write32(mmio + 0xec038, 0x2c010000); + write32(mmio + 0xec050, 0x2c010000); + write32(mmio + 0xec408, 0x2c010000); + write32(mmio + 0xec420, 0x2c010000); + write32(mmio + 0xec438, 0x2c010000); + write32(mmio + 0xec450, 0x2c010000); + write32(mmio + 0xf0010, 0x200090); + write32(mmio + 0xf1010, 0x200090); + write32(mmio + 0xf2010, 0x200090); + write32(mmio + 0xfd034, 0x8420000); + write32(mmio + 0x45010, 0x3); + write32(mmio + 0xf0060, 0x10); + write32(mmio + 0xf1060, 0x10); + write32(mmio + 0xf2060, 0x10); + write32(mmio + 0x9840, 0x0); + write32(mmio + 0x42000, 0xa0000000); + write32(mmio + 0xe4f00, 0x100030c); + write32(mmio + 0xe4f04, 0xb8230c); + write32(mmio + 0xe4f08, 0x6f8930c); + write32(mmio + 0xe4f0c, 0x5f8e38e); + write32(mmio + 0xe4f10, 0xb8030c); + write32(mmio + 0xe4f14, 0xb78830c); + write32(mmio + 0xe4f18, 0x9f8d3cf); + write32(mmio + 0xe4f1c, 0x1e8030c); + write32(mmio + 0xe4f20, 0x9f863cf); + write32(mmio + 0xe4f24, 0xff803cf); + read32(mmio + 0xe4100); + write32(mmio + 0xc4030, 0x10); + write32(mmio + 0xe4110, 0x8004003e); + write32(mmio + 0xe4114, 0x80060000); + write32(mmio + 0xe4118, 0x1000000); + read32(mmio + 0xe4110); + write32(mmio + 0xe4110, 0x5344003e); + read32(mmio + 0xe4110); + write32(mmio + 0xe4110, 0x8054003e); + read32(mmio + 0xe4110); + read32(mmio + 0xe4110); + write32(mmio + 0xe4110, 0x5344003e); + mdelay(1); + read32(mmio + 0xe4110); + write32(mmio + 0xe4110, 0x8054003e); + read32(mmio + 0xe4110); + read32(mmio + 0xe4110); + write32(mmio + 0xe4110, 0x5344003e); + mdelay(1); + read32(mmio + 0xe4110); + write32(mmio + 0xe4110, 0x8054003e); + read32(mmio + 0xe4110); + read32(mmio + 0xe4110); + write32(mmio + 0xe4110, 0x5344003e); + mdelay(1); + read32(mmio + 0xc4000); + read32(mmio + 0xe1140); + write32(mmio + 0xc4030, 0x10); + read32(mmio + 0xc4000); + write32(mmio + 0xe4f00, 0x100030c); + write32(mmio + 0xe4f04, 0xb8230c); + write32(mmio + 0xe4f08, 0x6f8930c); + write32(mmio + 0xe4f0c, 0x5f8e38e); + write32(mmio + 0xe4f10, 0xb8030c); + write32(mmio + 0xe4f14, 0xb78830c); + write32(mmio + 0xe4f18, 0x9f8d3cf); + write32(mmio + 0xe4f1c, 0x1e8030c); + write32(mmio + 0xe4f20, 0x9f863cf); + write32(mmio + 0xe4f24, 0xff803cf); + read32(mmio + 0xe4200); + write32(mmio + 0xc4030, 0x1010); + write32(mmio + 0xe4210, 0x8004003e); + write32(mmio + 0xe4214, 0x80060000); + write32(mmio + 0xe4218, 0x1002000); + read32(mmio + 0xe4210); + write32(mmio + 0xe4210, 0x5344003e); + read32(mmio + 0xe4210); + write32(mmio + 0xe4210, 0x8054003e); + read32(mmio + 0xe4210); + read32(mmio + 0xe4210); + write32(mmio + 0xe4210, 0x5344003e); + mdelay(1); + read32(mmio + 0xe4210); + write32(mmio + 0xe4210, 0x8054003e); + read32(mmio + 0xe4210); + read32(mmio + 0xe4210); + write32(mmio + 0xe4210, 0x5344003e); + mdelay(1); + read32(mmio + 0xe4210); + write32(mmio + 0xe4210, 0x8054003e); + read32(mmio + 0xe4210); + read32(mmio + 0xe4210); + write32(mmio + 0xe4210, 0x5344003e); + mdelay(1); + read32(mmio + 0xc4000); +} + +int i915lightup(const struct northbridge_intel_sandybridge_config *info, + u32 physbase, u16 piobase, u32 mmio, u32 lfb) +{ + int i; + u8 edid_data[128]; + struct edid edid; + + write32(mmio + 0x00070080, 0x00000000); + write32(mmio + DSPCNTR(0), 0x00000000); + write32(mmio + 0x00071180, 0x00000000); + write32(mmio + CPU_VGACNTRL, 0x0000298e | VGA_DISP_DISABLE); + write32(mmio + 0x0007019c, 0x00000000); + write32(mmio + 0x0007119c, 0x00000000); + write32(mmio + 0x000fc008, 0x2c010000); + write32(mmio + 0x000fc020, 0x2c010000); + write32(mmio + 0x000fc038, 0x2c010000); + write32(mmio + 0x000fc050, 0x2c010000); + write32(mmio + 0x000fc408, 0x2c010000); + write32(mmio + 0x000fc420, 0x2c010000); + write32(mmio + 0x000fc438, 0x2c010000); + write32(mmio + 0x000fc450, 0x2c010000); + vga_gr_write(0x18, 0); + write32(mmio + 0x00042004, 0x02000000); + write32(mmio + 0x000fd034, 0x8421ffe0); + + /* Setup GTT. */ + for (i = 0; i < 0x2000; i++) + { + outl((i << 2) | 1, piobase); + outl(physbase + (i << 12) + 1, piobase + 4); + } + + vga_misc_write(0x67); + + u8 cr[] = { 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3, + 0xff + }; + vga_cr_write(0x11, 0); + + for (i = 0; i <= 0x18; i++) + vga_cr_write(i, cr[i]); + + enable_port(mmio); + + intel_gmbus_read_edid(mmio + PCH_GMBUS0, 3, 0x50, edid_data, 128); + decode_edid(edid_data, + sizeof(edid_data), &edid); + + + /* Disable screen memory to prevent garbage from appearing. */ + vga_sr_write(1, vga_sr_read(1) | 0x20); + + u32 hactive = edid.x_resolution; + u32 vactive = edid.y_resolution; + u32 right_border = edid.hborder; + u32 bottom_border = edid.vborder; + int hpolarity = (edid.phsync == '-'); + int vpolarity = (edid.pvsync == '-'); + u32 vsync = edid.vspw; + u32 hsync = edid.hspw; + u32 vblank = edid.vbl; + u32 hblank = edid.hbl; + u32 hfront_porch = edid.hso; + u32 vfront_porch = edid.vso; + + u32 candp1, candn; + u32 best_delta = 0xffffffff; + + u32 target_frequency = info->gpu_lvds_dual_channel ? edid.pixel_clock + : (2 * edid.pixel_clock); + u32 pixel_p1 = 1; + u32 pixel_n = 1; + u32 pixel_m1 = 1; + u32 pixel_m2 = 1; + +#if !IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE) + vga_textmode_init(); +#else + vga_sr_write(1, 1); + vga_sr_write(0x2, 0xf); + vga_sr_write(0x3, 0x0); + vga_sr_write(0x4, 0xe); + vga_gr_write(0, 0x0); + vga_gr_write(1, 0x0); + vga_gr_write(2, 0x0); + vga_gr_write(3, 0x0); + vga_gr_write(4, 0x0); + vga_gr_write(5, 0x0); + vga_gr_write(6, 0x5); + vga_gr_write(7, 0xf); + vga_gr_write(0x10, 0x1); + vga_gr_write(0x11, 0); + + edid.bytes_per_line = (edid.bytes_per_line + 63) & ~63; + + write32(mmio + DSPCNTR(0), DISPPLANE_BGRX888); + write32(mmio + DSPADDR(0), 0); + write32(mmio + DSPSTRIDE(0), edid.bytes_per_line); + write32(mmio + DSPSURF(0), 0); + for (i = 0; i < 0x100; i++) + write32(mmio + LGC_PALETTE(0) + 4 * i, i * 0x010101); +#endif + + /* Find suitable divisors. */ + for (candp1 = 1; candp1 <= 8; candp1++) { + for (candn = 5; candn <= 10; candn++) { + u32 cur_frequency; + u32 m; /* 77 - 131. */ + u32 denom; /* 35 - 560. */ + u32 current_delta; + + denom = candn * candp1 * 7; + /* Doesnt overflow for up to + 5000000 kHz = 5 GHz. */ + m = (target_frequency * denom + 60000) / 120000; + + if (m < 77 || m > 131) + continue; + + cur_frequency = (120000 * m) / denom; + if (target_frequency > cur_frequency) + current_delta = target_frequency - cur_frequency; + else + current_delta = cur_frequency - target_frequency; + + + if (best_delta > current_delta) { + best_delta = current_delta; + pixel_n = candn; + pixel_p1 = candp1; + pixel_m2 = ((m + 3) % 5) + 7; + pixel_m1 = (m - pixel_m2) / 5; + } + } + } + + if (best_delta == 0xffffffff) { + printk (BIOS_ERR, "Couldn't find GFX clock divisors\n"); + return 0; + } + + u32 link_frequency = info->gpu_link_frequency_270_mhz ? 270000 : 162000; + u32 data_m1; + u32 data_n1 = 0x00800000; + u32 link_m1; + u32 link_n1 = 0x00080000; + + link_m1 = ((uint64_t)link_n1 * edid.pixel_clock) / link_frequency; + + data_m1 = ((uint64_t)data_n1 * 18 * edid.pixel_clock) + / (link_frequency * 8 * (info->gpu_lvds_num_lanes ? : 1)); + + printk(BIOS_INFO, "bringing up panel at resolution %d x %d\n", + hactive, vactive); + printk(BIOS_DEBUG, "Borders %d x %d\n", + right_border, bottom_border); + printk(BIOS_DEBUG, "Blank %d x %d\n", + hblank, vblank); + printk(BIOS_DEBUG, "Sync %d x %d\n", + hsync, vsync); + printk(BIOS_DEBUG, "Front porch %d x %d\n", + hfront_porch, vfront_porch); + printk(BIOS_DEBUG, (info->gpu_use_spread_spectrum_clock + ? "Spread spectrum clock\n" : "DREF clock\n")); + printk(BIOS_DEBUG, + info->gpu_lvds_dual_channel ? "Dual channel\n" : "Single channel\n"); + printk(BIOS_DEBUG, "Polarities %d, %d\n", + hpolarity, vpolarity); + printk(BIOS_DEBUG, "Data M1=%d, N1=%d\n", + data_m1, data_n1); + printk(BIOS_DEBUG, "Link frequency %d kHz\n", + link_frequency); + printk(BIOS_DEBUG, "Link M1=%d, N1=%d\n", + link_m1, link_n1); + printk(BIOS_DEBUG, "Pixel N=%d, M1=%d, M2=%d, P1=%d\n", + pixel_n, pixel_m1, pixel_m2, pixel_p1); + printk(BIOS_DEBUG, "Pixel clock %d kHz\n", + 120000 * (5 * pixel_m1 + pixel_m2) / pixel_n + / (pixel_p1 * 7)); + + write32(mmio + PCH_LVDS, + (hpolarity << 20) | (vpolarity << 21) + | (info->gpu_lvds_dual_channel ? LVDS_CLOCK_B_POWERUP_ALL + | LVDS_CLOCK_BOTH_POWERUP_ALL : 0) + | LVDS_BORDER_ENABLE | LVDS_CLOCK_A_POWERUP_ALL + | LVDS_DETECTED); + write32(mmio + BLC_PWM_CPU_CTL2, (1 << 31)); + write32(mmio + PCH_DREF_CONTROL, (info->gpu_use_spread_spectrum_clock + ? 0x1002 : 0x400)); + mdelay(1); + write32(mmio + PCH_PP_CONTROL, PANEL_UNLOCK_REGS + | (read32(mmio + PCH_PP_CONTROL) & ~PANEL_UNLOCK_MASK)); + write32(mmio + _PCH_FP0(0), + ((pixel_n - 2) << 16) + | ((pixel_m1 - 2) << 8) | pixel_m2); + write32(mmio + _PCH_DPLL(0), + DPLL_VCO_ENABLE | DPLLB_MODE_LVDS + | (info->gpu_lvds_dual_channel ? DPLLB_LVDS_P2_CLOCK_DIV_7 + : DPLLB_LVDS_P2_CLOCK_DIV_14) + | (0x10000 << (pixel_p1 - 1)) + | ((info->gpu_use_spread_spectrum_clock ? 3 : 0) << 13) + | (0x1 << (pixel_p1 - 1))); + + mdelay(1); + write32(mmio + 0xc7000, 0x8); + + mdelay(1); + write32(mmio + _PCH_DPLL(0), + DPLL_VCO_ENABLE | DPLLB_MODE_LVDS + | (info->gpu_lvds_dual_channel ? DPLLB_LVDS_P2_CLOCK_DIV_7 + : DPLLB_LVDS_P2_CLOCK_DIV_14) + | (0x10000 << (pixel_p1 - 1)) + | ((info->gpu_use_spread_spectrum_clock ? 3 : 0) << 13) + | (0x1 << (pixel_p1 - 1))); + /* Re-lock the registers. */ + write32(mmio + PCH_PP_CONTROL, + (read32(mmio + PCH_PP_CONTROL) & ~PANEL_UNLOCK_MASK)); + + write32(mmio + PCH_LVDS, + (hpolarity << 20) | (vpolarity << 21) + | (info->gpu_lvds_dual_channel ? LVDS_CLOCK_B_POWERUP_ALL + | LVDS_CLOCK_BOTH_POWERUP_ALL : 0) + | LVDS_BORDER_ENABLE | LVDS_CLOCK_A_POWERUP_ALL + | LVDS_DETECTED); + + write32(mmio + HTOTAL(0), + ((hactive + right_border + hblank - 1) << 16) + | (hactive - 1)); + write32(mmio + HBLANK(0), + ((hactive + right_border + hblank - 1) << 16) + | (hactive + right_border - 1)); + write32(mmio + HSYNC(0), + ((hactive + right_border + hfront_porch + hsync - 1) << 16) + | (hactive + right_border + hfront_porch - 1)); + + write32(mmio + VTOTAL(0), ((vactive + bottom_border + vblank - 1) << 16) + | (vactive - 1)); + write32(mmio + VBLANK(0), ((vactive + bottom_border + vblank - 1) << 16) + | (vactive + bottom_border - 1)); + write32(mmio + VSYNC(0), + (vactive + bottom_border + vfront_porch + vsync - 1) + | (vactive + bottom_border + vfront_porch - 1)); + + write32(mmio + PIPECONF(0), PIPECONF_DISABLE); + + write32(mmio + 0xf0008, 0); + +#if IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE) + write32(mmio + PIPESRC(0), ((hactive - 1) << 16) | (vactive - 1)); + write32(mmio + PF_CTL(0),0); + write32(mmio + PF_WIN_SZ(0), 0); + write32(mmio + PF_WIN_POS(0), 0); +#else + write32(mmio + PIPESRC(0), (719 << 16) | 399); + write32(mmio + PF_WIN_POS(0), 0); + write32(mmio + PF_CTL(0),PF_ENABLE | PF_FILTER_MED_3x3); + write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16)); +#endif + + mdelay(1); + + write32(mmio + PIPE_DATA_M1(0), 0x7e000000 | data_m1); + write32(mmio + PIPE_DATA_N1(0), data_n1); + write32(mmio + PIPE_LINK_M1(0), link_m1); + write32(mmio + PIPE_LINK_N1(0), link_n1); + + link_train(mmio); +#if IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE) + write32(mmio+CPU_VGACNTRL,0x298e | VGA_DISP_DISABLE); +#else + write32(mmio+CPU_VGACNTRL,0x298e); +#endif + write32(mmio+0x60100,0x44300); + write32(mmio+0x60100,0x80044f00); + + mdelay(1); + read32(mmio + 0x000f0014); // = 0x00000600 + +#if IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE) + write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE | DISPPLANE_BGRX888); + mdelay(1); +#endif + + write32(mmio + TRANS_HTOTAL(0), + ((hactive + right_border + hblank - 1) << 16) + | (hactive - 1)); + write32(mmio + TRANS_HBLANK(0), + ((hactive + right_border + hblank - 1) << 16) + | (hactive + right_border - 1)); + write32(mmio + TRANS_HSYNC(0), + ((hactive + right_border + hfront_porch + hsync - 1) << 16) + | (hactive + right_border + hfront_porch - 1)); + + write32(mmio + TRANS_VTOTAL(0), + ((vactive + bottom_border + vblank - 1) << 16) + | (vactive - 1)); + write32(mmio + TRANS_VBLANK(0), + ((vactive + bottom_border + vblank - 1) << 16) + | (vactive + bottom_border - 1)); + write32(mmio + TRANS_VSYNC(0), + (vactive + bottom_border + vfront_porch + vsync - 1) + | (vactive + bottom_border + vfront_porch - 1)); + + link_normal_operation(mmio); + + write32(mmio + PCH_PP_CONTROL, PANEL_UNLOCK_REGS | PANEL_POWER_OFF); + + mdelay(1); + + write32(mmio + PCH_TRANSCONF(0), TRANS_ENABLE | TRANS_6BPC +#if IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE) + | TRANS_STATE_MASK +#endif + ); + write32(mmio + PCH_LVDS, + LVDS_PORT_ENABLE + | (hpolarity << 20) | (vpolarity << 21) + | (info->gpu_lvds_dual_channel ? LVDS_CLOCK_B_POWERUP_ALL + | LVDS_CLOCK_BOTH_POWERUP_ALL : 0) + | LVDS_BORDER_ENABLE | LVDS_CLOCK_A_POWERUP_ALL + | LVDS_DETECTED); + + write32(mmio + PCH_PP_CONTROL, PANEL_UNLOCK_REGS | PANEL_POWER_OFF); + write32(mmio + PCH_PP_CONTROL, PANEL_UNLOCK_REGS | PANEL_POWER_RESET); + mdelay(1); + write32(mmio + PCH_PP_CONTROL, PANEL_UNLOCK_REGS + | PANEL_POWER_ON | PANEL_POWER_RESET); + + printk (BIOS_DEBUG, "waiting for panel powerup\n"); + while (1) + { + u32 reg32; + reg32 = read32(mmio + PCH_PP_STATUS); + if (((reg32 >> 28) & 3) == 0) + break; + } + printk (BIOS_DEBUG, "panel powered up\n"); + + write32(mmio + PCH_PP_CONTROL, PANEL_POWER_ON | PANEL_POWER_RESET); + + /* Enable screen memory. */ + vga_sr_write(1, vga_sr_read(1) & ~0x20); + + /* Clear interrupts. */ + write32(mmio + DEIIR, 0xffffffff); + write32(mmio + SDEIIR, 0xffffffff); + +#if IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE) + memset ((void *) lfb, 0, edid.x_resolution * edid.y_resolution * 4); + set_vbe_mode_info_valid(&edid, lfb); +#endif + return 1; +} + +#endif
1
0
0
0
Patch set updated for coreboot: 2064fe4 sandy/ivybridge: Native raminit.
by Vladimir Serbinenko
29 Jul '14
29 Jul '14
Vladimir Serbinenko (phcoder(a)gmail.com) just uploaded a new patch set to gerrit, which you can find at
http://review.coreboot.org/5786
-gerrit commit 2064fe496601c2d981318c3b64e8bc370b018e68 Author: Vladimir Serbinenko <phcoder(a)gmail.com> Date: Sun May 18 11:05:56 2014 +0200 sandy/ivybridge: Native raminit. Based on damo22's work and my X230 tracing. Works for my X230 in a variety of RAM configs. Also-By: Damien Zammit <damien(a)zamaudio.com> Change-Id: I1aa024c55a8416fc53b25e7123037df0e55a2769 Signed-off-by: Vladimir Serbinenko <phcoder(a)gmail.com> Signed-off-by: Damien Zammit <damien(a)zamaudio.com> --- src/cpu/intel/Makefile.inc | 1 + src/cpu/x86/smm/smmhandler_tseg.S | 2 +- src/cpu/x86/smm/smmrelocate.S | 4 +- src/device/dram/ddr3.c | 11 +- src/include/device/dram/ddr3.h | 5 + src/mainboard/lenovo/x230/Kconfig | 12 +- src/mainboard/lenovo/x230/romstage.c | 135 +- src/northbridge/intel/Makefile.inc | 1 + src/northbridge/intel/sandybridge/Kconfig | 13 +- src/northbridge/intel/sandybridge/Makefile.inc | 10 +- src/northbridge/intel/sandybridge/gma.c | 4 +- src/northbridge/intel/sandybridge/raminit_native.c | 3893 ++++++++++++++++++++ src/northbridge/intel/sandybridge/raminit_native.h | 29 + .../intel/sandybridge/raminit_patterns.h | 639 ++++ src/southbridge/intel/bd82x6x/Makefile.inc | 6 +- src/southbridge/intel/bd82x6x/early_me_native.c | 272 ++ src/southbridge/intel/bd82x6x/early_pch_native.c | 375 ++ src/southbridge/intel/bd82x6x/early_thermal.c | 70 + src/southbridge/intel/bd82x6x/pch.h | 2 + src/southbridge/intel/bd82x6x/smi.c | 3 - src/southbridge/intel/bd82x6x/usb_ehci.c | 33 + 21 files changed, 5411 insertions(+), 109 deletions(-) diff --git a/src/cpu/intel/Makefile.inc b/src/cpu/intel/Makefile.inc index 0392f69..68ea05d 100644 --- a/src/cpu/intel/Makefile.inc +++ b/src/cpu/intel/Makefile.inc @@ -19,6 +19,7 @@ subdirs-$(CONFIG_CPU_INTEL_SOCKET_RPGA989) += socket_rPGA989 subdirs-$(CONFIG_NORTHBRIDGE_INTEL_NEHALEM) += model_2065x subdirs-$(CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE) += model_206ax subdirs-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE) += model_206ax +subdirs-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE) += model_206ax subdirs-$(CONFIG_NORTHBRIDGE_INTEL_HASWELL) += haswell subdirs-$(CONFIG_NORTHBRIDGE_INTEL_FSP_SANDYBRIDGE) += fsp_model_206ax subdirs-$(CONFIG_NORTHBRIDGE_INTEL_FSP_IVYBRIDGE) += fsp_model_206ax diff --git a/src/cpu/x86/smm/smmhandler_tseg.S b/src/cpu/x86/smm/smmhandler_tseg.S index b33fcdf..380935a 100644 --- a/src/cpu/x86/smm/smmhandler_tseg.S +++ b/src/cpu/x86/smm/smmhandler_tseg.S @@ -57,7 +57,7 @@ #define SMI_UNLOCKED 1 #define __PRE_RAM__ -#if CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE || CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE +#if CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE || CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE || CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE #include <northbridge/intel/sandybridge/sandybridge.h> #define TSEG_BAR (DEFAULT_PCIEXBAR | TSEG) #elif CONFIG_NORTHBRIDGE_INTEL_NEHALEM diff --git a/src/cpu/x86/smm/smmrelocate.S b/src/cpu/x86/smm/smmrelocate.S index bdc9771..bc90fab 100644 --- a/src/cpu/x86/smm/smmrelocate.S +++ b/src/cpu/x86/smm/smmrelocate.S @@ -48,7 +48,7 @@ #if CONFIG_SMM_TSEG -#if CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE || CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE +#if CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE || CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE || CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE #include <northbridge/intel/sandybridge/sandybridge.h> #define TSEG_BAR (DEFAULT_PCIEXBAR | TSEG) #elif CONFIG_NORTHBRIDGE_INTEL_NEHALEM @@ -195,7 +195,7 @@ smm_relocate: xorl %edx, %edx wrmsr -#if CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE || CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE +#if CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE || CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE || CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE /* * IED base is top 4M of TSEG */ diff --git a/src/device/dram/ddr3.c b/src/device/dram/ddr3.c index 9b4f490..a43caed 100644 --- a/src/device/dram/ddr3.c +++ b/src/device/dram/ddr3.c @@ -110,7 +110,7 @@ int spd_decode_ddr3(dimm_attr * dimm, spd_raw_data spd) { int ret; u16 crc, spd_crc; - u8 ftb_divisor, ftb_dividend, capacity_shift, bus_width, sdram_width; + u8 ftb_divisor, ftb_dividend, capacity_shift, bus_width; u8 reg8; u32 mtb; /* medium time base */ unsigned int val, param; @@ -209,8 +209,8 @@ int spd_decode_ddr3(dimm_attr * dimm, spd_raw_data spd) printram(" Invalid SDRAM width\n"); ret = SPD_STATUS_INVALID_FIELD; } - sdram_width = (4 << val); - printram(" SDRAM width : %u\n", sdram_width); + dimm->width = (4 << val); + printram(" SDRAM width : %u\n", dimm->width); /* Memory bus width */ reg8 = spd[8]; @@ -236,7 +236,7 @@ int spd_decode_ddr3(dimm_attr * dimm, spd_raw_data spd) * capacity_shift * The rest is the JEDEC formula */ dimm->size_mb = ((1 << (capacity_shift + (25 - 20))) * bus_width - * dimm->ranks) / sdram_width; + * dimm->ranks) / dimm->width; /* Fine Timebase (FTB) Dividend/Divisor */ /* Dividend */ @@ -334,6 +334,9 @@ int spd_decode_ddr3(dimm_attr * dimm, spd_raw_data spd) printram(" DIMM Rank1 Address bits mirrored!!!\n"); } + dimm->reference_card = spd[62] & 0x1f; + printram(" DIMM Reference card %c\n", 'A' + dimm->reference_card); + return ret; } diff --git a/src/include/device/dram/ddr3.h b/src/include/device/dram/ddr3.h index b19c51c..ef0d0ec 100644 --- a/src/include/device/dram/ddr3.h +++ b/src/include/device/dram/ddr3.h @@ -37,6 +37,7 @@ * @{ */ #define TCK_1066MHZ 240 +#define TCK_933MHZ 275 #define TCK_800MHZ 320 #define TCK_666MHZ 384 #define TCK_533MHZ 480 @@ -137,6 +138,8 @@ typedef struct dimm_attr_st { u16 cas_supported; /* Flags extracted from SPD */ dimm_flags_t flags; + /* SDRAM width */ + u8 width; /* Number of ranks */ u8 ranks; /* Number or row address bits */ @@ -158,6 +161,8 @@ typedef struct dimm_attr_st { u32 tWTR; u32 tRTP; u32 tFAW; + + u8 reference_card; } dimm_attr; /** Result of the SPD decoding process */ diff --git a/src/mainboard/lenovo/x230/Kconfig b/src/mainboard/lenovo/x230/Kconfig index eb9cadc..cc6228d 100644 --- a/src/mainboard/lenovo/x230/Kconfig +++ b/src/mainboard/lenovo/x230/Kconfig @@ -3,7 +3,7 @@ if BOARD_LENOVO_X230 config BOARD_SPECIFIC_OPTIONS # dummy def_bool y select CPU_INTEL_SOCKET_RPGA989 - select NORTHBRIDGE_INTEL_IVYBRIDGE + select NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE select SOUTHBRIDGE_INTEL_C216 select EC_LENOVO_PMH7 select EC_LENOVO_H8 @@ -18,8 +18,8 @@ config BOARD_SPECIFIC_OPTIONS # dummy select SERIRQ_CONTINUOUS_MODE config HAVE_MRC_CACHE - bool - default n + bool + default y config HAVE_IFD_BIN bool @@ -41,10 +41,6 @@ config MMCONF_BASE_ADDRESS hex default 0xf0000000 -config CACHE_ROM_SIZE_OVERRIDE - hex - default 0x800000 - config IRQ_SLOT_COUNT int default 18 @@ -57,7 +53,7 @@ config USBDEBUG_HCD_INDEX int default 2 -config DRAM_GATE_GPIO +config DRAM_RESET_GATE_GPIO int default 10 diff --git a/src/mainboard/lenovo/x230/romstage.c b/src/mainboard/lenovo/x230/romstage.c index 8441db3..8c82e61 100644 --- a/src/mainboard/lenovo/x230/romstage.c +++ b/src/mainboard/lenovo/x230/romstage.c @@ -33,7 +33,7 @@ #include <cbmem.h> #include <console/console.h> #include "northbridge/intel/sandybridge/sandybridge.h" -#include "northbridge/intel/sandybridge/raminit.h" +#include "northbridge/intel/sandybridge/raminit_native.h" #include "southbridge/intel/bd82x6x/pch.h" #include "southbridge/intel/bd82x6x/gpio.h" #include <arch/cpu.h> @@ -109,66 +109,58 @@ static void rcba_config(void) RCBA32(BUC) = 0; } +static void +init_usb (void) +{ + const u32 rcba_dump[64] = { + /* 3500 */ 0x20000153, 0x20000153, 0x20000f57, 0x20000f57, + /* 3510 */ 0x20000f57, 0x20000f57, 0x20000153, 0x2000055b, + /* 3520 */ 0x20000153, 0x2000055b, 0x20000f57, 0x20000f57, + /* 3530 */ 0x20000f57, 0x20000f57, 0x00000000, 0x00000000, + /* 3540 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000, + /* 3550 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000, + /* 3560 */ 0x024c8001, 0x000024a3, 0x00040002, 0x01000050, + /* 3570 */ 0x02000772, 0x16000f9f, 0x1800ff4f, 0x0001d630, + /* 3580 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000, + /* 3590 */ 0x00000000, 0x00000000, 0x00000000, 0x00000040, + /* 35a0 */ 0x04000201, 0x00000200, 0x00000000, 0x00000000, + /* 35b0 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000, + /* 35c0 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000, + /* 35d0 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000, + /* 35e0 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000, + /* 35f0 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000, + }; + int i; + /* Activate PMBAR. */ + pci_write_config32(PCI_DEV(0, 0x1f, 0), PMBASE, DEFAULT_PMBASE | 1); + pci_write_config32(PCI_DEV(0, 0x1f, 0), PMBASE + 4, 0); + pci_write_config8(PCI_DEV(0, 0x1f, 0), 0x44 /* ACPI_CNTL */ , 0x80); /* Enable ACPI BAR */ + + /* Unlock registers. */ + outw (inw (DEFAULT_PMBASE | 0x003c) | 2, DEFAULT_PMBASE | 0x003c); + + for (i = 0; i < 64; i++) + write32 (DEFAULT_RCBABASE | (0x3500 + 4 * i), rcba_dump[i]); + + pcie_write_config32 (PCI_DEV (0, 0x14, 0), 0xe4, 0x00000000); + + /* Relock registers. */ + outw (0x0000, DEFAULT_PMBASE | 0x003c); +} + + void main(unsigned long bist) { - int boot_mode = 0; - int cbmem_was_initted; + int s3resume = 0; u32 pm1_cnt; u16 pm1_sts; + spd_raw_data spd[4]; if (MCHBAR16(SSKPD) == 0xCAFE) { outb(0x6, 0xcf9); hlt (); } - struct pei_data pei_data = { - .pei_version = PEI_VERSION, - .mchbar = DEFAULT_MCHBAR, - .dmibar = DEFAULT_DMIBAR, - .epbar = DEFAULT_EPBAR, - .pciexbar = CONFIG_MMCONF_BASE_ADDRESS, - .smbusbar = SMBUS_IO_BASE, - .wdbbar = 0x4000000, - .wdbsize = 0x1000, - .hpet_address = CONFIG_HPET_ADDRESS, - .rcba = DEFAULT_RCBABASE, - .pmbase = DEFAULT_PMBASE, - .gpiobase = DEFAULT_GPIOBASE, - .thermalbase = 0xfed08000, - .system_type = 0, // 0 Mobile, 1 Desktop/Server - .tseg_size = CONFIG_SMM_TSEG_SIZE, - .spd_addresses = { 0xA0, 0x00,0xA2,0x00 }, - .ts_addresses = { 0x00, 0x00, 0x00, 0x00 }, - .ec_present = 1, - .gbe_enable = 1, - .ddr3lv_support = 0, - // 0 = leave channel enabled - // 1 = disable dimm 0 on channel - // 2 = disable dimm 1 on channel - // 3 = disable dimm 0+1 on channel - .dimm_channel0_disabled = 2, - .dimm_channel1_disabled = 2, - .max_ddr3_freq = 1600, - .usb_port_config = { - /* enabled usb oc pin length */ - { 1, 0, 0x0080 }, /* P0 (left, fan side), OC 0 */ - { 1, 1, 0x0080 }, /* P1 (left touchpad side), OC 1 */ - { 1, 3, 0x0080 }, /* P2: dock, OC 3 */ - { 1, 0, 0x0040 }, /* P3: wwan, no OC */ - { 1, 0, 0x0080 }, /* P4: Wacom tablet on X230t, otherwise empty */ - { 1, 0, 0x0080 }, /* P5: Expresscard, no OC */ - { 0, 0, 0x0000 }, /* P6: Empty */ - { 1, 0, 0x0080 }, /* P7: dock, no OC */ - { 0, 0, 0x0000 }, /* P8: Empty */ - { 1, 5, 0x0080 }, /* P9: Right (EHCI debug), OC 5 */ - { 1, 0, 0x0040 }, /* P10: fingerprint reader, no OC */ - { 1, 0, 0x0040 }, /* P11: bluetooth, no OC. */ - { 1, 0, 0x0040 }, /* P12: wlan, no OC */ - { 1, 0, 0x0080 }, /* P13: webcam, no OC */ - }, - .ddr_refresh_rate_config = 2, /* Force double refresh rate */ - }; - timestamp_init(get_initial_timestamp()); timestamp_add_now(TS_START_ROMSTAGE); @@ -183,6 +175,8 @@ void main(unsigned long bist) setup_pch_gpios(&x230_gpio_map); + init_usb(); + /* Initialize console device(s) */ console_init(); @@ -204,7 +198,7 @@ void main(unsigned long bist) if ((pm1_sts & WAK_STS) && ((pm1_cnt >> 10) & 7) == 5) { if (acpi_s3_resume_allowed()) { printk(BIOS_DEBUG, "Resume from S3 detected.\n"); - boot_mode = 2; + s3resume = 1; /* Clear SLP_TYPE. This will break stage2 but * we care for that when we get there. */ @@ -218,31 +212,16 @@ void main(unsigned long bist) /* Enable SPD ROMs and DDR-III DRAM */ enable_smbus(); - /* Prepare USB controller early in S3 resume */ - if (boot_mode == 2) - enable_usb_bar(); - post_code(0x39); post_code(0x3a); - pei_data.boot_mode = boot_mode; timestamp_add_now(TS_BEFORE_INITRAM); - /* MRC.bin has a bug and sometimes halts (instead of reboot?). - */ - if (boot_mode != 2) - { - RCBA32(GCS) = RCBA32(GCS) & ~(1 << 5); /* reset */ - outw((0 << 11), DEFAULT_PMBASE | 0x60 | 0x08); /* let timer go */ - } - - sdram_initialize(&pei_data); + memset (spd, 0, sizeof (spd)); + read_spd (&spd[0], 0x50); + read_spd (&spd[2], 0x51); - if (boot_mode != 2) - { - RCBA32(GCS) = RCBA32(GCS) | (1 << 5); /* No reset */ - outw((1 << 11), DEFAULT_PMBASE | 0x60 | 0x08); /* halt timer */ - } + init_dram_ddr3 (spd, 1, TCK_800MHZ, s3resume); timestamp_add_now(TS_AFTER_INITRAM); post_code(0x3c); @@ -250,13 +229,7 @@ void main(unsigned long bist) rcba_config(); post_code(0x3d); - quick_ram_check(); - post_code(0x3e); - MCHBAR16(SSKPD) = 0xCAFE; - cbmem_was_initted = !cbmem_recovery(boot_mode==2); - if (boot_mode!=2) - save_mrc_data(&pei_data); #if CONFIG_HAVE_ACPI_RESUME /* If there is no high memory area, we didn't boot before, so @@ -266,18 +239,14 @@ void main(unsigned long bist) *(u32 *)CBMEM_BOOT_MODE = 0; *(u32 *)CBMEM_RESUME_BACKUP = 0; - if ((boot_mode == 2) && cbmem_was_initted) { + if (s3resume) { void *resume_backup_memory = cbmem_find(CBMEM_ID_RESUME); if (resume_backup_memory) { - *(u32 *)CBMEM_BOOT_MODE = boot_mode; + *(u32 *)CBMEM_BOOT_MODE = 2; *(u32 *)CBMEM_RESUME_BACKUP = (u32)resume_backup_memory; } /* Magic for S3 resume */ pci_write_config32(PCI_DEV(0, 0x00, 0), SKPAD, 0xcafed00d); - } else if (boot_mode == 2) { - /* Failed S3 resume, reset to come up cleanly */ - outb(0x6, 0xcf9); - hlt(); } else { pci_write_config32(PCI_DEV(0, 0x00, 0), SKPAD, 0xcafebabe); } diff --git a/src/northbridge/intel/Makefile.inc b/src/northbridge/intel/Makefile.inc index 808a1b2..f1c2540 100644 --- a/src/northbridge/intel/Makefile.inc +++ b/src/northbridge/intel/Makefile.inc @@ -15,6 +15,7 @@ subdirs-$(CONFIG_NORTHBRIDGE_INTEL_I5000) += i5000 subdirs-$(CONFIG_NORTHBRIDGE_INTEL_NEHALEM) += nehalem subdirs-$(CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE) += sandybridge subdirs-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE) += sandybridge +subdirs-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE) += sandybridge subdirs-$(CONFIG_NORTHBRIDGE_INTEL_HASWELL) += haswell subdirs-$(CONFIG_NORTHBRIDGE_INTEL_FSP_SANDYBRIDGE) += fsp_sandybridge subdirs-$(CONFIG_NORTHBRIDGE_INTEL_FSP_IVYBRIDGE) += fsp_sandybridge diff --git a/src/northbridge/intel/sandybridge/Kconfig b/src/northbridge/intel/sandybridge/Kconfig index f13b58d..2ceb945 100644 --- a/src/northbridge/intel/sandybridge/Kconfig +++ b/src/northbridge/intel/sandybridge/Kconfig @@ -33,7 +33,15 @@ config NORTHBRIDGE_INTEL_IVYBRIDGE select DYNAMIC_CBMEM select CPU_INTEL_MODEL_306AX -if NORTHBRIDGE_INTEL_SANDYBRIDGE || NORTHBRIDGE_INTEL_IVYBRIDGE +config NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE + bool + select CACHE_MRC_BIN + select MMCONF_SUPPORT + select MMCONF_SUPPORT_DEFAULT + select CPU_INTEL_MODEL_306AX + select HAVE_DEBUG_RAM_SETUP + +if NORTHBRIDGE_INTEL_SANDYBRIDGE || NORTHBRIDGE_INTEL_IVYBRIDGE || NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE config VGA_BIOS_ID string @@ -50,7 +58,8 @@ config MRC_CACHE_SIZE config DCACHE_RAM_BASE hex - default 0xff7e0000 + default 0xff7e0000 if !NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE + default 0xfefe0000 if NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE config DCACHE_RAM_SIZE hex diff --git a/src/northbridge/intel/sandybridge/Makefile.inc b/src/northbridge/intel/sandybridge/Makefile.inc index a201745..536656b 100644 --- a/src/northbridge/intel/sandybridge/Makefile.inc +++ b/src/northbridge/intel/sandybridge/Makefile.inc @@ -25,7 +25,10 @@ ramstage-$(CONFIG_GENERATE_ACPI_TABLES) += acpi.c ramstage-y += mrccache.c romstage-y += ram_calc.c -romstage-y += raminit.c +romstage-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE) += raminit.c +romstage-$(CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE) += raminit.c +romstage-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE) += raminit_native.c +romstage-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE) += ../../../device/dram/ddr3.c romstage-y += mrccache.c romstage-y += early_init.c romstage-y += report_platform.c @@ -48,7 +51,10 @@ $(obj)/mrc.cache: $(obj)/config.h cbfs-files-$(CONFIG_HAVE_MRC_CACHE) += mrc.cache mrc.cache-file := $(obj)/mrc.cache -mrc.cache-position := 0xfffd0000 +mrc-cache-position-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE) := 0xfffd0000 +mrc-cache-position-$(CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE) := 0xfffd0000 +mrc-cache-position-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE) := 0xfffe0000 +mrc.cache-position := $(mrc-cache-position-y) mrc.cache-type := 0xac endif diff --git a/src/northbridge/intel/sandybridge/gma.c b/src/northbridge/intel/sandybridge/gma.c index d271a1a..a82a284 100644 --- a/src/northbridge/intel/sandybridge/gma.c +++ b/src/northbridge/intel/sandybridge/gma.c @@ -650,9 +650,7 @@ static void gma_func0_init(struct device *dev) physbase = pci_read_config32(dev, 0x5c) & ~0xf; graphics_base = dev->resource_list[1].base; - int lightup_ok = i915lightup(conf, physbase, iobase, mmiobase, graphics_base); - if (lightup_ok) - gfx_set_init_done(1); + i915lightup(conf, physbase, iobase, mmiobase, graphics_base); #endif } diff --git a/src/northbridge/intel/sandybridge/raminit_native.c b/src/northbridge/intel/sandybridge/raminit_native.c new file mode 100644 index 0000000..b1e29a2 --- /dev/null +++ b/src/northbridge/intel/sandybridge/raminit_native.c @@ -0,0 +1,3893 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2014 Damien Zammit <damien(a)zamaudio.com> + * Copyright (C) 2014 Vladimir Serbinenko <phcoder(a)gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <console/console.h> +#include <console/usb.h> +#include <bootmode.h> +#include <string.h> +#include <arch/hlt.h> +#include <arch/io.h> +#include <cbmem.h> +#include <arch/cbfs.h> +#include <cbfs.h> +#include <ip_checksum.h> +#include <pc80/mc146818rtc.h> +#include <device/pci_def.h> +#include "raminit_native.h" +#include "sandybridge.h" +#include <delay.h> +#include <lib.h> + +/* Management Engine is in the southbridge */ +#include "southbridge/intel/bd82x6x/me.h" +/* For SPD. */ +#include "southbridge/intel/bd82x6x/smbus.h" +#include "arch/cpu.h" +#include "cpu/x86/msr.h" + +/* FIXME: no ECC support. */ +/* FIXME: no support for 3-channel chipsets. */ +/* FIXME: no S3. */ + +#define BASEFREQ 133 +#define tDLLK 512 + +#define IS_SANDY_CPU(x) ((x & 0xffff0) == 0x206a0) +#define IS_SANDY_CPU_C(x) ((x & 0xf) == 4) +#define IS_SANDY_CPU_D0(x) ((x & 0xf) == 5) +#define IS_SANDY_CPU_D1(x) ((x & 0xf) == 6) +#define IS_SANDY_CPU_D2(x) ((x & 0xf) == 7) + +#define IS_IVY_CPU(x) ((x & 0xffff0) == 0x306a0) +#define IS_IVY_CPU_C(x) ((x & 0xf) == 4) +#define IS_IVY_CPU_K(x) ((x & 0xf) == 5) +#define IS_IVY_CPU_D(x) ((x & 0xf) == 6) +#define IS_IVY_CPU_E(x) ((x & 0xf) >= 8) + +#define NUM_CHANNELS 2 +#define NUM_SLOTRANKS 4 +#define NUM_SLOTS 2 +#define NUM_LANES 8 + +/* FIXME: Vendor BIOS uses 64 but our algorithms are less + performant and even 1 seems to be enough in practice. */ +#define NUM_PATTERNS 4 + +typedef struct odtmap_st { + u16 rttwr; + u16 rttnom; +} odtmap; + +typedef struct dimm_info_st { + dimm_attr dimm[NUM_CHANNELS][NUM_SLOTS]; +} dimm_info; + +struct ram_rank_timings { + /* Register 4024. One byte per slotrank. */ + u8 val_4024; + /* Register 4028. One nibble per slotrank. */ + u8 val_4028; + + int val_320c; + + struct ram_lane_timings { + /* lane register offset 0x10. */ + u16 timA; /* bits 0 - 5, bits 16 - 18 */ + u8 rising; /* bits 8 - 14 */ + u8 falling; /* bits 20 - 26. */ + + /* lane register offset 0x20. */ + int timC; /* bit 0 - 5, 19. */ + u16 timB; /* bits 8 - 13, 15 - 17. */ + } lanes[NUM_LANES]; +}; + +struct ramctr_timing_st; + +typedef struct ramctr_timing_st { + int mobile; + + 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 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 */ + + u32 tREFI; + u32 tMOD; + u32 tXSOffset; + u32 tWLO; + u32 tCKE; + u32 tXPDLL; + u32 tXP; + u32 tAONPD; + + u16 reg_5064b0; /* bits 0-11. */ + + u8 rankmap[NUM_CHANNELS]; + int ref_card_offset[NUM_CHANNELS]; + u32 mad_dimm[NUM_CHANNELS]; + int channel_size_mb[NUM_CHANNELS]; + u32 reg_4004_b30[NUM_CHANNELS]; + + int reg_c14_offset; + int reg_320c_range_threshold; + + int edge_offset[3]; + int timC_offset[3]; + + int extended_temperature_range; + int auto_self_refresh; + + int rank_mirror[NUM_CHANNELS][NUM_SLOTRANKS]; + + struct ram_rank_timings timings[NUM_CHANNELS][NUM_SLOTRANKS]; +} ramctr_timing; + +#define SOUTHBRIDGE PCI_DEV(0, 0x1f, 0) +#define NORTHBRIDGE PCI_DEV(0, 0x0, 0) +#define FOR_ALL_LANES for (lane = 0; lane < NUM_LANES; lane++) +#define FOR_ALL_CHANNELS for (channel = 0; channel < NUM_CHANNELS; channel++) +#define FOR_ALL_POPULATED_RANKS for (slotrank = 0; slotrank < NUM_SLOTRANKS; slotrank++) if (ctrl->rankmap[channel] & (1 << slotrank)) +#define FOR_ALL_POPULATED_CHANNELS for (channel = 0; channel < NUM_CHANNELS; channel++) if (ctrl->rankmap[channel]) +#define MAX_EDGE_TIMING 71 +#define MAX_TIMC 127 +#define MAX_TIMB 511 +#define MAX_TIMA 127 + +static void program_timings(ramctr_timing * ctrl, int channel); + +static const char *ecc_decoder[] = { + "inactive", + "active on IO", + "disabled on IO", + "active" +}; + +static void wait_txt_clear(void) +{ + struct cpuid_result cp; + + cp = cpuid_ext(0x1, 0x0); + /* Check if TXT is supported? */ + if (!(cp.ecx & 0x40)) + return; + /* Some TXT public bit. */ + if (!(read32(0xfed30010) & 1)) + return; + /* Wait for TXT clear. */ + while (!(read8(0xfed40000) & (1 << 7))) ; +} + +static void sfence(void) +{ + asm volatile ("sfence"); +} + +/* + * Dump in the log memory controller configuration as read from the memory + * controller registers. + */ +static void report_memory_config(void) +{ + u32 addr_decoder_common, addr_decode_ch[NUM_CHANNELS]; + int i; + + addr_decoder_common = MCHBAR32(0x5000); + addr_decode_ch[0] = MCHBAR32(0x5004); + addr_decode_ch[1] = MCHBAR32(0x5008); + + printk(BIOS_DEBUG, "memcfg DDR3 clock %d MHz\n", + (MCHBAR32(0x5e04) * 13333 * 2 + 50) / 100); + printk(BIOS_DEBUG, "memcfg channel assignment: A: %d, B % d, C % d\n", + addr_decoder_common & 3, (addr_decoder_common >> 2) & 3, + (addr_decoder_common >> 4) & 3); + + for (i = 0; i < ARRAY_SIZE(addr_decode_ch); i++) { + u32 ch_conf = addr_decode_ch[i]; + printk(BIOS_DEBUG, "memcfg channel[%d] config (%8.8x):\n", i, + ch_conf); + printk(BIOS_DEBUG, " ECC %s\n", + ecc_decoder[(ch_conf >> 24) & 3]); + printk(BIOS_DEBUG, " enhanced interleave mode %s\n", + ((ch_conf >> 22) & 1) ? "on" : "off"); + printk(BIOS_DEBUG, " rank interleave %s\n", + ((ch_conf >> 21) & 1) ? "on" : "off"); + printk(BIOS_DEBUG, " DIMMA %d MB width x%d %s rank%s\n", + ((ch_conf >> 0) & 0xff) * 256, + ((ch_conf >> 19) & 1) ? 16 : 8, + ((ch_conf >> 17) & 1) ? "dual" : "single", + ((ch_conf >> 16) & 1) ? "" : ", selected"); + printk(BIOS_DEBUG, " DIMMB %d MB width x%d %s rank%s\n", + ((ch_conf >> 8) & 0xff) * 256, + ((ch_conf >> 20) & 1) ? 16 : 8, + ((ch_conf >> 18) & 1) ? "dual" : "single", + ((ch_conf >> 16) & 1) ? ", selected" : ""); + } +} + +static void post_system_agent_init(void) +{ + /* If PCIe init is skipped, set the PEG clock gating */ + MCHBAR32(0x7010) = MCHBAR32(0x7010) | 0x01; +} + +void read_spd(spd_raw_data * spd, u8 addr) +{ + int j; + for (j = 0; j < 256; j++) + (*spd)[j] = do_smbus_read_byte(SMBUS_IO_BASE, addr, j); +} + +static void dram_find_spds_ddr3(spd_raw_data * spd, dimm_info * dimm, + ramctr_timing * ctrl) +{ + int dimms = 0; + int channel, slot, spd_slot; + + memset (ctrl->rankmap, 0, sizeof (ctrl->rankmap)); + + ctrl->extended_temperature_range = 1; + ctrl->auto_self_refresh = 1; + + FOR_ALL_CHANNELS { + ctrl->channel_size_mb[channel] = 0; + + for (slot = 0; slot < NUM_SLOTS; slot++) { + spd_slot = 2 * channel + slot; + spd_decode_ddr3(&dimm->dimm[channel][slot], spd[spd_slot]); + if (dimm->dimm[channel][slot].dram_type != SPD_MEMORY_TYPE_SDRAM_DDR3) { + // set dimm invalid + dimm->dimm[channel][slot].ranks = 0; + dimm->dimm[channel][slot].size_mb = 0; + continue; + } + + dram_print_spd_ddr3(&dimm->dimm[channel][slot]); + dimms++; + ctrl->rank_mirror[channel][slot * 2] = 0; + ctrl->rank_mirror[channel][slot * 2 + 1] = dimm->dimm[channel][slot].flags.pins_mirrored; + ctrl->channel_size_mb[channel] += dimm->dimm[channel][slot].size_mb; + + ctrl->auto_self_refresh &= dimm->dimm[channel][slot].flags.asr; + ctrl->extended_temperature_range &= dimm->dimm[channel][slot].flags.ext_temp_refresh; + + ctrl->rankmap[channel] = ((1 << dimm->dimm[channel][slot].ranks) - 1) << (2 * slot); + printk(BIOS_DEBUG, "rankmap[%d] = 0x%x\n", channel, ctrl->rankmap[channel]); + } + if ((ctrl->rankmap[channel] & 3) && (ctrl->rankmap[channel] & 0xc) + && dimm->dimm[channel][0].reference_card <= 5 && dimm->dimm[channel][1].reference_card <= 5) { + const int ref_card_offset_table[6][6] = { + { 0, 0, 0, 0, 2, 2, }, + { 0, 0, 0, 0, 2, 2, }, + { 0, 0, 0, 0, 2, 2, }, + { 0, 0, 0, 0, 1, 1, }, + { 2, 2, 2, 1, 0, 0, }, + { 2, 2, 2, 1, 0, 0, }, + }; + ctrl->ref_card_offset[channel] = ref_card_offset_table[dimm->dimm[channel][0].reference_card] + [dimm->dimm[channel][1].reference_card]; + } else + ctrl->ref_card_offset[channel] = 0; + } + + if (!dimms) + die("No DIMMs were found"); +} + +static void dram_find_common_params(const dimm_info * dimms, + ramctr_timing * ctrl) +{ + size_t valid_dimms; + int channel, slot; + ctrl->cas_supported = 0xff; + valid_dimms = 0; + FOR_ALL_CHANNELS for (slot = 0; slot < 2; slot++) { + const dimm_attr *dimm = &dimms->dimm[channel][slot]; + if (dimm->dram_type != SPD_MEMORY_TYPE_SDRAM_DDR3) + continue; + valid_dimms++; + + /* 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->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 u8 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]; +} + +/* Frequency multiplier. */ +static u32 get_FRQ(u32 tCK) +{ + u32 FRQ; + FRQ = 256000 / (tCK * BASEFREQ); + if (FRQ > 8) + return 8; + if (FRQ < 3) + return 3; + return FRQ; +} + +static u32 get_REFI(u32 tCK) +{ + /* Get REFI based on MCU frequency using the following rule: + * _________________________________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * REFI: | 3120 | 4160 | 5200 | 6240 | 7280 | 8320 | + */ + static const u32 frq_refi_map[] = + { 3120, 4160, 5200, 6240, 7280, 8320 }; + return frq_refi_map[get_FRQ(tCK) - 3]; +} + +static u8 get_XSOffset(u32 tCK) +{ + /* Get XSOffset based on MCU frequency using the following rule: + * _________________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * XSOffset : | 4 | 6 | 7 | 8 | 10 | 11 | + */ + static const u8 frq_xs_map[] = { 4, 6, 7, 8, 10, 11 }; + return frq_xs_map[get_FRQ(tCK) - 3]; +} + +static u8 get_MOD(u32 tCK) +{ + /* Get MOD based on MCU frequency using the following rule: + * _____________________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * MOD : | 12 | 12 | 12 | 12 | 15 | 16 | + */ + static const u8 frq_mod_map[] = { 12, 12, 12, 12, 15, 16 }; + return frq_mod_map[get_FRQ(tCK) - 3]; +} + +static u8 get_WLO(u32 tCK) +{ + /* Get WLO based on MCU frequency using the following rule: + * _______________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * WLO : | 4 | 5 | 6 | 6 | 8 | 8 | + */ + static const u8 frq_wlo_map[] = { 4, 5, 6, 6, 8, 8 }; + return frq_wlo_map[get_FRQ(tCK) - 3]; +} + +static u8 get_CKE(u32 tCK) +{ + /* Get CKE based on MCU frequency using the following rule: + * _______________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * CKE : | 3 | 3 | 4 | 4 | 5 | 6 | + */ + static const u8 frq_cke_map[] = { 3, 3, 4, 4, 5, 6 }; + return frq_cke_map[get_FRQ(tCK) - 3]; +} + +static u8 get_XPDLL(u32 tCK) +{ + /* Get XPDLL based on MCU frequency using the following rule: + * _____________________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * XPDLL : | 10 | 13 | 16 | 20 | 23 | 26 | + */ + static const u8 frq_xpdll_map[] = { 10, 13, 16, 20, 23, 26 }; + return frq_xpdll_map[get_FRQ(tCK) - 3]; +} + +static u8 get_XP(u32 tCK) +{ + /* Get XP based on MCU frequency using the following rule: + * _______________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * XP : | 3 | 4 | 4 | 5 | 6 | 7 | + */ + static const u8 frq_xp_map[] = { 3, 4, 4, 5, 6, 7 }; + return frq_xp_map[get_FRQ(tCK) - 3]; +} + +static u8 get_AONPD(u32 tCK) +{ + /* Get AONPD based on MCU frequency using the following rule: + * ________________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * AONPD : | 4 | 5 | 6 | 8 | 8 | 10 | + */ + static const u8 frq_aonpd_map[] = { 4, 5, 6, 8, 8, 10 }; + return frq_aonpd_map[get_FRQ(tCK) - 3]; +} + +static u32 get_COMP2(u32 tCK) +{ + /* Get COMP2 based on MCU frequency using the following rule: + * ___________________________________________________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * COMP : | D6BEDCC | CE7C34C | CA57A4C | C6369CC | C42514C | C21410C | + */ + static const u32 frq_comp2_map[] = { 0xD6BEDCC, 0xCE7C34C, 0xCA57A4C, + 0xC6369CC, 0xC42514C, 0xC21410C + }; + return frq_comp2_map[get_FRQ(tCK) - 3]; +} + +static void dram_timing(ramctr_timing * ctrl) +{ + u8 val; + u32 val32; + + /* Maximum supported DDR3 frequency is 1066MHz (DDR3 2133) so make sure + * we cap it if we have faster DIMMs. + * Then, align it to the closest JEDEC standard frequency */ + if (ctrl->tCK <= TCK_1066MHZ) { + ctrl->tCK = TCK_1066MHZ; + ctrl->edge_offset[0] = 16; + ctrl->edge_offset[1] = 7; + ctrl->edge_offset[2] = 7; + ctrl->timC_offset[0] = 18; + ctrl->timC_offset[1] = 7; + ctrl->timC_offset[2] = 7; + ctrl->reg_c14_offset = 16; + ctrl->reg_5064b0 = 0x218; + ctrl->reg_320c_range_threshold = 13; + } else if (ctrl->tCK <= TCK_933MHZ) { + ctrl->tCK = TCK_933MHZ; + ctrl->edge_offset[0] = 14; + ctrl->edge_offset[1] = 6; + ctrl->edge_offset[2] = 6; + ctrl->timC_offset[0] = 15; + ctrl->timC_offset[1] = 6; + ctrl->timC_offset[2] = 6; + ctrl->reg_c14_offset = 14; + ctrl->reg_5064b0 = 0x1d5; + ctrl->reg_320c_range_threshold = 15; + } else if (ctrl->tCK <= TCK_800MHZ) { + ctrl->tCK = TCK_800MHZ; + ctrl->edge_offset[0] = 13; + ctrl->edge_offset[1] = 5; + ctrl->edge_offset[2] = 5; + ctrl->timC_offset[0] = 14; + ctrl->timC_offset[1] = 5; + ctrl->timC_offset[2] = 5; + ctrl->reg_c14_offset = 12; + ctrl->reg_5064b0 = 0x193; + ctrl->reg_320c_range_threshold = 15; + } else if (ctrl->tCK <= TCK_666MHZ) { + ctrl->tCK = TCK_666MHZ; + ctrl->edge_offset[0] = 10; + ctrl->edge_offset[1] = 4; + ctrl->edge_offset[2] = 4; + ctrl->timC_offset[0] = 11; + ctrl->timC_offset[1] = 4; + ctrl->timC_offset[2] = 4; + ctrl->reg_c14_offset = 10; + ctrl->reg_5064b0 = 0x150; + ctrl->reg_320c_range_threshold = 16; + } else if (ctrl->tCK <= TCK_533MHZ) { + ctrl->tCK = TCK_533MHZ; + ctrl->edge_offset[0] = 8; + ctrl->edge_offset[1] = 3; + ctrl->edge_offset[2] = 3; + ctrl->timC_offset[0] = 9; + ctrl->timC_offset[1] = 3; + ctrl->timC_offset[2] = 3; + ctrl->reg_c14_offset = 8; + ctrl->reg_5064b0 = 0x10d; + ctrl->reg_320c_range_threshold = 17; + } else { + ctrl->tCK = TCK_400MHZ; + ctrl->edge_offset[0] = 6; + ctrl->edge_offset[1] = 2; + ctrl->edge_offset[2] = 2; + ctrl->timC_offset[0] = 6; + ctrl->timC_offset[1] = 2; + ctrl->timC_offset[2] = 2; + ctrl->reg_c14_offset = 8; + ctrl->reg_5064b0 = 0xcd; + ctrl->reg_320c_range_threshold = 17; + } + + val32 = (1000 << 8) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected DRAM frequency: %u MHz\n", val32); + + /* Find CAS and CWL latencies */ + val = (ctrl->tAA + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "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)))) + printk(BIOS_DEBUG, "CAS not supported\n"); + printk(BIOS_DEBUG, "Selected CAS latency : %uT\n", val); + ctrl->CAS = val; + ctrl->CWL = get_CWL(ctrl->CAS); + printk(BIOS_DEBUG, "Selected CWL latency : %uT\n", ctrl->CWL); + + /* Find tRCD */ + ctrl->tRCD = (ctrl->tRCD + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected tRCD : %uT\n", ctrl->tRCD); + + ctrl->tRP = (ctrl->tRP + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected tRP : %uT\n", ctrl->tRP); + + /* Find tRAS */ + ctrl->tRAS = (ctrl->tRAS + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected tRAS : %uT\n", ctrl->tRAS); + + /* Find tWR */ + ctrl->tWR = (ctrl->tWR + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected tWR : %uT\n", ctrl->tWR); + + /* Find tFAW */ + ctrl->tFAW = (ctrl->tFAW + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected tFAW : %uT\n", ctrl->tFAW); + + /* Find tRRD */ + ctrl->tRRD = (ctrl->tRRD + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected tRRD : %uT\n", ctrl->tRRD); + + /* Find tRTP */ + ctrl->tRTP = (ctrl->tRTP + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected tRTP : %uT\n", ctrl->tRTP); + + /* Find tWTR */ + ctrl->tWTR = (ctrl->tWTR + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected tWTR : %uT\n", ctrl->tWTR); + + /* Refresh-to-Active or Refresh-to-Refresh (tRFC) */ + ctrl->tRFC = (ctrl->tRFC + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected tRFC : %uT\n", ctrl->tRFC); + + ctrl->tREFI = get_REFI(ctrl->tCK); + ctrl->tMOD = get_MOD(ctrl->tCK); + ctrl->tXSOffset = get_XSOffset(ctrl->tCK); + ctrl->tWLO = get_WLO(ctrl->tCK); + ctrl->tCKE = get_CKE(ctrl->tCK); + ctrl->tXPDLL = get_XPDLL(ctrl->tCK); + ctrl->tXP = get_XP(ctrl->tCK); + ctrl->tAONPD = get_AONPD(ctrl->tCK); +} + +static void dram_freq(ramctr_timing * ctrl) +{ + u8 val2; + u32 reg1 = 0; + + /* Step 1 - Set target PCU frequency */ + + if (ctrl->tCK <= TCK_1066MHZ) { + ctrl->tCK = TCK_1066MHZ; + } else if (ctrl->tCK <= TCK_933MHZ) { + ctrl->tCK = TCK_933MHZ; + } else if (ctrl->tCK <= TCK_800MHZ) { + ctrl->tCK = TCK_800MHZ; + } else if (ctrl->tCK <= TCK_666MHZ) { + ctrl->tCK = TCK_666MHZ; + } else if (ctrl->tCK <= TCK_533MHZ) { + ctrl->tCK = TCK_533MHZ; + } else { + ctrl->tCK = TCK_400MHZ; + } + + /* Frequency mulitplier. */ + u32 FRQ = get_FRQ(ctrl->tCK); + + /* Step 2 - Select frequency in the MCU */ + reg1 = FRQ; + reg1 |= 0x80000000; // set running bit + MCHBAR32(0x5e00) = reg1; + while (reg1 & 0x80000000) { + printk(BIOS_DEBUG, " PLL busy..."); + reg1 = MCHBAR32(0x5e00); + } + printk(BIOS_DEBUG, "done\n"); + + /* Step 3 - Verify lock frequency */ + reg1 = MCHBAR32(0x5e04); + val2 = (u8) reg1; + if (val2 < FRQ) { + printk(BIOS_DEBUG, "Lock frequency is lower, recalculating\n"); + ctrl->tCK = 256000 / (val2 * BASEFREQ); + } + printk(BIOS_DEBUG, "MCU frequency is set at : %d MHz\n", + (1000 << 8) / ctrl->tCK); +} + +static void dram_xover(ramctr_timing * ctrl) +{ + u32 reg; + int channel; + + FOR_ALL_CHANNELS { + // enable xover clk + printk(BIOS_DEBUG, "[%x] = %x\n", channel * 0x100 + 0xc14, + (ctrl->rankmap[channel] << 24)); + MCHBAR32(channel * 0x100 + 0xc14) = (ctrl->rankmap[channel] << 24); + + // enable xover ctl + reg = 0; + if (ctrl->rankmap[channel] & 0x5) { + reg |= 0x20000; + } + if (ctrl->rankmap[channel] & 0xa) { + reg |= 0x4000000; + } + // enable xover cmd + reg |= 0x4000; + printk(BIOS_DEBUG, "[%x] = %x\n", 0x100 * channel + 0x320c, + reg); + MCHBAR32(0x100 * channel + 0x320c) = reg; + } +} + +static void dram_timing_regs(ramctr_timing * ctrl) +{ + u32 reg, addr, val32, cpu, stretch; + struct cpuid_result cpures; + int channel; + + FOR_ALL_CHANNELS { + // DBP + reg = 0; + reg |= ctrl->tRCD; + reg |= (ctrl->tRP << 4); + reg |= (ctrl->CAS << 8); + reg |= (ctrl->CWL << 12); + reg |= (ctrl->tRAS << 16); + printk(BIOS_DEBUG, "[%x] = %x\n", 0x400 * channel + 0x4000, + reg); + MCHBAR32(0x400 * channel + 0x4000) = reg; + + // RAP + reg = 0; + reg |= ctrl->tRRD; + reg |= (ctrl->tRTP << 4); + reg |= (ctrl->tCKE << 8); + reg |= (ctrl->tWTR << 12); + reg |= (ctrl->tFAW << 16); + reg |= (ctrl->tWR << 24); + reg |= (3 << 30); + printk(BIOS_DEBUG, "[%x] = %x\n", 0x400 * channel + 0x4004, + reg); + MCHBAR32(0x400 * channel + 0x4004) = reg; + + // OTHP + addr = 0x400 * channel + 0x400c; + reg = 0; + reg |= ctrl->tXPDLL; + reg |= (ctrl->tXP << 5); + reg |= (ctrl->tAONPD << 8); + reg |= 0xa0000; + printk(BIOS_DEBUG, "[%x] = %x\n", addr, reg); + MCHBAR32(addr) = reg; + + MCHBAR32(0x400 * channel + 0x4014) = 0; + + MCHBAR32(addr) |= 0x00020000; + + // ODT stretch + reg = 0; + + cpures = cpuid(0); + cpu = cpures.eax; + if (IS_IVY_CPU(cpu) + || (IS_SANDY_CPU(cpu) && IS_SANDY_CPU_D2(cpu))) { + stretch = 2; + addr = 0x400 * channel + 0x400c; + printk(BIOS_DEBUG, "[%x] = %x\n", + 0x400 * channel + 0x400c, reg); + reg = MCHBAR32(addr); + + if (((ctrl->rankmap[channel] & 3) == 0) + || (ctrl->rankmap[channel] & 0xc) == 0) { + + // Rank 0 - operate on rank 2 + reg = (reg & ~0xc0000) | (stretch << 18); + + // Rank 2 - operate on rank 0 + reg = (reg & ~0x30000) | (stretch << 16); + + printk(BIOS_DEBUG, "[%x] = %x\n", addr, reg); + MCHBAR32(addr) = reg; + } + + } else if (IS_SANDY_CPU(cpu) && IS_SANDY_CPU_C(cpu)) { + stretch = 3; + addr = 0x400 * channel + 0x401c; + reg = MCHBAR32(addr); + + if (((ctrl->rankmap[channel] & 3) == 0) + || (ctrl->rankmap[channel] & 0xc) == 0) { + + // Rank 0 - operate on rank 2 + reg = (reg & ~0x3000) | (stretch << 12); + + // Rank 2 - operate on rank 0 + reg = (reg & ~0xc00) | (stretch << 10); + + printk(BIOS_DEBUG, "[%x] = %x\n", addr, reg); + MCHBAR32(addr) = reg; + } + } else { + stretch = 0; + } + + // REFI + reg = 0; + val32 = ctrl->tREFI; + reg = (reg & ~0xffff) | val32; + val32 = ctrl->tRFC; + reg = (reg & ~0x1ff0000) | (val32 << 16); + val32 = (u32) (ctrl->tREFI * 9) / 1024; + reg = (reg & ~0xfe000000) | (val32 << 25); + printk(BIOS_DEBUG, "[%x] = %x\n", 0x400 * channel + 0x4298, + reg); + MCHBAR32(0x400 * channel + 0x4298) = reg; + + MCHBAR32(0x400 * channel + 0x4294) |= 0xff; + + // SRFTP + reg = 0; + val32 = tDLLK; + reg = (reg & ~0xfff) | val32; + val32 = ctrl->tXSOffset; + reg = (reg & ~0xf000) | (val32 << 12); + val32 = tDLLK - ctrl->tXSOffset; + reg = (reg & ~0x3ff0000) | (val32 << 16); + val32 = ctrl->tMOD - 8; + reg = (reg & ~0xf0000000) | (val32 << 28); + printk(BIOS_DEBUG, "[%x] = %x\n", 0x400 * channel + 0x42a4, + reg); + MCHBAR32(0x400 * channel + 0x42a4) = reg; + } +} + +static void dram_dimm_mapping(dimm_info * info, ramctr_timing * ctrl) +{ + int t; + u32 reg, val32; + int channel; + + FOR_ALL_CHANNELS { + dimm_attr *dimmA = 0; + dimm_attr *dimmB = 0; + reg = 0; + val32 = 0; + if (info->dimm[channel][0].size_mb >= + info->dimm[channel][1].size_mb) { + // dimm 0 is bigger, set it to dimmA + dimmA = &info->dimm[channel][0]; + dimmB = &info->dimm[channel][1]; + reg |= (0 << 16); + } else { + // dimm 1 is bigger, set it to dimmA + dimmA = &info->dimm[channel][1]; + dimmB = &info->dimm[channel][0]; + reg |= (1 << 16); + // swap dimm info + t = ctrl->rank_mirror[channel][1]; + ctrl->rank_mirror[channel][1] = + ctrl->rank_mirror[channel][3]; + ctrl->rank_mirror[channel][3] = t; + } + // dimmA + if (dimmA && (dimmA->ranks > 0)) { + val32 = dimmA->size_mb / 256; + reg = (reg & ~0xff) | val32; + val32 = dimmA->ranks - 1; + reg = (reg & ~0x20000) | (val32 << 17); + val32 = (dimmA->width / 8) - 1; + reg = (reg & ~0x80000) | (val32 << 19); + } + // dimmB + if (dimmB && (dimmB->ranks > 0)) { + val32 = dimmB->size_mb / 256; + reg = (reg & ~0xff00) | (val32 << 8); + val32 = dimmB->ranks - 1; + reg = (reg & ~0x40000) | (val32 << 18); + val32 = (dimmB->width / 8) - 1; + reg = (reg & ~0x100000) | (val32 << 20); + } + reg = (reg & ~0x200000) | (1 << 21); // rank interleave + reg = (reg & ~0x400000) | (1 << 22); // enhanced interleave + + // Save MAD-DIMM register + if ((dimmA && (dimmA->ranks > 0)) + || (dimmB && (dimmB->ranks > 0))) { + ctrl->mad_dimm[channel] = reg; + } else { + ctrl->mad_dimm[channel] = 0; + } + } +} + +static void dram_dimm_set_mapping(ramctr_timing * ctrl) +{ + int channel; + FOR_ALL_CHANNELS { + MCHBAR32(0x5004 + channel * 4) = ctrl->mad_dimm[channel]; + } +} + +static void dram_zones(ramctr_timing * ctrl, int training) +{ + u32 reg, ch0size, ch1size; + u8 val; + reg = 0; + val = 0; + if (training) { + ch0size = ctrl->channel_size_mb[0] ? 256 : 0; + ch1size = ctrl->channel_size_mb[1] ? 256 : 0; + } else { + ch0size = ctrl->channel_size_mb[0]; + ch1size = ctrl->channel_size_mb[1]; + } + + if (ch0size >= ch1size) { + reg = MCHBAR32(0x5014); + val = ch1size / 256; + reg = (reg & ~0xff000000) | val << 24; + reg = (reg & ~0xff0000) | (2 * val) << 16; + MCHBAR32(0x5014) = reg; + MCHBAR32(0x5000) = 0x24; + } else { + reg = MCHBAR32(0x5014); + val = ch0size / 256; + reg = (reg & ~0xff000000) | val << 24; + reg = (reg & ~0xff0000) | (2 * val) << 16; + MCHBAR32(0x5014) = reg; + MCHBAR32(0x5000) = 0x21; + } +} + +static void dram_memorymap(ramctr_timing * ctrl, int me_uma_size) +{ + u32 reg, val, reclaim; + u32 tom, gfxstolen, gttsize; + size_t tsegsize, mmiosize, toludbase, touudbase, gfxstolenbase, gttbase, + tsegbase, mestolenbase; + size_t tsegbasedelta, remapbase, remaplimit; + uint16_t ggc; + + mmiosize = 0x400; + + ggc = pci_read_config16(NORTHBRIDGE, GGC); + if (!(ggc & 2)) { + gfxstolen = ((ggc >> 3) & 0x1f) * 32; + gttsize = ((ggc >> 8) & 0x3); + } else { + gfxstolen = 0; + gttsize = 0; + } + + tsegsize = CONFIG_SMM_TSEG_SIZE >> 20; + + tom = ctrl->channel_size_mb[0] + ctrl->channel_size_mb[1]; + + mestolenbase = tom - me_uma_size; + + toludbase = MIN(4096 - mmiosize + gfxstolen + gttsize + tsegsize, + tom - me_uma_size); + gfxstolenbase = toludbase - gfxstolen; + gttbase = gfxstolenbase - gttsize; + + tsegbase = gttbase - tsegsize; + + // Round tsegbase down to nearest address aligned to tsegsize + tsegbasedelta = tsegbase & (tsegsize - 1); + tsegbase &= ~(tsegsize - 1); + + gttbase -= tsegbasedelta; + gfxstolenbase -= tsegbasedelta; + toludbase -= tsegbasedelta; + + // Test if it is possible to reclaim a hole in the ram addressing + if (tom - me_uma_size > toludbase) { + // Reclaim is possible + reclaim = 1; + remapbase = MAX(4096, tom - me_uma_size); + remaplimit = + remapbase + MIN(4096, tom - me_uma_size) - toludbase - 1; + touudbase = remaplimit + 1; + } else { + // Reclaim not possible + reclaim = 0; + touudbase = tom - me_uma_size; + } + + // Update memory map in pci-e configuration space + + // TOM (top of memory) + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xa0); + val = tom & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + printk(BIOS_DEBUG, "PCI:[%x] = %x\n", 0xa0, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xa0, reg); + + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xa4); + val = tom & 0xfffff000; + reg = (reg & ~0x000fffff) | (val >> 12); + printk(BIOS_DEBUG, "PCI:[%x] = %x\n", 0xa4, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xa4, reg); + + // TOLUD (top of low used dram) + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xbc); + val = toludbase & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + printk(BIOS_DEBUG, "PCI:[%x] = %x\n", 0xbc, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xbc, reg); + + // TOUUD LSB (top of upper usable dram) + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xa8); + val = touudbase & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + printk(BIOS_DEBUG, "PCI:[%x] = %x\n", 0xa8, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xa8, reg); + + // TOUUD MSB + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xac); + val = touudbase & 0xfffff000; + reg = (reg & ~0x000fffff) | (val >> 12); + printk(BIOS_DEBUG, "PCI:[%x] = %x\n", 0xac, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xac, reg); + + if (reclaim) { + // REMAP BASE + pcie_write_config32(PCI_DEV(0, 0, 0), 0x90, remapbase << 20); + pcie_write_config32(PCI_DEV(0, 0, 0), 0x94, remapbase >> 12); + + // REMAP LIMIT + pcie_write_config32(PCI_DEV(0, 0, 0), 0x98, remaplimit << 20); + pcie_write_config32(PCI_DEV(0, 0, 0), 0x9c, remaplimit >> 12); + } + // TSEG + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xb8); + val = tsegbase & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + printk(BIOS_DEBUG, "PCI:[%x] = %x\n", 0xb8, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xb8, reg); + + // GFX stolen memory + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xb0); + val = gfxstolenbase & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + printk(BIOS_DEBUG, "PCI:[%x] = %x\n", 0xb0, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xb0, reg); + + // GTT stolen memory + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xb4); + val = gttbase & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + printk(BIOS_DEBUG, "PCI:[%x] = %x\n", 0xb4, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xb4, reg); + + if (me_uma_size) { + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0x7c); + val = (0x80000 - me_uma_size) & 0xfffff000; + reg = (reg & ~0x000fffff) | (val >> 12); + printk(BIOS_DEBUG, "PCI:[%x] = %x\n", 0x7c, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0x7c, reg); + + // ME base + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0x70); + val = mestolenbase & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + printk(BIOS_DEBUG, "PCI:[%x] = %x\n", 0x70, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0x70, reg); + + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0x74); + val = mestolenbase & 0xfffff000; + reg = (reg & ~0x000fffff) | (val >> 12); + printk(BIOS_DEBUG, "PCI:[%x] = %x\n", 0x74, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0x74, reg); + + // ME mask + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0x78); + val = (0x80000 - me_uma_size) & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + reg = (reg & ~0x400) | (1 << 10); // set lockbit on ME mem + + reg = (reg & ~0x800) | (1 << 11); // set ME memory enable + printk(BIOS_DEBUG, "PCI:[%x] = %x\n", 0x78, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0x78, reg); + } +} + +static void dram_ioregs(ramctr_timing * ctrl) +{ + u32 reg, comp2; + + int channel; + + // IO clock + FOR_ALL_CHANNELS { + MCHBAR32(0xc00 + 0x100 * channel) = ctrl->rankmap[channel]; + } + + // IO command + FOR_ALL_CHANNELS { + MCHBAR32(0x3200 + 0x100 * channel) = ctrl->rankmap[channel]; + } + + // IO control + FOR_ALL_POPULATED_CHANNELS { + program_timings(ctrl, channel); + } + + // Rcomp + printk(BIOS_DEBUG, "RCOMP..."); + reg = 0; + while (reg == 0) { + reg = MCHBAR32(0x5084) & 0x10000; + } + printk(BIOS_DEBUG, "done\n"); + + // Set comp2 + comp2 = get_COMP2(ctrl->tCK); + MCHBAR32(0x3714) = comp2; + printk(BIOS_DEBUG, "COMP2 done\n"); + + // Set comp1 + FOR_ALL_POPULATED_CHANNELS { + reg = MCHBAR32(0x1810 + channel * 0x100); //ch0 + reg = (reg & ~0xe00) | (1 << 9); //odt + reg = (reg & ~0xe00000) | (1 << 21); //clk drive up + reg = (reg & ~0x38000000) | (1 << 27); //ctl drive up + MCHBAR32(0x1810 + channel * 0x100) = reg; + } + printk(BIOS_DEBUG, "COMP1 done\n"); + + printk(BIOS_DEBUG, "FORCE RCOMP and wait 20us..."); + MCHBAR32(0x5f08) |= 0x100; + udelay(20); + printk(BIOS_DEBUG, "done\n"); +} + +static void wait_428c(int channel) +{ + while (1) { + if (read32(DEFAULT_MCHBAR | 0x428c | (channel << 10)) & 0x50) + return; + } +} + +static void write_reset(ramctr_timing * ctrl) +{ + int channel, slotrank; + + /* choose a populated channel. */ + channel = (ctrl->rankmap[0]) ? 0 : 1; + + wait_428c(channel); + + /* choose a populated rank. */ + slotrank = (ctrl->rankmap[channel] & 1) ? 0 : 2; + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x0f003); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0x80c01); + + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x60000); + + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0x400001); + wait_428c(channel); +} + +static void dram_jedecreset(ramctr_timing * ctrl) +{ + u32 reg, addr; + int channel; + + while (!(MCHBAR32(0x5084) & 0x10000)) ; + do { + reg = MCHBAR32(0x428c); + } while ((reg & 0x14) == 0); + + // Set state of memory controller + reg = 0x112; + MCHBAR32(0x5030) = reg; + MCHBAR32(0x4ea0) = 0; + reg |= 2; //ddr reset + MCHBAR32(0x5030) = reg; + + // Assert dimm reset signal + reg = MCHBAR32(0x5030); + reg &= ~0x2; + MCHBAR32(0x5030) = reg; + + // Wait 200us + udelay(200); + + // Deassert dimm reset signal + MCHBAR32(0x5030) |= 2; + + // Wait 500us + udelay(500); + + // Enable DCLK + MCHBAR32(0x5030) |= 4; + + // XXX Wait 20ns + udelay(1); + + FOR_ALL_CHANNELS { + // Set valid rank CKE + reg = 0; + reg = (reg & ~0xf) | ctrl->rankmap[channel]; + addr = 0x400 * channel + 0x42a0; + MCHBAR32(addr) = reg; + + // Wait 10ns for ranks to settle + //udelay(0.01); + + reg = (reg & ~0xf0) | (ctrl->rankmap[channel] << 4); + MCHBAR32(addr) = reg; + + // Write reset using a NOP + write_reset(ctrl); + } +} + +static odtmap get_ODT(ramctr_timing * ctrl, u8 rank) +{ + /* Get ODT based on rankmap: */ + int dimms_per_ch = 0; + int channel; + + FOR_ALL_CHANNELS { + dimms_per_ch = max ((ctrl->rankmap[channel] & 1) + + ((ctrl->rankmap[channel] >> 2) & 1), + dimms_per_ch); + } + + if (dimms_per_ch == 1) { + return (const odtmap){60, 60}; + } else if (dimms_per_ch == 2) { + return (const odtmap){120, 30}; + } else { + printk(BIOS_DEBUG, + "Huh, no dimms? m0 = %d m1 = %d dpc = %d\n", + ctrl->rankmap[0], + ctrl->rankmap[1], dimms_per_ch); + die(""); + } +} + +static void write_mrreg(ramctr_timing * ctrl, int channel, int slotrank, + int reg, u32 val) +{ + wait_428c(channel); + + printk(BIOS_SPEW, "MRd: %x <= %x\n", reg, val); + + if (ctrl->rank_mirror[channel][slotrank]) { + reg = ((reg >> 1) & 1) | ((reg << 1) & 2); + val = (val & ~0x1f8) | ((val >> 1) & 0xa8) + | ((val & 0xa8) << 1); + } + + printk(BIOS_SPEW, "MRd: %x <= %x\n", reg, val); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x0f000); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0x41001); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | (reg << 20) | val | 0x60000); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f000); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, 0x41001); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24) | (reg << 20) | val | 0x60000); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, 0x0f000); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, + 0x1001 | (ctrl->tMOD << 16)); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, + (slotrank << 24) | (reg << 20) | val | 0x60000); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, 0); + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0x80001); +} + +static u32 make_mr0(ramctr_timing * ctrl, u8 rank) +{ + u16 mr0reg, mch_cas, mch_wr; + static const u8 mch_wr_t[12] = { 1, 2, 3, 4, 0, 5, 0, 6, 0, 7, 0, 0 }; + mr0reg = 0x100; + + // Convert CAS to MCH register friendly + if (ctrl->CAS < 12) { + mch_cas = (u16) ((ctrl->CAS - 4) << 1); + } else { + mch_cas = (u16) (ctrl->CAS - 12); + mch_cas = ((mch_cas << 1) | 0x1); + } + + // Convert tWR to MCH register friendly + mch_wr = mch_wr_t[ctrl->tWR - 5]; + + mr0reg = (mr0reg & ~0x4) | (mch_cas & 0x1); + mr0reg = (mr0reg & ~0x70) | ((mch_cas & 0xe) << 3); + mr0reg = (mr0reg & ~0xe00) | (mch_wr << 9); + // Fast (desktop) 0x1 or slow (mobile) 0x0 + mr0reg = (mr0reg & ~0x1000) | (!ctrl->mobile << 12); + return mr0reg; +} + +static void dram_mr0(ramctr_timing * ctrl, u8 rank) +{ + int channel; + + FOR_ALL_POPULATED_CHANNELS write_mrreg(ctrl, channel, rank, 0, + make_mr0(ctrl, rank)); +} + +static u32 encode_odt(u32 odt) +{ + switch (odt) { + case 30: + return (1 << 9) | (1 << 2); // RZQ/8, RZQ/4 + case 60: + return (1 << 2); // RZQ/4 + case 120: + return (1 << 6); // RZQ/2 + default: + case 0: + return 0; + } +} + +static u32 make_mr1(ramctr_timing * ctrl, u8 rank) +{ + odtmap odt; + u32 mr1reg; + + odt = get_ODT(ctrl, rank); + mr1reg = 0x2; + + mr1reg |= encode_odt(odt.rttnom); + + return mr1reg; +} + +static void dram_mr1(ramctr_timing * ctrl, u8 rank) +{ + u16 mr1reg; + int channel; + + mr1reg = make_mr1(ctrl, rank); + + FOR_ALL_CHANNELS { + write_mrreg(ctrl, channel, rank, 1, mr1reg); + } +} + +static void dram_mr2(ramctr_timing * ctrl, u8 rank) +{ + u16 pasr, cwl, mr2reg; + odtmap odt; + int channel; + int srt; + + pasr = 0; + cwl = ctrl->CWL - 5; + odt = get_ODT(ctrl, rank); + + srt = ctrl->extended_temperature_range && !ctrl->auto_self_refresh; + + mr2reg = 0; + mr2reg = (mr2reg & ~0x7) | pasr; + mr2reg = (mr2reg & ~0x38) | (cwl << 3); + mr2reg = (mr2reg & ~0x40) | (ctrl->auto_self_refresh << 6); + mr2reg = (mr2reg & ~0x80) | (srt << 7); + mr2reg |= (odt.rttwr / 60) << 9; + + FOR_ALL_CHANNELS { + write_mrreg(ctrl, channel, rank, 2, mr2reg); + } +} + +static void dram_mr3(ramctr_timing * ctrl, u8 rank) +{ + int channel; + + FOR_ALL_CHANNELS { + write_mrreg(ctrl, channel, rank, 3, 0); + } +} + +static void dram_mrscommands(ramctr_timing * ctrl) +{ + u8 rank; + u32 reg, addr; + int channel; + + for (rank = 0; rank < 4; rank++) { + // MR2 + printk(BIOS_SPEW, "MR2 rank %d...", rank); + dram_mr2(ctrl, rank); + printk(BIOS_SPEW, "done\n"); + + // MR3 + printk(BIOS_SPEW, "MR3 rank %d...", rank); + dram_mr3(ctrl, rank); + printk(BIOS_SPEW, "done\n"); + + // MR1 + printk(BIOS_SPEW, "MR1 rank %d...", rank); + dram_mr1(ctrl, rank); + printk(BIOS_SPEW, "done\n"); + + // MR0 + printk(BIOS_SPEW, "MR0 rank %d...", rank); + dram_mr0(ctrl, rank); + printk(BIOS_SPEW, "done\n"); + } + + write32(DEFAULT_MCHBAR + 0x4e20, 0x7); + write32(DEFAULT_MCHBAR + 0x4e30, 0xf1001); + write32(DEFAULT_MCHBAR + 0x4e00, 0x60002); + write32(DEFAULT_MCHBAR + 0x4e10, 0); + write32(DEFAULT_MCHBAR + 0x4e24, 0x1f003); + write32(DEFAULT_MCHBAR + 0x4e34, 0x1901001); + write32(DEFAULT_MCHBAR + 0x4e04, 0x60400); + write32(DEFAULT_MCHBAR + 0x4e14, 0x288); + write32(DEFAULT_MCHBAR + 0x4e84, 0x40004); + + // Drain + FOR_ALL_CHANNELS { + // Wait for ref drained + wait_428c(channel); + } + + // Refresh enable + MCHBAR32(0x5030) |= 8; + + FOR_ALL_POPULATED_CHANNELS { + addr = 0x400 * channel + 0x4020; + reg = MCHBAR32(addr); + reg &= ~0x200000; + MCHBAR32(addr) = reg; + + wait_428c(channel); + + rank = (ctrl->rankmap[channel] & 1) ? 0 : 2; + + // Drain + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x0f003); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0x659001); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (rank << 24) | 0x60000); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0x3e0); + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0x1); + + // Drain + wait_428c(channel); + } +} + +const u32 lane_registers[] = { + 0x0000, 0x0200, 0x0400, 0x0600, + 0x1000, 0x1200, 0x1400, 0x1600, + 0x0800 +}; + +static void program_timings(ramctr_timing * ctrl, int channel) +{ + u32 reg32, reg_4024, reg_c14, reg_c18, reg_4028; + int lane; + int slotrank, slot; + int full_shift = 0; + u16 slot320c[NUM_SLOTS]; + + FOR_ALL_POPULATED_RANKS { + if (full_shift < -ctrl->timings[channel][slotrank].val_320c) + full_shift = -ctrl->timings[channel][slotrank].val_320c; + } + + for (slot = 0; slot < NUM_SLOTS; slot++) + switch ((ctrl->rankmap[channel] >> (2 * slot)) & 3) { + case 0: + default: + slot320c[slot] = 0x7f; + break; + case 1: + slot320c[slot] = + ctrl->timings[channel][2 * slot + 0].val_320c + + full_shift; + break; + case 2: + slot320c[slot] = + ctrl->timings[channel][2 * slot + 1].val_320c + + full_shift; + break; + case 3: + slot320c[slot] = + (ctrl->timings[channel][2 * slot].val_320c + + ctrl->timings[channel][2 * slot + + 1].val_320c) / 2 + + full_shift; + break; + } + + reg32 = (1 << 17) | (1 << 14); + reg32 |= ((slot320c[0] & 0x3f) << 6) | ((slot320c[0] & 0x40) << 9); + reg32 |= (slot320c[1] & 0x7f) << 18; + reg32 |= (full_shift & 0x3f) | ((full_shift & 0x40) << 6); + + MCHBAR32(0x320c + 0x100 * channel) = reg32; + + reg_c14 = ctrl->rankmap[channel] << 24; + reg_c18 = 0; + + FOR_ALL_POPULATED_RANKS { + int shift = + ctrl->timings[channel][slotrank].val_320c + full_shift; + int offset_val_c14; + if (shift < 0) + shift = 0; + offset_val_c14 = ctrl->reg_c14_offset + shift; + reg_c14 |= (offset_val_c14 & 0x3f) << (6 * slotrank); + reg_c18 |= ((offset_val_c14 >> 6) & 1) << slotrank; + } + + MCHBAR32(0xc14 + channel * 0x100) = reg_c14; + MCHBAR32(0xc18 + channel * 0x100) = reg_c18; + + reg_4028 = MCHBAR32(0x4028 + 0x400 * channel); + reg_4028 &= 0xffff0000; + + reg_4024 = 0; + + FOR_ALL_POPULATED_RANKS { + int post_timA_min_high = 7, post_timA_max_high = 0; + int pre_timA_min_high = 7, pre_timA_max_high = 0; + int shift_402x = 0; + int shift = + ctrl->timings[channel][slotrank].val_320c + full_shift; + + if (shift < 0) + shift = 0; + + FOR_ALL_LANES { + if (post_timA_min_high > + ((ctrl->timings[channel][slotrank].lanes[lane]. + timA + shift) >> 6)) + post_timA_min_high = + ((ctrl->timings[channel][slotrank]. + lanes[lane].timA + shift) >> 6); + if (pre_timA_min_high > + (ctrl->timings[channel][slotrank].lanes[lane]. + timA >> 6)) + pre_timA_min_high = + (ctrl->timings[channel][slotrank]. + lanes[lane].timA >> 6); + if (post_timA_max_high < + ((ctrl->timings[channel][slotrank].lanes[lane]. + timA + shift) >> 6)) + post_timA_max_high = + ((ctrl->timings[channel][slotrank]. + lanes[lane].timA + shift) >> 6); + if (pre_timA_max_high < + (ctrl->timings[channel][slotrank].lanes[lane]. + timA >> 6)) + pre_timA_max_high = + (ctrl->timings[channel][slotrank]. + lanes[lane].timA >> 6); + } + + if (pre_timA_max_high - pre_timA_min_high < + post_timA_max_high - post_timA_min_high) + shift_402x = +1; + else if (pre_timA_max_high - pre_timA_min_high > + post_timA_max_high - post_timA_min_high) + shift_402x = -1; + + reg_4028 |= + (ctrl->timings[channel][slotrank].val_4028 + shift_402x - + post_timA_min_high) << (4 * slotrank); + reg_4024 |= + (ctrl->timings[channel][slotrank].val_4024 + + shift_402x) << (8 * slotrank); + + FOR_ALL_LANES { + MCHBAR32(lane_registers[lane] + 0x10 + 0x100 * channel + + 4 * slotrank) + = + (((ctrl->timings[channel][slotrank].lanes[lane]. + timA + shift) & 0x3f) + | + ((ctrl->timings[channel][slotrank].lanes[lane]. + rising + shift) << 8) + | + (((ctrl->timings[channel][slotrank].lanes[lane]. + timA + shift - + (post_timA_min_high << 6)) & 0x1c0) << 10) + | (ctrl->timings[channel][slotrank].lanes[lane]. + falling << 20)); + + MCHBAR32(lane_registers[lane] + 0x20 + 0x100 * channel + + 4 * slotrank) + = + (((ctrl->timings[channel][slotrank].lanes[lane]. + timC + shift) & 0x3f) + | + (((ctrl->timings[channel][slotrank].lanes[lane]. + timB + shift) & 0x3f) << 8) + | + (((ctrl->timings[channel][slotrank].lanes[lane]. + timB + shift) & 0x1c0) << 9) + | + (((ctrl->timings[channel][slotrank].lanes[lane]. + timC + shift) & 0x40) << 13)); + } + } + MCHBAR32(0x4024 + 0x400 * channel) = reg_4024; + MCHBAR32(0x4028 + 0x400 * channel) = reg_4028; +} + +static void test_timA(ramctr_timing * ctrl, int channel, int slotrank) +{ + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f000); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + (0xc01 | (ctrl->tMOD << 16))); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x360004); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f105); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, 0x4040c01); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, (slotrank << 24)); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, 0x1f105); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, + 0x100f | ((ctrl->CAS + 36) << 16)); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, + (slotrank << 24) | 0x60000); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x422c + 0x400 * channel, 0x1f000); + write32(DEFAULT_MCHBAR + 0x423c + 0x400 * channel, + (0xc01 | (ctrl->tMOD << 16))); + write32(DEFAULT_MCHBAR + 0x420c + 0x400 * channel, + (slotrank << 24) | 0x360000); + write32(DEFAULT_MCHBAR + 0x421c + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0xc0001); + + wait_428c(channel); +} + +static int does_lane_work(ramctr_timing * ctrl, int channel, int slotrank, + int lane) +{ + u32 timA = ctrl->timings[channel][slotrank].lanes[lane].timA; + return ((read32 + (DEFAULT_MCHBAR + lane_registers[lane] + channel * 0x100 + 4 + + ((timA / 32) & 1) * 4) + >> (timA % 32)) & 1); +} + +struct run { + int middle; + int end; + int start; + int all; + int length; +}; + +static struct run get_longest_zero_run(int *seq, int sz) +{ + int i, ls; + int bl = 0, bs = 0; + struct run ret; + + ls = 0; + for (i = 0; i < 2 * sz; i++) + if (seq[i % sz]) { + if (i - ls > bl) { + bl = i - ls; + bs = ls; + } + ls = i + 1; + } + if (bl == 0) { + ret.middle = sz / 2; + ret.start = 0; + ret.end = sz; + ret.all = 1; + return ret; + } + + ret.start = bs % sz; + ret.end = (bs + bl - 1) % sz; + ret.middle = (bs + (bl - 1) / 2) % sz; + ret.length = bl; + ret.all = 0; + + return ret; +} + +static void discover_timA_coarse(ramctr_timing * ctrl, int channel, + int slotrank, int *upperA) +{ + int timA; + int statistics[NUM_LANES][128]; + int lane; + + for (timA = 0; timA < 128; timA++) { + FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane].timA = timA; + } + program_timings(ctrl, channel); + + test_timA(ctrl, channel, slotrank); + + FOR_ALL_LANES { + statistics[lane][timA] = + !does_lane_work(ctrl, channel, slotrank, lane); + printk(BIOS_SPEW, "Astat: %d, %d, %d, %x, %x\n", + channel, slotrank, lane, timA, + statistics[lane][timA]); + } + } + FOR_ALL_LANES { + struct run rn = get_longest_zero_run(statistics[lane], 128); + ctrl->timings[channel][slotrank].lanes[lane].timA = rn.middle; + upperA[lane] = rn.end; + if (upperA[lane] < rn.middle) + upperA[lane] += 128; + printk(BIOS_SPEW, "Aval: %d, %d, %d, %x\n", channel, slotrank, + lane, ctrl->timings[channel][slotrank].lanes[lane].timA); + printk(BIOS_SPEW, "Aend: %d, %d, %d, %x\n", channel, slotrank, + lane, upperA[lane]); + } +} + +static void discover_timA_fine(ramctr_timing * ctrl, int channel, int slotrank, + int *upperA) +{ + int timA_delta; + int statistics[NUM_LANES][51]; + int lane, i; + + memset(statistics, 0, sizeof(statistics)); + + for (timA_delta = -25; timA_delta <= 25; timA_delta++) { + FOR_ALL_LANES ctrl->timings[channel][slotrank].lanes[lane]. + timA = upperA[lane] + timA_delta + 0x40; + program_timings(ctrl, channel); + + for (i = 0; i < 100; i++) { + test_timA(ctrl, channel, slotrank); + FOR_ALL_LANES { + statistics[lane][timA_delta + 25] += + does_lane_work(ctrl, channel, slotrank, + lane); + } + } + } + FOR_ALL_LANES { + int last_zero, first_all; + + for (last_zero = -25; last_zero <= 25; last_zero++) + if (statistics[lane][last_zero + 25]) + break; + last_zero--; + for (first_all = -25; first_all <= 25; first_all++) + if (statistics[lane][first_all + 25] == 100) + break; + + printk(BIOS_SPEW, "lane %d: %d, %d\n", lane, last_zero, + first_all); + + ctrl->timings[channel][slotrank].lanes[lane].timA = + (last_zero + first_all) / 2 + upperA[lane]; + printk(BIOS_SPEW, "Aval: %d, %d, %d, %x\n", channel, slotrank, + lane, ctrl->timings[channel][slotrank].lanes[lane].timA); + } +} + +static void discover_402x(ramctr_timing * ctrl, int channel, int slotrank, + int *upperA) +{ + int works[NUM_LANES]; + int lane; + while (1) { + int all_works = 1, some_works = 0; + program_timings(ctrl, channel); + test_timA(ctrl, channel, slotrank); + FOR_ALL_LANES { + works[lane] = + !does_lane_work(ctrl, channel, slotrank, lane); + if (works[lane]) + some_works = 1; + else + all_works = 0; + } + if (all_works) + return; + if (!some_works) { + if (ctrl->timings[channel][slotrank].val_4024 < 2) + die("402x discovery failed"); + ctrl->timings[channel][slotrank].val_4024 -= 2; + printk(BIOS_SPEW, "4024 -= 2;\n"); + continue; + } + ctrl->timings[channel][slotrank].val_4028 += 2; + printk(BIOS_SPEW, "4028 += 2;\n"); + if (ctrl->timings[channel][slotrank].val_4028 >= 0x10) + die("402x discovery failed"); + FOR_ALL_LANES if (works[lane]) { + ctrl->timings[channel][slotrank].lanes[lane].timA += + 128; + upperA[lane] += 128; + printk(BIOS_SPEW, "increment %d, %d, %d\n", channel, + slotrank, lane); + } + } +} + +struct timA_minmax { + int timA_min_high, timA_max_high; +}; + +static void pre_timA_change(ramctr_timing * ctrl, int channel, int slotrank, + struct timA_minmax *mnmx) +{ + int lane; + mnmx->timA_min_high = 7; + mnmx->timA_max_high = 0; + + FOR_ALL_LANES { + if (mnmx->timA_min_high > + (ctrl->timings[channel][slotrank].lanes[lane].timA >> 6)) + mnmx->timA_min_high = + (ctrl->timings[channel][slotrank].lanes[lane]. + timA >> 6); + if (mnmx->timA_max_high < + (ctrl->timings[channel][slotrank].lanes[lane].timA >> 6)) + mnmx->timA_max_high = + (ctrl->timings[channel][slotrank].lanes[lane]. + timA >> 6); + } +} + +static void post_timA_change(ramctr_timing * ctrl, int channel, int slotrank, + struct timA_minmax *mnmx) +{ + struct timA_minmax post; + int shift_402x = 0; + + /* Get changed maxima. */ + pre_timA_change(ctrl, channel, slotrank, &post); + + if (mnmx->timA_max_high - mnmx->timA_min_high < + post.timA_max_high - post.timA_min_high) + shift_402x = +1; + else if (mnmx->timA_max_high - mnmx->timA_min_high > + post.timA_max_high - post.timA_min_high) + shift_402x = -1; + else + shift_402x = 0; + + ctrl->timings[channel][slotrank].val_4028 += shift_402x; + ctrl->timings[channel][slotrank].val_4024 += shift_402x; + printk(BIOS_SPEW, "4024 += %d;\n", shift_402x); + printk(BIOS_SPEW, "4028 += %d;\n", shift_402x); +} + +static void read_training(ramctr_timing * ctrl) +{ + int channel, slotrank, lane; + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS { + u32 r32; + int all_high, some_high; + int upperA[NUM_LANES]; + struct timA_minmax mnmx; + + wait_428c(channel); + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f002); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + 0xc01 | (ctrl->tRP << 16)); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x60400); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0); + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 1); + + write32(DEFAULT_MCHBAR + 0x3400, (slotrank << 2) | 0x8001); + + ctrl->timings[channel][slotrank].val_4028 = 4; + ctrl->timings[channel][slotrank].val_4024 = 55; + program_timings(ctrl, channel); + + discover_timA_coarse(ctrl, channel, slotrank, upperA); + + all_high = 1; + some_high = 0; + FOR_ALL_LANES { + if (ctrl->timings[channel][slotrank].lanes[lane]. + timA >= 0x40) + some_high = 1; + else + all_high = 0; + } + + if (all_high) { + ctrl->timings[channel][slotrank].val_4028--; + printk(BIOS_SPEW, "4028--;\n"); + FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane]. + timA -= 0x40; + upperA[lane] -= 0x40; + + } + } else if (some_high) { + ctrl->timings[channel][slotrank].val_4024++; + ctrl->timings[channel][slotrank].val_4028++; + printk(BIOS_SPEW, "4024++;\n"); + printk(BIOS_SPEW, "4028++;\n"); + } + + program_timings(ctrl, channel); + + pre_timA_change(ctrl, channel, slotrank, &mnmx); + + discover_402x(ctrl, channel, slotrank, upperA); + + post_timA_change(ctrl, channel, slotrank, &mnmx); + pre_timA_change(ctrl, channel, slotrank, &mnmx); + + discover_timA_fine(ctrl, channel, slotrank, upperA); + + post_timA_change(ctrl, channel, slotrank, &mnmx); + pre_timA_change(ctrl, channel, slotrank, &mnmx); + + FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane].timA -= mnmx.timA_min_high * 0x40; + } + ctrl->timings[channel][slotrank].val_4028 -= mnmx.timA_min_high; + printk(BIOS_SPEW, "4028 -= %d;\n", mnmx.timA_min_high); + + post_timA_change(ctrl, channel, slotrank, &mnmx); + + printk(BIOS_SPEW, "4/8: %d, %d, %x, %x\n", channel, slotrank, + ctrl->timings[channel][slotrank].val_4024, + ctrl->timings[channel][slotrank].val_4028); + + FOR_ALL_LANES + printk(BIOS_SPEW, "%d, %d, %d, %x\n", channel, slotrank, + lane, + ctrl->timings[channel][slotrank].lanes[lane].timA); + + write32(DEFAULT_MCHBAR + 0x3400, 0); + + r32 = read32(DEFAULT_MCHBAR + 0x5030); + write32(DEFAULT_MCHBAR + 0x5030, r32 | 0x20); + udelay(1); + + write32(DEFAULT_MCHBAR + 0x5030, r32 & ~0x20); + + udelay(1); + } + + FOR_ALL_POPULATED_CHANNELS { + program_timings(ctrl, channel); + } + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + write32(DEFAULT_MCHBAR + 0x4080 + 0x400 * channel + + 4 * lane, 0); + } +} + +static void test_timC(ramctr_timing * ctrl, int channel, int slotrank) +{ + int lane; + + FOR_ALL_LANES { + write32(DEFAULT_MCHBAR + 0x4340 + 0x400 * channel + 4 * lane, 0); + read32(DEFAULT_MCHBAR + 0x4140 + 0x400 * channel + 4 * lane); + } + + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f006); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + (max((ctrl->tFAW >> 2) + 1, ctrl->tRRD) << 10) + | 4 | (ctrl->tRCD << 16)); + + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | (6 << 16)); + + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0x244); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f207); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, 0x8041001); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24) | 8); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0x3e0); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, 0x1f201); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, 0x80411f4); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, (slotrank << 24)); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, 0x242); + + write32(DEFAULT_MCHBAR + 0x422c + 0x400 * channel, 0x1f207); + write32(DEFAULT_MCHBAR + 0x423c + 0x400 * channel, + 0x8000c01 | ((ctrl->CWL + ctrl->tWTR + 5) << 16)); + write32(DEFAULT_MCHBAR + 0x420c + 0x400 * channel, + (slotrank << 24) | 8); + write32(DEFAULT_MCHBAR + 0x421c + 0x400 * channel, 0x3e0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0xc0001); + + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f002); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + 0xc01 | (ctrl->tRP << 16)); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x60400); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0x240); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f006); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, + (max(ctrl->tRRD, (ctrl->tFAW >> 2) + 1) << 10) + | 8 | (ctrl->CAS << 16)); + + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24) | 0x60000); + + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0x244); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, 0x1f105); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, + 0x40011f4 | (max(ctrl->tRTP, 8) << 16)); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, (slotrank << 24)); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, 0x242); + + write32(DEFAULT_MCHBAR + 0x422c + 0x400 * channel, 0x1f002); + write32(DEFAULT_MCHBAR + 0x423c + 0x400 * channel, + 0xc01 | (ctrl->tRP << 16)); + write32(DEFAULT_MCHBAR + 0x420c + 0x400 * channel, + (slotrank << 24) | 0x60400); + write32(DEFAULT_MCHBAR + 0x421c + 0x400 * channel, 0x240); + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0xc0001); + wait_428c(channel); +} + +static void discover_timC(ramctr_timing * ctrl, int channel, int slotrank) +{ + int timC; + int statistics[NUM_LANES][MAX_TIMC + 1]; + int lane; + + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f002); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + 0xc01 | (ctrl->tRP << 16)); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x60400); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0x240); + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 1); + + for (timC = 0; timC <= MAX_TIMC; timC++) { + FOR_ALL_LANES ctrl->timings[channel][slotrank].lanes[lane]. + timC = timC; + program_timings(ctrl, channel); + + test_timC(ctrl, channel, slotrank); + + FOR_ALL_LANES { + statistics[lane][timC] = + read32(DEFAULT_MCHBAR + 0x4340 + 4 * lane + + 0x400 * channel); + printk(BIOS_SPEW, "Cstat: %d, %d, %d, %x, %x\n", + channel, slotrank, lane, timC, + statistics[lane][timC]); + } + } + FOR_ALL_LANES { + struct run rn = + get_longest_zero_run(statistics[lane], MAX_TIMC + 1); + ctrl->timings[channel][slotrank].lanes[lane].timC = rn.middle; + if (rn.all) + die("timC discovery failed"); + printk(BIOS_SPEW, "Cval: %d, %d, %d, %x\n", channel, slotrank, + lane, ctrl->timings[channel][slotrank].lanes[lane].timC); + } +} + +static int get_precedening_channels(ramctr_timing * ctrl, int target_channel) +{ + int channel, ret = 0; + FOR_ALL_POPULATED_CHANNELS if (channel < target_channel) + ret++; + return ret; +} + +static void fill_pattern0(ramctr_timing * ctrl, int channel, u32 a, u32 b) +{ + unsigned j; + unsigned channel_offset = + get_precedening_channels(ctrl, channel) * 0x40; + printk(BIOS_SPEW, "channel_offset=%x\n", channel_offset); + for (j = 0; j < 16; j++) + write32(0x04000000 + channel_offset + 4 * j, j & 2 ? b : a); + sfence(); +} + +static int num_of_channels(const ramctr_timing * ctrl) +{ + int ret = 0; + int channel; + FOR_ALL_POPULATED_CHANNELS ret++; + return ret; +} + +static void fill_pattern1(ramctr_timing * ctrl, int channel) +{ + unsigned j; + unsigned channel_offset = + get_precedening_channels(ctrl, channel) * 0x40; + unsigned channel_step = 0x40 * num_of_channels(ctrl); + for (j = 0; j < 16; j++) + write32(0x04000000 + channel_offset + j * 4, 0xffffffff); + for (j = 0; j < 16; j++) + write32(0x04000000 + channel_offset + channel_step + j * 4, 0); + sfence(); +} + +static void precharge(ramctr_timing * ctrl) +{ + int channel, slotrank, lane; + + FOR_ALL_POPULATED_CHANNELS { + FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane].falling = + 16; + ctrl->timings[channel][slotrank].lanes[lane].rising = + 16; + } program_timings(ctrl, channel); + + FOR_ALL_POPULATED_RANKS { + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, + 0x1f000); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + 0xc01 | (ctrl->tMOD << 16)); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x360004); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, + 0x1f105); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, + 0x4041003); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24) | 0); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, + 0x1f105); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, + 0x1001 | ((ctrl->CAS + 8) << 16)); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, + (slotrank << 24) | 0x60000); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x422c + 0x400 * channel, + 0x1f000); + write32(DEFAULT_MCHBAR + 0x423c + 0x400 * channel, + 0xc01 | (ctrl->tMOD << 16)); + write32(DEFAULT_MCHBAR + 0x420c + 0x400 * channel, + (slotrank << 24) | 0x360000); + write32(DEFAULT_MCHBAR + 0x421c + 0x400 * channel, 0); + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, + 0xc0001); + + wait_428c(channel); + } + + FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane].falling = + 48; + ctrl->timings[channel][slotrank].lanes[lane].rising = + 48; + } + + program_timings(ctrl, channel); + + FOR_ALL_POPULATED_RANKS { + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, + 0x1f000); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + 0xc01 | (ctrl->tMOD << 16)); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x360004); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, + 0x1f105); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, + 0x4041003); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24) | 0); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, + 0x1f105); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, + 0x1001 | ((ctrl->CAS + 8) << 16)); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, + (slotrank << 24) | 0x60000); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x422c + 0x400 * channel, + 0x1f000); + write32(DEFAULT_MCHBAR + 0x423c + 0x400 * channel, + 0xc01 | (ctrl->tMOD << 16)); + + write32(DEFAULT_MCHBAR + 0x420c + 0x400 * channel, + (slotrank << 24) | 0x360000); + write32(DEFAULT_MCHBAR + 0x421c + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, + 0xc0001); + wait_428c(channel); + } + } +} + +static void test_timB(ramctr_timing * ctrl, int channel, int slotrank) +{ + write_mrreg(ctrl, channel, slotrank, 1, + 0x80 | make_mr1(ctrl, slotrank)); + + wait_428c(channel); + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f207); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + 0x8000c01 | ((ctrl->CWL + ctrl->tWLO) << 16)); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + 8 | (slotrank << 24)); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f107); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, + 0x4000c01 | ((ctrl->CAS + 38) << 16)); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24) | 4); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x400 * channel + 0x4284, 0x40001); + wait_428c(channel); + + write_mrreg(ctrl, channel, slotrank, 1, + 0x1080 | make_mr1(ctrl, slotrank)); +} + +static void discover_timB(ramctr_timing * ctrl, int channel, int slotrank) +{ + int timB; + int statistics[NUM_LANES][128]; + int lane; + + write32(DEFAULT_MCHBAR + 0x3400, 0x108052 | (slotrank << 2)); + + for (timB = 0; timB < 128; timB++) { + FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane].timB = timB; + } + program_timings(ctrl, channel); + + test_timB(ctrl, channel, slotrank); + + FOR_ALL_LANES { + statistics[lane][timB] = + !((read32 + (DEFAULT_MCHBAR + lane_registers[lane] + + channel * 0x100 + 4 + ((timB / 32) & 1) * 4) + >> (timB % 32)) & 1); + printk(BIOS_SPEW, "Bstat: %d, %d, %d, %x, %x\n", + channel, slotrank, lane, timB, + statistics[lane][timB]); + } + } + FOR_ALL_LANES { + struct run rn = get_longest_zero_run(statistics[lane], 128); + ctrl->timings[channel][slotrank].lanes[lane].timB = rn.start; + if (rn.all) + die("timB discovery failed"); + printk(BIOS_SPEW, "Bval: %d, %d, %d, %x\n", channel, slotrank, + lane, ctrl->timings[channel][slotrank].lanes[lane].timB); + } +} + +static int get_timB_high_adjust(u64 val) +{ + int i; + if (val >= 0xfffffffffffff000LL) + return 3; + if (val >= 0xfffffffffff00000LL) + return -1; + if (val >= 0xfffffff000000000LL) + return -2; + if (val >= 0xfff0000000000000LL) + return -3; + + for (i = 0; i < 8; i++) + if (val >> (8 * (7 - i) + 4)) + return i; + return 8; +} + +static void adjust_high_timB(ramctr_timing * ctrl) +{ + int channel, slotrank, lane; + write32(DEFAULT_MCHBAR + 0x3400, 0x200); + FOR_ALL_POPULATED_CHANNELS { + fill_pattern1(ctrl, channel); + write32(DEFAULT_MCHBAR | 0x4288 | (channel << 10), 1); + } + FOR_ALL_POPULATED_CHANNELS FOR_ALL_POPULATED_RANKS { + + write32(DEFAULT_MCHBAR + 0x4288 + 0x400 * channel, 0x10001); + + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f006); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + 0xc01 | (ctrl->tRCD << 16)); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x60000); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f207); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, 0x8040c01); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24) | 0x8); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0x3e0); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, 0x1f201); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, 0x8041003); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, + (slotrank << 24)); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, 0x3e2); + + write32(DEFAULT_MCHBAR + 0x422c + 0x400 * channel, 0x1f207); + write32(DEFAULT_MCHBAR + 0x423c + 0x400 * channel, + 0x8000c01 | ((ctrl->CWL + ctrl->tWTR + 5) << 16)); + write32(DEFAULT_MCHBAR + 0x420c + 0x400 * channel, + (slotrank << 24) | 0x8); + write32(DEFAULT_MCHBAR + 0x421c + 0x400 * channel, 0x3e0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0xc0001); + + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f002); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + 0xc01 | ((ctrl->tRP) << 16)); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x60400); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0x240); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f006); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, + 0xc01 | ((ctrl->tRCD) << 16)); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24) | 0x60000); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, 0x3f105); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, + 0x4000c01 | + ((ctrl->tRP + + ctrl->timings[channel][slotrank].val_4024 + + ctrl->timings[channel][slotrank].val_4028) << 16)); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, + (slotrank << 24) | 0x60008); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0x80001); + wait_428c(channel); + FOR_ALL_LANES { + u64 res = + read32(DEFAULT_MCHBAR + lane_registers[lane] + + 0x100 * channel + 4); + res |= + ((u64) read32(DEFAULT_MCHBAR + lane_registers[lane] + + 0x100 * channel + 8)) << 32; + ctrl->timings[channel][slotrank].lanes[lane].timB += + get_timB_high_adjust(res) * 64; + + printk(BIOS_DEBUG, "High adjust %d:%016llx\n", lane, res); + printk(BIOS_SPEW, "Bval+: %d, %d, %d, %x\n", channel, + slotrank, lane, + ctrl->timings[channel][slotrank].lanes[lane]. + timB); + } + } + write32(DEFAULT_MCHBAR + 0x3400, 0); +} + +static void write_op(ramctr_timing * ctrl, int channel) +{ + int slotrank; + + wait_428c(channel); + + /* choose an existing rank. */ + slotrank = !(ctrl->rankmap[channel] & 1) ? 2 : 0; + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x0f003); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0x41001); + + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x60000); + + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0x3e0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 1); + wait_428c(channel); +} + +static void write_training(ramctr_timing * ctrl) +{ + int channel, slotrank, lane; + u32 r32; + + FOR_ALL_POPULATED_CHANNELS + write32(DEFAULT_MCHBAR + 0x4008 + 0x400 * channel, + read32(DEFAULT_MCHBAR + 0x4008 + + 0x400 * channel) | 0x8000000); + + FOR_ALL_POPULATED_CHANNELS { + write_op(ctrl, channel); + write32(DEFAULT_MCHBAR + 0x4020 + 0x400 * channel, + read32(DEFAULT_MCHBAR + 0x4020 + + 0x400 * channel) | 0x200000); + } + write32(DEFAULT_MCHBAR + 0x5030, read32(DEFAULT_MCHBAR + 0x5030) & ~8); + FOR_ALL_POPULATED_CHANNELS { + write_op(ctrl, channel); + } + + FOR_ALL_CHANNELS + FOR_ALL_POPULATED_RANKS + write_mrreg(ctrl, channel, slotrank, 1, + make_mr1(ctrl, slotrank) | 0x1080); + + write32(DEFAULT_MCHBAR + 0x3400, 0x108052); + + r32 = read32(DEFAULT_MCHBAR + 0x5030); + write32(DEFAULT_MCHBAR + 0x5030, r32 | 0x20); + udelay(1); + + write32(DEFAULT_MCHBAR + 0x5030, r32 & ~0x20); + + udelay(1); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS + discover_timB(ctrl, channel, slotrank); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS + write_mrreg(ctrl, channel, + slotrank, 1, make_mr1(ctrl, slotrank)); + + write32(DEFAULT_MCHBAR + 0x3400, 0); + + FOR_ALL_POPULATED_CHANNELS + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x5030, read32(DEFAULT_MCHBAR + 0x5030) | 8); + + FOR_ALL_POPULATED_CHANNELS { + write32(DEFAULT_MCHBAR + 0x4020 + 0x400 * channel, + ~0x00200000 & read32(DEFAULT_MCHBAR + 0x4020 + + 0x400 * channel)); + read32(DEFAULT_MCHBAR + 0x428c + 0x400 * channel); + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x0f003); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0x659001); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, 0x60000); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0x3e0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 1); + wait_428c(channel); + } + + r32 = read32(DEFAULT_MCHBAR + 0x5030); + write32(DEFAULT_MCHBAR + 0x5030, r32 | 0x20); + udelay(1); + + write32(DEFAULT_MCHBAR + 0x5030, r32 & ~0x20); + + udelay(1); + + printk(BIOS_SPEW, "CPE\n"); + precharge(ctrl); + printk(BIOS_SPEW, "CPF\n"); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + read32(DEFAULT_MCHBAR + 0x4080 + 0x400 * channel + 4 * lane); + write32(DEFAULT_MCHBAR + 0x4080 + 0x400 * channel + 4 * lane, + 0); + } + + FOR_ALL_POPULATED_CHANNELS { + fill_pattern0(ctrl, channel, 0xaaaaaaaa, 0x55555555); + write32(DEFAULT_MCHBAR | 0x4288 | (channel << 10), 0); + } + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS + discover_timC(ctrl, channel, slotrank); + + FOR_ALL_POPULATED_CHANNELS + program_timings(ctrl, channel); + + adjust_high_timB(ctrl); + + FOR_ALL_POPULATED_CHANNELS + program_timings(ctrl, channel); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + read32(DEFAULT_MCHBAR + 0x4080 + 0x400 * channel + 4 * lane); + write32(DEFAULT_MCHBAR + 0x4080 + 0x400 * channel + 4 * lane, + 0); + } +} + +static int test_320c(ramctr_timing * ctrl, int channel, int slotrank) +{ + struct ram_rank_timings saved_rt = ctrl->timings[channel][slotrank]; + int timC_delta; + int lanes_ok = 0; + int ctr = 0; + int lane; + + for (timC_delta = -5; timC_delta <= 5; timC_delta++) { + FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane].timC = + saved_rt.lanes[lane].timC + timC_delta; + } + program_timings(ctrl, channel); + FOR_ALL_LANES { + write32(DEFAULT_MCHBAR + 4 * lane + 0x4f40, 0); + } + + write32(DEFAULT_MCHBAR + 0x4288 + 0x400 * channel, 0x1f); + + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f006); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + ((max(ctrl->tRRD, (ctrl->tFAW >> 2) + 1)) << 10) + | 8 | (ctrl->tRCD << 16)); + + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | ctr | 0x60000); + + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0x244); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f201); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, + 0x8001020 | ((ctrl->CWL + ctrl->tWTR + 8) << 16)); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24)); + write32(DEFAULT_MCHBAR + 0x4244 + 0x400 * channel, 0x389abcd); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0x20e42); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, 0x1f105); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, + 0x4001020 | (max(ctrl->tRTP, 8) << 16)); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, + (slotrank << 24)); + write32(DEFAULT_MCHBAR + 0x4248 + 0x400 * channel, 0x389abcd); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, 0x20e42); + + write32(DEFAULT_MCHBAR + 0x422c + 0x400 * channel, 0x1f002); + write32(DEFAULT_MCHBAR + 0x423c + 0x400 * channel, 0xf1001); + write32(DEFAULT_MCHBAR + 0x420c + 0x400 * channel, + (slotrank << 24) | 0x60400); + write32(DEFAULT_MCHBAR + 0x421c + 0x400 * channel, 0x240); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0xc0001); + wait_428c(channel); + FOR_ALL_LANES { + u32 r32 = + read32(DEFAULT_MCHBAR + 0x4340 + 4 * lane + + 0x400 * channel); + + if (r32 == 0) + lanes_ok |= 1 << lane; + } + ctr++; + if (lanes_ok == ((1 << NUM_LANES) - 1)) + break; + } + + ctrl->timings[channel][slotrank] = saved_rt; + + printk(BIOS_SPEW, "3lanes: %x\n", lanes_ok); + return lanes_ok != ((1 << NUM_LANES) - 1); +} + +#include "raminit_patterns.h" + +static void fill_pattern5(ramctr_timing * ctrl, int channel, int patno) +{ + unsigned i, j; + unsigned channel_offset = + get_precedening_channels(ctrl, channel) * 0x40; + unsigned channel_step = 0x40 * num_of_channels(ctrl); + + if (patno) { + u8 base8 = 0x80 >> ((patno - 1) % 8); + u32 base = base8 | (base8 << 8) | (base8 << 16) | (base8 << 24); + for (i = 0; i < 32; i++) { + for (j = 0; j < 16; j++) { + u32 val = use_base[patno - 1][i] & (1 << (j / 2)) ? base : 0; + if (invert[patno - 1][i] & (1 << (j / 2))) + val = ~val; + write32(0x04000000 + channel_offset + i * channel_step + + j * 4, val); + } + } + + } else { + for (i = 0; i < sizeof(pattern) / sizeof(pattern[0]); i++) { + for (j = 0; j < 16; j++) + write32(0x04000000 + channel_offset + i * channel_step + + j * 4, pattern[i][j]); + } + sfence(); + } +} + +static void reprogram_320c(ramctr_timing * ctrl) +{ + int channel, slotrank; + u32 r32; + + FOR_ALL_POPULATED_CHANNELS { + wait_428c(channel); + + /* choose an existing rank. */ + slotrank = !(ctrl->rankmap[channel] & 1) ? 2 : 0; + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x0f003); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0x41001); + + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x60000); + + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0x3e0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 1); + wait_428c(channel); + write32(DEFAULT_MCHBAR + 0x4020 + 0x400 * channel, + read32(DEFAULT_MCHBAR + 0x4020 + + 0x400 * channel) | 0x200000); + } + write32(DEFAULT_MCHBAR + 0x5030, read32(DEFAULT_MCHBAR + 0x5030) & ~8); + FOR_ALL_POPULATED_CHANNELS { + wait_428c(channel); + + /* choose an existing rank. */ + slotrank = !(ctrl->rankmap[channel] & 1) ? 2 : 0; + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x0f003); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0x41001); + + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x60000); + + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0x3e0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 1); + wait_428c(channel); + } + + /* jedec reset */ + dram_jedecreset(ctrl); + /* mrs commands. */ + dram_mrscommands(ctrl); + + r32 = read32(DEFAULT_MCHBAR + 0x5030); + write32(DEFAULT_MCHBAR + 0x5030, r32 | 0x20); + udelay(1); + + write32(DEFAULT_MCHBAR + 0x5030, r32 & ~0x20); + + udelay(1); +} + +#define MIN_C320C_LEN 13 + +static int try_reg_4004_b30(ramctr_timing * ctrl, int r4004b30) +{ + struct ram_rank_timings saved_timings[NUM_CHANNELS][NUM_SLOTRANKS]; + int channel, slotrank; + int c320c; + int stat[NUM_SLOTRANKS][256]; + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS { + saved_timings[channel][slotrank] = ctrl->timings[channel][slotrank]; + } + + FOR_ALL_POPULATED_CHANNELS { + ctrl->reg_4004_b30[channel] = r4004b30; + } + + FOR_ALL_POPULATED_CHANNELS + MCHBAR32(0x4004 + 0x400 * channel) = + ctrl->tRRD + | (ctrl->tRTP << 4) + | (ctrl->tCKE << 8) + | (ctrl->tWTR << 12) + | (ctrl->tFAW << 16) + | (ctrl->tWR << 24) + | (ctrl->reg_4004_b30[channel] << 30); + + + FOR_ALL_CHANNELS { + int delta = 0; + if (ctrl->reg_4004_b30[channel] == 2) + delta = 2; + else if (ctrl->reg_4004_b30[channel] == 0) + delta = 4; + + FOR_ALL_POPULATED_RANKS { + ctrl->timings[channel][slotrank].val_4024 -= delta; + } + } + + FOR_ALL_POPULATED_CHANNELS { + for (c320c = -127; c320c <= 127; c320c++) { + FOR_ALL_POPULATED_RANKS { + ctrl->timings[channel][slotrank].val_320c = c320c; + } + program_timings(ctrl, channel); + reprogram_320c(ctrl); + FOR_ALL_POPULATED_RANKS { + stat[slotrank][c320c + 127] = + test_320c(ctrl, channel, slotrank); + printk(BIOS_SPEW, "3stat: %d, %d, %d: %d\n", + channel, slotrank, c320c, + stat[slotrank][c320c + 127]); + } + } + FOR_ALL_POPULATED_RANKS { + struct run rn = + get_longest_zero_run(stat[slotrank], 255); + ctrl->timings[channel][slotrank].val_320c = + rn.middle - 127; + printk(BIOS_SPEW, "3val: %d, %d: %d\n", channel, + slotrank, + ctrl->timings[channel][slotrank].val_320c); + if (rn.all || rn.length < MIN_C320C_LEN) { + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS { + ctrl->timings[channel][slotrank] = saved_timings[channel][slotrank]; + } + return 0; + } + } + } + return 1; +} + +static void command_training(ramctr_timing * ctrl) +{ + int channel; + + FOR_ALL_POPULATED_CHANNELS { + fill_pattern5(ctrl, channel, 0); + write32(DEFAULT_MCHBAR + 0x4288 + 0x400 * channel, 0x1f); + } + + if (!try_reg_4004_b30(ctrl, 0) && !try_reg_4004_b30(ctrl, 2)) + die("c320c discovery failed"); + + FOR_ALL_POPULATED_CHANNELS { + program_timings(ctrl, channel); + } + + reprogram_320c(ctrl); +} + +static void discover_edges_real(ramctr_timing * ctrl, int channel, int slotrank, + int *edges) +{ + int edge; + int statistics[NUM_LANES][MAX_EDGE_TIMING + 1]; + int lane; + + for (edge = 0; edge <= MAX_EDGE_TIMING; edge++) { + FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane].rising = + edge; + ctrl->timings[channel][slotrank].lanes[lane].falling = + edge; + } + printk(BIOS_SPEW, "edge %02x\n", edge); + program_timings(ctrl, channel); + + FOR_ALL_LANES { + write32(DEFAULT_MCHBAR + 0x4340 + 0x400 * channel + + 4 * lane, 0); + read32(DEFAULT_MCHBAR + 0x400 * channel + 4 * lane + + 0x4140); + } + + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f000); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + (0xc01 | (ctrl->tMOD << 16))); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x360004); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f105); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, 0x40411f4); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24)); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, 0x1f105); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, + 0x1001 | ((ctrl->CAS + 8) << 16)); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, + (slotrank << 24) | 0x60000); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x422c + 0x400 * channel, 0x1f000); + write32(DEFAULT_MCHBAR + 0x423c + 0x400 * channel, + (0xc01 | (ctrl->tMOD << 16))); + write32(DEFAULT_MCHBAR + 0x420c + 0x400 * channel, + (slotrank << 24) | 0x360000); + write32(DEFAULT_MCHBAR + 0x421c + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0xc0001); + + wait_428c(channel); + + FOR_ALL_LANES { + statistics[lane][edge] = + read32(DEFAULT_MCHBAR + 0x4340 + 0x400 * channel + + lane * 4); + } + } + FOR_ALL_LANES { + struct run rn = + get_longest_zero_run(statistics[lane], MAX_EDGE_TIMING + 1); + edges[lane] = rn.middle; + if (rn.all) + die("edge discovery failed"); + printk(BIOS_SPEW, "eval %d, %d, %d, %02x\n", channel, slotrank, + lane, edges[lane]); + } +} + +static void discover_edges(ramctr_timing * ctrl) +{ + int falling_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES]; + int rising_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES]; + int channel, slotrank, lane; + u32 r32; + + write32(DEFAULT_MCHBAR + 0x3400, 0); + + r32 = read32(DEFAULT_MCHBAR + 0x5030); + write32(DEFAULT_MCHBAR + 0x5030, r32 | 0x20); + udelay(1); + + write32(DEFAULT_MCHBAR + 0x5030, r32 & ~0x20); + + udelay(1); + + FOR_ALL_POPULATED_CHANNELS FOR_ALL_LANES { + write32(DEFAULT_MCHBAR + 4 * lane + + 0x400 * channel + 0x4080, 0); + } + + FOR_ALL_POPULATED_CHANNELS { + fill_pattern0(ctrl, channel, 0, 0); + write32(DEFAULT_MCHBAR | 0x4288 | (channel << 10), 0); + FOR_ALL_LANES { + read32(DEFAULT_MCHBAR + 0x400 * channel + + lane * 4 + 0x4140); + } + + FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane].falling = + 16; + ctrl->timings[channel][slotrank].lanes[lane].rising = + 16; + } + + program_timings(ctrl, channel); + + FOR_ALL_POPULATED_RANKS { + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, + 0x1f000); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + 0xc01 | (ctrl->tMOD << 16)); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x360004); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, + 0x1f105); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, + 0x4041003); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24) | 0); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, + 0x1f105); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, + 0x1001 | ((ctrl->CAS + 8) << 16)); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, + (slotrank << 24) | 0x60000); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x422c + 0x400 * channel, + 0x1f000); + write32(DEFAULT_MCHBAR + 0x423c + 0x400 * channel, + 0xc01 | (ctrl->tMOD << 16)); + write32(DEFAULT_MCHBAR + 0x420c + 0x400 * channel, + (slotrank << 24) | 0x360000); + write32(DEFAULT_MCHBAR + 0x421c + 0x400 * channel, 0); + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, + 0xc0001); + + wait_428c(channel); + } + + FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane].falling = + 48; + ctrl->timings[channel][slotrank].lanes[lane].rising = + 48; + } + + program_timings(ctrl, channel); + + FOR_ALL_POPULATED_RANKS { + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, + 0x1f000); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + 0xc01 | (ctrl->tMOD << 16)); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x360004); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, + 0x1f105); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, + 0x4041003); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24) | 0); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, + 0x1f105); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, + 0x1001 | ((ctrl->CAS + 8) << 16)); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, + (slotrank << 24) | 0x60000); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x422c + 0x400 * channel, + 0x1f000); + write32(DEFAULT_MCHBAR + 0x423c + 0x400 * channel, + 0xc01 | (ctrl->tMOD << 16)); + write32(DEFAULT_MCHBAR + 0x420c + 0x400 * channel, + (slotrank << 24) | 0x360000); + write32(DEFAULT_MCHBAR + 0x421c + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, + 0xc0001); + wait_428c(channel); + } + + FOR_ALL_LANES { + write32(DEFAULT_MCHBAR + 0x4080 + 0x400 * channel + + lane * 4, + ~read32(DEFAULT_MCHBAR + 0x4040 + + 0x400 * channel + lane * 4) & 0xff); + } + + fill_pattern0(ctrl, channel, 0, 0xffffffff); + write32(DEFAULT_MCHBAR | 0x4288 | (channel << 10), 0); + } + + /* FIXME: under some conditions (older chipsets?) vendor BIOS sets both edges to the same value. */ + write32(DEFAULT_MCHBAR + 0x4eb0, 0x300); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS { + discover_edges_real(ctrl, channel, slotrank, + falling_edges[channel][slotrank]); + } + + write32(DEFAULT_MCHBAR + 0x4eb0, 0x200); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS { + discover_edges_real(ctrl, channel, slotrank, + rising_edges[channel][slotrank]); + } + + write32(DEFAULT_MCHBAR + 0x4eb0, 0); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane].falling = + falling_edges[channel][slotrank][lane]; + ctrl->timings[channel][slotrank].lanes[lane].rising = + rising_edges[channel][slotrank][lane]; + } + + FOR_ALL_POPULATED_CHANNELS { + program_timings(ctrl, channel); + } + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + write32(DEFAULT_MCHBAR + 0x4080 + 0x400 * channel + 4 * lane, + 0); + } +} + +static void discover_edges_write_real(ramctr_timing * ctrl, int channel, + int slotrank, int *edges) +{ + int edge; + u32 raw_statistics[MAX_EDGE_TIMING + 1]; + int statistics[MAX_EDGE_TIMING + 1]; + const int reg3000b24[] = { 0, 0xc, 0x2c }; + int lane, i; + int lower[NUM_LANES]; + int upper[NUM_LANES]; + int pat; + + FOR_ALL_LANES { + lower[lane] = 0; + upper[lane] = MAX_EDGE_TIMING; + } + + for (i = 0; i < 3; i++) { + write32(DEFAULT_MCHBAR + 0x3000 + 0x100 * channel, + reg3000b24[i] << 24); + for (pat = 0; pat < NUM_PATTERNS; pat++) { + fill_pattern5(ctrl, channel, pat); + write32(DEFAULT_MCHBAR + 0x4288 + 0x400 * channel, 0x1f); + printk(BIOS_SPEW, "patterned\n"); + printk(BIOS_SPEW, "[%x] = 0x%08x\n(%d, %d)\n", + 0x3000 + 0x100 * channel, reg3000b24[i] << 24, channel, + slotrank); + for (edge = 0; edge <= MAX_EDGE_TIMING; edge++) { + FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane]. + rising = edge; + ctrl->timings[channel][slotrank].lanes[lane]. + falling = edge; + } + program_timings(ctrl, channel); + + FOR_ALL_LANES { + write32(DEFAULT_MCHBAR + 0x4340 + + 0x400 * channel + 4 * lane, 0); + read32(DEFAULT_MCHBAR + 0x400 * channel + + 4 * lane + 0x4140); + } + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, + 0x1f006); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + 0x4 | (ctrl->tRCD << 16) + | (max(ctrl->tRRD, (ctrl->tFAW >> 2) + 1) << + 10)); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x60000); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, + 0x240); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, + 0x1f201); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, + 0x8005020 | ((ctrl->tWTR + ctrl->CWL + 8) << + 16)); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24)); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, + 0x242); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, + 0x1f105); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, + 0x4005020 | (max(ctrl->tRTP, 8) << 16)); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, + (slotrank << 24)); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, + 0x242); + + write32(DEFAULT_MCHBAR + 0x422c + 0x400 * channel, + 0x1f002); + write32(DEFAULT_MCHBAR + 0x423c + 0x400 * channel, + 0xc01 | (ctrl->tRP << 16)); + write32(DEFAULT_MCHBAR + 0x420c + 0x400 * channel, + (slotrank << 24) | 0x60400); + write32(DEFAULT_MCHBAR + 0x421c + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, + 0xc0001); + wait_428c(channel); + FOR_ALL_LANES { + read32(DEFAULT_MCHBAR + 0x4340 + + 0x400 * channel + lane * 4); + } + + raw_statistics[edge] = + MCHBAR32(0x436c + 0x400 * channel); + } + FOR_ALL_LANES { + struct run rn; + for (edge = 0; edge <= MAX_EDGE_TIMING; edge++) + statistics[edge] = + ! !(raw_statistics[edge] & (1 << lane)); + rn = get_longest_zero_run(statistics, + MAX_EDGE_TIMING + 1); + printk(BIOS_SPEW, + "edges: %d, %d, %d: 0x%x-0x%x-0x%x, 0x%x-0x%x\n", + channel, slotrank, i, rn.start, rn.middle, + rn.end, rn.start + ctrl->edge_offset[i], + rn.end - ctrl->edge_offset[i]); + lower[lane] = + max(rn.start + ctrl->edge_offset[i], lower[lane]); + upper[lane] = + min(rn.end - ctrl->edge_offset[i], upper[lane]); + edges[lane] = (lower[lane] + upper[lane]) / 2; + + } + } + } + + write32(DEFAULT_MCHBAR + 0x3000, 0); + printk(BIOS_SPEW, "CPA\n"); +} + +static void discover_edges_write(ramctr_timing * ctrl) +{ + int falling_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES]; + int rising_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES]; + int channel, slotrank, lane; + + /* FIXME: under some conditions (older chipsets?) vendor BIOS sets both edges to the same value. */ + write32(DEFAULT_MCHBAR + 0x4eb0, 0x300); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS { + discover_edges_write_real(ctrl, channel, slotrank, + falling_edges[channel][slotrank]); + } + + write32(DEFAULT_MCHBAR + 0x4eb0, 0x200); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS { + discover_edges_write_real(ctrl, channel, slotrank, + rising_edges[channel][slotrank]); + } + + write32(DEFAULT_MCHBAR + 0x4eb0, 0); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane].falling = + falling_edges[channel][slotrank][lane]; + ctrl->timings[channel][slotrank].lanes[lane].rising = + rising_edges[channel][slotrank][lane]; + } + + FOR_ALL_POPULATED_CHANNELS + program_timings(ctrl, channel); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + write32(DEFAULT_MCHBAR + 0x4080 + 0x400 * channel + 4 * lane, + 0); + } +} + +static void test_timC_write(ramctr_timing *ctrl, int channel, int slotrank) +{ + wait_428c(channel); + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f006); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + (max((ctrl->tFAW >> 2) + 1, ctrl->tRRD) + << 10) | (ctrl->tRCD << 16) | 4); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x60000); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0x244); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f201); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, + 0x80011e0 | + ((ctrl->tWTR + ctrl->CWL + 8) << 16)); + write32(DEFAULT_MCHBAR + 0x4204 + + 0x400 * channel, (slotrank << 24)); + write32(DEFAULT_MCHBAR + 0x4214 + + 0x400 * channel, 0x242); + + write32(DEFAULT_MCHBAR + 0x4228 + + 0x400 * channel, 0x1f105); + write32(DEFAULT_MCHBAR + 0x4238 + + 0x400 * channel, + 0x40011e0 | (max(ctrl->tRTP, 8) << 16)); + write32(DEFAULT_MCHBAR + 0x4208 + + 0x400 * channel, (slotrank << 24)); + write32(DEFAULT_MCHBAR + 0x4218 + + 0x400 * channel, 0x242); + + write32(DEFAULT_MCHBAR + 0x422c + + 0x400 * channel, 0x1f002); + write32(DEFAULT_MCHBAR + 0x423c + + 0x400 * channel, + 0x1001 | (ctrl->tRP << 16)); + write32(DEFAULT_MCHBAR + 0x420c + + 0x400 * channel, + (slotrank << 24) | 0x60400); + write32(DEFAULT_MCHBAR + 0x421c + + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4284 + + 0x400 * channel, 0xc0001); + wait_428c(channel); +} + +static void discover_timC_write(ramctr_timing * ctrl) +{ + const u8 rege3c_b24[3] = { 0, 0xf, 0x2f }; + int i, pat; + + int lower[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES]; + int upper[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES]; + int channel, slotrank, lane; + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + lower[channel][slotrank][lane] = 0; + upper[channel][slotrank][lane] = MAX_TIMC; + } + + write32(DEFAULT_MCHBAR + 0x4ea8, 1); + + for (i = 0; i < 3; i++) + FOR_ALL_POPULATED_CHANNELS { + write32(DEFAULT_MCHBAR + 0xe3c + (channel * 0x100), + (rege3c_b24[i] << 24) + | (read32(DEFAULT_MCHBAR + 0xe3c + (channel * 0x100)) + & ~0x3f000000)); + udelay(2); + for (pat = 0; pat < NUM_PATTERNS; pat++) { + FOR_ALL_POPULATED_RANKS { + int timC; + u32 raw_statistics[MAX_TIMC + 1]; + int statistics[MAX_TIMC + 1]; + + fill_pattern5(ctrl, channel, pat); + write32(DEFAULT_MCHBAR + 0x4288 + 0x400 * channel, 0x1f); + for (timC = 0; timC < MAX_TIMC + 1; timC++) { + FOR_ALL_LANES + ctrl->timings[channel][slotrank].lanes[lane].timC = timC; + program_timings(ctrl, channel); + + test_timC_write (ctrl, channel, slotrank); + + raw_statistics[timC] = + MCHBAR32(0x436c + 0x400 * channel); + } + FOR_ALL_LANES { + struct run rn; + for (timC = 0; timC <= MAX_TIMC; timC++) + statistics[timC] = + !!(raw_statistics[timC] & + (1 << lane)); + rn = get_longest_zero_run(statistics, + MAX_TIMC + 1); + if (rn.all) + die("timC write discovery failed"); + printk(BIOS_SPEW, + "timC: %d, %d, %d: 0x%x-0x%x-0x%x, 0x%x-0x%x\n", + channel, slotrank, i, rn.start, + rn.middle, rn.end, + rn.start + ctrl->timC_offset[i], + rn.end - ctrl->timC_offset[i]); + lower[channel][slotrank][lane] = + max(rn.start + ctrl->timC_offset[i], + lower[channel][slotrank][lane]); + upper[channel][slotrank][lane] = + min(rn.end - ctrl->timC_offset[i], + upper[channel][slotrank][lane]); + + } + } + } + } + + FOR_ALL_CHANNELS { + write32(DEFAULT_MCHBAR + (channel * 0x100) + 0xe3c, + 0 | (read32(DEFAULT_MCHBAR + (channel * 0x100) + 0xe3c) & + ~0x3f000000)); + udelay(2); + } + + write32(DEFAULT_MCHBAR + 0x4ea8, 0); + + printk(BIOS_SPEW, "CPB\n"); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + printk(BIOS_SPEW, "timC [%d, %d, %d] = 0x%x\n", channel, + slotrank, lane, + (lower[channel][slotrank][lane] + + upper[channel][slotrank][lane]) / 2); + ctrl->timings[channel][slotrank].lanes[lane].timC = + (lower[channel][slotrank][lane] + + upper[channel][slotrank][lane]) / 2; + } + FOR_ALL_POPULATED_CHANNELS { + program_timings(ctrl, channel); + } +} + +static void normalize_training(ramctr_timing * ctrl) +{ + int channel, slotrank, lane; + int mat = 0; + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS { + int delta; + FOR_ALL_LANES mat = + max(ctrl->timings[channel][slotrank].lanes[lane].timA, mat); + delta = (mat >> 6) - ctrl->timings[channel][slotrank].val_4028; + ctrl->timings[channel][slotrank].val_4024 += delta; + ctrl->timings[channel][slotrank].val_4028 += delta; + } + + FOR_ALL_POPULATED_CHANNELS { + program_timings(ctrl, channel); + } +} + +static void write_controller_mr(ramctr_timing * ctrl) +{ + int channel, slotrank; + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS { + write32(DEFAULT_MCHBAR | 0x0004 | (channel << 8) | + lane_registers[slotrank], make_mr0(ctrl, slotrank)); + write32(DEFAULT_MCHBAR | 0x0008 | (channel << 8) | + lane_registers[slotrank], make_mr1(ctrl, slotrank)); + } +} + +static void channel_test(ramctr_timing * ctrl) +{ + int channel, slotrank, lane; + + FOR_ALL_POPULATED_CHANNELS + if (read32(DEFAULT_MCHBAR | 0x42a0 | (channel << 10)) & 0xa000) + die("Mini channel test failed (1)\n"); + FOR_ALL_POPULATED_CHANNELS { + fill_pattern0(ctrl, channel, 0x12345678, 0x98765432); + + write32(DEFAULT_MCHBAR | 0x4288 | (channel << 10), 0); + } + + for (slotrank = 0; slotrank < 4; slotrank++) + FOR_ALL_CHANNELS + if (ctrl->rankmap[channel] & (1 << slotrank)) { + FOR_ALL_LANES { + write32(DEFAULT_MCHBAR | (0x4f40 + 4 * lane), 0); + write32(DEFAULT_MCHBAR | (0x4d40 + 4 * lane), 0); + } + wait_428c(channel); + write32(DEFAULT_MCHBAR | 0x4220 | (channel << 10), 0x0001f006); + write32(DEFAULT_MCHBAR | 0x4230 | (channel << 10), 0x0028a004); + write32(DEFAULT_MCHBAR | 0x4200 | (channel << 10), + 0x00060000 | (slotrank << 24)); + write32(DEFAULT_MCHBAR | 0x4210 | (channel << 10), 0x00000244); + write32(DEFAULT_MCHBAR | 0x4224 | (channel << 10), 0x0001f201); + write32(DEFAULT_MCHBAR | 0x4234 | (channel << 10), 0x08281064); + write32(DEFAULT_MCHBAR | 0x4204 | (channel << 10), + 0x00000000 | (slotrank << 24)); + write32(DEFAULT_MCHBAR | 0x4214 | (channel << 10), 0x00000242); + write32(DEFAULT_MCHBAR | 0x4228 | (channel << 10), 0x0001f105); + write32(DEFAULT_MCHBAR | 0x4238 | (channel << 10), 0x04281064); + write32(DEFAULT_MCHBAR | 0x4208 | (channel << 10), + 0x00000000 | (slotrank << 24)); + write32(DEFAULT_MCHBAR | 0x4218 | (channel << 10), 0x00000242); + write32(DEFAULT_MCHBAR | 0x422c | (channel << 10), 0x0001f002); + write32(DEFAULT_MCHBAR | 0x423c | (channel << 10), 0x00280c01); + write32(DEFAULT_MCHBAR | 0x420c | (channel << 10), + 0x00060400 | (slotrank << 24)); + write32(DEFAULT_MCHBAR | 0x421c | (channel << 10), 0x00000240); + write32(DEFAULT_MCHBAR | 0x4284 | (channel << 10), 0x000c0001); + wait_428c(channel); + FOR_ALL_LANES + if (read32(DEFAULT_MCHBAR | 0x4340 | (channel << 10))) + die("Mini channel test failed (2)\n"); + } +} + +static void set_scrambling_seed(ramctr_timing * ctrl) +{ + int channel; + + /* FIXME: we hardcode seeds. Do we need to use some PRNG for them? + I don't think so. */ + static u32 seeds[NUM_CHANNELS][3] = { + {0x00009a36, 0xbafcfdcf, 0x46d1ab68}, + {0x00028bfa, 0x53fe4b49, 0x19ed5483} + }; + FOR_ALL_POPULATED_CHANNELS { + MCHBAR32(0x4020 + 0x400 * channel) &= ~0x10000000; + write32(DEFAULT_MCHBAR | 0x4034, seeds[channel][0]); + write32(DEFAULT_MCHBAR | 0x403c, seeds[channel][1]); + write32(DEFAULT_MCHBAR | 0x4038, seeds[channel][2]); + } +} + +static void set_4f8c(void) +{ + struct cpuid_result cpures; + u32 cpu; + + cpures = cpuid(0); + cpu = (cpures.eax); + if (IS_SANDY_CPU(cpu) && (IS_SANDY_CPU_D0(cpu) || IS_SANDY_CPU_D1(cpu))) { + MCHBAR32(0x4f8c) = 0x141D1519; + } else { + MCHBAR32(0x4f8c) = 0x551D1519; + } +} + +static void prepare_training(ramctr_timing * ctrl) +{ + int channel; + + FOR_ALL_POPULATED_CHANNELS { + // Always drive command bus + MCHBAR32(0x4004 + 0x400 * channel) |= 0x20000000; + } + + udelay(1); + + FOR_ALL_POPULATED_CHANNELS { + wait_428c(channel); + } +} + +static void set_4008c(ramctr_timing * ctrl) +{ + int channel, slotrank; + u32 reg; + FOR_ALL_POPULATED_CHANNELS { + u32 b20, b4_8_12; + int min_320c = 10000; + int max_320c = -10000; + + FOR_ALL_POPULATED_RANKS { + max_320c = max(ctrl->timings[channel][slotrank].val_320c, max_320c); + min_320c = min(ctrl->timings[channel][slotrank].val_320c, min_320c); + } + + if (max_320c - min_320c > 51) + b20 = 0; + else + b20 = ctrl->ref_card_offset[channel]; + + if (ctrl->reg_320c_range_threshold < max_320c - min_320c) + b4_8_12 = 0x3330; + else + b4_8_12 = 0x2220; + + reg = read32(DEFAULT_MCHBAR | 0x400c | (channel << 10)); + write32(DEFAULT_MCHBAR | 0x400c | (channel << 10), + (reg & 0xFFF0FFFF) + | (ctrl->ref_card_offset[channel] << 16) + | (ctrl->ref_card_offset[channel] << 18)); + write32(DEFAULT_MCHBAR | 0x4008 | (channel << 10), + 0x0a000000 + | (b20 << 20) + | ((ctrl->ref_card_offset[channel] + 2) << 16) + | b4_8_12); + } +} + +static void set_42a0(ramctr_timing * ctrl) +{ + int channel; + FOR_ALL_POPULATED_CHANNELS { + write32(DEFAULT_MCHBAR | (0x42a0 + 0x400 * channel), + 0x00001000 | ctrl->rankmap[channel]); + MCHBAR32(0x4004 + 0x400 * channel) &= ~0x20000000; // OK + } +} + +static int encode_5d10(int ns) +{ + return (ns + 499) / 500; +} + +/* FIXME: values in this function should be hardware revision-dependent. */ +static void final_registers(ramctr_timing * ctrl) +{ + int channel; + int t1_cycles = 0, t1_ns = 0, t2_ns; + int t3_ns; + u32 r32; + + write32(DEFAULT_MCHBAR | 0x4cd4, 0x00000046); + + write32(DEFAULT_MCHBAR | 0x400c, (read32(DEFAULT_MCHBAR | 0x400c) & 0xFFFFCFFF) | 0x1000); // OK + write32(DEFAULT_MCHBAR | 0x440c, (read32(DEFAULT_MCHBAR | 0x440c) & 0xFFFFCFFF) | 0x1000); // OK + write32(DEFAULT_MCHBAR | 0x4cb0, 0x00000740); + write32(DEFAULT_MCHBAR | 0x4380, 0x00000aaa); // OK + write32(DEFAULT_MCHBAR | 0x4780, 0x00000aaa); // OK + write32(DEFAULT_MCHBAR | 0x4f88, 0x5f7003ff); // OK + write32(DEFAULT_MCHBAR | 0x5064, 0x00073000 | ctrl->reg_5064b0); // OK + + FOR_ALL_CHANNELS { + switch (ctrl->rankmap[channel]) { + /* Unpopulated channel. */ + case 0: + write32(DEFAULT_MCHBAR + 0x4384 + channel * 0x400, 0); + break; + /* Only single-ranked dimms. */ + case 1: + case 4: + case 5: + write32(DEFAULT_MCHBAR + 0x4384 + channel * 0x400, 0x373131); + break; + /* Dual-ranked dimms present. */ + default: + write32(DEFAULT_MCHBAR + 0x4384 + channel * 0x400, 0x9b6ea1); + break; + } + } + + write32 (DEFAULT_MCHBAR | 0x5880, 0xca9171e5); + write32 (DEFAULT_MCHBAR | 0x5888, + (read32 (DEFAULT_MCHBAR | 0x5888) & ~0xffffff) | 0xe4d5d0); + write32 (DEFAULT_MCHBAR | 0x58a8, read32 (DEFAULT_MCHBAR | 0x58a8) & ~0x1f); + write32 (DEFAULT_MCHBAR | 0x4294, + (read32 (DEFAULT_MCHBAR | 0x4294) & ~0x30000) + | (1 << 16)); + write32 (DEFAULT_MCHBAR | 0x4694, + (read32 (DEFAULT_MCHBAR | 0x4694) & ~0x30000) + | (1 << 16)); + + MCHBAR32(0x5030) |= 1; // OK + MCHBAR32(0x5030) |= 0x80; // OK + MCHBAR32(0x5f18) = 0xfa; // OK + + /* Find a populated channel. */ + FOR_ALL_POPULATED_CHANNELS + break; + + t1_cycles = ((read32(DEFAULT_MCHBAR + 0x4290 + channel * 0x400) >> 8) & 0xff); + r32 = read32(DEFAULT_MCHBAR + 0x5064); + if (r32 & 0x20000) + t1_cycles += (r32 & 0xfff); + t1_cycles += (read32(DEFAULT_MCHBAR + channel * 0x400 + 0x42a4) & 0xfff); + t1_ns = t1_cycles * ctrl->tCK / 256 + 544; + if (!(r32 & 0x20000)) + t1_ns += 500; + + t2_ns = 10 * ((read32(DEFAULT_MCHBAR + 0x5f10) >> 8) & 0xfff); + if ( read32(DEFAULT_MCHBAR + 0x5f00) & 8 ) + { + t3_ns = 10 * ((read32(DEFAULT_MCHBAR + 0x5f20) >> 8) & 0xfff); + t3_ns += 10 * (read32(DEFAULT_MCHBAR + 0x5f18) & 0xff); + } + else + { + t3_ns = 500; + } + printk(BIOS_DEBUG, "t123: %d, %d, %d\n", + t1_ns, t2_ns, t3_ns); + write32 (DEFAULT_MCHBAR + 0x5d10, + ((encode_5d10(t1_ns) + encode_5d10(t2_ns)) << 16) + | (encode_5d10(t1_ns) << 8) + | ((encode_5d10(t3_ns) + encode_5d10(t2_ns) + encode_5d10(t1_ns)) << 24) + | (read32(DEFAULT_MCHBAR + 0x5d10) & 0xC0C0C0C0) + | 0xc); +} + +static void save_timings(ramctr_timing * ctrl) +{ + struct mrc_data_container *mrcdata; + int output_len = ALIGN(sizeof (*ctrl), 16); + + /* Save the MRC S3 restore data to cbmem */ + mrcdata = cbmem_add + (CBMEM_ID_MRCDATA, + output_len + sizeof(struct mrc_data_container)); + + printk(BIOS_DEBUG, "Relocate MRC DATA from %p to %p (%u bytes)\n", + ctrl, mrcdata, output_len); + + mrcdata->mrc_signature = MRC_DATA_SIGNATURE; + mrcdata->mrc_data_size = output_len; + mrcdata->reserved = 0; + memcpy(mrcdata->mrc_data, ctrl, sizeof (*ctrl)); + + /* Zero the unused space in aligned buffer. */ + if (output_len > sizeof (*ctrl)) + memset(mrcdata->mrc_data+sizeof (*ctrl), 0, + output_len - sizeof (*ctrl)); + + mrcdata->mrc_checksum = compute_ip_checksum(mrcdata->mrc_data, + mrcdata->mrc_data_size); +} + +static void restore_timings(ramctr_timing * ctrl) +{ + int channel, slotrank, lane; + + FOR_ALL_POPULATED_CHANNELS + MCHBAR32(0x4004 + 0x400 * channel) = + ctrl->tRRD + | (ctrl->tRTP << 4) + | (ctrl->tCKE << 8) + | (ctrl->tWTR << 12) + | (ctrl->tFAW << 16) + | (ctrl->tWR << 24) + | (ctrl->reg_4004_b30[channel] << 30); + + udelay(1); + + FOR_ALL_POPULATED_CHANNELS { + wait_428c(channel); + } + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + write32(DEFAULT_MCHBAR + 0x4080 + 0x400 * channel + + 4 * lane, 0); + } + + FOR_ALL_POPULATED_CHANNELS + write32(DEFAULT_MCHBAR + 0x4008 + 0x400 * channel, + read32(DEFAULT_MCHBAR + 0x4008 + + 0x400 * channel) | 0x8000000); + + FOR_ALL_POPULATED_CHANNELS { + udelay (1); + write32(DEFAULT_MCHBAR + 0x4020 + 0x400 * channel, + read32(DEFAULT_MCHBAR + 0x4020 + + 0x400 * channel) | 0x200000); + } + + printk(BIOS_SPEW, "CPE\n"); + + write32(DEFAULT_MCHBAR + 0x3400, 0); + write32(DEFAULT_MCHBAR + 0x4eb0, 0); + + printk(BIOS_SPEW, "CP5b\n"); + + FOR_ALL_POPULATED_CHANNELS { + program_timings(ctrl, channel); + } + + u32 reg, addr; + + while (!(MCHBAR32(0x5084) & 0x10000)) ; + do { + reg = MCHBAR32(0x428c); + } while ((reg & 0x14) == 0); + + // Set state of memory controller + MCHBAR32(0x5030) = 0x116; + MCHBAR32(0x4ea0) = 0; + + // Wait 500us + udelay(500); + + FOR_ALL_CHANNELS { + // Set valid rank CKE + reg = 0; + reg = (reg & ~0xf) | ctrl->rankmap[channel]; + addr = 0x400 * channel + 0x42a0; + MCHBAR32(addr) = reg; + + // Wait 10ns for ranks to settle + //udelay(0.01); + + reg = (reg & ~0xf0) | (ctrl->rankmap[channel] << 4); + MCHBAR32(addr) = reg; + + // Write reset using a NOP + write_reset(ctrl); + } + + /* mrs commands. */ + dram_mrscommands(ctrl); + + printk(BIOS_SPEW, "CP5c\n"); + + write32(DEFAULT_MCHBAR + 0x3000, 0); + + FOR_ALL_CHANNELS { + write32(DEFAULT_MCHBAR + (channel * 0x100) + 0xe3c, + 0 | (read32(DEFAULT_MCHBAR + (channel * 0x100) + 0xe3c) & + ~0x3f000000)); + udelay(2); + } + + write32(DEFAULT_MCHBAR + 0x4ea8, 0); +} + +void init_dram_ddr3(spd_raw_data * spds, int mobile, int min_tck, + int s3resume) +{ + int me_uma_size; + int cbmem_was_inited; + + MCHBAR32(0x5f00) |= 1; + + report_platform_info(); + + /* Wait for ME to be ready */ + intel_early_me_init(); + me_uma_size = intel_early_me_uma_size(); + + printk(BIOS_DEBUG, "Starting native Platform init\n"); + + u32 reg_5d10; + + wait_txt_clear(); + + wrmsr(0x000002e6, (msr_t) { .lo = 0, .hi = 0 }); + + reg_5d10 = read32(DEFAULT_MCHBAR | 0x5d10); // !!! = 0x00000000 + if ((pcie_read_config16(SOUTHBRIDGE, 0xa2) & 0xa0) == 0x20 /* 0x0004 */ + && reg_5d10 && !s3resume) { + write32(DEFAULT_MCHBAR | 0x5d10, 0); + /* Need reset. */ + outb(0x6, 0xcf9); + + hlt(); + } + + ramctr_timing ctrl; + + memset(&ctrl, 0, sizeof (ctrl)); + + early_pch_init_native(); + early_thermal_init(); + + ctrl.mobile = mobile; + ctrl.tCK = min_tck; + + /* FIXME: for non-S3 we should be able to use timing caching with + proper verification. Right now we use timings only for S3 case. + */ + if (s3resume) { + struct mrc_data_container *mrc_cache; + + mrc_cache = find_current_mrc_cache(); + if (!mrc_cache || mrc_cache->mrc_data_size < sizeof (ctrl)) { + /* Failed S3 resume, reset to come up cleanly */ + outb(0x6, 0xcf9); + hlt(); + } + memcpy(&ctrl, mrc_cache->mrc_data, sizeof (ctrl)); + } + + if (!s3resume) { + dimm_info info; + + /* Get DDR3 SPD data */ + dram_find_spds_ddr3(spds, &info, &ctrl); + + /* Find fastest common supported parameters */ + dram_find_common_params(&info, &ctrl); + + dram_dimm_mapping(&info, &ctrl); + } + + /* Set MCU frequency */ + dram_freq(&ctrl); + + if (!s3resume) { + /* Calculate timings */ + dram_timing(&ctrl); + } + + /* Set version register */ + MCHBAR32(0x5034) = 0xC04EB002; + + /* Enable crossover */ + dram_xover(&ctrl); + + /* Set timing and refresh registers */ + dram_timing_regs(&ctrl); + + /* Power mode preset */ + MCHBAR32(0x4e80) = 0x5500; + + /* Set scheduler parameters */ + MCHBAR32(0x4c20) = 0x10100005; + + /* Set cpu specific register */ + set_4f8c(); + + /* Clear IO reset bit */ + MCHBAR32(0x5030) &= ~0x20; + + /* Set MAD-DIMM registers */ + dram_dimm_set_mapping(&ctrl); + printk(BIOS_DEBUG, "Done dimm mapping\n"); + + /* Zone config */ + dram_zones(&ctrl, 1); + + /* Set memory map */ + dram_memorymap(&ctrl, me_uma_size); + printk(BIOS_DEBUG, "Done memory map\n"); + + /* Set IO registers */ + dram_ioregs(&ctrl); + printk(BIOS_DEBUG, "Done io registers\n"); + + udelay(1); + + if (s3resume) { + restore_timings(&ctrl); + } else { + /* Do jedec ddr3 reset sequence */ + dram_jedecreset(&ctrl); + printk(BIOS_DEBUG, "Done jedec reset\n"); + + /* MRS commands */ + dram_mrscommands(&ctrl); + printk(BIOS_DEBUG, "Done MRS commands\n"); + dram_mrscommands(&ctrl); + + /* Prepare for memory training */ + prepare_training(&ctrl); + + read_training(&ctrl); + write_training(&ctrl); + + printk(BIOS_SPEW, "CP5a\n"); + + discover_edges(&ctrl); + + printk(BIOS_SPEW, "CP5b\n"); + + command_training(&ctrl); + + printk(BIOS_SPEW, "CP5c\n"); + + discover_edges_write(&ctrl); + + discover_timC_write(&ctrl); + + normalize_training(&ctrl); + } + + set_4008c(&ctrl); + + write_controller_mr(&ctrl); + + if (!s3resume) { + channel_test(&ctrl); + } + + /* FIXME: should be hardware revision-dependent. */ + write32(DEFAULT_MCHBAR | 0x5024, 0x00a030ce); + + set_scrambling_seed(&ctrl); + + set_42a0(&ctrl); + + final_registers(&ctrl); + + /* Zone config */ + dram_zones(&ctrl, 0); + + if (!s3resume) + quick_ram_check(); + + intel_early_me_status(); + intel_early_me_init_done(ME_INIT_STATUS_SUCCESS); + intel_early_me_status(); + + post_system_agent_init(); + report_memory_config(); + + cbmem_was_inited = !cbmem_recovery(s3resume); + if (!s3resume) + save_timings(&ctrl); + if (s3resume && !cbmem_was_inited) { + /* Failed S3 resume, reset to come up cleanly */ + outb(0x6, 0xcf9); + hlt(); + } +} diff --git a/src/northbridge/intel/sandybridge/raminit_native.h b/src/northbridge/intel/sandybridge/raminit_native.h new file mode 100644 index 0000000..7ed75ff --- /dev/null +++ b/src/northbridge/intel/sandybridge/raminit_native.h @@ -0,0 +1,29 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2010 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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 + */ + +#ifndef RAMINIT_H +#define RAMINIT_H + +#include <device/dram/ddr3.h> + +/* The order is ch0dimmA, ch0dimmB, ch1dimmA, ch1dimmB. */ +void init_dram_ddr3(spd_raw_data *spds, int mobile, int min_tck, int s3resume); +void read_spd(spd_raw_data *spd, u8 addr); + +#endif /* RAMINIT_H */ diff --git a/src/northbridge/intel/sandybridge/raminit_patterns.h b/src/northbridge/intel/sandybridge/raminit_patterns.h new file mode 100644 index 0000000..61c67b4 --- /dev/null +++ b/src/northbridge/intel/sandybridge/raminit_patterns.h @@ -0,0 +1,639 @@ +const u32 pattern[][16] = { + {0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff}, + {0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000}, + {0xe62d6424, 0x9277e09e, 0x8f43dc3f, 0x76eae589, + 0x0010fdc6, 0xdc55e01c, 0x5effb0ab, 0x6cba5d29, + 0xa43d1e64, 0xab5c2e0f, 0x7796ed16, 0x96023bf4, + 0xa74c831d, 0x90f138c0, 0x17830a8a, 0x5ac17c47}, + {0x359ebbeb, 0x2b9b4512, 0xef584d98, 0x106bf7cb, + 0x363525ad, 0xb3a4dfdc, 0xa6b9fcd8, 0xd21689ec, + 0x84a3695b, 0xbd9c2e27, 0xdb3d0f44, 0x988158f1, + 0xcca91d3f, 0xb62a6d12, 0xe905e4cf, 0x7f1fa626}, + {0xe58efeae, 0xcd006081, 0xa9119403, 0xbcfbd35f, + 0x213b3bf7, 0x7bfcb773, 0xc85143f9, 0x0bdbff50, + 0xa3053c90, 0x51d66cb7, 0x296f4387, 0xb715f99e, + 0xfaddc989, 0xbb1de8a7, 0x39206b4d, 0x80174a57}, + {0xa1622ac1, 0xb4f4a5f0, 0x16dc2bc3, 0x50fb0954, + 0x2e261721, 0x52b82c3c, 0x821902b8, 0x0d4b6c38, + 0x1f618631, 0x047956f3, 0xd4337f5a, 0x591f8002, + 0x27f28db2, 0xfae37369, 0xb3f27580, 0x3cdb6397}, + {0x3dee23be, 0x19f36408, 0x227f4a6a, 0x024603c5, + 0xd5e062db, 0x6d8d4c5c, 0x7ff693b0, 0x76641be9, + 0x9e74f41c, 0xe7bc7f33, 0x2636f2e9, 0x70279750, + 0xce2355aa, 0x32d230ef, 0x22f9b468, 0xadd4e7a2}, + {0x936c0fed, 0xba0612d5, 0xa97c1ea7, 0x10e29d67, + 0x1c4c5dc8, 0x83645621, 0xcd8b521c, 0xb8301817, + 0xac7d6571, 0xcc41d200, 0x4ebdefdd, 0xd2917bde, + 0x60f75acc, 0x7791534b, 0x26ea2a83, 0x6b74513a}, + {0xd1957b85, 0xc6f8f9ca, 0xf04fb4be, 0xfeb786fb, + 0xa1dea3aa, 0x67fe7db6, 0x25d49c87, 0xe3d54870, + 0x93dc1f86, 0x7d0c1a18, 0x9272e128, 0x68e1b876, + 0xce284c9e, 0x8fa18792, 0x5785a340, 0xb6fcf198}, + {0xff7d8e4a, 0x0c21ee43, 0xe820b388, 0xb4443c0e, + 0xa1e6e498, 0x5c426110, 0x1b434ef3, 0xbef05b91, + 0xa6907968, 0x53662ac3, 0x6defac32, 0x2c11c29c, + 0x6175cced, 0xb17dd3ad, 0x6e6a1076, 0x1372b1fa}, + {0x4408ed06, 0x49460ffd, 0xb49d26cb, 0x6a3662a5, + 0x5e857047, 0xa387cd4a, 0x04edc81e, 0xfd94d8d4, + 0x2fe48d91, 0x9d2356bc, 0x96131878, 0xaca3fce4, + 0xbb312c6c, 0x5023b090, 0x3614be70, 0xa14dfabb}, + {0xd4cc1e83, 0x757a1930, 0xc3d16a61, 0x9e0d6681, + 0x8a081fa9, 0xbd11c888, 0x1672f010, 0xa083f71c, + 0x1ec02eef, 0xc4586ca8, 0x6d322b35, 0x56054679, + 0x1552a0ff, 0x5cb7707e, 0xdfb55d4a, 0xcc76cc07}, + {0x507cf71f, 0x2166421a, 0x54be4af0, 0xfd42158c, + 0x417b1f7f, 0x9466860b, 0x3a0075bf, 0x2055575c, + 0xcedfe7ab, 0xbe85aa5f, 0x39d0c2e3, 0x851c19df, + 0x39a35a3f, 0x3fb10d7d, 0x20b14899, 0x703b7f08}, + {0x8a7d9dd1, 0x33235565, 0xbd3d2e57, 0xa48c2726, + 0x0d5e2e13, 0xae421ff9, 0x8784a224, 0xf66c1510, + 0x057627aa, 0x8fb0cb41, 0x4289975a, 0xb181adfa, + 0x59f2059a, 0xe86feb05, 0x84222fc1, 0x319b3ce9}, + {0xe1e243b8, 0x3b0bcc1a, 0x70396f00, 0x5caff44d, + 0xe96961b3, 0xad73f692, 0x8b841a2d, 0xf5838839, + 0xec9c9d04, 0xcc2b5562, 0xf8ca2549, 0xa9c52ff8, + 0x3b2fde68, 0x3d4dc7f0, 0xa57387d0, 0x051199ad}, + {0x5f0ce4fc, 0xd830fbb7, 0x90abeb8f, 0x96d9cdbb, + 0x58f80a80, 0x0baaca36, 0x81a23623, 0x77127614, + 0xaa8382cd, 0x0922fbca, 0xd84d37e1, 0x721297df, + 0x160f3b3a, 0x10a1ecdc, 0x151c92f4, 0xc1fdcdab}, + {0x261c45cc, 0xfeddd2da, 0xfc3cb1c1, 0x6639641f, + 0x2c011892, 0x7108bee2, 0x8545e0b9, 0x7dd36dab, + 0x07d91950, 0x1520adcb, 0xf84aa939, 0x07d9bb2d, + 0xdf1ed826, 0xaee3c814, 0x1dca1e81, 0xc8e9f486}, + {0x933d306a, 0xaab7103d, 0xa8be37be, 0x49612f3a, + 0xb0cf28e5, 0xf9648902, 0x106d7c11, 0xf32e1813, + 0x21af36ef, 0xe695e4c4, 0x7ee1831d, 0x2aeda467, + 0x99d0c655, 0x3f0691ab, 0xcd68f7c1, 0xb469a20e}, + {0x8557aef0, 0x3eb0e373, 0x0853ac31, 0xe5bded62, + 0x3eddb0dd, 0x6bbf1caf, 0x2119c3d9, 0xe1732350, + 0x55456c75, 0xf6119375, 0x498dd1ad, 0x13f80916, + 0xb97f9f5e, 0x921d9f4c, 0xabdee367, 0x1d6bb8bf}, + {0xd165a3be, 0xd8b41598, 0xa20e1809, 0xefd5c8ce, + 0x18935c80, 0xdf1911f9, 0xc9e449eb, 0xb887a4d7, + 0x4a324f6f, 0x533e8031, 0x1c21c074, 0xa95f1ea5, + 0x765b320a, 0x839d7dfb, 0xc7d3aa93, 0xe534ae3d}, + {0xbe8592c8, 0x068457e6, 0x89b94fa3, 0xd522ad02, + 0x7e7db0b7, 0x2c5b896f, 0x9f8ecb37, 0x05b983ff, + 0x3fe9b25f, 0x34a6215b, 0x0592ba34, 0xd564f85a, + 0x156c426d, 0x25ad5460, 0xe7b5e8b7, 0xa73285c6}, + {0x5ad8d838, 0x27b42d36, 0xcc806ad1, 0x157a058a, + 0x7297735a, 0xffd6df8d, 0xff96f7a2, 0x155b27ea, + 0x84708101, 0x979fd78b, 0x49797d0c, 0x0dc93e3c, + 0x20287332, 0xed759f88, 0xe5068529, 0xb83aa781}, + {0xc38b302c, 0x57b54075, 0xac810692, 0xb0d493e7, + 0x4adda486, 0x0665ce2e, 0xb2a9c003, 0xafacc4ce, + 0x4d5e906d, 0xb3d52fab, 0xe6962c6b, 0x850f4dd1, + 0x5021656c, 0x5df6c06b, 0x9255125b, 0x2363c478}, + {0x188b715c, 0xe8b884b0, 0x5e6d0b9a, 0x1f0051e1, + 0xd2d35d4c, 0xbfeaecbe, 0xc84bb0ad, 0x67a232d6, + 0x99001587, 0xbf4313e1, 0x74f64061, 0x2c1fc562, + 0xb6fe8ca6, 0x5226a239, 0xf5198574, 0x61b51dca}, + {0x51dcecd3, 0xbadbe596, 0xebe3e84a, 0x772bfdfc, + 0x03656ac5, 0xa7c36e91, 0x6cd32cf0, 0xc3f699dd, + 0x7d5aba01, 0x51e38e82, 0x23103a98, 0x20298b9d, + 0x19436510, 0x63ad7e6c, 0x8bc2b33f, 0x27079917}, + {0x8bd5be78, 0xf2403bfa, 0x780ebdb6, 0x94c53b64, + 0x6241c2e2, 0x5bfb081e, 0x6799e88f, 0xc997b7d1, + 0x466ac8b1, 0xbf5909da, 0x497ea39f, 0x402ffb48, + 0xd7470c2d, 0x8510aba9, 0x6c52a1c9, 0x812ca967}, + {0x031f7ab4, 0xd32fe890, 0x36ae6de5, 0x083dcde4, + 0x99a7f12f, 0xe44864a7, 0x02b75fff, 0xf25dda35, + 0x7679ff4f, 0xed421e01, 0xd9c2cfa1, 0xd36b4e82, + 0x5315d908, 0xc7ebcb2a, 0xb6f3e4c1, 0xf5bfbae9}, + {0x3f4a2a96, 0x64d8bd5a, 0x19acd70d, 0xf62fcdd9, + 0x5de99cdf, 0x32f3b7cb, 0x2c020578, 0x4e9bafb8, + 0x74919a08, 0xaba33e91, 0xa6bd2254, 0x2435a9b9, + 0x47e2a1b4, 0xe837a28e, 0xe113f1b0, 0x7654bd79}, + {0x05537a6c, 0x77be1a5c, 0x4c7492c9, 0x9086bfb0, + 0x257adc18, 0xf4787fc1, 0xe3fb6d53, 0x9525e589, + 0x445a65bc, 0x833f7d08, 0x69cf1f7e, 0x9a6372e1, + 0xceedb52e, 0x31032997, 0xd1c36828, 0x132772d6}, + {0x0a166972, 0x89beaf3b, 0x8d780fbc, 0x8aea5392, + 0x58347a41, 0x1e381ec2, 0xcc6280c8, 0xee0863e1, + 0x976e2dd2, 0x8c6ee6e2, 0xa0ca57cd, 0x95114a7d, + 0x3c096704, 0xa941769d, 0x2de20c05, 0x0bf8f812}, + {0x22779d6c, 0x94e12e8f, 0x5ce40299, 0xea1b55b0, + 0x9ebec05d, 0xe076cd2b, 0x8fef5648, 0x6a284c65, + 0xa790b705, 0xf0b19997, 0x0d8ca8af, 0x17440419, + 0xef4f702f, 0x33cbcbb1, 0x83d60f26, 0x48988397}, + {0x0fed7f53, 0xb5acbb67, 0xc031c73f, 0x5364d9ef, + 0xa6dbd12d, 0x82174a6c, 0xccf8e7ab, 0xc473c036, + 0xcff493d8, 0xad9afc3b, 0x316a24e8, 0x1842bea4, + 0x4cc0c82e, 0x28ccd91e, 0xd7311b5d, 0x50a89860}, +}; + +static const u8 use_base[63][32] = { + { + 0x0e, 0x9e, 0xa1, 0x39, 0x06, 0x26, 0xc5, 0xe9, 0xed, 0x07, 0x49, 0x3b, 0x34, 0x7f, 0x1c, 0xa8, + 0xdf, 0x7b, 0xb7, 0xb8, 0x28, 0xbe, 0x8a, 0x70, 0x17, 0xe5, 0xc0, 0x44, 0x4a, 0x8e, 0x61, 0x3b, + }, + { + 0x42, 0xe6, 0xe0, 0x6a, 0xb3, 0x08, 0x28, 0xaf, 0xfa, 0xb9, 0xb7, 0x32, 0x83, 0x5c, 0xef, 0x3d, + 0x90, 0x91, 0x64, 0x31, 0xe9, 0x3c, 0x92, 0xe6, 0xa3, 0xd4, 0x6a, 0xc6, 0x01, 0xa6, 0xeb, 0xe6, + }, + { + 0x39, 0x7f, 0x6f, 0x81, 0xb4, 0x33, 0x4a, 0xde, 0x4f, 0x77, 0x28, 0x47, 0x08, 0xf9, 0x3a, 0x55, + 0x21, 0x57, 0x27, 0x59, 0xf5, 0x96, 0xad, 0xc1, 0x10, 0x33, 0xe0, 0xe2, 0xf8, 0xb6, 0x49, 0xbd, + }, + { + 0xdf, 0x57, 0x60, 0x27, 0x95, 0x50, 0x3a, 0x8c, 0x34, 0x8b, 0xae, 0xc5, 0x69, 0x26, 0xca, 0x39, + 0x55, 0x98, 0xfb, 0x05, 0x3c, 0x1c, 0x8d, 0xf8, 0xb9, 0x99, 0x05, 0x40, 0xe5, 0x5e, 0x2f, 0xf6, + }, + { + 0xc1, 0x6a, 0xea, 0xd6, 0x39, 0x56, 0x08, 0x89, 0x83, 0x4c, 0xef, 0xda, 0xb2, 0x69, 0x76, 0xe4, + 0x75, 0x3f, 0x39, 0x13, 0x96, 0xb5, 0x41, 0x84, 0x00, 0x64, 0x79, 0x47, 0xe4, 0xcb, 0xc3, 0xd0, + }, + { + 0xf8, 0xb1, 0x19, 0x76, 0x51, 0x99, 0xd7, 0x45, 0x38, 0x40, 0xbf, 0x10, 0x4c, 0x89, 0x43, 0xa9, + 0x89, 0xe2, 0x85, 0x3f, 0xb4, 0xe8, 0xbf, 0x5e, 0xc2, 0xb4, 0x16, 0x6d, 0x1c, 0x61, 0xca, 0x40, + }, + { + 0x1c, 0xdc, 0xa6, 0xdb, 0x71, 0x8b, 0xf9, 0xbb, 0xee, 0xc2, 0xa5, 0x66, 0xa4, 0xbc, 0xb6, 0x89, + 0x58, 0xb9, 0x6f, 0x57, 0x71, 0x57, 0x5c, 0xf0, 0xed, 0xcf, 0x2c, 0x2e, 0x1d, 0x34, 0xc3, 0x00, + }, + { + 0x1d, 0x30, 0x03, 0xb9, 0x15, 0x8e, 0x47, 0x8c, 0xf2, 0x4e, 0x2d, 0xf1, 0xbf, 0x96, 0xa7, 0xa1, + 0x3f, 0x26, 0xc3, 0xc9, 0x08, 0x0b, 0xa8, 0xdd, 0x9b, 0xeb, 0xbc, 0x77, 0x1c, 0x10, 0x03, 0x77, + }, + { + 0x50, 0x7e, 0x62, 0x26, 0xcb, 0x49, 0x7b, 0x1a, 0xd4, 0x54, 0xf1, 0x25, 0x3d, 0xa2, 0xe6, 0x8a, + 0xb3, 0x62, 0xf1, 0x7e, 0x03, 0xef, 0x1b, 0x27, 0x21, 0xcc, 0xfc, 0x72, 0x30, 0x0c, 0x69, 0xad, + }, + { + 0x11, 0xf5, 0xb2, 0xfa, 0x2d, 0xbc, 0xa1, 0xd9, 0x74, 0x15, 0x59, 0xf2, 0xc6, 0x66, 0x4f, 0xde, + 0x84, 0x82, 0x4f, 0xe8, 0x33, 0xd5, 0xc5, 0xdd, 0xba, 0x0c, 0xc7, 0x51, 0x1f, 0x3c, 0x6d, 0x44, + }, + { + 0xcf, 0xf5, 0x3b, 0xc1, 0xbd, 0x5f, 0x9c, 0xad, 0x57, 0xfb, 0xfc, 0xbe, 0x95, 0xa0, 0x48, 0x58, + 0x8a, 0x68, 0x97, 0x71, 0xf3, 0xc0, 0xd1, 0x31, 0x33, 0xb9, 0x3c, 0xe9, 0x4f, 0xbb, 0x8d, 0xeb, + }, + { + 0x29, 0x0c, 0xa1, 0xc8, 0x04, 0xdc, 0xf9, 0x25, 0x85, 0x7e, 0xea, 0x6d, 0x75, 0x28, 0x69, 0x3f, + 0x3a, 0x83, 0xe4, 0x33, 0x31, 0x77, 0x57, 0x2e, 0xa9, 0xa8, 0x05, 0xfe, 0x19, 0xb7, 0xc4, 0xd1, + }, + { + 0x6d, 0x5d, 0x3f, 0x4f, 0x8a, 0x6a, 0x77, 0x2d, 0xf7, 0x9f, 0x73, 0xab, 0x40, 0xd9, 0x89, 0x57, + 0x69, 0xd7, 0xc8, 0xc3, 0x69, 0x54, 0x93, 0x7c, 0x9f, 0x4a, 0xcc, 0xaf, 0xcc, 0x0e, 0xe0, 0xb8, + }, + { + 0xb6, 0xd5, 0x36, 0x3f, 0x1c, 0x34, 0x54, 0x9b, 0xfc, 0xec, 0x5b, 0xb0, 0x26, 0xa6, 0xc0, 0x61, + 0x6d, 0x4c, 0x4f, 0x86, 0x2a, 0xbd, 0x34, 0x35, 0x52, 0x2c, 0x82, 0x01, 0x66, 0x0e, 0x80, 0x01, + }, + { + 0x48, 0x39, 0x43, 0xb8, 0xf9, 0x2b, 0x25, 0xe8, 0xf7, 0xf0, 0x1a, 0xed, 0x33, 0x1e, 0x30, 0xba, + 0x15, 0x37, 0xeb, 0xae, 0x97, 0xa7, 0x36, 0xa4, 0xc7, 0x1f, 0x91, 0x01, 0x38, 0x80, 0x5a, 0x76, + }, + { + 0x74, 0xbe, 0x15, 0x6b, 0x85, 0x28, 0xe4, 0xc4, 0x13, 0x68, 0x67, 0x03, 0x27, 0x7e, 0x32, 0x08, + 0x87, 0x23, 0xda, 0xf2, 0x47, 0xdd, 0xac, 0x2c, 0xc5, 0x7f, 0x06, 0xc8, 0x17, 0x4c, 0x6c, 0x81, + }, + { + 0x0d, 0x9f, 0x68, 0xbb, 0xa6, 0x6c, 0x7d, 0x3f, 0x81, 0xcf, 0x9a, 0x52, 0x87, 0xce, 0x98, 0x25, + 0x40, 0x2b, 0x1b, 0xdf, 0xd3, 0x6b, 0x53, 0xed, 0x80, 0xd2, 0x3d, 0xca, 0xdf, 0x07, 0x4e, 0x6b, + }, + { + 0xff, 0xf1, 0xd2, 0x1f, 0xbd, 0xd6, 0xa7, 0x3d, 0xb4, 0xc6, 0x88, 0x9d, 0x7b, 0x05, 0x04, 0x0b, + 0x4c, 0x6f, 0x11, 0x7f, 0x19, 0x18, 0x48, 0xf1, 0x26, 0xad, 0xd0, 0x60, 0xfa, 0x40, 0x35, 0xbb, + }, + { + 0xae, 0xec, 0x0e, 0x2e, 0xfd, 0x46, 0xf0, 0x9c, 0x06, 0x1b, 0x62, 0xbf, 0xf0, 0x3e, 0xba, 0xdf, + 0xb2, 0xa2, 0x83, 0x83, 0xda, 0x04, 0x15, 0xec, 0x1e, 0x2e, 0x1a, 0x64, 0x08, 0x8e, 0xd3, 0x87, + }, + { + 0x61, 0x14, 0x05, 0x0b, 0xdb, 0xf4, 0xf0, 0xa3, 0x41, 0x11, 0x7b, 0xd9, 0xa1, 0x40, 0x4f, 0x62, + 0x98, 0x37, 0xa0, 0x90, 0x3d, 0x78, 0x63, 0x24, 0xbc, 0x8e, 0x9e, 0x99, 0x2e, 0xc7, 0xb1, 0x6d, + }, + { + 0x0f, 0xf1, 0x5f, 0xe4, 0x94, 0x3d, 0x24, 0x0d, 0xa2, 0xcf, 0xed, 0xbb, 0x55, 0x8e, 0xdb, 0x07, + 0x12, 0x05, 0x79, 0x82, 0xb1, 0x3a, 0x71, 0x76, 0xbb, 0x8b, 0xcb, 0xcc, 0x00, 0x40, 0x2e, 0xab, + }, + { + 0x48, 0x59, 0xfa, 0x46, 0x15, 0x5e, 0xa2, 0x0d, 0xe8, 0x81, 0x69, 0xe6, 0x2f, 0x5f, 0x6d, 0xaf, + 0xad, 0xc7, 0x30, 0xd6, 0xec, 0x03, 0x1e, 0x19, 0xdd, 0x1d, 0x00, 0x94, 0x0b, 0x93, 0x5a, 0x28, + }, + { + 0xfa, 0x64, 0x62, 0x57, 0x02, 0x7e, 0x37, 0xb8, 0x10, 0xa9, 0x4b, 0xe7, 0xbf, 0x03, 0xdc, 0x1c, + 0xe7, 0x21, 0x68, 0x60, 0x53, 0xec, 0xf0, 0xfc, 0xbf, 0xe5, 0x8e, 0xca, 0x77, 0xdb, 0xa5, 0xae, + }, + { + 0xc1, 0xa9, 0x9f, 0xc2, 0x87, 0x11, 0xad, 0x1c, 0xc5, 0x56, 0x61, 0xc0, 0x20, 0x33, 0xc9, 0x85, + 0xf0, 0x81, 0x36, 0x18, 0xdb, 0xaa, 0x7e, 0x79, 0x36, 0x2d, 0xfc, 0x8f, 0x72, 0x3c, 0x4c, 0xa3, + }, + { + 0xb4, 0xd3, 0x38, 0xed, 0xd3, 0x6c, 0x03, 0x26, 0x0e, 0x1c, 0x8a, 0xa8, 0x72, 0x17, 0xcb, 0xf7, + 0x87, 0xf3, 0x3f, 0x73, 0x5d, 0x12, 0xe8, 0x3b, 0x55, 0xb6, 0xcc, 0xc6, 0x85, 0xad, 0x9f, 0x9e, + }, + { + 0xe9, 0x97, 0xde, 0x7f, 0xe0, 0x9a, 0xc1, 0xdc, 0x96, 0x4c, 0xc3, 0x0d, 0x2d, 0xd4, 0x98, 0x54, + 0x89, 0x1c, 0x57, 0x7d, 0x17, 0x96, 0xe9, 0x2f, 0x02, 0x73, 0x07, 0x5c, 0x8b, 0x44, 0xd7, 0x75, + }, + { + 0xaf, 0xf2, 0x39, 0xc4, 0x23, 0xff, 0xd5, 0x85, 0xf3, 0x11, 0x44, 0x9e, 0xab, 0x59, 0x29, 0x33, + 0xe6, 0xc2, 0x1d, 0xba, 0xa8, 0x5b, 0x70, 0xc3, 0xc0, 0xf8, 0x56, 0x3b, 0x8e, 0x43, 0x4c, 0x4b, + }, + { + 0x46, 0x93, 0xb5, 0x8a, 0x71, 0x67, 0xcb, 0x42, 0x6b, 0x1b, 0x43, 0x58, 0x8b, 0x18, 0xb9, 0xf3, + 0xdc, 0x91, 0x1c, 0x08, 0x83, 0xe3, 0x63, 0xfa, 0xf9, 0x99, 0x99, 0xcb, 0x05, 0x15, 0x7b, 0x85, + }, + { + 0xcf, 0xc6, 0x3c, 0x01, 0xbd, 0xfb, 0x00, 0x8c, 0x8b, 0x07, 0x69, 0xac, 0x61, 0xdb, 0x30, 0xd5, + 0x7c, 0x71, 0x98, 0x69, 0x2e, 0x4a, 0x4a, 0x44, 0xe4, 0x72, 0x6f, 0xf2, 0x9d, 0x58, 0x02, 0x23, + }, + { + 0x29, 0x10, 0xe1, 0xe5, 0x3f, 0xe6, 0x26, 0xaf, 0x30, 0x3c, 0xfe, 0x1f, 0x97, 0x21, 0xdd, 0x8c, + 0xbb, 0x90, 0xdb, 0x2a, 0xb5, 0xb4, 0x46, 0x43, 0x50, 0x0b, 0x6b, 0xa8, 0x8f, 0x55, 0xfb, 0xd2, + }, + { + 0x89, 0x56, 0x19, 0xf9, 0x4a, 0xec, 0x38, 0x99, 0xaa, 0xcc, 0xc5, 0x15, 0xdf, 0x19, 0xee, 0x1a, + 0xc0, 0x94, 0xaf, 0x0f, 0x7b, 0xf4, 0x06, 0xf1, 0x70, 0xa3, 0x79, 0x06, 0xba, 0x4e, 0x09, 0xa6, + }, + { + 0x53, 0x3a, 0x35, 0x98, 0xa9, 0xcb, 0x2c, 0x72, 0x73, 0xb2, 0xb0, 0x63, 0x38, 0xfc, 0xa3, 0xa5, + 0xa3, 0xf1, 0x4d, 0x04, 0x2f, 0x1b, 0x83, 0xbd, 0xed, 0x20, 0x8e, 0xa5, 0x1e, 0x9d, 0xd6, 0x69, + }, + { + 0x78, 0x44, 0xe3, 0x22, 0xa4, 0x7c, 0x53, 0xef, 0x60, 0x8e, 0x39, 0x95, 0x7d, 0x9d, 0x3d, 0x0b, + 0x4a, 0x4f, 0xf4, 0x73, 0xf8, 0xfe, 0xe7, 0x65, 0x86, 0x72, 0x13, 0x0b, 0x4e, 0x8f, 0x4d, 0x7b, + }, + { + 0x46, 0xba, 0xd2, 0x82, 0x46, 0x18, 0x6e, 0x46, 0x96, 0x05, 0x1d, 0xfb, 0xf6, 0xde, 0xba, 0xb5, + 0x6b, 0x73, 0x7a, 0xd5, 0x76, 0x11, 0xb7, 0x7c, 0x0d, 0x61, 0xba, 0xf9, 0x05, 0x12, 0x2b, 0x4e, + }, + { + 0x41, 0x08, 0x8b, 0x63, 0x10, 0xeb, 0x85, 0x10, 0xf3, 0x05, 0x84, 0xc0, 0x81, 0x1f, 0x7f, 0xd3, + 0x9d, 0x01, 0xdc, 0x32, 0xd0, 0xe2, 0xd1, 0xd1, 0x41, 0x8a, 0xa0, 0xf2, 0x64, 0xda, 0x8b, 0x0e, + }, + { + 0x99, 0xf1, 0xf2, 0x88, 0xe8, 0x72, 0x8b, 0x40, 0x17, 0xcc, 0xa7, 0x4c, 0x7d, 0xf1, 0xc4, 0x3f, + 0xbf, 0xf8, 0xbe, 0xc9, 0xce, 0xce, 0x2b, 0xe9, 0x4d, 0x5b, 0xd1, 0xef, 0x76, 0xae, 0x3b, 0xbb, + }, + { + 0x64, 0x69, 0x47, 0x03, 0xe9, 0x3b, 0xc2, 0x2d, 0x2d, 0x1a, 0xdd, 0xa4, 0xac, 0xb6, 0x6e, 0x7a, + 0x41, 0x7d, 0x82, 0xed, 0x54, 0xf7, 0x05, 0xd8, 0xae, 0x07, 0x6c, 0x1c, 0xf6, 0x51, 0xa1, 0xc0, + }, + { + 0x84, 0xaf, 0xe8, 0x59, 0x0c, 0x14, 0x24, 0xec, 0xa0, 0xd2, 0xf3, 0x8f, 0x2f, 0x22, 0xe4, 0x52, + 0xf8, 0xa7, 0x39, 0x74, 0x7f, 0x80, 0x23, 0x3f, 0x30, 0xe3, 0xcb, 0x26, 0x12, 0x5c, 0xa7, 0x93, + }, + { + 0x48, 0xc8, 0x41, 0x42, 0xc5, 0xe7, 0x4d, 0x91, 0x54, 0xa6, 0x5b, 0xba, 0x46, 0x89, 0xd5, 0x42, + 0x46, 0xbc, 0xf2, 0x67, 0x4a, 0xf9, 0x88, 0xe9, 0x02, 0xa5, 0xc2, 0x38, 0x9d, 0x6a, 0x75, 0xcd, + }, + { + 0xab, 0x9b, 0x2c, 0x09, 0xda, 0xaa, 0xe9, 0xe2, 0xd7, 0xf1, 0xa4, 0x86, 0x41, 0x14, 0xcb, 0x4e, + 0x2b, 0xd1, 0x5a, 0x9a, 0x46, 0x47, 0x90, 0xb2, 0x63, 0x16, 0xcb, 0x60, 0x1c, 0x12, 0xe3, 0x2b, + }, + { + 0x54, 0x21, 0xc0, 0xbc, 0xb8, 0x29, 0xce, 0xa4, 0xf2, 0x38, 0xb4, 0x0d, 0x7d, 0xfa, 0xd4, 0x3e, + 0x28, 0xf4, 0xc4, 0xf4, 0x4a, 0x9f, 0x11, 0xf2, 0xe2, 0x31, 0xa3, 0x72, 0x16, 0xbb, 0xd9, 0x05, + }, + { + 0xdc, 0x6e, 0xbe, 0x64, 0xa2, 0xb2, 0x64, 0x46, 0x00, 0xee, 0xd2, 0xa5, 0x81, 0x86, 0x44, 0xa4, + 0x5c, 0xc4, 0xba, 0xc4, 0xa2, 0x44, 0x36, 0x77, 0xb2, 0xec, 0x0d, 0xbe, 0x8f, 0xc0, 0x80, 0x6f, + }, + { + 0x51, 0x51, 0xb2, 0x50, 0x11, 0x0b, 0x60, 0xb8, 0x8e, 0xc2, 0xf7, 0xa8, 0xb4, 0xd2, 0x48, 0xc3, + 0x51, 0x43, 0x52, 0xeb, 0x37, 0xac, 0xd0, 0xf7, 0x61, 0xa1, 0xe9, 0xe3, 0xa7, 0xdf, 0x26, 0xa9, + }, + { + 0x10, 0xd9, 0xf2, 0xfe, 0x71, 0x8e, 0x49, 0x2c, 0x64, 0x53, 0xb0, 0x9e, 0x7a, 0xcc, 0x86, 0xab, + 0x06, 0xd7, 0xc7, 0x13, 0xd1, 0xcb, 0x21, 0x42, 0x97, 0x29, 0x5d, 0xff, 0xaa, 0xec, 0x52, 0x40, + }, + { + 0x7b, 0x35, 0x93, 0xb9, 0xca, 0xbb, 0x7e, 0x09, 0x8f, 0x34, 0x32, 0x02, 0xe7, 0x0c, 0xcf, 0xd1, + 0x6c, 0x2d, 0x11, 0xcd, 0xa5, 0x3b, 0xba, 0x14, 0x47, 0xc5, 0x2c, 0xb8, 0xf6, 0xfb, 0x9d, 0x77, + }, + { + 0x45, 0xce, 0x12, 0x8e, 0xa2, 0x4e, 0x56, 0x58, 0xa7, 0xcf, 0x26, 0x4e, 0x32, 0x21, 0xe0, 0x2b, + 0xed, 0x8d, 0xe2, 0xd9, 0x51, 0x32, 0x9b, 0xdc, 0x7b, 0x0e, 0x14, 0x0a, 0xdb, 0x63, 0x6b, 0x42, + }, + { + 0x9d, 0x49, 0x72, 0xea, 0x89, 0xc7, 0xa2, 0xfd, 0x9a, 0x55, 0xd7, 0x05, 0x16, 0xeb, 0xf7, 0x49, + 0xb6, 0xcf, 0x56, 0xf7, 0x2b, 0xef, 0x6d, 0xbe, 0xdd, 0x0e, 0x90, 0x01, 0xaf, 0x1b, 0xbb, 0xaa, + }, + { + 0x2c, 0xb7, 0x26, 0x43, 0x02, 0xc5, 0x7b, 0xc6, 0x71, 0x1f, 0xf2, 0x28, 0xb4, 0xea, 0x5f, 0x02, + 0xc6, 0xeb, 0xb4, 0xf7, 0x6f, 0x01, 0x7f, 0xfe, 0x3a, 0xb0, 0xe3, 0xf3, 0x31, 0xd3, 0xcb, 0x0f, + }, + { + 0x75, 0x54, 0x90, 0xec, 0xed, 0xcc, 0xbc, 0x5c, 0x9b, 0x44, 0x30, 0x57, 0x57, 0xe0, 0xec, 0x58, + 0x20, 0x54, 0x20, 0xb0, 0x92, 0x3a, 0x06, 0x9f, 0x69, 0xcb, 0x88, 0xee, 0x52, 0x6e, 0x4c, 0xf6, + }, + { + 0x2a, 0x08, 0xd8, 0xdd, 0x2e, 0x07, 0x54, 0x0b, 0x37, 0xc6, 0x09, 0x26, 0x98, 0xf7, 0x45, 0xf6, + 0x05, 0x4f, 0x35, 0xe6, 0xb0, 0x44, 0xff, 0x62, 0x89, 0x47, 0x69, 0x30, 0xea, 0x3b, 0x7b, 0x81, + }, + { + 0x0f, 0x7f, 0x34, 0xbf, 0xf9, 0xce, 0xe7, 0x4c, 0xe1, 0x7a, 0x24, 0x74, 0xeb, 0x8b, 0xb0, 0x65, + 0x18, 0x19, 0xaf, 0x44, 0x45, 0x5e, 0xd9, 0xa4, 0xf0, 0xd8, 0xe8, 0x09, 0x22, 0x58, 0x4e, 0x4d, + }, + { + 0x48, 0x41, 0x7a, 0xd2, 0x26, 0xda, 0x39, 0xb2, 0xba, 0x03, 0x17, 0xe9, 0x80, 0x8e, 0x53, 0x4c, + 0xac, 0x64, 0x6b, 0xa7, 0x5f, 0xed, 0x64, 0x60, 0xb7, 0x5e, 0x7a, 0x68, 0x1a, 0x8a, 0xda, 0x2b, + }, + { + 0x52, 0x01, 0x25, 0xb0, 0x59, 0xcf, 0x61, 0x30, 0x52, 0xe7, 0x77, 0x66, 0xc9, 0x35, 0xac, 0xfe, + 0xc0, 0xa2, 0x18, 0x58, 0xf1, 0xc1, 0x8f, 0x28, 0x72, 0x2f, 0xdc, 0x36, 0x10, 0x5b, 0xd9, 0x6f, + }, + { + 0x05, 0xbf, 0x47, 0x32, 0x0e, 0xa7, 0xc6, 0xd6, 0x13, 0xa1, 0x72, 0x38, 0x8c, 0x1a, 0xbc, 0x6d, + 0x7c, 0xd8, 0x34, 0xac, 0x69, 0x5b, 0x43, 0xc4, 0x00, 0xf8, 0xf2, 0xa7, 0xaf, 0x9f, 0xb0, 0xde, + }, + { + 0x54, 0x67, 0xce, 0xf2, 0xfc, 0x91, 0xd2, 0x4d, 0x73, 0xc6, 0xc9, 0xc3, 0xfe, 0xcf, 0x72, 0xa0, + 0xc7, 0x43, 0xff, 0x87, 0x4b, 0xe3, 0x7f, 0xba, 0xd4, 0xa2, 0xa3, 0x14, 0x8f, 0xa0, 0x39, 0x91, + }, + { + 0xbd, 0x24, 0x35, 0xb5, 0x0e, 0x7a, 0x13, 0xb3, 0x92, 0x83, 0xaa, 0xbd, 0x0c, 0x22, 0x93, 0xbb, + 0x2a, 0xe7, 0x7a, 0x56, 0x2d, 0xae, 0x41, 0x62, 0x52, 0xb2, 0xe9, 0xbd, 0x29, 0x05, 0x51, 0x95, + }, + { + 0x97, 0x8f, 0x21, 0x82, 0x72, 0x4f, 0x65, 0xc8, 0xfc, 0x2e, 0x5e, 0x8a, 0x1a, 0xce, 0x34, 0x39, + 0x12, 0xe6, 0x9b, 0xc3, 0xab, 0x51, 0xa9, 0x40, 0xf7, 0xbe, 0x94, 0xd0, 0x66, 0xda, 0xa5, 0x39, + }, + { + 0x5a, 0x48, 0x43, 0x9a, 0x8e, 0x22, 0x85, 0x9b, 0x28, 0xc9, 0x63, 0xa2, 0x57, 0xa6, 0xe2, 0x16, + 0x64, 0xec, 0x3c, 0x59, 0x13, 0xc4, 0x7b, 0x51, 0xea, 0xfe, 0x2e, 0x70, 0xbd, 0xd9, 0x77, 0x85, + }, + { + 0x2b, 0x74, 0xb6, 0x95, 0x18, 0x94, 0x54, 0x6d, 0xae, 0xdd, 0xe9, 0xb2, 0xf9, 0xbd, 0xce, 0x27, + 0xa9, 0x87, 0x42, 0x13, 0x22, 0x29, 0x87, 0x7a, 0x04, 0xe3, 0xbe, 0x2f, 0x9c, 0x18, 0xbb, 0x13, + }, + { + 0x80, 0x95, 0x43, 0xaa, 0x19, 0x90, 0x03, 0x4f, 0x47, 0xbf, 0xf5, 0x8e, 0x2d, 0x55, 0x23, 0xb7, + 0x7b, 0x5d, 0xaa, 0x34, 0x37, 0xb2, 0x70, 0x86, 0x5e, 0xc4, 0x94, 0xf3, 0x61, 0xfd, 0x87, 0x65, + }, + { + 0xd4, 0xbc, 0x03, 0x65, 0xb0, 0xc5, 0x44, 0x81, 0x7b, 0x06, 0x94, 0x79, 0xca, 0x1f, 0xe2, 0x28, + 0x53, 0xc8, 0xa7, 0x10, 0x13, 0x77, 0xb7, 0x5c, 0x9a, 0x34, 0x1e, 0xd5, 0x78, 0xb1, 0x21, 0x61, + }, + { + 0x90, 0x0e, 0x7f, 0xa3, 0x24, 0x18, 0x12, 0xbf, 0x45, 0xd2, 0x52, 0xa3, 0x99, 0x74, 0x89, 0xd2, + 0x12, 0x8d, 0x32, 0x3c, 0xd0, 0x28, 0x54, 0x98, 0x6c, 0x9e, 0xdd, 0xc0, 0xd5, 0xf1, 0x8a, 0xb1, + }, + { + 0x82, 0xad, 0x7a, 0x5c, 0x4d, 0x81, 0x54, 0x41, 0x79, 0x42, 0x54, 0x5c, 0x49, 0x41, 0xed, 0x49, + 0xc7, 0x06, 0x61, 0xbb, 0x89, 0x2b, 0x90, 0x04, 0x1f, 0x8c, 0x31, 0x3b, 0x39, 0x4f, 0xf8, 0x33, + }, +}; +static const u8 invert[63][32] = { + { + 0x95, 0xb2, 0xa8, 0xe3, 0xac, 0xcf, 0x27, 0x3e, 0x1c, 0xa3, 0xcf, 0x7a, 0x20, 0xb4, 0x52, 0x83, + 0x0e, 0x21, 0x2d, 0xfe, 0x6f, 0x2e, 0x38, 0x13, 0x01, 0x2e, 0xa0, 0x58, 0x58, 0x6d, 0x4a, 0x6f, + }, + { + 0x63, 0x26, 0x5c, 0xd2, 0x9a, 0xc6, 0x8c, 0x5d, 0xc2, 0x0d, 0xba, 0x4f, 0x79, 0x88, 0xd1, 0x15, + 0x64, 0x55, 0x90, 0x7b, 0x76, 0x2d, 0x60, 0x04, 0x92, 0x77, 0x18, 0xd0, 0xba, 0x7f, 0xee, 0x3a, + }, + { + 0x57, 0xc1, 0x0b, 0x23, 0x06, 0x57, 0x0c, 0xde, 0xa1, 0xa5, 0x8d, 0xc6, 0x8e, 0xbd, 0x9e, 0x09, + 0xe5, 0xed, 0xe3, 0xfb, 0xb1, 0xa0, 0xda, 0x73, 0xfc, 0x3e, 0x5e, 0x6d, 0x38, 0x36, 0x26, 0xec, + }, + { + 0x8e, 0xe5, 0x30, 0x36, 0x9e, 0x30, 0x82, 0x02, 0xf6, 0x7c, 0x06, 0x71, 0xbb, 0x6e, 0x09, 0x68, + 0x16, 0xca, 0x10, 0x32, 0x90, 0xcc, 0x7a, 0x99, 0x18, 0x70, 0xe6, 0xe7, 0x3a, 0x78, 0x86, 0xe6, + }, + { + 0x18, 0x98, 0x14, 0xa7, 0xb7, 0x1f, 0x24, 0xed, 0xd0, 0xfc, 0x71, 0xa0, 0x7e, 0xef, 0xdd, 0xe2, + 0xa2, 0xf8, 0x2a, 0xc2, 0x5d, 0x94, 0x03, 0x13, 0x29, 0x39, 0x86, 0xed, 0x08, 0x99, 0x83, 0xab, + }, + { + 0xcd, 0x22, 0xa0, 0xbc, 0xea, 0xe7, 0xde, 0xca, 0x0c, 0x72, 0xbd, 0xf7, 0x40, 0x46, 0x92, 0xc5, + 0xa4, 0xf3, 0x48, 0x9a, 0x8f, 0x52, 0xab, 0x19, 0x07, 0x98, 0xae, 0x9b, 0xe7, 0xfc, 0xbd, 0x05, + }, + { + 0xd2, 0xce, 0x28, 0x79, 0x3f, 0xdd, 0xa1, 0x1c, 0x21, 0xe4, 0xeb, 0x54, 0x85, 0x5c, 0x9d, 0x64, + 0xd5, 0x5b, 0xb6, 0x06, 0x43, 0xcc, 0x80, 0x8b, 0xe3, 0xdb, 0x26, 0xf5, 0x7e, 0x5f, 0x81, 0x9d, + }, + { + 0x54, 0x42, 0xe9, 0x30, 0xd2, 0x2c, 0xba, 0x16, 0xa7, 0x99, 0x28, 0xe7, 0x54, 0x61, 0xee, 0x17, + 0xf0, 0x70, 0x34, 0xe2, 0xe7, 0x66, 0x16, 0x00, 0x95, 0x7b, 0xbd, 0xd8, 0x07, 0xab, 0xa9, 0x5b, + }, + { + 0xe7, 0x58, 0x21, 0x24, 0x0e, 0x32, 0xbd, 0x6b, 0xcb, 0xa6, 0xd9, 0x91, 0xd7, 0xfd, 0xe4, 0x4c, + 0x58, 0xd6, 0x06, 0x11, 0x02, 0x90, 0xe5, 0x1d, 0x91, 0x2f, 0x0f, 0x43, 0xe3, 0xc7, 0x66, 0xd8, + }, + { + 0x45, 0x65, 0x5e, 0x17, 0xe1, 0x00, 0xfd, 0x42, 0x30, 0x25, 0x0e, 0xa5, 0x26, 0x8a, 0x17, 0xfe, + 0xd0, 0xa2, 0xff, 0x7a, 0x09, 0xd3, 0x5a, 0xb4, 0x71, 0x84, 0x29, 0x03, 0x71, 0x70, 0x9b, 0x6e, + }, + { + 0xc7, 0x2d, 0xe6, 0xef, 0xba, 0x0b, 0x97, 0x9a, 0x91, 0xf2, 0xda, 0x26, 0x62, 0xe5, 0xbe, 0x5d, + 0xc5, 0x5d, 0x71, 0xc1, 0xb7, 0x3f, 0xb3, 0xb8, 0x74, 0xd0, 0x0c, 0x03, 0x74, 0xc0, 0x0c, 0xe4, + }, + { + 0x56, 0x38, 0x1e, 0x31, 0xca, 0x3b, 0xb5, 0xc4, 0xff, 0x5a, 0x9e, 0x86, 0xfe, 0x98, 0x0c, 0x27, + 0x23, 0x2c, 0xa0, 0x76, 0x6f, 0xae, 0xf3, 0xde, 0x71, 0x40, 0x0c, 0xdc, 0x41, 0xf9, 0x89, 0x99, + }, + { + 0x2c, 0x27, 0xed, 0x69, 0x50, 0x53, 0xc5, 0x97, 0xf4, 0x88, 0x9a, 0x2b, 0xce, 0x8a, 0xc5, 0xfb, + 0x0d, 0xbc, 0x6f, 0x9c, 0x84, 0x30, 0xf3, 0xcb, 0xc1, 0x30, 0xa4, 0xb5, 0x46, 0xd4, 0xcb, 0xea, + }, + { + 0xb7, 0xf0, 0x86, 0x66, 0xd3, 0x55, 0x64, 0xc9, 0x1b, 0x9b, 0x3d, 0x79, 0x13, 0x0a, 0x3e, 0xa1, + 0xcf, 0x54, 0x17, 0x77, 0xeb, 0x32, 0x1c, 0x47, 0x7d, 0xf0, 0xb4, 0x11, 0x3d, 0xd7, 0xef, 0x04, + }, + { + 0xf7, 0x7e, 0x71, 0xb6, 0x5e, 0xed, 0xf3, 0xfb, 0x56, 0x82, 0x22, 0x61, 0x29, 0xa2, 0x5d, 0xc6, + 0xcd, 0x03, 0x47, 0xc7, 0xcc, 0xe4, 0xf2, 0xa4, 0x3f, 0xed, 0x36, 0xae, 0xa7, 0x30, 0x84, 0x22, + }, + { + 0x13, 0x70, 0xe7, 0x97, 0x14, 0xfa, 0xa9, 0xb7, 0xd5, 0xa1, 0xa4, 0xfd, 0xe8, 0x0c, 0x92, 0xcf, + 0xc4, 0xdc, 0x5d, 0xb9, 0xa4, 0xa2, 0x16, 0xf8, 0x67, 0xdc, 0x12, 0x47, 0xb7, 0x75, 0xfd, 0x3c, + }, + { + 0x29, 0xaa, 0xdd, 0xb5, 0xdc, 0x7f, 0xce, 0xad, 0x02, 0x65, 0x27, 0x5e, 0xa5, 0x5d, 0x23, 0x0f, + 0xa7, 0x51, 0x4d, 0xf2, 0x7d, 0x2a, 0x31, 0xbf, 0x32, 0x3b, 0x80, 0xe3, 0xda, 0x56, 0xdb, 0xfc, + }, + { + 0x70, 0xd0, 0x50, 0x6d, 0xf2, 0xb3, 0x6f, 0xc1, 0x9a, 0x98, 0x02, 0x87, 0xb5, 0x31, 0x3d, 0x19, + 0xaa, 0xf4, 0xd2, 0xd4, 0x48, 0xb1, 0x08, 0x06, 0x98, 0x39, 0x00, 0x06, 0x20, 0xe5, 0x0c, 0xe1, + }, + { + 0xe6, 0xaf, 0x94, 0xa0, 0xdf, 0xc3, 0x6b, 0xb4, 0xcf, 0x78, 0xc0, 0xe8, 0x56, 0xdc, 0xac, 0xbb, + 0x5e, 0x9e, 0xda, 0x90, 0x1e, 0x7f, 0x44, 0x06, 0xe0, 0x00, 0x6a, 0xd9, 0xd1, 0xf9, 0x56, 0xac, + }, + { + 0x15, 0xa2, 0x90, 0x13, 0x4f, 0xa0, 0x9d, 0x0d, 0x9c, 0xf8, 0xc9, 0x20, 0x1c, 0x8e, 0x68, 0xcb, + 0x1f, 0x75, 0xb3, 0xb2, 0x14, 0xff, 0x19, 0x20, 0x5f, 0x30, 0xb1, 0x05, 0x36, 0x7c, 0xa2, 0xed, + }, + { + 0x9a, 0xb2, 0xf5, 0xfd, 0x04, 0x3e, 0x6b, 0x4a, 0x1d, 0x3a, 0x63, 0x96, 0x00, 0xad, 0x6c, 0x7c, + 0x4f, 0xaf, 0x4d, 0xb5, 0x03, 0x4a, 0xf7, 0x28, 0x7f, 0x1f, 0x38, 0xad, 0xfd, 0xc7, 0x4b, 0x7f, + }, + { + 0xf4, 0x5a, 0x9f, 0xf6, 0xd0, 0x1a, 0x23, 0x76, 0xee, 0x15, 0x10, 0x2c, 0x30, 0xbd, 0x45, 0xfc, + 0x65, 0x60, 0x20, 0xc5, 0x9b, 0xb4, 0x42, 0x83, 0xe9, 0x03, 0xd5, 0xec, 0xba, 0xb2, 0x3b, 0xb8, + }, + { + 0xf4, 0x1b, 0xc1, 0x73, 0x1a, 0x6c, 0x88, 0xfd, 0xc2, 0xfb, 0xe8, 0x7e, 0xcb, 0x8a, 0x0e, 0x0e, + 0x6a, 0x13, 0x54, 0xb0, 0x7b, 0xb8, 0x68, 0x90, 0x21, 0x38, 0x4e, 0x1f, 0x86, 0x51, 0x14, 0x2c, + }, + { + 0x6c, 0xd3, 0xc3, 0x8f, 0x06, 0x45, 0xec, 0x65, 0x87, 0x02, 0x3d, 0x89, 0x61, 0xde, 0x80, 0x42, + 0xf6, 0xe0, 0x8d, 0x91, 0xf0, 0x3a, 0x7a, 0x66, 0xba, 0x1c, 0xc7, 0xb6, 0x3d, 0xc4, 0x7f, 0x91, + }, + { + 0x53, 0xf6, 0x90, 0x34, 0x88, 0x3e, 0xb7, 0xef, 0x56, 0x39, 0x6e, 0x1f, 0x48, 0x14, 0xe4, 0x09, + 0xc6, 0xea, 0xc4, 0xd9, 0xed, 0x2e, 0x2e, 0x33, 0x03, 0x00, 0xb9, 0xac, 0x22, 0x65, 0xe9, 0x1b, + }, + { + 0x55, 0x78, 0x89, 0x36, 0xa0, 0x07, 0xa6, 0x99, 0xbf, 0x7c, 0xb5, 0xbd, 0xb6, 0x1e, 0xc3, 0x58, + 0xb3, 0x0f, 0x78, 0x64, 0x74, 0x77, 0x00, 0x50, 0x2e, 0x4c, 0x6a, 0xa1, 0xe8, 0x93, 0x89, 0x5d, + }, + { + 0x09, 0xf8, 0xdd, 0xe0, 0x42, 0xa4, 0x2e, 0x9d, 0xff, 0x0e, 0x70, 0x73, 0x9c, 0x87, 0xa0, 0x81, + 0x4d, 0xb1, 0xc3, 0xf3, 0xff, 0x96, 0x3b, 0x2a, 0xdf, 0x6d, 0x97, 0xba, 0x06, 0xa7, 0x7e, 0x0a, + }, + { + 0x1f, 0x46, 0xb4, 0x72, 0x14, 0x5b, 0x85, 0x01, 0x83, 0xcc, 0x24, 0x17, 0xc2, 0x07, 0xda, 0x60, + 0x6c, 0xab, 0xfa, 0xe5, 0xd9, 0xb4, 0xf0, 0x3f, 0xca, 0xf1, 0x30, 0x8d, 0xd2, 0x4e, 0xe3, 0xb4, + }, + { + 0x4f, 0xb3, 0x0d, 0x98, 0x38, 0x70, 0x28, 0xa2, 0xca, 0x5d, 0x2c, 0xdf, 0x1f, 0xce, 0xff, 0xcc, + 0x75, 0x49, 0xa0, 0xef, 0x54, 0xd9, 0x32, 0x1b, 0x17, 0xb6, 0x7e, 0x7a, 0xa6, 0x5f, 0x7a, 0xff, + }, + { + 0x81, 0x6b, 0x06, 0x73, 0x5b, 0x32, 0x0d, 0x37, 0xb4, 0x50, 0x63, 0x52, 0x25, 0x72, 0x5c, 0xf5, + 0x5d, 0x58, 0xa6, 0xbf, 0x08, 0xcc, 0x1d, 0x70, 0x2d, 0x12, 0x5d, 0xd7, 0xbd, 0xca, 0xe7, 0x10, + }, + { + 0x8f, 0xfc, 0x57, 0x17, 0xce, 0x47, 0x10, 0x79, 0xae, 0x66, 0xa5, 0xcc, 0x98, 0x0b, 0x77, 0xe8, + 0xa2, 0x6e, 0xc1, 0x0d, 0x03, 0xe3, 0x5b, 0xed, 0x38, 0x0e, 0x31, 0x2d, 0x19, 0x4d, 0xd6, 0x2a, + }, + { + 0xc6, 0x9d, 0x2d, 0x0b, 0xad, 0x6d, 0x0c, 0x61, 0x2d, 0x62, 0xe4, 0xce, 0x73, 0x47, 0x72, 0x20, + 0x0c, 0x8e, 0x8f, 0xe9, 0xe7, 0x67, 0x66, 0x2e, 0x17, 0x54, 0xec, 0x15, 0x3e, 0x1b, 0xf3, 0x04, + }, + { + 0xf4, 0xee, 0x03, 0x30, 0x2e, 0x1e, 0xa4, 0xb1, 0x86, 0x6d, 0xc3, 0x54, 0xf3, 0xc5, 0x61, 0xa6, + 0xb9, 0x28, 0x29, 0x11, 0x91, 0xcb, 0xbd, 0xc9, 0x77, 0x62, 0x09, 0x8c, 0xa4, 0x40, 0x84, 0x97, + }, + { + 0xff, 0x98, 0x9b, 0xbc, 0xc2, 0xf0, 0xf8, 0x7f, 0x5c, 0x86, 0x74, 0x33, 0xee, 0x42, 0x6e, 0xab, + 0xd4, 0xd2, 0x1a, 0x0d, 0x41, 0x2d, 0xac, 0xa1, 0x3e, 0x56, 0xed, 0x4b, 0x27, 0x5a, 0x65, 0xe4, + }, + { + 0x2b, 0xb1, 0xe3, 0x64, 0xaa, 0x32, 0x17, 0x57, 0x7c, 0x67, 0xb8, 0x6b, 0x00, 0x53, 0xbe, 0x3e, + 0xec, 0xd1, 0x1b, 0xc4, 0xc3, 0x8d, 0xe6, 0x19, 0xe8, 0x3a, 0x25, 0x98, 0x4e, 0xe9, 0xd4, 0x60, + }, + { + 0xa6, 0x2e, 0xb3, 0xc8, 0xcd, 0xc9, 0xc2, 0x8e, 0xe1, 0xf0, 0x8f, 0x96, 0x8e, 0xc6, 0x37, 0x11, + 0xbc, 0x6c, 0x0c, 0xf6, 0xb6, 0x83, 0x38, 0x96, 0x7a, 0x74, 0x5a, 0xa7, 0xe1, 0x11, 0x8d, 0x8b, + }, + { + 0x90, 0xf2, 0x4d, 0xbd, 0x83, 0x39, 0xe6, 0x54, 0xf6, 0x75, 0xf6, 0x2c, 0x28, 0x3d, 0xd1, 0xcf, + 0xe1, 0xfb, 0x9f, 0x97, 0x19, 0xca, 0x4d, 0x2c, 0x38, 0x3d, 0x36, 0xed, 0x19, 0xe9, 0x4a, 0x0b, + }, + { + 0x1a, 0x61, 0xb8, 0x19, 0x59, 0x16, 0x74, 0xec, 0xdb, 0x7b, 0xeb, 0xd6, 0xae, 0xcd, 0xe9, 0x55, + 0xdb, 0x45, 0xdc, 0xf2, 0x35, 0x84, 0xe9, 0xe6, 0x17, 0x48, 0xac, 0x38, 0x05, 0x21, 0x2c, 0x8e, + }, + { + 0x41, 0xac, 0x17, 0x42, 0xcc, 0x17, 0x10, 0x02, 0x07, 0x7e, 0xfc, 0x4d, 0x77, 0x06, 0x70, 0xcb, + 0x40, 0x8b, 0x47, 0x47, 0x07, 0x29, 0x82, 0xca, 0x93, 0x69, 0x2f, 0x3a, 0x64, 0xc6, 0xcb, 0x23, + }, + { + 0xa2, 0xcb, 0x2d, 0x02, 0x5d, 0x30, 0x9f, 0x32, 0xf5, 0xc5, 0x13, 0xff, 0xfc, 0xe2, 0xfb, 0x26, + 0x3b, 0x3b, 0xaf, 0xa4, 0x37, 0x6d, 0x45, 0xbf, 0xdb, 0xb9, 0xee, 0xec, 0x92, 0xa5, 0x1d, 0x0d, + }, + { + 0xa4, 0xef, 0x08, 0xb7, 0xb4, 0x68, 0x74, 0x93, 0xb2, 0xda, 0xba, 0xe9, 0x05, 0xf5, 0x09, 0xb6, + 0x53, 0xdd, 0x17, 0x60, 0xbb, 0x1e, 0xb0, 0x71, 0xd8, 0x47, 0x85, 0x02, 0x13, 0xbe, 0xa2, 0x67, + }, + { + 0x31, 0x50, 0x90, 0xb0, 0x83, 0x4a, 0xcf, 0x3f, 0xbe, 0x88, 0x90, 0x4b, 0xe1, 0x9f, 0xe6, 0xd0, + 0xfd, 0x01, 0x8e, 0xfc, 0xc0, 0x8c, 0x2f, 0x9b, 0x48, 0x70, 0x9d, 0x4e, 0x22, 0x21, 0x07, 0x09, + }, + { + 0x15, 0x9f, 0x37, 0x45, 0x52, 0x99, 0x6e, 0xe9, 0x1a, 0x25, 0x56, 0x0b, 0x19, 0xf1, 0xca, 0x9f, + 0x29, 0xe5, 0x23, 0xa6, 0x0b, 0x94, 0x0a, 0xe3, 0x74, 0xaa, 0xd5, 0x35, 0xaf, 0x6e, 0xb2, 0x24, + }, + { + 0x68, 0xab, 0xa6, 0x8b, 0x5f, 0xc7, 0x93, 0x1a, 0x06, 0x51, 0x2c, 0x3b, 0xad, 0x44, 0x6b, 0x69, + 0x1a, 0x1d, 0x41, 0xca, 0x8e, 0x59, 0x2c, 0x83, 0x71, 0x48, 0x8c, 0xaf, 0x50, 0x85, 0x00, 0xf3, + }, + { + 0xe2, 0xa6, 0x38, 0x93, 0xca, 0xe3, 0xd0, 0x36, 0xf4, 0xe9, 0x53, 0xfb, 0xa0, 0xd0, 0x13, 0xd3, + 0x2b, 0x7d, 0x46, 0xc8, 0x8b, 0xc7, 0x8c, 0xca, 0x59, 0xec, 0x66, 0x17, 0x70, 0xbb, 0xf9, 0x92, + }, + { + 0x89, 0xca, 0x92, 0x19, 0x01, 0xb8, 0x4b, 0x97, 0x06, 0x1a, 0x12, 0x91, 0x72, 0x11, 0xeb, 0x12, + 0x8b, 0x12, 0xd9, 0xdc, 0xc9, 0xb2, 0x37, 0xf8, 0x3e, 0x02, 0x03, 0xbe, 0x45, 0x45, 0xc9, 0x42, + }, + { + 0x45, 0x2c, 0x80, 0xe1, 0x3a, 0x0a, 0xdf, 0xa3, 0xd2, 0x4a, 0x23, 0x0d, 0x47, 0x0d, 0x49, 0xad, + 0xdf, 0xb0, 0x42, 0xdf, 0x87, 0x85, 0xa6, 0x8f, 0x9f, 0x7e, 0x9b, 0xa4, 0x42, 0x64, 0xcb, 0xfb, + }, + { + 0xc7, 0x39, 0x26, 0xb1, 0x90, 0x4d, 0xc1, 0x7a, 0xea, 0x31, 0x1b, 0xae, 0x1a, 0x5c, 0x1f, 0x4f, + 0x44, 0x2f, 0x87, 0x08, 0x5d, 0xa6, 0x74, 0xfd, 0xab, 0xb2, 0x4b, 0x01, 0xed, 0xd5, 0x4c, 0xe6, + }, + { + 0x2a, 0xef, 0xfa, 0x25, 0x3c, 0xd2, 0xc8, 0x08, 0x9c, 0x33, 0x3c, 0x47, 0xb3, 0xb5, 0x44, 0x34, + 0x97, 0xee, 0xe8, 0x52, 0x1c, 0x15, 0xb3, 0xe0, 0xda, 0xef, 0x77, 0xde, 0x15, 0x39, 0x4b, 0x38, + }, + { + 0x8a, 0x3a, 0x59, 0x61, 0x9d, 0x3e, 0x9b, 0x38, 0xc9, 0x84, 0x80, 0xaf, 0xb4, 0x37, 0x8a, 0x67, + 0x47, 0xc9, 0x6c, 0x72, 0xef, 0x39, 0x50, 0x28, 0x6c, 0x8f, 0xad, 0x09, 0x75, 0x26, 0xc9, 0xa9, + }, + { + 0x27, 0x1e, 0x8b, 0xf6, 0x6b, 0x56, 0x5d, 0x17, 0x58, 0xac, 0xdf, 0x27, 0xd9, 0x3e, 0x5b, 0xdd, + 0xaf, 0xbc, 0xb7, 0xf9, 0x76, 0x3b, 0x40, 0x06, 0xbc, 0x6e, 0xec, 0xaa, 0xb2, 0xdc, 0x9a, 0x0c, + }, + { + 0x09, 0x14, 0xef, 0x19, 0xc7, 0x7d, 0xc8, 0xa3, 0xd0, 0xaa, 0x7f, 0x09, 0x18, 0xaf, 0xd3, 0xde, + 0xbf, 0x05, 0xfc, 0xf9, 0xeb, 0xc0, 0x8e, 0xcf, 0xc7, 0x4c, 0x2f, 0x3f, 0xd4, 0x51, 0x41, 0xb2, + }, + { + 0xb7, 0x33, 0xf3, 0x72, 0x6d, 0x12, 0xc1, 0x5c, 0x5d, 0x81, 0xb3, 0x63, 0x81, 0x50, 0x81, 0xc0, + 0x4a, 0xea, 0x18, 0x7c, 0xa6, 0x2d, 0x23, 0xba, 0x4b, 0xb9, 0x31, 0xd9, 0xab, 0x20, 0x60, 0x77, + }, + { + 0xbb, 0x1c, 0x50, 0x2d, 0xdc, 0x18, 0x27, 0x98, 0x60, 0xde, 0x17, 0xd9, 0x17, 0x3c, 0xd5, 0x98, + 0xc3, 0x12, 0xfd, 0x8b, 0x25, 0x1e, 0xa5, 0xc1, 0xa8, 0xef, 0xec, 0x05, 0x3e, 0xfc, 0xd1, 0xfc, + }, + { + 0xe6, 0x3b, 0x9f, 0x33, 0x85, 0xeb, 0x91, 0xd0, 0xad, 0x2f, 0xc2, 0x96, 0x61, 0x64, 0xbc, 0x12, + 0x15, 0x79, 0x65, 0x93, 0xc2, 0x63, 0xa3, 0x27, 0x88, 0x60, 0x39, 0x35, 0x21, 0x05, 0xe9, 0x49, + }, + { + 0x9b, 0x68, 0xe7, 0xc8, 0xea, 0x0e, 0x5c, 0xa4, 0x03, 0x3a, 0x4e, 0x31, 0xb1, 0x92, 0xad, 0x9d, + 0x7e, 0xb5, 0x93, 0x81, 0xdd, 0x7a, 0xe9, 0xa1, 0x69, 0x28, 0x6a, 0xaf, 0x48, 0x05, 0x94, 0xc0, + }, + { + 0x66, 0x3d, 0x87, 0xc1, 0x48, 0x9d, 0xdf, 0x99, 0x25, 0xd7, 0xb0, 0xfa, 0x03, 0x8b, 0x62, 0x60, + 0xc5, 0x07, 0x3f, 0xa2, 0xc8, 0xbd, 0x70, 0xdb, 0x40, 0x6c, 0x65, 0xbf, 0x15, 0xfc, 0x1e, 0xc9, + }, + { + 0x38, 0x9c, 0x1a, 0x5b, 0x4f, 0x84, 0xca, 0xe1, 0x30, 0x6a, 0xf0, 0xb6, 0xf1, 0x61, 0xd3, 0xb0, + 0xa6, 0x6d, 0x0d, 0x11, 0x03, 0xe0, 0xcb, 0x9f, 0xbe, 0x7e, 0xc2, 0x7a, 0x53, 0x9d, 0x39, 0xcb, + }, + { + 0xf3, 0x47, 0x4a, 0x37, 0xcd, 0x19, 0x27, 0x0f, 0xfb, 0x3f, 0xcb, 0x81, 0x1e, 0x0f, 0xfd, 0x1f, + 0x2e, 0x8d, 0xff, 0xe9, 0x52, 0x8b, 0x8e, 0x52, 0x3c, 0x82, 0xe6, 0x44, 0xf6, 0x92, 0xd4, 0xd4, + }, + { + 0x3a, 0xe8, 0x4d, 0xcc, 0x4a, 0x0e, 0xaa, 0xf6, 0x32, 0x88, 0x4c, 0xee, 0xaa, 0x9c, 0xeb, 0x59, + 0xb5, 0xb8, 0x06, 0x89, 0x49, 0xc9, 0xa6, 0xf7, 0xa6, 0x14, 0x44, 0x55, 0x5e, 0x3e, 0x86, 0x08, + }, + { + 0xca, 0x3d, 0x95, 0x21, 0xf3, 0xbb, 0x78, 0x29, 0x6a, 0x38, 0xd3, 0xe4, 0x48, 0x98, 0x6f, 0x0e, + 0xaf, 0x46, 0xa5, 0x02, 0xdd, 0xfb, 0x52, 0x42, 0x9b, 0x69, 0x97, 0xe6, 0x68, 0x21, 0x0d, 0x69, + }, + { + 0x3a, 0x8a, 0x14, 0x6e, 0xa2, 0x24, 0x8f, 0x89, 0x5e, 0x99, 0x8a, 0x5b, 0x90, 0xb1, 0xf3, 0x64, + 0x4d, 0x10, 0xef, 0x45, 0xa9, 0xfb, 0xbb, 0xc0, 0xf5, 0x66, 0xdf, 0x15, 0xae, 0xd0, 0xd9, 0x56, + }, + { + 0x62, 0x50, 0x52, 0xb5, 0xb9, 0x76, 0xa7, 0xcb, 0xe6, 0xf7, 0x3a, 0x9f, 0xa4, 0x1e, 0x0a, 0x4d, + 0x88, 0xa4, 0x1c, 0xea, 0x11, 0x8c, 0xfb, 0xbe, 0x70, 0x62, 0xec, 0x4e, 0x00, 0x56, 0x0e, 0xa9, + }, +}; diff --git a/src/southbridge/intel/bd82x6x/Makefile.inc b/src/southbridge/intel/bd82x6x/Makefile.inc index 64038e5..fa21277 100644 --- a/src/southbridge/intel/bd82x6x/Makefile.inc +++ b/src/southbridge/intel/bd82x6x/Makefile.inc @@ -45,10 +45,14 @@ smm-$(CONFIG_SPI_FLASH_SMM) += ../common/spi.c ramstage-$(CONFIG_HAVE_SMI_HANDLER) += smi.c smm-$(CONFIG_HAVE_SMI_HANDLER) += smihandler.c me.c me_8.x.c finalize.c pch.c -romstage-y += early_usb.c early_smbus.c early_me.c me_status.c gpio.c +romstage-y += early_usb.c early_smbus.c me_status.c gpio.c romstage-y += reset.c romstage-y += early_spi.c early_pch.c +romstage-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE) += early_me.c +romstage-$(CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE) += early_me.c +romstage-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE) += early_thermal.c early_pch_native.c early_me_native.c + ifeq ($(CONFIG_BUILD_WITH_FAKE_IFD),y) IFD_BIN_PATH := $(objgenerated)/ifdfake.bin IFD_SECTIONS := $(addprefix -b ,$(CONFIG_IFD_BIOS_SECTION:"%"=%)) \ diff --git a/src/southbridge/intel/bd82x6x/early_me_native.c b/src/southbridge/intel/bd82x6x/early_me_native.c new file mode 100644 index 0000000..ab54ffd --- /dev/null +++ b/src/southbridge/intel/bd82x6x/early_me_native.c @@ -0,0 +1,272 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011 The Chromium OS Authors. All rights reserved. + * + * 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 + */ + +#include <arch/hlt.h> +#include <arch/io.h> +#include <console/console.h> +#include <delay.h> +#include <device/pci_ids.h> +#include <string.h> +#include "me.h" +#include "pch.h" + +static const char *me_ack_values[] = { + [ME_HFS_ACK_NO_DID] = "No DID Ack received", + [ME_HFS_ACK_RESET] = "Non-power cycle reset", + [ME_HFS_ACK_PWR_CYCLE] = "Power cycle reset", + [ME_HFS_ACK_S3] = "Go to S3", + [ME_HFS_ACK_S4] = "Go to S4", + [ME_HFS_ACK_S5] = "Go to S5", + [ME_HFS_ACK_GBL_RESET] = "Global Reset", + [ME_HFS_ACK_CONTINUE] = "Continue to boot" +}; + +static inline void pci_read_dword_ptr(void *ptr, int offset) +{ + u32 dword = pci_read_config32(PCH_ME_DEV, offset); + memcpy(ptr, &dword, sizeof(dword)); +} + +static inline void pci_write_dword_ptr(void *ptr, int offset) +{ + u32 dword = 0; + memcpy(&dword, ptr, sizeof(dword)); + pci_write_config32(PCH_ME_DEV, offset, dword); +} + +void intel_early_me_status(void) +{ + struct me_hfs hfs; + struct me_gmes gmes; + + pci_read_dword_ptr(&hfs, PCI_ME_HFS); + pci_read_dword_ptr(&gmes, PCI_ME_GMES); + + intel_me_status(&hfs, &gmes); +} + +int intel_early_me_init(void) +{ + int count; + struct me_uma uma; + struct me_hfs hfs; + + printk(BIOS_INFO, "Intel ME early init\n"); + + /* Wait for ME UMA SIZE VALID bit to be set */ + for (count = ME_RETRY; count > 0; --count) { + pci_read_dword_ptr(&uma, PCI_ME_UMA); + if (uma.valid) + break; + udelay(ME_DELAY); + } + if (!count) { + printk(BIOS_ERR, "ERROR: ME is not ready!\n"); + return -1; + } + + /* Check for valid firmware */ + pci_read_dword_ptr(&hfs, PCI_ME_HFS); + if (hfs.fpt_bad) { + printk(BIOS_WARNING, "WARNING: ME has bad firmware\n"); + return -1; + } + + printk(BIOS_INFO, "Intel ME firmware is ready\n"); + return 0; +} + +int intel_early_me_uma_size(void) +{ + struct me_uma uma; + + pci_read_dword_ptr(&uma, PCI_ME_UMA); + if (uma.valid) { + printk(BIOS_DEBUG, "ME: Requested %uMB UMA\n", uma.size); + return uma.size; + } + + printk(BIOS_DEBUG, "ME: Invalid UMA size\n"); + return 0; +} + +static inline void set_global_reset(int enable) +{ + u32 etr3 = pci_read_config32(PCH_LPC_DEV, ETR3); + + /* Clear CF9 Without Resume Well Reset Enable */ + etr3 &= ~ETR3_CWORWRE; + + /* CF9GR indicates a Global Reset */ + if (enable) + etr3 |= ETR3_CF9GR; + else + etr3 &= ~ETR3_CF9GR; + + pci_write_config32(PCH_LPC_DEV, ETR3, etr3); +} + +int intel_early_me_init_done(u8 status) +{ + u8 reset, errorcode, opmode; + u16 reg16; + u32 mebase_l, mebase_h; + u32 millisec; + u32 hfs, me_fws2; + struct me_did did = { + .init_done = ME_INIT_DONE, + .status = status + }; + u32 meDID; + + hfs = (pci_read_config32(PCI_DEV(0, 0x16, 0), PCI_ME_HFS) & 0xff000) >> 12; + + opmode = (hfs & 0xf0) >> 4; + errorcode = hfs & 0xf; + + if (opmode != ME_HFS_MODE_NORMAL) { + printk(BIOS_NOTICE, "ME: Wrong mode : %d\n", opmode); + //return 0; + } + if (errorcode) { + printk(BIOS_NOTICE, "ME: HFS error : %d\n", errorcode); + //return 0; + } + + me_fws2 = pci_read_config32(PCI_DEV(0, 0x16, 0), 0x48); + printk(BIOS_NOTICE, "ME: FWS2: 0x%x\n", me_fws2); + printk(BIOS_NOTICE, "ME: Bist in progress: 0x%x\n", me_fws2 & 0x1); + printk(BIOS_NOTICE, "ME: ICC Status : 0x%x\n", (me_fws2 & 0x6) >> 1); + printk(BIOS_NOTICE, "ME: Invoke MEBx : 0x%x\n", (me_fws2 & 0x8) >> 3); + printk(BIOS_NOTICE, "ME: CPU replaced : 0x%x\n", (me_fws2 & 0x10) >> 4); + printk(BIOS_NOTICE, "ME: MBP ready : 0x%x\n", (me_fws2 & 0x20) >> 5); + printk(BIOS_NOTICE, "ME: MFS failure : 0x%x\n", (me_fws2 & 0x40) >> 6); + printk(BIOS_NOTICE, "ME: Warm reset req : 0x%x\n", (me_fws2 & 0x80) >> 7); + printk(BIOS_NOTICE, "ME: CPU repl valid : 0x%x\n", (me_fws2 & 0x100) >> 8); + printk(BIOS_NOTICE, "ME: (Reserved) : 0x%x\n", (me_fws2 & 0x600) >> 9); + printk(BIOS_NOTICE, "ME: FW update req : 0x%x\n", (me_fws2 & 0x800) >> 11); + printk(BIOS_NOTICE, "ME: (Reserved) : 0x%x\n", (me_fws2 & 0xf000) >> 12); + printk(BIOS_NOTICE, "ME: Current state : 0x%x\n", (me_fws2 & 0xff0000) >> 16); + printk(BIOS_NOTICE, "ME: Current PM event: 0x%x\n", (me_fws2 & 0xf000000) >> 24); + printk(BIOS_NOTICE, "ME: Progress code : 0x%x\n", (me_fws2 & 0xf0000000) >> 28); + + // Poll cpu replaced for 50ms + millisec = 0; + while ((((me_fws2 & 0x100) >> 8) == 0) && millisec < 50) { + udelay(1000); + me_fws2 = pci_read_config32(PCI_DEV(0, 0x16, 0), 0x48); + millisec++; + } + if (millisec >= 50 || ((me_fws2 & 0x100) >> 8) == 0x0) { + printk(BIOS_NOTICE, "Waited long enough, or CPU was not replaced, continue...\n"); + } else if ((me_fws2 & 0x100) == 0x100) { + if ((me_fws2 & 0x80) == 0x80) { + printk(BIOS_NOTICE, "CPU was replaced & warm reset required...\n"); + reg16 = pcie_read_config16(PCI_DEV(0, 31, 0), 0xa2) & ~0x80; + pcie_write_config16(PCI_DEV(0, 31, 0), 0xa2, reg16); + set_global_reset(0); + outb(0x6, 0xcf9); + hlt(); + } + + if (((me_fws2 & 0x10) == 0x10) && (me_fws2 & 0x80) == 0x00) { + printk(BIOS_NOTICE, "Full training required\n"); + } + } + + printk(BIOS_NOTICE, "PASSED! Tell ME that DRAM is ready\n"); + + /* MEBASE from MESEG_BASE[35:20] */ + mebase_l = pci_read_config32(PCI_CPU_DEVICE, PCI_CPU_MEBASE_L); + mebase_h = pci_read_config32(PCI_CPU_DEVICE, PCI_CPU_MEBASE_H) & 0xf; + did.uma_base = (mebase_l >> 20) | (mebase_h << 12); + + meDID = did.uma_base | (1 << 28);// | (1 << 23); + pci_write_config32(PCI_DEV(0, 0x16, 0), PCI_ME_H_GS, meDID); + + udelay(1100); + + /* Must wait for ME acknowledgement */ + millisec = 0; + hfs = (pci_read_config32(PCI_DEV(0, 0x16, 0), PCI_ME_HFS) & 0xfe000000) >> 24; + while ((((hfs & 0xf0) >> 4) != ME_HFS_BIOS_DRAM_ACK) && (millisec < 5000)) { + udelay(1000); + hfs = (pci_read_config32(PCI_DEV(0, 0x16, 0), PCI_ME_HFS) & 0xfe000000) >> 24; + millisec++; + } + + me_fws2 = pci_read_config32(PCI_DEV(0, 0x16, 0), 0x48); + printk(BIOS_NOTICE, "ME: FWS2: 0x%x\n", me_fws2); + printk(BIOS_NOTICE, "ME: Bist in progress: 0x%x\n", me_fws2 & 0x1); + printk(BIOS_NOTICE, "ME: ICC Status : 0x%x\n", (me_fws2 & 0x6) >> 1); + printk(BIOS_NOTICE, "ME: Invoke MEBx : 0x%x\n", (me_fws2 & 0x8) >> 3); + printk(BIOS_NOTICE, "ME: CPU replaced : 0x%x\n", (me_fws2 & 0x10) >> 4); + printk(BIOS_NOTICE, "ME: MBP ready : 0x%x\n", (me_fws2 & 0x20) >> 5); + printk(BIOS_NOTICE, "ME: MFS failure : 0x%x\n", (me_fws2 & 0x40) >> 6); + printk(BIOS_NOTICE, "ME: Warm reset req : 0x%x\n", (me_fws2 & 0x80) >> 7); + printk(BIOS_NOTICE, "ME: CPU repl valid : 0x%x\n", (me_fws2 & 0x100) >> 8); + printk(BIOS_NOTICE, "ME: (Reserved) : 0x%x\n", (me_fws2 & 0x600) >> 9); + printk(BIOS_NOTICE, "ME: FW update req : 0x%x\n", (me_fws2 & 0x800) >> 11); + printk(BIOS_NOTICE, "ME: (Reserved) : 0x%x\n", (me_fws2 & 0xf000) >> 12); + printk(BIOS_NOTICE, "ME: Current state : 0x%x\n", (me_fws2 & 0xff0000) >> 16); + printk(BIOS_NOTICE, "ME: Current PM event: 0x%x\n", (me_fws2 & 0xf000000) >> 24); + printk(BIOS_NOTICE, "ME: Progress code : 0x%x\n", (me_fws2 & 0xf0000000) >> 28); + + + /* Return the requested BIOS action */ + printk(BIOS_NOTICE, "ME: Requested BIOS Action: %s\n", + me_ack_values[(hfs & 0xe) >> 1]); + + reset = inb(0xcf9); + reset &= 0xf1; + switch ((hfs & 0xe) >> 1) { + case ME_HFS_ACK_NO_DID: + case ME_HFS_ACK_CONTINUE: + /* Continue to boot */ + return 0; + case ME_HFS_ACK_RESET: + /* Non-power cycle reset */ + set_global_reset(0); + reset |= 0x06; + break; + case ME_HFS_ACK_PWR_CYCLE: + /* Power cycle reset */ + set_global_reset(0); + reset |= 0x0e; + break; + case ME_HFS_ACK_GBL_RESET: + /* Global reset */ + set_global_reset(1); + reset |= 0x0e; + break; + case ME_HFS_ACK_S3: + case ME_HFS_ACK_S4: + case ME_HFS_ACK_S5: + break; + } + + /* Perform the requested reset */ + if (reset) { + outb(reset, 0xcf9); + hlt(); + } + return -1; +} diff --git a/src/southbridge/intel/bd82x6x/early_pch_native.c b/src/southbridge/intel/bd82x6x/early_pch_native.c new file mode 100644 index 0000000..5cd6315 --- /dev/null +++ b/src/southbridge/intel/bd82x6x/early_pch_native.c @@ -0,0 +1,375 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2014 Vladimir Serbinenko <phcoder(a)gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <console/console.h> +#include <string.h> +#include <arch/hlt.h> +#include <arch/io.h> +#include <cbmem.h> +#include <arch/cbfs.h> +#include <cbfs.h> +#include <ip_checksum.h> +#include <pc80/mc146818rtc.h> +#include <device/pci_def.h> +#include <delay.h> + +#include "pch.h" +/* For DMI bar. */ +#include "northbridge/intel/sandybridge/sandybridge.h" + +#define SOUTHBRIDGE PCI_DEV(0, 0x1f, 0) + +static void +wait_2338 (void) +{ + while (read8 (DEFAULT_RCBA | 0x2338) & 1); +} + +static u32 +read_2338 (u32 edx) +{ + u32 ret; + + write32 (DEFAULT_RCBA | 0x2330, edx); + write16 (DEFAULT_RCBA | 0x2338, (read16 (DEFAULT_RCBA | 0x2338) + & 0x1ff) | 0x600); + wait_2338 (); + ret = read32 (DEFAULT_RCBA | 0x2334); + wait_2338 (); + read8 (DEFAULT_RCBA | 0x2338); + return ret; +} + +static void +write_2338 (u32 edx, u32 val) +{ + read_2338 (edx); + write16 (DEFAULT_RCBA | 0x2338, (read16 (DEFAULT_RCBA | 0x2338) + & 0x1ff) | 0x600); + wait_2338 (); + + write32 (DEFAULT_RCBA | 0x2334, val); + wait_2338 (); + write16 (DEFAULT_RCBA | 0x2338, + (read16 (DEFAULT_RCBA | 0x2338) & 0x1ff) | 0x600); + read8 (DEFAULT_RCBA | 0x2338); +} + + +static void +init_dmi (void) +{ + int i; + + write32 (DEFAULT_DMIBAR | 0x0914, + read32 (DEFAULT_DMIBAR | 0x0914) | 0x80000000); + write32 (DEFAULT_DMIBAR | 0x0934, + read32 (DEFAULT_DMIBAR | 0x0934) | 0x80000000); + for (i = 0; i < 4; i++) + { + write32 (DEFAULT_DMIBAR | 0x0a00 | (i << 4), + read32 (DEFAULT_DMIBAR | 0x0a00 | (i << 4)) & 0xf3ffffff); + write32 (DEFAULT_DMIBAR | 0x0a04 | (i << 4), + read32 (DEFAULT_DMIBAR | 0x0a04 | (i << 4)) | 0x800); + } + write32 (DEFAULT_DMIBAR | 0x0c30, (read32 (DEFAULT_DMIBAR | 0x0c30) + & 0xfffffff) | 0x40000000); + for (i = 0; i < 2; i++) + { + write32 (DEFAULT_DMIBAR | 0x0904 | (i << 5), + read32 (DEFAULT_DMIBAR | 0x0904 | (i << 5)) & 0xfe3fffff); + write32 (DEFAULT_DMIBAR | 0x090c | (i << 5), + read32 (DEFAULT_DMIBAR | 0x090c | (i << 5)) & 0xfff1ffff); + } + write32 (DEFAULT_DMIBAR | 0x090c, + read32 (DEFAULT_DMIBAR | 0x090c) & 0xfe1fffff); + write32 (DEFAULT_DMIBAR | 0x092c, + read32 (DEFAULT_DMIBAR | 0x092c) & 0xfe1fffff); + read32 (DEFAULT_DMIBAR | 0x0904); // !!! = 0x7a1842ec + write32 (DEFAULT_DMIBAR | 0x0904, 0x7a1842ec); + read32 (DEFAULT_DMIBAR | 0x090c); // !!! = 0x00000208 + write32 (DEFAULT_DMIBAR | 0x090c, 0x00000128); + read32 (DEFAULT_DMIBAR | 0x0924); // !!! = 0x7a1842ec + write32 (DEFAULT_DMIBAR | 0x0924, 0x7a1842ec); + read32 (DEFAULT_DMIBAR | 0x092c); // !!! = 0x00000208 + write32 (DEFAULT_DMIBAR | 0x092c, 0x00000128); + read32 (DEFAULT_DMIBAR | 0x0700); // !!! = 0x46139008 + write32 (DEFAULT_DMIBAR | 0x0700, 0x46139008); + read32 (DEFAULT_DMIBAR | 0x0720); // !!! = 0x46139008 + write32 (DEFAULT_DMIBAR | 0x0720, 0x46139008); + read32 (DEFAULT_DMIBAR | 0x0c04); // !!! = 0x2e680008 + write32 (DEFAULT_DMIBAR | 0x0c04, 0x2e680008); + read32 (DEFAULT_DMIBAR | 0x0904); // !!! = 0x7a1842ec + write32 (DEFAULT_DMIBAR | 0x0904, 0x3a1842ec); + read32 (DEFAULT_DMIBAR | 0x0924); // !!! = 0x7a1842ec + write32 (DEFAULT_DMIBAR | 0x0924, 0x3a1842ec); + read32 (DEFAULT_DMIBAR | 0x0910); // !!! = 0x00006300 + write32 (DEFAULT_DMIBAR | 0x0910, 0x00004300); + read32 (DEFAULT_DMIBAR | 0x0930); // !!! = 0x00006300 + write32 (DEFAULT_DMIBAR | 0x0930, 0x00004300); + read32 (DEFAULT_DMIBAR | 0x0a00); // !!! = 0x03042010 + write32 (DEFAULT_DMIBAR | 0x0a00, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a10); // !!! = 0x03042010 + write32 (DEFAULT_DMIBAR | 0x0a10, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a20); // !!! = 0x03042010 + write32 (DEFAULT_DMIBAR | 0x0a20, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a30); // !!! = 0x03042010 + write32 (DEFAULT_DMIBAR | 0x0a30, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0c00); // !!! = 0x29700c08 + write32 (DEFAULT_DMIBAR | 0x0c00, 0x29700c08); + read32 (DEFAULT_DMIBAR | 0x0a04); // !!! = 0x0c0708f0 + write32 (DEFAULT_DMIBAR | 0x0a04, 0x0c0718f0); + read32 (DEFAULT_DMIBAR | 0x0a14); // !!! = 0x0c0708f0 + write32 (DEFAULT_DMIBAR | 0x0a14, 0x0c0718f0); + read32 (DEFAULT_DMIBAR | 0x0a24); // !!! = 0x0c0708f0 + write32 (DEFAULT_DMIBAR | 0x0a24, 0x0c0718f0); + read32 (DEFAULT_DMIBAR | 0x0a34); // !!! = 0x0c0708f0 + write32 (DEFAULT_DMIBAR | 0x0a34, 0x0c0718f0); + read32 (DEFAULT_DMIBAR | 0x0900); // !!! = 0x50000000 + write32 (DEFAULT_DMIBAR | 0x0900, 0x50000000); + read32 (DEFAULT_DMIBAR | 0x0920); // !!! = 0x50000000 + write32 (DEFAULT_DMIBAR | 0x0920, 0x50000000); + read32 (DEFAULT_DMIBAR | 0x0908); // !!! = 0x51ffffff + write32 (DEFAULT_DMIBAR | 0x0908, 0x51ffffff); + read32 (DEFAULT_DMIBAR | 0x0928); // !!! = 0x51ffffff + write32 (DEFAULT_DMIBAR | 0x0928, 0x51ffffff); + read32 (DEFAULT_DMIBAR | 0x0a00); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a00, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a10); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a10, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a20); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a20, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a30); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a30, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0700); // !!! = 0x46139008 + write32 (DEFAULT_DMIBAR | 0x0700, 0x46139008); + read32 (DEFAULT_DMIBAR | 0x0720); // !!! = 0x46139008 + write32 (DEFAULT_DMIBAR | 0x0720, 0x46139008); + read32 (DEFAULT_DMIBAR | 0x0904); // !!! = 0x3a1842ec + write32 (DEFAULT_DMIBAR | 0x0904, 0x3a1846ec); + read32 (DEFAULT_DMIBAR | 0x0924); // !!! = 0x3a1842ec + write32 (DEFAULT_DMIBAR | 0x0924, 0x3a1846ec); + read32 (DEFAULT_DMIBAR | 0x0a00); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a00, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a10); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a10, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a20); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a20, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a30); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a30, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0908); // !!! = 0x51ffffff + write32 (DEFAULT_DMIBAR | 0x0908, 0x51ffffff); + read32 (DEFAULT_DMIBAR | 0x0928); // !!! = 0x51ffffff + write32 (DEFAULT_DMIBAR | 0x0928, 0x51ffffff); + read32 (DEFAULT_DMIBAR | 0x0c00); // !!! = 0x29700c08 + write32 (DEFAULT_DMIBAR | 0x0c00, 0x29700c08); + read32 (DEFAULT_DMIBAR | 0x0c0c); // !!! = 0x16063400 + write32 (DEFAULT_DMIBAR | 0x0c0c, 0x00063400); + read32 (DEFAULT_DMIBAR | 0x0700); // !!! = 0x46139008 + write32 (DEFAULT_DMIBAR | 0x0700, 0x46339008); + read32 (DEFAULT_DMIBAR | 0x0720); // !!! = 0x46139008 + write32 (DEFAULT_DMIBAR | 0x0720, 0x46339008); + read32 (DEFAULT_DMIBAR | 0x0700); // !!! = 0x46339008 + write32 (DEFAULT_DMIBAR | 0x0700, 0x45339008); + read32 (DEFAULT_DMIBAR | 0x0720); // !!! = 0x46339008 + write32 (DEFAULT_DMIBAR | 0x0720, 0x45339008); + read32 (DEFAULT_DMIBAR | 0x0700); // !!! = 0x45339008 + write32 (DEFAULT_DMIBAR | 0x0700, 0x453b9008); + read32 (DEFAULT_DMIBAR | 0x0720); // !!! = 0x45339008 + write32 (DEFAULT_DMIBAR | 0x0720, 0x453b9008); + read32 (DEFAULT_DMIBAR | 0x0700); // !!! = 0x453b9008 + write32 (DEFAULT_DMIBAR | 0x0700, 0x45bb9008); + read32 (DEFAULT_DMIBAR | 0x0720); // !!! = 0x453b9008 + write32 (DEFAULT_DMIBAR | 0x0720, 0x45bb9008); + read32 (DEFAULT_DMIBAR | 0x0700); // !!! = 0x45bb9008 + write32 (DEFAULT_DMIBAR | 0x0700, 0x45fb9008); + read32 (DEFAULT_DMIBAR | 0x0720); // !!! = 0x45bb9008 + write32 (DEFAULT_DMIBAR | 0x0720, 0x45fb9008); + read32 (DEFAULT_DMIBAR | 0x0914); // !!! = 0x9021a080 + write32 (DEFAULT_DMIBAR | 0x0914, 0x9021a280); + read32 (DEFAULT_DMIBAR | 0x0934); // !!! = 0x9021a080 + write32 (DEFAULT_DMIBAR | 0x0934, 0x9021a280); + read32 (DEFAULT_DMIBAR | 0x0914); // !!! = 0x9021a280 + write32 (DEFAULT_DMIBAR | 0x0914, 0x9821a280); + read32 (DEFAULT_DMIBAR | 0x0934); // !!! = 0x9021a280 + write32 (DEFAULT_DMIBAR | 0x0934, 0x9821a280); + read32 (DEFAULT_DMIBAR | 0x0a00); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a00, 0x03242018); + read32 (DEFAULT_DMIBAR | 0x0a10); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a10, 0x03242018); + read32 (DEFAULT_DMIBAR | 0x0a20); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a20, 0x03242018); + read32 (DEFAULT_DMIBAR | 0x0a30); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a30, 0x03242018); + read32 (DEFAULT_DMIBAR | 0x0258); // !!! = 0x40000600 + write32 (DEFAULT_DMIBAR | 0x0258, 0x60000600); + read32 (DEFAULT_DMIBAR | 0x0904); // !!! = 0x3a1846ec + write32 (DEFAULT_DMIBAR | 0x0904, 0x2a1846ec); + read32 (DEFAULT_DMIBAR | 0x0914); // !!! = 0x9821a280 + write32 (DEFAULT_DMIBAR | 0x0914, 0x98200280); + read32 (DEFAULT_DMIBAR | 0x0924); // !!! = 0x3a1846ec + write32 (DEFAULT_DMIBAR | 0x0924, 0x2a1846ec); + read32 (DEFAULT_DMIBAR | 0x0934); // !!! = 0x9821a280 + write32 (DEFAULT_DMIBAR | 0x0934, 0x98200280); + read32 (DEFAULT_DMIBAR | 0x022c); // !!! = 0x00c26460 + write32 (DEFAULT_DMIBAR | 0x022c, 0x00c2403c); + read8 (DEFAULT_RCBA | 0x21a4); // !!! = 0x42 + + read32 (DEFAULT_RCBA | 0x21a4); // !!! = 0x00012c42 + read32 (DEFAULT_RCBA | 0x2340); // !!! = 0x0013001b + write32 (DEFAULT_RCBA | 0x2340, 0x003a001b); + read8 (DEFAULT_RCBA | 0x21b0); // !!! = 0x01 + write8 (DEFAULT_RCBA | 0x21b0, 0x02); + read32 (DEFAULT_DMIBAR | 0x0084); // !!! = 0x0041ac41 + write32 (DEFAULT_DMIBAR | 0x0084, 0x0041ac42); + read8 (DEFAULT_DMIBAR | 0x0088); // !!! = 0x00 + write8 (DEFAULT_DMIBAR | 0x0088, 0x20); + read16 (DEFAULT_DMIBAR | 0x008a); // !!! = 0x0041 + read8 (DEFAULT_DMIBAR | 0x0088); // !!! = 0x00 + write8 (DEFAULT_DMIBAR | 0x0088, 0x20); + read16 (DEFAULT_DMIBAR | 0x008a); // !!! = 0x0042 + read16 (DEFAULT_DMIBAR | 0x008a); // !!! = 0x0042 + + read32 (DEFAULT_DMIBAR | 0x0014); // !!! = 0x8000007f + write32 (DEFAULT_DMIBAR | 0x0014, 0x80000019); + read32 (DEFAULT_DMIBAR | 0x0020); // !!! = 0x01000000 + write32 (DEFAULT_DMIBAR | 0x0020, 0x81000022); + read32 (DEFAULT_DMIBAR | 0x002c); // !!! = 0x02000000 + write32 (DEFAULT_DMIBAR | 0x002c, 0x82000044); + read32 (DEFAULT_DMIBAR | 0x0038); // !!! = 0x07000080 + write32 (DEFAULT_DMIBAR | 0x0038, 0x87000080); + read8 (DEFAULT_DMIBAR | 0x0004); // !!! = 0x00 + write8 (DEFAULT_DMIBAR | 0x0004, 0x01); + + read32 (DEFAULT_RCBA | 0x0050); // !!! = 0x01200654 + write32 (DEFAULT_RCBA | 0x0050, 0x01200654); + read32 (DEFAULT_RCBA | 0x0050); // !!! = 0x01200654 + write32 (DEFAULT_RCBA | 0x0050, 0x012a0654); + read32 (DEFAULT_RCBA | 0x0050); // !!! = 0x012a0654 + read8 (DEFAULT_RCBA | 0x1114); // !!! = 0x00 + write8 (DEFAULT_RCBA | 0x1114, 0x05); + read32 (DEFAULT_RCBA | 0x2014); // !!! = 0x80000011 + write32 (DEFAULT_RCBA | 0x2014, 0x80000019); + read32 (DEFAULT_RCBA | 0x2020); // !!! = 0x00000000 + write32 (DEFAULT_RCBA | 0x2020, 0x81000022); + read32 (DEFAULT_RCBA | 0x2020); // !!! = 0x81000022 + read32 (DEFAULT_RCBA | 0x2030); // !!! = 0x00000000 + write32 (DEFAULT_RCBA | 0x2030, 0x82000044); + read32 (DEFAULT_RCBA | 0x2030); // !!! = 0x82000044 + read32 (DEFAULT_RCBA | 0x2040); // !!! = 0x00000000 + write32 (DEFAULT_RCBA | 0x2040, 0x87000080); + read32 (DEFAULT_RCBA | 0x0050); // !!! = 0x012a0654 + write32 (DEFAULT_RCBA | 0x0050, 0x812a0654); + read32 (DEFAULT_RCBA | 0x0050); // !!! = 0x812a0654 + read16 (DEFAULT_RCBA | 0x201a); // !!! = 0x0000 + read16 (DEFAULT_RCBA | 0x2026); // !!! = 0x0000 + read16 (DEFAULT_RCBA | 0x2036); // !!! = 0x0000 + read16 (DEFAULT_RCBA | 0x2046); // !!! = 0x0000 + read16 (DEFAULT_DMIBAR | 0x001a); // !!! = 0x0000 + read16 (DEFAULT_DMIBAR | 0x0026); // !!! = 0x0000 + read16 (DEFAULT_DMIBAR | 0x0032); // !!! = 0x0000 + read16 (DEFAULT_DMIBAR | 0x003e); // !!! = 0x0000 +} + +void +early_pch_init_native (void) +{ + pcie_write_config8 (SOUTHBRIDGE, 0xa6, + pcie_read_config8 (SOUTHBRIDGE, 0xa6) | 2); + + write32 (DEFAULT_RCBA | 0x2088, 0x00109000); + read32 (DEFAULT_RCBA | 0x20ac); // !!! = 0x00000000 + write32 (DEFAULT_RCBA | 0x20ac, 0x40000000); + write32 (DEFAULT_RCBA | 0x100c, 0x01110000); + write8 (DEFAULT_RCBA | 0x2340, 0x1b); + read32 (DEFAULT_RCBA | 0x2314); // !!! = 0x0a080000 + write32 (DEFAULT_RCBA | 0x2314, 0x0a280000); + read32 (DEFAULT_RCBA | 0x2310); // !!! = 0xc809605b + write32 (DEFAULT_RCBA | 0x2310, 0xa809605b); + write32 (DEFAULT_RCBA | 0x2324, 0x00854c74); + read8 (DEFAULT_RCBA | 0x0400); // !!! = 0x00 + read32 (DEFAULT_RCBA | 0x2310); // !!! = 0xa809605b + write32 (DEFAULT_RCBA | 0x2310, 0xa809605b); + read32 (DEFAULT_RCBA | 0x2310); // !!! = 0xa809605b + write32 (DEFAULT_RCBA | 0x2310, 0xa809605b); + + write_2338 (0xea007f62, 0x00590133); + write_2338 (0xec007f62, 0x00590133); + write_2338 (0xec007f64, 0x59555588); + write_2338 (0xea0040b9, 0x0001051c); + write_2338 (0xeb0040a1, 0x800084ff); + write_2338 (0xec0040a1, 0x800084ff); + write_2338 (0xea004001, 0x00008400); + write_2338 (0xeb004002, 0x40201758); + write_2338 (0xec004002, 0x40201758); + write_2338 (0xea004002, 0x00601758); + write_2338 (0xea0040a1, 0x810084ff); + write_2338 (0xeb0040b1, 0x0001c598); + write_2338 (0xec0040b1, 0x0001c598); + write_2338 (0xeb0040b6, 0x0001c598); + write_2338 (0xea0000a9, 0x80ff969f); + write_2338 (0xea0001a9, 0x80ff969f); + write_2338 (0xeb0040b2, 0x0001c396); + write_2338 (0xeb0040b3, 0x0001c396); + write_2338 (0xec0040b2, 0x0001c396); + write_2338 (0xea0001a9, 0x80ff94ff); + write_2338 (0xea000151, 0x0088037f); + write_2338 (0xea0000a9, 0x80ff94ff); + write_2338 (0xea000051, 0x0088037f); + + write_2338 (0xea007f05, 0x00010642); + write_2338 (0xea0040b7, 0x0001c91c); + write_2338 (0xea0040b8, 0x0001c91c); + write_2338 (0xeb0040a1, 0x820084ff); + write_2338 (0xec0040a1, 0x820084ff); + write_2338 (0xea007f0a, 0xc2480000); + + write_2338 (0xec00404d, 0x1ff177f); + write_2338 (0xec000084, 0x5a600000); + write_2338 (0xec000184, 0x5a600000); + write_2338 (0xec000284, 0x5a600000); + write_2338 (0xec000384, 0x5a600000); + write_2338 (0xec000094, 0x000f0501); + write_2338 (0xec000194, 0x000f0501); + write_2338 (0xec000294, 0x000f0501); + write_2338 (0xec000394, 0x000f0501); + write_2338 (0xec000096, 0x00000001); + write_2338 (0xec000196, 0x00000001); + write_2338 (0xec000296, 0x00000001); + write_2338 (0xec000396, 0x00000001); + write_2338 (0xec000001, 0x00008c08); + write_2338 (0xec000101, 0x00008c08); + write_2338 (0xec000201, 0x00008c08); + write_2338 (0xec000301, 0x00008c08); + write_2338 (0xec0040b5, 0x0001c518); + write_2338 (0xec000087, 0x06077597); + write_2338 (0xec000187, 0x06077597); + write_2338 (0xec000287, 0x06077597); + write_2338 (0xec000387, 0x06077597); + write_2338 (0xea000050, 0x00bb0157); + write_2338 (0xea000150, 0x00bb0157); + write_2338 (0xec007f60, 0x77777d77); + write_2338 (0xea00008d, 0x01320000); + write_2338 (0xea00018d, 0x01320000); + write_2338 (0xec0007b2, 0x04514b5e); + write_2338 (0xec00078c, 0x40000200); + write_2338 (0xec000780, 0x02000020); + + init_dmi(); +} diff --git a/src/southbridge/intel/bd82x6x/early_thermal.c b/src/southbridge/intel/bd82x6x/early_thermal.c new file mode 100644 index 0000000..02ec9a7 --- /dev/null +++ b/src/southbridge/intel/bd82x6x/early_thermal.c @@ -0,0 +1,70 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2014 Vladimir Serbinenko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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 + */ + +#include <arch/io.h> +#include "pch.h" +#include "cpu/intel/model_206ax/model_206ax.h" +#include <cpu/x86/msr.h> + +/* Early thermal init, must be done prior to giving ME its memory + which is done at the end of raminit. */ +void early_thermal_init(void) +{ + device_t dev; + msr_t msr; + + dev = PCI_DEV(0x0, 0x1f, 0x6); + + /* Program address for temporary BAR. */ + pci_write_config32(dev, 0x40, 0x40000000); + pci_write_config32(dev, 0x44, 0x0); + + /* Activate temporary BAR. */ + pci_write_config32(dev, 0x40, + pci_read_config32(dev, 0x40) | 5); + + + write16 (0x40000004, 0x3a2b); + write8 (0x4000000c, 0xff); + write8 (0x4000000d, 0x00); + write8 (0x4000000e, 0x40); + write8 (0x40000082, 0x00); + write8 (0x40000001, 0xba); + + /* Perform init. */ + /* Configure TJmax. */ + msr = rdmsr(MSR_TEMPERATURE_TARGET); + write16(0x40000012, ((msr.lo >> 16) & 0xff) << 6); + /* Northbridge temperature slope and offset. */ + write16(0x40000016, 0x808c); + + write16 (0x40000014, 0xde87); + + /* Enable thermal data reporting, processor, PCH and northbridge. */ + write16(0x4000001a, (read16(0x4000001a) & ~0xf) | 0x10f0); + + /* Disable temporary BAR. */ + pci_write_config32(dev, 0x40, + pci_read_config32(dev, 0x40) & ~1); + pci_write_config32(dev, 0x40, 0); + + write32 (DEFAULT_RCBA | 0x38b0, + (read32 (DEFAULT_RCBA | 0x38b0) & 0xffff8003) | 0x403c); +} diff --git a/src/southbridge/intel/bd82x6x/pch.h b/src/southbridge/intel/bd82x6x/pch.h index 90de855..83128e2 100644 --- a/src/southbridge/intel/bd82x6x/pch.h +++ b/src/southbridge/intel/bd82x6x/pch.h @@ -74,6 +74,8 @@ void enable_smbus(void); void enable_usb_bar(void); int smbus_read_byte(unsigned device, unsigned address); int early_spi_read(u32 offset, u32 size, u8 *buffer); +void early_thermal_init(void); +void early_pch_init_native(void); #endif #endif diff --git a/src/southbridge/intel/bd82x6x/smi.c b/src/southbridge/intel/bd82x6x/smi.c index 0166edf..a20232e 100644 --- a/src/southbridge/intel/bd82x6x/smi.c +++ b/src/southbridge/intel/bd82x6x/smi.c @@ -29,10 +29,7 @@ #include <cpu/x86/smm.h> #include <string.h> #include "pch.h" - -#if CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE || CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE #include "northbridge/intel/sandybridge/sandybridge.h" -#endif extern unsigned char _binary_smm_start; extern unsigned char _binary_smm_end; diff --git a/src/southbridge/intel/bd82x6x/usb_ehci.c b/src/southbridge/intel/bd82x6x/usb_ehci.c index 78f92d9..97f20bd 100644 --- a/src/southbridge/intel/bd82x6x/usb_ehci.c +++ b/src/southbridge/intel/bd82x6x/usb_ehci.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <kconfig.h> #include <console/console.h> #include <device/device.h> #include <device/pci.h> @@ -36,11 +37,43 @@ static void usb_ehci_init(struct device *dev) RCBA32(0x35b0) = reg32; printk(BIOS_DEBUG, "EHCI: Setting up controller.. "); + + /* For others, done in MRC. */ +#if IS_ENABLED(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE) + pci_write_config32(dev, 0x84, 0x930c8811); + pci_write_config32(dev, 0x88, 0x24000d30); + pci_write_config32(dev, 0xf4, 0x80408588); + pci_write_config32(dev, 0xf4, 0x80808588); + pci_write_config32(dev, 0xf4, 0x00808588); + pci_write_config32(dev, 0xfc, 0x205b1708); +#endif + reg32 = pci_read_config32(dev, PCI_COMMAND); reg32 |= PCI_COMMAND_MASTER; //reg32 |= PCI_COMMAND_SERR; pci_write_config32(dev, PCI_COMMAND, reg32); + /* For others, done in MRC. */ +#if IS_ENABLED(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE) + struct resource *res; + u8 access_cntl; + + access_cntl = pci_read_config8(dev, 0x80); + + /* Enable writes to protected registers. */ + pci_write_config8(dev, 0x80, access_cntl | 1); + + res = find_resource(dev, PCI_BASE_ADDRESS_0); + if (res) { + /* Number of ports and companion controllers. */ + reg32 = read32(res->base + 4); + write32(res->base + 4, (reg32 & 0xfff00000) | 3); + } + + /* Restore protection. */ + pci_write_config8(dev, 0x80, access_cntl); +#endif + printk(BIOS_DEBUG, "done.\n"); }
1
0
0
0
Patch set updated for coreboot: 98d3ad7 x230: Deploy VBT
by Vladimir Serbinenko
29 Jul '14
29 Jul '14
Vladimir Serbinenko (phcoder(a)gmail.com) just uploaded a new patch set to gerrit, which you can find at
http://review.coreboot.org/5396
-gerrit commit 98d3ad75064595832e61d3fac3694f8b6139cc6b Author: Vladimir Serbinenko <phcoder(a)gmail.com> Date: Sun Feb 23 00:13:56 2014 +0100 x230: Deploy VBT Change-Id: Ide31a56bfdbc31cd3b87993dfb4ed8ef0107cdba Signed-off-by: Vladimir Serbinenko <phcoder(a)gmail.com> --- src/drivers/intel/gma/intel_bios.h | 733 +++++++++++++++++++++ src/northbridge/intel/sandybridge/gma.c | 1 + .../intel/sandybridge/gma_ivybridge_lvds.c | 82 +++ 3 files changed, 816 insertions(+) diff --git a/src/drivers/intel/gma/intel_bios.h b/src/drivers/intel/gma/intel_bios.h new file mode 100644 index 0000000..36426d8 --- /dev/null +++ b/src/drivers/intel/gma/intel_bios.h @@ -0,0 +1,733 @@ +/* + * Copyright © 2006 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + * Eric Anholt <eric(a)anholt.net> + * + */ + +#ifndef _I830_BIOS_H_ +#define _I830_BIOS_H_ + +struct vbt_header { + u8 signature[20]; /**< Always starts with 'VBT$' */ + u16 version; /**< decimal */ + u16 header_size; /**< in bytes */ + u16 vbt_size; /**< in bytes */ + u8 vbt_checksum; + u8 reserved0; + u32 bdb_offset; /**< from beginning of VBT */ + u32 aim_offset[4]; /**< from beginning of VBT */ +} __attribute__((packed)); + +struct bdb_header { + u8 signature[16]; /**< Always 'BIOS_DATA_BLOCK' */ + u16 version; /**< decimal */ + u16 header_size; /**< in bytes */ + u16 bdb_size; /**< in bytes */ +}; + +/* strictly speaking, this is a "skip" block, but it has interesting info */ +struct vbios_data { + u8 type; /* 0 == desktop, 1 == mobile */ + u8 relstage; + u8 chipset; + u8 lvds_present:1; + u8 tv_present:1; + u8 rsvd2:6; /* finish byte */ + u8 rsvd3[4]; + u8 signon[155]; + u8 copyright[61]; + u16 code_segment; + u8 dos_boot_mode; + u8 bandwidth_percent; + u8 rsvd4; /* popup memory size */ + u8 resize_pci_bios; + u8 rsvd5; /* is crt already on ddc2 */ +} __attribute__((packed)); + +/* + * There are several types of BIOS data blocks (BDBs), each block has + * an ID and size in the first 3 bytes (ID in first, size in next 2). + * Known types are listed below. + */ +#define BDB_GENERAL_FEATURES 1 +#define BDB_GENERAL_DEFINITIONS 2 +#define BDB_OLD_TOGGLE_LIST 3 +#define BDB_MODE_SUPPORT_LIST 4 +#define BDB_GENERIC_MODE_TABLE 5 +#define BDB_EXT_MMIO_REGS 6 +#define BDB_SWF_IO 7 +#define BDB_SWF_MMIO 8 +#define BDB_DOT_CLOCK_TABLE 9 +#define BDB_MODE_REMOVAL_TABLE 10 +#define BDB_CHILD_DEVICE_TABLE 11 +#define BDB_DRIVER_FEATURES 12 +#define BDB_DRIVER_PERSISTENCE 13 +#define BDB_EXT_TABLE_PTRS 14 +#define BDB_DOT_CLOCK_OVERRIDE 15 +#define BDB_DISPLAY_SELECT 16 +/* 17 rsvd */ +#define BDB_DRIVER_ROTATION 18 +#define BDB_DISPLAY_REMOVE 19 +#define BDB_OEM_CUSTOM 20 +#define BDB_EFP_LIST 21 /* workarounds for VGA hsync/vsync */ +#define BDB_SDVO_LVDS_OPTIONS 22 +#define BDB_SDVO_PANEL_DTDS 23 +#define BDB_SDVO_LVDS_PNP_IDS 24 +#define BDB_SDVO_LVDS_POWER_SEQ 25 +#define BDB_TV_OPTIONS 26 +#define BDB_EDP 27 +#define BDB_LVDS_OPTIONS 40 +#define BDB_LVDS_LFP_DATA_PTRS 41 +#define BDB_LVDS_LFP_DATA 42 +#define BDB_LVDS_BACKLIGHT 43 +#define BDB_LVDS_POWER 44 +#define BDB_MIPI 50 +#define BDB_SKIP 254 /* VBIOS private block, ignore */ + +struct bdb_general_features { + /* bits 1 */ + u8 panel_fitting:2; + u8 flexaim:1; + u8 msg_enable:1; + u8 clear_screen:3; + u8 color_flip:1; + + /* bits 2 */ + u8 download_ext_vbt:1; + u8 enable_ssc:1; + u8 ssc_freq:1; + u8 enable_lfp_on_override:1; + u8 disable_ssc_ddt:1; + u8 rsvd7:1; + u8 display_clock_mode:1; + u8 rsvd8:1; /* finish byte */ + + /* bits 3 */ + u8 disable_smooth_vision:1; + u8 single_dvi:1; + u8 rsvd9:1; + u8 fdi_rx_polarity_inverted:1; + u8 rsvd10:4; /* finish byte */ + + /* bits 4 */ + u8 legacy_monitor_detect; + + /* bits 5 */ + u8 int_crt_support:1; + u8 int_tv_support:1; + u8 int_efp_support:1; + u8 dp_ssc_enb:1; /* PCH attached eDP supports SSC */ + u8 dp_ssc_freq:1; /* SSC freq for PCH attached eDP */ + u8 rsvd11:3; /* finish byte */ +} __attribute__((packed)); + +/* pre-915 */ +#define GPIO_PIN_DVI_LVDS 0x03 /* "DVI/LVDS DDC GPIO pins" */ +#define GPIO_PIN_ADD_I2C 0x05 /* "ADDCARD I2C GPIO pins" */ +#define GPIO_PIN_ADD_DDC 0x04 /* "ADDCARD DDC GPIO pins" */ +#define GPIO_PIN_ADD_DDC_I2C 0x06 /* "ADDCARD DDC/I2C GPIO pins" */ + +/* Pre 915 */ +#define DEVICE_TYPE_NONE 0x00 +#define DEVICE_TYPE_CRT 0x01 +#define DEVICE_TYPE_TV 0x09 +#define DEVICE_TYPE_EFP 0x12 +#define DEVICE_TYPE_LFP 0x22 +/* On 915+ */ +#define DEVICE_TYPE_CRT_DPMS 0x6001 +#define DEVICE_TYPE_CRT_DPMS_HOTPLUG 0x4001 +#define DEVICE_TYPE_TV_COMPOSITE 0x0209 +#define DEVICE_TYPE_TV_MACROVISION 0x0289 +#define DEVICE_TYPE_TV_RF_COMPOSITE 0x020c +#define DEVICE_TYPE_TV_SVIDEO_COMPOSITE 0x0609 +#define DEVICE_TYPE_TV_SCART 0x0209 +#define DEVICE_TYPE_TV_CODEC_HOTPLUG_PWR 0x6009 +#define DEVICE_TYPE_EFP_HOTPLUG_PWR 0x6012 +#define DEVICE_TYPE_EFP_DVI_HOTPLUG_PWR 0x6052 +#define DEVICE_TYPE_EFP_DVI_I 0x6053 +#define DEVICE_TYPE_EFP_DVI_D_DUAL 0x6152 +#define DEVICE_TYPE_EFP_DVI_D_HDCP 0x60d2 +#define DEVICE_TYPE_OPENLDI_HOTPLUG_PWR 0x6062 +#define DEVICE_TYPE_OPENLDI_DUALPIX 0x6162 +#define DEVICE_TYPE_LFP_PANELLINK 0x5012 +#define DEVICE_TYPE_LFP_CMOS_PWR 0x5042 +#define DEVICE_TYPE_LFP_LVDS_PWR 0x5062 +#define DEVICE_TYPE_LFP_LVDS_DUAL 0x5162 +#define DEVICE_TYPE_LFP_LVDS_DUAL_HDCP 0x51e2 + +#define DEVICE_CFG_NONE 0x00 +#define DEVICE_CFG_12BIT_DVOB 0x01 +#define DEVICE_CFG_12BIT_DVOC 0x02 +#define DEVICE_CFG_24BIT_DVOBC 0x09 +#define DEVICE_CFG_24BIT_DVOCB 0x0a +#define DEVICE_CFG_DUAL_DVOB 0x11 +#define DEVICE_CFG_DUAL_DVOC 0x12 +#define DEVICE_CFG_DUAL_DVOBC 0x13 +#define DEVICE_CFG_DUAL_LINK_DVOBC 0x19 +#define DEVICE_CFG_DUAL_LINK_DVOCB 0x1a + +#define DEVICE_WIRE_NONE 0x00 +#define DEVICE_WIRE_DVOB 0x01 +#define DEVICE_WIRE_DVOC 0x02 +#define DEVICE_WIRE_DVOBC 0x03 +#define DEVICE_WIRE_DVOBB 0x05 +#define DEVICE_WIRE_DVOCC 0x06 +#define DEVICE_WIRE_DVOB_MASTER 0x0d +#define DEVICE_WIRE_DVOC_MASTER 0x0e + +#define DEVICE_PORT_DVOA 0x00 /* none on 845+ */ +#define DEVICE_PORT_DVOB 0x01 +#define DEVICE_PORT_DVOC 0x02 + +/* We used to keep this struct but without any version control. We should avoid + * using it in the future, but it should be safe to keep using it in the old + * code. */ +struct old_child_dev_config { + u16 handle; + u16 device_type; + u8 device_id[10]; /* ascii string */ + u16 addin_offset; + u8 dvo_port; /* See Device_PORT_* above */ + u8 i2c_pin; + u8 slave_addr; + u8 ddc_pin; + u16 edid_ptr; + u8 dvo_cfg; /* See DEVICE_CFG_* above */ + u8 dvo2_port; + u8 i2c2_pin; + u8 slave2_addr; + u8 ddc2_pin; + u8 capabilities; + u8 dvo_wiring;/* See DEVICE_WIRE_* above */ + u8 dvo2_wiring; + u16 extended_type; + u8 dvo_function; +} __attribute__((packed)); + +/* This one contains field offsets that are known to be common for all BDB + * versions. Notice that the meaning of the contents contents may still change, + * but at least the offsets are consistent. */ +struct common_child_dev_config { + u16 handle; + u16 device_type; + u8 not_common1[12]; + u8 dvo_port; + u8 not_common2[2]; + u8 ddc_pin; + u16 edid_ptr; +} __attribute__((packed)); + +/* This field changes depending on the BDB version, so the most reliable way to + * read it is by checking the BDB version and reading the raw pointer. */ +union child_device_config { + /* This one is safe to be used anywhere, but the code should still check + * the BDB version. */ + u8 raw[33]; + /* This one should only be kept for legacy code. */ + struct old_child_dev_config old; + /* This one should also be safe to use anywhere, even without version + * checks. */ + struct common_child_dev_config common; +}; + +struct bdb_general_definitions { + /* DDC GPIO */ + u8 crt_ddc_gmbus_pin; + + /* DPMS bits */ + u8 dpms_acpi:1; + u8 skip_boot_crt_detect:1; + u8 dpms_aim:1; + u8 rsvd1:5; /* finish byte */ + + /* boot device bits */ + u8 boot_display[2]; + u8 child_dev_size; + + /* + * Device info: + * If TV is present, it'll be at devices[0]. + * LVDS will be next, either devices[0] or [1], if present. + * On some platforms the number of device is 6. But could be as few as + * 4 if both TV and LVDS are missing. + * And the device num is related with the size of general definition + * block. It is obtained by using the following formula: + * number = (block_size - sizeof(bdb_general_definitions))/ + * sizeof(child_device_config); + */ + union child_device_config devices[0]; +} __attribute__((packed)); + +struct bdb_lvds_options { + u8 panel_type; + u8 rsvd1; + /* LVDS capabilities, stored in a dword */ + u8 pfit_mode:2; + u8 pfit_text_mode_enhanced:1; + u8 pfit_gfx_mode_enhanced:1; + u8 pfit_ratio_auto:1; + u8 pixel_dither:1; + u8 lvds_edid:1; + u8 rsvd2:1; + u8 rsvd4; +} __attribute__((packed)); + +/* LFP pointer table contains entries to the struct below */ +struct bdb_lvds_lfp_data_ptr { + u16 fp_timing_offset; /* offsets are from start of bdb */ + u8 fp_table_size; + u16 dvo_timing_offset; + u8 dvo_table_size; + u16 panel_pnp_id_offset; + u8 pnp_table_size; +} __attribute__((packed)); + +struct bdb_lvds_lfp_data_ptrs { + u8 lvds_entries; /* followed by one or more lvds_data_ptr structs */ + struct bdb_lvds_lfp_data_ptr ptr[16]; +} __attribute__((packed)); + +/* LFP data has 3 blocks per entry */ +struct lvds_fp_timing { + u16 x_res; + u16 y_res; + u32 lvds_reg; + u32 lvds_reg_val; + u32 pp_on_reg; + u32 pp_on_reg_val; + u32 pp_off_reg; + u32 pp_off_reg_val; + u32 pp_cycle_reg; + u32 pp_cycle_reg_val; + u32 pfit_reg; + u32 pfit_reg_val; + u16 terminator; +} __attribute__((packed)); + +struct lvds_dvo_timing { + u16 clock; /**< In 10khz */ + u8 hactive_lo; + u8 hblank_lo; + u8 hblank_hi:4; + u8 hactive_hi:4; + u8 vactive_lo; + u8 vblank_lo; + u8 vblank_hi:4; + u8 vactive_hi:4; + u8 hsync_off_lo; + u8 hsync_pulse_width; + u8 vsync_pulse_width:4; + u8 vsync_off:4; + u8 rsvd0:6; + u8 hsync_off_hi:2; + u8 h_image; + u8 v_image; + u8 max_hv; + u8 h_border; + u8 v_border; + u8 rsvd1:3; + u8 digital:2; + u8 vsync_positive:1; + u8 hsync_positive:1; + u8 rsvd2:1; +} __attribute__((packed)); + +struct lvds_pnp_id { + u16 mfg_name; + u16 product_code; + u32 serial; + u8 mfg_week; + u8 mfg_year; +} __attribute__((packed)); + +struct bdb_lvds_lfp_data_entry { + struct lvds_fp_timing fp_timing; + struct lvds_dvo_timing dvo_timing; + struct lvds_pnp_id pnp_id; +} __attribute__((packed)); + +struct bdb_lvds_lfp_data { + struct bdb_lvds_lfp_data_entry data[16]; +} __attribute__((packed)); + +struct aimdb_header { + char signature[16]; + char oem_device[20]; + u16 aimdb_version; + u16 aimdb_header_size; + u16 aimdb_size; +} __attribute__((packed)); + +struct aimdb_block { + u8 aimdb_id; + u16 aimdb_size; +} __attribute__((packed)); + +struct vch_panel_data { + u16 fp_timing_offset; + u8 fp_timing_size; + u16 dvo_timing_offset; + u8 dvo_timing_size; + u16 text_fitting_offset; + u8 text_fitting_size; + u16 graphics_fitting_offset; + u8 graphics_fitting_size; +} __attribute__((packed)); + +struct vch_bdb_22 { + struct aimdb_block aimdb_block; + struct vch_panel_data panels[16]; +} __attribute__((packed)); + +struct bdb_sdvo_lvds_options { + u8 panel_backlight; + u8 h40_set_panel_type; + u8 panel_type; + u8 ssc_clk_freq; + u16 als_low_trip; + u16 als_high_trip; + u8 sclalarcoeff_tab_row_num; + u8 sclalarcoeff_tab_row_size; + u8 coefficient[8]; + u8 panel_misc_bits_1; + u8 panel_misc_bits_2; + u8 panel_misc_bits_3; + u8 panel_misc_bits_4; +} __attribute__((packed)); + + +#define BDB_DRIVER_FEATURE_NO_LVDS 0 +#define BDB_DRIVER_FEATURE_INT_LVDS 1 +#define BDB_DRIVER_FEATURE_SDVO_LVDS 2 +#define BDB_DRIVER_FEATURE_EDP 3 + +struct bdb_driver_features { + u8 boot_dev_algorithm:1; + u8 block_display_switch:1; + u8 allow_display_switch:1; + u8 hotplug_dvo:1; + u8 dual_view_zoom:1; + u8 int15h_hook:1; + u8 sprite_in_clone:1; + u8 primary_lfp_id:1; + + u16 boot_mode_x; + u16 boot_mode_y; + u8 boot_mode_bpp; + u8 boot_mode_refresh; + + u16 enable_lfp_primary:1; + u16 selective_mode_pruning:1; + u16 dual_frequency:1; + u16 render_clock_freq:1; /* 0: high freq; 1: low freq */ + u16 nt_clone_support:1; + u16 power_scheme_ui:1; /* 0: CUI; 1: 3rd party */ + u16 sprite_display_assign:1; /* 0: secondary; 1: primary */ + u16 cui_aspect_scaling:1; + u16 preserve_aspect_ratio:1; + u16 sdvo_device_power_down:1; + u16 crt_hotplug:1; + u16 lvds_config:2; + u16 tv_hotplug:1; + u16 hdmi_config:2; + + u8 static_display:1; + u8 reserved2:7; + u16 legacy_crt_max_x; + u16 legacy_crt_max_y; + u8 legacy_crt_max_refresh; + + u8 hdmi_termination; + u8 custom_vbt_version; +} __attribute__((packed)); + +#define EDP_18BPP 0 +#define EDP_24BPP 1 +#define EDP_30BPP 2 +#define EDP_RATE_1_62 0 +#define EDP_RATE_2_7 1 +#define EDP_LANE_1 0 +#define EDP_LANE_2 1 +#define EDP_LANE_4 3 +#define EDP_PREEMPHASIS_NONE 0 +#define EDP_PREEMPHASIS_3_5dB 1 +#define EDP_PREEMPHASIS_6dB 2 +#define EDP_PREEMPHASIS_9_5dB 3 +#define EDP_VSWING_0_4V 0 +#define EDP_VSWING_0_6V 1 +#define EDP_VSWING_0_8V 2 +#define EDP_VSWING_1_2V 3 + +struct edp_power_seq { + u16 t1_t3; + u16 t8; + u16 t9; + u16 t10; + u16 t11_t12; +} __attribute__ ((packed)); + +struct edp_link_params { + u8 rate:4; + u8 lanes:4; + u8 preemphasis:4; + u8 vswing:4; +} __attribute__ ((packed)); + +struct bdb_edp { + struct edp_power_seq power_seqs[16]; + u32 color_depth; + struct edp_link_params link_params[16]; + u32 sdrrs_msa_timing_delay; + + /* ith bit indicates enabled/disabled for (i+1)th panel */ + u16 edp_s3d_feature; + u16 edp_t3_optimization; +} __attribute__ ((packed)); + +/* + * Driver<->VBIOS interaction occurs through scratch bits in + * GR18 & SWF*. + */ + +/* GR18 bits are set on display switch and hotkey events */ +#define GR18_DRIVER_SWITCH_EN (1<<7) /* 0: VBIOS control, 1: driver control */ +#define GR18_HOTKEY_MASK 0x78 /* See also SWF4 15:0 */ +#define GR18_HK_NONE (0x0<<3) +#define GR18_HK_LFP_STRETCH (0x1<<3) +#define GR18_HK_TOGGLE_DISP (0x2<<3) +#define GR18_HK_DISP_SWITCH (0x4<<3) /* see SWF14 15:0 for what to enable */ +#define GR18_HK_POPUP_DISABLED (0x6<<3) +#define GR18_HK_POPUP_ENABLED (0x7<<3) +#define GR18_HK_PFIT (0x8<<3) +#define GR18_HK_APM_CHANGE (0xa<<3) +#define GR18_HK_MULTIPLE (0xc<<3) +#define GR18_USER_INT_EN (1<<2) +#define GR18_A0000_FLUSH_EN (1<<1) +#define GR18_SMM_EN (1<<0) + +/* Set by driver, cleared by VBIOS */ +#define SWF00_YRES_SHIFT 16 +#define SWF00_XRES_SHIFT 0 +#define SWF00_RES_MASK 0xffff + +/* Set by VBIOS at boot time and driver at runtime */ +#define SWF01_TV2_FORMAT_SHIFT 8 +#define SWF01_TV1_FORMAT_SHIFT 0 +#define SWF01_TV_FORMAT_MASK 0xffff + +#define SWF10_VBIOS_BLC_I2C_EN (1<<29) +#define SWF10_GTT_OVERRIDE_EN (1<<28) +#define SWF10_LFP_DPMS_OVR (1<<27) /* override DPMS on display switch */ +#define SWF10_ACTIVE_TOGGLE_LIST_MASK (7<<24) +#define SWF10_OLD_TOGGLE 0x0 +#define SWF10_TOGGLE_LIST_1 0x1 +#define SWF10_TOGGLE_LIST_2 0x2 +#define SWF10_TOGGLE_LIST_3 0x3 +#define SWF10_TOGGLE_LIST_4 0x4 +#define SWF10_PANNING_EN (1<<23) +#define SWF10_DRIVER_LOADED (1<<22) +#define SWF10_EXTENDED_DESKTOP (1<<21) +#define SWF10_EXCLUSIVE_MODE (1<<20) +#define SWF10_OVERLAY_EN (1<<19) +#define SWF10_PLANEB_HOLDOFF (1<<18) +#define SWF10_PLANEA_HOLDOFF (1<<17) +#define SWF10_VGA_HOLDOFF (1<<16) +#define SWF10_ACTIVE_DISP_MASK 0xffff +#define SWF10_PIPEB_LFP2 (1<<15) +#define SWF10_PIPEB_EFP2 (1<<14) +#define SWF10_PIPEB_TV2 (1<<13) +#define SWF10_PIPEB_CRT2 (1<<12) +#define SWF10_PIPEB_LFP (1<<11) +#define SWF10_PIPEB_EFP (1<<10) +#define SWF10_PIPEB_TV (1<<9) +#define SWF10_PIPEB_CRT (1<<8) +#define SWF10_PIPEA_LFP2 (1<<7) +#define SWF10_PIPEA_EFP2 (1<<6) +#define SWF10_PIPEA_TV2 (1<<5) +#define SWF10_PIPEA_CRT2 (1<<4) +#define SWF10_PIPEA_LFP (1<<3) +#define SWF10_PIPEA_EFP (1<<2) +#define SWF10_PIPEA_TV (1<<1) +#define SWF10_PIPEA_CRT (1<<0) + +#define SWF11_MEMORY_SIZE_SHIFT 16 +#define SWF11_SV_TEST_EN (1<<15) +#define SWF11_IS_AGP (1<<14) +#define SWF11_DISPLAY_HOLDOFF (1<<13) +#define SWF11_DPMS_REDUCED (1<<12) +#define SWF11_IS_VBE_MODE (1<<11) +#define SWF11_PIPEB_ACCESS (1<<10) /* 0 here means pipe a */ +#define SWF11_DPMS_MASK 0x07 +#define SWF11_DPMS_OFF (1<<2) +#define SWF11_DPMS_SUSPEND (1<<1) +#define SWF11_DPMS_STANDBY (1<<0) +#define SWF11_DPMS_ON 0 + +#define SWF14_GFX_PFIT_EN (1<<31) +#define SWF14_TEXT_PFIT_EN (1<<30) +#define SWF14_LID_STATUS_CLOSED (1<<29) /* 0 here means open */ +#define SWF14_POPUP_EN (1<<28) +#define SWF14_DISPLAY_HOLDOFF (1<<27) +#define SWF14_DISP_DETECT_EN (1<<26) +#define SWF14_DOCKING_STATUS_DOCKED (1<<25) /* 0 here means undocked */ +#define SWF14_DRIVER_STATUS (1<<24) +#define SWF14_OS_TYPE_WIN9X (1<<23) +#define SWF14_OS_TYPE_WINNT (1<<22) +/* 21:19 rsvd */ +#define SWF14_PM_TYPE_MASK 0x00070000 +#define SWF14_PM_ACPI_VIDEO (0x4 << 16) +#define SWF14_PM_ACPI (0x3 << 16) +#define SWF14_PM_APM_12 (0x2 << 16) +#define SWF14_PM_APM_11 (0x1 << 16) +#define SWF14_HK_REQUEST_MASK 0x0000ffff /* see GR18 6:3 for event type */ + /* if GR18 indicates a display switch */ +#define SWF14_DS_PIPEB_LFP2_EN (1<<15) +#define SWF14_DS_PIPEB_EFP2_EN (1<<14) +#define SWF14_DS_PIPEB_TV2_EN (1<<13) +#define SWF14_DS_PIPEB_CRT2_EN (1<<12) +#define SWF14_DS_PIPEB_LFP_EN (1<<11) +#define SWF14_DS_PIPEB_EFP_EN (1<<10) +#define SWF14_DS_PIPEB_TV_EN (1<<9) +#define SWF14_DS_PIPEB_CRT_EN (1<<8) +#define SWF14_DS_PIPEA_LFP2_EN (1<<7) +#define SWF14_DS_PIPEA_EFP2_EN (1<<6) +#define SWF14_DS_PIPEA_TV2_EN (1<<5) +#define SWF14_DS_PIPEA_CRT2_EN (1<<4) +#define SWF14_DS_PIPEA_LFP_EN (1<<3) +#define SWF14_DS_PIPEA_EFP_EN (1<<2) +#define SWF14_DS_PIPEA_TV_EN (1<<1) +#define SWF14_DS_PIPEA_CRT_EN (1<<0) + /* if GR18 indicates a panel fitting request */ +#define SWF14_PFIT_EN (1<<0) /* 0 means disable */ + /* if GR18 indicates an APM change request */ +#define SWF14_APM_HIBERNATE 0x4 +#define SWF14_APM_SUSPEND 0x3 +#define SWF14_APM_STANDBY 0x1 +#define SWF14_APM_RESTORE 0x0 + +/* Add the device class for LFP, TV, HDMI */ +#define DEVICE_TYPE_INT_LFP 0x1022 +#define DEVICE_TYPE_INT_TV 0x1009 +#define DEVICE_TYPE_HDMI 0x60D2 +#define DEVICE_TYPE_DP 0x68C6 +#define DEVICE_TYPE_eDP 0x78C6 + +#define DEVICE_TYPE_CLASS_EXTENSION (1 << 15) +#define DEVICE_TYPE_POWER_MANAGEMENT (1 << 14) +#define DEVICE_TYPE_HOTPLUG_SIGNALING (1 << 13) +#define DEVICE_TYPE_INTERNAL_CONNECTOR (1 << 12) +#define DEVICE_TYPE_NOT_HDMI_OUTPUT (1 << 11) +#define DEVICE_TYPE_MIPI_OUTPUT (1 << 10) +#define DEVICE_TYPE_COMPOSITE_OUTPUT (1 << 9) +#define DEVICE_TYPE_DUAL_CHANNEL (1 << 8) +#define DEVICE_TYPE_HIGH_SPEED_LINK (1 << 6) +#define DEVICE_TYPE_LVDS_SINGALING (1 << 5) +#define DEVICE_TYPE_TMDS_DVI_SIGNALING (1 << 4) +#define DEVICE_TYPE_VIDEO_SIGNALING (1 << 3) +#define DEVICE_TYPE_DISPLAYPORT_OUTPUT (1 << 2) +#define DEVICE_TYPE_DIGITAL_OUTPUT (1 << 1) +#define DEVICE_TYPE_ANALOG_OUTPUT (1 << 0) + +/* + * Bits we care about when checking for DEVICE_TYPE_eDP + * Depending on the system, the other bits may or may not + * be set for eDP outputs. + */ +#define DEVICE_TYPE_eDP_BITS \ + (DEVICE_TYPE_INTERNAL_CONNECTOR | \ + DEVICE_TYPE_NOT_HDMI_OUTPUT | \ + DEVICE_TYPE_MIPI_OUTPUT | \ + DEVICE_TYPE_COMPOSITE_OUTPUT | \ + DEVICE_TYPE_DUAL_CHANNEL | \ + DEVICE_TYPE_LVDS_SINGALING | \ + DEVICE_TYPE_TMDS_DVI_SIGNALING | \ + DEVICE_TYPE_VIDEO_SIGNALING | \ + DEVICE_TYPE_DISPLAYPORT_OUTPUT | \ + DEVICE_TYPE_DIGITAL_OUTPUT | \ + DEVICE_TYPE_ANALOG_OUTPUT) + +/* define the DVO port for HDMI output type */ +#define DVO_B 1 +#define DVO_C 2 +#define DVO_D 3 + +/* define the PORT for DP output type */ +#define PORT_IDPB 7 +#define PORT_IDPC 8 +#define PORT_IDPD 9 + +/* Possible values for the "DVO Port" field for versions >= 155: */ +#define DVO_PORT_HDMIA 0 +#define DVO_PORT_HDMIB 1 +#define DVO_PORT_HDMIC 2 +#define DVO_PORT_HDMID 3 +#define DVO_PORT_LVDS 4 +#define DVO_PORT_TV 5 +#define DVO_PORT_CRT 6 +#define DVO_PORT_DPB 7 +#define DVO_PORT_DPC 8 +#define DVO_PORT_DPD 9 +#define DVO_PORT_DPA 10 + +/* MIPI DSI panel info */ +struct bdb_mipi { + u16 panel_id; + u16 bridge_revision; + + /* General params */ + u32 dithering:1; + u32 bpp_pixel_format:1; + u32 rsvd1:1; + u32 dphy_valid:1; + u32 resvd2:28; + + u16 port_info; + u16 rsvd3:2; + u16 num_lanes:2; + u16 rsvd4:12; + + /* DSI config */ + u16 virt_ch_num:2; + u16 vtm:2; + u16 rsvd5:12; + + u32 dsi_clock; + u32 bridge_ref_clk; + u16 rsvd_pwr; + + /* Dphy Params */ + u32 prepare_cnt:5; + u32 rsvd6:3; + u32 clk_zero_cnt:8; + u32 trail_cnt:5; + u32 rsvd7:3; + u32 exit_zero_cnt:6; + u32 rsvd8:2; + + u32 hl_switch_cnt; + u32 lp_byte_clk; + u32 clk_lane_switch_cnt; +} __attribute__((packed)); + +#endif /* _I830_BIOS_H_ */ diff --git a/src/northbridge/intel/sandybridge/gma.c b/src/northbridge/intel/sandybridge/gma.c index d271a1a..a01fe9f 100644 --- a/src/northbridge/intel/sandybridge/gma.c +++ b/src/northbridge/intel/sandybridge/gma.c @@ -21,6 +21,7 @@ #include <console/console.h> #include <bootmode.h> #include <delay.h> +#include <string.h> #include <device/device.h> #include <device/pci.h> #include <device/pci_ids.h> diff --git a/src/northbridge/intel/sandybridge/gma_ivybridge_lvds.c b/src/northbridge/intel/sandybridge/gma_ivybridge_lvds.c index 1f53a74..ff877ff 100644 --- a/src/northbridge/intel/sandybridge/gma_ivybridge_lvds.c +++ b/src/northbridge/intel/sandybridge/gma_ivybridge_lvds.c @@ -26,13 +26,64 @@ #include <drivers/intel/gma/edid.h> #include <drivers/intel/gma/i915.h> +#include <drivers/intel/gma/intel_bios.h> #include "gma.h" #include "chip.h" #include <pc80/vga.h> #include <pc80/vga_io.h> +#include <device/pci_def.h> +#include <device/pci_rom.h> #if IS_ENABLED(CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT) +static size_t generate_vbt(const struct northbridge_intel_sandybridge_config *conf, + void *vbt) +{ + struct vbt_header *head = vbt; + struct bdb_header *bdb_head; + struct bdb_general_features *genfeat; + u8 *ptr; + + memset(head, 0, sizeof (*head)); + + memcpy(head->signature, "$VBT SNB/IVB-MOBILE ", 20); + head->version = 100; + head->header_size = sizeof (*head); + head->bdb_offset = sizeof (*head); + + bdb_head = (struct bdb_header *) (head + 1); + memset(bdb_head, 0, sizeof (*bdb_head)); + memcpy(bdb_head->signature, "BIOS_DATA_BLOCK ", 16); + bdb_head->version = 0xa8; + bdb_head->header_size = sizeof (*bdb_head); + + ptr = (u8 *) (bdb_head + 1); + + ptr[0] = BDB_GENERAL_FEATURES; + ptr[1] = sizeof (*genfeat); + ptr[2] = sizeof (*genfeat) >> 8; + ptr += 3; + + genfeat = (struct bdb_general_features *) ptr; + memset(genfeat, 0, sizeof (*genfeat)); + genfeat->panel_fitting = 3; + genfeat->flexaim = 1; + genfeat->download_ext_vbt = 1; + genfeat->enable_ssc = conf->gpu_use_spread_spectrum_clock; + genfeat->ssc_freq = !conf->gpu_link_frequency_270_mhz; + genfeat->rsvd10 = 0x4; + genfeat->legacy_monitor_detect = 1; + genfeat->int_crt_support = 1; + genfeat->dp_ssc_enb = 1; + + ptr += sizeof (*genfeat); + + bdb_head->bdb_size = ptr - (u8 *)bdb_head; + head->vbt_size = ptr - (u8 *)head; + head->vbt_checksum = 0; + return ptr - (u8 *)head; +} + static void link_train(u32 mmio) { write32(mmio+0xf000c,0x40); @@ -509,6 +560,37 @@ int i915lightup(const struct northbridge_intel_sandybridge_config *info, memset ((void *) lfb, 0, edid.x_resolution * edid.y_resolution * 4); set_vbe_mode_info_valid(&edid, lfb); #endif + + /* Linux relies on VBT for panel info. */ + optionrom_header_t *oh = (void *)PCI_VGA_RAM_IMAGE_START; + optionrom_pcir_t *pcir; + size_t vbt_size; + size_t fake_oprom_size; + struct device *dev; + + dev = dev_find_slot(0, PCI_DEVFN(2, 0)); + + memset(oh, 0, 8192); + + oh->signature = OPROM_SIGNATURE; + oh->pcir_offset = 0x40; + oh->vbt_offset = 0x80; + + pcir = (void *)(PCI_VGA_RAM_IMAGE_START + 0x40); + pcir->signature = 0x52494350; // PCIR + pcir->vendor = dev->vendor; + pcir->device = dev->device; + pcir->length = sizeof(*pcir); + pcir->revision = dev->class; + pcir->classcode[0] = dev->class >> 8; + pcir->classcode[1] = dev->class >> 16; + pcir->classcode[2] = dev->class >> 24; + pcir->indicator = 0x80; + + vbt_size = generate_vbt (info, (void *)(PCI_VGA_RAM_IMAGE_START + 0x80)); + fake_oprom_size = (0x80 + vbt_size + 511) / 512; + oh->size = fake_oprom_size; + pcir->imagelength = fake_oprom_size; return 1; }
1
0
0
0
Patch set updated for coreboot: 4155077 nehalem: Remove fake_vbt copying.
by Vladimir Serbinenko
29 Jul '14
29 Jul '14
Vladimir Serbinenko (phcoder(a)gmail.com) just uploaded a new patch set to gerrit, which you can find at
http://review.coreboot.org/5895
-gerrit commit 4155077e6333acfb447c46273f80c6d3befd6f55 Author: Vladimir Serbinenko <phcoder(a)gmail.com> Date: Sat May 31 22:26:42 2014 +0200 nehalem: Remove fake_vbt copying. Instead generate simple VBT in code. Tested on X201. Change-Id: I2244053edd24c22694161d9bf5f7f2f3eb4e2f57 Signed-off-by: Vladimir Serbinenko <phcoder(a)gmail.com> --- src/mainboard/lenovo/x201/Makefile.inc | 1 - src/mainboard/lenovo/x201/gma.c | 514 -------------------------- src/mainboard/packardbell/ms2290/Makefile.inc | 1 - src/mainboard/packardbell/ms2290/gma.c | 272 -------------- src/northbridge/intel/nehalem/gma.c | 73 +++- 5 files changed, 60 insertions(+), 801 deletions(-) diff --git a/src/mainboard/lenovo/x201/Makefile.inc b/src/mainboard/lenovo/x201/Makefile.inc index c6574c5..eb099f3 100644 --- a/src/mainboard/lenovo/x201/Makefile.inc +++ b/src/mainboard/lenovo/x201/Makefile.inc @@ -21,4 +21,3 @@ smm-$(CONFIG_HAVE_SMI_HANDLER) += dock.c smm-$(CONFIG_HAVE_SMI_HANDLER) += smihandler.c romstage-y += dock.c ramstage-y += dock.c -ramstage-y += gma.c diff --git a/src/mainboard/lenovo/x201/gma.c b/src/mainboard/lenovo/x201/gma.c deleted file mode 100644 index f417905..0000000 --- a/src/mainboard/lenovo/x201/gma.c +++ /dev/null @@ -1,514 +0,0 @@ -#include <arch/io.h> -#include <device/device.h> -#include <device/pci.h> -#include <device/pci_ids.h> -#include <device/pci_ops.h> - -#include "northbridge/intel/nehalem/nehalem.h" - -/* This array contains the information on flat panel. When using native - graphics init coreboot copies it to where VGA Option ROM would be so - that OS can find it and able to use internal display. This contains no - executable code and is just information on the panel. - */ - -unsigned char fake_vbt[] = { - 0x24, 0x56, 0x42, 0x54, 0x20, 0x49, 0x52, 0x4f, 0x4e, 0x4c, 0x41, 0x4b, - 0x45, 0x2d, 0x4d, 0x4f, - 0x42, 0x49, 0x4c, 0x45, 0x64, 0x00, 0x30, 0x00, 0x8e, 0x0f, 0x48, 0x00, - 0x30, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x42, 0x49, 0x4f, 0x53, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x42, 0x4c, - 0x4f, 0x43, 0x4b, 0x20, - 0x9c, 0x00, 0x16, 0x00, 0x5e, 0x0f, 0xfe, 0xea, 0x00, 0x00, 0x64, 0x01, - 0x01, 0x0f, 0x0d, 0x32, - 0x30, 0x32, 0x36, 0x44, 0x43, 0x49, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x6c, - 0x28, 0x52, 0x29, 0x49, - 0x72, 0x6f, 0x6e, 0x6c, 0x61, 0x6b, 0x65, 0x20, 0x4d, 0x6f, 0x62, 0x69, - 0x6c, 0x65, 0x20, 0x50, - 0x43, 0x49, 0x20, 0x41, 0x63, 0x63, 0x65, 0x6c, 0x65, 0x72, 0x61, 0x74, - 0x65, 0x64, 0x20, 0x53, - 0x56, 0x47, 0x41, 0x20, 0x42, 0x49, 0x4f, 0x53, 0x0d, 0x0a, 0x42, 0x75, - 0x69, 0x6c, 0x64, 0x20, - 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x3a, 0x20, 0x32, 0x30, 0x32, 0x36, - 0x20, 0x50, 0x43, 0x20, - 0x31, 0x34, 0x2e, 0x33, 0x34, 0x20, 0x20, 0x30, 0x39, 0x2f, 0x32, 0x38, - 0x20, 0x2f, 0x32, 0x30, - 0x31, 0x30, 0x20, 0x20, 0x32, 0x32, 0x3a, 0x32, 0x30, 0x3a, 0x35, 0x32, - 0x0d, 0x0a, 0x44, 0x45, - 0x43, 0x4f, 0x4d, 0x50, 0x49, 0x4c, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x20, - 0x4f, 0x52, 0x20, 0x44, - 0x49, 0x53, 0x41, 0x53, 0x53, 0x45, 0x4d, 0x42, 0x4c, 0x59, 0x20, 0x50, - 0x52, 0x4f, 0x48, 0x49, - 0x42, 0x49, 0x54, 0x45, 0x44, 0x0d, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x43, 0x6f, - 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x43, 0x29, 0x20, - 0x32, 0x30, 0x30, 0x30, - 0x2d, 0x32, 0x30, 0x30, 0x33, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x6c, 0x20, - 0x43, 0x6f, 0x72, 0x70, - 0x2e, 0x20, 0x41, 0x6c, 0x6c, 0x20, 0x52, 0x69, 0x67, 0x68, 0x74, 0x73, - 0x20, 0x52, 0x65, 0x73, - 0x65, 0x72, 0x76, 0x65, 0x64, 0x2e, 0x0d, 0x0a, 0x0d, 0x0a, 0x00, 0x00, - 0xc0, 0x03, 0x08, 0x04, - 0x00, 0x00, 0x00, 0x01, 0x05, 0x00, 0x07, 0x03, 0x00, 0x01, 0x19, 0xfe, - 0x32, 0x00, 0x44, 0x04, - 0x40, 0x06, 0x04, 0x02, 0x09, 0x01, 0x08, 0x0a, 0x02, 0x08, 0x0c, 0x04, - 0x08, 0x03, 0x01, 0x02, - 0x05, 0x01, 0x04, 0x0d, 0x01, 0x04, 0x0b, 0x01, 0x02, 0x07, 0x01, 0x04, - 0x15, 0x01, 0x04, 0x45, - 0x01, 0x04, 0x0e, 0x04, 0x08, 0x46, 0x04, 0x40, 0x28, 0x20, 0x08, 0x48, - 0x40, 0x08, 0x10, 0x00, - 0x02, 0x0d, 0x01, 0x02, 0x04, 0x00, 0x00, 0x21, 0x08, 0x00, 0x22, 0x10, - 0x00, 0x20, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xcd, 0x04, 0x00, 0x00, 0x03, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xc6, - 0x68, 0x00, 0x20, 0x00, - 0x01, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xe3, 0x08, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, - 0x00, 0x07, 0x20, 0x01, 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x20, - 0x00, 0x01, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x01, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x03, 0x01, 0x00, 0x00, 0x04, 0x1c, 0x00, 0x30, 0x32, 0x34, 0x36, 0x38, - 0x3a, 0x3c, 0x40, 0x42, - 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, - 0x80, 0x81, 0x82, 0x83, - 0x84, 0x1a, 0x00, 0xfe, 0xad, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x01, 0x30, 0x00, 0xbf, - 0x06, 0x1e, 0x00, 0x59, - 0x03, 0x28, 0x00, 0x86, 0x03, 0x02, 0x00, 0x90, 0x03, 0x38, 0x00, 0xd1, - 0x03, 0xc8, 0x00, 0x1f, - 0x06, 0x30, 0x00, 0x52, 0x06, 0x18, 0x00, 0x6d, 0x06, 0x18, 0x00, 0x88, - 0x06, 0x18, 0x00, 0x8b, - 0x07, 0x08, 0x00, 0xcf, 0x07, 0x12, 0x00, 0xe1, 0x07, 0x12, 0x00, 0xf3, - 0x07, 0x12, 0x00, 0x05, - 0x08, 0x12, 0x00, 0x1a, 0x08, 0x0a, 0x00, 0x24, 0x08, 0x0a, 0x00, 0x2e, - 0x08, 0x0a, 0x00, 0x38, - 0x08, 0x0a, 0x00, 0x45, 0x08, 0x0a, 0x00, 0x4f, 0x08, 0x0a, 0x00, 0x59, - 0x08, 0x0a, 0x00, 0x63, - 0x08, 0x0a, 0x00, 0x75, 0x08, 0x0a, 0x00, 0x7f, 0x08, 0x0a, 0x00, 0x89, - 0x08, 0x0a, 0x00, 0x93, - 0x08, 0x0a, 0x00, 0x9d, 0x08, 0x0a, 0x00, 0xa7, 0x08, 0x0a, 0x00, 0xb1, - 0x08, 0x0a, 0x00, 0xbb, - 0x08, 0x0a, 0x00, 0xc5, 0x08, 0x0a, 0x00, 0xcf, 0x08, 0x0a, 0x00, 0xd9, - 0x08, 0x0a, 0x00, 0xe3, - 0x08, 0x0a, 0x00, 0xed, 0x08, 0x0a, 0x00, 0xf7, 0x08, 0x0a, 0x00, 0x01, - 0x09, 0x0a, 0x00, 0x0b, - 0x09, 0x0a, 0x00, 0x06, 0x5d, 0x00, 0xfc, 0xff, 0x02, 0x80, 0x00, 0x07, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x80, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x11, 0x07, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x10, 0x04, 0x00, 0x8e, 0x29, 0x00, 0x80, 0x9c, 0x01, 0x07, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x9c, 0x11, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0xff, 0xff, 0x07, 0x07, 0x00, 0xfe, 0xff, 0xce, 0x18, 0x00, 0xff, - 0xff, 0x08, 0x3d, 0x00, - 0xfc, 0xff, 0x02, 0x40, 0xf0, 0x04, 0x00, 0x01, 0x00, 0x00, 0x01, 0x44, - 0xf0, 0x04, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x48, 0xf0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, - 0xf0, 0x04, 0x00, 0x00, - 0x00, 0x03, 0x03, 0x50, 0xf0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, - 0xf0, 0x04, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x58, 0xf0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0x0a, 0xcb, 0x00, - 0x0a, 0x80, 0x04, 0x60, 0x03, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0x00, - 0x05, 0x58, 0x02, 0xff, - 0xff, 0xff, 0xbf, 0xff, 0xff, 0x00, 0x05, 0xc0, 0x03, 0xff, 0xff, 0xff, - 0xbf, 0xff, 0xff, 0x80, - 0x07, 0xa0, 0x05, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0xff, 0xff, 0x40, 0x07, 0x70, 0x05, 0xff, 0xff, 0xff, 0xbf, 0xff, - 0xff, 0x00, 0x07, 0x40, - 0x05, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0x80, 0x02, 0xe0, 0x01, 0xff, - 0x1b, 0xfe, 0x07, 0xff, - 0xff, 0x20, 0x03, 0x58, 0x02, 0xff, 0x1b, 0xfe, 0x07, 0xff, 0xff, 0x00, - 0x04, 0x00, 0x03, 0xff, - 0x1b, 0xfe, 0x07, 0xff, 0xff, 0x40, 0x06, 0xb0, 0x04, 0xff, 0x1b, 0xff, - 0x07, 0xff, 0xff, 0x00, - 0x08, 0x00, 0x06, 0xff, 0xdb, 0xff, 0x07, 0xff, 0xff, 0x00, 0x05, 0x00, - 0x04, 0xff, 0x1b, 0xfe, - 0x07, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xff, 0xff, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x0b, - 0xc7, 0x00, 0x21, 0x40, - 0x00, 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, - 0x05, 0x70, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x02, 0x05, 0x72, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x50, 0x00, 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x20, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x20, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x11, 0x00, 0x4a, 0x00, 0x04, 0x00, - 0x03, 0x08, 0x3c, 0x84, - 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x0d, 0x03, 0x00, - 0xf7, 0x03, 0xc8, 0x0e, - 0x09, 0x00, 0x01, 0x90, 0x05, 0x5a, 0x00, 0xec, 0x05, 0x2d, 0x00, 0x0f, - 0x8b, 0x00, 0x09, 0x0a, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x05, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x84, 0x00, - 0x10, 0x00, 0x03, 0x08, - 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x08, 0x00, 0x04, 0x00, 0x00, 0x04, - 0x08, 0x00, 0x40, 0x00, - 0x00, 0x40, 0x08, 0x00, 0x20, 0x00, 0x00, 0x20, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x08, - 0x00, 0x03, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x08, 0x00, 0x04, - 0x00, 0x00, 0x04, 0x08, - 0x00, 0x40, 0x00, 0x00, 0x40, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, - 0x03, 0x01, 0x00, 0x00, - 0x01, 0x08, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0x01, 0x04, 0x00, - 0x04, 0x00, 0x00, 0x04, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x01, 0x00, 0x00, 0x01, - 0x08, 0x00, 0x00, 0x08, - 0x00, 0x02, 0x00, 0x00, 0x01, 0x04, 0x00, 0x04, 0x00, 0x00, 0x04, 0x08, - 0x00, 0x00, 0x00, 0x00, - 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, - 0x0c, 0x00, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x20, - 0x00, 0x0f, 0x02, 0x09, - 0x00, 0x05, 0x00, 0x03, 0x00, 0x00, 0x09, 0x00, 0x05, 0x00, 0x03, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x14, 0x9e, 0x00, - 0x06, 0x1a, 0x03, 0xff, 0x00, 0x03, 0xe0, 0x01, 0x07, 0x3c, 0x40, 0x0b, - 0x00, 0xc0, 0x30, 0xe0, - 0x14, 0x10, 0x18, 0x48, 0x36, 0x00, 0x05, 0xa3, 0x10, 0x00, 0x00, 0x18, - 0x03, 0xff, 0xc0, 0x03, - 0x58, 0x02, 0x07, 0x3c, 0xc8, 0x11, 0xc0, 0x00, 0x31, 0x58, 0x18, 0x20, - 0x20, 0x60, 0x36, 0x00, - 0x05, 0xa3, 0x10, 0x00, 0x00, 0x18, 0x03, 0xff, 0x00, 0x05, 0x20, 0x03, - 0x07, 0x3c, 0x9e, 0x20, - 0x00, 0x90, 0x51, 0x20, 0x1f, 0x30, 0x48, 0x80, 0x36, 0x00, 0x05, 0xa3, - 0x10, 0x00, 0x00, 0x18, - 0x03, 0xff, 0x00, 0x03, 0xe0, 0x01, 0x07, 0x32, 0x2c, 0x09, 0x00, 0xa0, - 0x30, 0xe0, 0x1a, 0x10, - 0x18, 0x10, 0x36, 0x00, 0x05, 0xa3, 0x10, 0x00, 0x00, 0x18, 0x03, 0xff, - 0xc0, 0x03, 0x58, 0x02, - 0x07, 0x32, 0xb2, 0x0d, 0xc0, 0xa0, 0x30, 0x58, 0x1a, 0x20, 0x18, 0x10, - 0x36, 0x00, 0x05, 0xa3, - 0x10, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3c, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x16, 0x4b, - 0x00, 0x00, 0x00, 0x03, 0x07, 0x00, 0x00, 0x00, 0x00, 0x08, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x30, 0x84, 0x0e, 0x00, 0x00, 0x4c, 0x46, 0x50, 0x5f, - 0x50, 0x61, 0x6e, 0x65, - 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x4c, 0x46, 0x50, 0x5f, 0x50, 0x61, 0x6e, - 0x65, 0x6c, 0x4e, 0x61, - 0x6d, 0x65, 0x4c, 0x46, 0x50, 0x5f, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x4e, - 0x61, 0x6d, 0x65, 0x4c, - 0x46, 0x50, 0x5f, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, - 0x17, 0x48, 0x00, 0x64, - 0x19, 0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x18, 0x88, 0x36, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x18, 0x30, 0x2a, 0x00, 0x98, 0x51, 0x00, 0x30, 0x40, 0x30, 0x70, 0x13, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x1e, 0xa8, 0x2f, 0x78, 0xe0, 0x51, 0x1a, 0x26, 0x40, 0x58, - 0x98, 0x13, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1e, 0x48, 0x3f, 0x40, 0x30, 0x62, 0xb0, 0x32, - 0x40, 0x40, 0xc0, 0x13, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x18, 0x28, 0x00, 0x36, 0x7f, - 0x03, 0x00, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x0c, 0x36, 0x7f, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x0c, 0x36, 0x7f, - 0x01, 0x90, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x36, 0x7f, 0x06, 0x00, - 0x04, 0x00, 0x00, 0x00, - 0x00, 0x0c, 0x19, 0x28, 0x00, 0x19, 0x00, 0xfa, 0x00, 0xfa, 0x00, 0x19, - 0x00, 0x90, 0x01, 0x20, - 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0xc8, 0x00, 0x40, 0x00, 0x40, - 0x00, 0x40, 0x00, 0x40, - 0x00, 0x2c, 0x01, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x2c, - 0x01, 0x1a, 0x02, 0x00, - 0x00, 0x40, 0x1b, 0xc8, 0x00, 0xd0, 0x07, 0x0a, 0x00, 0xd0, 0x07, 0xf4, - 0x01, 0x88, 0x13, 0xd0, - 0x07, 0x0a, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x88, 0x13, 0xd0, 0x07, 0x0a, - 0x00, 0xd0, 0x07, 0xf4, - 0x01, 0x88, 0x13, 0xd0, 0x07, 0x0a, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x88, - 0x13, 0xd0, 0x07, 0x0a, - 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x88, 0x13, 0xd0, 0x07, 0x0a, 0x00, 0xd0, - 0x07, 0xf4, 0x01, 0x88, - 0x13, 0xd0, 0x07, 0x0a, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x88, 0x13, 0xd0, - 0x07, 0x0a, 0x00, 0xd0, - 0x07, 0xf4, 0x01, 0x88, 0x13, 0xd0, 0x07, 0x0a, 0x00, 0xd0, 0x07, 0xf4, - 0x01, 0x88, 0x13, 0xd0, - 0x07, 0x0a, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x88, 0x13, 0xd0, 0x07, 0x0a, - 0x00, 0xd0, 0x07, 0xf4, - 0x01, 0x88, 0x13, 0xd0, 0x07, 0x0a, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x88, - 0x13, 0xd0, 0x07, 0x0a, - 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x88, 0x13, 0xd0, 0x07, 0x0a, 0x00, 0xd0, - 0x07, 0xf4, 0x01, 0x88, - 0x13, 0xd0, 0x07, 0x0a, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x88, 0x13, 0xd0, - 0x07, 0x0a, 0x00, 0xd0, - 0x07, 0xf4, 0x01, 0x88, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x28, 0x18, 0x00, - 0x01, 0x00, 0x73, 0x00, 0x54, 0x05, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xa8, 0x0a, 0x00, 0x00, 0x29, 0x94, 0x00, 0x03, - 0xf2, 0x09, 0x20, 0x18, - 0x0a, 0x12, 0x2a, 0x0a, 0x0a, 0x34, 0x0a, 0x20, 0x5a, 0x0a, 0x12, 0x6c, - 0x0a, 0x0a, 0x76, 0x0a, - 0x20, 0x9c, 0x0a, 0x12, 0xae, 0x0a, 0x0a, 0xb8, 0x0a, 0x20, 0xde, 0x0a, - 0x12, 0xf0, 0x0a, 0x0a, - 0xfa, 0x0a, 0x20, 0x20, 0x0b, 0x12, 0x32, 0x0b, 0x0a, 0x3c, 0x0b, 0x20, - 0x62, 0x0b, 0x12, 0x74, - 0x0b, 0x0a, 0x7e, 0x0b, 0x20, 0xa4, 0x0b, 0x12, 0xb6, 0x0b, 0x0a, 0xc0, - 0x0b, 0x20, 0xe6, 0x0b, - 0x12, 0xf8, 0x0b, 0x0a, 0x02, 0x0c, 0x20, 0x28, 0x0c, 0x12, 0x3a, 0x0c, - 0x0a, 0x44, 0x0c, 0x20, - 0x6a, 0x0c, 0x12, 0x7c, 0x0c, 0x0a, 0x86, 0x0c, 0x20, 0xac, 0x0c, 0x12, - 0xbe, 0x0c, 0x0a, 0xc8, - 0x0c, 0x20, 0xee, 0x0c, 0x12, 0x00, 0x0d, 0x0a, 0x0a, 0x0d, 0x20, 0x30, - 0x0d, 0x12, 0x42, 0x0d, - 0x0a, 0x4c, 0x0d, 0x20, 0x72, 0x0d, 0x12, 0x84, 0x0d, 0x0a, 0x8e, 0x0d, - 0x20, 0xb4, 0x0d, 0x12, - 0xc6, 0x0d, 0x0a, 0xd0, 0x0d, 0x20, 0xf6, 0x0d, 0x12, 0x08, 0x0e, 0x0a, - 0x12, 0x0e, 0x0d, 0x2a, - 0xf0, 0x04, 0x80, 0x02, 0xe0, 0x01, 0x80, 0x11, 0x0e, 0x00, 0x00, 0x03, - 0x00, 0x00, 0x08, 0x72, - 0x0c, 0x00, 0xc4, 0x09, 0xfa, 0x00, 0x0c, 0x72, 0x0c, 0x00, 0xc4, 0x09, - 0xfa, 0x00, 0x10, 0x72, - 0x0c, 0x00, 0x05, 0x0f, 0x27, 0x00, 0xff, 0xff, 0xd6, 0x09, 0x80, 0x90, - 0x20, 0xe0, 0x1d, 0x10, - 0x08, 0x60, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x36, 0x7f, - 0x01, 0x00, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x0c, 0x00, 0x05, 0x20, 0x03, 0x80, 0x11, 0x0e, 0x00, - 0x00, 0x03, 0x00, 0x00, - 0x08, 0x72, 0x0c, 0x00, 0xc4, 0x09, 0xfa, 0x00, 0x0c, 0x72, 0x0c, 0x00, - 0xc4, 0x09, 0xfa, 0x00, - 0x10, 0x72, 0x0c, 0x00, 0x03, 0x0f, 0x27, 0x00, 0xff, 0xff, 0x12, 0x1b, - 0x00, 0x80, 0x50, 0x20, - 0x14, 0x30, 0x18, 0x20, 0x44, 0x00, 0x05, 0xa3, 0x10, 0x00, 0x00, 0x1f, - 0x30, 0xae, 0x11, 0x40, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xa0, 0x05, 0x84, 0x03, 0x80, 0x11, - 0x0e, 0x00, 0x00, 0x03, - 0x00, 0x00, 0x08, 0x72, 0x0c, 0x00, 0xc4, 0x09, 0xfa, 0x00, 0x0c, 0x72, - 0x0c, 0x00, 0xc4, 0x09, - 0xfa, 0x00, 0x10, 0x72, 0x0c, 0x00, 0x03, 0x0f, 0x27, 0x00, 0xff, 0xff, - 0xf0, 0x1c, 0xa0, 0xa0, - 0x50, 0x84, 0x1a, 0x30, 0x18, 0x10, 0x36, 0x00, 0x05, 0xa3, 0x10, 0x00, - 0x00, 0x18, 0x30, 0xae, - 0x14, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x05, 0x20, 0x03, - 0x80, 0x11, 0x0e, 0x00, - 0x3c, 0x03, 0x00, 0x00, 0x08, 0x72, 0x0c, 0x00, 0xc4, 0x09, 0xfa, 0x00, - 0x0c, 0x72, 0x0c, 0x00, - 0xc4, 0x09, 0xfa, 0x00, 0x10, 0x72, 0x0c, 0x00, 0x03, 0x0f, 0x27, 0x00, - 0xff, 0xff, 0x64, 0x19, - 0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x18, 0x88, 0x36, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x18, - 0x30, 0xae, 0x31, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x05, - 0x20, 0x03, 0x80, 0x11, - 0x0e, 0x00, 0x3c, 0x03, 0x00, 0x00, 0x08, 0x72, 0x0c, 0x00, 0xc4, 0x09, - 0xfa, 0x00, 0x0c, 0x72, - 0x0c, 0x00, 0xc4, 0x09, 0xfa, 0x00, 0x10, 0x72, 0x0c, 0x00, 0x03, 0x0f, - 0x27, 0x00, 0xff, 0xff, - 0xc7, 0x1b, 0x00, 0xa0, 0x50, 0x20, 0x17, 0x30, 0x30, 0x20, 0x36, 0x00, - 0x05, 0xa3, 0x10, 0x00, - 0x00, 0x18, 0x30, 0xae, 0x11, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, - 0x00, 0x05, 0x20, 0x03, - 0x80, 0x11, 0x0e, 0x00, 0x3c, 0x03, 0x00, 0x00, 0x08, 0x72, 0x0c, 0x00, - 0xc4, 0x09, 0xfa, 0x00, - 0x0c, 0x72, 0x0c, 0x00, 0xc4, 0x09, 0xfa, 0x00, 0x10, 0x72, 0x0c, 0x00, - 0x03, 0x0f, 0x27, 0x00, - 0xff, 0xff, 0xc0, 0x1b, 0x00, 0xab, 0x50, 0x20, 0x10, 0x30, 0x34, 0x40, - 0x33, 0x00, 0x05, 0xa3, - 0x10, 0x00, 0x00, 0x19, 0x30, 0xae, 0x11, 0x40, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x13, 0x00, 0x05, - 0x20, 0x03, 0x80, 0x11, 0x0e, 0x00, 0x3c, 0x03, 0x00, 0x00, 0x08, 0x72, - 0x0c, 0x00, 0xc4, 0x09, - 0xfa, 0x00, 0x0c, 0x72, 0x0c, 0x00, 0xc4, 0x09, 0xfa, 0x00, 0x10, 0x72, - 0x0c, 0x00, 0x03, 0x0f, - 0x27, 0x00, 0xff, 0xff, 0xcc, 0x1b, 0x00, 0xa1, 0x50, 0x20, 0x17, 0x30, - 0x31, 0x20, 0x36, 0x00, - 0x05, 0xa3, 0x10, 0x00, 0x00, 0x19, 0x30, 0xae, 0x10, 0x40, 0x00, 0x00, - 0x00, 0x00, 0x2d, 0x12, - 0x00, 0x05, 0x00, 0x03, 0x80, 0x11, 0x0e, 0x00, 0x00, 0x03, 0x00, 0x00, - 0x08, 0x72, 0x0c, 0x00, - 0xc4, 0x09, 0xfa, 0x00, 0x0c, 0x72, 0x0c, 0x00, 0xc4, 0x09, 0xfa, 0x00, - 0x10, 0x72, 0x0c, 0x00, - 0x03, 0x0f, 0x27, 0x00, 0xff, 0xff, 0xa9, 0x1a, 0x00, 0xa0, 0x50, 0x00, - 0x0a, 0x30, 0x30, 0x20, - 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x36, 0x7f, 0x03, 0x90, - 0x08, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x90, 0x06, 0x1a, 0x04, 0x80, 0x11, 0x0e, 0x00, 0x3c, 0x03, - 0x00, 0x00, 0x08, 0x72, - 0x0c, 0x00, 0xc4, 0x09, 0xfa, 0x00, 0x0c, 0x72, 0x0c, 0x00, 0xc4, 0x09, - 0xfa, 0x00, 0x10, 0x72, - 0x0c, 0x00, 0x03, 0x0f, 0x27, 0x00, 0xff, 0xff, 0x7c, 0x2e, 0x90, 0xa0, - 0x60, 0x1a, 0x1e, 0x40, - 0x30, 0x20, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x36, 0x7f, - 0x04, 0x90, 0x09, 0x00, - 0x00, 0x00, 0x00, 0x0c, 0x80, 0x07, 0xb0, 0x04, 0x80, 0x11, 0x0e, 0x00, - 0x3c, 0x03, 0x00, 0x00, - 0x08, 0x72, 0x0c, 0x00, 0xc4, 0x09, 0xfa, 0x00, 0x0c, 0x72, 0x0c, 0x00, - 0xc4, 0x09, 0xfa, 0x00, - 0x10, 0x72, 0x0c, 0x00, 0x05, 0x0f, 0x27, 0x00, 0xff, 0xff, 0x28, 0x3c, - 0x80, 0xa0, 0x70, 0xb0, - 0x23, 0x40, 0x30, 0x20, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, - 0x36, 0x7f, 0x05, 0x90, - 0x0a, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x04, 0x00, 0x03, 0x80, 0x11, - 0x0e, 0x00, 0x00, 0x03, - 0x00, 0x00, 0x08, 0x72, 0x0c, 0x00, 0xc4, 0x09, 0xfa, 0x00, 0x0c, 0x72, - 0x0c, 0x00, 0xc4, 0x09, - 0xfa, 0x00, 0x10, 0x72, 0x0c, 0x00, 0x05, 0x0f, 0x27, 0x00, 0xff, 0xff, - 0x64, 0x19, 0x00, 0x40, - 0x41, 0x00, 0x26, 0x30, 0x18, 0x88, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x1e, 0x36, 0x7f, - 0x03, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x04, 0x00, 0x03, - 0x80, 0x11, 0x0e, 0x00, - 0x00, 0x03, 0x00, 0x00, 0x08, 0x72, 0x0c, 0x00, 0xc4, 0x09, 0xfa, 0x00, - 0x0c, 0x72, 0x0c, 0x00, - 0xc4, 0x09, 0xfa, 0x00, 0x10, 0x72, 0x0c, 0x00, 0x03, 0x0f, 0x27, 0x00, - 0xff, 0xff, 0x64, 0x19, - 0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x18, 0x88, 0x36, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x1e, - 0x36, 0x7f, 0x03, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x04, - 0x00, 0x03, 0x80, 0x11, - 0x0e, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08, 0x72, 0x0c, 0x00, 0xc4, 0x09, - 0xfa, 0x00, 0x0c, 0x72, - 0x0c, 0x00, 0xc4, 0x09, 0xfa, 0x00, 0x10, 0x72, 0x0c, 0x00, 0x03, 0x0f, - 0x27, 0x00, 0xff, 0xff, - 0x64, 0x19, 0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x18, 0x88, 0x36, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x1e, 0x36, 0x7f, 0x03, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x0c, - 0x00, 0x05, 0x20, 0x03, - 0x80, 0x11, 0x0e, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08, 0x72, 0x0c, 0x00, - 0xc4, 0x09, 0xfa, 0x00, - 0x0c, 0x72, 0x0c, 0x00, 0xc4, 0x09, 0xfa, 0x00, 0x10, 0x72, 0x0c, 0x00, - 0x03, 0x0f, 0x27, 0x00, - 0xff, 0xff, 0xea, 0x1a, 0x00, 0xa0, 0x50, 0x20, 0x17, 0x30, 0x0c, 0x30, - 0x43, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x1e, 0x36, 0x7f, 0x03, 0x00, 0x0e, 0x00, 0x00, 0x00, - 0x00, 0x0c, 0x00, 0x05, - 0x58, 0x02, 0x80, 0x11, 0x0e, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08, 0x72, - 0x0c, 0x00, 0xc4, 0x09, - 0xfa, 0x00, 0x0c, 0x72, 0x0c, 0x00, 0xc4, 0x09, 0xfa, 0x00, 0x10, 0x72, - 0x0c, 0x00, 0x03, 0x0f, - 0x27, 0x00, 0xff, 0xff, 0x06, 0x18, 0x00, 0x70, 0x51, 0x58, 0x15, 0x20, - 0x38, 0x80, 0x13, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x36, 0x7f, 0x03, 0x00, 0x0f, 0x00, - 0x00, 0x00, 0x00, 0x0c, - 0x00, 0x08, 0x00, 0x06, 0x80, 0x11, 0x0e, 0x00, 0x3c, 0x03, 0x00, 0x00, - 0x08, 0x72, 0x0c, 0x00, - 0xc4, 0x09, 0xfa, 0x00, 0x0c, 0x72, 0x0c, 0x00, 0xc4, 0x09, 0xfa, 0x00, - 0x10, 0x72, 0x0c, 0x00, - 0x03, 0x0f, 0x27, 0x00, 0xff, 0xff, 0x29, 0x40, 0x00, 0x60, 0x80, 0x00, - 0x13, 0x60, 0x10, 0x10, - 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x36, 0x7f, 0x03, 0x00, - 0x10, 0x00, 0x00, 0x00, - 0x00, 0x0c, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x4d, - 0x50, 0x57, 0x58, 0x47, 0x41, 0x32, 0x32, 0x30, 0x4e, 0x49, 0x54, 0x00, - 0x4d, 0x50, 0x57, 0x58, - 0x47, 0x41, 0x2b, 0x32, 0x35, 0x30, 0x4e, 0x49, 0x54, 0x43, 0x5f, 0x44, - 0x42, 0x34, 0x30, 0x30, - 0x4e, 0x49, 0x54, 0x00, 0x00, 0x00, 0x43, 0x5f, 0x4d, 0x54, 0x50, 0x33, - 0x30, 0x30, 0x4e, 0x49, - 0x54, 0x00, 0x00, 0x43, 0x5f, 0x50, 0x50, 0x32, 0x32, 0x30, 0x4e, 0x49, - 0x54, 0x00, 0x00, 0x00, - 0x4d, 0x50, 0x43, 0x5f, 0x43, 0x43, 0x46, 0x4c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x70, 0x61, 0x6e, - 0x65, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x61, - 0x6e, 0x65, 0x6c, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x61, 0x6e, 0x65, 0x6c, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x70, 0x61, - 0x6e, 0x65, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, - 0x61, 0x6e, 0x65, 0x6c, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x61, 0x6e, 0x65, - 0x6c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x2b, 0x61, 0x00, 0x06, 0x4e, 0xdc, 0x00, 0x00, 0x58, 0xaa, - 0x4a, 0x71, 0x02, 0x04, - 0x58, 0xaa, 0x4a, 0xa5, 0x00, 0x04, 0x58, 0xaa, 0x4a, 0x96, 0x00, 0x02, - 0x58, 0xaa, 0x4a, 0x5a, - 0x00, 0x04, 0x58, 0xaa, 0x4a, 0xff, 0x00, 0x05, 0x58, 0xaa, 0x4a, 0xa5, - 0x00, 0x16, 0x58, 0xaa, - 0x4e, 0xdc, 0x00, 0x00, 0x58, 0xaa, 0x4e, 0xdc, 0x00, 0x00, 0x58, 0xaa, - 0x4e, 0xdc, 0x00, 0x00, - 0x58, 0xaa, 0x4e, 0xdc, 0x00, 0x00, 0x58, 0xaa, 0x4e, 0xdc, 0x00, 0x00, - 0x58, 0xaa, 0x4e, 0xdc, - 0x00, 0x00, 0x58, 0xaa, 0x4e, 0xdc, 0x00, 0x00, 0x58, 0xaa, 0x4e, 0xdc, - 0x00, 0x00, 0x58, 0xaa, - 0x4e, 0xdc, 0x00, 0x00, 0x58, 0xaa, 0x2c, 0x15, 0x00, 0x09, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, -}; diff --git a/src/mainboard/packardbell/ms2290/Makefile.inc b/src/mainboard/packardbell/ms2290/Makefile.inc index a9db8d8..b47ace2 100644 --- a/src/mainboard/packardbell/ms2290/Makefile.inc +++ b/src/mainboard/packardbell/ms2290/Makefile.inc @@ -18,4 +18,3 @@ ## smm-$(CONFIG_HAVE_SMI_HANDLER) += smihandler.c -ramstage-y += gma.c diff --git a/src/mainboard/packardbell/ms2290/gma.c b/src/mainboard/packardbell/ms2290/gma.c deleted file mode 100644 index 540d858..0000000 --- a/src/mainboard/packardbell/ms2290/gma.c +++ /dev/null @@ -1,272 +0,0 @@ -#include <arch/io.h> -#include <device/device.h> -#include <device/pci.h> -#include <device/pci_ids.h> -#include <device/pci_ops.h> - -#include "northbridge/intel/nehalem/nehalem.h" - -/* This array contains the information on flat panel. When using native - graphics init coreboot copies it to where VGA Option ROM would be so - that OS can find it and able to use internal display. This contains no - executable code and is just information on the panel. - */ - -unsigned char fake_vbt[] = { -0x24, 0x56, 0x42, 0x54, 0x20, 0x49, 0x52, 0x4f, 0x4e, 0x4c, 0x41, 0x4b, 0x45, 0x2d, 0x4d, 0x4f, -0x42, 0x49, 0x4c, 0x45, 0x64, 0x00, 0x30, 0x00, 0xc3, 0x10, 0xa4, 0x00, 0x30, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x42, 0x49, 0x4f, 0x53, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x20, -0x9b, 0x00, 0x16, 0x00, 0x93, 0x10, 0xfe, 0xea, 0x00, 0x00, 0x64, 0x01, 0x01, 0x0f, 0x0d, 0x31, -0x39, 0x39, 0x34, 0x49, 0x6e, 0x74, 0x65, 0x6c, 0x28, 0x52, 0x29, 0x49, 0x72, 0x6f, 0x6e, 0x6c, -0x61, 0x6b, 0x65, 0x20, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x20, 0x50, 0x43, 0x49, 0x20, 0x41, -0x63, 0x63, 0x65, 0x6c, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x20, 0x53, 0x56, 0x47, 0x41, 0x20, -0x42, 0x49, 0x4f, 0x53, 0x0d, 0x0a, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x20, 0x4e, 0x75, 0x6d, 0x62, -0x65, 0x72, 0x3a, 0x20, 0x69, 0x6c, 0x6d, 0x31, 0x39, 0x39, 0x34, 0x31, 0x2e, 0x6a, 0x76, 0x37, -0x20, 0x50, 0x43, 0x20, 0x31, 0x34, 0x2e, 0x33, 0x34, 0x20, 0x20, 0x30, 0x35, 0x2f, 0x32, 0x36, -0x2f, 0x32, 0x30, 0x31, 0x30, 0x20, 0x20, 0x31, 0x39, 0x3a, 0x32, 0x32, 0x3a, 0x30, 0x33, 0x0d, -0x0a, 0x44, 0x45, 0x43, 0x4f, 0x4d, 0x50, 0x49, 0x4c, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x20, 0x4f, -0x52, 0x20, 0x44, 0x49, 0x53, 0x41, 0x53, 0x53, 0x45, 0x4d, 0x42, 0x4c, 0x59, 0x20, 0x50, 0x52, -0x4f, 0x48, 0x49, 0x42, 0x49, 0x54, 0x45, 0x44, 0x0d, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x43, 0x6f, -0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x43, 0x29, 0x20, 0x32, 0x30, 0x30, 0x30, -0x2d, 0x32, 0x30, 0x30, 0x33, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x6c, 0x20, 0x43, 0x6f, 0x72, 0x70, -0x2e, 0x20, 0x41, 0x6c, 0x6c, 0x20, 0x52, 0x69, 0x67, 0x68, 0x74, 0x73, 0x20, 0x52, 0x65, 0x73, -0x65, 0x72, 0x76, 0x65, 0x64, 0x2e, 0x0d, 0x0a, 0x0d, 0x0a, 0x00, 0x00, 0xc0, 0x03, 0x08, 0x04, -0x01, 0x00, 0x00, 0x01, 0x05, 0x00, 0x07, 0x01, 0x00, 0x01, 0x01, 0xfe, 0x20, 0x00, 0x01, 0x01, -0x08, 0x08, 0x04, 0x04, 0x09, 0x08, 0x0c, 0x08, 0x05, 0x04, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0d, -0x01, 0x02, 0x04, 0x00, 0x00, 0x21, 0x08, 0x00, 0x22, 0x10, 0x00, 0x4c, 0x46, 0x50, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xc0, 0xd1, 0x04, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xd2, 0x60, 0x00, 0x20, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xe4, 0x01, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x05, -0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x20, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, -0x00, 0x00, 0x04, 0x1c, 0x00, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x40, 0x42, 0x44, 0x46, -0x48, 0x4a, 0x4c, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x80, 0x81, 0x82, 0x83, 0x84, 0x1a, -0x00, 0xfe, 0xac, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, -0x01, 0x00, 0x00, 0x00, 0x0e, 0x01, 0x20, 0x00, 0xf4, 0x07, 0x1e, 0x00, 0x8e, 0x04, 0x28, 0x00, -0xbb, 0x04, 0x02, 0x00, 0xc5, 0x04, 0x38, 0x00, 0x06, 0x05, 0xc8, 0x00, 0x54, 0x07, 0x30, 0x00, -0x87, 0x07, 0x18, 0x00, 0xa2, 0x07, 0x18, 0x00, 0xbd, 0x07, 0x18, 0x00, 0xc0, 0x08, 0x08, 0x00, -0x04, 0x09, 0x12, 0x00, 0x16, 0x09, 0x12, 0x00, 0x28, 0x09, 0x12, 0x00, 0x3a, 0x09, 0x12, 0x00, -0x4f, 0x09, 0x0a, 0x00, 0x59, 0x09, 0x0a, 0x00, 0x63, 0x09, 0x0a, 0x00, 0x6d, 0x09, 0x0a, 0x00, -0x7a, 0x09, 0x0a, 0x00, 0x84, 0x09, 0x0a, 0x00, 0x8e, 0x09, 0x0a, 0x00, 0x98, 0x09, 0x0a, 0x00, -0xaa, 0x09, 0x0a, 0x00, 0xb4, 0x09, 0x0a, 0x00, 0xbe, 0x09, 0x0a, 0x00, 0xc8, 0x09, 0x0a, 0x00, -0xd2, 0x09, 0x0a, 0x00, 0xdc, 0x09, 0x0a, 0x00, 0xe6, 0x09, 0x0a, 0x00, 0xf0, 0x09, 0x0a, 0x00, -0xfa, 0x09, 0x0a, 0x00, 0x04, 0x0a, 0x0a, 0x00, 0x0e, 0x0a, 0x0a, 0x00, 0x18, 0x0a, 0x0a, 0x00, -0x22, 0x0a, 0x0a, 0x00, 0x2c, 0x0a, 0x0a, 0x00, 0x36, 0x0a, 0x0a, 0x00, 0x40, 0x0a, 0x0a, 0x00, -0x06, 0xa5, 0x01, 0xfc, 0xff, 0x02, 0x14, 0x60, 0x0c, 0x00, 0x80, 0x00, 0x80, 0x04, 0x40, 0x60, -0x0c, 0x00, 0x07, 0x0d, 0x03, 0x00, 0x44, 0x60, 0x0c, 0x00, 0x07, 0x0d, 0x03, 0x00, 0x18, 0x60, -0x0c, 0x00, 0x80, 0x00, 0x80, 0x04, 0x48, 0x60, 0x0c, 0x00, 0x07, 0x0d, 0x03, 0x00, 0x4c, 0x60, -0x0c, 0x00, 0x07, 0x0d, 0x03, 0x00, 0x80, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, -0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x11, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, -0x04, 0x00, 0x00, 0x00, 0x00, 0x80, 0x9c, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x11, -0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x7f, 0x02, 0x1f, 0x03, 0x04, 0x00, -0x06, 0x00, 0x87, 0x02, 0x17, 0x03, 0x08, 0x00, 0x06, 0x00, 0x8f, 0x02, 0xef, 0x02, 0x0c, 0x00, -0x06, 0x00, 0xdf, 0x01, 0x0c, 0x02, 0x10, 0x00, 0x06, 0x00, 0xe7, 0x01, 0x04, 0x02, 0x14, 0x00, -0x06, 0x00, 0xe9, 0x01, 0xeb, 0x01, 0x1c, 0x00, 0x06, 0x00, 0xdf, 0x01, 0x7f, 0x02, 0x00, 0x10, -0x06, 0x00, 0x7f, 0x02, 0x1f, 0x03, 0x04, 0x10, 0x06, 0x00, 0x87, 0x02, 0x17, 0x03, 0x08, 0x10, -0x06, 0x00, 0x8f, 0x02, 0xef, 0x02, 0x0c, 0x10, 0x06, 0x00, 0xdf, 0x01, 0x0c, 0x02, 0x10, 0x10, -0x06, 0x00, 0xe7, 0x01, 0x04, 0x02, 0x14, 0x10, 0x06, 0x00, 0xe9, 0x01, 0xeb, 0x01, 0x1c, 0x10, -0x06, 0x00, 0xdf, 0x01, 0x7f, 0x02, 0x00, 0x00, 0x0e, 0x00, 0x7f, 0x02, 0x1f, 0x03, 0x04, 0x00, -0x0e, 0x00, 0x87, 0x02, 0x17, 0x03, 0x08, 0x00, 0x0e, 0x00, 0x8f, 0x02, 0xef, 0x02, 0x0c, 0x00, -0x0e, 0x00, 0xdf, 0x01, 0x0c, 0x02, 0x10, 0x00, 0x0e, 0x00, 0xe7, 0x01, 0x04, 0x02, 0x14, 0x00, -0x0e, 0x00, 0xe9, 0x01, 0xeb, 0x01, 0x00, 0x10, 0x0e, 0x00, 0x7f, 0x02, 0x1f, 0x03, 0x04, 0x10, -0x0e, 0x00, 0x87, 0x02, 0x17, 0x03, 0x08, 0x10, 0x0e, 0x00, 0x8f, 0x02, 0xef, 0x02, 0x0c, 0x10, -0x0e, 0x00, 0xdf, 0x01, 0x0c, 0x02, 0x10, 0x10, 0x0e, 0x00, 0xe7, 0x01, 0x04, 0x02, 0x14, 0x10, -0x0e, 0x00, 0xe9, 0x01, 0xeb, 0x01, 0x00, 0x50, 0x04, 0x00, 0x22, 0x06, 0x24, 0xc2, 0x08, 0x00, -0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, -0x04, 0x00, 0x8e, 0x29, 0x00, 0x80, 0x00, 0x11, 0x0e, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x40, -0x06, 0x00, 0x18, 0x00, 0x00, 0x00, 0x40, 0x11, 0x0e, 0x00, 0x18, 0x00, 0x00, 0x00, 0x50, 0x11, -0x0e, 0x00, 0x18, 0x00, 0x00, 0x00, 0x60, 0x11, 0x0e, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x07, 0x07, 0x00, 0xfe, 0xff, 0xce, 0x18, 0x00, -0xff, 0xff, 0x08, 0x3d, 0x00, 0xfc, 0xff, 0x02, 0x40, 0xf0, 0x04, 0x00, 0x01, 0x00, 0x00, 0x01, -0x44, 0xf0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0xf0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -0x4c, 0xf0, 0x04, 0x00, 0x00, 0x00, 0x03, 0x03, 0x50, 0xf0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -0x54, 0xf0, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x58, 0xf0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -0xff, 0xff, 0x0a, 0xcb, 0x00, 0x0a, 0x80, 0x02, 0xe0, 0x01, 0xff, 0xff, 0xff, 0xda, 0xff, 0xff, -0x20, 0x03, 0x58, 0x02, 0xff, 0x03, 0xfe, 0x07, 0xff, 0xff, 0x00, 0x04, 0x00, 0x03, 0xff, 0x1b, -0xfe, 0x07, 0xff, 0xff, 0x80, 0x04, 0x60, 0x03, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0x00, 0x05, -0x58, 0x02, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0x00, 0x05, 0xd0, 0x02, 0xff, 0x1b, 0xff, 0xbf, -0xff, 0xff, 0x00, 0x05, 0x00, 0x03, 0xff, 0x9b, 0xff, 0xbf, 0xff, 0xff, 0x00, 0x05, 0xc0, 0x03, -0xff, 0x9b, 0xff, 0x07, 0xff, 0xff, 0x00, 0x05, 0x00, 0x04, 0xff, 0x1b, 0xfe, 0x07, 0xff, 0xff, -0x56, 0x05, 0x00, 0x03, 0xff, 0x9b, 0xff, 0x07, 0xff, 0xff, 0x40, 0x06, 0x84, 0x03, 0xff, 0x1b, -0xfe, 0x07, 0xff, 0xff, 0x40, 0x06, 0xb0, 0x04, 0xff, 0x1b, 0xfe, 0x07, 0xff, 0xff, 0x00, 0x07, -0x40, 0x05, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0x40, 0x07, 0x70, 0x05, 0xff, 0xff, 0xff, 0x07, -0xff, 0xff, 0x80, 0x07, 0x38, 0x04, 0xff, 0x1b, 0xff, 0x07, 0xff, 0xff, 0x80, 0x07, 0xb0, 0x04, -0xff, 0xdb, 0xff, 0x07, 0xff, 0xff, 0x80, 0x07, 0xa0, 0x05, 0xff, 0x9b, 0xff, 0x07, 0xff, 0xff, -0x00, 0x08, 0x00, 0x06, 0xff, 0xdb, 0xff, 0x07, 0xff, 0xff, 0x78, 0x05, 0x1a, 0x04, 0xff, 0x9b, -0xff, 0x07, 0xff, 0xff, 0x90, 0x06, 0xb1, 0x03, 0xff, 0x1b, 0xff, 0x07, 0xff, 0xff, 0x00, 0x00, -0x0b, 0xc7, 0x00, 0x21, 0x40, 0x00, 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x09, 0x06, 0x03, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x05, 0x72, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x20, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x11, 0x00, 0x4e, 0x56, 0x05, -0x00, 0x03, 0x10, 0x3c, 0x84, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x00, 0x01, 0x0d, 0x03, -0x00, 0x78, 0x01, 0x0a, 0x0e, 0x09, 0x00, 0x01, 0xc5, 0x06, 0x5a, 0x00, 0x21, 0x07, 0x2d, 0x00, -0x0f, 0x8b, 0x00, 0x09, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, -0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x84, -0x00, 0x10, 0x00, 0x03, 0x01, 0x08, 0x00, 0x04, 0x08, 0x00, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, -0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x01, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x08, 0x00, -0x02, 0x00, 0x00, 0x01, 0x04, 0x00, 0x04, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, -0x00, 0x03, 0x01, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0x01, 0x04, -0x00, 0x04, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x01, 0x00, 0x00, -0x01, 0x08, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0x01, 0x04, 0x00, 0x04, 0x00, 0x00, 0x04, -0x08, 0x00, 0x00, 0x00, 0x00, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x12, 0x0c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, -0x20, 0x00, 0x0f, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x14, 0x9e, 0x00, 0x06, 0x1a, 0x03, 0x99, 0x00, 0x05, 0x20, 0x03, 0x07, 0x3c, 0xa9, -0x20, 0x00, 0x90, 0x51, 0x20, 0x1c, 0x30, 0x08, 0x88, 0x93, 0x00, 0x00, 0x20, 0x53, 0x00, 0x00, -0x00, 0x01, 0x99, 0xa0, 0x05, 0x84, 0x03, 0x07, 0x3c, 0xab, 0x22, 0xa0, 0xa0, 0x50, 0x84, 0x1a, -0x30, 0x30, 0x20, 0x36, 0x00, 0x2f, 0xbe, 0x10, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x07, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3c, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, -0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x16, 0x4b, 0x00, 0x00, 0x00, 0x03, 0x07, 0x00, 0x00, 0x00, 0x00, 0x08, 0x01, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x84, 0x0e, 0x00, 0x00, 0x4c, 0x46, 0x50, -0x5f, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x4c, 0x46, 0x50, 0x5f, 0x50, 0x61, -0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x4c, 0x46, 0x50, 0x5f, 0x50, 0x61, 0x6e, 0x65, 0x6c, -0x4e, 0x61, 0x6d, 0x65, 0x4c, 0x46, 0x50, 0x5f, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, -0x65, 0x17, 0x48, 0x00, 0x64, 0x19, 0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x18, 0x88, 0x36, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x2a, 0x00, 0x98, 0x51, 0x00, 0x30, 0x40, 0x30, 0x70, -0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xa8, 0x2f, 0x78, 0xe0, 0x51, 0x1a, 0x26, 0x40, -0x58, 0x98, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x48, 0x3f, 0x40, 0x30, 0x62, 0xb0, -0x32, 0x40, 0x40, 0xc0, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x18, 0x28, 0x00, 0x36, -0x7f, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x36, 0x7f, 0x05, 0x00, 0x02, 0x00, 0x00, -0x00, 0x00, 0x0c, 0x36, 0x7f, 0x01, 0x90, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x36, 0x7f, 0x06, -0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x19, 0x28, 0x00, 0x19, 0x00, 0xfa, 0x00, 0xfa, 0x00, -0x19, 0x00, 0x90, 0x01, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0xc8, 0x00, 0x40, 0x00, -0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x2c, 0x01, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, -0x2c, 0x01, 0x1a, 0x02, 0x00, 0x00, 0x00, 0x1b, 0xc8, 0x00, 0xd0, 0x07, 0x0a, 0x00, 0xd0, 0x07, -0xf4, 0x01, 0x88, 0x13, 0xd0, 0x07, 0x0a, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x88, 0x13, 0xd0, 0x07, -0x0a, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x88, 0x13, 0xd0, 0x07, 0x0a, 0x00, 0xd0, 0x07, 0xf4, 0x01, -0x88, 0x13, 0xd0, 0x07, 0x0a, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x88, 0x13, 0xd0, 0x07, 0x0a, 0x00, -0xd0, 0x07, 0xf4, 0x01, 0x88, 0x13, 0xd0, 0x07, 0x0a, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x88, 0x13, -0xd0, 0x07, 0x0a, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x88, 0x13, 0xd0, 0x07, 0x0a, 0x00, 0xd0, 0x07, -0xf4, 0x01, 0x88, 0x13, 0xd0, 0x07, 0x0a, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x88, 0x13, 0xd0, 0x07, -0x0a, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x88, 0x13, 0xd0, 0x07, 0x0a, 0x00, 0xd0, 0x07, 0xf4, 0x01, -0x88, 0x13, 0xd0, 0x07, 0x0a, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x88, 0x13, 0xd0, 0x07, 0x0a, 0x00, -0xd0, 0x07, 0xf4, 0x01, 0x88, 0x13, 0xd0, 0x07, 0x0a, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x88, 0x13, -0xd0, 0x07, 0x0a, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x88, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x28, 0x18, 0x00, 0x02, 0x00, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x94, 0x00, -0x03, 0x27, 0x0b, 0x20, 0x4d, 0x0b, 0x12, 0x5f, 0x0b, 0x0a, 0x69, 0x0b, 0x20, 0x8f, 0x0b, 0x12, -0xa1, 0x0b, 0x0a, 0xab, 0x0b, 0x20, 0xd1, 0x0b, 0x12, 0xe3, 0x0b, 0x0a, 0xed, 0x0b, 0x20, 0x13, -0x0c, 0x12, 0x25, 0x0c, 0x0a, 0x2f, 0x0c, 0x20, 0x55, 0x0c, 0x12, 0x67, 0x0c, 0x0a, 0x71, 0x0c, -0x20, 0x97, 0x0c, 0x12, 0xa9, 0x0c, 0x0a, 0xb3, 0x0c, 0x20, 0xd9, 0x0c, 0x12, 0xeb, 0x0c, 0x0a, -0xf5, 0x0c, 0x20, 0x1b, 0x0d, 0x12, 0x2d, 0x0d, 0x0a, 0x37, 0x0d, 0x20, 0x5d, 0x0d, 0x12, 0x6f, -0x0d, 0x0a, 0x79, 0x0d, 0x20, 0x9f, 0x0d, 0x12, 0xb1, 0x0d, 0x0a, 0xbb, 0x0d, 0x20, 0xe1, 0x0d, -0x12, 0xf3, 0x0d, 0x0a, 0xfd, 0x0d, 0x20, 0x23, 0x0e, 0x12, 0x35, 0x0e, 0x0a, 0x3f, 0x0e, 0x20, -0x65, 0x0e, 0x12, 0x77, 0x0e, 0x0a, 0x81, 0x0e, 0x20, 0xa7, 0x0e, 0x12, 0xb9, 0x0e, 0x0a, 0xc3, -0x0e, 0x20, 0xe9, 0x0e, 0x12, 0xfb, 0x0e, 0x0a, 0x05, 0x0f, 0x20, 0x2b, 0x0f, 0x12, 0x3d, 0x0f, -0x0a, 0x47, 0x0f, 0x0d, 0x2a, 0xf0, 0x04, 0x80, 0x02, 0xe0, 0x01, 0x80, 0x11, 0x0e, 0x00, 0x00, -0x03, 0x00, 0x00, 0x08, 0x72, 0x0c, 0x00, 0xd0, 0x07, 0x58, 0x02, 0x0c, 0x72, 0x0c, 0x00, 0xd0, -0x07, 0xf4, 0x01, 0x10, 0x72, 0x0c, 0x00, 0x05, 0x0f, 0x27, 0x00, 0xff, 0xff, 0xd6, 0x09, 0x80, -0x90, 0x20, 0xe0, 0x1d, 0x10, 0x08, 0x60, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x36, -0x7f, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x20, 0x03, 0x58, 0x02, 0x80, 0x11, 0x0e, -0x00, 0x00, 0x03, 0x00, 0x00, 0x08, 0x72, 0x0c, 0x00, 0xd0, 0x07, 0x58, 0x02, 0x0c, 0x72, 0x0c, -0x00, 0xd0, 0x07, 0xf4, 0x01, 0x10, 0x72, 0x0c, 0x00, 0x05, 0x0f, 0x27, 0x00, 0xff, 0xff, 0xa0, -0x0f, 0x20, 0x00, 0x31, 0x58, 0x1c, 0x20, 0x28, 0x80, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x1e, 0x36, 0x7f, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x40, 0x06, 0x84, 0x03, 0x80, -0x11, 0x0e, 0x00, 0x3c, 0x03, 0x30, 0x00, 0x08, 0x72, 0x0c, 0x00, 0xb8, 0x0b, 0x2c, 0x01, 0x0c, -0x72, 0x0c, 0x00, 0xb8, 0x0b, 0x2c, 0x01, 0x10, 0x72, 0x0c, 0x00, 0x06, 0x0f, 0x27, 0x00, 0xff, -0xff, 0x2f, 0x26, 0x40, 0xb8, 0x60, 0x84, 0x0c, 0x30, 0x30, 0x30, 0x23, 0x00, 0x7e, 0xd7, 0x10, -0x00, 0x00, 0x19, 0x30, 0xe4, 0x89, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x05, 0x00, -0x04, 0x80, 0x11, 0x0e, 0x00, 0x3c, 0x03, 0x00, 0x00, 0x08, 0x72, 0x0c, 0x00, 0xd0, 0x07, 0x58, -0x02, 0x0c, 0x72, 0x0c, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x10, 0x72, 0x0c, 0x00, 0x05, 0x0f, 0x27, -0x00, 0xff, 0xff, 0x30, 0x2a, 0x00, 0x98, 0x51, 0x00, 0x30, 0x40, 0x30, 0x70, 0x13, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x1e, 0x36, 0x7f, 0x05, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x78, -0x05, 0x1a, 0x04, 0x80, 0x11, 0x0e, 0x00, 0x3c, 0x03, 0x00, 0x00, 0x08, 0x72, 0x0c, 0x00, 0xd0, -0x07, 0x58, 0x02, 0x0c, 0x72, 0x0c, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x10, 0x72, 0x0c, 0x00, 0x05, -0x0f, 0x27, 0x00, 0xff, 0xff, 0x30, 0x2a, 0x78, 0x20, 0x51, 0x1a, 0x10, 0x40, 0x10, 0x70, 0x13, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x36, 0x7f, 0x01, 0x90, 0x05, 0x00, 0x00, 0x00, 0x00, -0x0c, 0x78, 0x05, 0x1a, 0x04, 0x80, 0x11, 0x0e, 0x00, 0x3c, 0x03, 0x00, 0x00, 0x08, 0x72, 0x0c, -0x00, 0xd0, 0x07, 0x58, 0x02, 0x0c, 0x72, 0x0c, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x10, 0x72, 0x0c, -0x00, 0x05, 0x0f, 0x27, 0x00, 0xff, 0xff, 0xa8, 0x2f, 0x78, 0xe0, 0x51, 0x1a, 0x26, 0x40, 0x58, -0x98, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x36, 0x7f, 0x01, 0x90, 0x06, 0x00, 0x00, -0x00, 0x00, 0x0c, 0x40, 0x06, 0xb0, 0x04, 0x80, 0x11, 0x0e, 0x00, 0x3c, 0x03, 0x00, 0x00, 0x08, -0x72, 0x0c, 0x00, 0xd0, 0x07, 0x58, 0x02, 0x0c, 0x72, 0x0c, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x10, -0x72, 0x0c, 0x00, 0x05, 0x0f, 0x27, 0x00, 0xff, 0xff, 0x48, 0x3f, 0x40, 0x30, 0x62, 0xb0, 0x32, -0x40, 0x40, 0xc0, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x36, 0x7f, 0x06, 0x00, 0x07, -0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x05, 0x00, 0x03, 0x80, 0x11, 0x0e, 0x00, 0x00, 0x03, 0x00, -0x00, 0x08, 0x72, 0x0c, 0x00, 0xd0, 0x07, 0x58, 0x02, 0x0c, 0x72, 0x0c, 0x00, 0xd0, 0x07, 0xf4, -0x01, 0x10, 0x72, 0x0c, 0x00, 0x05, 0x0f, 0x27, 0x00, 0xff, 0xff, 0xa9, 0x1a, 0x00, 0xa0, 0x50, -0x00, 0x0a, 0x30, 0x30, 0x20, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x36, 0x7f, 0x03, -0x90, 0x08, 0x00, 0x00, 0x00, 0x00, 0x01, 0x90, 0x06, 0x1a, 0x04, 0x80, 0x11, 0x0e, 0x00, 0x3c, -0x03, 0x00, 0x00, 0x08, 0x72, 0x0c, 0x00, 0xd0, 0x07, 0x58, 0x02, 0x0c, 0x72, 0x0c, 0x00, 0xd0, -0x07, 0xf4, 0x01, 0x10, 0x72, 0x0c, 0x00, 0x05, 0x0f, 0x27, 0x00, 0xff, 0xff, 0x7c, 0x2e, 0x90, -0xa0, 0x60, 0x1a, 0x1e, 0x40, 0x30, 0x20, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x36, -0x7f, 0x04, 0x90, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x80, 0x07, 0xb0, 0x04, 0x80, 0x11, 0x0e, -0x00, 0x3c, 0x03, 0x00, 0x00, 0x08, 0x72, 0x0c, 0x00, 0xd0, 0x07, 0x58, 0x02, 0x0c, 0x72, 0x0c, -0x00, 0xd0, 0x07, 0xf4, 0x01, 0x10, 0x72, 0x0c, 0x00, 0x05, 0x0f, 0x27, 0x00, 0xff, 0xff, 0x28, -0x3c, 0x80, 0xa0, 0x70, 0xb0, 0x23, 0x40, 0x30, 0x20, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x1e, 0x36, 0x7f, 0x05, 0x90, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x04, 0x00, 0x03, 0x80, -0x11, 0x0e, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08, 0x72, 0x0c, 0x00, 0xd0, 0x07, 0x58, 0x02, 0x0c, -0x72, 0x0c, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x10, 0x72, 0x0c, 0x00, 0x05, 0x0f, 0x27, 0x00, 0xff, -0xff, 0x64, 0x19, 0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x18, 0x88, 0x36, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x1e, 0x36, 0x7f, 0x03, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x04, 0x00, -0x03, 0x80, 0x11, 0x0e, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08, 0x72, 0x0c, 0x00, 0xd0, 0x07, 0x58, -0x02, 0x0c, 0x72, 0x0c, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x10, 0x72, 0x0c, 0x00, 0x05, 0x0f, 0x27, -0x00, 0xff, 0xff, 0x64, 0x19, 0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x18, 0x88, 0x36, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x1e, 0x36, 0x7f, 0x03, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, -0x04, 0x00, 0x03, 0x80, 0x11, 0x0e, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08, 0x72, 0x0c, 0x00, 0xd0, -0x07, 0x58, 0x02, 0x0c, 0x72, 0x0c, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x10, 0x72, 0x0c, 0x00, 0x05, -0x0f, 0x27, 0x00, 0xff, 0xff, 0x64, 0x19, 0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x18, 0x88, 0x36, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x36, 0x7f, 0x03, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, -0x0c, 0x00, 0x05, 0x20, 0x03, 0x80, 0x11, 0x0e, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08, 0x72, 0x0c, -0x00, 0xd0, 0x07, 0x58, 0x02, 0x0c, 0x72, 0x0c, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x10, 0x72, 0x0c, -0x00, 0x05, 0x0f, 0x27, 0x00, 0xff, 0xff, 0xea, 0x1a, 0x00, 0xa0, 0x50, 0x20, 0x17, 0x30, 0x0c, -0x30, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x36, 0x7f, 0x03, 0x90, 0x0e, 0x00, 0x00, -0x00, 0x00, 0x0c, 0x00, 0x05, 0x58, 0x02, 0x80, 0x11, 0x0e, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08, -0x72, 0x0c, 0x00, 0xd0, 0x07, 0x58, 0x02, 0x0c, 0x72, 0x0c, 0x00, 0xd0, 0x07, 0xf4, 0x01, 0x10, -0x72, 0x0c, 0x00, 0x05, 0x0f, 0x27, 0x00, 0xff, 0xff, 0x06, 0x18, 0x00, 0x70, 0x51, 0x58, 0x15, -0x20, 0x38, 0x80, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x36, 0x7f, 0x03, 0x00, 0x0f, -0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x06, 0x80, 0x11, 0x0e, 0x00, 0x3c, 0x03, 0x00, -0x00, 0x08, 0x72, 0x0c, 0x00, 0xd0, 0x07, 0x58, 0x02, 0x0c, 0x72, 0x0c, 0x00, 0xd0, 0x07, 0xf4, -0x01, 0x10, 0x72, 0x0c, 0x00, 0x05, 0x0f, 0x27, 0x00, 0xff, 0xff, 0x29, 0x40, 0x00, 0x60, 0x80, -0x00, 0x13, 0x60, 0x10, 0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x36, 0x7f, 0x03, -0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x4c, 0x46, 0x50, 0x5f, 0x50, 0x61, 0x6e, 0x65, 0x6c, -0x4e, 0x61, 0x6d, 0x65, 0x4c, 0x46, 0x50, 0x5f, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, -0x65, 0x4c, 0x46, 0x50, 0x5f, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x4c, 0x46, -0x50, 0x5f, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x4c, 0x46, 0x50, 0x5f, 0x50, -0x61, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x4c, 0x46, 0x50, 0x5f, 0x50, 0x61, 0x6e, 0x65, -0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x4c, 0x46, 0x50, 0x5f, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x4e, 0x61, -0x6d, 0x65, 0x4c, 0x46, 0x50, 0x5f, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x4c, -0x46, 0x50, 0x5f, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x4c, 0x46, 0x50, 0x5f, -0x50, 0x61, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x4c, 0x46, 0x50, 0x5f, 0x50, 0x61, 0x6e -}; diff --git a/src/northbridge/intel/nehalem/gma.c b/src/northbridge/intel/nehalem/gma.c index 3a9dcf5..bc4c74d 100644 --- a/src/northbridge/intel/nehalem/gma.c +++ b/src/northbridge/intel/nehalem/gma.c @@ -32,7 +32,7 @@ #include <drivers/intel/gma/i915.h> #include <pc80/vga.h> #include <pc80/vga_io.h> - +#include <drivers/intel/gma/intel_bios.h> #include "chip.h" #include "nehalem.h" @@ -1044,9 +1044,55 @@ static void intel_gma_init(const struct northbridge_intel_nehalem_config *info, #endif } +static size_t generate_vbt(const struct northbridge_intel_nehalem_config *conf, + void *vbt) +{ + struct vbt_header *head = vbt; + struct bdb_header *bdb_head; + struct bdb_general_features *genfeat; + u8 *ptr; + + memset(head, 0, sizeof (*head)); + + memcpy (head->signature, "$VBT IRONLAKE-MOBILE", 20); + head->version = 100; + head->header_size = sizeof (*head); + head->bdb_offset = sizeof (*head); + + bdb_head = (struct bdb_header *) (head + 1); + memset(bdb_head, 0, sizeof (*bdb_head)); + memcpy(bdb_head->signature, "BIOS_DATA_BLOCK ", 16); + bdb_head->version = 0xa8; + bdb_head->header_size = sizeof (*bdb_head); + + ptr = (u8 *) (bdb_head + 1); + + ptr[0] = BDB_GENERAL_FEATURES; + ptr[1] = sizeof (*genfeat); + ptr[2] = sizeof (*genfeat) >> 8; + ptr += 3; + + genfeat = (struct bdb_general_features *) ptr; + memset(genfeat, 0, sizeof (*genfeat)); + genfeat->panel_fitting = 3; + genfeat->flexaim = 1; + genfeat->download_ext_vbt = 1; + genfeat->enable_ssc = conf->gpu_use_spread_spectrum_clock; + genfeat->ssc_freq = !conf->gpu_link_frequency_270_mhz; + genfeat->rsvd10 = 0x4; + genfeat->legacy_monitor_detect = 1; + genfeat->int_crt_support = 1; + genfeat->dp_ssc_enb = 1; + + ptr += sizeof (*genfeat); + + bdb_head->bdb_size = ptr - (u8 *)bdb_head; + head->vbt_size = ptr - (u8 *)head; + head->vbt_checksum = 0; + return ptr - (u8 *)head; +} #endif - static void gma_func0_init(struct device *dev) { u32 reg32; @@ -1080,23 +1126,21 @@ static void gma_func0_init(struct device *dev) intel_gma_init(conf, gtt_res->base, physbase, pio_res->base, lfb_res->base); } -#endif /* Linux relies on VBT for panel info. */ - if (read16(0xc0000) != 0xaa55) { - optionrom_header_t *oh = (void *)0xc0000; + if (read16(PCI_VGA_RAM_IMAGE_START) != OPROM_SIGNATURE) { + optionrom_header_t *oh = (void *)PCI_VGA_RAM_IMAGE_START; optionrom_pcir_t *pcir; - int sz; + size_t vbt_size; + size_t fake_oprom_size; - memset(oh->reserved, 0, 8192); + memset(oh, 0, 8192); - sz = (0x80 + sizeof(fake_vbt) + 511) / 512; - oh->signature = 0xaa55; - oh->size = sz; + oh->signature = OPROM_SIGNATURE; oh->pcir_offset = 0x40; oh->vbt_offset = 0x80; - pcir = (void *)0xc0040; + pcir = (void *)(PCI_VGA_RAM_IMAGE_START + 0x40); pcir->signature = 0x52494350; // PCIR pcir->vendor = dev->vendor; pcir->device = dev->device; @@ -1105,11 +1149,14 @@ static void gma_func0_init(struct device *dev) pcir->classcode[0] = dev->class >> 8; pcir->classcode[1] = dev->class >> 16; pcir->classcode[2] = dev->class >> 24; - pcir->imagelength = sz; pcir->indicator = 0x80; - memcpy((void *)0xc0080, fake_vbt, sizeof(fake_vbt)); + vbt_size = generate_vbt (conf, (void *)(PCI_VGA_RAM_IMAGE_START + 0x80)); + fake_oprom_size = (0x80 + vbt_size + 511) / 512; + oh->size = fake_oprom_size; + pcir->imagelength = fake_oprom_size; } +#endif /* Post VBIOS init */
1
0
0
0
Patch set updated for coreboot: c033698 ivybridge: LVDS gfx init.
by Vladimir Serbinenko
29 Jul '14
29 Jul '14
Vladimir Serbinenko (phcoder(a)gmail.com) just uploaded a new patch set to gerrit, which you can find at
http://review.coreboot.org/5285
-gerrit commit c033698a017b238f041159eef7a356f7638e1c5f Author: Vladimir Serbinenko <phcoder(a)gmail.com> Date: Sun Feb 23 00:10:35 2014 +0100 ivybridge: LVDS gfx init. Change-Id: If71e9c94922cd4283d5e175dfd8757d398a72be1 Signed-off-by: Vladimir Serbinenko <phcoder(a)gmail.com> --- src/mainboard/lenovo/x230/Kconfig | 6 + src/mainboard/lenovo/x230/devicetree.cb | 6 + src/northbridge/intel/sandybridge/Kconfig | 4 + src/northbridge/intel/sandybridge/Makefile.inc | 1 + src/northbridge/intel/sandybridge/chip.h | 5 + src/northbridge/intel/sandybridge/gma.c | 4 +- .../intel/sandybridge/gma_ivybridge_lvds.c | 515 +++++++++++++++++++++ 7 files changed, 540 insertions(+), 1 deletion(-) diff --git a/src/mainboard/lenovo/x230/Kconfig b/src/mainboard/lenovo/x230/Kconfig index cc6228d..f835ab4 100644 --- a/src/mainboard/lenovo/x230/Kconfig +++ b/src/mainboard/lenovo/x230/Kconfig @@ -13,6 +13,12 @@ config BOARD_SPECIFIC_OPTIONS # dummy select HAVE_CMOS_DEFAULT select HAVE_ACPI_RESUME select HAVE_SMI_HANDLER + select EARLY_CBMEM_INIT + select VGA + select INTEL_EDID + select MAINBOARD_HAS_NATIVE_VGA_INIT + select MAINBOARD_HAS_NATIVE_VGA_INIT_TEXTMODECFG + select IVYBRIDGE_LVDS # Workaround for EC/KBC IRQ1. select SERIRQ_CONTINUOUS_MODE diff --git a/src/mainboard/lenovo/x230/devicetree.cb b/src/mainboard/lenovo/x230/devicetree.cb index a76de5f..1a93ad8 100644 --- a/src/mainboard/lenovo/x230/devicetree.cb +++ b/src/mainboard/lenovo/x230/devicetree.cb @@ -10,6 +10,12 @@ chip northbridge/intel/sandybridge register "gpu_panel_power_down_delay" = "100" # T5+T6: 10ms register "gpu_panel_power_backlight_on_delay" = "2100" # T3: 210ms register "gpu_panel_power_backlight_off_delay" = "2100" # T4: 210ms + register "gpu_use_spread_spectrum_clock" = "1" + register "gpu_lvds_dual_channel" = "0" + register "gpu_link_frequency_270_mhz" = "1" + register "gpu_lvds_num_lanes" = "1" + register "gpu_cpu_backlight" = "0x1155" + register "gpu_pch_backlight" = "0x11551155" device cpu_cluster 0 on chip cpu/intel/socket_rPGA989 diff --git a/src/northbridge/intel/sandybridge/Kconfig b/src/northbridge/intel/sandybridge/Kconfig index 2ceb945..883d36f 100644 --- a/src/northbridge/intel/sandybridge/Kconfig +++ b/src/northbridge/intel/sandybridge/Kconfig @@ -51,6 +51,10 @@ config CACHE_MRC_SIZE_KB int default 512 +config IVYBRIDGE_LVDS + bool + default n + config MRC_CACHE_SIZE hex depends on !CHROMEOS diff --git a/src/northbridge/intel/sandybridge/Makefile.inc b/src/northbridge/intel/sandybridge/Makefile.inc index 536656b..532a970 100644 --- a/src/northbridge/intel/sandybridge/Makefile.inc +++ b/src/northbridge/intel/sandybridge/Makefile.inc @@ -20,6 +20,7 @@ ramstage-y += ram_calc.c ramstage-y += northbridge.c ramstage-y += gma.c +ramstage-$(CONFIG_IVYBRIDGE_LVDS) += gma_ivybridge_lvds.c ramstage-$(CONFIG_GENERATE_ACPI_TABLES) += acpi.c ramstage-y += mrccache.c diff --git a/src/northbridge/intel/sandybridge/chip.h b/src/northbridge/intel/sandybridge/chip.h index 17bc7e7..cc32c37 100644 --- a/src/northbridge/intel/sandybridge/chip.h +++ b/src/northbridge/intel/sandybridge/chip.h @@ -38,4 +38,9 @@ struct northbridge_intel_sandybridge_config { u32 gpu_cpu_backlight; /* CPU Backlight PWM value */ u32 gpu_pch_backlight; /* PCH Backlight PWM value */ + + int gpu_use_spread_spectrum_clock; + int gpu_lvds_dual_channel; + int gpu_link_frequency_270_mhz; + int gpu_lvds_num_lanes; }; diff --git a/src/northbridge/intel/sandybridge/gma.c b/src/northbridge/intel/sandybridge/gma.c index a82a284..d271a1a 100644 --- a/src/northbridge/intel/sandybridge/gma.c +++ b/src/northbridge/intel/sandybridge/gma.c @@ -650,7 +650,9 @@ static void gma_func0_init(struct device *dev) physbase = pci_read_config32(dev, 0x5c) & ~0xf; graphics_base = dev->resource_list[1].base; - i915lightup(conf, physbase, iobase, mmiobase, graphics_base); + int lightup_ok = i915lightup(conf, physbase, iobase, mmiobase, graphics_base); + if (lightup_ok) + gfx_set_init_done(1); #endif } diff --git a/src/northbridge/intel/sandybridge/gma_ivybridge_lvds.c b/src/northbridge/intel/sandybridge/gma_ivybridge_lvds.c new file mode 100644 index 0000000..1f53a74 --- /dev/null +++ b/src/northbridge/intel/sandybridge/gma_ivybridge_lvds.c @@ -0,0 +1,515 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013, 2014 Vladimir Serbinenko + * + * 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 or (at your option) + * any later version 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 + */ + +#include <arch/io.h> +#include <console/console.h> +#include <delay.h> +#include <device/device.h> +#include <string.h> + +#include <drivers/intel/gma/edid.h> +#include <drivers/intel/gma/i915.h> +#include "gma.h" +#include "chip.h" +#include <pc80/vga.h> +#include <pc80/vga_io.h> + +#if IS_ENABLED(CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT) + +static void link_train(u32 mmio) +{ + write32(mmio+0xf000c,0x40); + write32(mmio+0x60100,0x40000); + write32(mmio+0xf0018,0x8ff); + write32(mmio+0xf1018,0x8ff); + write32(mmio+0xf000c,0x2040); + mdelay(1); + write32(mmio+0xf000c,0x2050); + write32(mmio+0x60100,0x44000); + mdelay(1); + write32(mmio+0x70008,0x40); + write32(mmio+0xe0300,0x60000418); + write32(mmio+0xf000c,0x22050); + write32(mmio+0x70008,0x50); + write32(mmio+0x70008,0x80000050); +} + +static void link_normal_operation(u32 mmio) +{ + write32(mmio + FDI_TX_CTL(0), 0x80044f02); + write32(mmio + FDI_RX_CTL(0), + FDI_RX_ENABLE | FDI_6BPC + | 0x2f50); +} + +static void enable_port(u32 mmio) +{ + write32(mmio + 0xec008, 0x2c010000); + write32(mmio + 0xec020, 0x2c010000); + write32(mmio + 0xec038, 0x2c010000); + write32(mmio + 0xec050, 0x2c010000); + write32(mmio + 0xec408, 0x2c010000); + write32(mmio + 0xec420, 0x2c010000); + write32(mmio + 0xec438, 0x2c010000); + write32(mmio + 0xec450, 0x2c010000); + write32(mmio + 0xf0010, 0x200090); + write32(mmio + 0xf1010, 0x200090); + write32(mmio + 0xf2010, 0x200090); + write32(mmio + 0xfd034, 0x8420000); + write32(mmio + 0x45010, 0x3); + write32(mmio + 0xf0060, 0x10); + write32(mmio + 0xf1060, 0x10); + write32(mmio + 0xf2060, 0x10); + write32(mmio + 0x9840, 0x0); + write32(mmio + 0x42000, 0xa0000000); + write32(mmio + 0xe4f00, 0x100030c); + write32(mmio + 0xe4f04, 0xb8230c); + write32(mmio + 0xe4f08, 0x6f8930c); + write32(mmio + 0xe4f0c, 0x5f8e38e); + write32(mmio + 0xe4f10, 0xb8030c); + write32(mmio + 0xe4f14, 0xb78830c); + write32(mmio + 0xe4f18, 0x9f8d3cf); + write32(mmio + 0xe4f1c, 0x1e8030c); + write32(mmio + 0xe4f20, 0x9f863cf); + write32(mmio + 0xe4f24, 0xff803cf); + read32(mmio + 0xe4100); + write32(mmio + 0xc4030, 0x10); + write32(mmio + 0xe4110, 0x8004003e); + write32(mmio + 0xe4114, 0x80060000); + write32(mmio + 0xe4118, 0x1000000); + read32(mmio + 0xe4110); + write32(mmio + 0xe4110, 0x5344003e); + read32(mmio + 0xe4110); + write32(mmio + 0xe4110, 0x8054003e); + read32(mmio + 0xe4110); + read32(mmio + 0xe4110); + write32(mmio + 0xe4110, 0x5344003e); + mdelay(1); + read32(mmio + 0xe4110); + write32(mmio + 0xe4110, 0x8054003e); + read32(mmio + 0xe4110); + read32(mmio + 0xe4110); + write32(mmio + 0xe4110, 0x5344003e); + mdelay(1); + read32(mmio + 0xe4110); + write32(mmio + 0xe4110, 0x8054003e); + read32(mmio + 0xe4110); + read32(mmio + 0xe4110); + write32(mmio + 0xe4110, 0x5344003e); + mdelay(1); + read32(mmio + 0xc4000); + read32(mmio + 0xe1140); + write32(mmio + 0xc4030, 0x10); + read32(mmio + 0xc4000); + write32(mmio + 0xe4f00, 0x100030c); + write32(mmio + 0xe4f04, 0xb8230c); + write32(mmio + 0xe4f08, 0x6f8930c); + write32(mmio + 0xe4f0c, 0x5f8e38e); + write32(mmio + 0xe4f10, 0xb8030c); + write32(mmio + 0xe4f14, 0xb78830c); + write32(mmio + 0xe4f18, 0x9f8d3cf); + write32(mmio + 0xe4f1c, 0x1e8030c); + write32(mmio + 0xe4f20, 0x9f863cf); + write32(mmio + 0xe4f24, 0xff803cf); + read32(mmio + 0xe4200); + write32(mmio + 0xc4030, 0x1010); + write32(mmio + 0xe4210, 0x8004003e); + write32(mmio + 0xe4214, 0x80060000); + write32(mmio + 0xe4218, 0x1002000); + read32(mmio + 0xe4210); + write32(mmio + 0xe4210, 0x5344003e); + read32(mmio + 0xe4210); + write32(mmio + 0xe4210, 0x8054003e); + read32(mmio + 0xe4210); + read32(mmio + 0xe4210); + write32(mmio + 0xe4210, 0x5344003e); + mdelay(1); + read32(mmio + 0xe4210); + write32(mmio + 0xe4210, 0x8054003e); + read32(mmio + 0xe4210); + read32(mmio + 0xe4210); + write32(mmio + 0xe4210, 0x5344003e); + mdelay(1); + read32(mmio + 0xe4210); + write32(mmio + 0xe4210, 0x8054003e); + read32(mmio + 0xe4210); + read32(mmio + 0xe4210); + write32(mmio + 0xe4210, 0x5344003e); + mdelay(1); + read32(mmio + 0xc4000); +} + +int i915lightup(const struct northbridge_intel_sandybridge_config *info, + u32 physbase, u16 piobase, u32 mmio, u32 lfb) +{ + int i; + u8 edid_data[128]; + struct edid edid; + + write32(mmio + 0x00070080, 0x00000000); + write32(mmio + DSPCNTR(0), 0x00000000); + write32(mmio + 0x00071180, 0x00000000); + write32(mmio + CPU_VGACNTRL, 0x0000298e | VGA_DISP_DISABLE); + write32(mmio + 0x0007019c, 0x00000000); + write32(mmio + 0x0007119c, 0x00000000); + write32(mmio + 0x000fc008, 0x2c010000); + write32(mmio + 0x000fc020, 0x2c010000); + write32(mmio + 0x000fc038, 0x2c010000); + write32(mmio + 0x000fc050, 0x2c010000); + write32(mmio + 0x000fc408, 0x2c010000); + write32(mmio + 0x000fc420, 0x2c010000); + write32(mmio + 0x000fc438, 0x2c010000); + write32(mmio + 0x000fc450, 0x2c010000); + vga_gr_write(0x18, 0); + write32(mmio + 0x00042004, 0x02000000); + write32(mmio + 0x000fd034, 0x8421ffe0); + + /* Setup GTT. */ + for (i = 0; i < 0x2000; i++) + { + outl((i << 2) | 1, piobase); + outl(physbase + (i << 12) + 1, piobase + 4); + } + + vga_misc_write(0x67); + + u8 cr[] = { 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3, + 0xff + }; + vga_cr_write(0x11, 0); + + for (i = 0; i <= 0x18; i++) + vga_cr_write(i, cr[i]); + + enable_port(mmio); + + intel_gmbus_read_edid(mmio + PCH_GMBUS0, 3, 0x50, edid_data, 128); + decode_edid(edid_data, + sizeof(edid_data), &edid); + + + /* Disable screen memory to prevent garbage from appearing. */ + vga_sr_write(1, vga_sr_read(1) | 0x20); + + u32 hactive = edid.x_resolution; + u32 vactive = edid.y_resolution; + u32 right_border = edid.hborder; + u32 bottom_border = edid.vborder; + int hpolarity = (edid.phsync == '-'); + int vpolarity = (edid.pvsync == '-'); + u32 vsync = edid.vspw; + u32 hsync = edid.hspw; + u32 vblank = edid.vbl; + u32 hblank = edid.hbl; + u32 hfront_porch = edid.hso; + u32 vfront_porch = edid.vso; + + u32 candp1, candn; + u32 best_delta = 0xffffffff; + + u32 target_frequency = info->gpu_lvds_dual_channel ? edid.pixel_clock + : (2 * edid.pixel_clock); + u32 pixel_p1 = 1; + u32 pixel_n = 1; + u32 pixel_m1 = 1; + u32 pixel_m2 = 1; + +#if !IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE) + vga_textmode_init(); +#else + vga_sr_write(1, 1); + vga_sr_write(0x2, 0xf); + vga_sr_write(0x3, 0x0); + vga_sr_write(0x4, 0xe); + vga_gr_write(0, 0x0); + vga_gr_write(1, 0x0); + vga_gr_write(2, 0x0); + vga_gr_write(3, 0x0); + vga_gr_write(4, 0x0); + vga_gr_write(5, 0x0); + vga_gr_write(6, 0x5); + vga_gr_write(7, 0xf); + vga_gr_write(0x10, 0x1); + vga_gr_write(0x11, 0); + + edid.bytes_per_line = (edid.bytes_per_line + 63) & ~63; + + write32(mmio + DSPCNTR(0), DISPPLANE_BGRX888); + write32(mmio + DSPADDR(0), 0); + write32(mmio + DSPSTRIDE(0), edid.bytes_per_line); + write32(mmio + DSPSURF(0), 0); + for (i = 0; i < 0x100; i++) + write32(mmio + LGC_PALETTE(0) + 4 * i, i * 0x010101); +#endif + + /* Find suitable divisors. */ + for (candp1 = 1; candp1 <= 8; candp1++) { + for (candn = 5; candn <= 10; candn++) { + u32 cur_frequency; + u32 m; /* 77 - 131. */ + u32 denom; /* 35 - 560. */ + u32 current_delta; + + denom = candn * candp1 * 7; + /* Doesnt overflow for up to + 5000000 kHz = 5 GHz. */ + m = (target_frequency * denom + 60000) / 120000; + + if (m < 77 || m > 131) + continue; + + cur_frequency = (120000 * m) / denom; + if (target_frequency > cur_frequency) + current_delta = target_frequency - cur_frequency; + else + current_delta = cur_frequency - target_frequency; + + + if (best_delta > current_delta) { + best_delta = current_delta; + pixel_n = candn; + pixel_p1 = candp1; + pixel_m2 = ((m + 3) % 5) + 7; + pixel_m1 = (m - pixel_m2) / 5; + } + } + } + + if (best_delta == 0xffffffff) { + printk (BIOS_ERR, "Couldn't find GFX clock divisors\n"); + return 0; + } + + u32 link_frequency = info->gpu_link_frequency_270_mhz ? 270000 : 162000; + u32 data_m1; + u32 data_n1 = 0x00800000; + u32 link_m1; + u32 link_n1 = 0x00080000; + + link_m1 = ((uint64_t)link_n1 * edid.pixel_clock) / link_frequency; + + data_m1 = ((uint64_t)data_n1 * 18 * edid.pixel_clock) + / (link_frequency * 8 * (info->gpu_lvds_num_lanes ? : 1)); + + printk(BIOS_INFO, "bringing up panel at resolution %d x %d\n", + hactive, vactive); + printk(BIOS_DEBUG, "Borders %d x %d\n", + right_border, bottom_border); + printk(BIOS_DEBUG, "Blank %d x %d\n", + hblank, vblank); + printk(BIOS_DEBUG, "Sync %d x %d\n", + hsync, vsync); + printk(BIOS_DEBUG, "Front porch %d x %d\n", + hfront_porch, vfront_porch); + printk(BIOS_DEBUG, (info->gpu_use_spread_spectrum_clock + ? "Spread spectrum clock\n" : "DREF clock\n")); + printk(BIOS_DEBUG, + info->gpu_lvds_dual_channel ? "Dual channel\n" : "Single channel\n"); + printk(BIOS_DEBUG, "Polarities %d, %d\n", + hpolarity, vpolarity); + printk(BIOS_DEBUG, "Data M1=%d, N1=%d\n", + data_m1, data_n1); + printk(BIOS_DEBUG, "Link frequency %d kHz\n", + link_frequency); + printk(BIOS_DEBUG, "Link M1=%d, N1=%d\n", + link_m1, link_n1); + printk(BIOS_DEBUG, "Pixel N=%d, M1=%d, M2=%d, P1=%d\n", + pixel_n, pixel_m1, pixel_m2, pixel_p1); + printk(BIOS_DEBUG, "Pixel clock %d kHz\n", + 120000 * (5 * pixel_m1 + pixel_m2) / pixel_n + / (pixel_p1 * 7)); + + write32(mmio + PCH_LVDS, + (hpolarity << 20) | (vpolarity << 21) + | (info->gpu_lvds_dual_channel ? LVDS_CLOCK_B_POWERUP_ALL + | LVDS_CLOCK_BOTH_POWERUP_ALL : 0) + | LVDS_BORDER_ENABLE | LVDS_CLOCK_A_POWERUP_ALL + | LVDS_DETECTED); + write32(mmio + BLC_PWM_CPU_CTL2, (1 << 31)); + write32(mmio + PCH_DREF_CONTROL, (info->gpu_use_spread_spectrum_clock + ? 0x1002 : 0x400)); + mdelay(1); + write32(mmio + PCH_PP_CONTROL, PANEL_UNLOCK_REGS + | (read32(mmio + PCH_PP_CONTROL) & ~PANEL_UNLOCK_MASK)); + write32(mmio + _PCH_FP0(0), + ((pixel_n - 2) << 16) + | ((pixel_m1 - 2) << 8) | pixel_m2); + write32(mmio + _PCH_DPLL(0), + DPLL_VCO_ENABLE | DPLLB_MODE_LVDS + | (info->gpu_lvds_dual_channel ? DPLLB_LVDS_P2_CLOCK_DIV_7 + : DPLLB_LVDS_P2_CLOCK_DIV_14) + | (0x10000 << (pixel_p1 - 1)) + | ((info->gpu_use_spread_spectrum_clock ? 3 : 0) << 13) + | (0x1 << (pixel_p1 - 1))); + + mdelay(1); + write32(mmio + 0xc7000, 0x8); + + mdelay(1); + write32(mmio + _PCH_DPLL(0), + DPLL_VCO_ENABLE | DPLLB_MODE_LVDS + | (info->gpu_lvds_dual_channel ? DPLLB_LVDS_P2_CLOCK_DIV_7 + : DPLLB_LVDS_P2_CLOCK_DIV_14) + | (0x10000 << (pixel_p1 - 1)) + | ((info->gpu_use_spread_spectrum_clock ? 3 : 0) << 13) + | (0x1 << (pixel_p1 - 1))); + /* Re-lock the registers. */ + write32(mmio + PCH_PP_CONTROL, + (read32(mmio + PCH_PP_CONTROL) & ~PANEL_UNLOCK_MASK)); + + write32(mmio + PCH_LVDS, + (hpolarity << 20) | (vpolarity << 21) + | (info->gpu_lvds_dual_channel ? LVDS_CLOCK_B_POWERUP_ALL + | LVDS_CLOCK_BOTH_POWERUP_ALL : 0) + | LVDS_BORDER_ENABLE | LVDS_CLOCK_A_POWERUP_ALL + | LVDS_DETECTED); + + write32(mmio + HTOTAL(0), + ((hactive + right_border + hblank - 1) << 16) + | (hactive - 1)); + write32(mmio + HBLANK(0), + ((hactive + right_border + hblank - 1) << 16) + | (hactive + right_border - 1)); + write32(mmio + HSYNC(0), + ((hactive + right_border + hfront_porch + hsync - 1) << 16) + | (hactive + right_border + hfront_porch - 1)); + + write32(mmio + VTOTAL(0), ((vactive + bottom_border + vblank - 1) << 16) + | (vactive - 1)); + write32(mmio + VBLANK(0), ((vactive + bottom_border + vblank - 1) << 16) + | (vactive + bottom_border - 1)); + write32(mmio + VSYNC(0), + (vactive + bottom_border + vfront_porch + vsync - 1) + | (vactive + bottom_border + vfront_porch - 1)); + + write32(mmio + PIPECONF(0), PIPECONF_DISABLE); + + write32(mmio + 0xf0008, 0); + +#if IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE) + write32(mmio + PIPESRC(0), ((hactive - 1) << 16) | (vactive - 1)); + write32(mmio + PF_CTL(0),0); + write32(mmio + PF_WIN_SZ(0), 0); + write32(mmio + PF_WIN_POS(0), 0); +#else + write32(mmio + PIPESRC(0), (719 << 16) | 399); + write32(mmio + PF_WIN_POS(0), 0); + write32(mmio + PF_CTL(0),PF_ENABLE | PF_FILTER_MED_3x3); + write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16)); +#endif + + mdelay(1); + + write32(mmio + PIPE_DATA_M1(0), 0x7e000000 | data_m1); + write32(mmio + PIPE_DATA_N1(0), data_n1); + write32(mmio + PIPE_LINK_M1(0), link_m1); + write32(mmio + PIPE_LINK_N1(0), link_n1); + + link_train(mmio); +#if IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE) + write32(mmio+CPU_VGACNTRL,0x298e | VGA_DISP_DISABLE); +#else + write32(mmio+CPU_VGACNTRL,0x298e); +#endif + write32(mmio+0x60100,0x44300); + write32(mmio+0x60100,0x80044f00); + + mdelay(1); + read32(mmio + 0x000f0014); // = 0x00000600 + +#if IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE) + write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE | DISPPLANE_BGRX888); + mdelay(1); +#endif + + write32(mmio + TRANS_HTOTAL(0), + ((hactive + right_border + hblank - 1) << 16) + | (hactive - 1)); + write32(mmio + TRANS_HBLANK(0), + ((hactive + right_border + hblank - 1) << 16) + | (hactive + right_border - 1)); + write32(mmio + TRANS_HSYNC(0), + ((hactive + right_border + hfront_porch + hsync - 1) << 16) + | (hactive + right_border + hfront_porch - 1)); + + write32(mmio + TRANS_VTOTAL(0), + ((vactive + bottom_border + vblank - 1) << 16) + | (vactive - 1)); + write32(mmio + TRANS_VBLANK(0), + ((vactive + bottom_border + vblank - 1) << 16) + | (vactive + bottom_border - 1)); + write32(mmio + TRANS_VSYNC(0), + (vactive + bottom_border + vfront_porch + vsync - 1) + | (vactive + bottom_border + vfront_porch - 1)); + + link_normal_operation(mmio); + + write32(mmio + PCH_PP_CONTROL, PANEL_UNLOCK_REGS | PANEL_POWER_OFF); + + mdelay(1); + + write32(mmio + PCH_TRANSCONF(0), TRANS_ENABLE | TRANS_6BPC +#if IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE) + | TRANS_STATE_MASK +#endif + ); + write32(mmio + PCH_LVDS, + LVDS_PORT_ENABLE + | (hpolarity << 20) | (vpolarity << 21) + | (info->gpu_lvds_dual_channel ? LVDS_CLOCK_B_POWERUP_ALL + | LVDS_CLOCK_BOTH_POWERUP_ALL : 0) + | LVDS_BORDER_ENABLE | LVDS_CLOCK_A_POWERUP_ALL + | LVDS_DETECTED); + + write32(mmio + PCH_PP_CONTROL, PANEL_UNLOCK_REGS | PANEL_POWER_OFF); + write32(mmio + PCH_PP_CONTROL, PANEL_UNLOCK_REGS | PANEL_POWER_RESET); + mdelay(1); + write32(mmio + PCH_PP_CONTROL, PANEL_UNLOCK_REGS + | PANEL_POWER_ON | PANEL_POWER_RESET); + + printk (BIOS_DEBUG, "waiting for panel powerup\n"); + while (1) + { + u32 reg32; + reg32 = read32(mmio + PCH_PP_STATUS); + if (((reg32 >> 28) & 3) == 0) + break; + } + printk (BIOS_DEBUG, "panel powered up\n"); + + write32(mmio + PCH_PP_CONTROL, PANEL_POWER_ON | PANEL_POWER_RESET); + + /* Enable screen memory. */ + vga_sr_write(1, vga_sr_read(1) & ~0x20); + + /* Clear interrupts. */ + write32(mmio + DEIIR, 0xffffffff); + write32(mmio + SDEIIR, 0xffffffff); + +#if IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE) + memset ((void *) lfb, 0, edid.x_resolution * edid.y_resolution * 4); + set_vbe_mode_info_valid(&edid, lfb); +#endif + return 1; +} + +#endif
1
0
0
0
Patch set updated for coreboot: 4b9e2a3 sandy/ivybridge: Native raminit.
by Vladimir Serbinenko
29 Jul '14
29 Jul '14
Vladimir Serbinenko (phcoder(a)gmail.com) just uploaded a new patch set to gerrit, which you can find at
http://review.coreboot.org/5786
-gerrit commit 4b9e2a342a2c054ec79faecd72e53d6ec11d2cba Author: Vladimir Serbinenko <phcoder(a)gmail.com> Date: Sun May 18 11:05:56 2014 +0200 sandy/ivybridge: Native raminit. Based on damo22's work and my X230 tracing. Works for my X230 in a variety of RAM configs. Also-By: Damien Zammit <damien(a)zamaudio.com> Change-Id: I1aa024c55a8416fc53b25e7123037df0e55a2769 Signed-off-by: Vladimir Serbinenko <phcoder(a)gmail.com> Signed-off-by: Damien Zammit <damien(a)zamaudio.com> --- src/cpu/intel/Makefile.inc | 1 + src/cpu/x86/smm/smmhandler_tseg.S | 2 +- src/cpu/x86/smm/smmrelocate.S | 4 +- src/device/dram/ddr3.c | 11 +- src/include/device/dram/ddr3.h | 5 + src/mainboard/lenovo/x230/Kconfig | 12 +- src/mainboard/lenovo/x230/romstage.c | 135 +- src/northbridge/intel/Makefile.inc | 1 + src/northbridge/intel/sandybridge/Kconfig | 13 +- src/northbridge/intel/sandybridge/Makefile.inc | 10 +- src/northbridge/intel/sandybridge/gma.c | 4 +- src/northbridge/intel/sandybridge/raminit_native.c | 3895 ++++++++++++++++++++ src/northbridge/intel/sandybridge/raminit_native.h | 29 + .../intel/sandybridge/raminit_patterns.h | 639 ++++ src/southbridge/intel/bd82x6x/Makefile.inc | 6 +- src/southbridge/intel/bd82x6x/early_me_native.c | 272 ++ src/southbridge/intel/bd82x6x/early_pch_native.c | 375 ++ src/southbridge/intel/bd82x6x/early_thermal.c | 70 + src/southbridge/intel/bd82x6x/pch.h | 2 + src/southbridge/intel/bd82x6x/smi.c | 3 - src/southbridge/intel/bd82x6x/usb_ehci.c | 33 + 21 files changed, 5413 insertions(+), 109 deletions(-) diff --git a/src/cpu/intel/Makefile.inc b/src/cpu/intel/Makefile.inc index 0392f69..68ea05d 100644 --- a/src/cpu/intel/Makefile.inc +++ b/src/cpu/intel/Makefile.inc @@ -19,6 +19,7 @@ subdirs-$(CONFIG_CPU_INTEL_SOCKET_RPGA989) += socket_rPGA989 subdirs-$(CONFIG_NORTHBRIDGE_INTEL_NEHALEM) += model_2065x subdirs-$(CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE) += model_206ax subdirs-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE) += model_206ax +subdirs-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE) += model_206ax subdirs-$(CONFIG_NORTHBRIDGE_INTEL_HASWELL) += haswell subdirs-$(CONFIG_NORTHBRIDGE_INTEL_FSP_SANDYBRIDGE) += fsp_model_206ax subdirs-$(CONFIG_NORTHBRIDGE_INTEL_FSP_IVYBRIDGE) += fsp_model_206ax diff --git a/src/cpu/x86/smm/smmhandler_tseg.S b/src/cpu/x86/smm/smmhandler_tseg.S index b33fcdf..380935a 100644 --- a/src/cpu/x86/smm/smmhandler_tseg.S +++ b/src/cpu/x86/smm/smmhandler_tseg.S @@ -57,7 +57,7 @@ #define SMI_UNLOCKED 1 #define __PRE_RAM__ -#if CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE || CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE +#if CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE || CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE || CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE #include <northbridge/intel/sandybridge/sandybridge.h> #define TSEG_BAR (DEFAULT_PCIEXBAR | TSEG) #elif CONFIG_NORTHBRIDGE_INTEL_NEHALEM diff --git a/src/cpu/x86/smm/smmrelocate.S b/src/cpu/x86/smm/smmrelocate.S index bdc9771..bc90fab 100644 --- a/src/cpu/x86/smm/smmrelocate.S +++ b/src/cpu/x86/smm/smmrelocate.S @@ -48,7 +48,7 @@ #if CONFIG_SMM_TSEG -#if CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE || CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE +#if CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE || CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE || CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE #include <northbridge/intel/sandybridge/sandybridge.h> #define TSEG_BAR (DEFAULT_PCIEXBAR | TSEG) #elif CONFIG_NORTHBRIDGE_INTEL_NEHALEM @@ -195,7 +195,7 @@ smm_relocate: xorl %edx, %edx wrmsr -#if CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE || CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE +#if CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE || CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE || CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE /* * IED base is top 4M of TSEG */ diff --git a/src/device/dram/ddr3.c b/src/device/dram/ddr3.c index 9b4f490..a43caed 100644 --- a/src/device/dram/ddr3.c +++ b/src/device/dram/ddr3.c @@ -110,7 +110,7 @@ int spd_decode_ddr3(dimm_attr * dimm, spd_raw_data spd) { int ret; u16 crc, spd_crc; - u8 ftb_divisor, ftb_dividend, capacity_shift, bus_width, sdram_width; + u8 ftb_divisor, ftb_dividend, capacity_shift, bus_width; u8 reg8; u32 mtb; /* medium time base */ unsigned int val, param; @@ -209,8 +209,8 @@ int spd_decode_ddr3(dimm_attr * dimm, spd_raw_data spd) printram(" Invalid SDRAM width\n"); ret = SPD_STATUS_INVALID_FIELD; } - sdram_width = (4 << val); - printram(" SDRAM width : %u\n", sdram_width); + dimm->width = (4 << val); + printram(" SDRAM width : %u\n", dimm->width); /* Memory bus width */ reg8 = spd[8]; @@ -236,7 +236,7 @@ int spd_decode_ddr3(dimm_attr * dimm, spd_raw_data spd) * capacity_shift * The rest is the JEDEC formula */ dimm->size_mb = ((1 << (capacity_shift + (25 - 20))) * bus_width - * dimm->ranks) / sdram_width; + * dimm->ranks) / dimm->width; /* Fine Timebase (FTB) Dividend/Divisor */ /* Dividend */ @@ -334,6 +334,9 @@ int spd_decode_ddr3(dimm_attr * dimm, spd_raw_data spd) printram(" DIMM Rank1 Address bits mirrored!!!\n"); } + dimm->reference_card = spd[62] & 0x1f; + printram(" DIMM Reference card %c\n", 'A' + dimm->reference_card); + return ret; } diff --git a/src/include/device/dram/ddr3.h b/src/include/device/dram/ddr3.h index b19c51c..ef0d0ec 100644 --- a/src/include/device/dram/ddr3.h +++ b/src/include/device/dram/ddr3.h @@ -37,6 +37,7 @@ * @{ */ #define TCK_1066MHZ 240 +#define TCK_933MHZ 275 #define TCK_800MHZ 320 #define TCK_666MHZ 384 #define TCK_533MHZ 480 @@ -137,6 +138,8 @@ typedef struct dimm_attr_st { u16 cas_supported; /* Flags extracted from SPD */ dimm_flags_t flags; + /* SDRAM width */ + u8 width; /* Number of ranks */ u8 ranks; /* Number or row address bits */ @@ -158,6 +161,8 @@ typedef struct dimm_attr_st { u32 tWTR; u32 tRTP; u32 tFAW; + + u8 reference_card; } dimm_attr; /** Result of the SPD decoding process */ diff --git a/src/mainboard/lenovo/x230/Kconfig b/src/mainboard/lenovo/x230/Kconfig index eb9cadc..cc6228d 100644 --- a/src/mainboard/lenovo/x230/Kconfig +++ b/src/mainboard/lenovo/x230/Kconfig @@ -3,7 +3,7 @@ if BOARD_LENOVO_X230 config BOARD_SPECIFIC_OPTIONS # dummy def_bool y select CPU_INTEL_SOCKET_RPGA989 - select NORTHBRIDGE_INTEL_IVYBRIDGE + select NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE select SOUTHBRIDGE_INTEL_C216 select EC_LENOVO_PMH7 select EC_LENOVO_H8 @@ -18,8 +18,8 @@ config BOARD_SPECIFIC_OPTIONS # dummy select SERIRQ_CONTINUOUS_MODE config HAVE_MRC_CACHE - bool - default n + bool + default y config HAVE_IFD_BIN bool @@ -41,10 +41,6 @@ config MMCONF_BASE_ADDRESS hex default 0xf0000000 -config CACHE_ROM_SIZE_OVERRIDE - hex - default 0x800000 - config IRQ_SLOT_COUNT int default 18 @@ -57,7 +53,7 @@ config USBDEBUG_HCD_INDEX int default 2 -config DRAM_GATE_GPIO +config DRAM_RESET_GATE_GPIO int default 10 diff --git a/src/mainboard/lenovo/x230/romstage.c b/src/mainboard/lenovo/x230/romstage.c index 8441db3..8c82e61 100644 --- a/src/mainboard/lenovo/x230/romstage.c +++ b/src/mainboard/lenovo/x230/romstage.c @@ -33,7 +33,7 @@ #include <cbmem.h> #include <console/console.h> #include "northbridge/intel/sandybridge/sandybridge.h" -#include "northbridge/intel/sandybridge/raminit.h" +#include "northbridge/intel/sandybridge/raminit_native.h" #include "southbridge/intel/bd82x6x/pch.h" #include "southbridge/intel/bd82x6x/gpio.h" #include <arch/cpu.h> @@ -109,66 +109,58 @@ static void rcba_config(void) RCBA32(BUC) = 0; } +static void +init_usb (void) +{ + const u32 rcba_dump[64] = { + /* 3500 */ 0x20000153, 0x20000153, 0x20000f57, 0x20000f57, + /* 3510 */ 0x20000f57, 0x20000f57, 0x20000153, 0x2000055b, + /* 3520 */ 0x20000153, 0x2000055b, 0x20000f57, 0x20000f57, + /* 3530 */ 0x20000f57, 0x20000f57, 0x00000000, 0x00000000, + /* 3540 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000, + /* 3550 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000, + /* 3560 */ 0x024c8001, 0x000024a3, 0x00040002, 0x01000050, + /* 3570 */ 0x02000772, 0x16000f9f, 0x1800ff4f, 0x0001d630, + /* 3580 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000, + /* 3590 */ 0x00000000, 0x00000000, 0x00000000, 0x00000040, + /* 35a0 */ 0x04000201, 0x00000200, 0x00000000, 0x00000000, + /* 35b0 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000, + /* 35c0 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000, + /* 35d0 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000, + /* 35e0 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000, + /* 35f0 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000, + }; + int i; + /* Activate PMBAR. */ + pci_write_config32(PCI_DEV(0, 0x1f, 0), PMBASE, DEFAULT_PMBASE | 1); + pci_write_config32(PCI_DEV(0, 0x1f, 0), PMBASE + 4, 0); + pci_write_config8(PCI_DEV(0, 0x1f, 0), 0x44 /* ACPI_CNTL */ , 0x80); /* Enable ACPI BAR */ + + /* Unlock registers. */ + outw (inw (DEFAULT_PMBASE | 0x003c) | 2, DEFAULT_PMBASE | 0x003c); + + for (i = 0; i < 64; i++) + write32 (DEFAULT_RCBABASE | (0x3500 + 4 * i), rcba_dump[i]); + + pcie_write_config32 (PCI_DEV (0, 0x14, 0), 0xe4, 0x00000000); + + /* Relock registers. */ + outw (0x0000, DEFAULT_PMBASE | 0x003c); +} + + void main(unsigned long bist) { - int boot_mode = 0; - int cbmem_was_initted; + int s3resume = 0; u32 pm1_cnt; u16 pm1_sts; + spd_raw_data spd[4]; if (MCHBAR16(SSKPD) == 0xCAFE) { outb(0x6, 0xcf9); hlt (); } - struct pei_data pei_data = { - .pei_version = PEI_VERSION, - .mchbar = DEFAULT_MCHBAR, - .dmibar = DEFAULT_DMIBAR, - .epbar = DEFAULT_EPBAR, - .pciexbar = CONFIG_MMCONF_BASE_ADDRESS, - .smbusbar = SMBUS_IO_BASE, - .wdbbar = 0x4000000, - .wdbsize = 0x1000, - .hpet_address = CONFIG_HPET_ADDRESS, - .rcba = DEFAULT_RCBABASE, - .pmbase = DEFAULT_PMBASE, - .gpiobase = DEFAULT_GPIOBASE, - .thermalbase = 0xfed08000, - .system_type = 0, // 0 Mobile, 1 Desktop/Server - .tseg_size = CONFIG_SMM_TSEG_SIZE, - .spd_addresses = { 0xA0, 0x00,0xA2,0x00 }, - .ts_addresses = { 0x00, 0x00, 0x00, 0x00 }, - .ec_present = 1, - .gbe_enable = 1, - .ddr3lv_support = 0, - // 0 = leave channel enabled - // 1 = disable dimm 0 on channel - // 2 = disable dimm 1 on channel - // 3 = disable dimm 0+1 on channel - .dimm_channel0_disabled = 2, - .dimm_channel1_disabled = 2, - .max_ddr3_freq = 1600, - .usb_port_config = { - /* enabled usb oc pin length */ - { 1, 0, 0x0080 }, /* P0 (left, fan side), OC 0 */ - { 1, 1, 0x0080 }, /* P1 (left touchpad side), OC 1 */ - { 1, 3, 0x0080 }, /* P2: dock, OC 3 */ - { 1, 0, 0x0040 }, /* P3: wwan, no OC */ - { 1, 0, 0x0080 }, /* P4: Wacom tablet on X230t, otherwise empty */ - { 1, 0, 0x0080 }, /* P5: Expresscard, no OC */ - { 0, 0, 0x0000 }, /* P6: Empty */ - { 1, 0, 0x0080 }, /* P7: dock, no OC */ - { 0, 0, 0x0000 }, /* P8: Empty */ - { 1, 5, 0x0080 }, /* P9: Right (EHCI debug), OC 5 */ - { 1, 0, 0x0040 }, /* P10: fingerprint reader, no OC */ - { 1, 0, 0x0040 }, /* P11: bluetooth, no OC. */ - { 1, 0, 0x0040 }, /* P12: wlan, no OC */ - { 1, 0, 0x0080 }, /* P13: webcam, no OC */ - }, - .ddr_refresh_rate_config = 2, /* Force double refresh rate */ - }; - timestamp_init(get_initial_timestamp()); timestamp_add_now(TS_START_ROMSTAGE); @@ -183,6 +175,8 @@ void main(unsigned long bist) setup_pch_gpios(&x230_gpio_map); + init_usb(); + /* Initialize console device(s) */ console_init(); @@ -204,7 +198,7 @@ void main(unsigned long bist) if ((pm1_sts & WAK_STS) && ((pm1_cnt >> 10) & 7) == 5) { if (acpi_s3_resume_allowed()) { printk(BIOS_DEBUG, "Resume from S3 detected.\n"); - boot_mode = 2; + s3resume = 1; /* Clear SLP_TYPE. This will break stage2 but * we care for that when we get there. */ @@ -218,31 +212,16 @@ void main(unsigned long bist) /* Enable SPD ROMs and DDR-III DRAM */ enable_smbus(); - /* Prepare USB controller early in S3 resume */ - if (boot_mode == 2) - enable_usb_bar(); - post_code(0x39); post_code(0x3a); - pei_data.boot_mode = boot_mode; timestamp_add_now(TS_BEFORE_INITRAM); - /* MRC.bin has a bug and sometimes halts (instead of reboot?). - */ - if (boot_mode != 2) - { - RCBA32(GCS) = RCBA32(GCS) & ~(1 << 5); /* reset */ - outw((0 << 11), DEFAULT_PMBASE | 0x60 | 0x08); /* let timer go */ - } - - sdram_initialize(&pei_data); + memset (spd, 0, sizeof (spd)); + read_spd (&spd[0], 0x50); + read_spd (&spd[2], 0x51); - if (boot_mode != 2) - { - RCBA32(GCS) = RCBA32(GCS) | (1 << 5); /* No reset */ - outw((1 << 11), DEFAULT_PMBASE | 0x60 | 0x08); /* halt timer */ - } + init_dram_ddr3 (spd, 1, TCK_800MHZ, s3resume); timestamp_add_now(TS_AFTER_INITRAM); post_code(0x3c); @@ -250,13 +229,7 @@ void main(unsigned long bist) rcba_config(); post_code(0x3d); - quick_ram_check(); - post_code(0x3e); - MCHBAR16(SSKPD) = 0xCAFE; - cbmem_was_initted = !cbmem_recovery(boot_mode==2); - if (boot_mode!=2) - save_mrc_data(&pei_data); #if CONFIG_HAVE_ACPI_RESUME /* If there is no high memory area, we didn't boot before, so @@ -266,18 +239,14 @@ void main(unsigned long bist) *(u32 *)CBMEM_BOOT_MODE = 0; *(u32 *)CBMEM_RESUME_BACKUP = 0; - if ((boot_mode == 2) && cbmem_was_initted) { + if (s3resume) { void *resume_backup_memory = cbmem_find(CBMEM_ID_RESUME); if (resume_backup_memory) { - *(u32 *)CBMEM_BOOT_MODE = boot_mode; + *(u32 *)CBMEM_BOOT_MODE = 2; *(u32 *)CBMEM_RESUME_BACKUP = (u32)resume_backup_memory; } /* Magic for S3 resume */ pci_write_config32(PCI_DEV(0, 0x00, 0), SKPAD, 0xcafed00d); - } else if (boot_mode == 2) { - /* Failed S3 resume, reset to come up cleanly */ - outb(0x6, 0xcf9); - hlt(); } else { pci_write_config32(PCI_DEV(0, 0x00, 0), SKPAD, 0xcafebabe); } diff --git a/src/northbridge/intel/Makefile.inc b/src/northbridge/intel/Makefile.inc index 808a1b2..f1c2540 100644 --- a/src/northbridge/intel/Makefile.inc +++ b/src/northbridge/intel/Makefile.inc @@ -15,6 +15,7 @@ subdirs-$(CONFIG_NORTHBRIDGE_INTEL_I5000) += i5000 subdirs-$(CONFIG_NORTHBRIDGE_INTEL_NEHALEM) += nehalem subdirs-$(CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE) += sandybridge subdirs-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE) += sandybridge +subdirs-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE) += sandybridge subdirs-$(CONFIG_NORTHBRIDGE_INTEL_HASWELL) += haswell subdirs-$(CONFIG_NORTHBRIDGE_INTEL_FSP_SANDYBRIDGE) += fsp_sandybridge subdirs-$(CONFIG_NORTHBRIDGE_INTEL_FSP_IVYBRIDGE) += fsp_sandybridge diff --git a/src/northbridge/intel/sandybridge/Kconfig b/src/northbridge/intel/sandybridge/Kconfig index f13b58d..2ceb945 100644 --- a/src/northbridge/intel/sandybridge/Kconfig +++ b/src/northbridge/intel/sandybridge/Kconfig @@ -33,7 +33,15 @@ config NORTHBRIDGE_INTEL_IVYBRIDGE select DYNAMIC_CBMEM select CPU_INTEL_MODEL_306AX -if NORTHBRIDGE_INTEL_SANDYBRIDGE || NORTHBRIDGE_INTEL_IVYBRIDGE +config NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE + bool + select CACHE_MRC_BIN + select MMCONF_SUPPORT + select MMCONF_SUPPORT_DEFAULT + select CPU_INTEL_MODEL_306AX + select HAVE_DEBUG_RAM_SETUP + +if NORTHBRIDGE_INTEL_SANDYBRIDGE || NORTHBRIDGE_INTEL_IVYBRIDGE || NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE config VGA_BIOS_ID string @@ -50,7 +58,8 @@ config MRC_CACHE_SIZE config DCACHE_RAM_BASE hex - default 0xff7e0000 + default 0xff7e0000 if !NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE + default 0xfefe0000 if NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE config DCACHE_RAM_SIZE hex diff --git a/src/northbridge/intel/sandybridge/Makefile.inc b/src/northbridge/intel/sandybridge/Makefile.inc index a201745..536656b 100644 --- a/src/northbridge/intel/sandybridge/Makefile.inc +++ b/src/northbridge/intel/sandybridge/Makefile.inc @@ -25,7 +25,10 @@ ramstage-$(CONFIG_GENERATE_ACPI_TABLES) += acpi.c ramstage-y += mrccache.c romstage-y += ram_calc.c -romstage-y += raminit.c +romstage-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE) += raminit.c +romstage-$(CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE) += raminit.c +romstage-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE) += raminit_native.c +romstage-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE) += ../../../device/dram/ddr3.c romstage-y += mrccache.c romstage-y += early_init.c romstage-y += report_platform.c @@ -48,7 +51,10 @@ $(obj)/mrc.cache: $(obj)/config.h cbfs-files-$(CONFIG_HAVE_MRC_CACHE) += mrc.cache mrc.cache-file := $(obj)/mrc.cache -mrc.cache-position := 0xfffd0000 +mrc-cache-position-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE) := 0xfffd0000 +mrc-cache-position-$(CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE) := 0xfffd0000 +mrc-cache-position-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE) := 0xfffe0000 +mrc.cache-position := $(mrc-cache-position-y) mrc.cache-type := 0xac endif diff --git a/src/northbridge/intel/sandybridge/gma.c b/src/northbridge/intel/sandybridge/gma.c index d271a1a..a82a284 100644 --- a/src/northbridge/intel/sandybridge/gma.c +++ b/src/northbridge/intel/sandybridge/gma.c @@ -650,9 +650,7 @@ static void gma_func0_init(struct device *dev) physbase = pci_read_config32(dev, 0x5c) & ~0xf; graphics_base = dev->resource_list[1].base; - int lightup_ok = i915lightup(conf, physbase, iobase, mmiobase, graphics_base); - if (lightup_ok) - gfx_set_init_done(1); + i915lightup(conf, physbase, iobase, mmiobase, graphics_base); #endif } diff --git a/src/northbridge/intel/sandybridge/raminit_native.c b/src/northbridge/intel/sandybridge/raminit_native.c new file mode 100644 index 0000000..d4a2c42 --- /dev/null +++ b/src/northbridge/intel/sandybridge/raminit_native.c @@ -0,0 +1,3895 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2014 Damien Zammit <damien(a)zamaudio.com> + * Copyright (C) 2014 Vladimir Serbinenko <phcoder(a)gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <console/console.h> +#include <console/usb.h> +#include <bootmode.h> +#include <string.h> +#include <arch/hlt.h> +#include <arch/io.h> +#include <cbmem.h> +#include <arch/cbfs.h> +#include <cbfs.h> +#include <ip_checksum.h> +#include <pc80/mc146818rtc.h> +#include <device/pci_def.h> +#include "raminit_native.h" +#include "sandybridge.h" +#include <delay.h> +#include <lib.h> + +/* Management Engine is in the southbridge */ +#include "southbridge/intel/bd82x6x/me.h" +/* For SPD. */ +#include "southbridge/intel/bd82x6x/smbus.h" +#include "arch/cpu.h" +#include "cpu/x86/msr.h" + +/* FIXME: no ECC support. */ +/* FIXME: no support for 3-channel chipsets. */ +/* FIXME: no S3. */ + +#define BASEFREQ 133 +#define tDLLK 512 + +#define IS_SANDY_CPU(x) ((x & 0xffff0) == 0x206a0) +#define IS_SANDY_CPU_C(x) ((x & 0xf) == 4) +#define IS_SANDY_CPU_D0(x) ((x & 0xf) == 5) +#define IS_SANDY_CPU_D1(x) ((x & 0xf) == 6) +#define IS_SANDY_CPU_D2(x) ((x & 0xf) == 7) + +#define IS_IVY_CPU(x) ((x & 0xffff0) == 0x306a0) +#define IS_IVY_CPU_C(x) ((x & 0xf) == 4) +#define IS_IVY_CPU_K(x) ((x & 0xf) == 5) +#define IS_IVY_CPU_D(x) ((x & 0xf) == 6) +#define IS_IVY_CPU_E(x) ((x & 0xf) >= 8) + +#define NUM_CHANNELS 2 +#define NUM_SLOTRANKS 4 +#define NUM_SLOTS 2 +#define NUM_LANES 8 + +/* FIXME: Vendor BIOS uses 64 but our algorithms are less + performant and even 1 seems to be enough in practice. */ +#define NUM_PATTERNS 4 + +typedef struct odtmap_st { + u16 rttwr; + u16 rttnom; +} odtmap; + +typedef struct dimm_info_st { + dimm_attr dimm[NUM_CHANNELS][NUM_SLOTS]; +} dimm_info; + +struct ram_rank_timings { + /* Register 4024. One byte per slotrank. */ + u8 val_4024; + /* Register 4028. One nibble per slotrank. */ + u8 val_4028; + + int val_320c; + + struct ram_lane_timings { + /* lane register offset 0x10. */ + u16 timA; /* bits 0 - 5, bits 16 - 18 */ + u8 rising; /* bits 8 - 14 */ + u8 falling; /* bits 20 - 26. */ + + /* lane register offset 0x20. */ + int timC; /* bit 0 - 5, 19. */ + u16 timB; /* bits 8 - 13, 15 - 17. */ + } lanes[NUM_LANES]; +}; + +struct ramctr_timing_st; + +typedef struct ramctr_timing_st { + int mobile; + + 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 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 */ + + u32 tREFI; + u32 tMOD; + u32 tXSOffset; + u32 tWLO; + u32 tCKE; + u32 tXPDLL; + u32 tXP; + u32 tAONPD; + + u16 reg_5064b0; /* bits 0-11. */ + + u8 rankmap[NUM_CHANNELS]; + int ref_card_offset[NUM_CHANNELS]; + u32 mad_dimm[NUM_CHANNELS]; + int channel_size_mb[NUM_CHANNELS]; + u32 reg_4004_b30[NUM_CHANNELS]; + + int reg_c14_offset; + int reg_320c_range_threshold; + + int edge_offset[3]; + int timC_offset[3]; + + int extended_temperature_range; + int auto_self_refresh; + + int rank_mirror[NUM_CHANNELS][NUM_SLOTRANKS]; + + struct ram_rank_timings timings[NUM_CHANNELS][NUM_SLOTRANKS]; +} ramctr_timing; + +#define SOUTHBRIDGE PCI_DEV(0, 0x1f, 0) +#define NORTHBRIDGE PCI_DEV(0, 0x0, 0) +#define FOR_ALL_LANES for (lane = 0; lane < NUM_LANES; lane++) +#define FOR_ALL_CHANNELS for (channel = 0; channel < NUM_CHANNELS; channel++) +#define FOR_ALL_POPULATED_RANKS for (slotrank = 0; slotrank < NUM_SLOTRANKS; slotrank++) if (ctrl->rankmap[channel] & (1 << slotrank)) +#define FOR_ALL_POPULATED_CHANNELS for (channel = 0; channel < NUM_CHANNELS; channel++) if (ctrl->rankmap[channel]) +#define max(a,b) ((a) > (b) ? (a) : (b)) +#define min(a,b) ((a) < (b) ? (a) : (b)) +#define MAX_EDGE_TIMING 71 +#define MAX_TIMC 127 +#define MAX_TIMB 511 +#define MAX_TIMA 127 + +static void program_timings(ramctr_timing * ctrl, int channel); + +static const char *ecc_decoder[] = { + "inactive", + "active on IO", + "disabled on IO", + "active" +}; + +static void wait_txt_clear(void) +{ + struct cpuid_result cp; + + cp = cpuid_ext(0x1, 0x0); + /* Check if TXT is supported? */ + if (!(cp.ecx & 0x40)) + return; + /* Some TXT public bit. */ + if (!(read32(0xfed30010) & 1)) + return; + /* Wait for TXT clear. */ + while (!(read8(0xfed40000) & (1 << 7))) ; +} + +static void sfence(void) +{ + asm volatile ("sfence"); +} + +/* + * Dump in the log memory controller configuration as read from the memory + * controller registers. + */ +static void report_memory_config(void) +{ + u32 addr_decoder_common, addr_decode_ch[NUM_CHANNELS]; + int i; + + addr_decoder_common = MCHBAR32(0x5000); + addr_decode_ch[0] = MCHBAR32(0x5004); + addr_decode_ch[1] = MCHBAR32(0x5008); + + printk(BIOS_DEBUG, "memcfg DDR3 clock %d MHz\n", + (MCHBAR32(0x5e04) * 13333 * 2 + 50) / 100); + printk(BIOS_DEBUG, "memcfg channel assignment: A: %d, B % d, C % d\n", + addr_decoder_common & 3, (addr_decoder_common >> 2) & 3, + (addr_decoder_common >> 4) & 3); + + for (i = 0; i < ARRAY_SIZE(addr_decode_ch); i++) { + u32 ch_conf = addr_decode_ch[i]; + printk(BIOS_DEBUG, "memcfg channel[%d] config (%8.8x):\n", i, + ch_conf); + printk(BIOS_DEBUG, " ECC %s\n", + ecc_decoder[(ch_conf >> 24) & 3]); + printk(BIOS_DEBUG, " enhanced interleave mode %s\n", + ((ch_conf >> 22) & 1) ? "on" : "off"); + printk(BIOS_DEBUG, " rank interleave %s\n", + ((ch_conf >> 21) & 1) ? "on" : "off"); + printk(BIOS_DEBUG, " DIMMA %d MB width x%d %s rank%s\n", + ((ch_conf >> 0) & 0xff) * 256, + ((ch_conf >> 19) & 1) ? 16 : 8, + ((ch_conf >> 17) & 1) ? "dual" : "single", + ((ch_conf >> 16) & 1) ? "" : ", selected"); + printk(BIOS_DEBUG, " DIMMB %d MB width x%d %s rank%s\n", + ((ch_conf >> 8) & 0xff) * 256, + ((ch_conf >> 20) & 1) ? 16 : 8, + ((ch_conf >> 18) & 1) ? "dual" : "single", + ((ch_conf >> 16) & 1) ? ", selected" : ""); + } +} + +static void post_system_agent_init(void) +{ + /* If PCIe init is skipped, set the PEG clock gating */ + MCHBAR32(0x7010) = MCHBAR32(0x7010) | 0x01; +} + +void read_spd(spd_raw_data * spd, u8 addr) +{ + int j; + for (j = 0; j < 256; j++) + (*spd)[j] = do_smbus_read_byte(SMBUS_IO_BASE, addr, j); +} + +static void dram_find_spds_ddr3(spd_raw_data * spd, dimm_info * dimm, + ramctr_timing * ctrl) +{ + int dimms = 0; + int channel, slot, spd_slot; + + memset (ctrl->rankmap, 0, sizeof (ctrl->rankmap)); + + ctrl->extended_temperature_range = 1; + ctrl->auto_self_refresh = 1; + + FOR_ALL_CHANNELS { + ctrl->channel_size_mb[channel] = 0; + + for (slot = 0; slot < NUM_SLOTS; slot++) { + spd_slot = 2 * channel + slot; + spd_decode_ddr3(&dimm->dimm[channel][slot], spd[spd_slot]); + if (dimm->dimm[channel][slot].dram_type != SPD_MEMORY_TYPE_SDRAM_DDR3) { + // set dimm invalid + dimm->dimm[channel][slot].ranks = 0; + dimm->dimm[channel][slot].size_mb = 0; + continue; + } + + dram_print_spd_ddr3(&dimm->dimm[channel][slot]); + dimms++; + ctrl->rank_mirror[channel][slot * 2] = 0; + ctrl->rank_mirror[channel][slot * 2 + 1] = dimm->dimm[channel][slot].flags.pins_mirrored; + ctrl->channel_size_mb[channel] += dimm->dimm[channel][slot].size_mb; + + ctrl->auto_self_refresh &= dimm->dimm[channel][slot].flags.asr; + ctrl->extended_temperature_range &= dimm->dimm[channel][slot].flags.ext_temp_refresh; + + ctrl->rankmap[channel] = ((1 << dimm->dimm[channel][slot].ranks) - 1) << (2 * slot); + printk(BIOS_DEBUG, "rankmap[%d] = 0x%x\n", channel, ctrl->rankmap[channel]); + } + if ((ctrl->rankmap[channel] & 3) && (ctrl->rankmap[channel] & 0xc) + && dimm->dimm[channel][0].reference_card <= 5 && dimm->dimm[channel][1].reference_card <= 5) { + const int ref_card_offset_table[6][6] = { + { 0, 0, 0, 0, 2, 2, }, + { 0, 0, 0, 0, 2, 2, }, + { 0, 0, 0, 0, 2, 2, }, + { 0, 0, 0, 0, 1, 1, }, + { 2, 2, 2, 1, 0, 0, }, + { 2, 2, 2, 1, 0, 0, }, + }; + ctrl->ref_card_offset[channel] = ref_card_offset_table[dimm->dimm[channel][0].reference_card] + [dimm->dimm[channel][1].reference_card]; + } else + ctrl->ref_card_offset[channel] = 0; + } + + if (!dimms) + die("No DIMMs were found"); +} + +static void dram_find_common_params(const dimm_info * dimms, + ramctr_timing * ctrl) +{ + size_t valid_dimms; + int channel, slot; + ctrl->cas_supported = 0xff; + valid_dimms = 0; + FOR_ALL_CHANNELS for (slot = 0; slot < 2; slot++) { + const dimm_attr *dimm = &dimms->dimm[channel][slot]; + if (dimm->dram_type != SPD_MEMORY_TYPE_SDRAM_DDR3) + continue; + valid_dimms++; + + /* 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->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 u8 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]; +} + +/* Frequency multiplier. */ +static u32 get_FRQ(u32 tCK) +{ + u32 FRQ; + FRQ = 256000 / (tCK * BASEFREQ); + if (FRQ > 8) + return 8; + if (FRQ < 3) + return 3; + return FRQ; +} + +static u32 get_REFI(u32 tCK) +{ + /* Get REFI based on MCU frequency using the following rule: + * _________________________________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * REFI: | 3120 | 4160 | 5200 | 6240 | 7280 | 8320 | + */ + static const u32 frq_refi_map[] = + { 3120, 4160, 5200, 6240, 7280, 8320 }; + return frq_refi_map[get_FRQ(tCK) - 3]; +} + +static u8 get_XSOffset(u32 tCK) +{ + /* Get XSOffset based on MCU frequency using the following rule: + * _________________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * XSOffset : | 4 | 6 | 7 | 8 | 10 | 11 | + */ + static const u8 frq_xs_map[] = { 4, 6, 7, 8, 10, 11 }; + return frq_xs_map[get_FRQ(tCK) - 3]; +} + +static u8 get_MOD(u32 tCK) +{ + /* Get MOD based on MCU frequency using the following rule: + * _____________________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * MOD : | 12 | 12 | 12 | 12 | 15 | 16 | + */ + static const u8 frq_mod_map[] = { 12, 12, 12, 12, 15, 16 }; + return frq_mod_map[get_FRQ(tCK) - 3]; +} + +static u8 get_WLO(u32 tCK) +{ + /* Get WLO based on MCU frequency using the following rule: + * _______________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * WLO : | 4 | 5 | 6 | 6 | 8 | 8 | + */ + static const u8 frq_wlo_map[] = { 4, 5, 6, 6, 8, 8 }; + return frq_wlo_map[get_FRQ(tCK) - 3]; +} + +static u8 get_CKE(u32 tCK) +{ + /* Get CKE based on MCU frequency using the following rule: + * _______________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * CKE : | 3 | 3 | 4 | 4 | 5 | 6 | + */ + static const u8 frq_cke_map[] = { 3, 3, 4, 4, 5, 6 }; + return frq_cke_map[get_FRQ(tCK) - 3]; +} + +static u8 get_XPDLL(u32 tCK) +{ + /* Get XPDLL based on MCU frequency using the following rule: + * _____________________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * XPDLL : | 10 | 13 | 16 | 20 | 23 | 26 | + */ + static const u8 frq_xpdll_map[] = { 10, 13, 16, 20, 23, 26 }; + return frq_xpdll_map[get_FRQ(tCK) - 3]; +} + +static u8 get_XP(u32 tCK) +{ + /* Get XP based on MCU frequency using the following rule: + * _______________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * XP : | 3 | 4 | 4 | 5 | 6 | 7 | + */ + static const u8 frq_xp_map[] = { 3, 4, 4, 5, 6, 7 }; + return frq_xp_map[get_FRQ(tCK) - 3]; +} + +static u8 get_AONPD(u32 tCK) +{ + /* Get AONPD based on MCU frequency using the following rule: + * ________________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * AONPD : | 4 | 5 | 6 | 8 | 8 | 10 | + */ + static const u8 frq_aonpd_map[] = { 4, 5, 6, 8, 8, 10 }; + return frq_aonpd_map[get_FRQ(tCK) - 3]; +} + +static u32 get_COMP2(u32 tCK) +{ + /* Get COMP2 based on MCU frequency using the following rule: + * ___________________________________________________________ + * FRQ : | 3 | 4 | 5 | 6 | 7 | 8 | + * COMP : | D6BEDCC | CE7C34C | CA57A4C | C6369CC | C42514C | C21410C | + */ + static const u32 frq_comp2_map[] = { 0xD6BEDCC, 0xCE7C34C, 0xCA57A4C, + 0xC6369CC, 0xC42514C, 0xC21410C + }; + return frq_comp2_map[get_FRQ(tCK) - 3]; +} + +static void dram_timing(ramctr_timing * ctrl) +{ + u8 val; + u32 val32; + + /* Maximum supported DDR3 frequency is 1066MHz (DDR3 2133) so make sure + * we cap it if we have faster DIMMs. + * Then, align it to the closest JEDEC standard frequency */ + if (ctrl->tCK <= TCK_1066MHZ) { + ctrl->tCK = TCK_1066MHZ; + ctrl->edge_offset[0] = 16; + ctrl->edge_offset[1] = 7; + ctrl->edge_offset[2] = 7; + ctrl->timC_offset[0] = 18; + ctrl->timC_offset[1] = 7; + ctrl->timC_offset[2] = 7; + ctrl->reg_c14_offset = 16; + ctrl->reg_5064b0 = 0x218; + ctrl->reg_320c_range_threshold = 13; + } else if (ctrl->tCK <= TCK_933MHZ) { + ctrl->tCK = TCK_933MHZ; + ctrl->edge_offset[0] = 14; + ctrl->edge_offset[1] = 6; + ctrl->edge_offset[2] = 6; + ctrl->timC_offset[0] = 15; + ctrl->timC_offset[1] = 6; + ctrl->timC_offset[2] = 6; + ctrl->reg_c14_offset = 14; + ctrl->reg_5064b0 = 0x1d5; + ctrl->reg_320c_range_threshold = 15; + } else if (ctrl->tCK <= TCK_800MHZ) { + ctrl->tCK = TCK_800MHZ; + ctrl->edge_offset[0] = 13; + ctrl->edge_offset[1] = 5; + ctrl->edge_offset[2] = 5; + ctrl->timC_offset[0] = 14; + ctrl->timC_offset[1] = 5; + ctrl->timC_offset[2] = 5; + ctrl->reg_c14_offset = 12; + ctrl->reg_5064b0 = 0x193; + ctrl->reg_320c_range_threshold = 15; + } else if (ctrl->tCK <= TCK_666MHZ) { + ctrl->tCK = TCK_666MHZ; + ctrl->edge_offset[0] = 10; + ctrl->edge_offset[1] = 4; + ctrl->edge_offset[2] = 4; + ctrl->timC_offset[0] = 11; + ctrl->timC_offset[1] = 4; + ctrl->timC_offset[2] = 4; + ctrl->reg_c14_offset = 10; + ctrl->reg_5064b0 = 0x150; + ctrl->reg_320c_range_threshold = 16; + } else if (ctrl->tCK <= TCK_533MHZ) { + ctrl->tCK = TCK_533MHZ; + ctrl->edge_offset[0] = 8; + ctrl->edge_offset[1] = 3; + ctrl->edge_offset[2] = 3; + ctrl->timC_offset[0] = 9; + ctrl->timC_offset[1] = 3; + ctrl->timC_offset[2] = 3; + ctrl->reg_c14_offset = 8; + ctrl->reg_5064b0 = 0x10d; + ctrl->reg_320c_range_threshold = 17; + } else { + ctrl->tCK = TCK_400MHZ; + ctrl->edge_offset[0] = 6; + ctrl->edge_offset[1] = 2; + ctrl->edge_offset[2] = 2; + ctrl->timC_offset[0] = 6; + ctrl->timC_offset[1] = 2; + ctrl->timC_offset[2] = 2; + ctrl->reg_c14_offset = 8; + ctrl->reg_5064b0 = 0xcd; + ctrl->reg_320c_range_threshold = 17; + } + + val32 = (1000 << 8) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected DRAM frequency: %u MHz\n", val32); + + /* Find CAS and CWL latencies */ + val = (ctrl->tAA + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "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)))) + printk(BIOS_DEBUG, "CAS not supported\n"); + printk(BIOS_DEBUG, "Selected CAS latency : %uT\n", val); + ctrl->CAS = val; + ctrl->CWL = get_CWL(ctrl->CAS); + printk(BIOS_DEBUG, "Selected CWL latency : %uT\n", ctrl->CWL); + + /* Find tRCD */ + ctrl->tRCD = (ctrl->tRCD + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected tRCD : %uT\n", ctrl->tRCD); + + ctrl->tRP = (ctrl->tRP + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected tRP : %uT\n", ctrl->tRP); + + /* Find tRAS */ + ctrl->tRAS = (ctrl->tRAS + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected tRAS : %uT\n", ctrl->tRAS); + + /* Find tWR */ + ctrl->tWR = (ctrl->tWR + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected tWR : %uT\n", ctrl->tWR); + + /* Find tFAW */ + ctrl->tFAW = (ctrl->tFAW + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected tFAW : %uT\n", ctrl->tFAW); + + /* Find tRRD */ + ctrl->tRRD = (ctrl->tRRD + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected tRRD : %uT\n", ctrl->tRRD); + + /* Find tRTP */ + ctrl->tRTP = (ctrl->tRTP + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected tRTP : %uT\n", ctrl->tRTP); + + /* Find tWTR */ + ctrl->tWTR = (ctrl->tWTR + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected tWTR : %uT\n", ctrl->tWTR); + + /* Refresh-to-Active or Refresh-to-Refresh (tRFC) */ + ctrl->tRFC = (ctrl->tRFC + ctrl->tCK - 1) / ctrl->tCK; + printk(BIOS_DEBUG, "Selected tRFC : %uT\n", ctrl->tRFC); + + ctrl->tREFI = get_REFI(ctrl->tCK); + ctrl->tMOD = get_MOD(ctrl->tCK); + ctrl->tXSOffset = get_XSOffset(ctrl->tCK); + ctrl->tWLO = get_WLO(ctrl->tCK); + ctrl->tCKE = get_CKE(ctrl->tCK); + ctrl->tXPDLL = get_XPDLL(ctrl->tCK); + ctrl->tXP = get_XP(ctrl->tCK); + ctrl->tAONPD = get_AONPD(ctrl->tCK); +} + +static void dram_freq(ramctr_timing * ctrl) +{ + u8 val2; + u32 reg1 = 0; + + /* Step 1 - Set target PCU frequency */ + + if (ctrl->tCK <= TCK_1066MHZ) { + ctrl->tCK = TCK_1066MHZ; + } else if (ctrl->tCK <= TCK_933MHZ) { + ctrl->tCK = TCK_933MHZ; + } else if (ctrl->tCK <= TCK_800MHZ) { + ctrl->tCK = TCK_800MHZ; + } else if (ctrl->tCK <= TCK_666MHZ) { + ctrl->tCK = TCK_666MHZ; + } else if (ctrl->tCK <= TCK_533MHZ) { + ctrl->tCK = TCK_533MHZ; + } else { + ctrl->tCK = TCK_400MHZ; + } + + /* Frequency mulitplier. */ + u32 FRQ = get_FRQ(ctrl->tCK); + + /* Step 2 - Select frequency in the MCU */ + reg1 = FRQ; + reg1 |= 0x80000000; // set running bit + MCHBAR32(0x5e00) = reg1; + while (reg1 & 0x80000000) { + printk(BIOS_DEBUG, " PLL busy..."); + reg1 = MCHBAR32(0x5e00); + } + printk(BIOS_DEBUG, "done\n"); + + /* Step 3 - Verify lock frequency */ + reg1 = MCHBAR32(0x5e04); + val2 = (u8) reg1; + if (val2 < FRQ) { + printk(BIOS_DEBUG, "Lock frequency is lower, recalculating\n"); + ctrl->tCK = 256000 / (val2 * BASEFREQ); + } + printk(BIOS_DEBUG, "MCU frequency is set at : %d MHz\n", + (1000 << 8) / ctrl->tCK); +} + +static void dram_xover(ramctr_timing * ctrl) +{ + u32 reg; + int channel; + + FOR_ALL_CHANNELS { + // enable xover clk + printk(BIOS_DEBUG, "[%x] = %x\n", channel * 0x100 + 0xc14, + (ctrl->rankmap[channel] << 24)); + MCHBAR32(channel * 0x100 + 0xc14) = (ctrl->rankmap[channel] << 24); + + // enable xover ctl + reg = 0; + if (ctrl->rankmap[channel] & 0x5) { + reg |= 0x20000; + } + if (ctrl->rankmap[channel] & 0xa) { + reg |= 0x4000000; + } + // enable xover cmd + reg |= 0x4000; + printk(BIOS_DEBUG, "[%x] = %x\n", 0x100 * channel + 0x320c, + reg); + MCHBAR32(0x100 * channel + 0x320c) = reg; + } +} + +static void dram_timing_regs(ramctr_timing * ctrl) +{ + u32 reg, addr, val32, cpu, stretch; + struct cpuid_result cpures; + int channel; + + FOR_ALL_CHANNELS { + // DBP + reg = 0; + reg |= ctrl->tRCD; + reg |= (ctrl->tRP << 4); + reg |= (ctrl->CAS << 8); + reg |= (ctrl->CWL << 12); + reg |= (ctrl->tRAS << 16); + printk(BIOS_DEBUG, "[%x] = %x\n", 0x400 * channel + 0x4000, + reg); + MCHBAR32(0x400 * channel + 0x4000) = reg; + + // RAP + reg = 0; + reg |= ctrl->tRRD; + reg |= (ctrl->tRTP << 4); + reg |= (ctrl->tCKE << 8); + reg |= (ctrl->tWTR << 12); + reg |= (ctrl->tFAW << 16); + reg |= (ctrl->tWR << 24); + reg |= (3 << 30); + printk(BIOS_DEBUG, "[%x] = %x\n", 0x400 * channel + 0x4004, + reg); + MCHBAR32(0x400 * channel + 0x4004) = reg; + + // OTHP + addr = 0x400 * channel + 0x400c; + reg = 0; + reg |= ctrl->tXPDLL; + reg |= (ctrl->tXP << 5); + reg |= (ctrl->tAONPD << 8); + reg |= 0xa0000; + printk(BIOS_DEBUG, "[%x] = %x\n", addr, reg); + MCHBAR32(addr) = reg; + + MCHBAR32(0x400 * channel + 0x4014) = 0; + + MCHBAR32(addr) |= 0x00020000; + + // ODT stretch + reg = 0; + + cpures = cpuid(0); + cpu = cpures.eax; + if (IS_IVY_CPU(cpu) + || (IS_SANDY_CPU(cpu) && IS_SANDY_CPU_D2(cpu))) { + stretch = 2; + addr = 0x400 * channel + 0x400c; + printk(BIOS_DEBUG, "[%x] = %x\n", + 0x400 * channel + 0x400c, reg); + reg = MCHBAR32(addr); + + if (((ctrl->rankmap[channel] & 3) == 0) + || (ctrl->rankmap[channel] & 0xc) == 0) { + + // Rank 0 - operate on rank 2 + reg = (reg & ~0xc0000) | (stretch << 18); + + // Rank 2 - operate on rank 0 + reg = (reg & ~0x30000) | (stretch << 16); + + printk(BIOS_DEBUG, "[%x] = %x\n", addr, reg); + MCHBAR32(addr) = reg; + } + + } else if (IS_SANDY_CPU(cpu) && IS_SANDY_CPU_C(cpu)) { + stretch = 3; + addr = 0x400 * channel + 0x401c; + reg = MCHBAR32(addr); + + if (((ctrl->rankmap[channel] & 3) == 0) + || (ctrl->rankmap[channel] & 0xc) == 0) { + + // Rank 0 - operate on rank 2 + reg = (reg & ~0x3000) | (stretch << 12); + + // Rank 2 - operate on rank 0 + reg = (reg & ~0xc00) | (stretch << 10); + + printk(BIOS_DEBUG, "[%x] = %x\n", addr, reg); + MCHBAR32(addr) = reg; + } + } else { + stretch = 0; + } + + // REFI + reg = 0; + val32 = ctrl->tREFI; + reg = (reg & ~0xffff) | val32; + val32 = ctrl->tRFC; + reg = (reg & ~0x1ff0000) | (val32 << 16); + val32 = (u32) (ctrl->tREFI * 9) / 1024; + reg = (reg & ~0xfe000000) | (val32 << 25); + printk(BIOS_DEBUG, "[%x] = %x\n", 0x400 * channel + 0x4298, + reg); + MCHBAR32(0x400 * channel + 0x4298) = reg; + + MCHBAR32(0x400 * channel + 0x4294) |= 0xff; + + // SRFTP + reg = 0; + val32 = tDLLK; + reg = (reg & ~0xfff) | val32; + val32 = ctrl->tXSOffset; + reg = (reg & ~0xf000) | (val32 << 12); + val32 = tDLLK - ctrl->tXSOffset; + reg = (reg & ~0x3ff0000) | (val32 << 16); + val32 = ctrl->tMOD - 8; + reg = (reg & ~0xf0000000) | (val32 << 28); + printk(BIOS_DEBUG, "[%x] = %x\n", 0x400 * channel + 0x42a4, + reg); + MCHBAR32(0x400 * channel + 0x42a4) = reg; + } +} + +static void dram_dimm_mapping(dimm_info * info, ramctr_timing * ctrl) +{ + int t; + u32 reg, val32; + int channel; + + FOR_ALL_CHANNELS { + dimm_attr *dimmA = 0; + dimm_attr *dimmB = 0; + reg = 0; + val32 = 0; + if (info->dimm[channel][0].size_mb >= + info->dimm[channel][1].size_mb) { + // dimm 0 is bigger, set it to dimmA + dimmA = &info->dimm[channel][0]; + dimmB = &info->dimm[channel][1]; + reg |= (0 << 16); + } else { + // dimm 1 is bigger, set it to dimmA + dimmA = &info->dimm[channel][1]; + dimmB = &info->dimm[channel][0]; + reg |= (1 << 16); + // swap dimm info + t = ctrl->rank_mirror[channel][1]; + ctrl->rank_mirror[channel][1] = + ctrl->rank_mirror[channel][3]; + ctrl->rank_mirror[channel][3] = t; + } + // dimmA + if (dimmA && (dimmA->ranks > 0)) { + val32 = dimmA->size_mb / 256; + reg = (reg & ~0xff) | val32; + val32 = dimmA->ranks - 1; + reg = (reg & ~0x20000) | (val32 << 17); + val32 = (dimmA->width / 8) - 1; + reg = (reg & ~0x80000) | (val32 << 19); + } + // dimmB + if (dimmB && (dimmB->ranks > 0)) { + val32 = dimmB->size_mb / 256; + reg = (reg & ~0xff00) | (val32 << 8); + val32 = dimmB->ranks - 1; + reg = (reg & ~0x40000) | (val32 << 18); + val32 = (dimmB->width / 8) - 1; + reg = (reg & ~0x100000) | (val32 << 20); + } + reg = (reg & ~0x200000) | (1 << 21); // rank interleave + reg = (reg & ~0x400000) | (1 << 22); // enhanced interleave + + // Save MAD-DIMM register + if ((dimmA && (dimmA->ranks > 0)) + || (dimmB && (dimmB->ranks > 0))) { + ctrl->mad_dimm[channel] = reg; + } else { + ctrl->mad_dimm[channel] = 0; + } + } +} + +static void dram_dimm_set_mapping(ramctr_timing * ctrl) +{ + int channel; + FOR_ALL_CHANNELS { + MCHBAR32(0x5004 + channel * 4) = ctrl->mad_dimm[channel]; + } +} + +static void dram_zones(ramctr_timing * ctrl, int training) +{ + u32 reg, ch0size, ch1size; + u8 val; + reg = 0; + val = 0; + if (training) { + ch0size = ctrl->channel_size_mb[0] ? 256 : 0; + ch1size = ctrl->channel_size_mb[1] ? 256 : 0; + } else { + ch0size = ctrl->channel_size_mb[0]; + ch1size = ctrl->channel_size_mb[1]; + } + + if (ch0size >= ch1size) { + reg = MCHBAR32(0x5014); + val = ch1size / 256; + reg = (reg & ~0xff000000) | val << 24; + reg = (reg & ~0xff0000) | (2 * val) << 16; + MCHBAR32(0x5014) = reg; + MCHBAR32(0x5000) = 0x24; + } else { + reg = MCHBAR32(0x5014); + val = ch0size / 256; + reg = (reg & ~0xff000000) | val << 24; + reg = (reg & ~0xff0000) | (2 * val) << 16; + MCHBAR32(0x5014) = reg; + MCHBAR32(0x5000) = 0x21; + } +} + +static void dram_memorymap(ramctr_timing * ctrl, int me_uma_size) +{ + u32 reg, val, reclaim; + u32 tom, gfxstolen, gttsize; + size_t tsegsize, mmiosize, toludbase, touudbase, gfxstolenbase, gttbase, + tsegbase, mestolenbase; + size_t tsegbasedelta, remapbase, remaplimit; + uint16_t ggc; + + mmiosize = 0x400; + + ggc = pci_read_config16(NORTHBRIDGE, GGC); + if (!(ggc & 2)) { + gfxstolen = ((ggc >> 3) & 0x1f) * 32; + gttsize = ((ggc >> 8) & 0x3); + } else { + gfxstolen = 0; + gttsize = 0; + } + + tsegsize = CONFIG_SMM_TSEG_SIZE >> 20; + + tom = ctrl->channel_size_mb[0] + ctrl->channel_size_mb[1]; + + mestolenbase = tom - me_uma_size; + + toludbase = MIN(4096 - mmiosize + gfxstolen + gttsize + tsegsize, + tom - me_uma_size); + gfxstolenbase = toludbase - gfxstolen; + gttbase = gfxstolenbase - gttsize; + + tsegbase = gttbase - tsegsize; + + // Round tsegbase down to nearest address aligned to tsegsize + tsegbasedelta = tsegbase & (tsegsize - 1); + tsegbase &= ~(tsegsize - 1); + + gttbase -= tsegbasedelta; + gfxstolenbase -= tsegbasedelta; + toludbase -= tsegbasedelta; + + // Test if it is possible to reclaim a hole in the ram addressing + if (tom - me_uma_size > toludbase) { + // Reclaim is possible + reclaim = 1; + remapbase = MAX(4096, tom - me_uma_size); + remaplimit = + remapbase + MIN(4096, tom - me_uma_size) - toludbase - 1; + touudbase = remaplimit + 1; + } else { + // Reclaim not possible + reclaim = 0; + touudbase = tom - me_uma_size; + } + + // Update memory map in pci-e configuration space + + // TOM (top of memory) + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xa0); + val = tom & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + printk(BIOS_DEBUG, "PCI:[%x] = %x\n", 0xa0, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xa0, reg); + + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xa4); + val = tom & 0xfffff000; + reg = (reg & ~0x000fffff) | (val >> 12); + printk(BIOS_DEBUG, "PCI:[%x] = %x\n", 0xa4, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xa4, reg); + + // TOLUD (top of low used dram) + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xbc); + val = toludbase & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + printk(BIOS_DEBUG, "PCI:[%x] = %x\n", 0xbc, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xbc, reg); + + // TOUUD LSB (top of upper usable dram) + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xa8); + val = touudbase & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + printk(BIOS_DEBUG, "PCI:[%x] = %x\n", 0xa8, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xa8, reg); + + // TOUUD MSB + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xac); + val = touudbase & 0xfffff000; + reg = (reg & ~0x000fffff) | (val >> 12); + printk(BIOS_DEBUG, "PCI:[%x] = %x\n", 0xac, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xac, reg); + + if (reclaim) { + // REMAP BASE + pcie_write_config32(PCI_DEV(0, 0, 0), 0x90, remapbase << 20); + pcie_write_config32(PCI_DEV(0, 0, 0), 0x94, remapbase >> 12); + + // REMAP LIMIT + pcie_write_config32(PCI_DEV(0, 0, 0), 0x98, remaplimit << 20); + pcie_write_config32(PCI_DEV(0, 0, 0), 0x9c, remaplimit >> 12); + } + // TSEG + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xb8); + val = tsegbase & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + printk(BIOS_DEBUG, "PCI:[%x] = %x\n", 0xb8, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xb8, reg); + + // GFX stolen memory + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xb0); + val = gfxstolenbase & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + printk(BIOS_DEBUG, "PCI:[%x] = %x\n", 0xb0, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xb0, reg); + + // GTT stolen memory + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0xb4); + val = gttbase & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + printk(BIOS_DEBUG, "PCI:[%x] = %x\n", 0xb4, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0xb4, reg); + + if (me_uma_size) { + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0x7c); + val = (0x80000 - me_uma_size) & 0xfffff000; + reg = (reg & ~0x000fffff) | (val >> 12); + printk(BIOS_DEBUG, "PCI:[%x] = %x\n", 0x7c, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0x7c, reg); + + // ME base + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0x70); + val = mestolenbase & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + printk(BIOS_DEBUG, "PCI:[%x] = %x\n", 0x70, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0x70, reg); + + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0x74); + val = mestolenbase & 0xfffff000; + reg = (reg & ~0x000fffff) | (val >> 12); + printk(BIOS_DEBUG, "PCI:[%x] = %x\n", 0x74, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0x74, reg); + + // ME mask + reg = pcie_read_config32(PCI_DEV(0, 0, 0), 0x78); + val = (0x80000 - me_uma_size) & 0xfff; + reg = (reg & ~0xfff00000) | (val << 20); + reg = (reg & ~0x400) | (1 << 10); // set lockbit on ME mem + + reg = (reg & ~0x800) | (1 << 11); // set ME memory enable + printk(BIOS_DEBUG, "PCI:[%x] = %x\n", 0x78, reg); + pcie_write_config32(PCI_DEV(0, 0, 0), 0x78, reg); + } +} + +static void dram_ioregs(ramctr_timing * ctrl) +{ + u32 reg, comp2; + + int channel; + + // IO clock + FOR_ALL_CHANNELS { + MCHBAR32(0xc00 + 0x100 * channel) = ctrl->rankmap[channel]; + } + + // IO command + FOR_ALL_CHANNELS { + MCHBAR32(0x3200 + 0x100 * channel) = ctrl->rankmap[channel]; + } + + // IO control + FOR_ALL_POPULATED_CHANNELS { + program_timings(ctrl, channel); + } + + // Rcomp + printk(BIOS_DEBUG, "RCOMP..."); + reg = 0; + while (reg == 0) { + reg = MCHBAR32(0x5084) & 0x10000; + } + printk(BIOS_DEBUG, "done\n"); + + // Set comp2 + comp2 = get_COMP2(ctrl->tCK); + MCHBAR32(0x3714) = comp2; + printk(BIOS_DEBUG, "COMP2 done\n"); + + // Set comp1 + FOR_ALL_POPULATED_CHANNELS { + reg = MCHBAR32(0x1810 + channel * 0x100); //ch0 + reg = (reg & ~0xe00) | (1 << 9); //odt + reg = (reg & ~0xe00000) | (1 << 21); //clk drive up + reg = (reg & ~0x38000000) | (1 << 27); //ctl drive up + MCHBAR32(0x1810 + channel * 0x100) = reg; + } + printk(BIOS_DEBUG, "COMP1 done\n"); + + printk(BIOS_DEBUG, "FORCE RCOMP and wait 20us..."); + MCHBAR32(0x5f08) |= 0x100; + udelay(20); + printk(BIOS_DEBUG, "done\n"); +} + +static void wait_428c(int channel) +{ + while (1) { + if (read32(DEFAULT_MCHBAR | 0x428c | (channel << 10)) & 0x50) + return; + } +} + +static void write_reset(ramctr_timing * ctrl) +{ + int channel, slotrank; + + /* choose a populated channel. */ + channel = (ctrl->rankmap[0]) ? 0 : 1; + + wait_428c(channel); + + /* choose a populated rank. */ + slotrank = (ctrl->rankmap[channel] & 1) ? 0 : 2; + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x0f003); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0x80c01); + + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x60000); + + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0x400001); + wait_428c(channel); +} + +static void dram_jedecreset(ramctr_timing * ctrl) +{ + u32 reg, addr; + int channel; + + while (!(MCHBAR32(0x5084) & 0x10000)) ; + do { + reg = MCHBAR32(0x428c); + } while ((reg & 0x14) == 0); + + // Set state of memory controller + reg = 0x112; + MCHBAR32(0x5030) = reg; + MCHBAR32(0x4ea0) = 0; + reg |= 2; //ddr reset + MCHBAR32(0x5030) = reg; + + // Assert dimm reset signal + reg = MCHBAR32(0x5030); + reg &= ~0x2; + MCHBAR32(0x5030) = reg; + + // Wait 200us + udelay(200); + + // Deassert dimm reset signal + MCHBAR32(0x5030) |= 2; + + // Wait 500us + udelay(500); + + // Enable DCLK + MCHBAR32(0x5030) |= 4; + + // XXX Wait 20ns + udelay(1); + + FOR_ALL_CHANNELS { + // Set valid rank CKE + reg = 0; + reg = (reg & ~0xf) | ctrl->rankmap[channel]; + addr = 0x400 * channel + 0x42a0; + MCHBAR32(addr) = reg; + + // Wait 10ns for ranks to settle + //udelay(0.01); + + reg = (reg & ~0xf0) | (ctrl->rankmap[channel] << 4); + MCHBAR32(addr) = reg; + + // Write reset using a NOP + write_reset(ctrl); + } +} + +static odtmap get_ODT(ramctr_timing * ctrl, u8 rank) +{ + /* Get ODT based on rankmap: */ + int dimms_per_ch = 0; + int channel; + + FOR_ALL_CHANNELS { + dimms_per_ch = max ((ctrl->rankmap[channel] & 1) + + ((ctrl->rankmap[channel] >> 2) & 1), + dimms_per_ch); + } + + if (dimms_per_ch == 1) { + return (const odtmap){60, 60}; + } else if (dimms_per_ch == 2) { + return (const odtmap){120, 30}; + } else { + printk(BIOS_DEBUG, + "Huh, no dimms? m0 = %d m1 = %d dpc = %d\n", + ctrl->rankmap[0], + ctrl->rankmap[1], dimms_per_ch); + die(""); + } +} + +static void write_mrreg(ramctr_timing * ctrl, int channel, int slotrank, + int reg, u32 val) +{ + wait_428c(channel); + + printk(BIOS_SPEW, "MRd: %x <= %x\n", reg, val); + + if (ctrl->rank_mirror[channel][slotrank]) { + reg = ((reg >> 1) & 1) | ((reg << 1) & 2); + val = (val & ~0x1f8) | ((val >> 1) & 0xa8) + | ((val & 0xa8) << 1); + } + + printk(BIOS_SPEW, "MRd: %x <= %x\n", reg, val); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x0f000); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0x41001); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | (reg << 20) | val | 0x60000); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f000); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, 0x41001); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24) | (reg << 20) | val | 0x60000); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, 0x0f000); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, + 0x1001 | (ctrl->tMOD << 16)); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, + (slotrank << 24) | (reg << 20) | val | 0x60000); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, 0); + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0x80001); +} + +static u32 make_mr0(ramctr_timing * ctrl, u8 rank) +{ + u16 mr0reg, mch_cas, mch_wr; + static const u8 mch_wr_t[12] = { 1, 2, 3, 4, 0, 5, 0, 6, 0, 7, 0, 0 }; + mr0reg = 0x100; + + // Convert CAS to MCH register friendly + if (ctrl->CAS < 12) { + mch_cas = (u16) ((ctrl->CAS - 4) << 1); + } else { + mch_cas = (u16) (ctrl->CAS - 12); + mch_cas = ((mch_cas << 1) | 0x1); + } + + // Convert tWR to MCH register friendly + mch_wr = mch_wr_t[ctrl->tWR - 5]; + + mr0reg = (mr0reg & ~0x4) | (mch_cas & 0x1); + mr0reg = (mr0reg & ~0x70) | ((mch_cas & 0xe) << 3); + mr0reg = (mr0reg & ~0xe00) | (mch_wr << 9); + // Fast (desktop) 0x1 or slow (mobile) 0x0 + mr0reg = (mr0reg & ~0x1000) | (!ctrl->mobile << 12); + return mr0reg; +} + +static void dram_mr0(ramctr_timing * ctrl, u8 rank) +{ + int channel; + + FOR_ALL_POPULATED_CHANNELS write_mrreg(ctrl, channel, rank, 0, + make_mr0(ctrl, rank)); +} + +static u32 encode_odt(u32 odt) +{ + switch (odt) { + case 30: + return (1 << 9) | (1 << 2); // RZQ/8, RZQ/4 + case 60: + return (1 << 2); // RZQ/4 + case 120: + return (1 << 6); // RZQ/2 + default: + case 0: + return 0; + } +} + +static u32 make_mr1(ramctr_timing * ctrl, u8 rank) +{ + odtmap odt; + u32 mr1reg; + + odt = get_ODT(ctrl, rank); + mr1reg = 0x2; + + mr1reg |= encode_odt(odt.rttnom); + + return mr1reg; +} + +static void dram_mr1(ramctr_timing * ctrl, u8 rank) +{ + u16 mr1reg; + int channel; + + mr1reg = make_mr1(ctrl, rank); + + FOR_ALL_CHANNELS { + write_mrreg(ctrl, channel, rank, 1, mr1reg); + } +} + +static void dram_mr2(ramctr_timing * ctrl, u8 rank) +{ + u16 pasr, cwl, mr2reg; + odtmap odt; + int channel; + int srt; + + pasr = 0; + cwl = ctrl->CWL - 5; + odt = get_ODT(ctrl, rank); + + srt = ctrl->extended_temperature_range && !ctrl->auto_self_refresh; + + mr2reg = 0; + mr2reg = (mr2reg & ~0x7) | pasr; + mr2reg = (mr2reg & ~0x38) | (cwl << 3); + mr2reg = (mr2reg & ~0x40) | (ctrl->auto_self_refresh << 6); + mr2reg = (mr2reg & ~0x80) | (srt << 7); + mr2reg |= (odt.rttwr / 60) << 9; + + FOR_ALL_CHANNELS { + write_mrreg(ctrl, channel, rank, 2, mr2reg); + } +} + +static void dram_mr3(ramctr_timing * ctrl, u8 rank) +{ + int channel; + + FOR_ALL_CHANNELS { + write_mrreg(ctrl, channel, rank, 3, 0); + } +} + +static void dram_mrscommands(ramctr_timing * ctrl) +{ + u8 rank; + u32 reg, addr; + int channel; + + for (rank = 0; rank < 4; rank++) { + // MR2 + printk(BIOS_SPEW, "MR2 rank %d...", rank); + dram_mr2(ctrl, rank); + printk(BIOS_SPEW, "done\n"); + + // MR3 + printk(BIOS_SPEW, "MR3 rank %d...", rank); + dram_mr3(ctrl, rank); + printk(BIOS_SPEW, "done\n"); + + // MR1 + printk(BIOS_SPEW, "MR1 rank %d...", rank); + dram_mr1(ctrl, rank); + printk(BIOS_SPEW, "done\n"); + + // MR0 + printk(BIOS_SPEW, "MR0 rank %d...", rank); + dram_mr0(ctrl, rank); + printk(BIOS_SPEW, "done\n"); + } + + write32(DEFAULT_MCHBAR + 0x4e20, 0x7); + write32(DEFAULT_MCHBAR + 0x4e30, 0xf1001); + write32(DEFAULT_MCHBAR + 0x4e00, 0x60002); + write32(DEFAULT_MCHBAR + 0x4e10, 0); + write32(DEFAULT_MCHBAR + 0x4e24, 0x1f003); + write32(DEFAULT_MCHBAR + 0x4e34, 0x1901001); + write32(DEFAULT_MCHBAR + 0x4e04, 0x60400); + write32(DEFAULT_MCHBAR + 0x4e14, 0x288); + write32(DEFAULT_MCHBAR + 0x4e84, 0x40004); + + // Drain + FOR_ALL_CHANNELS { + // Wait for ref drained + wait_428c(channel); + } + + // Refresh enable + MCHBAR32(0x5030) |= 8; + + FOR_ALL_POPULATED_CHANNELS { + addr = 0x400 * channel + 0x4020; + reg = MCHBAR32(addr); + reg &= ~0x200000; + MCHBAR32(addr) = reg; + + wait_428c(channel); + + rank = (ctrl->rankmap[channel] & 1) ? 0 : 2; + + // Drain + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x0f003); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0x659001); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (rank << 24) | 0x60000); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0x3e0); + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0x1); + + // Drain + wait_428c(channel); + } +} + +const u32 lane_registers[] = { + 0x0000, 0x0200, 0x0400, 0x0600, + 0x1000, 0x1200, 0x1400, 0x1600, + 0x0800 +}; + +static void program_timings(ramctr_timing * ctrl, int channel) +{ + u32 reg32, reg_4024, reg_c14, reg_c18, reg_4028; + int lane; + int slotrank, slot; + int full_shift = 0; + u16 slot320c[NUM_SLOTS]; + + FOR_ALL_POPULATED_RANKS { + if (full_shift < -ctrl->timings[channel][slotrank].val_320c) + full_shift = -ctrl->timings[channel][slotrank].val_320c; + } + + for (slot = 0; slot < NUM_SLOTS; slot++) + switch ((ctrl->rankmap[channel] >> (2 * slot)) & 3) { + case 0: + default: + slot320c[slot] = 0x7f; + break; + case 1: + slot320c[slot] = + ctrl->timings[channel][2 * slot + 0].val_320c + + full_shift; + break; + case 2: + slot320c[slot] = + ctrl->timings[channel][2 * slot + 1].val_320c + + full_shift; + break; + case 3: + slot320c[slot] = + (ctrl->timings[channel][2 * slot].val_320c + + ctrl->timings[channel][2 * slot + + 1].val_320c) / 2 + + full_shift; + break; + } + + reg32 = (1 << 17) | (1 << 14); + reg32 |= ((slot320c[0] & 0x3f) << 6) | ((slot320c[0] & 0x40) << 9); + reg32 |= (slot320c[1] & 0x7f) << 18; + reg32 |= (full_shift & 0x3f) | ((full_shift & 0x40) << 6); + + MCHBAR32(0x320c + 0x100 * channel) = reg32; + + reg_c14 = ctrl->rankmap[channel] << 24; + reg_c18 = 0; + + FOR_ALL_POPULATED_RANKS { + int shift = + ctrl->timings[channel][slotrank].val_320c + full_shift; + int offset_val_c14; + if (shift < 0) + shift = 0; + offset_val_c14 = ctrl->reg_c14_offset + shift; + reg_c14 |= (offset_val_c14 & 0x3f) << (6 * slotrank); + reg_c18 |= ((offset_val_c14 >> 6) & 1) << slotrank; + } + + MCHBAR32(0xc14 + channel * 0x100) = reg_c14; + MCHBAR32(0xc18 + channel * 0x100) = reg_c18; + + reg_4028 = MCHBAR32(0x4028 + 0x400 * channel); + reg_4028 &= 0xffff0000; + + reg_4024 = 0; + + FOR_ALL_POPULATED_RANKS { + int post_timA_min_high = 7, post_timA_max_high = 0; + int pre_timA_min_high = 7, pre_timA_max_high = 0; + int shift_402x = 0; + int shift = + ctrl->timings[channel][slotrank].val_320c + full_shift; + + if (shift < 0) + shift = 0; + + FOR_ALL_LANES { + if (post_timA_min_high > + ((ctrl->timings[channel][slotrank].lanes[lane]. + timA + shift) >> 6)) + post_timA_min_high = + ((ctrl->timings[channel][slotrank]. + lanes[lane].timA + shift) >> 6); + if (pre_timA_min_high > + (ctrl->timings[channel][slotrank].lanes[lane]. + timA >> 6)) + pre_timA_min_high = + (ctrl->timings[channel][slotrank]. + lanes[lane].timA >> 6); + if (post_timA_max_high < + ((ctrl->timings[channel][slotrank].lanes[lane]. + timA + shift) >> 6)) + post_timA_max_high = + ((ctrl->timings[channel][slotrank]. + lanes[lane].timA + shift) >> 6); + if (pre_timA_max_high < + (ctrl->timings[channel][slotrank].lanes[lane]. + timA >> 6)) + pre_timA_max_high = + (ctrl->timings[channel][slotrank]. + lanes[lane].timA >> 6); + } + + if (pre_timA_max_high - pre_timA_min_high < + post_timA_max_high - post_timA_min_high) + shift_402x = +1; + else if (pre_timA_max_high - pre_timA_min_high > + post_timA_max_high - post_timA_min_high) + shift_402x = -1; + + reg_4028 |= + (ctrl->timings[channel][slotrank].val_4028 + shift_402x - + post_timA_min_high) << (4 * slotrank); + reg_4024 |= + (ctrl->timings[channel][slotrank].val_4024 + + shift_402x) << (8 * slotrank); + + FOR_ALL_LANES { + MCHBAR32(lane_registers[lane] + 0x10 + 0x100 * channel + + 4 * slotrank) + = + (((ctrl->timings[channel][slotrank].lanes[lane]. + timA + shift) & 0x3f) + | + ((ctrl->timings[channel][slotrank].lanes[lane]. + rising + shift) << 8) + | + (((ctrl->timings[channel][slotrank].lanes[lane]. + timA + shift - + (post_timA_min_high << 6)) & 0x1c0) << 10) + | (ctrl->timings[channel][slotrank].lanes[lane]. + falling << 20)); + + MCHBAR32(lane_registers[lane] + 0x20 + 0x100 * channel + + 4 * slotrank) + = + (((ctrl->timings[channel][slotrank].lanes[lane]. + timC + shift) & 0x3f) + | + (((ctrl->timings[channel][slotrank].lanes[lane]. + timB + shift) & 0x3f) << 8) + | + (((ctrl->timings[channel][slotrank].lanes[lane]. + timB + shift) & 0x1c0) << 9) + | + (((ctrl->timings[channel][slotrank].lanes[lane]. + timC + shift) & 0x40) << 13)); + } + } + MCHBAR32(0x4024 + 0x400 * channel) = reg_4024; + MCHBAR32(0x4028 + 0x400 * channel) = reg_4028; +} + +static void test_timA(ramctr_timing * ctrl, int channel, int slotrank) +{ + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f000); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + (0xc01 | (ctrl->tMOD << 16))); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x360004); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f105); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, 0x4040c01); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, (slotrank << 24)); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, 0x1f105); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, + 0x100f | ((ctrl->CAS + 36) << 16)); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, + (slotrank << 24) | 0x60000); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x422c + 0x400 * channel, 0x1f000); + write32(DEFAULT_MCHBAR + 0x423c + 0x400 * channel, + (0xc01 | (ctrl->tMOD << 16))); + write32(DEFAULT_MCHBAR + 0x420c + 0x400 * channel, + (slotrank << 24) | 0x360000); + write32(DEFAULT_MCHBAR + 0x421c + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0xc0001); + + wait_428c(channel); +} + +static int does_lane_work(ramctr_timing * ctrl, int channel, int slotrank, + int lane) +{ + u32 timA = ctrl->timings[channel][slotrank].lanes[lane].timA; + return ((read32 + (DEFAULT_MCHBAR + lane_registers[lane] + channel * 0x100 + 4 + + ((timA / 32) & 1) * 4) + >> (timA % 32)) & 1); +} + +struct run { + int middle; + int end; + int start; + int all; + int length; +}; + +static struct run get_longest_zero_run(int *seq, int sz) +{ + int i, ls; + int bl = 0, bs = 0; + struct run ret; + + ls = 0; + for (i = 0; i < 2 * sz; i++) + if (seq[i % sz]) { + if (i - ls > bl) { + bl = i - ls; + bs = ls; + } + ls = i + 1; + } + if (bl == 0) { + ret.middle = sz / 2; + ret.start = 0; + ret.end = sz; + ret.all = 1; + return ret; + } + + ret.start = bs % sz; + ret.end = (bs + bl - 1) % sz; + ret.middle = (bs + (bl - 1) / 2) % sz; + ret.length = bl; + ret.all = 0; + + return ret; +} + +static void discover_timA_coarse(ramctr_timing * ctrl, int channel, + int slotrank, int *upperA) +{ + int timA; + int statistics[NUM_LANES][128]; + int lane; + + for (timA = 0; timA < 128; timA++) { + FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane].timA = timA; + } + program_timings(ctrl, channel); + + test_timA(ctrl, channel, slotrank); + + FOR_ALL_LANES { + statistics[lane][timA] = + !does_lane_work(ctrl, channel, slotrank, lane); + printk(BIOS_SPEW, "Astat: %d, %d, %d, %x, %x\n", + channel, slotrank, lane, timA, + statistics[lane][timA]); + } + } + FOR_ALL_LANES { + struct run rn = get_longest_zero_run(statistics[lane], 128); + ctrl->timings[channel][slotrank].lanes[lane].timA = rn.middle; + upperA[lane] = rn.end; + if (upperA[lane] < rn.middle) + upperA[lane] += 128; + printk(BIOS_SPEW, "Aval: %d, %d, %d, %x\n", channel, slotrank, + lane, ctrl->timings[channel][slotrank].lanes[lane].timA); + printk(BIOS_SPEW, "Aend: %d, %d, %d, %x\n", channel, slotrank, + lane, upperA[lane]); + } +} + +static void discover_timA_fine(ramctr_timing * ctrl, int channel, int slotrank, + int *upperA) +{ + int timA_delta; + int statistics[NUM_LANES][51]; + int lane, i; + + memset(statistics, 0, sizeof(statistics)); + + for (timA_delta = -25; timA_delta <= 25; timA_delta++) { + FOR_ALL_LANES ctrl->timings[channel][slotrank].lanes[lane]. + timA = upperA[lane] + timA_delta + 0x40; + program_timings(ctrl, channel); + + for (i = 0; i < 100; i++) { + test_timA(ctrl, channel, slotrank); + FOR_ALL_LANES { + statistics[lane][timA_delta + 25] += + does_lane_work(ctrl, channel, slotrank, + lane); + } + } + } + FOR_ALL_LANES { + int last_zero, first_all; + + for (last_zero = -25; last_zero <= 25; last_zero++) + if (statistics[lane][last_zero + 25]) + break; + last_zero--; + for (first_all = -25; first_all <= 25; first_all++) + if (statistics[lane][first_all + 25] == 100) + break; + + printk(BIOS_SPEW, "lane %d: %d, %d\n", lane, last_zero, + first_all); + + ctrl->timings[channel][slotrank].lanes[lane].timA = + (last_zero + first_all) / 2 + upperA[lane]; + printk(BIOS_SPEW, "Aval: %d, %d, %d, %x\n", channel, slotrank, + lane, ctrl->timings[channel][slotrank].lanes[lane].timA); + } +} + +static void discover_402x(ramctr_timing * ctrl, int channel, int slotrank, + int *upperA) +{ + int works[NUM_LANES]; + int lane; + while (1) { + int all_works = 1, some_works = 0; + program_timings(ctrl, channel); + test_timA(ctrl, channel, slotrank); + FOR_ALL_LANES { + works[lane] = + !does_lane_work(ctrl, channel, slotrank, lane); + if (works[lane]) + some_works = 1; + else + all_works = 0; + } + if (all_works) + return; + if (!some_works) { + if (ctrl->timings[channel][slotrank].val_4024 < 2) + die("402x discovery failed"); + ctrl->timings[channel][slotrank].val_4024 -= 2; + printk(BIOS_SPEW, "4024 -= 2;\n"); + continue; + } + ctrl->timings[channel][slotrank].val_4028 += 2; + printk(BIOS_SPEW, "4028 += 2;\n"); + if (ctrl->timings[channel][slotrank].val_4028 >= 0x10) + die("402x discovery failed"); + FOR_ALL_LANES if (works[lane]) { + ctrl->timings[channel][slotrank].lanes[lane].timA += + 128; + upperA[lane] += 128; + printk(BIOS_SPEW, "increment %d, %d, %d\n", channel, + slotrank, lane); + } + } +} + +struct timA_minmax { + int timA_min_high, timA_max_high; +}; + +static void pre_timA_change(ramctr_timing * ctrl, int channel, int slotrank, + struct timA_minmax *mnmx) +{ + int lane; + mnmx->timA_min_high = 7; + mnmx->timA_max_high = 0; + + FOR_ALL_LANES { + if (mnmx->timA_min_high > + (ctrl->timings[channel][slotrank].lanes[lane].timA >> 6)) + mnmx->timA_min_high = + (ctrl->timings[channel][slotrank].lanes[lane]. + timA >> 6); + if (mnmx->timA_max_high < + (ctrl->timings[channel][slotrank].lanes[lane].timA >> 6)) + mnmx->timA_max_high = + (ctrl->timings[channel][slotrank].lanes[lane]. + timA >> 6); + } +} + +static void post_timA_change(ramctr_timing * ctrl, int channel, int slotrank, + struct timA_minmax *mnmx) +{ + struct timA_minmax post; + int shift_402x = 0; + + /* Get changed maxima. */ + pre_timA_change(ctrl, channel, slotrank, &post); + + if (mnmx->timA_max_high - mnmx->timA_min_high < + post.timA_max_high - post.timA_min_high) + shift_402x = +1; + else if (mnmx->timA_max_high - mnmx->timA_min_high > + post.timA_max_high - post.timA_min_high) + shift_402x = -1; + else + shift_402x = 0; + + ctrl->timings[channel][slotrank].val_4028 += shift_402x; + ctrl->timings[channel][slotrank].val_4024 += shift_402x; + printk(BIOS_SPEW, "4024 += %d;\n", shift_402x); + printk(BIOS_SPEW, "4028 += %d;\n", shift_402x); +} + +static void read_training(ramctr_timing * ctrl) +{ + int channel, slotrank, lane; + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS { + u32 r32; + int all_high, some_high; + int upperA[NUM_LANES]; + struct timA_minmax mnmx; + + wait_428c(channel); + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f002); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + 0xc01 | (ctrl->tRP << 16)); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x60400); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0); + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 1); + + write32(DEFAULT_MCHBAR + 0x3400, (slotrank << 2) | 0x8001); + + ctrl->timings[channel][slotrank].val_4028 = 4; + ctrl->timings[channel][slotrank].val_4024 = 55; + program_timings(ctrl, channel); + + discover_timA_coarse(ctrl, channel, slotrank, upperA); + + all_high = 1; + some_high = 0; + FOR_ALL_LANES { + if (ctrl->timings[channel][slotrank].lanes[lane]. + timA >= 0x40) + some_high = 1; + else + all_high = 0; + } + + if (all_high) { + ctrl->timings[channel][slotrank].val_4028--; + printk(BIOS_SPEW, "4028--;\n"); + FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane]. + timA -= 0x40; + upperA[lane] -= 0x40; + + } + } else if (some_high) { + ctrl->timings[channel][slotrank].val_4024++; + ctrl->timings[channel][slotrank].val_4028++; + printk(BIOS_SPEW, "4024++;\n"); + printk(BIOS_SPEW, "4028++;\n"); + } + + program_timings(ctrl, channel); + + pre_timA_change(ctrl, channel, slotrank, &mnmx); + + discover_402x(ctrl, channel, slotrank, upperA); + + post_timA_change(ctrl, channel, slotrank, &mnmx); + pre_timA_change(ctrl, channel, slotrank, &mnmx); + + discover_timA_fine(ctrl, channel, slotrank, upperA); + + post_timA_change(ctrl, channel, slotrank, &mnmx); + pre_timA_change(ctrl, channel, slotrank, &mnmx); + + FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane].timA -= mnmx.timA_min_high * 0x40; + } + ctrl->timings[channel][slotrank].val_4028 -= mnmx.timA_min_high; + printk(BIOS_SPEW, "4028 -= %d;\n", mnmx.timA_min_high); + + post_timA_change(ctrl, channel, slotrank, &mnmx); + + printk(BIOS_SPEW, "4/8: %d, %d, %x, %x\n", channel, slotrank, + ctrl->timings[channel][slotrank].val_4024, + ctrl->timings[channel][slotrank].val_4028); + + FOR_ALL_LANES + printk(BIOS_SPEW, "%d, %d, %d, %x\n", channel, slotrank, + lane, + ctrl->timings[channel][slotrank].lanes[lane].timA); + + write32(DEFAULT_MCHBAR + 0x3400, 0); + + r32 = read32(DEFAULT_MCHBAR + 0x5030); + write32(DEFAULT_MCHBAR + 0x5030, r32 | 0x20); + udelay(1); + + write32(DEFAULT_MCHBAR + 0x5030, r32 & ~0x20); + + udelay(1); + } + + FOR_ALL_POPULATED_CHANNELS { + program_timings(ctrl, channel); + } + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + write32(DEFAULT_MCHBAR + 0x4080 + 0x400 * channel + + 4 * lane, 0); + } +} + +static void test_timC(ramctr_timing * ctrl, int channel, int slotrank) +{ + int lane; + + FOR_ALL_LANES { + write32(DEFAULT_MCHBAR + 0x4340 + 0x400 * channel + 4 * lane, 0); + read32(DEFAULT_MCHBAR + 0x4140 + 0x400 * channel + 4 * lane); + } + + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f006); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + (max((ctrl->tFAW >> 2) + 1, ctrl->tRRD) << 10) + | 4 | (ctrl->tRCD << 16)); + + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | (6 << 16)); + + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0x244); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f207); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, 0x8041001); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24) | 8); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0x3e0); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, 0x1f201); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, 0x80411f4); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, (slotrank << 24)); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, 0x242); + + write32(DEFAULT_MCHBAR + 0x422c + 0x400 * channel, 0x1f207); + write32(DEFAULT_MCHBAR + 0x423c + 0x400 * channel, + 0x8000c01 | ((ctrl->CWL + ctrl->tWTR + 5) << 16)); + write32(DEFAULT_MCHBAR + 0x420c + 0x400 * channel, + (slotrank << 24) | 8); + write32(DEFAULT_MCHBAR + 0x421c + 0x400 * channel, 0x3e0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0xc0001); + + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f002); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + 0xc01 | (ctrl->tRP << 16)); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x60400); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0x240); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f006); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, + (max(ctrl->tRRD, (ctrl->tFAW >> 2) + 1) << 10) + | 8 | (ctrl->CAS << 16)); + + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24) | 0x60000); + + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0x244); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, 0x1f105); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, + 0x40011f4 | (max(ctrl->tRTP, 8) << 16)); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, (slotrank << 24)); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, 0x242); + + write32(DEFAULT_MCHBAR + 0x422c + 0x400 * channel, 0x1f002); + write32(DEFAULT_MCHBAR + 0x423c + 0x400 * channel, + 0xc01 | (ctrl->tRP << 16)); + write32(DEFAULT_MCHBAR + 0x420c + 0x400 * channel, + (slotrank << 24) | 0x60400); + write32(DEFAULT_MCHBAR + 0x421c + 0x400 * channel, 0x240); + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0xc0001); + wait_428c(channel); +} + +static void discover_timC(ramctr_timing * ctrl, int channel, int slotrank) +{ + int timC; + int statistics[NUM_LANES][MAX_TIMC + 1]; + int lane; + + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f002); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + 0xc01 | (ctrl->tRP << 16)); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x60400); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0x240); + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 1); + + for (timC = 0; timC <= MAX_TIMC; timC++) { + FOR_ALL_LANES ctrl->timings[channel][slotrank].lanes[lane]. + timC = timC; + program_timings(ctrl, channel); + + test_timC(ctrl, channel, slotrank); + + FOR_ALL_LANES { + statistics[lane][timC] = + read32(DEFAULT_MCHBAR + 0x4340 + 4 * lane + + 0x400 * channel); + printk(BIOS_SPEW, "Cstat: %d, %d, %d, %x, %x\n", + channel, slotrank, lane, timC, + statistics[lane][timC]); + } + } + FOR_ALL_LANES { + struct run rn = + get_longest_zero_run(statistics[lane], MAX_TIMC + 1); + ctrl->timings[channel][slotrank].lanes[lane].timC = rn.middle; + if (rn.all) + die("timC discovery failed"); + printk(BIOS_SPEW, "Cval: %d, %d, %d, %x\n", channel, slotrank, + lane, ctrl->timings[channel][slotrank].lanes[lane].timC); + } +} + +static int get_precedening_channels(ramctr_timing * ctrl, int target_channel) +{ + int channel, ret = 0; + FOR_ALL_POPULATED_CHANNELS if (channel < target_channel) + ret++; + return ret; +} + +static void fill_pattern0(ramctr_timing * ctrl, int channel, u32 a, u32 b) +{ + unsigned j; + unsigned channel_offset = + get_precedening_channels(ctrl, channel) * 0x40; + printk(BIOS_SPEW, "channel_offset=%x\n", channel_offset); + for (j = 0; j < 16; j++) + write32(0x04000000 + channel_offset + 4 * j, j & 2 ? b : a); + sfence(); +} + +static int num_of_channels(const ramctr_timing * ctrl) +{ + int ret = 0; + int channel; + FOR_ALL_POPULATED_CHANNELS ret++; + return ret; +} + +static void fill_pattern1(ramctr_timing * ctrl, int channel) +{ + unsigned j; + unsigned channel_offset = + get_precedening_channels(ctrl, channel) * 0x40; + unsigned channel_step = 0x40 * num_of_channels(ctrl); + for (j = 0; j < 16; j++) + write32(0x04000000 + channel_offset + j * 4, 0xffffffff); + for (j = 0; j < 16; j++) + write32(0x04000000 + channel_offset + channel_step + j * 4, 0); + sfence(); +} + +static void precharge(ramctr_timing * ctrl) +{ + int channel, slotrank, lane; + + FOR_ALL_POPULATED_CHANNELS { + FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane].falling = + 16; + ctrl->timings[channel][slotrank].lanes[lane].rising = + 16; + } program_timings(ctrl, channel); + + FOR_ALL_POPULATED_RANKS { + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, + 0x1f000); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + 0xc01 | (ctrl->tMOD << 16)); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x360004); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, + 0x1f105); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, + 0x4041003); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24) | 0); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, + 0x1f105); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, + 0x1001 | ((ctrl->CAS + 8) << 16)); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, + (slotrank << 24) | 0x60000); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x422c + 0x400 * channel, + 0x1f000); + write32(DEFAULT_MCHBAR + 0x423c + 0x400 * channel, + 0xc01 | (ctrl->tMOD << 16)); + write32(DEFAULT_MCHBAR + 0x420c + 0x400 * channel, + (slotrank << 24) | 0x360000); + write32(DEFAULT_MCHBAR + 0x421c + 0x400 * channel, 0); + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, + 0xc0001); + + wait_428c(channel); + } + + FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane].falling = + 48; + ctrl->timings[channel][slotrank].lanes[lane].rising = + 48; + } + + program_timings(ctrl, channel); + + FOR_ALL_POPULATED_RANKS { + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, + 0x1f000); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + 0xc01 | (ctrl->tMOD << 16)); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x360004); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, + 0x1f105); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, + 0x4041003); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24) | 0); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, + 0x1f105); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, + 0x1001 | ((ctrl->CAS + 8) << 16)); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, + (slotrank << 24) | 0x60000); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x422c + 0x400 * channel, + 0x1f000); + write32(DEFAULT_MCHBAR + 0x423c + 0x400 * channel, + 0xc01 | (ctrl->tMOD << 16)); + + write32(DEFAULT_MCHBAR + 0x420c + 0x400 * channel, + (slotrank << 24) | 0x360000); + write32(DEFAULT_MCHBAR + 0x421c + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, + 0xc0001); + wait_428c(channel); + } + } +} + +static void test_timB(ramctr_timing * ctrl, int channel, int slotrank) +{ + write_mrreg(ctrl, channel, slotrank, 1, + 0x80 | make_mr1(ctrl, slotrank)); + + wait_428c(channel); + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f207); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + 0x8000c01 | ((ctrl->CWL + ctrl->tWLO) << 16)); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + 8 | (slotrank << 24)); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f107); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, + 0x4000c01 | ((ctrl->CAS + 38) << 16)); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24) | 4); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x400 * channel + 0x4284, 0x40001); + wait_428c(channel); + + write_mrreg(ctrl, channel, slotrank, 1, + 0x1080 | make_mr1(ctrl, slotrank)); +} + +static void discover_timB(ramctr_timing * ctrl, int channel, int slotrank) +{ + int timB; + int statistics[NUM_LANES][128]; + int lane; + + write32(DEFAULT_MCHBAR + 0x3400, 0x108052 | (slotrank << 2)); + + for (timB = 0; timB < 128; timB++) { + FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane].timB = timB; + } + program_timings(ctrl, channel); + + test_timB(ctrl, channel, slotrank); + + FOR_ALL_LANES { + statistics[lane][timB] = + !((read32 + (DEFAULT_MCHBAR + lane_registers[lane] + + channel * 0x100 + 4 + ((timB / 32) & 1) * 4) + >> (timB % 32)) & 1); + printk(BIOS_SPEW, "Bstat: %d, %d, %d, %x, %x\n", + channel, slotrank, lane, timB, + statistics[lane][timB]); + } + } + FOR_ALL_LANES { + struct run rn = get_longest_zero_run(statistics[lane], 128); + ctrl->timings[channel][slotrank].lanes[lane].timB = rn.start; + if (rn.all) + die("timB discovery failed"); + printk(BIOS_SPEW, "Bval: %d, %d, %d, %x\n", channel, slotrank, + lane, ctrl->timings[channel][slotrank].lanes[lane].timB); + } +} + +static int get_timB_high_adjust(u64 val) +{ + int i; + if (val >= 0xfffffffffffff000LL) + return 3; + if (val >= 0xfffffffffff00000LL) + return -1; + if (val >= 0xfffffff000000000LL) + return -2; + if (val >= 0xfff0000000000000LL) + return -3; + + for (i = 0; i < 8; i++) + if (val >> (8 * (7 - i) + 4)) + return i; + return 8; +} + +static void adjust_high_timB(ramctr_timing * ctrl) +{ + int channel, slotrank, lane; + write32(DEFAULT_MCHBAR + 0x3400, 0x200); + FOR_ALL_POPULATED_CHANNELS { + fill_pattern1(ctrl, channel); + write32(DEFAULT_MCHBAR | 0x4288 | (channel << 10), 1); + } + FOR_ALL_POPULATED_CHANNELS FOR_ALL_POPULATED_RANKS { + + write32(DEFAULT_MCHBAR + 0x4288 + 0x400 * channel, 0x10001); + + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f006); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + 0xc01 | (ctrl->tRCD << 16)); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x60000); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f207); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, 0x8040c01); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24) | 0x8); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0x3e0); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, 0x1f201); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, 0x8041003); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, + (slotrank << 24)); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, 0x3e2); + + write32(DEFAULT_MCHBAR + 0x422c + 0x400 * channel, 0x1f207); + write32(DEFAULT_MCHBAR + 0x423c + 0x400 * channel, + 0x8000c01 | ((ctrl->CWL + ctrl->tWTR + 5) << 16)); + write32(DEFAULT_MCHBAR + 0x420c + 0x400 * channel, + (slotrank << 24) | 0x8); + write32(DEFAULT_MCHBAR + 0x421c + 0x400 * channel, 0x3e0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0xc0001); + + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f002); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + 0xc01 | ((ctrl->tRP) << 16)); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x60400); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0x240); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f006); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, + 0xc01 | ((ctrl->tRCD) << 16)); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24) | 0x60000); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, 0x3f105); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, + 0x4000c01 | + ((ctrl->tRP + + ctrl->timings[channel][slotrank].val_4024 + + ctrl->timings[channel][slotrank].val_4028) << 16)); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, + (slotrank << 24) | 0x60008); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0x80001); + wait_428c(channel); + FOR_ALL_LANES { + u64 res = + read32(DEFAULT_MCHBAR + lane_registers[lane] + + 0x100 * channel + 4); + res |= + ((u64) read32(DEFAULT_MCHBAR + lane_registers[lane] + + 0x100 * channel + 8)) << 32; + ctrl->timings[channel][slotrank].lanes[lane].timB += + get_timB_high_adjust(res) * 64; + + printk(BIOS_DEBUG, "High adjust %d:%016llx\n", lane, res); + printk(BIOS_SPEW, "Bval+: %d, %d, %d, %x\n", channel, + slotrank, lane, + ctrl->timings[channel][slotrank].lanes[lane]. + timB); + } + } + write32(DEFAULT_MCHBAR + 0x3400, 0); +} + +static void write_op(ramctr_timing * ctrl, int channel) +{ + int slotrank; + + wait_428c(channel); + + /* choose an existing rank. */ + slotrank = !(ctrl->rankmap[channel] & 1) ? 2 : 0; + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x0f003); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0x41001); + + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x60000); + + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0x3e0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 1); + wait_428c(channel); +} + +static void write_training(ramctr_timing * ctrl) +{ + int channel, slotrank, lane; + u32 r32; + + FOR_ALL_POPULATED_CHANNELS + write32(DEFAULT_MCHBAR + 0x4008 + 0x400 * channel, + read32(DEFAULT_MCHBAR + 0x4008 + + 0x400 * channel) | 0x8000000); + + FOR_ALL_POPULATED_CHANNELS { + write_op(ctrl, channel); + write32(DEFAULT_MCHBAR + 0x4020 + 0x400 * channel, + read32(DEFAULT_MCHBAR + 0x4020 + + 0x400 * channel) | 0x200000); + } + write32(DEFAULT_MCHBAR + 0x5030, read32(DEFAULT_MCHBAR + 0x5030) & ~8); + FOR_ALL_POPULATED_CHANNELS { + write_op(ctrl, channel); + } + + FOR_ALL_CHANNELS + FOR_ALL_POPULATED_RANKS + write_mrreg(ctrl, channel, slotrank, 1, + make_mr1(ctrl, slotrank) | 0x1080); + + write32(DEFAULT_MCHBAR + 0x3400, 0x108052); + + r32 = read32(DEFAULT_MCHBAR + 0x5030); + write32(DEFAULT_MCHBAR + 0x5030, r32 | 0x20); + udelay(1); + + write32(DEFAULT_MCHBAR + 0x5030, r32 & ~0x20); + + udelay(1); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS + discover_timB(ctrl, channel, slotrank); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS + write_mrreg(ctrl, channel, + slotrank, 1, make_mr1(ctrl, slotrank)); + + write32(DEFAULT_MCHBAR + 0x3400, 0); + + FOR_ALL_POPULATED_CHANNELS + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x5030, read32(DEFAULT_MCHBAR + 0x5030) | 8); + + FOR_ALL_POPULATED_CHANNELS { + write32(DEFAULT_MCHBAR + 0x4020 + 0x400 * channel, + ~0x00200000 & read32(DEFAULT_MCHBAR + 0x4020 + + 0x400 * channel)); + read32(DEFAULT_MCHBAR + 0x428c + 0x400 * channel); + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x0f003); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0x659001); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, 0x60000); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0x3e0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 1); + wait_428c(channel); + } + + r32 = read32(DEFAULT_MCHBAR + 0x5030); + write32(DEFAULT_MCHBAR + 0x5030, r32 | 0x20); + udelay(1); + + write32(DEFAULT_MCHBAR + 0x5030, r32 & ~0x20); + + udelay(1); + + printk(BIOS_SPEW, "CPE\n"); + precharge(ctrl); + printk(BIOS_SPEW, "CPF\n"); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + read32(DEFAULT_MCHBAR + 0x4080 + 0x400 * channel + 4 * lane); + write32(DEFAULT_MCHBAR + 0x4080 + 0x400 * channel + 4 * lane, + 0); + } + + FOR_ALL_POPULATED_CHANNELS { + fill_pattern0(ctrl, channel, 0xaaaaaaaa, 0x55555555); + write32(DEFAULT_MCHBAR | 0x4288 | (channel << 10), 0); + } + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS + discover_timC(ctrl, channel, slotrank); + + FOR_ALL_POPULATED_CHANNELS + program_timings(ctrl, channel); + + adjust_high_timB(ctrl); + + FOR_ALL_POPULATED_CHANNELS + program_timings(ctrl, channel); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + read32(DEFAULT_MCHBAR + 0x4080 + 0x400 * channel + 4 * lane); + write32(DEFAULT_MCHBAR + 0x4080 + 0x400 * channel + 4 * lane, + 0); + } +} + +static int test_320c(ramctr_timing * ctrl, int channel, int slotrank) +{ + struct ram_rank_timings saved_rt = ctrl->timings[channel][slotrank]; + int timC_delta; + int lanes_ok = 0; + int ctr = 0; + int lane; + + for (timC_delta = -5; timC_delta <= 5; timC_delta++) { + FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane].timC = + saved_rt.lanes[lane].timC + timC_delta; + } + program_timings(ctrl, channel); + FOR_ALL_LANES { + write32(DEFAULT_MCHBAR + 4 * lane + 0x4f40, 0); + } + + write32(DEFAULT_MCHBAR + 0x4288 + 0x400 * channel, 0x1f); + + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f006); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + ((max(ctrl->tRRD, (ctrl->tFAW >> 2) + 1)) << 10) + | 8 | (ctrl->tRCD << 16)); + + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | ctr | 0x60000); + + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0x244); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f201); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, + 0x8001020 | ((ctrl->CWL + ctrl->tWTR + 8) << 16)); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24)); + write32(DEFAULT_MCHBAR + 0x4244 + 0x400 * channel, 0x389abcd); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0x20e42); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, 0x1f105); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, + 0x4001020 | (max(ctrl->tRTP, 8) << 16)); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, + (slotrank << 24)); + write32(DEFAULT_MCHBAR + 0x4248 + 0x400 * channel, 0x389abcd); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, 0x20e42); + + write32(DEFAULT_MCHBAR + 0x422c + 0x400 * channel, 0x1f002); + write32(DEFAULT_MCHBAR + 0x423c + 0x400 * channel, 0xf1001); + write32(DEFAULT_MCHBAR + 0x420c + 0x400 * channel, + (slotrank << 24) | 0x60400); + write32(DEFAULT_MCHBAR + 0x421c + 0x400 * channel, 0x240); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0xc0001); + wait_428c(channel); + FOR_ALL_LANES { + u32 r32 = + read32(DEFAULT_MCHBAR + 0x4340 + 4 * lane + + 0x400 * channel); + + if (r32 == 0) + lanes_ok |= 1 << lane; + } + ctr++; + if (lanes_ok == ((1 << NUM_LANES) - 1)) + break; + } + + ctrl->timings[channel][slotrank] = saved_rt; + + printk(BIOS_SPEW, "3lanes: %x\n", lanes_ok); + return lanes_ok != ((1 << NUM_LANES) - 1); +} + +#include "raminit_patterns.h" + +static void fill_pattern5(ramctr_timing * ctrl, int channel, int patno) +{ + unsigned i, j; + unsigned channel_offset = + get_precedening_channels(ctrl, channel) * 0x40; + unsigned channel_step = 0x40 * num_of_channels(ctrl); + + if (patno) { + u8 base8 = 0x80 >> ((patno - 1) % 8); + u32 base = base8 | (base8 << 8) | (base8 << 16) | (base8 << 24); + for (i = 0; i < 32; i++) { + for (j = 0; j < 16; j++) { + u32 val = use_base[patno - 1][i] & (1 << (j / 2)) ? base : 0; + if (invert[patno - 1][i] & (1 << (j / 2))) + val = ~val; + write32(0x04000000 + channel_offset + i * channel_step + + j * 4, val); + } + } + + } else { + for (i = 0; i < sizeof(pattern) / sizeof(pattern[0]); i++) { + for (j = 0; j < 16; j++) + write32(0x04000000 + channel_offset + i * channel_step + + j * 4, pattern[i][j]); + } + sfence(); + } +} + +static void reprogram_320c(ramctr_timing * ctrl) +{ + int channel, slotrank; + u32 r32; + + FOR_ALL_POPULATED_CHANNELS { + wait_428c(channel); + + /* choose an existing rank. */ + slotrank = !(ctrl->rankmap[channel] & 1) ? 2 : 0; + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x0f003); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0x41001); + + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x60000); + + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0x3e0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 1); + wait_428c(channel); + write32(DEFAULT_MCHBAR + 0x4020 + 0x400 * channel, + read32(DEFAULT_MCHBAR + 0x4020 + + 0x400 * channel) | 0x200000); + } + write32(DEFAULT_MCHBAR + 0x5030, read32(DEFAULT_MCHBAR + 0x5030) & ~8); + FOR_ALL_POPULATED_CHANNELS { + wait_428c(channel); + + /* choose an existing rank. */ + slotrank = !(ctrl->rankmap[channel] & 1) ? 2 : 0; + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x0f003); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0x41001); + + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x60000); + + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0x3e0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 1); + wait_428c(channel); + } + + /* jedec reset */ + dram_jedecreset(ctrl); + /* mrs commands. */ + dram_mrscommands(ctrl); + + r32 = read32(DEFAULT_MCHBAR + 0x5030); + write32(DEFAULT_MCHBAR + 0x5030, r32 | 0x20); + udelay(1); + + write32(DEFAULT_MCHBAR + 0x5030, r32 & ~0x20); + + udelay(1); +} + +#define MIN_C320C_LEN 13 + +static int try_reg_4004_b30(ramctr_timing * ctrl, int r4004b30) +{ + struct ram_rank_timings saved_timings[NUM_CHANNELS][NUM_SLOTRANKS]; + int channel, slotrank; + int c320c; + int stat[NUM_SLOTRANKS][256]; + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS { + saved_timings[channel][slotrank] = ctrl->timings[channel][slotrank]; + } + + FOR_ALL_POPULATED_CHANNELS { + ctrl->reg_4004_b30[channel] = r4004b30; + } + + FOR_ALL_POPULATED_CHANNELS + MCHBAR32(0x4004 + 0x400 * channel) = + ctrl->tRRD + | (ctrl->tRTP << 4) + | (ctrl->tCKE << 8) + | (ctrl->tWTR << 12) + | (ctrl->tFAW << 16) + | (ctrl->tWR << 24) + | (ctrl->reg_4004_b30[channel] << 30); + + + FOR_ALL_CHANNELS { + int delta = 0; + if (ctrl->reg_4004_b30[channel] == 2) + delta = 2; + else if (ctrl->reg_4004_b30[channel] == 0) + delta = 4; + + FOR_ALL_POPULATED_RANKS { + ctrl->timings[channel][slotrank].val_4024 -= delta; + } + } + + FOR_ALL_POPULATED_CHANNELS { + for (c320c = -127; c320c <= 127; c320c++) { + FOR_ALL_POPULATED_RANKS { + ctrl->timings[channel][slotrank].val_320c = c320c; + } + program_timings(ctrl, channel); + reprogram_320c(ctrl); + FOR_ALL_POPULATED_RANKS { + stat[slotrank][c320c + 127] = + test_320c(ctrl, channel, slotrank); + printk(BIOS_SPEW, "3stat: %d, %d, %d: %d\n", + channel, slotrank, c320c, + stat[slotrank][c320c + 127]); + } + } + FOR_ALL_POPULATED_RANKS { + struct run rn = + get_longest_zero_run(stat[slotrank], 255); + ctrl->timings[channel][slotrank].val_320c = + rn.middle - 127; + printk(BIOS_SPEW, "3val: %d, %d: %d\n", channel, + slotrank, + ctrl->timings[channel][slotrank].val_320c); + if (rn.all || rn.length < MIN_C320C_LEN) { + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS { + ctrl->timings[channel][slotrank] = saved_timings[channel][slotrank]; + } + return 0; + } + } + } + return 1; +} + +static void command_training(ramctr_timing * ctrl) +{ + int channel; + + FOR_ALL_POPULATED_CHANNELS { + fill_pattern5(ctrl, channel, 0); + write32(DEFAULT_MCHBAR + 0x4288 + 0x400 * channel, 0x1f); + } + + if (!try_reg_4004_b30(ctrl, 0) && !try_reg_4004_b30(ctrl, 2)) + die("c320c discovery failed"); + + FOR_ALL_POPULATED_CHANNELS { + program_timings(ctrl, channel); + } + + reprogram_320c(ctrl); +} + +static void discover_edges_real(ramctr_timing * ctrl, int channel, int slotrank, + int *edges) +{ + int edge; + int statistics[NUM_LANES][MAX_EDGE_TIMING + 1]; + int lane; + + for (edge = 0; edge <= MAX_EDGE_TIMING; edge++) { + FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane].rising = + edge; + ctrl->timings[channel][slotrank].lanes[lane].falling = + edge; + } + printk(BIOS_SPEW, "edge %02x\n", edge); + program_timings(ctrl, channel); + + FOR_ALL_LANES { + write32(DEFAULT_MCHBAR + 0x4340 + 0x400 * channel + + 4 * lane, 0); + read32(DEFAULT_MCHBAR + 0x400 * channel + 4 * lane + + 0x4140); + } + + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f000); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + (0xc01 | (ctrl->tMOD << 16))); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x360004); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f105); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, 0x40411f4); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24)); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, 0x1f105); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, + 0x1001 | ((ctrl->CAS + 8) << 16)); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, + (slotrank << 24) | 0x60000); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x422c + 0x400 * channel, 0x1f000); + write32(DEFAULT_MCHBAR + 0x423c + 0x400 * channel, + (0xc01 | (ctrl->tMOD << 16))); + write32(DEFAULT_MCHBAR + 0x420c + 0x400 * channel, + (slotrank << 24) | 0x360000); + write32(DEFAULT_MCHBAR + 0x421c + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, 0xc0001); + + wait_428c(channel); + + FOR_ALL_LANES { + statistics[lane][edge] = + read32(DEFAULT_MCHBAR + 0x4340 + 0x400 * channel + + lane * 4); + } + } + FOR_ALL_LANES { + struct run rn = + get_longest_zero_run(statistics[lane], MAX_EDGE_TIMING + 1); + edges[lane] = rn.middle; + if (rn.all) + die("edge discovery failed"); + printk(BIOS_SPEW, "eval %d, %d, %d, %02x\n", channel, slotrank, + lane, edges[lane]); + } +} + +static void discover_edges(ramctr_timing * ctrl) +{ + int falling_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES]; + int rising_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES]; + int channel, slotrank, lane; + u32 r32; + + write32(DEFAULT_MCHBAR + 0x3400, 0); + + r32 = read32(DEFAULT_MCHBAR + 0x5030); + write32(DEFAULT_MCHBAR + 0x5030, r32 | 0x20); + udelay(1); + + write32(DEFAULT_MCHBAR + 0x5030, r32 & ~0x20); + + udelay(1); + + FOR_ALL_POPULATED_CHANNELS FOR_ALL_LANES { + write32(DEFAULT_MCHBAR + 4 * lane + + 0x400 * channel + 0x4080, 0); + } + + FOR_ALL_POPULATED_CHANNELS { + fill_pattern0(ctrl, channel, 0, 0); + write32(DEFAULT_MCHBAR | 0x4288 | (channel << 10), 0); + FOR_ALL_LANES { + read32(DEFAULT_MCHBAR + 0x400 * channel + + lane * 4 + 0x4140); + } + + FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane].falling = + 16; + ctrl->timings[channel][slotrank].lanes[lane].rising = + 16; + } + + program_timings(ctrl, channel); + + FOR_ALL_POPULATED_RANKS { + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, + 0x1f000); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + 0xc01 | (ctrl->tMOD << 16)); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x360004); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, + 0x1f105); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, + 0x4041003); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24) | 0); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, + 0x1f105); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, + 0x1001 | ((ctrl->CAS + 8) << 16)); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, + (slotrank << 24) | 0x60000); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x422c + 0x400 * channel, + 0x1f000); + write32(DEFAULT_MCHBAR + 0x423c + 0x400 * channel, + 0xc01 | (ctrl->tMOD << 16)); + write32(DEFAULT_MCHBAR + 0x420c + 0x400 * channel, + (slotrank << 24) | 0x360000); + write32(DEFAULT_MCHBAR + 0x421c + 0x400 * channel, 0); + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, + 0xc0001); + + wait_428c(channel); + } + + FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane].falling = + 48; + ctrl->timings[channel][slotrank].lanes[lane].rising = + 48; + } + + program_timings(ctrl, channel); + + FOR_ALL_POPULATED_RANKS { + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, + 0x1f000); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + 0xc01 | (ctrl->tMOD << 16)); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x360004); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, + 0x1f105); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, + 0x4041003); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24) | 0); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, + 0x1f105); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, + 0x1001 | ((ctrl->CAS + 8) << 16)); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, + (slotrank << 24) | 0x60000); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x422c + 0x400 * channel, + 0x1f000); + write32(DEFAULT_MCHBAR + 0x423c + 0x400 * channel, + 0xc01 | (ctrl->tMOD << 16)); + write32(DEFAULT_MCHBAR + 0x420c + 0x400 * channel, + (slotrank << 24) | 0x360000); + write32(DEFAULT_MCHBAR + 0x421c + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, + 0xc0001); + wait_428c(channel); + } + + FOR_ALL_LANES { + write32(DEFAULT_MCHBAR + 0x4080 + 0x400 * channel + + lane * 4, + ~read32(DEFAULT_MCHBAR + 0x4040 + + 0x400 * channel + lane * 4) & 0xff); + } + + fill_pattern0(ctrl, channel, 0, 0xffffffff); + write32(DEFAULT_MCHBAR | 0x4288 | (channel << 10), 0); + } + + /* FIXME: under some conditions (older chipsets?) vendor BIOS sets both edges to the same value. */ + write32(DEFAULT_MCHBAR + 0x4eb0, 0x300); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS { + discover_edges_real(ctrl, channel, slotrank, + falling_edges[channel][slotrank]); + } + + write32(DEFAULT_MCHBAR + 0x4eb0, 0x200); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS { + discover_edges_real(ctrl, channel, slotrank, + rising_edges[channel][slotrank]); + } + + write32(DEFAULT_MCHBAR + 0x4eb0, 0); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane].falling = + falling_edges[channel][slotrank][lane]; + ctrl->timings[channel][slotrank].lanes[lane].rising = + rising_edges[channel][slotrank][lane]; + } + + FOR_ALL_POPULATED_CHANNELS { + program_timings(ctrl, channel); + } + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + write32(DEFAULT_MCHBAR + 0x4080 + 0x400 * channel + 4 * lane, + 0); + } +} + +static void discover_edges_write_real(ramctr_timing * ctrl, int channel, + int slotrank, int *edges) +{ + int edge; + u32 raw_statistics[MAX_EDGE_TIMING + 1]; + int statistics[MAX_EDGE_TIMING + 1]; + const int reg3000b24[] = { 0, 0xc, 0x2c }; + int lane, i; + int lower[NUM_LANES]; + int upper[NUM_LANES]; + int pat; + + FOR_ALL_LANES { + lower[lane] = 0; + upper[lane] = MAX_EDGE_TIMING; + } + + for (i = 0; i < 3; i++) { + write32(DEFAULT_MCHBAR + 0x3000 + 0x100 * channel, + reg3000b24[i] << 24); + for (pat = 0; pat < NUM_PATTERNS; pat++) { + fill_pattern5(ctrl, channel, pat); + write32(DEFAULT_MCHBAR + 0x4288 + 0x400 * channel, 0x1f); + printk(BIOS_SPEW, "patterned\n"); + printk(BIOS_SPEW, "[%x] = 0x%08x\n(%d, %d)\n", + 0x3000 + 0x100 * channel, reg3000b24[i] << 24, channel, + slotrank); + for (edge = 0; edge <= MAX_EDGE_TIMING; edge++) { + FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane]. + rising = edge; + ctrl->timings[channel][slotrank].lanes[lane]. + falling = edge; + } + program_timings(ctrl, channel); + + FOR_ALL_LANES { + write32(DEFAULT_MCHBAR + 0x4340 + + 0x400 * channel + 4 * lane, 0); + read32(DEFAULT_MCHBAR + 0x400 * channel + + 4 * lane + 0x4140); + } + wait_428c(channel); + + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, + 0x1f006); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + 0x4 | (ctrl->tRCD << 16) + | (max(ctrl->tRRD, (ctrl->tFAW >> 2) + 1) << + 10)); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x60000); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, + 0x240); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, + 0x1f201); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, + 0x8005020 | ((ctrl->tWTR + ctrl->CWL + 8) << + 16)); + write32(DEFAULT_MCHBAR + 0x4204 + 0x400 * channel, + (slotrank << 24)); + write32(DEFAULT_MCHBAR + 0x4214 + 0x400 * channel, + 0x242); + + write32(DEFAULT_MCHBAR + 0x4228 + 0x400 * channel, + 0x1f105); + write32(DEFAULT_MCHBAR + 0x4238 + 0x400 * channel, + 0x4005020 | (max(ctrl->tRTP, 8) << 16)); + write32(DEFAULT_MCHBAR + 0x4208 + 0x400 * channel, + (slotrank << 24)); + write32(DEFAULT_MCHBAR + 0x4218 + 0x400 * channel, + 0x242); + + write32(DEFAULT_MCHBAR + 0x422c + 0x400 * channel, + 0x1f002); + write32(DEFAULT_MCHBAR + 0x423c + 0x400 * channel, + 0xc01 | (ctrl->tRP << 16)); + write32(DEFAULT_MCHBAR + 0x420c + 0x400 * channel, + (slotrank << 24) | 0x60400); + write32(DEFAULT_MCHBAR + 0x421c + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4284 + 0x400 * channel, + 0xc0001); + wait_428c(channel); + FOR_ALL_LANES { + read32(DEFAULT_MCHBAR + 0x4340 + + 0x400 * channel + lane * 4); + } + + raw_statistics[edge] = + MCHBAR32(0x436c + 0x400 * channel); + } + FOR_ALL_LANES { + struct run rn; + for (edge = 0; edge <= MAX_EDGE_TIMING; edge++) + statistics[edge] = + ! !(raw_statistics[edge] & (1 << lane)); + rn = get_longest_zero_run(statistics, + MAX_EDGE_TIMING + 1); + printk(BIOS_SPEW, + "edges: %d, %d, %d: 0x%x-0x%x-0x%x, 0x%x-0x%x\n", + channel, slotrank, i, rn.start, rn.middle, + rn.end, rn.start + ctrl->edge_offset[i], + rn.end - ctrl->edge_offset[i]); + lower[lane] = + max(rn.start + ctrl->edge_offset[i], lower[lane]); + upper[lane] = + min(rn.end - ctrl->edge_offset[i], upper[lane]); + edges[lane] = (lower[lane] + upper[lane]) / 2; + + } + } + } + + write32(DEFAULT_MCHBAR + 0x3000, 0); + printk(BIOS_SPEW, "CPA\n"); +} + +static void discover_edges_write(ramctr_timing * ctrl) +{ + int falling_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES]; + int rising_edges[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES]; + int channel, slotrank, lane; + + /* FIXME: under some conditions (older chipsets?) vendor BIOS sets both edges to the same value. */ + write32(DEFAULT_MCHBAR + 0x4eb0, 0x300); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS { + discover_edges_write_real(ctrl, channel, slotrank, + falling_edges[channel][slotrank]); + } + + write32(DEFAULT_MCHBAR + 0x4eb0, 0x200); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS { + discover_edges_write_real(ctrl, channel, slotrank, + rising_edges[channel][slotrank]); + } + + write32(DEFAULT_MCHBAR + 0x4eb0, 0); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + ctrl->timings[channel][slotrank].lanes[lane].falling = + falling_edges[channel][slotrank][lane]; + ctrl->timings[channel][slotrank].lanes[lane].rising = + rising_edges[channel][slotrank][lane]; + } + + FOR_ALL_POPULATED_CHANNELS + program_timings(ctrl, channel); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + write32(DEFAULT_MCHBAR + 0x4080 + 0x400 * channel + 4 * lane, + 0); + } +} + +static void test_timC_write(ramctr_timing *ctrl, int channel, int slotrank) +{ + wait_428c(channel); + write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x1f006); + write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, + (max((ctrl->tFAW >> 2) + 1, ctrl->tRRD) + << 10) | (ctrl->tRCD << 16) | 4); + write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, + (slotrank << 24) | 0x60000); + write32(DEFAULT_MCHBAR + 0x4210 + 0x400 * channel, 0x244); + + write32(DEFAULT_MCHBAR + 0x4224 + 0x400 * channel, 0x1f201); + write32(DEFAULT_MCHBAR + 0x4234 + 0x400 * channel, + 0x80011e0 | + ((ctrl->tWTR + ctrl->CWL + 8) << 16)); + write32(DEFAULT_MCHBAR + 0x4204 + + 0x400 * channel, (slotrank << 24)); + write32(DEFAULT_MCHBAR + 0x4214 + + 0x400 * channel, 0x242); + + write32(DEFAULT_MCHBAR + 0x4228 + + 0x400 * channel, 0x1f105); + write32(DEFAULT_MCHBAR + 0x4238 + + 0x400 * channel, + 0x40011e0 | (max(ctrl->tRTP, 8) << 16)); + write32(DEFAULT_MCHBAR + 0x4208 + + 0x400 * channel, (slotrank << 24)); + write32(DEFAULT_MCHBAR + 0x4218 + + 0x400 * channel, 0x242); + + write32(DEFAULT_MCHBAR + 0x422c + + 0x400 * channel, 0x1f002); + write32(DEFAULT_MCHBAR + 0x423c + + 0x400 * channel, + 0x1001 | (ctrl->tRP << 16)); + write32(DEFAULT_MCHBAR + 0x420c + + 0x400 * channel, + (slotrank << 24) | 0x60400); + write32(DEFAULT_MCHBAR + 0x421c + + 0x400 * channel, 0); + + write32(DEFAULT_MCHBAR + 0x4284 + + 0x400 * channel, 0xc0001); + wait_428c(channel); +} + +static void discover_timC_write(ramctr_timing * ctrl) +{ + const u8 rege3c_b24[3] = { 0, 0xf, 0x2f }; + int i, pat; + + int lower[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES]; + int upper[NUM_CHANNELS][NUM_SLOTRANKS][NUM_LANES]; + int channel, slotrank, lane; + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + lower[channel][slotrank][lane] = 0; + upper[channel][slotrank][lane] = MAX_TIMC; + } + + write32(DEFAULT_MCHBAR + 0x4ea8, 1); + + for (i = 0; i < 3; i++) + FOR_ALL_POPULATED_CHANNELS { + write32(DEFAULT_MCHBAR + 0xe3c + (channel * 0x100), + (rege3c_b24[i] << 24) + | (read32(DEFAULT_MCHBAR + 0xe3c + (channel * 0x100)) + & ~0x3f000000)); + udelay(2); + for (pat = 0; pat < NUM_PATTERNS; pat++) { + FOR_ALL_POPULATED_RANKS { + int timC; + u32 raw_statistics[MAX_TIMC + 1]; + int statistics[MAX_TIMC + 1]; + + fill_pattern5(ctrl, channel, pat); + write32(DEFAULT_MCHBAR + 0x4288 + 0x400 * channel, 0x1f); + for (timC = 0; timC < MAX_TIMC + 1; timC++) { + FOR_ALL_LANES + ctrl->timings[channel][slotrank].lanes[lane].timC = timC; + program_timings(ctrl, channel); + + test_timC_write (ctrl, channel, slotrank); + + raw_statistics[timC] = + MCHBAR32(0x436c + 0x400 * channel); + } + FOR_ALL_LANES { + struct run rn; + for (timC = 0; timC <= MAX_TIMC; timC++) + statistics[timC] = + !!(raw_statistics[timC] & + (1 << lane)); + rn = get_longest_zero_run(statistics, + MAX_TIMC + 1); + if (rn.all) + die("timC write discovery failed"); + printk(BIOS_SPEW, + "timC: %d, %d, %d: 0x%x-0x%x-0x%x, 0x%x-0x%x\n", + channel, slotrank, i, rn.start, + rn.middle, rn.end, + rn.start + ctrl->timC_offset[i], + rn.end - ctrl->timC_offset[i]); + lower[channel][slotrank][lane] = + max(rn.start + ctrl->timC_offset[i], + lower[channel][slotrank][lane]); + upper[channel][slotrank][lane] = + min(rn.end - ctrl->timC_offset[i], + upper[channel][slotrank][lane]); + + } + } + } + } + + FOR_ALL_CHANNELS { + write32(DEFAULT_MCHBAR + (channel * 0x100) + 0xe3c, + 0 | (read32(DEFAULT_MCHBAR + (channel * 0x100) + 0xe3c) & + ~0x3f000000)); + udelay(2); + } + + write32(DEFAULT_MCHBAR + 0x4ea8, 0); + + printk(BIOS_SPEW, "CPB\n"); + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + printk(BIOS_SPEW, "timC [%d, %d, %d] = 0x%x\n", channel, + slotrank, lane, + (lower[channel][slotrank][lane] + + upper[channel][slotrank][lane]) / 2); + ctrl->timings[channel][slotrank].lanes[lane].timC = + (lower[channel][slotrank][lane] + + upper[channel][slotrank][lane]) / 2; + } + FOR_ALL_POPULATED_CHANNELS { + program_timings(ctrl, channel); + } +} + +static void normalize_training(ramctr_timing * ctrl) +{ + int channel, slotrank, lane; + int mat = 0; + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS { + int delta; + FOR_ALL_LANES mat = + max(ctrl->timings[channel][slotrank].lanes[lane].timA, mat); + delta = (mat >> 6) - ctrl->timings[channel][slotrank].val_4028; + ctrl->timings[channel][slotrank].val_4024 += delta; + ctrl->timings[channel][slotrank].val_4028 += delta; + } + + FOR_ALL_POPULATED_CHANNELS { + program_timings(ctrl, channel); + } +} + +static void write_controller_mr(ramctr_timing * ctrl) +{ + int channel, slotrank; + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS { + write32(DEFAULT_MCHBAR | 0x0004 | (channel << 8) | + lane_registers[slotrank], make_mr0(ctrl, slotrank)); + write32(DEFAULT_MCHBAR | 0x0008 | (channel << 8) | + lane_registers[slotrank], make_mr1(ctrl, slotrank)); + } +} + +static void channel_test(ramctr_timing * ctrl) +{ + int channel, slotrank, lane; + + FOR_ALL_POPULATED_CHANNELS + if (read32(DEFAULT_MCHBAR | 0x42a0 | (channel << 10)) & 0xa000) + die("Mini channel test failed (1)\n"); + FOR_ALL_POPULATED_CHANNELS { + fill_pattern0(ctrl, channel, 0x12345678, 0x98765432); + + write32(DEFAULT_MCHBAR | 0x4288 | (channel << 10), 0); + } + + for (slotrank = 0; slotrank < 4; slotrank++) + FOR_ALL_CHANNELS + if (ctrl->rankmap[channel] & (1 << slotrank)) { + FOR_ALL_LANES { + write32(DEFAULT_MCHBAR | (0x4f40 + 4 * lane), 0); + write32(DEFAULT_MCHBAR | (0x4d40 + 4 * lane), 0); + } + wait_428c(channel); + write32(DEFAULT_MCHBAR | 0x4220 | (channel << 10), 0x0001f006); + write32(DEFAULT_MCHBAR | 0x4230 | (channel << 10), 0x0028a004); + write32(DEFAULT_MCHBAR | 0x4200 | (channel << 10), + 0x00060000 | (slotrank << 24)); + write32(DEFAULT_MCHBAR | 0x4210 | (channel << 10), 0x00000244); + write32(DEFAULT_MCHBAR | 0x4224 | (channel << 10), 0x0001f201); + write32(DEFAULT_MCHBAR | 0x4234 | (channel << 10), 0x08281064); + write32(DEFAULT_MCHBAR | 0x4204 | (channel << 10), + 0x00000000 | (slotrank << 24)); + write32(DEFAULT_MCHBAR | 0x4214 | (channel << 10), 0x00000242); + write32(DEFAULT_MCHBAR | 0x4228 | (channel << 10), 0x0001f105); + write32(DEFAULT_MCHBAR | 0x4238 | (channel << 10), 0x04281064); + write32(DEFAULT_MCHBAR | 0x4208 | (channel << 10), + 0x00000000 | (slotrank << 24)); + write32(DEFAULT_MCHBAR | 0x4218 | (channel << 10), 0x00000242); + write32(DEFAULT_MCHBAR | 0x422c | (channel << 10), 0x0001f002); + write32(DEFAULT_MCHBAR | 0x423c | (channel << 10), 0x00280c01); + write32(DEFAULT_MCHBAR | 0x420c | (channel << 10), + 0x00060400 | (slotrank << 24)); + write32(DEFAULT_MCHBAR | 0x421c | (channel << 10), 0x00000240); + write32(DEFAULT_MCHBAR | 0x4284 | (channel << 10), 0x000c0001); + wait_428c(channel); + FOR_ALL_LANES + if (read32(DEFAULT_MCHBAR | 0x4340 | (channel << 10))) + die("Mini channel test failed (2)\n"); + } +} + +static void set_scrambling_seed(ramctr_timing * ctrl) +{ + int channel; + + /* FIXME: we hardcode seeds. Do we need to use some PRNG for them? + I don't think so. */ + static u32 seeds[NUM_CHANNELS][3] = { + {0x00009a36, 0xbafcfdcf, 0x46d1ab68}, + {0x00028bfa, 0x53fe4b49, 0x19ed5483} + }; + FOR_ALL_POPULATED_CHANNELS { + MCHBAR32(0x4020 + 0x400 * channel) &= ~0x10000000; + write32(DEFAULT_MCHBAR | 0x4034, seeds[channel][0]); + write32(DEFAULT_MCHBAR | 0x403c, seeds[channel][1]); + write32(DEFAULT_MCHBAR | 0x4038, seeds[channel][2]); + } +} + +static void set_4f8c(void) +{ + struct cpuid_result cpures; + u32 cpu; + + cpures = cpuid(0); + cpu = (cpures.eax); + if (IS_SANDY_CPU(cpu) && (IS_SANDY_CPU_D0(cpu) || IS_SANDY_CPU_D1(cpu))) { + MCHBAR32(0x4f8c) = 0x141D1519; + } else { + MCHBAR32(0x4f8c) = 0x551D1519; + } +} + +static void prepare_training(ramctr_timing * ctrl) +{ + int channel; + + FOR_ALL_POPULATED_CHANNELS { + // Always drive command bus + MCHBAR32(0x4004 + 0x400 * channel) |= 0x20000000; + } + + udelay(1); + + FOR_ALL_POPULATED_CHANNELS { + wait_428c(channel); + } +} + +static void set_4008c(ramctr_timing * ctrl) +{ + int channel, slotrank; + u32 reg; + FOR_ALL_POPULATED_CHANNELS { + u32 b20, b4_8_12; + int min_320c = 10000; + int max_320c = -10000; + + FOR_ALL_POPULATED_RANKS { + max_320c = max(ctrl->timings[channel][slotrank].val_320c, max_320c); + min_320c = min(ctrl->timings[channel][slotrank].val_320c, min_320c); + } + + if (max_320c - min_320c > 51) + b20 = 0; + else + b20 = ctrl->ref_card_offset[channel]; + + if (ctrl->reg_320c_range_threshold < max_320c - min_320c) + b4_8_12 = 0x3330; + else + b4_8_12 = 0x2220; + + reg = read32(DEFAULT_MCHBAR | 0x400c | (channel << 10)); + write32(DEFAULT_MCHBAR | 0x400c | (channel << 10), + (reg & 0xFFF0FFFF) + | (ctrl->ref_card_offset[channel] << 16) + | (ctrl->ref_card_offset[channel] << 18)); + write32(DEFAULT_MCHBAR | 0x4008 | (channel << 10), + 0x0a000000 + | (b20 << 20) + | ((ctrl->ref_card_offset[channel] + 2) << 16) + | b4_8_12); + } +} + +static void set_42a0(ramctr_timing * ctrl) +{ + int channel; + FOR_ALL_POPULATED_CHANNELS { + write32(DEFAULT_MCHBAR | (0x42a0 + 0x400 * channel), + 0x00001000 | ctrl->rankmap[channel]); + MCHBAR32(0x4004 + 0x400 * channel) &= ~0x20000000; // OK + } +} + +static int encode_5d10(int ns) +{ + return (ns + 499) / 500; +} + +/* FIXME: values in this function should be hardware revision-dependent. */ +static void final_registers(ramctr_timing * ctrl) +{ + int channel; + int t1_cycles = 0, t1_ns = 0, t2_ns; + int t3_ns; + u32 r32; + + write32(DEFAULT_MCHBAR | 0x4cd4, 0x00000046); + + write32(DEFAULT_MCHBAR | 0x400c, (read32(DEFAULT_MCHBAR | 0x400c) & 0xFFFFCFFF) | 0x1000); // OK + write32(DEFAULT_MCHBAR | 0x440c, (read32(DEFAULT_MCHBAR | 0x440c) & 0xFFFFCFFF) | 0x1000); // OK + write32(DEFAULT_MCHBAR | 0x4cb0, 0x00000740); + write32(DEFAULT_MCHBAR | 0x4380, 0x00000aaa); // OK + write32(DEFAULT_MCHBAR | 0x4780, 0x00000aaa); // OK + write32(DEFAULT_MCHBAR | 0x4f88, 0x5f7003ff); // OK + write32(DEFAULT_MCHBAR | 0x5064, 0x00073000 | ctrl->reg_5064b0); // OK + + FOR_ALL_CHANNELS { + switch (ctrl->rankmap[channel]) { + /* Unpopulated channel. */ + case 0: + write32(DEFAULT_MCHBAR + 0x4384 + channel * 0x400, 0); + break; + /* Only single-ranked dimms. */ + case 1: + case 4: + case 5: + write32(DEFAULT_MCHBAR + 0x4384 + channel * 0x400, 0x373131); + break; + /* Dual-ranked dimms present. */ + default: + write32(DEFAULT_MCHBAR + 0x4384 + channel * 0x400, 0x9b6ea1); + break; + } + } + + write32 (DEFAULT_MCHBAR | 0x5880, 0xca9171e5); + write32 (DEFAULT_MCHBAR | 0x5888, + (read32 (DEFAULT_MCHBAR | 0x5888) & ~0xffffff) | 0xe4d5d0); + write32 (DEFAULT_MCHBAR | 0x58a8, read32 (DEFAULT_MCHBAR | 0x58a8) & ~0x1f); + write32 (DEFAULT_MCHBAR | 0x4294, + (read32 (DEFAULT_MCHBAR | 0x4294) & ~0x30000) + | (1 << 16)); + write32 (DEFAULT_MCHBAR | 0x4694, + (read32 (DEFAULT_MCHBAR | 0x4694) & ~0x30000) + | (1 << 16)); + + MCHBAR32(0x5030) |= 1; // OK + MCHBAR32(0x5030) |= 0x80; // OK + MCHBAR32(0x5f18) = 0xfa; // OK + + /* Find a populated channel. */ + FOR_ALL_POPULATED_CHANNELS + break; + + t1_cycles = ((read32(DEFAULT_MCHBAR + 0x4290 + channel * 0x400) >> 8) & 0xff); + r32 = read32(DEFAULT_MCHBAR + 0x5064); + if (r32 & 0x20000) + t1_cycles += (r32 & 0xfff); + t1_cycles += (read32(DEFAULT_MCHBAR + channel * 0x400 + 0x42a4) & 0xfff); + t1_ns = t1_cycles * ctrl->tCK / 256 + 544; + if (!(r32 & 0x20000)) + t1_ns += 500; + + t2_ns = 10 * ((read32(DEFAULT_MCHBAR + 0x5f10) >> 8) & 0xfff); + if ( read32(DEFAULT_MCHBAR + 0x5f00) & 8 ) + { + t3_ns = 10 * ((read32(DEFAULT_MCHBAR + 0x5f20) >> 8) & 0xfff); + t3_ns += 10 * (read32(DEFAULT_MCHBAR + 0x5f18) & 0xff); + } + else + { + t3_ns = 500; + } + printk(BIOS_DEBUG, "t123: %d, %d, %d\n", + t1_ns, t2_ns, t3_ns); + write32 (DEFAULT_MCHBAR + 0x5d10, + ((encode_5d10(t1_ns) + encode_5d10(t2_ns)) << 16) + | (encode_5d10(t1_ns) << 8) + | ((encode_5d10(t3_ns) + encode_5d10(t2_ns) + encode_5d10(t1_ns)) << 24) + | (read32(DEFAULT_MCHBAR + 0x5d10) & 0xC0C0C0C0) + | 0xc); +} + +static void save_timings(ramctr_timing * ctrl) +{ + struct mrc_data_container *mrcdata; + int output_len = ALIGN(sizeof (*ctrl), 16); + + /* Save the MRC S3 restore data to cbmem */ + mrcdata = cbmem_add + (CBMEM_ID_MRCDATA, + output_len + sizeof(struct mrc_data_container)); + + printk(BIOS_DEBUG, "Relocate MRC DATA from %p to %p (%u bytes)\n", + ctrl, mrcdata, output_len); + + mrcdata->mrc_signature = MRC_DATA_SIGNATURE; + mrcdata->mrc_data_size = output_len; + mrcdata->reserved = 0; + memcpy(mrcdata->mrc_data, ctrl, sizeof (*ctrl)); + + /* Zero the unused space in aligned buffer. */ + if (output_len > sizeof (*ctrl)) + memset(mrcdata->mrc_data+sizeof (*ctrl), 0, + output_len - sizeof (*ctrl)); + + mrcdata->mrc_checksum = compute_ip_checksum(mrcdata->mrc_data, + mrcdata->mrc_data_size); +} + +static void restore_timings(ramctr_timing * ctrl) +{ + int channel, slotrank, lane; + + FOR_ALL_POPULATED_CHANNELS + MCHBAR32(0x4004 + 0x400 * channel) = + ctrl->tRRD + | (ctrl->tRTP << 4) + | (ctrl->tCKE << 8) + | (ctrl->tWTR << 12) + | (ctrl->tFAW << 16) + | (ctrl->tWR << 24) + | (ctrl->reg_4004_b30[channel] << 30); + + udelay(1); + + FOR_ALL_POPULATED_CHANNELS { + wait_428c(channel); + } + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { + write32(DEFAULT_MCHBAR + 0x4080 + 0x400 * channel + + 4 * lane, 0); + } + + FOR_ALL_POPULATED_CHANNELS + write32(DEFAULT_MCHBAR + 0x4008 + 0x400 * channel, + read32(DEFAULT_MCHBAR + 0x4008 + + 0x400 * channel) | 0x8000000); + + FOR_ALL_POPULATED_CHANNELS { + udelay (1); + write32(DEFAULT_MCHBAR + 0x4020 + 0x400 * channel, + read32(DEFAULT_MCHBAR + 0x4020 + + 0x400 * channel) | 0x200000); + } + + printk(BIOS_SPEW, "CPE\n"); + + write32(DEFAULT_MCHBAR + 0x3400, 0); + write32(DEFAULT_MCHBAR + 0x4eb0, 0); + + printk(BIOS_SPEW, "CP5b\n"); + + FOR_ALL_POPULATED_CHANNELS { + program_timings(ctrl, channel); + } + + u32 reg, addr; + + while (!(MCHBAR32(0x5084) & 0x10000)) ; + do { + reg = MCHBAR32(0x428c); + } while ((reg & 0x14) == 0); + + // Set state of memory controller + MCHBAR32(0x5030) = 0x116; + MCHBAR32(0x4ea0) = 0; + + // Wait 500us + udelay(500); + + FOR_ALL_CHANNELS { + // Set valid rank CKE + reg = 0; + reg = (reg & ~0xf) | ctrl->rankmap[channel]; + addr = 0x400 * channel + 0x42a0; + MCHBAR32(addr) = reg; + + // Wait 10ns for ranks to settle + //udelay(0.01); + + reg = (reg & ~0xf0) | (ctrl->rankmap[channel] << 4); + MCHBAR32(addr) = reg; + + // Write reset using a NOP + write_reset(ctrl); + } + + /* mrs commands. */ + dram_mrscommands(ctrl); + + printk(BIOS_SPEW, "CP5c\n"); + + write32(DEFAULT_MCHBAR + 0x3000, 0); + + FOR_ALL_CHANNELS { + write32(DEFAULT_MCHBAR + (channel * 0x100) + 0xe3c, + 0 | (read32(DEFAULT_MCHBAR + (channel * 0x100) + 0xe3c) & + ~0x3f000000)); + udelay(2); + } + + write32(DEFAULT_MCHBAR + 0x4ea8, 0); +} + +void init_dram_ddr3(spd_raw_data * spds, int mobile, int min_tck, + int s3resume) +{ + int me_uma_size; + int cbmem_was_inited; + + MCHBAR32(0x5f00) |= 1; + + report_platform_info(); + + /* Wait for ME to be ready */ + intel_early_me_init(); + me_uma_size = intel_early_me_uma_size(); + + printk(BIOS_DEBUG, "Starting native Platform init\n"); + + u32 reg_5d10; + + wait_txt_clear(); + + wrmsr(0x000002e6, (msr_t) { .lo = 0, .hi = 0 }); + + reg_5d10 = read32(DEFAULT_MCHBAR | 0x5d10); // !!! = 0x00000000 + if ((pcie_read_config16(SOUTHBRIDGE, 0xa2) & 0xa0) == 0x20 /* 0x0004 */ + && reg_5d10 && !s3resume) { + write32(DEFAULT_MCHBAR | 0x5d10, 0); + /* Need reset. */ + outb(0x6, 0xcf9); + + hlt(); + } + + ramctr_timing ctrl; + + memset(&ctrl, 0, sizeof (ctrl)); + + early_pch_init_native(); + early_thermal_init(); + + ctrl.mobile = mobile; + ctrl.tCK = min_tck; + + /* FIXME: for non-S3 we should be able to use timing caching with + proper verification. Right now we use timings only for S3 case. + */ + if (s3resume) { + struct mrc_data_container *mrc_cache; + + mrc_cache = find_current_mrc_cache(); + if (!mrc_cache || mrc_cache->mrc_data_size < sizeof (ctrl)) { + /* Failed S3 resume, reset to come up cleanly */ + outb(0x6, 0xcf9); + hlt(); + } + memcpy(&ctrl, mrc_cache->mrc_data, sizeof (ctrl)); + } + + if (!s3resume) { + dimm_info info; + + /* Get DDR3 SPD data */ + dram_find_spds_ddr3(spds, &info, &ctrl); + + /* Find fastest common supported parameters */ + dram_find_common_params(&info, &ctrl); + + dram_dimm_mapping(&info, &ctrl); + } + + /* Set MCU frequency */ + dram_freq(&ctrl); + + if (!s3resume) { + /* Calculate timings */ + dram_timing(&ctrl); + } + + /* Set version register */ + MCHBAR32(0x5034) = 0xC04EB002; + + /* Enable crossover */ + dram_xover(&ctrl); + + /* Set timing and refresh registers */ + dram_timing_regs(&ctrl); + + /* Power mode preset */ + MCHBAR32(0x4e80) = 0x5500; + + /* Set scheduler parameters */ + MCHBAR32(0x4c20) = 0x10100005; + + /* Set cpu specific register */ + set_4f8c(); + + /* Clear IO reset bit */ + MCHBAR32(0x5030) &= ~0x20; + + /* Set MAD-DIMM registers */ + dram_dimm_set_mapping(&ctrl); + printk(BIOS_DEBUG, "Done dimm mapping\n"); + + /* Zone config */ + dram_zones(&ctrl, 1); + + /* Set memory map */ + dram_memorymap(&ctrl, me_uma_size); + printk(BIOS_DEBUG, "Done memory map\n"); + + /* Set IO registers */ + dram_ioregs(&ctrl); + printk(BIOS_DEBUG, "Done io registers\n"); + + udelay(1); + + if (s3resume) { + restore_timings(&ctrl); + } else { + /* Do jedec ddr3 reset sequence */ + dram_jedecreset(&ctrl); + printk(BIOS_DEBUG, "Done jedec reset\n"); + + /* MRS commands */ + dram_mrscommands(&ctrl); + printk(BIOS_DEBUG, "Done MRS commands\n"); + dram_mrscommands(&ctrl); + + /* Prepare for memory training */ + prepare_training(&ctrl); + + read_training(&ctrl); + write_training(&ctrl); + + printk(BIOS_SPEW, "CP5a\n"); + + discover_edges(&ctrl); + + printk(BIOS_SPEW, "CP5b\n"); + + command_training(&ctrl); + + printk(BIOS_SPEW, "CP5c\n"); + + discover_edges_write(&ctrl); + + discover_timC_write(&ctrl); + + normalize_training(&ctrl); + } + + set_4008c(&ctrl); + + write_controller_mr(&ctrl); + + if (!s3resume) { + channel_test(&ctrl); + } + + /* FIXME: should be hardware revision-dependent. */ + write32(DEFAULT_MCHBAR | 0x5024, 0x00a030ce); + + set_scrambling_seed(&ctrl); + + set_42a0(&ctrl); + + final_registers(&ctrl); + + /* Zone config */ + dram_zones(&ctrl, 0); + + if (!s3resume) + quick_ram_check(); + + intel_early_me_status(); + intel_early_me_init_done(ME_INIT_STATUS_SUCCESS); + intel_early_me_status(); + + post_system_agent_init(); + report_memory_config(); + + cbmem_was_inited = !cbmem_recovery(s3resume); + if (!s3resume) + save_timings(&ctrl); + if (s3resume && !cbmem_was_inited) { + /* Failed S3 resume, reset to come up cleanly */ + outb(0x6, 0xcf9); + hlt(); + } +} diff --git a/src/northbridge/intel/sandybridge/raminit_native.h b/src/northbridge/intel/sandybridge/raminit_native.h new file mode 100644 index 0000000..7ed75ff --- /dev/null +++ b/src/northbridge/intel/sandybridge/raminit_native.h @@ -0,0 +1,29 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2010 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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 + */ + +#ifndef RAMINIT_H +#define RAMINIT_H + +#include <device/dram/ddr3.h> + +/* The order is ch0dimmA, ch0dimmB, ch1dimmA, ch1dimmB. */ +void init_dram_ddr3(spd_raw_data *spds, int mobile, int min_tck, int s3resume); +void read_spd(spd_raw_data *spd, u8 addr); + +#endif /* RAMINIT_H */ diff --git a/src/northbridge/intel/sandybridge/raminit_patterns.h b/src/northbridge/intel/sandybridge/raminit_patterns.h new file mode 100644 index 0000000..61c67b4 --- /dev/null +++ b/src/northbridge/intel/sandybridge/raminit_patterns.h @@ -0,0 +1,639 @@ +const u32 pattern[][16] = { + {0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff}, + {0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000}, + {0xe62d6424, 0x9277e09e, 0x8f43dc3f, 0x76eae589, + 0x0010fdc6, 0xdc55e01c, 0x5effb0ab, 0x6cba5d29, + 0xa43d1e64, 0xab5c2e0f, 0x7796ed16, 0x96023bf4, + 0xa74c831d, 0x90f138c0, 0x17830a8a, 0x5ac17c47}, + {0x359ebbeb, 0x2b9b4512, 0xef584d98, 0x106bf7cb, + 0x363525ad, 0xb3a4dfdc, 0xa6b9fcd8, 0xd21689ec, + 0x84a3695b, 0xbd9c2e27, 0xdb3d0f44, 0x988158f1, + 0xcca91d3f, 0xb62a6d12, 0xe905e4cf, 0x7f1fa626}, + {0xe58efeae, 0xcd006081, 0xa9119403, 0xbcfbd35f, + 0x213b3bf7, 0x7bfcb773, 0xc85143f9, 0x0bdbff50, + 0xa3053c90, 0x51d66cb7, 0x296f4387, 0xb715f99e, + 0xfaddc989, 0xbb1de8a7, 0x39206b4d, 0x80174a57}, + {0xa1622ac1, 0xb4f4a5f0, 0x16dc2bc3, 0x50fb0954, + 0x2e261721, 0x52b82c3c, 0x821902b8, 0x0d4b6c38, + 0x1f618631, 0x047956f3, 0xd4337f5a, 0x591f8002, + 0x27f28db2, 0xfae37369, 0xb3f27580, 0x3cdb6397}, + {0x3dee23be, 0x19f36408, 0x227f4a6a, 0x024603c5, + 0xd5e062db, 0x6d8d4c5c, 0x7ff693b0, 0x76641be9, + 0x9e74f41c, 0xe7bc7f33, 0x2636f2e9, 0x70279750, + 0xce2355aa, 0x32d230ef, 0x22f9b468, 0xadd4e7a2}, + {0x936c0fed, 0xba0612d5, 0xa97c1ea7, 0x10e29d67, + 0x1c4c5dc8, 0x83645621, 0xcd8b521c, 0xb8301817, + 0xac7d6571, 0xcc41d200, 0x4ebdefdd, 0xd2917bde, + 0x60f75acc, 0x7791534b, 0x26ea2a83, 0x6b74513a}, + {0xd1957b85, 0xc6f8f9ca, 0xf04fb4be, 0xfeb786fb, + 0xa1dea3aa, 0x67fe7db6, 0x25d49c87, 0xe3d54870, + 0x93dc1f86, 0x7d0c1a18, 0x9272e128, 0x68e1b876, + 0xce284c9e, 0x8fa18792, 0x5785a340, 0xb6fcf198}, + {0xff7d8e4a, 0x0c21ee43, 0xe820b388, 0xb4443c0e, + 0xa1e6e498, 0x5c426110, 0x1b434ef3, 0xbef05b91, + 0xa6907968, 0x53662ac3, 0x6defac32, 0x2c11c29c, + 0x6175cced, 0xb17dd3ad, 0x6e6a1076, 0x1372b1fa}, + {0x4408ed06, 0x49460ffd, 0xb49d26cb, 0x6a3662a5, + 0x5e857047, 0xa387cd4a, 0x04edc81e, 0xfd94d8d4, + 0x2fe48d91, 0x9d2356bc, 0x96131878, 0xaca3fce4, + 0xbb312c6c, 0x5023b090, 0x3614be70, 0xa14dfabb}, + {0xd4cc1e83, 0x757a1930, 0xc3d16a61, 0x9e0d6681, + 0x8a081fa9, 0xbd11c888, 0x1672f010, 0xa083f71c, + 0x1ec02eef, 0xc4586ca8, 0x6d322b35, 0x56054679, + 0x1552a0ff, 0x5cb7707e, 0xdfb55d4a, 0xcc76cc07}, + {0x507cf71f, 0x2166421a, 0x54be4af0, 0xfd42158c, + 0x417b1f7f, 0x9466860b, 0x3a0075bf, 0x2055575c, + 0xcedfe7ab, 0xbe85aa5f, 0x39d0c2e3, 0x851c19df, + 0x39a35a3f, 0x3fb10d7d, 0x20b14899, 0x703b7f08}, + {0x8a7d9dd1, 0x33235565, 0xbd3d2e57, 0xa48c2726, + 0x0d5e2e13, 0xae421ff9, 0x8784a224, 0xf66c1510, + 0x057627aa, 0x8fb0cb41, 0x4289975a, 0xb181adfa, + 0x59f2059a, 0xe86feb05, 0x84222fc1, 0x319b3ce9}, + {0xe1e243b8, 0x3b0bcc1a, 0x70396f00, 0x5caff44d, + 0xe96961b3, 0xad73f692, 0x8b841a2d, 0xf5838839, + 0xec9c9d04, 0xcc2b5562, 0xf8ca2549, 0xa9c52ff8, + 0x3b2fde68, 0x3d4dc7f0, 0xa57387d0, 0x051199ad}, + {0x5f0ce4fc, 0xd830fbb7, 0x90abeb8f, 0x96d9cdbb, + 0x58f80a80, 0x0baaca36, 0x81a23623, 0x77127614, + 0xaa8382cd, 0x0922fbca, 0xd84d37e1, 0x721297df, + 0x160f3b3a, 0x10a1ecdc, 0x151c92f4, 0xc1fdcdab}, + {0x261c45cc, 0xfeddd2da, 0xfc3cb1c1, 0x6639641f, + 0x2c011892, 0x7108bee2, 0x8545e0b9, 0x7dd36dab, + 0x07d91950, 0x1520adcb, 0xf84aa939, 0x07d9bb2d, + 0xdf1ed826, 0xaee3c814, 0x1dca1e81, 0xc8e9f486}, + {0x933d306a, 0xaab7103d, 0xa8be37be, 0x49612f3a, + 0xb0cf28e5, 0xf9648902, 0x106d7c11, 0xf32e1813, + 0x21af36ef, 0xe695e4c4, 0x7ee1831d, 0x2aeda467, + 0x99d0c655, 0x3f0691ab, 0xcd68f7c1, 0xb469a20e}, + {0x8557aef0, 0x3eb0e373, 0x0853ac31, 0xe5bded62, + 0x3eddb0dd, 0x6bbf1caf, 0x2119c3d9, 0xe1732350, + 0x55456c75, 0xf6119375, 0x498dd1ad, 0x13f80916, + 0xb97f9f5e, 0x921d9f4c, 0xabdee367, 0x1d6bb8bf}, + {0xd165a3be, 0xd8b41598, 0xa20e1809, 0xefd5c8ce, + 0x18935c80, 0xdf1911f9, 0xc9e449eb, 0xb887a4d7, + 0x4a324f6f, 0x533e8031, 0x1c21c074, 0xa95f1ea5, + 0x765b320a, 0x839d7dfb, 0xc7d3aa93, 0xe534ae3d}, + {0xbe8592c8, 0x068457e6, 0x89b94fa3, 0xd522ad02, + 0x7e7db0b7, 0x2c5b896f, 0x9f8ecb37, 0x05b983ff, + 0x3fe9b25f, 0x34a6215b, 0x0592ba34, 0xd564f85a, + 0x156c426d, 0x25ad5460, 0xe7b5e8b7, 0xa73285c6}, + {0x5ad8d838, 0x27b42d36, 0xcc806ad1, 0x157a058a, + 0x7297735a, 0xffd6df8d, 0xff96f7a2, 0x155b27ea, + 0x84708101, 0x979fd78b, 0x49797d0c, 0x0dc93e3c, + 0x20287332, 0xed759f88, 0xe5068529, 0xb83aa781}, + {0xc38b302c, 0x57b54075, 0xac810692, 0xb0d493e7, + 0x4adda486, 0x0665ce2e, 0xb2a9c003, 0xafacc4ce, + 0x4d5e906d, 0xb3d52fab, 0xe6962c6b, 0x850f4dd1, + 0x5021656c, 0x5df6c06b, 0x9255125b, 0x2363c478}, + {0x188b715c, 0xe8b884b0, 0x5e6d0b9a, 0x1f0051e1, + 0xd2d35d4c, 0xbfeaecbe, 0xc84bb0ad, 0x67a232d6, + 0x99001587, 0xbf4313e1, 0x74f64061, 0x2c1fc562, + 0xb6fe8ca6, 0x5226a239, 0xf5198574, 0x61b51dca}, + {0x51dcecd3, 0xbadbe596, 0xebe3e84a, 0x772bfdfc, + 0x03656ac5, 0xa7c36e91, 0x6cd32cf0, 0xc3f699dd, + 0x7d5aba01, 0x51e38e82, 0x23103a98, 0x20298b9d, + 0x19436510, 0x63ad7e6c, 0x8bc2b33f, 0x27079917}, + {0x8bd5be78, 0xf2403bfa, 0x780ebdb6, 0x94c53b64, + 0x6241c2e2, 0x5bfb081e, 0x6799e88f, 0xc997b7d1, + 0x466ac8b1, 0xbf5909da, 0x497ea39f, 0x402ffb48, + 0xd7470c2d, 0x8510aba9, 0x6c52a1c9, 0x812ca967}, + {0x031f7ab4, 0xd32fe890, 0x36ae6de5, 0x083dcde4, + 0x99a7f12f, 0xe44864a7, 0x02b75fff, 0xf25dda35, + 0x7679ff4f, 0xed421e01, 0xd9c2cfa1, 0xd36b4e82, + 0x5315d908, 0xc7ebcb2a, 0xb6f3e4c1, 0xf5bfbae9}, + {0x3f4a2a96, 0x64d8bd5a, 0x19acd70d, 0xf62fcdd9, + 0x5de99cdf, 0x32f3b7cb, 0x2c020578, 0x4e9bafb8, + 0x74919a08, 0xaba33e91, 0xa6bd2254, 0x2435a9b9, + 0x47e2a1b4, 0xe837a28e, 0xe113f1b0, 0x7654bd79}, + {0x05537a6c, 0x77be1a5c, 0x4c7492c9, 0x9086bfb0, + 0x257adc18, 0xf4787fc1, 0xe3fb6d53, 0x9525e589, + 0x445a65bc, 0x833f7d08, 0x69cf1f7e, 0x9a6372e1, + 0xceedb52e, 0x31032997, 0xd1c36828, 0x132772d6}, + {0x0a166972, 0x89beaf3b, 0x8d780fbc, 0x8aea5392, + 0x58347a41, 0x1e381ec2, 0xcc6280c8, 0xee0863e1, + 0x976e2dd2, 0x8c6ee6e2, 0xa0ca57cd, 0x95114a7d, + 0x3c096704, 0xa941769d, 0x2de20c05, 0x0bf8f812}, + {0x22779d6c, 0x94e12e8f, 0x5ce40299, 0xea1b55b0, + 0x9ebec05d, 0xe076cd2b, 0x8fef5648, 0x6a284c65, + 0xa790b705, 0xf0b19997, 0x0d8ca8af, 0x17440419, + 0xef4f702f, 0x33cbcbb1, 0x83d60f26, 0x48988397}, + {0x0fed7f53, 0xb5acbb67, 0xc031c73f, 0x5364d9ef, + 0xa6dbd12d, 0x82174a6c, 0xccf8e7ab, 0xc473c036, + 0xcff493d8, 0xad9afc3b, 0x316a24e8, 0x1842bea4, + 0x4cc0c82e, 0x28ccd91e, 0xd7311b5d, 0x50a89860}, +}; + +static const u8 use_base[63][32] = { + { + 0x0e, 0x9e, 0xa1, 0x39, 0x06, 0x26, 0xc5, 0xe9, 0xed, 0x07, 0x49, 0x3b, 0x34, 0x7f, 0x1c, 0xa8, + 0xdf, 0x7b, 0xb7, 0xb8, 0x28, 0xbe, 0x8a, 0x70, 0x17, 0xe5, 0xc0, 0x44, 0x4a, 0x8e, 0x61, 0x3b, + }, + { + 0x42, 0xe6, 0xe0, 0x6a, 0xb3, 0x08, 0x28, 0xaf, 0xfa, 0xb9, 0xb7, 0x32, 0x83, 0x5c, 0xef, 0x3d, + 0x90, 0x91, 0x64, 0x31, 0xe9, 0x3c, 0x92, 0xe6, 0xa3, 0xd4, 0x6a, 0xc6, 0x01, 0xa6, 0xeb, 0xe6, + }, + { + 0x39, 0x7f, 0x6f, 0x81, 0xb4, 0x33, 0x4a, 0xde, 0x4f, 0x77, 0x28, 0x47, 0x08, 0xf9, 0x3a, 0x55, + 0x21, 0x57, 0x27, 0x59, 0xf5, 0x96, 0xad, 0xc1, 0x10, 0x33, 0xe0, 0xe2, 0xf8, 0xb6, 0x49, 0xbd, + }, + { + 0xdf, 0x57, 0x60, 0x27, 0x95, 0x50, 0x3a, 0x8c, 0x34, 0x8b, 0xae, 0xc5, 0x69, 0x26, 0xca, 0x39, + 0x55, 0x98, 0xfb, 0x05, 0x3c, 0x1c, 0x8d, 0xf8, 0xb9, 0x99, 0x05, 0x40, 0xe5, 0x5e, 0x2f, 0xf6, + }, + { + 0xc1, 0x6a, 0xea, 0xd6, 0x39, 0x56, 0x08, 0x89, 0x83, 0x4c, 0xef, 0xda, 0xb2, 0x69, 0x76, 0xe4, + 0x75, 0x3f, 0x39, 0x13, 0x96, 0xb5, 0x41, 0x84, 0x00, 0x64, 0x79, 0x47, 0xe4, 0xcb, 0xc3, 0xd0, + }, + { + 0xf8, 0xb1, 0x19, 0x76, 0x51, 0x99, 0xd7, 0x45, 0x38, 0x40, 0xbf, 0x10, 0x4c, 0x89, 0x43, 0xa9, + 0x89, 0xe2, 0x85, 0x3f, 0xb4, 0xe8, 0xbf, 0x5e, 0xc2, 0xb4, 0x16, 0x6d, 0x1c, 0x61, 0xca, 0x40, + }, + { + 0x1c, 0xdc, 0xa6, 0xdb, 0x71, 0x8b, 0xf9, 0xbb, 0xee, 0xc2, 0xa5, 0x66, 0xa4, 0xbc, 0xb6, 0x89, + 0x58, 0xb9, 0x6f, 0x57, 0x71, 0x57, 0x5c, 0xf0, 0xed, 0xcf, 0x2c, 0x2e, 0x1d, 0x34, 0xc3, 0x00, + }, + { + 0x1d, 0x30, 0x03, 0xb9, 0x15, 0x8e, 0x47, 0x8c, 0xf2, 0x4e, 0x2d, 0xf1, 0xbf, 0x96, 0xa7, 0xa1, + 0x3f, 0x26, 0xc3, 0xc9, 0x08, 0x0b, 0xa8, 0xdd, 0x9b, 0xeb, 0xbc, 0x77, 0x1c, 0x10, 0x03, 0x77, + }, + { + 0x50, 0x7e, 0x62, 0x26, 0xcb, 0x49, 0x7b, 0x1a, 0xd4, 0x54, 0xf1, 0x25, 0x3d, 0xa2, 0xe6, 0x8a, + 0xb3, 0x62, 0xf1, 0x7e, 0x03, 0xef, 0x1b, 0x27, 0x21, 0xcc, 0xfc, 0x72, 0x30, 0x0c, 0x69, 0xad, + }, + { + 0x11, 0xf5, 0xb2, 0xfa, 0x2d, 0xbc, 0xa1, 0xd9, 0x74, 0x15, 0x59, 0xf2, 0xc6, 0x66, 0x4f, 0xde, + 0x84, 0x82, 0x4f, 0xe8, 0x33, 0xd5, 0xc5, 0xdd, 0xba, 0x0c, 0xc7, 0x51, 0x1f, 0x3c, 0x6d, 0x44, + }, + { + 0xcf, 0xf5, 0x3b, 0xc1, 0xbd, 0x5f, 0x9c, 0xad, 0x57, 0xfb, 0xfc, 0xbe, 0x95, 0xa0, 0x48, 0x58, + 0x8a, 0x68, 0x97, 0x71, 0xf3, 0xc0, 0xd1, 0x31, 0x33, 0xb9, 0x3c, 0xe9, 0x4f, 0xbb, 0x8d, 0xeb, + }, + { + 0x29, 0x0c, 0xa1, 0xc8, 0x04, 0xdc, 0xf9, 0x25, 0x85, 0x7e, 0xea, 0x6d, 0x75, 0x28, 0x69, 0x3f, + 0x3a, 0x83, 0xe4, 0x33, 0x31, 0x77, 0x57, 0x2e, 0xa9, 0xa8, 0x05, 0xfe, 0x19, 0xb7, 0xc4, 0xd1, + }, + { + 0x6d, 0x5d, 0x3f, 0x4f, 0x8a, 0x6a, 0x77, 0x2d, 0xf7, 0x9f, 0x73, 0xab, 0x40, 0xd9, 0x89, 0x57, + 0x69, 0xd7, 0xc8, 0xc3, 0x69, 0x54, 0x93, 0x7c, 0x9f, 0x4a, 0xcc, 0xaf, 0xcc, 0x0e, 0xe0, 0xb8, + }, + { + 0xb6, 0xd5, 0x36, 0x3f, 0x1c, 0x34, 0x54, 0x9b, 0xfc, 0xec, 0x5b, 0xb0, 0x26, 0xa6, 0xc0, 0x61, + 0x6d, 0x4c, 0x4f, 0x86, 0x2a, 0xbd, 0x34, 0x35, 0x52, 0x2c, 0x82, 0x01, 0x66, 0x0e, 0x80, 0x01, + }, + { + 0x48, 0x39, 0x43, 0xb8, 0xf9, 0x2b, 0x25, 0xe8, 0xf7, 0xf0, 0x1a, 0xed, 0x33, 0x1e, 0x30, 0xba, + 0x15, 0x37, 0xeb, 0xae, 0x97, 0xa7, 0x36, 0xa4, 0xc7, 0x1f, 0x91, 0x01, 0x38, 0x80, 0x5a, 0x76, + }, + { + 0x74, 0xbe, 0x15, 0x6b, 0x85, 0x28, 0xe4, 0xc4, 0x13, 0x68, 0x67, 0x03, 0x27, 0x7e, 0x32, 0x08, + 0x87, 0x23, 0xda, 0xf2, 0x47, 0xdd, 0xac, 0x2c, 0xc5, 0x7f, 0x06, 0xc8, 0x17, 0x4c, 0x6c, 0x81, + }, + { + 0x0d, 0x9f, 0x68, 0xbb, 0xa6, 0x6c, 0x7d, 0x3f, 0x81, 0xcf, 0x9a, 0x52, 0x87, 0xce, 0x98, 0x25, + 0x40, 0x2b, 0x1b, 0xdf, 0xd3, 0x6b, 0x53, 0xed, 0x80, 0xd2, 0x3d, 0xca, 0xdf, 0x07, 0x4e, 0x6b, + }, + { + 0xff, 0xf1, 0xd2, 0x1f, 0xbd, 0xd6, 0xa7, 0x3d, 0xb4, 0xc6, 0x88, 0x9d, 0x7b, 0x05, 0x04, 0x0b, + 0x4c, 0x6f, 0x11, 0x7f, 0x19, 0x18, 0x48, 0xf1, 0x26, 0xad, 0xd0, 0x60, 0xfa, 0x40, 0x35, 0xbb, + }, + { + 0xae, 0xec, 0x0e, 0x2e, 0xfd, 0x46, 0xf0, 0x9c, 0x06, 0x1b, 0x62, 0xbf, 0xf0, 0x3e, 0xba, 0xdf, + 0xb2, 0xa2, 0x83, 0x83, 0xda, 0x04, 0x15, 0xec, 0x1e, 0x2e, 0x1a, 0x64, 0x08, 0x8e, 0xd3, 0x87, + }, + { + 0x61, 0x14, 0x05, 0x0b, 0xdb, 0xf4, 0xf0, 0xa3, 0x41, 0x11, 0x7b, 0xd9, 0xa1, 0x40, 0x4f, 0x62, + 0x98, 0x37, 0xa0, 0x90, 0x3d, 0x78, 0x63, 0x24, 0xbc, 0x8e, 0x9e, 0x99, 0x2e, 0xc7, 0xb1, 0x6d, + }, + { + 0x0f, 0xf1, 0x5f, 0xe4, 0x94, 0x3d, 0x24, 0x0d, 0xa2, 0xcf, 0xed, 0xbb, 0x55, 0x8e, 0xdb, 0x07, + 0x12, 0x05, 0x79, 0x82, 0xb1, 0x3a, 0x71, 0x76, 0xbb, 0x8b, 0xcb, 0xcc, 0x00, 0x40, 0x2e, 0xab, + }, + { + 0x48, 0x59, 0xfa, 0x46, 0x15, 0x5e, 0xa2, 0x0d, 0xe8, 0x81, 0x69, 0xe6, 0x2f, 0x5f, 0x6d, 0xaf, + 0xad, 0xc7, 0x30, 0xd6, 0xec, 0x03, 0x1e, 0x19, 0xdd, 0x1d, 0x00, 0x94, 0x0b, 0x93, 0x5a, 0x28, + }, + { + 0xfa, 0x64, 0x62, 0x57, 0x02, 0x7e, 0x37, 0xb8, 0x10, 0xa9, 0x4b, 0xe7, 0xbf, 0x03, 0xdc, 0x1c, + 0xe7, 0x21, 0x68, 0x60, 0x53, 0xec, 0xf0, 0xfc, 0xbf, 0xe5, 0x8e, 0xca, 0x77, 0xdb, 0xa5, 0xae, + }, + { + 0xc1, 0xa9, 0x9f, 0xc2, 0x87, 0x11, 0xad, 0x1c, 0xc5, 0x56, 0x61, 0xc0, 0x20, 0x33, 0xc9, 0x85, + 0xf0, 0x81, 0x36, 0x18, 0xdb, 0xaa, 0x7e, 0x79, 0x36, 0x2d, 0xfc, 0x8f, 0x72, 0x3c, 0x4c, 0xa3, + }, + { + 0xb4, 0xd3, 0x38, 0xed, 0xd3, 0x6c, 0x03, 0x26, 0x0e, 0x1c, 0x8a, 0xa8, 0x72, 0x17, 0xcb, 0xf7, + 0x87, 0xf3, 0x3f, 0x73, 0x5d, 0x12, 0xe8, 0x3b, 0x55, 0xb6, 0xcc, 0xc6, 0x85, 0xad, 0x9f, 0x9e, + }, + { + 0xe9, 0x97, 0xde, 0x7f, 0xe0, 0x9a, 0xc1, 0xdc, 0x96, 0x4c, 0xc3, 0x0d, 0x2d, 0xd4, 0x98, 0x54, + 0x89, 0x1c, 0x57, 0x7d, 0x17, 0x96, 0xe9, 0x2f, 0x02, 0x73, 0x07, 0x5c, 0x8b, 0x44, 0xd7, 0x75, + }, + { + 0xaf, 0xf2, 0x39, 0xc4, 0x23, 0xff, 0xd5, 0x85, 0xf3, 0x11, 0x44, 0x9e, 0xab, 0x59, 0x29, 0x33, + 0xe6, 0xc2, 0x1d, 0xba, 0xa8, 0x5b, 0x70, 0xc3, 0xc0, 0xf8, 0x56, 0x3b, 0x8e, 0x43, 0x4c, 0x4b, + }, + { + 0x46, 0x93, 0xb5, 0x8a, 0x71, 0x67, 0xcb, 0x42, 0x6b, 0x1b, 0x43, 0x58, 0x8b, 0x18, 0xb9, 0xf3, + 0xdc, 0x91, 0x1c, 0x08, 0x83, 0xe3, 0x63, 0xfa, 0xf9, 0x99, 0x99, 0xcb, 0x05, 0x15, 0x7b, 0x85, + }, + { + 0xcf, 0xc6, 0x3c, 0x01, 0xbd, 0xfb, 0x00, 0x8c, 0x8b, 0x07, 0x69, 0xac, 0x61, 0xdb, 0x30, 0xd5, + 0x7c, 0x71, 0x98, 0x69, 0x2e, 0x4a, 0x4a, 0x44, 0xe4, 0x72, 0x6f, 0xf2, 0x9d, 0x58, 0x02, 0x23, + }, + { + 0x29, 0x10, 0xe1, 0xe5, 0x3f, 0xe6, 0x26, 0xaf, 0x30, 0x3c, 0xfe, 0x1f, 0x97, 0x21, 0xdd, 0x8c, + 0xbb, 0x90, 0xdb, 0x2a, 0xb5, 0xb4, 0x46, 0x43, 0x50, 0x0b, 0x6b, 0xa8, 0x8f, 0x55, 0xfb, 0xd2, + }, + { + 0x89, 0x56, 0x19, 0xf9, 0x4a, 0xec, 0x38, 0x99, 0xaa, 0xcc, 0xc5, 0x15, 0xdf, 0x19, 0xee, 0x1a, + 0xc0, 0x94, 0xaf, 0x0f, 0x7b, 0xf4, 0x06, 0xf1, 0x70, 0xa3, 0x79, 0x06, 0xba, 0x4e, 0x09, 0xa6, + }, + { + 0x53, 0x3a, 0x35, 0x98, 0xa9, 0xcb, 0x2c, 0x72, 0x73, 0xb2, 0xb0, 0x63, 0x38, 0xfc, 0xa3, 0xa5, + 0xa3, 0xf1, 0x4d, 0x04, 0x2f, 0x1b, 0x83, 0xbd, 0xed, 0x20, 0x8e, 0xa5, 0x1e, 0x9d, 0xd6, 0x69, + }, + { + 0x78, 0x44, 0xe3, 0x22, 0xa4, 0x7c, 0x53, 0xef, 0x60, 0x8e, 0x39, 0x95, 0x7d, 0x9d, 0x3d, 0x0b, + 0x4a, 0x4f, 0xf4, 0x73, 0xf8, 0xfe, 0xe7, 0x65, 0x86, 0x72, 0x13, 0x0b, 0x4e, 0x8f, 0x4d, 0x7b, + }, + { + 0x46, 0xba, 0xd2, 0x82, 0x46, 0x18, 0x6e, 0x46, 0x96, 0x05, 0x1d, 0xfb, 0xf6, 0xde, 0xba, 0xb5, + 0x6b, 0x73, 0x7a, 0xd5, 0x76, 0x11, 0xb7, 0x7c, 0x0d, 0x61, 0xba, 0xf9, 0x05, 0x12, 0x2b, 0x4e, + }, + { + 0x41, 0x08, 0x8b, 0x63, 0x10, 0xeb, 0x85, 0x10, 0xf3, 0x05, 0x84, 0xc0, 0x81, 0x1f, 0x7f, 0xd3, + 0x9d, 0x01, 0xdc, 0x32, 0xd0, 0xe2, 0xd1, 0xd1, 0x41, 0x8a, 0xa0, 0xf2, 0x64, 0xda, 0x8b, 0x0e, + }, + { + 0x99, 0xf1, 0xf2, 0x88, 0xe8, 0x72, 0x8b, 0x40, 0x17, 0xcc, 0xa7, 0x4c, 0x7d, 0xf1, 0xc4, 0x3f, + 0xbf, 0xf8, 0xbe, 0xc9, 0xce, 0xce, 0x2b, 0xe9, 0x4d, 0x5b, 0xd1, 0xef, 0x76, 0xae, 0x3b, 0xbb, + }, + { + 0x64, 0x69, 0x47, 0x03, 0xe9, 0x3b, 0xc2, 0x2d, 0x2d, 0x1a, 0xdd, 0xa4, 0xac, 0xb6, 0x6e, 0x7a, + 0x41, 0x7d, 0x82, 0xed, 0x54, 0xf7, 0x05, 0xd8, 0xae, 0x07, 0x6c, 0x1c, 0xf6, 0x51, 0xa1, 0xc0, + }, + { + 0x84, 0xaf, 0xe8, 0x59, 0x0c, 0x14, 0x24, 0xec, 0xa0, 0xd2, 0xf3, 0x8f, 0x2f, 0x22, 0xe4, 0x52, + 0xf8, 0xa7, 0x39, 0x74, 0x7f, 0x80, 0x23, 0x3f, 0x30, 0xe3, 0xcb, 0x26, 0x12, 0x5c, 0xa7, 0x93, + }, + { + 0x48, 0xc8, 0x41, 0x42, 0xc5, 0xe7, 0x4d, 0x91, 0x54, 0xa6, 0x5b, 0xba, 0x46, 0x89, 0xd5, 0x42, + 0x46, 0xbc, 0xf2, 0x67, 0x4a, 0xf9, 0x88, 0xe9, 0x02, 0xa5, 0xc2, 0x38, 0x9d, 0x6a, 0x75, 0xcd, + }, + { + 0xab, 0x9b, 0x2c, 0x09, 0xda, 0xaa, 0xe9, 0xe2, 0xd7, 0xf1, 0xa4, 0x86, 0x41, 0x14, 0xcb, 0x4e, + 0x2b, 0xd1, 0x5a, 0x9a, 0x46, 0x47, 0x90, 0xb2, 0x63, 0x16, 0xcb, 0x60, 0x1c, 0x12, 0xe3, 0x2b, + }, + { + 0x54, 0x21, 0xc0, 0xbc, 0xb8, 0x29, 0xce, 0xa4, 0xf2, 0x38, 0xb4, 0x0d, 0x7d, 0xfa, 0xd4, 0x3e, + 0x28, 0xf4, 0xc4, 0xf4, 0x4a, 0x9f, 0x11, 0xf2, 0xe2, 0x31, 0xa3, 0x72, 0x16, 0xbb, 0xd9, 0x05, + }, + { + 0xdc, 0x6e, 0xbe, 0x64, 0xa2, 0xb2, 0x64, 0x46, 0x00, 0xee, 0xd2, 0xa5, 0x81, 0x86, 0x44, 0xa4, + 0x5c, 0xc4, 0xba, 0xc4, 0xa2, 0x44, 0x36, 0x77, 0xb2, 0xec, 0x0d, 0xbe, 0x8f, 0xc0, 0x80, 0x6f, + }, + { + 0x51, 0x51, 0xb2, 0x50, 0x11, 0x0b, 0x60, 0xb8, 0x8e, 0xc2, 0xf7, 0xa8, 0xb4, 0xd2, 0x48, 0xc3, + 0x51, 0x43, 0x52, 0xeb, 0x37, 0xac, 0xd0, 0xf7, 0x61, 0xa1, 0xe9, 0xe3, 0xa7, 0xdf, 0x26, 0xa9, + }, + { + 0x10, 0xd9, 0xf2, 0xfe, 0x71, 0x8e, 0x49, 0x2c, 0x64, 0x53, 0xb0, 0x9e, 0x7a, 0xcc, 0x86, 0xab, + 0x06, 0xd7, 0xc7, 0x13, 0xd1, 0xcb, 0x21, 0x42, 0x97, 0x29, 0x5d, 0xff, 0xaa, 0xec, 0x52, 0x40, + }, + { + 0x7b, 0x35, 0x93, 0xb9, 0xca, 0xbb, 0x7e, 0x09, 0x8f, 0x34, 0x32, 0x02, 0xe7, 0x0c, 0xcf, 0xd1, + 0x6c, 0x2d, 0x11, 0xcd, 0xa5, 0x3b, 0xba, 0x14, 0x47, 0xc5, 0x2c, 0xb8, 0xf6, 0xfb, 0x9d, 0x77, + }, + { + 0x45, 0xce, 0x12, 0x8e, 0xa2, 0x4e, 0x56, 0x58, 0xa7, 0xcf, 0x26, 0x4e, 0x32, 0x21, 0xe0, 0x2b, + 0xed, 0x8d, 0xe2, 0xd9, 0x51, 0x32, 0x9b, 0xdc, 0x7b, 0x0e, 0x14, 0x0a, 0xdb, 0x63, 0x6b, 0x42, + }, + { + 0x9d, 0x49, 0x72, 0xea, 0x89, 0xc7, 0xa2, 0xfd, 0x9a, 0x55, 0xd7, 0x05, 0x16, 0xeb, 0xf7, 0x49, + 0xb6, 0xcf, 0x56, 0xf7, 0x2b, 0xef, 0x6d, 0xbe, 0xdd, 0x0e, 0x90, 0x01, 0xaf, 0x1b, 0xbb, 0xaa, + }, + { + 0x2c, 0xb7, 0x26, 0x43, 0x02, 0xc5, 0x7b, 0xc6, 0x71, 0x1f, 0xf2, 0x28, 0xb4, 0xea, 0x5f, 0x02, + 0xc6, 0xeb, 0xb4, 0xf7, 0x6f, 0x01, 0x7f, 0xfe, 0x3a, 0xb0, 0xe3, 0xf3, 0x31, 0xd3, 0xcb, 0x0f, + }, + { + 0x75, 0x54, 0x90, 0xec, 0xed, 0xcc, 0xbc, 0x5c, 0x9b, 0x44, 0x30, 0x57, 0x57, 0xe0, 0xec, 0x58, + 0x20, 0x54, 0x20, 0xb0, 0x92, 0x3a, 0x06, 0x9f, 0x69, 0xcb, 0x88, 0xee, 0x52, 0x6e, 0x4c, 0xf6, + }, + { + 0x2a, 0x08, 0xd8, 0xdd, 0x2e, 0x07, 0x54, 0x0b, 0x37, 0xc6, 0x09, 0x26, 0x98, 0xf7, 0x45, 0xf6, + 0x05, 0x4f, 0x35, 0xe6, 0xb0, 0x44, 0xff, 0x62, 0x89, 0x47, 0x69, 0x30, 0xea, 0x3b, 0x7b, 0x81, + }, + { + 0x0f, 0x7f, 0x34, 0xbf, 0xf9, 0xce, 0xe7, 0x4c, 0xe1, 0x7a, 0x24, 0x74, 0xeb, 0x8b, 0xb0, 0x65, + 0x18, 0x19, 0xaf, 0x44, 0x45, 0x5e, 0xd9, 0xa4, 0xf0, 0xd8, 0xe8, 0x09, 0x22, 0x58, 0x4e, 0x4d, + }, + { + 0x48, 0x41, 0x7a, 0xd2, 0x26, 0xda, 0x39, 0xb2, 0xba, 0x03, 0x17, 0xe9, 0x80, 0x8e, 0x53, 0x4c, + 0xac, 0x64, 0x6b, 0xa7, 0x5f, 0xed, 0x64, 0x60, 0xb7, 0x5e, 0x7a, 0x68, 0x1a, 0x8a, 0xda, 0x2b, + }, + { + 0x52, 0x01, 0x25, 0xb0, 0x59, 0xcf, 0x61, 0x30, 0x52, 0xe7, 0x77, 0x66, 0xc9, 0x35, 0xac, 0xfe, + 0xc0, 0xa2, 0x18, 0x58, 0xf1, 0xc1, 0x8f, 0x28, 0x72, 0x2f, 0xdc, 0x36, 0x10, 0x5b, 0xd9, 0x6f, + }, + { + 0x05, 0xbf, 0x47, 0x32, 0x0e, 0xa7, 0xc6, 0xd6, 0x13, 0xa1, 0x72, 0x38, 0x8c, 0x1a, 0xbc, 0x6d, + 0x7c, 0xd8, 0x34, 0xac, 0x69, 0x5b, 0x43, 0xc4, 0x00, 0xf8, 0xf2, 0xa7, 0xaf, 0x9f, 0xb0, 0xde, + }, + { + 0x54, 0x67, 0xce, 0xf2, 0xfc, 0x91, 0xd2, 0x4d, 0x73, 0xc6, 0xc9, 0xc3, 0xfe, 0xcf, 0x72, 0xa0, + 0xc7, 0x43, 0xff, 0x87, 0x4b, 0xe3, 0x7f, 0xba, 0xd4, 0xa2, 0xa3, 0x14, 0x8f, 0xa0, 0x39, 0x91, + }, + { + 0xbd, 0x24, 0x35, 0xb5, 0x0e, 0x7a, 0x13, 0xb3, 0x92, 0x83, 0xaa, 0xbd, 0x0c, 0x22, 0x93, 0xbb, + 0x2a, 0xe7, 0x7a, 0x56, 0x2d, 0xae, 0x41, 0x62, 0x52, 0xb2, 0xe9, 0xbd, 0x29, 0x05, 0x51, 0x95, + }, + { + 0x97, 0x8f, 0x21, 0x82, 0x72, 0x4f, 0x65, 0xc8, 0xfc, 0x2e, 0x5e, 0x8a, 0x1a, 0xce, 0x34, 0x39, + 0x12, 0xe6, 0x9b, 0xc3, 0xab, 0x51, 0xa9, 0x40, 0xf7, 0xbe, 0x94, 0xd0, 0x66, 0xda, 0xa5, 0x39, + }, + { + 0x5a, 0x48, 0x43, 0x9a, 0x8e, 0x22, 0x85, 0x9b, 0x28, 0xc9, 0x63, 0xa2, 0x57, 0xa6, 0xe2, 0x16, + 0x64, 0xec, 0x3c, 0x59, 0x13, 0xc4, 0x7b, 0x51, 0xea, 0xfe, 0x2e, 0x70, 0xbd, 0xd9, 0x77, 0x85, + }, + { + 0x2b, 0x74, 0xb6, 0x95, 0x18, 0x94, 0x54, 0x6d, 0xae, 0xdd, 0xe9, 0xb2, 0xf9, 0xbd, 0xce, 0x27, + 0xa9, 0x87, 0x42, 0x13, 0x22, 0x29, 0x87, 0x7a, 0x04, 0xe3, 0xbe, 0x2f, 0x9c, 0x18, 0xbb, 0x13, + }, + { + 0x80, 0x95, 0x43, 0xaa, 0x19, 0x90, 0x03, 0x4f, 0x47, 0xbf, 0xf5, 0x8e, 0x2d, 0x55, 0x23, 0xb7, + 0x7b, 0x5d, 0xaa, 0x34, 0x37, 0xb2, 0x70, 0x86, 0x5e, 0xc4, 0x94, 0xf3, 0x61, 0xfd, 0x87, 0x65, + }, + { + 0xd4, 0xbc, 0x03, 0x65, 0xb0, 0xc5, 0x44, 0x81, 0x7b, 0x06, 0x94, 0x79, 0xca, 0x1f, 0xe2, 0x28, + 0x53, 0xc8, 0xa7, 0x10, 0x13, 0x77, 0xb7, 0x5c, 0x9a, 0x34, 0x1e, 0xd5, 0x78, 0xb1, 0x21, 0x61, + }, + { + 0x90, 0x0e, 0x7f, 0xa3, 0x24, 0x18, 0x12, 0xbf, 0x45, 0xd2, 0x52, 0xa3, 0x99, 0x74, 0x89, 0xd2, + 0x12, 0x8d, 0x32, 0x3c, 0xd0, 0x28, 0x54, 0x98, 0x6c, 0x9e, 0xdd, 0xc0, 0xd5, 0xf1, 0x8a, 0xb1, + }, + { + 0x82, 0xad, 0x7a, 0x5c, 0x4d, 0x81, 0x54, 0x41, 0x79, 0x42, 0x54, 0x5c, 0x49, 0x41, 0xed, 0x49, + 0xc7, 0x06, 0x61, 0xbb, 0x89, 0x2b, 0x90, 0x04, 0x1f, 0x8c, 0x31, 0x3b, 0x39, 0x4f, 0xf8, 0x33, + }, +}; +static const u8 invert[63][32] = { + { + 0x95, 0xb2, 0xa8, 0xe3, 0xac, 0xcf, 0x27, 0x3e, 0x1c, 0xa3, 0xcf, 0x7a, 0x20, 0xb4, 0x52, 0x83, + 0x0e, 0x21, 0x2d, 0xfe, 0x6f, 0x2e, 0x38, 0x13, 0x01, 0x2e, 0xa0, 0x58, 0x58, 0x6d, 0x4a, 0x6f, + }, + { + 0x63, 0x26, 0x5c, 0xd2, 0x9a, 0xc6, 0x8c, 0x5d, 0xc2, 0x0d, 0xba, 0x4f, 0x79, 0x88, 0xd1, 0x15, + 0x64, 0x55, 0x90, 0x7b, 0x76, 0x2d, 0x60, 0x04, 0x92, 0x77, 0x18, 0xd0, 0xba, 0x7f, 0xee, 0x3a, + }, + { + 0x57, 0xc1, 0x0b, 0x23, 0x06, 0x57, 0x0c, 0xde, 0xa1, 0xa5, 0x8d, 0xc6, 0x8e, 0xbd, 0x9e, 0x09, + 0xe5, 0xed, 0xe3, 0xfb, 0xb1, 0xa0, 0xda, 0x73, 0xfc, 0x3e, 0x5e, 0x6d, 0x38, 0x36, 0x26, 0xec, + }, + { + 0x8e, 0xe5, 0x30, 0x36, 0x9e, 0x30, 0x82, 0x02, 0xf6, 0x7c, 0x06, 0x71, 0xbb, 0x6e, 0x09, 0x68, + 0x16, 0xca, 0x10, 0x32, 0x90, 0xcc, 0x7a, 0x99, 0x18, 0x70, 0xe6, 0xe7, 0x3a, 0x78, 0x86, 0xe6, + }, + { + 0x18, 0x98, 0x14, 0xa7, 0xb7, 0x1f, 0x24, 0xed, 0xd0, 0xfc, 0x71, 0xa0, 0x7e, 0xef, 0xdd, 0xe2, + 0xa2, 0xf8, 0x2a, 0xc2, 0x5d, 0x94, 0x03, 0x13, 0x29, 0x39, 0x86, 0xed, 0x08, 0x99, 0x83, 0xab, + }, + { + 0xcd, 0x22, 0xa0, 0xbc, 0xea, 0xe7, 0xde, 0xca, 0x0c, 0x72, 0xbd, 0xf7, 0x40, 0x46, 0x92, 0xc5, + 0xa4, 0xf3, 0x48, 0x9a, 0x8f, 0x52, 0xab, 0x19, 0x07, 0x98, 0xae, 0x9b, 0xe7, 0xfc, 0xbd, 0x05, + }, + { + 0xd2, 0xce, 0x28, 0x79, 0x3f, 0xdd, 0xa1, 0x1c, 0x21, 0xe4, 0xeb, 0x54, 0x85, 0x5c, 0x9d, 0x64, + 0xd5, 0x5b, 0xb6, 0x06, 0x43, 0xcc, 0x80, 0x8b, 0xe3, 0xdb, 0x26, 0xf5, 0x7e, 0x5f, 0x81, 0x9d, + }, + { + 0x54, 0x42, 0xe9, 0x30, 0xd2, 0x2c, 0xba, 0x16, 0xa7, 0x99, 0x28, 0xe7, 0x54, 0x61, 0xee, 0x17, + 0xf0, 0x70, 0x34, 0xe2, 0xe7, 0x66, 0x16, 0x00, 0x95, 0x7b, 0xbd, 0xd8, 0x07, 0xab, 0xa9, 0x5b, + }, + { + 0xe7, 0x58, 0x21, 0x24, 0x0e, 0x32, 0xbd, 0x6b, 0xcb, 0xa6, 0xd9, 0x91, 0xd7, 0xfd, 0xe4, 0x4c, + 0x58, 0xd6, 0x06, 0x11, 0x02, 0x90, 0xe5, 0x1d, 0x91, 0x2f, 0x0f, 0x43, 0xe3, 0xc7, 0x66, 0xd8, + }, + { + 0x45, 0x65, 0x5e, 0x17, 0xe1, 0x00, 0xfd, 0x42, 0x30, 0x25, 0x0e, 0xa5, 0x26, 0x8a, 0x17, 0xfe, + 0xd0, 0xa2, 0xff, 0x7a, 0x09, 0xd3, 0x5a, 0xb4, 0x71, 0x84, 0x29, 0x03, 0x71, 0x70, 0x9b, 0x6e, + }, + { + 0xc7, 0x2d, 0xe6, 0xef, 0xba, 0x0b, 0x97, 0x9a, 0x91, 0xf2, 0xda, 0x26, 0x62, 0xe5, 0xbe, 0x5d, + 0xc5, 0x5d, 0x71, 0xc1, 0xb7, 0x3f, 0xb3, 0xb8, 0x74, 0xd0, 0x0c, 0x03, 0x74, 0xc0, 0x0c, 0xe4, + }, + { + 0x56, 0x38, 0x1e, 0x31, 0xca, 0x3b, 0xb5, 0xc4, 0xff, 0x5a, 0x9e, 0x86, 0xfe, 0x98, 0x0c, 0x27, + 0x23, 0x2c, 0xa0, 0x76, 0x6f, 0xae, 0xf3, 0xde, 0x71, 0x40, 0x0c, 0xdc, 0x41, 0xf9, 0x89, 0x99, + }, + { + 0x2c, 0x27, 0xed, 0x69, 0x50, 0x53, 0xc5, 0x97, 0xf4, 0x88, 0x9a, 0x2b, 0xce, 0x8a, 0xc5, 0xfb, + 0x0d, 0xbc, 0x6f, 0x9c, 0x84, 0x30, 0xf3, 0xcb, 0xc1, 0x30, 0xa4, 0xb5, 0x46, 0xd4, 0xcb, 0xea, + }, + { + 0xb7, 0xf0, 0x86, 0x66, 0xd3, 0x55, 0x64, 0xc9, 0x1b, 0x9b, 0x3d, 0x79, 0x13, 0x0a, 0x3e, 0xa1, + 0xcf, 0x54, 0x17, 0x77, 0xeb, 0x32, 0x1c, 0x47, 0x7d, 0xf0, 0xb4, 0x11, 0x3d, 0xd7, 0xef, 0x04, + }, + { + 0xf7, 0x7e, 0x71, 0xb6, 0x5e, 0xed, 0xf3, 0xfb, 0x56, 0x82, 0x22, 0x61, 0x29, 0xa2, 0x5d, 0xc6, + 0xcd, 0x03, 0x47, 0xc7, 0xcc, 0xe4, 0xf2, 0xa4, 0x3f, 0xed, 0x36, 0xae, 0xa7, 0x30, 0x84, 0x22, + }, + { + 0x13, 0x70, 0xe7, 0x97, 0x14, 0xfa, 0xa9, 0xb7, 0xd5, 0xa1, 0xa4, 0xfd, 0xe8, 0x0c, 0x92, 0xcf, + 0xc4, 0xdc, 0x5d, 0xb9, 0xa4, 0xa2, 0x16, 0xf8, 0x67, 0xdc, 0x12, 0x47, 0xb7, 0x75, 0xfd, 0x3c, + }, + { + 0x29, 0xaa, 0xdd, 0xb5, 0xdc, 0x7f, 0xce, 0xad, 0x02, 0x65, 0x27, 0x5e, 0xa5, 0x5d, 0x23, 0x0f, + 0xa7, 0x51, 0x4d, 0xf2, 0x7d, 0x2a, 0x31, 0xbf, 0x32, 0x3b, 0x80, 0xe3, 0xda, 0x56, 0xdb, 0xfc, + }, + { + 0x70, 0xd0, 0x50, 0x6d, 0xf2, 0xb3, 0x6f, 0xc1, 0x9a, 0x98, 0x02, 0x87, 0xb5, 0x31, 0x3d, 0x19, + 0xaa, 0xf4, 0xd2, 0xd4, 0x48, 0xb1, 0x08, 0x06, 0x98, 0x39, 0x00, 0x06, 0x20, 0xe5, 0x0c, 0xe1, + }, + { + 0xe6, 0xaf, 0x94, 0xa0, 0xdf, 0xc3, 0x6b, 0xb4, 0xcf, 0x78, 0xc0, 0xe8, 0x56, 0xdc, 0xac, 0xbb, + 0x5e, 0x9e, 0xda, 0x90, 0x1e, 0x7f, 0x44, 0x06, 0xe0, 0x00, 0x6a, 0xd9, 0xd1, 0xf9, 0x56, 0xac, + }, + { + 0x15, 0xa2, 0x90, 0x13, 0x4f, 0xa0, 0x9d, 0x0d, 0x9c, 0xf8, 0xc9, 0x20, 0x1c, 0x8e, 0x68, 0xcb, + 0x1f, 0x75, 0xb3, 0xb2, 0x14, 0xff, 0x19, 0x20, 0x5f, 0x30, 0xb1, 0x05, 0x36, 0x7c, 0xa2, 0xed, + }, + { + 0x9a, 0xb2, 0xf5, 0xfd, 0x04, 0x3e, 0x6b, 0x4a, 0x1d, 0x3a, 0x63, 0x96, 0x00, 0xad, 0x6c, 0x7c, + 0x4f, 0xaf, 0x4d, 0xb5, 0x03, 0x4a, 0xf7, 0x28, 0x7f, 0x1f, 0x38, 0xad, 0xfd, 0xc7, 0x4b, 0x7f, + }, + { + 0xf4, 0x5a, 0x9f, 0xf6, 0xd0, 0x1a, 0x23, 0x76, 0xee, 0x15, 0x10, 0x2c, 0x30, 0xbd, 0x45, 0xfc, + 0x65, 0x60, 0x20, 0xc5, 0x9b, 0xb4, 0x42, 0x83, 0xe9, 0x03, 0xd5, 0xec, 0xba, 0xb2, 0x3b, 0xb8, + }, + { + 0xf4, 0x1b, 0xc1, 0x73, 0x1a, 0x6c, 0x88, 0xfd, 0xc2, 0xfb, 0xe8, 0x7e, 0xcb, 0x8a, 0x0e, 0x0e, + 0x6a, 0x13, 0x54, 0xb0, 0x7b, 0xb8, 0x68, 0x90, 0x21, 0x38, 0x4e, 0x1f, 0x86, 0x51, 0x14, 0x2c, + }, + { + 0x6c, 0xd3, 0xc3, 0x8f, 0x06, 0x45, 0xec, 0x65, 0x87, 0x02, 0x3d, 0x89, 0x61, 0xde, 0x80, 0x42, + 0xf6, 0xe0, 0x8d, 0x91, 0xf0, 0x3a, 0x7a, 0x66, 0xba, 0x1c, 0xc7, 0xb6, 0x3d, 0xc4, 0x7f, 0x91, + }, + { + 0x53, 0xf6, 0x90, 0x34, 0x88, 0x3e, 0xb7, 0xef, 0x56, 0x39, 0x6e, 0x1f, 0x48, 0x14, 0xe4, 0x09, + 0xc6, 0xea, 0xc4, 0xd9, 0xed, 0x2e, 0x2e, 0x33, 0x03, 0x00, 0xb9, 0xac, 0x22, 0x65, 0xe9, 0x1b, + }, + { + 0x55, 0x78, 0x89, 0x36, 0xa0, 0x07, 0xa6, 0x99, 0xbf, 0x7c, 0xb5, 0xbd, 0xb6, 0x1e, 0xc3, 0x58, + 0xb3, 0x0f, 0x78, 0x64, 0x74, 0x77, 0x00, 0x50, 0x2e, 0x4c, 0x6a, 0xa1, 0xe8, 0x93, 0x89, 0x5d, + }, + { + 0x09, 0xf8, 0xdd, 0xe0, 0x42, 0xa4, 0x2e, 0x9d, 0xff, 0x0e, 0x70, 0x73, 0x9c, 0x87, 0xa0, 0x81, + 0x4d, 0xb1, 0xc3, 0xf3, 0xff, 0x96, 0x3b, 0x2a, 0xdf, 0x6d, 0x97, 0xba, 0x06, 0xa7, 0x7e, 0x0a, + }, + { + 0x1f, 0x46, 0xb4, 0x72, 0x14, 0x5b, 0x85, 0x01, 0x83, 0xcc, 0x24, 0x17, 0xc2, 0x07, 0xda, 0x60, + 0x6c, 0xab, 0xfa, 0xe5, 0xd9, 0xb4, 0xf0, 0x3f, 0xca, 0xf1, 0x30, 0x8d, 0xd2, 0x4e, 0xe3, 0xb4, + }, + { + 0x4f, 0xb3, 0x0d, 0x98, 0x38, 0x70, 0x28, 0xa2, 0xca, 0x5d, 0x2c, 0xdf, 0x1f, 0xce, 0xff, 0xcc, + 0x75, 0x49, 0xa0, 0xef, 0x54, 0xd9, 0x32, 0x1b, 0x17, 0xb6, 0x7e, 0x7a, 0xa6, 0x5f, 0x7a, 0xff, + }, + { + 0x81, 0x6b, 0x06, 0x73, 0x5b, 0x32, 0x0d, 0x37, 0xb4, 0x50, 0x63, 0x52, 0x25, 0x72, 0x5c, 0xf5, + 0x5d, 0x58, 0xa6, 0xbf, 0x08, 0xcc, 0x1d, 0x70, 0x2d, 0x12, 0x5d, 0xd7, 0xbd, 0xca, 0xe7, 0x10, + }, + { + 0x8f, 0xfc, 0x57, 0x17, 0xce, 0x47, 0x10, 0x79, 0xae, 0x66, 0xa5, 0xcc, 0x98, 0x0b, 0x77, 0xe8, + 0xa2, 0x6e, 0xc1, 0x0d, 0x03, 0xe3, 0x5b, 0xed, 0x38, 0x0e, 0x31, 0x2d, 0x19, 0x4d, 0xd6, 0x2a, + }, + { + 0xc6, 0x9d, 0x2d, 0x0b, 0xad, 0x6d, 0x0c, 0x61, 0x2d, 0x62, 0xe4, 0xce, 0x73, 0x47, 0x72, 0x20, + 0x0c, 0x8e, 0x8f, 0xe9, 0xe7, 0x67, 0x66, 0x2e, 0x17, 0x54, 0xec, 0x15, 0x3e, 0x1b, 0xf3, 0x04, + }, + { + 0xf4, 0xee, 0x03, 0x30, 0x2e, 0x1e, 0xa4, 0xb1, 0x86, 0x6d, 0xc3, 0x54, 0xf3, 0xc5, 0x61, 0xa6, + 0xb9, 0x28, 0x29, 0x11, 0x91, 0xcb, 0xbd, 0xc9, 0x77, 0x62, 0x09, 0x8c, 0xa4, 0x40, 0x84, 0x97, + }, + { + 0xff, 0x98, 0x9b, 0xbc, 0xc2, 0xf0, 0xf8, 0x7f, 0x5c, 0x86, 0x74, 0x33, 0xee, 0x42, 0x6e, 0xab, + 0xd4, 0xd2, 0x1a, 0x0d, 0x41, 0x2d, 0xac, 0xa1, 0x3e, 0x56, 0xed, 0x4b, 0x27, 0x5a, 0x65, 0xe4, + }, + { + 0x2b, 0xb1, 0xe3, 0x64, 0xaa, 0x32, 0x17, 0x57, 0x7c, 0x67, 0xb8, 0x6b, 0x00, 0x53, 0xbe, 0x3e, + 0xec, 0xd1, 0x1b, 0xc4, 0xc3, 0x8d, 0xe6, 0x19, 0xe8, 0x3a, 0x25, 0x98, 0x4e, 0xe9, 0xd4, 0x60, + }, + { + 0xa6, 0x2e, 0xb3, 0xc8, 0xcd, 0xc9, 0xc2, 0x8e, 0xe1, 0xf0, 0x8f, 0x96, 0x8e, 0xc6, 0x37, 0x11, + 0xbc, 0x6c, 0x0c, 0xf6, 0xb6, 0x83, 0x38, 0x96, 0x7a, 0x74, 0x5a, 0xa7, 0xe1, 0x11, 0x8d, 0x8b, + }, + { + 0x90, 0xf2, 0x4d, 0xbd, 0x83, 0x39, 0xe6, 0x54, 0xf6, 0x75, 0xf6, 0x2c, 0x28, 0x3d, 0xd1, 0xcf, + 0xe1, 0xfb, 0x9f, 0x97, 0x19, 0xca, 0x4d, 0x2c, 0x38, 0x3d, 0x36, 0xed, 0x19, 0xe9, 0x4a, 0x0b, + }, + { + 0x1a, 0x61, 0xb8, 0x19, 0x59, 0x16, 0x74, 0xec, 0xdb, 0x7b, 0xeb, 0xd6, 0xae, 0xcd, 0xe9, 0x55, + 0xdb, 0x45, 0xdc, 0xf2, 0x35, 0x84, 0xe9, 0xe6, 0x17, 0x48, 0xac, 0x38, 0x05, 0x21, 0x2c, 0x8e, + }, + { + 0x41, 0xac, 0x17, 0x42, 0xcc, 0x17, 0x10, 0x02, 0x07, 0x7e, 0xfc, 0x4d, 0x77, 0x06, 0x70, 0xcb, + 0x40, 0x8b, 0x47, 0x47, 0x07, 0x29, 0x82, 0xca, 0x93, 0x69, 0x2f, 0x3a, 0x64, 0xc6, 0xcb, 0x23, + }, + { + 0xa2, 0xcb, 0x2d, 0x02, 0x5d, 0x30, 0x9f, 0x32, 0xf5, 0xc5, 0x13, 0xff, 0xfc, 0xe2, 0xfb, 0x26, + 0x3b, 0x3b, 0xaf, 0xa4, 0x37, 0x6d, 0x45, 0xbf, 0xdb, 0xb9, 0xee, 0xec, 0x92, 0xa5, 0x1d, 0x0d, + }, + { + 0xa4, 0xef, 0x08, 0xb7, 0xb4, 0x68, 0x74, 0x93, 0xb2, 0xda, 0xba, 0xe9, 0x05, 0xf5, 0x09, 0xb6, + 0x53, 0xdd, 0x17, 0x60, 0xbb, 0x1e, 0xb0, 0x71, 0xd8, 0x47, 0x85, 0x02, 0x13, 0xbe, 0xa2, 0x67, + }, + { + 0x31, 0x50, 0x90, 0xb0, 0x83, 0x4a, 0xcf, 0x3f, 0xbe, 0x88, 0x90, 0x4b, 0xe1, 0x9f, 0xe6, 0xd0, + 0xfd, 0x01, 0x8e, 0xfc, 0xc0, 0x8c, 0x2f, 0x9b, 0x48, 0x70, 0x9d, 0x4e, 0x22, 0x21, 0x07, 0x09, + }, + { + 0x15, 0x9f, 0x37, 0x45, 0x52, 0x99, 0x6e, 0xe9, 0x1a, 0x25, 0x56, 0x0b, 0x19, 0xf1, 0xca, 0x9f, + 0x29, 0xe5, 0x23, 0xa6, 0x0b, 0x94, 0x0a, 0xe3, 0x74, 0xaa, 0xd5, 0x35, 0xaf, 0x6e, 0xb2, 0x24, + }, + { + 0x68, 0xab, 0xa6, 0x8b, 0x5f, 0xc7, 0x93, 0x1a, 0x06, 0x51, 0x2c, 0x3b, 0xad, 0x44, 0x6b, 0x69, + 0x1a, 0x1d, 0x41, 0xca, 0x8e, 0x59, 0x2c, 0x83, 0x71, 0x48, 0x8c, 0xaf, 0x50, 0x85, 0x00, 0xf3, + }, + { + 0xe2, 0xa6, 0x38, 0x93, 0xca, 0xe3, 0xd0, 0x36, 0xf4, 0xe9, 0x53, 0xfb, 0xa0, 0xd0, 0x13, 0xd3, + 0x2b, 0x7d, 0x46, 0xc8, 0x8b, 0xc7, 0x8c, 0xca, 0x59, 0xec, 0x66, 0x17, 0x70, 0xbb, 0xf9, 0x92, + }, + { + 0x89, 0xca, 0x92, 0x19, 0x01, 0xb8, 0x4b, 0x97, 0x06, 0x1a, 0x12, 0x91, 0x72, 0x11, 0xeb, 0x12, + 0x8b, 0x12, 0xd9, 0xdc, 0xc9, 0xb2, 0x37, 0xf8, 0x3e, 0x02, 0x03, 0xbe, 0x45, 0x45, 0xc9, 0x42, + }, + { + 0x45, 0x2c, 0x80, 0xe1, 0x3a, 0x0a, 0xdf, 0xa3, 0xd2, 0x4a, 0x23, 0x0d, 0x47, 0x0d, 0x49, 0xad, + 0xdf, 0xb0, 0x42, 0xdf, 0x87, 0x85, 0xa6, 0x8f, 0x9f, 0x7e, 0x9b, 0xa4, 0x42, 0x64, 0xcb, 0xfb, + }, + { + 0xc7, 0x39, 0x26, 0xb1, 0x90, 0x4d, 0xc1, 0x7a, 0xea, 0x31, 0x1b, 0xae, 0x1a, 0x5c, 0x1f, 0x4f, + 0x44, 0x2f, 0x87, 0x08, 0x5d, 0xa6, 0x74, 0xfd, 0xab, 0xb2, 0x4b, 0x01, 0xed, 0xd5, 0x4c, 0xe6, + }, + { + 0x2a, 0xef, 0xfa, 0x25, 0x3c, 0xd2, 0xc8, 0x08, 0x9c, 0x33, 0x3c, 0x47, 0xb3, 0xb5, 0x44, 0x34, + 0x97, 0xee, 0xe8, 0x52, 0x1c, 0x15, 0xb3, 0xe0, 0xda, 0xef, 0x77, 0xde, 0x15, 0x39, 0x4b, 0x38, + }, + { + 0x8a, 0x3a, 0x59, 0x61, 0x9d, 0x3e, 0x9b, 0x38, 0xc9, 0x84, 0x80, 0xaf, 0xb4, 0x37, 0x8a, 0x67, + 0x47, 0xc9, 0x6c, 0x72, 0xef, 0x39, 0x50, 0x28, 0x6c, 0x8f, 0xad, 0x09, 0x75, 0x26, 0xc9, 0xa9, + }, + { + 0x27, 0x1e, 0x8b, 0xf6, 0x6b, 0x56, 0x5d, 0x17, 0x58, 0xac, 0xdf, 0x27, 0xd9, 0x3e, 0x5b, 0xdd, + 0xaf, 0xbc, 0xb7, 0xf9, 0x76, 0x3b, 0x40, 0x06, 0xbc, 0x6e, 0xec, 0xaa, 0xb2, 0xdc, 0x9a, 0x0c, + }, + { + 0x09, 0x14, 0xef, 0x19, 0xc7, 0x7d, 0xc8, 0xa3, 0xd0, 0xaa, 0x7f, 0x09, 0x18, 0xaf, 0xd3, 0xde, + 0xbf, 0x05, 0xfc, 0xf9, 0xeb, 0xc0, 0x8e, 0xcf, 0xc7, 0x4c, 0x2f, 0x3f, 0xd4, 0x51, 0x41, 0xb2, + }, + { + 0xb7, 0x33, 0xf3, 0x72, 0x6d, 0x12, 0xc1, 0x5c, 0x5d, 0x81, 0xb3, 0x63, 0x81, 0x50, 0x81, 0xc0, + 0x4a, 0xea, 0x18, 0x7c, 0xa6, 0x2d, 0x23, 0xba, 0x4b, 0xb9, 0x31, 0xd9, 0xab, 0x20, 0x60, 0x77, + }, + { + 0xbb, 0x1c, 0x50, 0x2d, 0xdc, 0x18, 0x27, 0x98, 0x60, 0xde, 0x17, 0xd9, 0x17, 0x3c, 0xd5, 0x98, + 0xc3, 0x12, 0xfd, 0x8b, 0x25, 0x1e, 0xa5, 0xc1, 0xa8, 0xef, 0xec, 0x05, 0x3e, 0xfc, 0xd1, 0xfc, + }, + { + 0xe6, 0x3b, 0x9f, 0x33, 0x85, 0xeb, 0x91, 0xd0, 0xad, 0x2f, 0xc2, 0x96, 0x61, 0x64, 0xbc, 0x12, + 0x15, 0x79, 0x65, 0x93, 0xc2, 0x63, 0xa3, 0x27, 0x88, 0x60, 0x39, 0x35, 0x21, 0x05, 0xe9, 0x49, + }, + { + 0x9b, 0x68, 0xe7, 0xc8, 0xea, 0x0e, 0x5c, 0xa4, 0x03, 0x3a, 0x4e, 0x31, 0xb1, 0x92, 0xad, 0x9d, + 0x7e, 0xb5, 0x93, 0x81, 0xdd, 0x7a, 0xe9, 0xa1, 0x69, 0x28, 0x6a, 0xaf, 0x48, 0x05, 0x94, 0xc0, + }, + { + 0x66, 0x3d, 0x87, 0xc1, 0x48, 0x9d, 0xdf, 0x99, 0x25, 0xd7, 0xb0, 0xfa, 0x03, 0x8b, 0x62, 0x60, + 0xc5, 0x07, 0x3f, 0xa2, 0xc8, 0xbd, 0x70, 0xdb, 0x40, 0x6c, 0x65, 0xbf, 0x15, 0xfc, 0x1e, 0xc9, + }, + { + 0x38, 0x9c, 0x1a, 0x5b, 0x4f, 0x84, 0xca, 0xe1, 0x30, 0x6a, 0xf0, 0xb6, 0xf1, 0x61, 0xd3, 0xb0, + 0xa6, 0x6d, 0x0d, 0x11, 0x03, 0xe0, 0xcb, 0x9f, 0xbe, 0x7e, 0xc2, 0x7a, 0x53, 0x9d, 0x39, 0xcb, + }, + { + 0xf3, 0x47, 0x4a, 0x37, 0xcd, 0x19, 0x27, 0x0f, 0xfb, 0x3f, 0xcb, 0x81, 0x1e, 0x0f, 0xfd, 0x1f, + 0x2e, 0x8d, 0xff, 0xe9, 0x52, 0x8b, 0x8e, 0x52, 0x3c, 0x82, 0xe6, 0x44, 0xf6, 0x92, 0xd4, 0xd4, + }, + { + 0x3a, 0xe8, 0x4d, 0xcc, 0x4a, 0x0e, 0xaa, 0xf6, 0x32, 0x88, 0x4c, 0xee, 0xaa, 0x9c, 0xeb, 0x59, + 0xb5, 0xb8, 0x06, 0x89, 0x49, 0xc9, 0xa6, 0xf7, 0xa6, 0x14, 0x44, 0x55, 0x5e, 0x3e, 0x86, 0x08, + }, + { + 0xca, 0x3d, 0x95, 0x21, 0xf3, 0xbb, 0x78, 0x29, 0x6a, 0x38, 0xd3, 0xe4, 0x48, 0x98, 0x6f, 0x0e, + 0xaf, 0x46, 0xa5, 0x02, 0xdd, 0xfb, 0x52, 0x42, 0x9b, 0x69, 0x97, 0xe6, 0x68, 0x21, 0x0d, 0x69, + }, + { + 0x3a, 0x8a, 0x14, 0x6e, 0xa2, 0x24, 0x8f, 0x89, 0x5e, 0x99, 0x8a, 0x5b, 0x90, 0xb1, 0xf3, 0x64, + 0x4d, 0x10, 0xef, 0x45, 0xa9, 0xfb, 0xbb, 0xc0, 0xf5, 0x66, 0xdf, 0x15, 0xae, 0xd0, 0xd9, 0x56, + }, + { + 0x62, 0x50, 0x52, 0xb5, 0xb9, 0x76, 0xa7, 0xcb, 0xe6, 0xf7, 0x3a, 0x9f, 0xa4, 0x1e, 0x0a, 0x4d, + 0x88, 0xa4, 0x1c, 0xea, 0x11, 0x8c, 0xfb, 0xbe, 0x70, 0x62, 0xec, 0x4e, 0x00, 0x56, 0x0e, 0xa9, + }, +}; diff --git a/src/southbridge/intel/bd82x6x/Makefile.inc b/src/southbridge/intel/bd82x6x/Makefile.inc index 64038e5..fa21277 100644 --- a/src/southbridge/intel/bd82x6x/Makefile.inc +++ b/src/southbridge/intel/bd82x6x/Makefile.inc @@ -45,10 +45,14 @@ smm-$(CONFIG_SPI_FLASH_SMM) += ../common/spi.c ramstage-$(CONFIG_HAVE_SMI_HANDLER) += smi.c smm-$(CONFIG_HAVE_SMI_HANDLER) += smihandler.c me.c me_8.x.c finalize.c pch.c -romstage-y += early_usb.c early_smbus.c early_me.c me_status.c gpio.c +romstage-y += early_usb.c early_smbus.c me_status.c gpio.c romstage-y += reset.c romstage-y += early_spi.c early_pch.c +romstage-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE) += early_me.c +romstage-$(CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE) += early_me.c +romstage-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE) += early_thermal.c early_pch_native.c early_me_native.c + ifeq ($(CONFIG_BUILD_WITH_FAKE_IFD),y) IFD_BIN_PATH := $(objgenerated)/ifdfake.bin IFD_SECTIONS := $(addprefix -b ,$(CONFIG_IFD_BIOS_SECTION:"%"=%)) \ diff --git a/src/southbridge/intel/bd82x6x/early_me_native.c b/src/southbridge/intel/bd82x6x/early_me_native.c new file mode 100644 index 0000000..ab54ffd --- /dev/null +++ b/src/southbridge/intel/bd82x6x/early_me_native.c @@ -0,0 +1,272 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011 The Chromium OS Authors. All rights reserved. + * + * 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 + */ + +#include <arch/hlt.h> +#include <arch/io.h> +#include <console/console.h> +#include <delay.h> +#include <device/pci_ids.h> +#include <string.h> +#include "me.h" +#include "pch.h" + +static const char *me_ack_values[] = { + [ME_HFS_ACK_NO_DID] = "No DID Ack received", + [ME_HFS_ACK_RESET] = "Non-power cycle reset", + [ME_HFS_ACK_PWR_CYCLE] = "Power cycle reset", + [ME_HFS_ACK_S3] = "Go to S3", + [ME_HFS_ACK_S4] = "Go to S4", + [ME_HFS_ACK_S5] = "Go to S5", + [ME_HFS_ACK_GBL_RESET] = "Global Reset", + [ME_HFS_ACK_CONTINUE] = "Continue to boot" +}; + +static inline void pci_read_dword_ptr(void *ptr, int offset) +{ + u32 dword = pci_read_config32(PCH_ME_DEV, offset); + memcpy(ptr, &dword, sizeof(dword)); +} + +static inline void pci_write_dword_ptr(void *ptr, int offset) +{ + u32 dword = 0; + memcpy(&dword, ptr, sizeof(dword)); + pci_write_config32(PCH_ME_DEV, offset, dword); +} + +void intel_early_me_status(void) +{ + struct me_hfs hfs; + struct me_gmes gmes; + + pci_read_dword_ptr(&hfs, PCI_ME_HFS); + pci_read_dword_ptr(&gmes, PCI_ME_GMES); + + intel_me_status(&hfs, &gmes); +} + +int intel_early_me_init(void) +{ + int count; + struct me_uma uma; + struct me_hfs hfs; + + printk(BIOS_INFO, "Intel ME early init\n"); + + /* Wait for ME UMA SIZE VALID bit to be set */ + for (count = ME_RETRY; count > 0; --count) { + pci_read_dword_ptr(&uma, PCI_ME_UMA); + if (uma.valid) + break; + udelay(ME_DELAY); + } + if (!count) { + printk(BIOS_ERR, "ERROR: ME is not ready!\n"); + return -1; + } + + /* Check for valid firmware */ + pci_read_dword_ptr(&hfs, PCI_ME_HFS); + if (hfs.fpt_bad) { + printk(BIOS_WARNING, "WARNING: ME has bad firmware\n"); + return -1; + } + + printk(BIOS_INFO, "Intel ME firmware is ready\n"); + return 0; +} + +int intel_early_me_uma_size(void) +{ + struct me_uma uma; + + pci_read_dword_ptr(&uma, PCI_ME_UMA); + if (uma.valid) { + printk(BIOS_DEBUG, "ME: Requested %uMB UMA\n", uma.size); + return uma.size; + } + + printk(BIOS_DEBUG, "ME: Invalid UMA size\n"); + return 0; +} + +static inline void set_global_reset(int enable) +{ + u32 etr3 = pci_read_config32(PCH_LPC_DEV, ETR3); + + /* Clear CF9 Without Resume Well Reset Enable */ + etr3 &= ~ETR3_CWORWRE; + + /* CF9GR indicates a Global Reset */ + if (enable) + etr3 |= ETR3_CF9GR; + else + etr3 &= ~ETR3_CF9GR; + + pci_write_config32(PCH_LPC_DEV, ETR3, etr3); +} + +int intel_early_me_init_done(u8 status) +{ + u8 reset, errorcode, opmode; + u16 reg16; + u32 mebase_l, mebase_h; + u32 millisec; + u32 hfs, me_fws2; + struct me_did did = { + .init_done = ME_INIT_DONE, + .status = status + }; + u32 meDID; + + hfs = (pci_read_config32(PCI_DEV(0, 0x16, 0), PCI_ME_HFS) & 0xff000) >> 12; + + opmode = (hfs & 0xf0) >> 4; + errorcode = hfs & 0xf; + + if (opmode != ME_HFS_MODE_NORMAL) { + printk(BIOS_NOTICE, "ME: Wrong mode : %d\n", opmode); + //return 0; + } + if (errorcode) { + printk(BIOS_NOTICE, "ME: HFS error : %d\n", errorcode); + //return 0; + } + + me_fws2 = pci_read_config32(PCI_DEV(0, 0x16, 0), 0x48); + printk(BIOS_NOTICE, "ME: FWS2: 0x%x\n", me_fws2); + printk(BIOS_NOTICE, "ME: Bist in progress: 0x%x\n", me_fws2 & 0x1); + printk(BIOS_NOTICE, "ME: ICC Status : 0x%x\n", (me_fws2 & 0x6) >> 1); + printk(BIOS_NOTICE, "ME: Invoke MEBx : 0x%x\n", (me_fws2 & 0x8) >> 3); + printk(BIOS_NOTICE, "ME: CPU replaced : 0x%x\n", (me_fws2 & 0x10) >> 4); + printk(BIOS_NOTICE, "ME: MBP ready : 0x%x\n", (me_fws2 & 0x20) >> 5); + printk(BIOS_NOTICE, "ME: MFS failure : 0x%x\n", (me_fws2 & 0x40) >> 6); + printk(BIOS_NOTICE, "ME: Warm reset req : 0x%x\n", (me_fws2 & 0x80) >> 7); + printk(BIOS_NOTICE, "ME: CPU repl valid : 0x%x\n", (me_fws2 & 0x100) >> 8); + printk(BIOS_NOTICE, "ME: (Reserved) : 0x%x\n", (me_fws2 & 0x600) >> 9); + printk(BIOS_NOTICE, "ME: FW update req : 0x%x\n", (me_fws2 & 0x800) >> 11); + printk(BIOS_NOTICE, "ME: (Reserved) : 0x%x\n", (me_fws2 & 0xf000) >> 12); + printk(BIOS_NOTICE, "ME: Current state : 0x%x\n", (me_fws2 & 0xff0000) >> 16); + printk(BIOS_NOTICE, "ME: Current PM event: 0x%x\n", (me_fws2 & 0xf000000) >> 24); + printk(BIOS_NOTICE, "ME: Progress code : 0x%x\n", (me_fws2 & 0xf0000000) >> 28); + + // Poll cpu replaced for 50ms + millisec = 0; + while ((((me_fws2 & 0x100) >> 8) == 0) && millisec < 50) { + udelay(1000); + me_fws2 = pci_read_config32(PCI_DEV(0, 0x16, 0), 0x48); + millisec++; + } + if (millisec >= 50 || ((me_fws2 & 0x100) >> 8) == 0x0) { + printk(BIOS_NOTICE, "Waited long enough, or CPU was not replaced, continue...\n"); + } else if ((me_fws2 & 0x100) == 0x100) { + if ((me_fws2 & 0x80) == 0x80) { + printk(BIOS_NOTICE, "CPU was replaced & warm reset required...\n"); + reg16 = pcie_read_config16(PCI_DEV(0, 31, 0), 0xa2) & ~0x80; + pcie_write_config16(PCI_DEV(0, 31, 0), 0xa2, reg16); + set_global_reset(0); + outb(0x6, 0xcf9); + hlt(); + } + + if (((me_fws2 & 0x10) == 0x10) && (me_fws2 & 0x80) == 0x00) { + printk(BIOS_NOTICE, "Full training required\n"); + } + } + + printk(BIOS_NOTICE, "PASSED! Tell ME that DRAM is ready\n"); + + /* MEBASE from MESEG_BASE[35:20] */ + mebase_l = pci_read_config32(PCI_CPU_DEVICE, PCI_CPU_MEBASE_L); + mebase_h = pci_read_config32(PCI_CPU_DEVICE, PCI_CPU_MEBASE_H) & 0xf; + did.uma_base = (mebase_l >> 20) | (mebase_h << 12); + + meDID = did.uma_base | (1 << 28);// | (1 << 23); + pci_write_config32(PCI_DEV(0, 0x16, 0), PCI_ME_H_GS, meDID); + + udelay(1100); + + /* Must wait for ME acknowledgement */ + millisec = 0; + hfs = (pci_read_config32(PCI_DEV(0, 0x16, 0), PCI_ME_HFS) & 0xfe000000) >> 24; + while ((((hfs & 0xf0) >> 4) != ME_HFS_BIOS_DRAM_ACK) && (millisec < 5000)) { + udelay(1000); + hfs = (pci_read_config32(PCI_DEV(0, 0x16, 0), PCI_ME_HFS) & 0xfe000000) >> 24; + millisec++; + } + + me_fws2 = pci_read_config32(PCI_DEV(0, 0x16, 0), 0x48); + printk(BIOS_NOTICE, "ME: FWS2: 0x%x\n", me_fws2); + printk(BIOS_NOTICE, "ME: Bist in progress: 0x%x\n", me_fws2 & 0x1); + printk(BIOS_NOTICE, "ME: ICC Status : 0x%x\n", (me_fws2 & 0x6) >> 1); + printk(BIOS_NOTICE, "ME: Invoke MEBx : 0x%x\n", (me_fws2 & 0x8) >> 3); + printk(BIOS_NOTICE, "ME: CPU replaced : 0x%x\n", (me_fws2 & 0x10) >> 4); + printk(BIOS_NOTICE, "ME: MBP ready : 0x%x\n", (me_fws2 & 0x20) >> 5); + printk(BIOS_NOTICE, "ME: MFS failure : 0x%x\n", (me_fws2 & 0x40) >> 6); + printk(BIOS_NOTICE, "ME: Warm reset req : 0x%x\n", (me_fws2 & 0x80) >> 7); + printk(BIOS_NOTICE, "ME: CPU repl valid : 0x%x\n", (me_fws2 & 0x100) >> 8); + printk(BIOS_NOTICE, "ME: (Reserved) : 0x%x\n", (me_fws2 & 0x600) >> 9); + printk(BIOS_NOTICE, "ME: FW update req : 0x%x\n", (me_fws2 & 0x800) >> 11); + printk(BIOS_NOTICE, "ME: (Reserved) : 0x%x\n", (me_fws2 & 0xf000) >> 12); + printk(BIOS_NOTICE, "ME: Current state : 0x%x\n", (me_fws2 & 0xff0000) >> 16); + printk(BIOS_NOTICE, "ME: Current PM event: 0x%x\n", (me_fws2 & 0xf000000) >> 24); + printk(BIOS_NOTICE, "ME: Progress code : 0x%x\n", (me_fws2 & 0xf0000000) >> 28); + + + /* Return the requested BIOS action */ + printk(BIOS_NOTICE, "ME: Requested BIOS Action: %s\n", + me_ack_values[(hfs & 0xe) >> 1]); + + reset = inb(0xcf9); + reset &= 0xf1; + switch ((hfs & 0xe) >> 1) { + case ME_HFS_ACK_NO_DID: + case ME_HFS_ACK_CONTINUE: + /* Continue to boot */ + return 0; + case ME_HFS_ACK_RESET: + /* Non-power cycle reset */ + set_global_reset(0); + reset |= 0x06; + break; + case ME_HFS_ACK_PWR_CYCLE: + /* Power cycle reset */ + set_global_reset(0); + reset |= 0x0e; + break; + case ME_HFS_ACK_GBL_RESET: + /* Global reset */ + set_global_reset(1); + reset |= 0x0e; + break; + case ME_HFS_ACK_S3: + case ME_HFS_ACK_S4: + case ME_HFS_ACK_S5: + break; + } + + /* Perform the requested reset */ + if (reset) { + outb(reset, 0xcf9); + hlt(); + } + return -1; +} diff --git a/src/southbridge/intel/bd82x6x/early_pch_native.c b/src/southbridge/intel/bd82x6x/early_pch_native.c new file mode 100644 index 0000000..5cd6315 --- /dev/null +++ b/src/southbridge/intel/bd82x6x/early_pch_native.c @@ -0,0 +1,375 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2014 Vladimir Serbinenko <phcoder(a)gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <console/console.h> +#include <string.h> +#include <arch/hlt.h> +#include <arch/io.h> +#include <cbmem.h> +#include <arch/cbfs.h> +#include <cbfs.h> +#include <ip_checksum.h> +#include <pc80/mc146818rtc.h> +#include <device/pci_def.h> +#include <delay.h> + +#include "pch.h" +/* For DMI bar. */ +#include "northbridge/intel/sandybridge/sandybridge.h" + +#define SOUTHBRIDGE PCI_DEV(0, 0x1f, 0) + +static void +wait_2338 (void) +{ + while (read8 (DEFAULT_RCBA | 0x2338) & 1); +} + +static u32 +read_2338 (u32 edx) +{ + u32 ret; + + write32 (DEFAULT_RCBA | 0x2330, edx); + write16 (DEFAULT_RCBA | 0x2338, (read16 (DEFAULT_RCBA | 0x2338) + & 0x1ff) | 0x600); + wait_2338 (); + ret = read32 (DEFAULT_RCBA | 0x2334); + wait_2338 (); + read8 (DEFAULT_RCBA | 0x2338); + return ret; +} + +static void +write_2338 (u32 edx, u32 val) +{ + read_2338 (edx); + write16 (DEFAULT_RCBA | 0x2338, (read16 (DEFAULT_RCBA | 0x2338) + & 0x1ff) | 0x600); + wait_2338 (); + + write32 (DEFAULT_RCBA | 0x2334, val); + wait_2338 (); + write16 (DEFAULT_RCBA | 0x2338, + (read16 (DEFAULT_RCBA | 0x2338) & 0x1ff) | 0x600); + read8 (DEFAULT_RCBA | 0x2338); +} + + +static void +init_dmi (void) +{ + int i; + + write32 (DEFAULT_DMIBAR | 0x0914, + read32 (DEFAULT_DMIBAR | 0x0914) | 0x80000000); + write32 (DEFAULT_DMIBAR | 0x0934, + read32 (DEFAULT_DMIBAR | 0x0934) | 0x80000000); + for (i = 0; i < 4; i++) + { + write32 (DEFAULT_DMIBAR | 0x0a00 | (i << 4), + read32 (DEFAULT_DMIBAR | 0x0a00 | (i << 4)) & 0xf3ffffff); + write32 (DEFAULT_DMIBAR | 0x0a04 | (i << 4), + read32 (DEFAULT_DMIBAR | 0x0a04 | (i << 4)) | 0x800); + } + write32 (DEFAULT_DMIBAR | 0x0c30, (read32 (DEFAULT_DMIBAR | 0x0c30) + & 0xfffffff) | 0x40000000); + for (i = 0; i < 2; i++) + { + write32 (DEFAULT_DMIBAR | 0x0904 | (i << 5), + read32 (DEFAULT_DMIBAR | 0x0904 | (i << 5)) & 0xfe3fffff); + write32 (DEFAULT_DMIBAR | 0x090c | (i << 5), + read32 (DEFAULT_DMIBAR | 0x090c | (i << 5)) & 0xfff1ffff); + } + write32 (DEFAULT_DMIBAR | 0x090c, + read32 (DEFAULT_DMIBAR | 0x090c) & 0xfe1fffff); + write32 (DEFAULT_DMIBAR | 0x092c, + read32 (DEFAULT_DMIBAR | 0x092c) & 0xfe1fffff); + read32 (DEFAULT_DMIBAR | 0x0904); // !!! = 0x7a1842ec + write32 (DEFAULT_DMIBAR | 0x0904, 0x7a1842ec); + read32 (DEFAULT_DMIBAR | 0x090c); // !!! = 0x00000208 + write32 (DEFAULT_DMIBAR | 0x090c, 0x00000128); + read32 (DEFAULT_DMIBAR | 0x0924); // !!! = 0x7a1842ec + write32 (DEFAULT_DMIBAR | 0x0924, 0x7a1842ec); + read32 (DEFAULT_DMIBAR | 0x092c); // !!! = 0x00000208 + write32 (DEFAULT_DMIBAR | 0x092c, 0x00000128); + read32 (DEFAULT_DMIBAR | 0x0700); // !!! = 0x46139008 + write32 (DEFAULT_DMIBAR | 0x0700, 0x46139008); + read32 (DEFAULT_DMIBAR | 0x0720); // !!! = 0x46139008 + write32 (DEFAULT_DMIBAR | 0x0720, 0x46139008); + read32 (DEFAULT_DMIBAR | 0x0c04); // !!! = 0x2e680008 + write32 (DEFAULT_DMIBAR | 0x0c04, 0x2e680008); + read32 (DEFAULT_DMIBAR | 0x0904); // !!! = 0x7a1842ec + write32 (DEFAULT_DMIBAR | 0x0904, 0x3a1842ec); + read32 (DEFAULT_DMIBAR | 0x0924); // !!! = 0x7a1842ec + write32 (DEFAULT_DMIBAR | 0x0924, 0x3a1842ec); + read32 (DEFAULT_DMIBAR | 0x0910); // !!! = 0x00006300 + write32 (DEFAULT_DMIBAR | 0x0910, 0x00004300); + read32 (DEFAULT_DMIBAR | 0x0930); // !!! = 0x00006300 + write32 (DEFAULT_DMIBAR | 0x0930, 0x00004300); + read32 (DEFAULT_DMIBAR | 0x0a00); // !!! = 0x03042010 + write32 (DEFAULT_DMIBAR | 0x0a00, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a10); // !!! = 0x03042010 + write32 (DEFAULT_DMIBAR | 0x0a10, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a20); // !!! = 0x03042010 + write32 (DEFAULT_DMIBAR | 0x0a20, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a30); // !!! = 0x03042010 + write32 (DEFAULT_DMIBAR | 0x0a30, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0c00); // !!! = 0x29700c08 + write32 (DEFAULT_DMIBAR | 0x0c00, 0x29700c08); + read32 (DEFAULT_DMIBAR | 0x0a04); // !!! = 0x0c0708f0 + write32 (DEFAULT_DMIBAR | 0x0a04, 0x0c0718f0); + read32 (DEFAULT_DMIBAR | 0x0a14); // !!! = 0x0c0708f0 + write32 (DEFAULT_DMIBAR | 0x0a14, 0x0c0718f0); + read32 (DEFAULT_DMIBAR | 0x0a24); // !!! = 0x0c0708f0 + write32 (DEFAULT_DMIBAR | 0x0a24, 0x0c0718f0); + read32 (DEFAULT_DMIBAR | 0x0a34); // !!! = 0x0c0708f0 + write32 (DEFAULT_DMIBAR | 0x0a34, 0x0c0718f0); + read32 (DEFAULT_DMIBAR | 0x0900); // !!! = 0x50000000 + write32 (DEFAULT_DMIBAR | 0x0900, 0x50000000); + read32 (DEFAULT_DMIBAR | 0x0920); // !!! = 0x50000000 + write32 (DEFAULT_DMIBAR | 0x0920, 0x50000000); + read32 (DEFAULT_DMIBAR | 0x0908); // !!! = 0x51ffffff + write32 (DEFAULT_DMIBAR | 0x0908, 0x51ffffff); + read32 (DEFAULT_DMIBAR | 0x0928); // !!! = 0x51ffffff + write32 (DEFAULT_DMIBAR | 0x0928, 0x51ffffff); + read32 (DEFAULT_DMIBAR | 0x0a00); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a00, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a10); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a10, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a20); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a20, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a30); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a30, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0700); // !!! = 0x46139008 + write32 (DEFAULT_DMIBAR | 0x0700, 0x46139008); + read32 (DEFAULT_DMIBAR | 0x0720); // !!! = 0x46139008 + write32 (DEFAULT_DMIBAR | 0x0720, 0x46139008); + read32 (DEFAULT_DMIBAR | 0x0904); // !!! = 0x3a1842ec + write32 (DEFAULT_DMIBAR | 0x0904, 0x3a1846ec); + read32 (DEFAULT_DMIBAR | 0x0924); // !!! = 0x3a1842ec + write32 (DEFAULT_DMIBAR | 0x0924, 0x3a1846ec); + read32 (DEFAULT_DMIBAR | 0x0a00); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a00, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a10); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a10, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a20); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a20, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0a30); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a30, 0x03042018); + read32 (DEFAULT_DMIBAR | 0x0908); // !!! = 0x51ffffff + write32 (DEFAULT_DMIBAR | 0x0908, 0x51ffffff); + read32 (DEFAULT_DMIBAR | 0x0928); // !!! = 0x51ffffff + write32 (DEFAULT_DMIBAR | 0x0928, 0x51ffffff); + read32 (DEFAULT_DMIBAR | 0x0c00); // !!! = 0x29700c08 + write32 (DEFAULT_DMIBAR | 0x0c00, 0x29700c08); + read32 (DEFAULT_DMIBAR | 0x0c0c); // !!! = 0x16063400 + write32 (DEFAULT_DMIBAR | 0x0c0c, 0x00063400); + read32 (DEFAULT_DMIBAR | 0x0700); // !!! = 0x46139008 + write32 (DEFAULT_DMIBAR | 0x0700, 0x46339008); + read32 (DEFAULT_DMIBAR | 0x0720); // !!! = 0x46139008 + write32 (DEFAULT_DMIBAR | 0x0720, 0x46339008); + read32 (DEFAULT_DMIBAR | 0x0700); // !!! = 0x46339008 + write32 (DEFAULT_DMIBAR | 0x0700, 0x45339008); + read32 (DEFAULT_DMIBAR | 0x0720); // !!! = 0x46339008 + write32 (DEFAULT_DMIBAR | 0x0720, 0x45339008); + read32 (DEFAULT_DMIBAR | 0x0700); // !!! = 0x45339008 + write32 (DEFAULT_DMIBAR | 0x0700, 0x453b9008); + read32 (DEFAULT_DMIBAR | 0x0720); // !!! = 0x45339008 + write32 (DEFAULT_DMIBAR | 0x0720, 0x453b9008); + read32 (DEFAULT_DMIBAR | 0x0700); // !!! = 0x453b9008 + write32 (DEFAULT_DMIBAR | 0x0700, 0x45bb9008); + read32 (DEFAULT_DMIBAR | 0x0720); // !!! = 0x453b9008 + write32 (DEFAULT_DMIBAR | 0x0720, 0x45bb9008); + read32 (DEFAULT_DMIBAR | 0x0700); // !!! = 0x45bb9008 + write32 (DEFAULT_DMIBAR | 0x0700, 0x45fb9008); + read32 (DEFAULT_DMIBAR | 0x0720); // !!! = 0x45bb9008 + write32 (DEFAULT_DMIBAR | 0x0720, 0x45fb9008); + read32 (DEFAULT_DMIBAR | 0x0914); // !!! = 0x9021a080 + write32 (DEFAULT_DMIBAR | 0x0914, 0x9021a280); + read32 (DEFAULT_DMIBAR | 0x0934); // !!! = 0x9021a080 + write32 (DEFAULT_DMIBAR | 0x0934, 0x9021a280); + read32 (DEFAULT_DMIBAR | 0x0914); // !!! = 0x9021a280 + write32 (DEFAULT_DMIBAR | 0x0914, 0x9821a280); + read32 (DEFAULT_DMIBAR | 0x0934); // !!! = 0x9021a280 + write32 (DEFAULT_DMIBAR | 0x0934, 0x9821a280); + read32 (DEFAULT_DMIBAR | 0x0a00); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a00, 0x03242018); + read32 (DEFAULT_DMIBAR | 0x0a10); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a10, 0x03242018); + read32 (DEFAULT_DMIBAR | 0x0a20); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a20, 0x03242018); + read32 (DEFAULT_DMIBAR | 0x0a30); // !!! = 0x03042018 + write32 (DEFAULT_DMIBAR | 0x0a30, 0x03242018); + read32 (DEFAULT_DMIBAR | 0x0258); // !!! = 0x40000600 + write32 (DEFAULT_DMIBAR | 0x0258, 0x60000600); + read32 (DEFAULT_DMIBAR | 0x0904); // !!! = 0x3a1846ec + write32 (DEFAULT_DMIBAR | 0x0904, 0x2a1846ec); + read32 (DEFAULT_DMIBAR | 0x0914); // !!! = 0x9821a280 + write32 (DEFAULT_DMIBAR | 0x0914, 0x98200280); + read32 (DEFAULT_DMIBAR | 0x0924); // !!! = 0x3a1846ec + write32 (DEFAULT_DMIBAR | 0x0924, 0x2a1846ec); + read32 (DEFAULT_DMIBAR | 0x0934); // !!! = 0x9821a280 + write32 (DEFAULT_DMIBAR | 0x0934, 0x98200280); + read32 (DEFAULT_DMIBAR | 0x022c); // !!! = 0x00c26460 + write32 (DEFAULT_DMIBAR | 0x022c, 0x00c2403c); + read8 (DEFAULT_RCBA | 0x21a4); // !!! = 0x42 + + read32 (DEFAULT_RCBA | 0x21a4); // !!! = 0x00012c42 + read32 (DEFAULT_RCBA | 0x2340); // !!! = 0x0013001b + write32 (DEFAULT_RCBA | 0x2340, 0x003a001b); + read8 (DEFAULT_RCBA | 0x21b0); // !!! = 0x01 + write8 (DEFAULT_RCBA | 0x21b0, 0x02); + read32 (DEFAULT_DMIBAR | 0x0084); // !!! = 0x0041ac41 + write32 (DEFAULT_DMIBAR | 0x0084, 0x0041ac42); + read8 (DEFAULT_DMIBAR | 0x0088); // !!! = 0x00 + write8 (DEFAULT_DMIBAR | 0x0088, 0x20); + read16 (DEFAULT_DMIBAR | 0x008a); // !!! = 0x0041 + read8 (DEFAULT_DMIBAR | 0x0088); // !!! = 0x00 + write8 (DEFAULT_DMIBAR | 0x0088, 0x20); + read16 (DEFAULT_DMIBAR | 0x008a); // !!! = 0x0042 + read16 (DEFAULT_DMIBAR | 0x008a); // !!! = 0x0042 + + read32 (DEFAULT_DMIBAR | 0x0014); // !!! = 0x8000007f + write32 (DEFAULT_DMIBAR | 0x0014, 0x80000019); + read32 (DEFAULT_DMIBAR | 0x0020); // !!! = 0x01000000 + write32 (DEFAULT_DMIBAR | 0x0020, 0x81000022); + read32 (DEFAULT_DMIBAR | 0x002c); // !!! = 0x02000000 + write32 (DEFAULT_DMIBAR | 0x002c, 0x82000044); + read32 (DEFAULT_DMIBAR | 0x0038); // !!! = 0x07000080 + write32 (DEFAULT_DMIBAR | 0x0038, 0x87000080); + read8 (DEFAULT_DMIBAR | 0x0004); // !!! = 0x00 + write8 (DEFAULT_DMIBAR | 0x0004, 0x01); + + read32 (DEFAULT_RCBA | 0x0050); // !!! = 0x01200654 + write32 (DEFAULT_RCBA | 0x0050, 0x01200654); + read32 (DEFAULT_RCBA | 0x0050); // !!! = 0x01200654 + write32 (DEFAULT_RCBA | 0x0050, 0x012a0654); + read32 (DEFAULT_RCBA | 0x0050); // !!! = 0x012a0654 + read8 (DEFAULT_RCBA | 0x1114); // !!! = 0x00 + write8 (DEFAULT_RCBA | 0x1114, 0x05); + read32 (DEFAULT_RCBA | 0x2014); // !!! = 0x80000011 + write32 (DEFAULT_RCBA | 0x2014, 0x80000019); + read32 (DEFAULT_RCBA | 0x2020); // !!! = 0x00000000 + write32 (DEFAULT_RCBA | 0x2020, 0x81000022); + read32 (DEFAULT_RCBA | 0x2020); // !!! = 0x81000022 + read32 (DEFAULT_RCBA | 0x2030); // !!! = 0x00000000 + write32 (DEFAULT_RCBA | 0x2030, 0x82000044); + read32 (DEFAULT_RCBA | 0x2030); // !!! = 0x82000044 + read32 (DEFAULT_RCBA | 0x2040); // !!! = 0x00000000 + write32 (DEFAULT_RCBA | 0x2040, 0x87000080); + read32 (DEFAULT_RCBA | 0x0050); // !!! = 0x012a0654 + write32 (DEFAULT_RCBA | 0x0050, 0x812a0654); + read32 (DEFAULT_RCBA | 0x0050); // !!! = 0x812a0654 + read16 (DEFAULT_RCBA | 0x201a); // !!! = 0x0000 + read16 (DEFAULT_RCBA | 0x2026); // !!! = 0x0000 + read16 (DEFAULT_RCBA | 0x2036); // !!! = 0x0000 + read16 (DEFAULT_RCBA | 0x2046); // !!! = 0x0000 + read16 (DEFAULT_DMIBAR | 0x001a); // !!! = 0x0000 + read16 (DEFAULT_DMIBAR | 0x0026); // !!! = 0x0000 + read16 (DEFAULT_DMIBAR | 0x0032); // !!! = 0x0000 + read16 (DEFAULT_DMIBAR | 0x003e); // !!! = 0x0000 +} + +void +early_pch_init_native (void) +{ + pcie_write_config8 (SOUTHBRIDGE, 0xa6, + pcie_read_config8 (SOUTHBRIDGE, 0xa6) | 2); + + write32 (DEFAULT_RCBA | 0x2088, 0x00109000); + read32 (DEFAULT_RCBA | 0x20ac); // !!! = 0x00000000 + write32 (DEFAULT_RCBA | 0x20ac, 0x40000000); + write32 (DEFAULT_RCBA | 0x100c, 0x01110000); + write8 (DEFAULT_RCBA | 0x2340, 0x1b); + read32 (DEFAULT_RCBA | 0x2314); // !!! = 0x0a080000 + write32 (DEFAULT_RCBA | 0x2314, 0x0a280000); + read32 (DEFAULT_RCBA | 0x2310); // !!! = 0xc809605b + write32 (DEFAULT_RCBA | 0x2310, 0xa809605b); + write32 (DEFAULT_RCBA | 0x2324, 0x00854c74); + read8 (DEFAULT_RCBA | 0x0400); // !!! = 0x00 + read32 (DEFAULT_RCBA | 0x2310); // !!! = 0xa809605b + write32 (DEFAULT_RCBA | 0x2310, 0xa809605b); + read32 (DEFAULT_RCBA | 0x2310); // !!! = 0xa809605b + write32 (DEFAULT_RCBA | 0x2310, 0xa809605b); + + write_2338 (0xea007f62, 0x00590133); + write_2338 (0xec007f62, 0x00590133); + write_2338 (0xec007f64, 0x59555588); + write_2338 (0xea0040b9, 0x0001051c); + write_2338 (0xeb0040a1, 0x800084ff); + write_2338 (0xec0040a1, 0x800084ff); + write_2338 (0xea004001, 0x00008400); + write_2338 (0xeb004002, 0x40201758); + write_2338 (0xec004002, 0x40201758); + write_2338 (0xea004002, 0x00601758); + write_2338 (0xea0040a1, 0x810084ff); + write_2338 (0xeb0040b1, 0x0001c598); + write_2338 (0xec0040b1, 0x0001c598); + write_2338 (0xeb0040b6, 0x0001c598); + write_2338 (0xea0000a9, 0x80ff969f); + write_2338 (0xea0001a9, 0x80ff969f); + write_2338 (0xeb0040b2, 0x0001c396); + write_2338 (0xeb0040b3, 0x0001c396); + write_2338 (0xec0040b2, 0x0001c396); + write_2338 (0xea0001a9, 0x80ff94ff); + write_2338 (0xea000151, 0x0088037f); + write_2338 (0xea0000a9, 0x80ff94ff); + write_2338 (0xea000051, 0x0088037f); + + write_2338 (0xea007f05, 0x00010642); + write_2338 (0xea0040b7, 0x0001c91c); + write_2338 (0xea0040b8, 0x0001c91c); + write_2338 (0xeb0040a1, 0x820084ff); + write_2338 (0xec0040a1, 0x820084ff); + write_2338 (0xea007f0a, 0xc2480000); + + write_2338 (0xec00404d, 0x1ff177f); + write_2338 (0xec000084, 0x5a600000); + write_2338 (0xec000184, 0x5a600000); + write_2338 (0xec000284, 0x5a600000); + write_2338 (0xec000384, 0x5a600000); + write_2338 (0xec000094, 0x000f0501); + write_2338 (0xec000194, 0x000f0501); + write_2338 (0xec000294, 0x000f0501); + write_2338 (0xec000394, 0x000f0501); + write_2338 (0xec000096, 0x00000001); + write_2338 (0xec000196, 0x00000001); + write_2338 (0xec000296, 0x00000001); + write_2338 (0xec000396, 0x00000001); + write_2338 (0xec000001, 0x00008c08); + write_2338 (0xec000101, 0x00008c08); + write_2338 (0xec000201, 0x00008c08); + write_2338 (0xec000301, 0x00008c08); + write_2338 (0xec0040b5, 0x0001c518); + write_2338 (0xec000087, 0x06077597); + write_2338 (0xec000187, 0x06077597); + write_2338 (0xec000287, 0x06077597); + write_2338 (0xec000387, 0x06077597); + write_2338 (0xea000050, 0x00bb0157); + write_2338 (0xea000150, 0x00bb0157); + write_2338 (0xec007f60, 0x77777d77); + write_2338 (0xea00008d, 0x01320000); + write_2338 (0xea00018d, 0x01320000); + write_2338 (0xec0007b2, 0x04514b5e); + write_2338 (0xec00078c, 0x40000200); + write_2338 (0xec000780, 0x02000020); + + init_dmi(); +} diff --git a/src/southbridge/intel/bd82x6x/early_thermal.c b/src/southbridge/intel/bd82x6x/early_thermal.c new file mode 100644 index 0000000..02ec9a7 --- /dev/null +++ b/src/southbridge/intel/bd82x6x/early_thermal.c @@ -0,0 +1,70 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2014 Vladimir Serbinenko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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 + */ + +#include <arch/io.h> +#include "pch.h" +#include "cpu/intel/model_206ax/model_206ax.h" +#include <cpu/x86/msr.h> + +/* Early thermal init, must be done prior to giving ME its memory + which is done at the end of raminit. */ +void early_thermal_init(void) +{ + device_t dev; + msr_t msr; + + dev = PCI_DEV(0x0, 0x1f, 0x6); + + /* Program address for temporary BAR. */ + pci_write_config32(dev, 0x40, 0x40000000); + pci_write_config32(dev, 0x44, 0x0); + + /* Activate temporary BAR. */ + pci_write_config32(dev, 0x40, + pci_read_config32(dev, 0x40) | 5); + + + write16 (0x40000004, 0x3a2b); + write8 (0x4000000c, 0xff); + write8 (0x4000000d, 0x00); + write8 (0x4000000e, 0x40); + write8 (0x40000082, 0x00); + write8 (0x40000001, 0xba); + + /* Perform init. */ + /* Configure TJmax. */ + msr = rdmsr(MSR_TEMPERATURE_TARGET); + write16(0x40000012, ((msr.lo >> 16) & 0xff) << 6); + /* Northbridge temperature slope and offset. */ + write16(0x40000016, 0x808c); + + write16 (0x40000014, 0xde87); + + /* Enable thermal data reporting, processor, PCH and northbridge. */ + write16(0x4000001a, (read16(0x4000001a) & ~0xf) | 0x10f0); + + /* Disable temporary BAR. */ + pci_write_config32(dev, 0x40, + pci_read_config32(dev, 0x40) & ~1); + pci_write_config32(dev, 0x40, 0); + + write32 (DEFAULT_RCBA | 0x38b0, + (read32 (DEFAULT_RCBA | 0x38b0) & 0xffff8003) | 0x403c); +} diff --git a/src/southbridge/intel/bd82x6x/pch.h b/src/southbridge/intel/bd82x6x/pch.h index 90de855..83128e2 100644 --- a/src/southbridge/intel/bd82x6x/pch.h +++ b/src/southbridge/intel/bd82x6x/pch.h @@ -74,6 +74,8 @@ void enable_smbus(void); void enable_usb_bar(void); int smbus_read_byte(unsigned device, unsigned address); int early_spi_read(u32 offset, u32 size, u8 *buffer); +void early_thermal_init(void); +void early_pch_init_native(void); #endif #endif diff --git a/src/southbridge/intel/bd82x6x/smi.c b/src/southbridge/intel/bd82x6x/smi.c index 0166edf..a20232e 100644 --- a/src/southbridge/intel/bd82x6x/smi.c +++ b/src/southbridge/intel/bd82x6x/smi.c @@ -29,10 +29,7 @@ #include <cpu/x86/smm.h> #include <string.h> #include "pch.h" - -#if CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE || CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE #include "northbridge/intel/sandybridge/sandybridge.h" -#endif extern unsigned char _binary_smm_start; extern unsigned char _binary_smm_end; diff --git a/src/southbridge/intel/bd82x6x/usb_ehci.c b/src/southbridge/intel/bd82x6x/usb_ehci.c index 78f92d9..97f20bd 100644 --- a/src/southbridge/intel/bd82x6x/usb_ehci.c +++ b/src/southbridge/intel/bd82x6x/usb_ehci.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <kconfig.h> #include <console/console.h> #include <device/device.h> #include <device/pci.h> @@ -36,11 +37,43 @@ static void usb_ehci_init(struct device *dev) RCBA32(0x35b0) = reg32; printk(BIOS_DEBUG, "EHCI: Setting up controller.. "); + + /* For others, done in MRC. */ +#if IS_ENABLED(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE) + pci_write_config32(dev, 0x84, 0x930c8811); + pci_write_config32(dev, 0x88, 0x24000d30); + pci_write_config32(dev, 0xf4, 0x80408588); + pci_write_config32(dev, 0xf4, 0x80808588); + pci_write_config32(dev, 0xf4, 0x00808588); + pci_write_config32(dev, 0xfc, 0x205b1708); +#endif + reg32 = pci_read_config32(dev, PCI_COMMAND); reg32 |= PCI_COMMAND_MASTER; //reg32 |= PCI_COMMAND_SERR; pci_write_config32(dev, PCI_COMMAND, reg32); + /* For others, done in MRC. */ +#if IS_ENABLED(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE_NATIVE) + struct resource *res; + u8 access_cntl; + + access_cntl = pci_read_config8(dev, 0x80); + + /* Enable writes to protected registers. */ + pci_write_config8(dev, 0x80, access_cntl | 1); + + res = find_resource(dev, PCI_BASE_ADDRESS_0); + if (res) { + /* Number of ports and companion controllers. */ + reg32 = read32(res->base + 4); + write32(res->base + 4, (reg32 & 0xfff00000) | 3); + } + + /* Restore protection. */ + pci_write_config8(dev, 0x80, access_cntl); +#endif + printk(BIOS_DEBUG, "done.\n"); }
1
0
0
0
Patch set updated for coreboot: b8cfb8a x230: Deploy VBT
by Vladimir Serbinenko
29 Jul '14
29 Jul '14
Vladimir Serbinenko (phcoder(a)gmail.com) just uploaded a new patch set to gerrit, which you can find at
http://review.coreboot.org/5396
-gerrit commit b8cfb8ac3a9516a2a7ca8b72482e9597db6acbc9 Author: Vladimir Serbinenko <phcoder(a)gmail.com> Date: Sun Feb 23 00:13:56 2014 +0100 x230: Deploy VBT Change-Id: Ide31a56bfdbc31cd3b87993dfb4ed8ef0107cdba Signed-off-by: Vladimir Serbinenko <phcoder(a)gmail.com> --- src/drivers/intel/gma/intel_bios.h | 733 +++++++++++++++++++++ src/northbridge/intel/sandybridge/gma.c | 1 + .../intel/sandybridge/gma_ivybridge_lvds.c | 82 +++ 3 files changed, 816 insertions(+) diff --git a/src/drivers/intel/gma/intel_bios.h b/src/drivers/intel/gma/intel_bios.h new file mode 100644 index 0000000..36426d8 --- /dev/null +++ b/src/drivers/intel/gma/intel_bios.h @@ -0,0 +1,733 @@ +/* + * Copyright © 2006 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + * Eric Anholt <eric(a)anholt.net> + * + */ + +#ifndef _I830_BIOS_H_ +#define _I830_BIOS_H_ + +struct vbt_header { + u8 signature[20]; /**< Always starts with 'VBT$' */ + u16 version; /**< decimal */ + u16 header_size; /**< in bytes */ + u16 vbt_size; /**< in bytes */ + u8 vbt_checksum; + u8 reserved0; + u32 bdb_offset; /**< from beginning of VBT */ + u32 aim_offset[4]; /**< from beginning of VBT */ +} __attribute__((packed)); + +struct bdb_header { + u8 signature[16]; /**< Always 'BIOS_DATA_BLOCK' */ + u16 version; /**< decimal */ + u16 header_size; /**< in bytes */ + u16 bdb_size; /**< in bytes */ +}; + +/* strictly speaking, this is a "skip" block, but it has interesting info */ +struct vbios_data { + u8 type; /* 0 == desktop, 1 == mobile */ + u8 relstage; + u8 chipset; + u8 lvds_present:1; + u8 tv_present:1; + u8 rsvd2:6; /* finish byte */ + u8 rsvd3[4]; + u8 signon[155]; + u8 copyright[61]; + u16 code_segment; + u8 dos_boot_mode; + u8 bandwidth_percent; + u8 rsvd4; /* popup memory size */ + u8 resize_pci_bios; + u8 rsvd5; /* is crt already on ddc2 */ +} __attribute__((packed)); + +/* + * There are several types of BIOS data blocks (BDBs), each block has + * an ID and size in the first 3 bytes (ID in first, size in next 2). + * Known types are listed below. + */ +#define BDB_GENERAL_FEATURES 1 +#define BDB_GENERAL_DEFINITIONS 2 +#define BDB_OLD_TOGGLE_LIST 3 +#define BDB_MODE_SUPPORT_LIST 4 +#define BDB_GENERIC_MODE_TABLE 5 +#define BDB_EXT_MMIO_REGS 6 +#define BDB_SWF_IO 7 +#define BDB_SWF_MMIO 8 +#define BDB_DOT_CLOCK_TABLE 9 +#define BDB_MODE_REMOVAL_TABLE 10 +#define BDB_CHILD_DEVICE_TABLE 11 +#define BDB_DRIVER_FEATURES 12 +#define BDB_DRIVER_PERSISTENCE 13 +#define BDB_EXT_TABLE_PTRS 14 +#define BDB_DOT_CLOCK_OVERRIDE 15 +#define BDB_DISPLAY_SELECT 16 +/* 17 rsvd */ +#define BDB_DRIVER_ROTATION 18 +#define BDB_DISPLAY_REMOVE 19 +#define BDB_OEM_CUSTOM 20 +#define BDB_EFP_LIST 21 /* workarounds for VGA hsync/vsync */ +#define BDB_SDVO_LVDS_OPTIONS 22 +#define BDB_SDVO_PANEL_DTDS 23 +#define BDB_SDVO_LVDS_PNP_IDS 24 +#define BDB_SDVO_LVDS_POWER_SEQ 25 +#define BDB_TV_OPTIONS 26 +#define BDB_EDP 27 +#define BDB_LVDS_OPTIONS 40 +#define BDB_LVDS_LFP_DATA_PTRS 41 +#define BDB_LVDS_LFP_DATA 42 +#define BDB_LVDS_BACKLIGHT 43 +#define BDB_LVDS_POWER 44 +#define BDB_MIPI 50 +#define BDB_SKIP 254 /* VBIOS private block, ignore */ + +struct bdb_general_features { + /* bits 1 */ + u8 panel_fitting:2; + u8 flexaim:1; + u8 msg_enable:1; + u8 clear_screen:3; + u8 color_flip:1; + + /* bits 2 */ + u8 download_ext_vbt:1; + u8 enable_ssc:1; + u8 ssc_freq:1; + u8 enable_lfp_on_override:1; + u8 disable_ssc_ddt:1; + u8 rsvd7:1; + u8 display_clock_mode:1; + u8 rsvd8:1; /* finish byte */ + + /* bits 3 */ + u8 disable_smooth_vision:1; + u8 single_dvi:1; + u8 rsvd9:1; + u8 fdi_rx_polarity_inverted:1; + u8 rsvd10:4; /* finish byte */ + + /* bits 4 */ + u8 legacy_monitor_detect; + + /* bits 5 */ + u8 int_crt_support:1; + u8 int_tv_support:1; + u8 int_efp_support:1; + u8 dp_ssc_enb:1; /* PCH attached eDP supports SSC */ + u8 dp_ssc_freq:1; /* SSC freq for PCH attached eDP */ + u8 rsvd11:3; /* finish byte */ +} __attribute__((packed)); + +/* pre-915 */ +#define GPIO_PIN_DVI_LVDS 0x03 /* "DVI/LVDS DDC GPIO pins" */ +#define GPIO_PIN_ADD_I2C 0x05 /* "ADDCARD I2C GPIO pins" */ +#define GPIO_PIN_ADD_DDC 0x04 /* "ADDCARD DDC GPIO pins" */ +#define GPIO_PIN_ADD_DDC_I2C 0x06 /* "ADDCARD DDC/I2C GPIO pins" */ + +/* Pre 915 */ +#define DEVICE_TYPE_NONE 0x00 +#define DEVICE_TYPE_CRT 0x01 +#define DEVICE_TYPE_TV 0x09 +#define DEVICE_TYPE_EFP 0x12 +#define DEVICE_TYPE_LFP 0x22 +/* On 915+ */ +#define DEVICE_TYPE_CRT_DPMS 0x6001 +#define DEVICE_TYPE_CRT_DPMS_HOTPLUG 0x4001 +#define DEVICE_TYPE_TV_COMPOSITE 0x0209 +#define DEVICE_TYPE_TV_MACROVISION 0x0289 +#define DEVICE_TYPE_TV_RF_COMPOSITE 0x020c +#define DEVICE_TYPE_TV_SVIDEO_COMPOSITE 0x0609 +#define DEVICE_TYPE_TV_SCART 0x0209 +#define DEVICE_TYPE_TV_CODEC_HOTPLUG_PWR 0x6009 +#define DEVICE_TYPE_EFP_HOTPLUG_PWR 0x6012 +#define DEVICE_TYPE_EFP_DVI_HOTPLUG_PWR 0x6052 +#define DEVICE_TYPE_EFP_DVI_I 0x6053 +#define DEVICE_TYPE_EFP_DVI_D_DUAL 0x6152 +#define DEVICE_TYPE_EFP_DVI_D_HDCP 0x60d2 +#define DEVICE_TYPE_OPENLDI_HOTPLUG_PWR 0x6062 +#define DEVICE_TYPE_OPENLDI_DUALPIX 0x6162 +#define DEVICE_TYPE_LFP_PANELLINK 0x5012 +#define DEVICE_TYPE_LFP_CMOS_PWR 0x5042 +#define DEVICE_TYPE_LFP_LVDS_PWR 0x5062 +#define DEVICE_TYPE_LFP_LVDS_DUAL 0x5162 +#define DEVICE_TYPE_LFP_LVDS_DUAL_HDCP 0x51e2 + +#define DEVICE_CFG_NONE 0x00 +#define DEVICE_CFG_12BIT_DVOB 0x01 +#define DEVICE_CFG_12BIT_DVOC 0x02 +#define DEVICE_CFG_24BIT_DVOBC 0x09 +#define DEVICE_CFG_24BIT_DVOCB 0x0a +#define DEVICE_CFG_DUAL_DVOB 0x11 +#define DEVICE_CFG_DUAL_DVOC 0x12 +#define DEVICE_CFG_DUAL_DVOBC 0x13 +#define DEVICE_CFG_DUAL_LINK_DVOBC 0x19 +#define DEVICE_CFG_DUAL_LINK_DVOCB 0x1a + +#define DEVICE_WIRE_NONE 0x00 +#define DEVICE_WIRE_DVOB 0x01 +#define DEVICE_WIRE_DVOC 0x02 +#define DEVICE_WIRE_DVOBC 0x03 +#define DEVICE_WIRE_DVOBB 0x05 +#define DEVICE_WIRE_DVOCC 0x06 +#define DEVICE_WIRE_DVOB_MASTER 0x0d +#define DEVICE_WIRE_DVOC_MASTER 0x0e + +#define DEVICE_PORT_DVOA 0x00 /* none on 845+ */ +#define DEVICE_PORT_DVOB 0x01 +#define DEVICE_PORT_DVOC 0x02 + +/* We used to keep this struct but without any version control. We should avoid + * using it in the future, but it should be safe to keep using it in the old + * code. */ +struct old_child_dev_config { + u16 handle; + u16 device_type; + u8 device_id[10]; /* ascii string */ + u16 addin_offset; + u8 dvo_port; /* See Device_PORT_* above */ + u8 i2c_pin; + u8 slave_addr; + u8 ddc_pin; + u16 edid_ptr; + u8 dvo_cfg; /* See DEVICE_CFG_* above */ + u8 dvo2_port; + u8 i2c2_pin; + u8 slave2_addr; + u8 ddc2_pin; + u8 capabilities; + u8 dvo_wiring;/* See DEVICE_WIRE_* above */ + u8 dvo2_wiring; + u16 extended_type; + u8 dvo_function; +} __attribute__((packed)); + +/* This one contains field offsets that are known to be common for all BDB + * versions. Notice that the meaning of the contents contents may still change, + * but at least the offsets are consistent. */ +struct common_child_dev_config { + u16 handle; + u16 device_type; + u8 not_common1[12]; + u8 dvo_port; + u8 not_common2[2]; + u8 ddc_pin; + u16 edid_ptr; +} __attribute__((packed)); + +/* This field changes depending on the BDB version, so the most reliable way to + * read it is by checking the BDB version and reading the raw pointer. */ +union child_device_config { + /* This one is safe to be used anywhere, but the code should still check + * the BDB version. */ + u8 raw[33]; + /* This one should only be kept for legacy code. */ + struct old_child_dev_config old; + /* This one should also be safe to use anywhere, even without version + * checks. */ + struct common_child_dev_config common; +}; + +struct bdb_general_definitions { + /* DDC GPIO */ + u8 crt_ddc_gmbus_pin; + + /* DPMS bits */ + u8 dpms_acpi:1; + u8 skip_boot_crt_detect:1; + u8 dpms_aim:1; + u8 rsvd1:5; /* finish byte */ + + /* boot device bits */ + u8 boot_display[2]; + u8 child_dev_size; + + /* + * Device info: + * If TV is present, it'll be at devices[0]. + * LVDS will be next, either devices[0] or [1], if present. + * On some platforms the number of device is 6. But could be as few as + * 4 if both TV and LVDS are missing. + * And the device num is related with the size of general definition + * block. It is obtained by using the following formula: + * number = (block_size - sizeof(bdb_general_definitions))/ + * sizeof(child_device_config); + */ + union child_device_config devices[0]; +} __attribute__((packed)); + +struct bdb_lvds_options { + u8 panel_type; + u8 rsvd1; + /* LVDS capabilities, stored in a dword */ + u8 pfit_mode:2; + u8 pfit_text_mode_enhanced:1; + u8 pfit_gfx_mode_enhanced:1; + u8 pfit_ratio_auto:1; + u8 pixel_dither:1; + u8 lvds_edid:1; + u8 rsvd2:1; + u8 rsvd4; +} __attribute__((packed)); + +/* LFP pointer table contains entries to the struct below */ +struct bdb_lvds_lfp_data_ptr { + u16 fp_timing_offset; /* offsets are from start of bdb */ + u8 fp_table_size; + u16 dvo_timing_offset; + u8 dvo_table_size; + u16 panel_pnp_id_offset; + u8 pnp_table_size; +} __attribute__((packed)); + +struct bdb_lvds_lfp_data_ptrs { + u8 lvds_entries; /* followed by one or more lvds_data_ptr structs */ + struct bdb_lvds_lfp_data_ptr ptr[16]; +} __attribute__((packed)); + +/* LFP data has 3 blocks per entry */ +struct lvds_fp_timing { + u16 x_res; + u16 y_res; + u32 lvds_reg; + u32 lvds_reg_val; + u32 pp_on_reg; + u32 pp_on_reg_val; + u32 pp_off_reg; + u32 pp_off_reg_val; + u32 pp_cycle_reg; + u32 pp_cycle_reg_val; + u32 pfit_reg; + u32 pfit_reg_val; + u16 terminator; +} __attribute__((packed)); + +struct lvds_dvo_timing { + u16 clock; /**< In 10khz */ + u8 hactive_lo; + u8 hblank_lo; + u8 hblank_hi:4; + u8 hactive_hi:4; + u8 vactive_lo; + u8 vblank_lo; + u8 vblank_hi:4; + u8 vactive_hi:4; + u8 hsync_off_lo; + u8 hsync_pulse_width; + u8 vsync_pulse_width:4; + u8 vsync_off:4; + u8 rsvd0:6; + u8 hsync_off_hi:2; + u8 h_image; + u8 v_image; + u8 max_hv; + u8 h_border; + u8 v_border; + u8 rsvd1:3; + u8 digital:2; + u8 vsync_positive:1; + u8 hsync_positive:1; + u8 rsvd2:1; +} __attribute__((packed)); + +struct lvds_pnp_id { + u16 mfg_name; + u16 product_code; + u32 serial; + u8 mfg_week; + u8 mfg_year; +} __attribute__((packed)); + +struct bdb_lvds_lfp_data_entry { + struct lvds_fp_timing fp_timing; + struct lvds_dvo_timing dvo_timing; + struct lvds_pnp_id pnp_id; +} __attribute__((packed)); + +struct bdb_lvds_lfp_data { + struct bdb_lvds_lfp_data_entry data[16]; +} __attribute__((packed)); + +struct aimdb_header { + char signature[16]; + char oem_device[20]; + u16 aimdb_version; + u16 aimdb_header_size; + u16 aimdb_size; +} __attribute__((packed)); + +struct aimdb_block { + u8 aimdb_id; + u16 aimdb_size; +} __attribute__((packed)); + +struct vch_panel_data { + u16 fp_timing_offset; + u8 fp_timing_size; + u16 dvo_timing_offset; + u8 dvo_timing_size; + u16 text_fitting_offset; + u8 text_fitting_size; + u16 graphics_fitting_offset; + u8 graphics_fitting_size; +} __attribute__((packed)); + +struct vch_bdb_22 { + struct aimdb_block aimdb_block; + struct vch_panel_data panels[16]; +} __attribute__((packed)); + +struct bdb_sdvo_lvds_options { + u8 panel_backlight; + u8 h40_set_panel_type; + u8 panel_type; + u8 ssc_clk_freq; + u16 als_low_trip; + u16 als_high_trip; + u8 sclalarcoeff_tab_row_num; + u8 sclalarcoeff_tab_row_size; + u8 coefficient[8]; + u8 panel_misc_bits_1; + u8 panel_misc_bits_2; + u8 panel_misc_bits_3; + u8 panel_misc_bits_4; +} __attribute__((packed)); + + +#define BDB_DRIVER_FEATURE_NO_LVDS 0 +#define BDB_DRIVER_FEATURE_INT_LVDS 1 +#define BDB_DRIVER_FEATURE_SDVO_LVDS 2 +#define BDB_DRIVER_FEATURE_EDP 3 + +struct bdb_driver_features { + u8 boot_dev_algorithm:1; + u8 block_display_switch:1; + u8 allow_display_switch:1; + u8 hotplug_dvo:1; + u8 dual_view_zoom:1; + u8 int15h_hook:1; + u8 sprite_in_clone:1; + u8 primary_lfp_id:1; + + u16 boot_mode_x; + u16 boot_mode_y; + u8 boot_mode_bpp; + u8 boot_mode_refresh; + + u16 enable_lfp_primary:1; + u16 selective_mode_pruning:1; + u16 dual_frequency:1; + u16 render_clock_freq:1; /* 0: high freq; 1: low freq */ + u16 nt_clone_support:1; + u16 power_scheme_ui:1; /* 0: CUI; 1: 3rd party */ + u16 sprite_display_assign:1; /* 0: secondary; 1: primary */ + u16 cui_aspect_scaling:1; + u16 preserve_aspect_ratio:1; + u16 sdvo_device_power_down:1; + u16 crt_hotplug:1; + u16 lvds_config:2; + u16 tv_hotplug:1; + u16 hdmi_config:2; + + u8 static_display:1; + u8 reserved2:7; + u16 legacy_crt_max_x; + u16 legacy_crt_max_y; + u8 legacy_crt_max_refresh; + + u8 hdmi_termination; + u8 custom_vbt_version; +} __attribute__((packed)); + +#define EDP_18BPP 0 +#define EDP_24BPP 1 +#define EDP_30BPP 2 +#define EDP_RATE_1_62 0 +#define EDP_RATE_2_7 1 +#define EDP_LANE_1 0 +#define EDP_LANE_2 1 +#define EDP_LANE_4 3 +#define EDP_PREEMPHASIS_NONE 0 +#define EDP_PREEMPHASIS_3_5dB 1 +#define EDP_PREEMPHASIS_6dB 2 +#define EDP_PREEMPHASIS_9_5dB 3 +#define EDP_VSWING_0_4V 0 +#define EDP_VSWING_0_6V 1 +#define EDP_VSWING_0_8V 2 +#define EDP_VSWING_1_2V 3 + +struct edp_power_seq { + u16 t1_t3; + u16 t8; + u16 t9; + u16 t10; + u16 t11_t12; +} __attribute__ ((packed)); + +struct edp_link_params { + u8 rate:4; + u8 lanes:4; + u8 preemphasis:4; + u8 vswing:4; +} __attribute__ ((packed)); + +struct bdb_edp { + struct edp_power_seq power_seqs[16]; + u32 color_depth; + struct edp_link_params link_params[16]; + u32 sdrrs_msa_timing_delay; + + /* ith bit indicates enabled/disabled for (i+1)th panel */ + u16 edp_s3d_feature; + u16 edp_t3_optimization; +} __attribute__ ((packed)); + +/* + * Driver<->VBIOS interaction occurs through scratch bits in + * GR18 & SWF*. + */ + +/* GR18 bits are set on display switch and hotkey events */ +#define GR18_DRIVER_SWITCH_EN (1<<7) /* 0: VBIOS control, 1: driver control */ +#define GR18_HOTKEY_MASK 0x78 /* See also SWF4 15:0 */ +#define GR18_HK_NONE (0x0<<3) +#define GR18_HK_LFP_STRETCH (0x1<<3) +#define GR18_HK_TOGGLE_DISP (0x2<<3) +#define GR18_HK_DISP_SWITCH (0x4<<3) /* see SWF14 15:0 for what to enable */ +#define GR18_HK_POPUP_DISABLED (0x6<<3) +#define GR18_HK_POPUP_ENABLED (0x7<<3) +#define GR18_HK_PFIT (0x8<<3) +#define GR18_HK_APM_CHANGE (0xa<<3) +#define GR18_HK_MULTIPLE (0xc<<3) +#define GR18_USER_INT_EN (1<<2) +#define GR18_A0000_FLUSH_EN (1<<1) +#define GR18_SMM_EN (1<<0) + +/* Set by driver, cleared by VBIOS */ +#define SWF00_YRES_SHIFT 16 +#define SWF00_XRES_SHIFT 0 +#define SWF00_RES_MASK 0xffff + +/* Set by VBIOS at boot time and driver at runtime */ +#define SWF01_TV2_FORMAT_SHIFT 8 +#define SWF01_TV1_FORMAT_SHIFT 0 +#define SWF01_TV_FORMAT_MASK 0xffff + +#define SWF10_VBIOS_BLC_I2C_EN (1<<29) +#define SWF10_GTT_OVERRIDE_EN (1<<28) +#define SWF10_LFP_DPMS_OVR (1<<27) /* override DPMS on display switch */ +#define SWF10_ACTIVE_TOGGLE_LIST_MASK (7<<24) +#define SWF10_OLD_TOGGLE 0x0 +#define SWF10_TOGGLE_LIST_1 0x1 +#define SWF10_TOGGLE_LIST_2 0x2 +#define SWF10_TOGGLE_LIST_3 0x3 +#define SWF10_TOGGLE_LIST_4 0x4 +#define SWF10_PANNING_EN (1<<23) +#define SWF10_DRIVER_LOADED (1<<22) +#define SWF10_EXTENDED_DESKTOP (1<<21) +#define SWF10_EXCLUSIVE_MODE (1<<20) +#define SWF10_OVERLAY_EN (1<<19) +#define SWF10_PLANEB_HOLDOFF (1<<18) +#define SWF10_PLANEA_HOLDOFF (1<<17) +#define SWF10_VGA_HOLDOFF (1<<16) +#define SWF10_ACTIVE_DISP_MASK 0xffff +#define SWF10_PIPEB_LFP2 (1<<15) +#define SWF10_PIPEB_EFP2 (1<<14) +#define SWF10_PIPEB_TV2 (1<<13) +#define SWF10_PIPEB_CRT2 (1<<12) +#define SWF10_PIPEB_LFP (1<<11) +#define SWF10_PIPEB_EFP (1<<10) +#define SWF10_PIPEB_TV (1<<9) +#define SWF10_PIPEB_CRT (1<<8) +#define SWF10_PIPEA_LFP2 (1<<7) +#define SWF10_PIPEA_EFP2 (1<<6) +#define SWF10_PIPEA_TV2 (1<<5) +#define SWF10_PIPEA_CRT2 (1<<4) +#define SWF10_PIPEA_LFP (1<<3) +#define SWF10_PIPEA_EFP (1<<2) +#define SWF10_PIPEA_TV (1<<1) +#define SWF10_PIPEA_CRT (1<<0) + +#define SWF11_MEMORY_SIZE_SHIFT 16 +#define SWF11_SV_TEST_EN (1<<15) +#define SWF11_IS_AGP (1<<14) +#define SWF11_DISPLAY_HOLDOFF (1<<13) +#define SWF11_DPMS_REDUCED (1<<12) +#define SWF11_IS_VBE_MODE (1<<11) +#define SWF11_PIPEB_ACCESS (1<<10) /* 0 here means pipe a */ +#define SWF11_DPMS_MASK 0x07 +#define SWF11_DPMS_OFF (1<<2) +#define SWF11_DPMS_SUSPEND (1<<1) +#define SWF11_DPMS_STANDBY (1<<0) +#define SWF11_DPMS_ON 0 + +#define SWF14_GFX_PFIT_EN (1<<31) +#define SWF14_TEXT_PFIT_EN (1<<30) +#define SWF14_LID_STATUS_CLOSED (1<<29) /* 0 here means open */ +#define SWF14_POPUP_EN (1<<28) +#define SWF14_DISPLAY_HOLDOFF (1<<27) +#define SWF14_DISP_DETECT_EN (1<<26) +#define SWF14_DOCKING_STATUS_DOCKED (1<<25) /* 0 here means undocked */ +#define SWF14_DRIVER_STATUS (1<<24) +#define SWF14_OS_TYPE_WIN9X (1<<23) +#define SWF14_OS_TYPE_WINNT (1<<22) +/* 21:19 rsvd */ +#define SWF14_PM_TYPE_MASK 0x00070000 +#define SWF14_PM_ACPI_VIDEO (0x4 << 16) +#define SWF14_PM_ACPI (0x3 << 16) +#define SWF14_PM_APM_12 (0x2 << 16) +#define SWF14_PM_APM_11 (0x1 << 16) +#define SWF14_HK_REQUEST_MASK 0x0000ffff /* see GR18 6:3 for event type */ + /* if GR18 indicates a display switch */ +#define SWF14_DS_PIPEB_LFP2_EN (1<<15) +#define SWF14_DS_PIPEB_EFP2_EN (1<<14) +#define SWF14_DS_PIPEB_TV2_EN (1<<13) +#define SWF14_DS_PIPEB_CRT2_EN (1<<12) +#define SWF14_DS_PIPEB_LFP_EN (1<<11) +#define SWF14_DS_PIPEB_EFP_EN (1<<10) +#define SWF14_DS_PIPEB_TV_EN (1<<9) +#define SWF14_DS_PIPEB_CRT_EN (1<<8) +#define SWF14_DS_PIPEA_LFP2_EN (1<<7) +#define SWF14_DS_PIPEA_EFP2_EN (1<<6) +#define SWF14_DS_PIPEA_TV2_EN (1<<5) +#define SWF14_DS_PIPEA_CRT2_EN (1<<4) +#define SWF14_DS_PIPEA_LFP_EN (1<<3) +#define SWF14_DS_PIPEA_EFP_EN (1<<2) +#define SWF14_DS_PIPEA_TV_EN (1<<1) +#define SWF14_DS_PIPEA_CRT_EN (1<<0) + /* if GR18 indicates a panel fitting request */ +#define SWF14_PFIT_EN (1<<0) /* 0 means disable */ + /* if GR18 indicates an APM change request */ +#define SWF14_APM_HIBERNATE 0x4 +#define SWF14_APM_SUSPEND 0x3 +#define SWF14_APM_STANDBY 0x1 +#define SWF14_APM_RESTORE 0x0 + +/* Add the device class for LFP, TV, HDMI */ +#define DEVICE_TYPE_INT_LFP 0x1022 +#define DEVICE_TYPE_INT_TV 0x1009 +#define DEVICE_TYPE_HDMI 0x60D2 +#define DEVICE_TYPE_DP 0x68C6 +#define DEVICE_TYPE_eDP 0x78C6 + +#define DEVICE_TYPE_CLASS_EXTENSION (1 << 15) +#define DEVICE_TYPE_POWER_MANAGEMENT (1 << 14) +#define DEVICE_TYPE_HOTPLUG_SIGNALING (1 << 13) +#define DEVICE_TYPE_INTERNAL_CONNECTOR (1 << 12) +#define DEVICE_TYPE_NOT_HDMI_OUTPUT (1 << 11) +#define DEVICE_TYPE_MIPI_OUTPUT (1 << 10) +#define DEVICE_TYPE_COMPOSITE_OUTPUT (1 << 9) +#define DEVICE_TYPE_DUAL_CHANNEL (1 << 8) +#define DEVICE_TYPE_HIGH_SPEED_LINK (1 << 6) +#define DEVICE_TYPE_LVDS_SINGALING (1 << 5) +#define DEVICE_TYPE_TMDS_DVI_SIGNALING (1 << 4) +#define DEVICE_TYPE_VIDEO_SIGNALING (1 << 3) +#define DEVICE_TYPE_DISPLAYPORT_OUTPUT (1 << 2) +#define DEVICE_TYPE_DIGITAL_OUTPUT (1 << 1) +#define DEVICE_TYPE_ANALOG_OUTPUT (1 << 0) + +/* + * Bits we care about when checking for DEVICE_TYPE_eDP + * Depending on the system, the other bits may or may not + * be set for eDP outputs. + */ +#define DEVICE_TYPE_eDP_BITS \ + (DEVICE_TYPE_INTERNAL_CONNECTOR | \ + DEVICE_TYPE_NOT_HDMI_OUTPUT | \ + DEVICE_TYPE_MIPI_OUTPUT | \ + DEVICE_TYPE_COMPOSITE_OUTPUT | \ + DEVICE_TYPE_DUAL_CHANNEL | \ + DEVICE_TYPE_LVDS_SINGALING | \ + DEVICE_TYPE_TMDS_DVI_SIGNALING | \ + DEVICE_TYPE_VIDEO_SIGNALING | \ + DEVICE_TYPE_DISPLAYPORT_OUTPUT | \ + DEVICE_TYPE_DIGITAL_OUTPUT | \ + DEVICE_TYPE_ANALOG_OUTPUT) + +/* define the DVO port for HDMI output type */ +#define DVO_B 1 +#define DVO_C 2 +#define DVO_D 3 + +/* define the PORT for DP output type */ +#define PORT_IDPB 7 +#define PORT_IDPC 8 +#define PORT_IDPD 9 + +/* Possible values for the "DVO Port" field for versions >= 155: */ +#define DVO_PORT_HDMIA 0 +#define DVO_PORT_HDMIB 1 +#define DVO_PORT_HDMIC 2 +#define DVO_PORT_HDMID 3 +#define DVO_PORT_LVDS 4 +#define DVO_PORT_TV 5 +#define DVO_PORT_CRT 6 +#define DVO_PORT_DPB 7 +#define DVO_PORT_DPC 8 +#define DVO_PORT_DPD 9 +#define DVO_PORT_DPA 10 + +/* MIPI DSI panel info */ +struct bdb_mipi { + u16 panel_id; + u16 bridge_revision; + + /* General params */ + u32 dithering:1; + u32 bpp_pixel_format:1; + u32 rsvd1:1; + u32 dphy_valid:1; + u32 resvd2:28; + + u16 port_info; + u16 rsvd3:2; + u16 num_lanes:2; + u16 rsvd4:12; + + /* DSI config */ + u16 virt_ch_num:2; + u16 vtm:2; + u16 rsvd5:12; + + u32 dsi_clock; + u32 bridge_ref_clk; + u16 rsvd_pwr; + + /* Dphy Params */ + u32 prepare_cnt:5; + u32 rsvd6:3; + u32 clk_zero_cnt:8; + u32 trail_cnt:5; + u32 rsvd7:3; + u32 exit_zero_cnt:6; + u32 rsvd8:2; + + u32 hl_switch_cnt; + u32 lp_byte_clk; + u32 clk_lane_switch_cnt; +} __attribute__((packed)); + +#endif /* _I830_BIOS_H_ */ diff --git a/src/northbridge/intel/sandybridge/gma.c b/src/northbridge/intel/sandybridge/gma.c index a82a284..fcd704f 100644 --- a/src/northbridge/intel/sandybridge/gma.c +++ b/src/northbridge/intel/sandybridge/gma.c @@ -21,6 +21,7 @@ #include <console/console.h> #include <bootmode.h> #include <delay.h> +#include <string.h> #include <device/device.h> #include <device/pci.h> #include <device/pci_ids.h> diff --git a/src/northbridge/intel/sandybridge/gma_ivybridge_lvds.c b/src/northbridge/intel/sandybridge/gma_ivybridge_lvds.c index 1f53a74..ff877ff 100644 --- a/src/northbridge/intel/sandybridge/gma_ivybridge_lvds.c +++ b/src/northbridge/intel/sandybridge/gma_ivybridge_lvds.c @@ -26,13 +26,64 @@ #include <drivers/intel/gma/edid.h> #include <drivers/intel/gma/i915.h> +#include <drivers/intel/gma/intel_bios.h> #include "gma.h" #include "chip.h" #include <pc80/vga.h> #include <pc80/vga_io.h> +#include <device/pci_def.h> +#include <device/pci_rom.h> #if IS_ENABLED(CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT) +static size_t generate_vbt(const struct northbridge_intel_sandybridge_config *conf, + void *vbt) +{ + struct vbt_header *head = vbt; + struct bdb_header *bdb_head; + struct bdb_general_features *genfeat; + u8 *ptr; + + memset(head, 0, sizeof (*head)); + + memcpy(head->signature, "$VBT SNB/IVB-MOBILE ", 20); + head->version = 100; + head->header_size = sizeof (*head); + head->bdb_offset = sizeof (*head); + + bdb_head = (struct bdb_header *) (head + 1); + memset(bdb_head, 0, sizeof (*bdb_head)); + memcpy(bdb_head->signature, "BIOS_DATA_BLOCK ", 16); + bdb_head->version = 0xa8; + bdb_head->header_size = sizeof (*bdb_head); + + ptr = (u8 *) (bdb_head + 1); + + ptr[0] = BDB_GENERAL_FEATURES; + ptr[1] = sizeof (*genfeat); + ptr[2] = sizeof (*genfeat) >> 8; + ptr += 3; + + genfeat = (struct bdb_general_features *) ptr; + memset(genfeat, 0, sizeof (*genfeat)); + genfeat->panel_fitting = 3; + genfeat->flexaim = 1; + genfeat->download_ext_vbt = 1; + genfeat->enable_ssc = conf->gpu_use_spread_spectrum_clock; + genfeat->ssc_freq = !conf->gpu_link_frequency_270_mhz; + genfeat->rsvd10 = 0x4; + genfeat->legacy_monitor_detect = 1; + genfeat->int_crt_support = 1; + genfeat->dp_ssc_enb = 1; + + ptr += sizeof (*genfeat); + + bdb_head->bdb_size = ptr - (u8 *)bdb_head; + head->vbt_size = ptr - (u8 *)head; + head->vbt_checksum = 0; + return ptr - (u8 *)head; +} + static void link_train(u32 mmio) { write32(mmio+0xf000c,0x40); @@ -509,6 +560,37 @@ int i915lightup(const struct northbridge_intel_sandybridge_config *info, memset ((void *) lfb, 0, edid.x_resolution * edid.y_resolution * 4); set_vbe_mode_info_valid(&edid, lfb); #endif + + /* Linux relies on VBT for panel info. */ + optionrom_header_t *oh = (void *)PCI_VGA_RAM_IMAGE_START; + optionrom_pcir_t *pcir; + size_t vbt_size; + size_t fake_oprom_size; + struct device *dev; + + dev = dev_find_slot(0, PCI_DEVFN(2, 0)); + + memset(oh, 0, 8192); + + oh->signature = OPROM_SIGNATURE; + oh->pcir_offset = 0x40; + oh->vbt_offset = 0x80; + + pcir = (void *)(PCI_VGA_RAM_IMAGE_START + 0x40); + pcir->signature = 0x52494350; // PCIR + pcir->vendor = dev->vendor; + pcir->device = dev->device; + pcir->length = sizeof(*pcir); + pcir->revision = dev->class; + pcir->classcode[0] = dev->class >> 8; + pcir->classcode[1] = dev->class >> 16; + pcir->classcode[2] = dev->class >> 24; + pcir->indicator = 0x80; + + vbt_size = generate_vbt (info, (void *)(PCI_VGA_RAM_IMAGE_START + 0x80)); + fake_oprom_size = (0x80 + vbt_size + 511) / 512; + oh->size = fake_oprom_size; + pcir->imagelength = fake_oprom_size; return 1; }
1
0
0
0
← Newer
1
...
10
11
12
13
14
15
16
...
87
Older →
Jump to page:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
Results per page:
10
25
50
100
200