/* * This file is part of the coreboot project. * * Copyright (C) 2006 Indrek Kruusa * Copyright (C) 2006 Ronald G. Minnich * Copyright (C) 2007 Advanced Micro Devices, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /************************************************************************** ;* ;* SetDelayControl ;* ;*************************************************************************/ #include "cpu/x86/msr.h" /** * Delay Control Settings table from AMD (MCP 0x4C00000F). */ static const msrinit_t delay_msr_table[] = { {CPU_BC_MSS_ARRAY_CTL0, {.hi = 0x00000000, .lo = 0x2814D352}}, {CPU_BC_MSS_ARRAY_CTL1, {.hi = 0x00000000, .lo = 0x1068334D}}, {CPU_BC_MSS_ARRAY_CTL2, {.hi = 0x00000106, .lo = 0x83104104}}, }; static const struct delay_controls { u8 dimms; u8 devices; u32 slow_hi; u32 slow_low; u32 fast_hi; u32 fast_low; } delay_control_table[] = { /* DIMMs Devs Slow (<=333MHz) Fast (>334MHz) */ { 1, 4, 0x0837100FF, 0x056960004, 0x0827100FF, 0x056960004 }, { 1, 8, 0x0837100AA, 0x056960004, 0x0827100AA, 0x056960004 }, { 1, 16, 0x0837100AA, 0x056960004, 0x082710055, 0x056960004 }, { 2, 8, 0x0837100A5, 0x056960004, 0x082710000, 0x056960004 }, { 2, 16, 0x0937100A5, 0x056960004, 0x0C27100A5, 0x056960004 }, { 2, 20, 0x0B37100A5, 0x056960004, 0x0B27100A5, 0x056960004 }, { 2, 24, 0x0B37100A5, 0x056960004, 0x0B27100A5, 0x056960004 }, { 2, 32, 0x0B37100A5, 0x056960004, 0x0B2710000, 0x056960004 }, }; /* * Bit 55 (disable SDCLK 1,3,5) should be set if there is a single DIMM * in slot 0, but it should be clear for all 2 DIMM settings and if a * single DIMM is in slot 1. Bits 54:52 should always be set to '111'. * * Settings for single DIMM and no VTT termination (like DB800 platform) * 0xF2F100FF 0x56960004 * ------------------------------------- * ADDR/CTL have 22 ohm series R * DQ/DQM/DQS have 33 ohm series R */ /** * This is Black Magic DRAM timing juju[1]. * * DRAM delay depends on CPU clock, memory bus clock, memory bus loading, * memory bus termination, your middle initial (ha! caught you!), GeodeLink * clock rate, and DRAM timing specifications. * * From this the code computes a number which is "known to work". No, * hardware is not an exact science. And, finally, if an FS2 (JTAG debugger) * is hooked up, then just don't do anything. This code was written by a master * of the Dark Arts at AMD and should not be modified in any way. * * [1] (http://www.thefreedictionary.com/juju) * * @param dimm0 The SMBus address of DIMM 0 (mainboard dependent). * @param dimm1 The SMBus address of DIMM 1 (mainboard dependent). * @param terminated The bus is terminated. (mainboard dependent). */ static void SetDelayControl(u8 dimm0, u8 dimm1, int terminated) { u32 glspeed; u8 spdbyte0, spdbyte1, dimms, i; msr_t msr; glspeed = GeodeLinkSpeed(); /* Fix delay controls for DM and IM arrays. */ for (i = 0; i < ARRAY_SIZE(delay_msr_table); i++) wrmsr(delay_msr_table[i].index, delay_msr_table[i].msr); msr = rdmsr(GLCP_FIFOCTL); msr.hi = 0x00000005; wrmsr(GLCP_FIFOCTL, msr); /* Enable setting. */ msr.hi = 0; msr.lo = 0x00000001; wrmsr(CPU_BC_MSS_ARRAY_CTL_ENA, msr); /* Debug Delay Control setup check. * Leave it alone if it has been setup. FS2 or something is here. */ msr = rdmsr(GLCP_DELAY_CONTROLS); if (msr.lo & ~(DELAY_LOWER_STATUS_MASK)) return; /* Delay Controls based on DIMM loading. UGH! * Number of devices = module width (SPD 6) / device width (SPD 13) * * physical banks (SPD 5) * * Note: We only support a module width of 64. */ dimms = 0; spdbyte0 = spd_read_byte(dimm0, SPD_PRIMARY_SDRAM_WIDTH); if (spdbyte0 != 0xFF) { dimms++; spdbyte0 = (u8)64 / spdbyte0 * (u8)(spd_read_byte(dimm0, SPD_NUM_DIMM_BANKS)); } else { spdbyte0 = 0; } spdbyte1 = spd_read_byte(dimm1, SPD_PRIMARY_SDRAM_WIDTH); if (spdbyte1 != 0xFF) { dimms++; spdbyte1 = (u8)64 / spdbyte1 * (u8)(spd_read_byte(dimm1, SPD_NUM_DIMM_BANKS)); } else { spdbyte1 = 0; } /* Zero GLCP_DELAY_CONTROLS MSR */ msr.hi = msr.lo = 0; /* Save some power, disable clock to second DIMM if it is empty. */ if (spdbyte1 == 0) msr.hi |= DELAY_UPPER_DISABLE_CLK135; spdbyte0 += spdbyte1; if ((dimms == 1) && (terminated == DRAM_TERMINATED)) { msr.hi = 0xF2F100FF; msr.lo = 0x56960004; } else for (i = 0; i < ARRAY_SIZE(delay_control_table); i++) { if ((dimms == delay_control_table[i].dimms) && (spdbyte0 <= delay_control_table[i].devices)) { if (glspeed < 334) { msr.hi |= delay_control_table[i].slow_hi; msr.lo |= delay_control_table[i].slow_low; } else { msr.hi |= delay_control_table[i].fast_hi; msr.lo |= delay_control_table[i].fast_low; } break; } } wrmsr(GLCP_DELAY_CONTROLS, msr); } /* ***************************************************************************/ /* * cpuRegInit*/ /* ***************************************************************************/ void cpuRegInit(int debug_clock_disable, u8 dimm0, u8 dimm1, int terminated) { int msrnum; msr_t msr; /* Castle 2.0 BTM periodic sync period. */ /* [40:37] 1 sync record per 256 bytes */ print_debug("Castle 2.0 BTM periodic sync period.\n"); msrnum = CPU_PF_CONF; msr = rdmsr(msrnum); msr.hi |= (0x8 << 5); wrmsr(msrnum, msr); /* * LX performance setting. * Enable Quack for fewer re-RAS on the MC */ print_debug("Enable Quack for fewer re-RAS on the MC\n"); msrnum = GLIU0_ARB; msr = rdmsr(msrnum); msr.hi &= ~ARB_UPPER_DACK_EN_SET; msr.hi |= ARB_UPPER_QUACK_EN_SET; wrmsr(msrnum, msr); msrnum = GLIU1_ARB; msr = rdmsr(msrnum); msr.hi &= ~ARB_UPPER_DACK_EN_SET; msr.hi |= ARB_UPPER_QUACK_EN_SET; wrmsr(msrnum, msr); /* GLIU port active enable, limit south pole masters * (AES and PCI) to one outstanding transaction. */ print_debug(" GLIU port active enable\n"); msrnum = GLIU1_PORT_ACTIVE; msr = rdmsr(msrnum); msr.lo &= ~0x880; wrmsr(msrnum, msr); /* Set the Delay Control in GLCP */ print_debug("Set the Delay Control in GLCP\n"); SetDelayControl(dimm0, dimm1, terminated); /* Enable RSDC */ print_debug("Enable RSDC\n"); msrnum = CPU_AC_SMM_CTL; msr = rdmsr(msrnum); msr.lo |= SMM_INST_EN_SET; wrmsr(msrnum, msr); /* FPU imprecise exceptions bit */ print_debug("FPU imprecise exceptions bit\n"); msrnum = CPU_FPU_MSR_MODE; msr = rdmsr(msrnum); msr.lo |= FPU_IE_SET; wrmsr(msrnum, msr); /* Power Savers (Do after BIST) */ /* Enable Suspend on HLT & PAUSE instructions */ print_debug("Enable Suspend on HLT & PAUSE instructions\n"); msrnum = CPU_XC_CONFIG; msr = rdmsr(msrnum); msr.lo |= XC_CONFIG_SUSP_ON_HLT | XC_CONFIG_SUSP_ON_PAUSE; wrmsr(msrnum, msr); /* Enable SUSP and allow TSC to run in Suspend (keep speed detection happy) */ print_debug("Enable SUSP and allow TSC to run in Suspend\n"); msrnum = CPU_BC_CONF_0; msr = rdmsr(msrnum); msr.lo |= TSC_SUSP_SET | SUSP_EN_SET; msr.lo &= 0x0F0FFFFFF; msr.lo |= 0x002000000; /* PBZ213: Set PAUSEDLY = 2 */ wrmsr(msrnum, msr); /* Disable the debug clock to save power. */ /* NOTE: leave it enabled for fs2 debug */ if (debug_clock_disable && 0) { msrnum = GLCP_DBGCLKCTL; msr.hi = 0; msr.lo = 0; wrmsr(msrnum, msr); } /* Setup throttling delays to proper mode if it is ever enabled. */ print_debug("Setup throttling delays to proper mode\n"); msrnum = GLCP_TH_OD; msr.hi = 0; msr.lo = 0x00000603C; wrmsr(msrnum, msr); print_debug("Done cpuRegInit\n"); }