diff options
Diffstat (limited to 'src/northbridge/intel/sandybridge/raminit.c')
-rw-r--r-- | src/northbridge/intel/sandybridge/raminit.c | 3516 |
1 files changed, 8 insertions, 3508 deletions
diff --git a/src/northbridge/intel/sandybridge/raminit.c b/src/northbridge/intel/sandybridge/raminit.c index 166416e287..1fdcb4f4f9 100644 --- a/src/northbridge/intel/sandybridge/raminit.c +++ b/src/northbridge/intel/sandybridge/raminit.c @@ -3,6 +3,7 @@ * * Copyright (C) 2014 Damien Zammit <damien@zamaudio.com> * Copyright (C) 2014 Vladimir Serbinenko <phcoder@gmail.com> + * Copyright (C) 2016 Patrick Rudolph <siro@das-labor.org> * * 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 @@ -20,197 +21,23 @@ #include <string.h> #include <arch/io.h> #include <cbmem.h> -#include <arch/cbfs.h> -#include <cbfs.h> #include <halt.h> -#include <ip_checksum.h> #include <timestamp.h> -#include <pc80/mc146818rtc.h> #include <northbridge/intel/common/mrc_cache.h> -#include <device/pci_def.h> -#include <memory_info.h> +#include <southbridge/intel/bd82x6x/me.h> +#include <southbridge/intel/bd82x6x/smbus.h> +#include <cpu/x86/msr.h> +#include <delay.h> #include <smbios.h> +#include <memory_info.h> +#include <lib.h> #include "raminit_native.h" +#include "raminit_common.h" #include "sandybridge.h" -#include <delay.h> -#include <lib.h> -#include <device/device.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" -#include <northbridge/intel/sandybridge/chip.h> /* FIXME: no ECC support. */ /* FIXME: no support for 3-channel chipsets. */ -/* - * Register description: - * Intel provides a command queue of depth four. - * Every command is configured by using multiple registers. - * On executing the command queue you have to provide the depth used. - * - * Known registers: - * Channel X = [0, 1] - * Command queue index Y = [0, 1, 2, 3] - * - * DEFAULT_MCHBAR + 0x4220 + 0x400 * X + 4 * Y: command io register - * Controls the DRAM command signals - * Bit 0: !RAS - * Bit 1: !CAS - * Bit 2: !WE - * - * DEFAULT_MCHBAR + 0x4200 + 0x400 * X + 4 * Y: addr bankslot io register - * Controls the address, bank address and slotrank signals - * Bit 0-15 : Address - * Bit 20-22: Bank Address - * Bit 24-25: slotrank - * - * DEFAULT_MCHBAR + 0x4230 + 0x400 * X + 4 * Y: idle register - * Controls the idle time after issuing this DRAM command - * Bit 16-32: number of clock-cycles to idle - * - * DEFAULT_MCHBAR + 0x4284 + 0x400 * channel: execute command queue - * Starts to execute all queued commands - * Bit 0 : start DRAM command execution - * Bit 16-20: (number of queued commands - 1) * 4 - */ - -#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 { - u16 spd_crc[NUM_CHANNELS][NUM_SLOTS]; - 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 cmd_stretch[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]; - - dimm_info info; -} 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 -#define MAX_CAS 18 -#define MIN_CAS 4 - -#define MAKE_ERR ((channel<<16)|(slotrank<<8)|1) -#define GET_ERR_CHANNEL(x) (x>>16) - -#define MC_BIOS_REQ 0x5e00 -#define MC_BIOS_DATA 0x5e04 - -static void program_timings(ramctr_timing * ctrl, int channel); -static unsigned int get_mmio_size(void); - static const char *ecc_decoder[] = { "inactive", "active on IO", @@ -233,20 +60,6 @@ static void wait_txt_clear(void) while (!(read8((void *)0xfed40000) & (1 << 7))); } -static void sfence(void) -{ - asm volatile ("sfence"); -} - -static void toggle_io_reset(void) { - /* toggle IO reset bit */ - u32 r32 = read32(DEFAULT_MCHBAR + 0x5030); - write32(DEFAULT_MCHBAR + 0x5030, r32 | 0x20); - udelay(1); - write32(DEFAULT_MCHBAR + 0x5030, r32 & ~0x20); - udelay(1); -} - /* * Disable a channel in ramctr_timing. */ @@ -464,73 +277,6 @@ static void dram_find_spds_ddr3(spd_raw_data *spd, ramctr_timing *ctrl) die("No DIMMs were found"); } -static void dram_find_common_params(ramctr_timing *ctrl) -{ - size_t valid_dimms; - int channel, slot; - dimm_info *dimms = &ctrl->info; - - ctrl->cas_supported = (1 << (MAX_CAS - MIN_CAS + 1)) - 1; - 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"); -} - -/* CAS write latency. To be programmed in MR2. - * See DDR3 SPEC for MR2 documentation. */ -static u8 get_CWL(u32 tCK) -{ - /* Get CWL based on tCK using the following rule: */ - switch (tCK) { - case TCK_1333MHZ: - return 12; - case TCK_1200MHZ: - case TCK_1100MHZ: - return 11; - case TCK_1066MHZ: - case TCK_1000MHZ: - return 10; - case TCK_933MHZ: - case TCK_900MHZ: - return 9; - case TCK_800MHZ: - case TCK_700MHZ: - return 8; - case TCK_666MHZ: - return 7; - case TCK_533MHZ: - return 6; - default: - return 5; - } -} - /* Frequency multiplier. */ static u32 get_FRQ(u32 tCK) { @@ -645,28 +391,6 @@ static u32 get_COMP2(u32 tCK) return frq_comp2_map[get_FRQ(tCK) - 3]; } -static u32 get_XOVER_CLK(u8 rankmap) -{ - return rankmap << 24; -} - -static u32 get_XOVER_CMD(u8 rankmap) -{ - u32 reg; - - // enable xover cmd - reg = 0x4000; - - // enable xover ctl - if (rankmap & 0x3) - reg |= 0x20000; - - if (rankmap & 0xc) - reg |= 0x4000000; - - return reg; -} - static void dram_timing(ramctr_timing * ctrl) { u8 val; @@ -874,393 +598,6 @@ static void dram_freq(ramctr_timing * ctrl) } } -static void dram_xover(ramctr_timing * ctrl) -{ - u32 reg; - int channel; - - FOR_ALL_CHANNELS { - // enable xover clk - reg = get_XOVER_CLK(ctrl->rankmap[channel]); - printram("XOVER CLK [%x] = %x\n", channel * 0x100 + 0xc14, - reg); - MCHBAR32(channel * 0x100 + 0xc14) = reg; - - // enable xover ctl & xover cmd - reg = get_XOVER_CMD(ctrl->rankmap[channel]); - printram("XOVER CMD [%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); - printram("DBP [%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); - printram("RAP [%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; - printram("OTHP [%x] = %x\n", addr, reg); - MCHBAR32(addr) = reg; - - MCHBAR32(0x400 * channel + 0x4014) = 0; - - MCHBAR32(addr) |= 0x00020000; - - // ODT stretch - reg = 0; - - cpures = cpuid(1); - cpu = cpures.eax; - if (IS_IVY_CPU(cpu) - || (IS_SANDY_CPU(cpu) && IS_SANDY_CPU_D2(cpu))) { - stretch = 2; - addr = 0x400 * channel + 0x400c; - printram("ODT stretch [%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); - - printram("ODT stretch [%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); - - printram("ODT stretch [%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); - printram("REFI [%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); - printram("SRFTP [%x] = %x\n", 0x400 * channel + 0x42a4, - reg); - MCHBAR32(0x400 * channel + 0x42a4) = reg; - } -} - -static void dram_dimm_mapping(ramctr_timing *ctrl) -{ - u32 reg, val32; - int channel; - dimm_info *info = &ctrl->info; - - 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); - } - // 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 = get_mmio_size(); - - 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 - printk(BIOS_DEBUG, "Update PCI-E configuration space:\n"); - - // 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(0, 0, 0)[%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(0, 0, 0)[%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(0, 0, 0)[%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(0, 0, 0)[%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(0, 0, 0)[%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(0, 0, 0)[%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(0, 0, 0)[%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(0, 0, 0)[%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(0, 0, 0)[%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(0, 0, 0)[%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(0, 0, 0)[%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(0, 0, 0)[%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; @@ -1311,2765 +648,12 @@ static void dram_ioregs(ramctr_timing * ctrl) printram("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; - - /* DRAM command ZQCS */ - 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, int channel) -{ - /* Get ODT based on rankmap: */ - int dimms_per_ch = (ctrl->rankmap[channel] & 1) - + ((ctrl->rankmap[channel] >> 2) & 1); - - if (dimms_per_ch == 1) { - return (const odtmap){60, 60}; - } else { - return (const odtmap){120, 30}; - } -} - -static void write_mrreg(ramctr_timing *ctrl, int channel, int slotrank, - int reg, u32 val) -{ - wait_428c(channel); - - if (ctrl->rank_mirror[channel][slotrank]) { - /* DDR3 Rank1 Address mirror - * swap the following pins: - * A3<->A4, A5<->A6, A7<->A8, BA0<->BA1 */ - reg = ((reg >> 1) & 1) | ((reg << 1) & 2); - val = (val & ~0x1f8) | ((val >> 1) & 0xa8) - | ((val & 0xa8) << 1); - } - - /* DRAM command MRS */ - 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); - - /* DRAM command MRS */ - 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); - - /* DRAM command MRS */ - 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 }; - - /* DLL Reset - self clearing - set after CLK frequency has been changed */ - 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) << 2); - mr0reg = (mr0reg & ~0x70) | ((mch_cas & 0xe) << 3); - mr0reg = (mr0reg & ~0xe00) | (mch_wr << 9); - - // Precharge PD - Fast (desktop) 0x1 or slow (mobile) 0x0 - mostly power-saving feature - mr0reg = (mr0reg & ~0x1000) | (!ctrl->mobile << 12); - return mr0reg; -} - -static void dram_mr0(ramctr_timing *ctrl, u8 rank, int channel) -{ - 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, int channel) -{ - odtmap odt; - u32 mr1reg; - - odt = get_ODT(ctrl, rank, channel); - mr1reg = 0x2; - - mr1reg |= encode_odt(odt.rttnom); - - return mr1reg; -} - -static void dram_mr1(ramctr_timing *ctrl, u8 rank, int channel) -{ - u16 mr1reg; - - mr1reg = make_mr1(ctrl, rank, channel); - - write_mrreg(ctrl, channel, rank, 1, mr1reg); -} - -static void dram_mr2(ramctr_timing *ctrl, u8 rank, int channel) -{ - u16 pasr, cwl, mr2reg; - odtmap odt; - int srt; - - pasr = 0; - cwl = ctrl->CWL - 5; - odt = get_ODT(ctrl, rank, channel); - - 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; - - write_mrreg(ctrl, channel, rank, 2, mr2reg); -} - -static void dram_mr3(ramctr_timing *ctrl, u8 rank, int channel) -{ - write_mrreg(ctrl, channel, rank, 3, 0); -} - -static void dram_mrscommands(ramctr_timing * ctrl) -{ - u8 slotrank; - u32 reg, addr; - int channel; - - FOR_ALL_POPULATED_CHANNELS { - FOR_ALL_POPULATED_RANKS { - // MR2 - dram_mr2(ctrl, slotrank, channel); - - // MR3 - dram_mr3(ctrl, slotrank, channel); - - // MR1 - dram_mr1(ctrl, slotrank, channel); - - // MR0 - dram_mr0(ctrl, slotrank, channel); - } - } - - /* DRAM command NOP */ - write32(DEFAULT_MCHBAR + 0x4e20, 0x7); - write32(DEFAULT_MCHBAR + 0x4e30, 0xf1001); - write32(DEFAULT_MCHBAR + 0x4e00, 0x60002); - write32(DEFAULT_MCHBAR + 0x4e10, 0); - - /* DRAM command ZQCL */ - write32(DEFAULT_MCHBAR + 0x4e24, 0x1f003); - write32(DEFAULT_MCHBAR + 0x4e34, 0x1901001); - write32(DEFAULT_MCHBAR + 0x4e04, 0x60400); - write32(DEFAULT_MCHBAR + 0x4e14, 0x288); - - /* execute command queue on all channels ? */ - 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); - - slotrank = (ctrl->rankmap[channel] & 1) ? 0 : 2; - - // Drain - wait_428c(channel); - - /* DRAM command ZQCS */ - write32(DEFAULT_MCHBAR + 0x4220 + 0x400 * channel, 0x0f003); - write32(DEFAULT_MCHBAR + 0x4230 + 0x400 * channel, 0x659001); - write32(DEFAULT_MCHBAR + 0x4200 + 0x400 * channel, - (slotrank << 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; - } - - /* enable CMD XOVER */ - reg32 = get_XOVER_CMD(ctrl->rankmap[channel]); - 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; - - /* enable CLK XOVER */ - reg_c14 = get_XOVER_CLK(ctrl->rankmap[channel]); - 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; - /* set CLK phase 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 + shift) << 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); - - /* DRAM command MRS - * write MR3 MPR enable - * in this mode only RD and RDA are allowed - * all reads return a predefined pattern */ - 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); - - /* DRAM command RD */ - 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); - - /* DRAM command RD */ - 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); - - /* DRAM command MRS - * write MR3 MPR disable */ - 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); - printram("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; - printram("Aval: %d, %d, %d: %x\n", channel, slotrank, - lane, ctrl->timings[channel][slotrank].lanes[lane].timA); - printram("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; - - printram("lane %d: %d, %d\n", lane, last_zero, - first_all); - - ctrl->timings[channel][slotrank].lanes[lane].timA = - (last_zero + first_all) / 2 + upperA[lane]; - printram("Aval: %d, %d, %d: %x\n", channel, slotrank, - lane, ctrl->timings[channel][slotrank].lanes[lane].timA); - } -} - -static int 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 0; - if (!some_works) { - if (ctrl->timings[channel][slotrank].val_4024 < 2) { - printk(BIOS_EMERG, "402x discovery failed (1): %d, %d\n", - channel, slotrank); - return MAKE_ERR; - } - ctrl->timings[channel][slotrank].val_4024 -= 2; - printram("4024 -= 2;\n"); - continue; - } - ctrl->timings[channel][slotrank].val_4028 += 2; - printram("4028 += 2;\n"); - if (ctrl->timings[channel][slotrank].val_4028 >= 0x10) { - printk(BIOS_EMERG, "402x discovery failed (2): %d, %d\n", - channel, slotrank); - return MAKE_ERR; - } - FOR_ALL_LANES if (works[lane]) { - ctrl->timings[channel][slotrank].lanes[lane].timA += - 128; - upperA[lane] += 128; - printram("increment %d, %d, %d\n", channel, - slotrank, lane); - } - } - return 0; -} - -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; - printram("4024 += %d;\n", shift_402x); - printram("4028 += %d;\n", shift_402x); -} - -/* Compensate the skew between DQS and DQs. - * To ease PCB design a small skew between Data Strobe signals and - * Data Signals is allowed. - * The controller has to measure and compensate this skew for every byte-lane. - * By delaying either all DQs signals or DQS signal, a full phase - * shift can be introduced. - * It is assumed that one byte-lane's DQs signals have the same routing delay. - * - * To measure the actual skew, the DRAM is placed in "read leveling" mode. - * In read leveling mode the DRAM-chip outputs an alternating periodic pattern. - * The memory controller iterates over all possible values to do a full phase shift - * and issues read commands. - * With DQS and DQs in phase the data read is expected to alternate on every byte: - * 0xFF 0x00 0xFF ... - * Once the controller has detected this pattern a bit in the result register is - * set for the current phase shift. - */ -static int read_training(ramctr_timing * ctrl) -{ - int channel, slotrank, lane; - int err; - - FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS { - int all_high, some_high; - int upperA[NUM_LANES]; - struct timA_minmax mnmx; - - wait_428c(channel); - - /* DRAM command PREA */ - 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--; - printram("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++; - printram("4024++;\n"); - printram("4028++;\n"); - } - - program_timings(ctrl, channel); - - pre_timA_change(ctrl, channel, slotrank, &mnmx); - - err = discover_402x(ctrl, channel, slotrank, upperA); - if (err) - return err; - - 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; - printram("4028 -= %d;\n", mnmx.timA_min_high); - - post_timA_change(ctrl, channel, slotrank, &mnmx); - - printram("4/8: %d, %d, %x, %x\n", channel, slotrank, - ctrl->timings[channel][slotrank].val_4024, - ctrl->timings[channel][slotrank].val_4028); - - printram("final results:\n"); - FOR_ALL_LANES - printram("Aval: %d, %d, %d: %x\n", channel, slotrank, - lane, - ctrl->timings[channel][slotrank].lanes[lane].timA); - - write32(DEFAULT_MCHBAR + 0x3400, 0); - - toggle_io_reset(); - } - - 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); - } - return 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); - - /* DRAM command ACT */ - 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); - - /* DRAM command NOP */ - 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); - - /* DRAM command WR */ - 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); - - /* DRAM command NOP */ - 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); - - /* DRAM command PREA */ - 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); - - /* DRAM command ACT */ - 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); - - /* DRAM command RD */ - 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); - - /* DRAM command PREA */ - 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 int discover_timC(ramctr_timing *ctrl, int channel, int slotrank) -{ - int timC; - int statistics[NUM_LANES][MAX_TIMC + 1]; - int lane; - - wait_428c(channel); - - /* DRAM command PREA */ - 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); - printram("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) { - printk(BIOS_EMERG, "timC discovery failed: %d, %d, %d\n", - channel, slotrank, lane); - return MAKE_ERR; - } - printram("Cval: %d, %d, %d: %x\n", channel, slotrank, - lane, ctrl->timings[channel][slotrank].lanes[lane].timC); - } - return 0; -} - -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; - for (j = 0; j < 16; j++) - write32((void *)(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((void *)(0x04000000 + channel_offset + j * 4), 0xffffffff); - for (j = 0; j < 16; j++) - write32((void *)(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); - - /* DRAM command MRS - * write MR3 MPR enable - * in this mode only RD and RDA are allowed - * all reads return a predefined pattern */ - 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); - - /* DRAM command RD */ - 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); - - /* DRAM command RD */ - 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); - - /* DRAM command MRS - * write MR3 MPR disable */ - 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); - /* DRAM command MRS - * write MR3 MPR enable - * in this mode only RD and RDA are allowed - * all reads return a predefined pattern */ - 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); - - /* DRAM command RD */ - 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); - - /* DRAM command RD */ - 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); - - /* DRAM command MRS - * write MR3 MPR disable */ - 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) -{ - /* enable DQs on this slotrank */ - write_mrreg(ctrl, channel, slotrank, 1, - 0x80 | make_mr1(ctrl, slotrank, channel)); - - wait_428c(channel); - /* DRAM command NOP */ - 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); - - /* DRAM command NOP */ - 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); - - /* disable DQs on this slotrank */ - write_mrreg(ctrl, channel, slotrank, 1, - 0x1080 | make_mr1(ctrl, slotrank, channel)); -} - -static int 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); - printram("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); - /* timC is a direct function of timB's 6 LSBs. - * Some tests increments the value of timB by a small value, - * which might cause the 6bit value to overflow, if it's close - * to 0x3F. Increment the value by a small offset if it's likely - * to overflow, to make sure it won't overflow while running - * tests and bricks the system due to a non matching timC. - * - * TODO: find out why some tests (edge write discovery) - * increment timB. */ - if ((rn.start & 0x3F) == 0x3E) - rn.start += 2; - else if ((rn.start & 0x3F) == 0x3F) - rn.start += 1; - ctrl->timings[channel][slotrank].lanes[lane].timB = rn.start; - if (rn.all) { - printk(BIOS_EMERG, "timB discovery failed: %d, %d, %d\n", - channel, slotrank, lane); - return MAKE_ERR; - } - printram("Bval: %d, %d, %d: %x\n", channel, slotrank, - lane, ctrl->timings[channel][slotrank].lanes[lane].timB); - } - return 0; -} - -static int get_timB_high_adjust(u64 val) -{ - int i; - - /* good */ - if (val == 0xffffffffffffffffLL) - return 0; - - if (val >= 0xf000000000000000LL) { - /* needs negative adjustment */ - for (i = 0; i < 8; i++) - if (val << (8 * (7 - i) + 4)) - return -i; - } else { - /* needs positive adjustment */ - 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, old; - 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); - - /* DRAM command ACT */ - 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); - - /* DRAM command NOP */ - 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); - - /* DRAM command WR */ - 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); - - /* DRAM command NOP */ - 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); - - /* DRAM command PREA */ - 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); - - /* DRAM command ACT */ - 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); - - /* DRAM command RD */ - 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; - old = ctrl->timings[channel][slotrank].lanes[lane].timB; - ctrl->timings[channel][slotrank].lanes[lane].timB += - get_timB_high_adjust(res) * 64; - - printram("High adjust %d:%016llx\n", lane, res); - printram("Bval+: %d, %d, %d, %x -> %x\n", channel, - slotrank, lane, old, - 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; - - /* DRAM command ACT */ - 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); -} - -/* Compensate the skew between CMD/ADDR/CLK and DQ/DQS lanes. - * DDR3 adopted the fly-by topology. The data and strobes signals reach - * the chips at different times with respect to command, address and - * clock signals. - * By delaying either all DQ/DQs or all CMD/ADDR/CLK signals, a full phase - * shift can be introduced. - * It is assumed that the CLK/ADDR/CMD signals have the same routing delay. - * - * To find the required phase shift the DRAM is placed in "write leveling" mode. - * In this mode the DRAM-chip samples the CLK on every DQS edge and feeds back the - * sampled value on the data lanes (DQs). - */ -static int write_training(ramctr_timing * ctrl) -{ - int channel, slotrank, lane; - int err; - - 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); - } - - /* refresh disable */ - write32(DEFAULT_MCHBAR + 0x5030, read32(DEFAULT_MCHBAR + 0x5030) & ~8); - FOR_ALL_POPULATED_CHANNELS { - write_op(ctrl, channel); - } - - /* enable write leveling on all ranks - * disable all DQ outputs - * only NOP is allowed in this mode */ - FOR_ALL_CHANNELS - FOR_ALL_POPULATED_RANKS - write_mrreg(ctrl, channel, slotrank, 1, - make_mr1(ctrl, slotrank, channel) | 0x1080); - - write32(DEFAULT_MCHBAR + 0x3400, 0x108052); - - toggle_io_reset(); - - /* set any valid value for timB, it gets corrected later */ - FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS { - err = discover_timB(ctrl, channel, slotrank); - if (err) - return err; - } - - /* disable write leveling on all ranks */ - FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS - write_mrreg(ctrl, channel, - slotrank, 1, make_mr1(ctrl, slotrank, channel)); - - write32(DEFAULT_MCHBAR + 0x3400, 0); - - FOR_ALL_POPULATED_CHANNELS - wait_428c(channel); - - /* refresh enable */ - 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); - - /* DRAM command ZQCS */ - 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); - } - - toggle_io_reset(); - - printram("CPE\n"); - precharge(ctrl); - printram("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 { - err = discover_timC(ctrl, channel, slotrank); - if (err) - return err; - } - - FOR_ALL_POPULATED_CHANNELS - program_timings(ctrl, channel); - - /* measure and adjust timB timings */ - 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); - } - return 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); - /* DRAM command ACT */ - 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); - /* DRAM command WR */ - 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); - - /* DRAM command RD */ - 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); - - /* DRAM command PRE */ - 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; - - printram("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((void *)(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((void *)(0x04000000 + channel_offset + i * channel_step + - j * 4), pattern[i][j]); - } - sfence(); - } -} - -static void reprogram_320c(ramctr_timing * ctrl) -{ - int channel, slotrank; - - FOR_ALL_POPULATED_CHANNELS { - wait_428c(channel); - - /* choose an existing rank. */ - slotrank = !(ctrl->rankmap[channel] & 1) ? 2 : 0; - - /* DRAM command ZQCS */ - 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); - } - - /* refresh disable */ - 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; - - /* DRAM command ZQCS */ - 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); - - toggle_io_reset(); -} - -#define MIN_C320C_LEN 13 - -static int try_cmd_stretch(ramctr_timing *ctrl, int channel, int cmd_stretch) -{ - struct ram_rank_timings saved_timings[NUM_CHANNELS][NUM_SLOTRANKS]; - int slotrank; - int c320c; - int stat[NUM_SLOTRANKS][256]; - int delta = 0; - - printram("Trying cmd_stretch %d on channel %d\n", cmd_stretch, channel); - - FOR_ALL_POPULATED_RANKS { - saved_timings[channel][slotrank] = - ctrl->timings[channel][slotrank]; - } - - ctrl->cmd_stretch[channel] = cmd_stretch; - - MCHBAR32(0x4004 + 0x400 * channel) = - ctrl->tRRD - | (ctrl->tRTP << 4) - | (ctrl->tCKE << 8) - | (ctrl->tWTR << 12) - | (ctrl->tFAW << 16) - | (ctrl->tWR << 24) - | (ctrl->cmd_stretch[channel] << 30); - - if (ctrl->cmd_stretch[channel] == 2) - delta = 2; - else if (ctrl->cmd_stretch[channel] == 0) - delta = 4; - - FOR_ALL_POPULATED_RANKS { - ctrl->timings[channel][slotrank].val_4024 -= delta; - } - - 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); - printram("3stat: %d, %d, %d: %x\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; - printram("3val: %d, %d: %d\n", channel, - slotrank, - ctrl->timings[channel][slotrank].val_320c); - if (rn.all || rn.length < MIN_C320C_LEN) { - FOR_ALL_POPULATED_RANKS { - ctrl->timings[channel][slotrank] = - saved_timings[channel][slotrank]; - } - return MAKE_ERR; - } - } - - return 0; -} - -/* Adjust CMD phase shift and try multiple command rates. - * A command rate of 2T doubles the time needed for address and - * command decode. */ -static int command_training(ramctr_timing *ctrl) -{ - int channel; - int err; - - FOR_ALL_POPULATED_CHANNELS { - fill_pattern5(ctrl, channel, 0); - write32(DEFAULT_MCHBAR + 0x4288 + 0x400 * channel, 0x1f); - } - - FOR_ALL_POPULATED_CHANNELS { - /* try command rate 1T and 2T */ - err = try_cmd_stretch(ctrl, channel, 0); - if (err) { - err = try_cmd_stretch(ctrl, channel, 2); - if (err) { - printk(BIOS_EMERG, "c320c discovery failed\n"); - return err; - } - printram("Using CMD rate 2T on channel %u\n", channel); - } else - printram("Using CMD rate 1T on channel %u\n", channel); - } - - FOR_ALL_POPULATED_CHANNELS - program_timings(ctrl, channel); - - reprogram_320c(ctrl); - return 0; -} - -static int 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; - } - 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); - /* DRAM command MRS - * write MR3 MPR enable - * in this mode only RD and RDA are allowed - * all reads return a predefined pattern */ - 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); - - /* DRAM command RD */ - 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); - - /* DRAM command RD */ - 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); - - /* DRAM command MRS - * MR3 disable MPR */ - 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) { - printk(BIOS_EMERG, "edge discovery failed: %d, %d, %d\n", - channel, slotrank, lane); - return MAKE_ERR; - } - printram("eval %d, %d, %d: %02x\n", channel, slotrank, - lane, edges[lane]); - } - return 0; -} - -static int 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; - int err; - - write32(DEFAULT_MCHBAR + 0x3400, 0); - - toggle_io_reset(); - - 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); - - /* DRAM command MRS - * MR3 enable MPR - * write MR3 MPR enable - * in this mode only RD and RDA are allowed - * all reads return a predefined pattern */ - 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); - - /* DRAM command RD */ - 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); - - /* DRAM command RD */ - 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); - - /* DRAM command MRS - * MR3 disable MPR */ - 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); - } - - /* XXX: check any measured value ? */ - - 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); - - /* DRAM command MRS - * MR3 enable MPR - * write MR3 MPR enable - * in this mode only RD and RDA are allowed - * all reads return a predefined pattern */ - 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); - - /* DRAM command RD */ - 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); - - /* DRAM command RD */ - 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); - - /* DRAM command MRS - * MR3 disable MPR */ - 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); - } - - /* XXX: check any measured value ? */ - - 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); - printram("discover falling edges:\n[%x] = %x\n", 0x4eb0, 0x300); - - FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS { - err = discover_edges_real(ctrl, channel, slotrank, - falling_edges[channel][slotrank]); - if (err) - return err; - } - - write32(DEFAULT_MCHBAR + 0x4eb0, 0x200); - printram("discover rising edges:\n[%x] = %x\n", 0x4eb0, 0x200); - - FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS { - err = discover_edges_real(ctrl, channel, slotrank, - rising_edges[channel][slotrank]); - if (err) - return err; - } - - 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); - } - return 0; -} - -static int 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); - printram("[%x] = 0x%08x\n", - 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); - printram("using pattern %d\n", pat); - 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); - - /* DRAM command ACT */ - 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); - - /* DRAM command WR */ - 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); - - /* DRAM command RD */ - 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); - - /* DRAM command PRE */ - 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); - printram("edges: %d, %d, %d: 0x%02x-0x%02x-0x%02x, 0x%02x-0x%02x\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; - if (rn.all || (lower[lane] > upper[lane])) { - printk(BIOS_EMERG, "edge write discovery failed: %d, %d, %d\n", - channel, slotrank, lane); - return MAKE_ERR; - } - } - } - } - - write32(DEFAULT_MCHBAR + 0x3000, 0); - printram("CPA\n"); - return 0; -} - -static int 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; - int err; - - /* FIXME: under some conditions (older chipsets?) vendor BIOS sets both edges to the same value. */ - write32(DEFAULT_MCHBAR + 0x4eb0, 0x300); - printram("discover falling edges write:\n[%x] = %x\n", 0x4eb0, 0x300); - - FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS { - err = discover_edges_write_real(ctrl, channel, slotrank, - falling_edges[channel][slotrank]); - if (err) - return err; - } - - write32(DEFAULT_MCHBAR + 0x4eb0, 0x200); - printram("discover rising edges write:\n[%x] = %x\n", 0x4eb0, 0x200); - - FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS { - err = discover_edges_write_real(ctrl, channel, slotrank, - rising_edges[channel][slotrank]); - if (err) - return err; - } - - 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); - } - return 0; -} - -static void test_timC_write(ramctr_timing *ctrl, int channel, int slotrank) -{ - wait_428c(channel); - /* DRAM command ACT */ - 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); - - /* DRAM command WR */ - 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); - - /* DRAM command RD */ - 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); - - /* DRAM command PRE */ - 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 int 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); - printram("discover timC write:\n"); - - 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]; - - /* Make sure rn.start < rn.end */ - statistics[MAX_TIMC] = 1; - - fill_pattern5(ctrl, channel, pat); - write32(DEFAULT_MCHBAR + 0x4288 + 0x400 * channel, 0x1f); - for (timC = 0; timC < MAX_TIMC; 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) { - printk(BIOS_EMERG, "timC write discovery failed: %d, %d, %d\n", - channel, slotrank, lane); - return MAKE_ERR; - } - printram("timC: %d, %d, %d: 0x%02x-0x%02x-0x%02x, 0x%02x-0x%02x\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); - - printram("CPB\n"); - - FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS FOR_ALL_LANES { - printram("timC %d, %d, %d: %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); - } - return 0; -} - -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, channel)); - } -} - -static int channel_test(ramctr_timing *ctrl) -{ - int channel, slotrank, lane; - - slotrank = 0; - FOR_ALL_POPULATED_CHANNELS - if (read32(DEFAULT_MCHBAR + 0x42a0 + (channel << 10)) & 0xa000) { - printk(BIOS_EMERG, "Mini channel test failed (1): %d\n", - channel); - return MAKE_ERR; - } - 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); - /* DRAM command ACT */ - 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); - /* DRAM command WR */ - 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); - /* DRAM command RD */ - 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); - /* DRAM command PRE */ - 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) + 4 * lane)) { - printk(BIOS_EMERG, "Mini channel test failed (2): %d, %d, %d\n", - channel, slotrank, lane); - return MAKE_ERR; - } - } - return 0; -} - -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(1); - 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) { /* Save the MRC S3 restore data to cbmem */ store_current_mrc_cache(ctrl, sizeof(*ctrl)); } -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->cmd_stretch[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); - } - - printram("CPE\n"); - - write32(DEFAULT_MCHBAR + 0x3400, 0); - write32(DEFAULT_MCHBAR + 0x4eb0, 0); - - printram("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); - - printram("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); -} - static int try_init_dram_ddr3(ramctr_timing *ctrl, int fast_boot, int s3_resume, int me_uma_size) { @@ -4343,90 +927,6 @@ static void init_dram_ddr3(int mobile, int min_tck, int s3resume) fill_smbios17(&ctrl); } -#define HOST_BRIDGE PCI_DEVFN(0, 0) -#define DEFAULT_TCK TCK_800MHZ - -static unsigned int get_mem_min_tck(void) -{ - u32 reg32; - u8 rev; - const struct device *dev; - const struct northbridge_intel_sandybridge_config *cfg = NULL; - - dev = dev_find_slot(0, HOST_BRIDGE); - if (dev) - cfg = dev->chip_info; - - /* If this is zero, it just means devicetree.cb didn't set it */ - if (!cfg || cfg->max_mem_clock_mhz == 0) { - rev = pci_read_config8(PCI_DEV(0, 0, 0), PCI_DEVICE_ID); - - if ((rev & BASE_REV_MASK) == BASE_REV_SNB) { - /* read Capabilities A Register DMFC bits */ - reg32 = pci_read_config32(PCI_DEV(0, 0, 0), CAPID0_A); - reg32 &= 0x7; - - switch (reg32) { - case 7: return TCK_533MHZ; - case 6: return TCK_666MHZ; - case 5: return TCK_800MHZ; - /* reserved: */ - default: - break; - } - } else { - /* read Capabilities B Register DMFC bits */ - reg32 = pci_read_config32(PCI_DEV(0, 0, 0), CAPID0_B); - reg32 = (reg32 >> 4) & 0x7; - - switch (reg32) { - case 7: return TCK_533MHZ; - case 6: return TCK_666MHZ; - case 5: return TCK_800MHZ; - case 4: return TCK_933MHZ; - case 3: return TCK_1066MHZ; - case 2: return TCK_1200MHZ; - case 1: return TCK_1333MHZ; - /* reserved: */ - default: - break; - } - } - return DEFAULT_TCK; - } else { - if (cfg->max_mem_clock_mhz >= 1066) - return TCK_1066MHZ; - else if (cfg->max_mem_clock_mhz >= 933) - return TCK_933MHZ; - else if (cfg->max_mem_clock_mhz >= 800) - return TCK_800MHZ; - else if (cfg->max_mem_clock_mhz >= 666) - return TCK_666MHZ; - else if (cfg->max_mem_clock_mhz >= 533) - return TCK_533MHZ; - else - return TCK_400MHZ; - } -} - -#define DEFAULT_PCI_MMIO_SIZE 2048 - -static unsigned int get_mmio_size(void) -{ - const struct device *dev; - const struct northbridge_intel_sandybridge_config *cfg = NULL; - - dev = dev_find_slot(0, HOST_BRIDGE); - if (dev) - cfg = dev->chip_info; - - /* If this is zero, it just means devicetree.cb didn't set it */ - if (!cfg || cfg->pci_mmio_size == 0) - return DEFAULT_PCI_MMIO_SIZE; - else - return cfg->pci_mmio_size; -} - void perform_raminit(int s3resume) { post_code(0x3a); |