From patchwork Sat Feb 12 18:53:49 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: searching volunteer to install coreboot on asus m4a78 pro Date: Sat, 12 Feb 2011 18:53:49 -0000 From: xdrudis X-Patchwork-Id: 2628 Message-Id: <20110212185349.GA7933@ideafix.casa.ct> To: coreboot@coreboot.org On Sat, Feb 12, 2011 at 10:32:54AM -0700, Marc Jones wrote: > On Sat, Feb 12, 2011 at 12:03 AM, xdrudis wrote: > ;;; > > >> * AMD Athlon II X4 615e support > > > > I have a Phenom II X4 910e > > Looks quite similar. Yours is revision RB_C3 also, I think? > > > > I found fidvid.c did not suppport this version and coreboot > > hanged while setting frequency and voltage of the CPU. > > I've apparently fixed it but I have a 1600 lines patch, > > and I really should see how to break it up in chunks that > > can be reasonably reviewed . In fact for fidvid.c itself > > the patch is bigger than the file. I hope I can do something > > this weekend to break into decent patches... > > It would be good to see this. The AMD BKDG has changed with regard to > the VID setup since the code was added. I think that dual PVI works > well, but SVI is suspect in my recent review of it. They two are not > as different as once indicated. > My board is SVI, and I've tried to bring it to comply a little more with Fam10 Bios and Kernel Development Guide #31116, rev 3.48, April 22, 2010 . I hope it's the correct version. There are still lots of FIXMEs, some paranoid checks and possibly some errors for any other hardware but mine. I even removed (with #if 0) a little code I couldn't make any sense with the documentation, I hope it doesn't break much. > The fid shouldn't require too much change. There are some features > that are not supported, but nothing that should prevent booting at > maxfid. > I basically found it only worked for revision B, but now I don't remember whether it was fid or vid. One of the hangs seemed to be the CPU refusing to go into a pstate out of limits and coreboot waiting infinetely for the CPU to get to that pstate. I also don't know how much of what I've changed was really necessary, at a certain point I just got tired of random changes and decided to implement as much of the BKDG as I could and try again. Maybe some thing are in BKDG but are not really necessary for booting. I'm attaching the monster. But I'm splitting it into many smaller patches, so it may be easier to read. So you may want to wait. > > > My board still doesn't boot though. It currently gets to > > ram stage and hangs while enabling pci devices. It's similar > > to a problem I found in romstage and I worked around it with > > a patch that wasn't probably the right approach (it wasn't commited). > > This time I'll have to see what's causing it (likely that I have > > an RX781, not an RS780, it's more or less the same without > > graphics, but I may have to tweak something somehow). > > This should be a matter of getting your lspci and the devicetree to > match up. If there is no graphics, you will need to remove that and > also look for any uma stuff that might be left around. > I tried to match lspci and devicetree.cb, but I may have got it wrong. I didn't know that uma could hang a pci read. It basically works for pci devices, but once it gets to where the external graphics card should be (00:02.0) it hangs there. src/southbridge/amd/rs780/rs780.c static u32 get_vid_did(device_t dev) I haven't looked much into it. I wanted to send the fidvid changes before I forget (more). Index: src/cpu/amd/model_10xxx/fidvid.c =================================================================== --- src/cpu/amd/model_10xxx/fidvid.c (revision 6323) +++ src/cpu/amd/model_10xxx/fidvid.c (working copy) @@ -16,8 +16,93 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +/* + * This file initializes the CPU cores for voltage and frequency settings + * in the different power states. + */ +/* +checklist (functions are in this file if no source file named) +Fam10 Bios and Kernel Development Guide #31116, rev 3.48, April 22, 2010 + +2.4.2.6 Requirements for p-states + +1.- F3x[84:80] According to table 100 : prep_fid_change + +2.- COF/VID : + 2.4.2.9.1 Steps 1,3-6 and warning for 2,7 if they apply + fixPsNbVidBeforeWR(...) + 2.4.2.9.1 Step 8 enable_fid_change + We do this for all nodes, I don't understand BKDG 100% on + whether this is or isn't meant by "on the local + processor". Must be OK. + 2.4.2.9.1 Steps 9-10 (repeat 1-7 and reset) romstage.c/init_cpus ? + 2.4.2.9.1 Steps 11-12 init_fidvid_stage2 + 2.4.2.9.2 DualPlane PVI : Not supported, don't know how to detect, + needs specific circuitry. + +3.- 2.4.2.7 dualPlaneOnly(dev) + +4.- 2.4.2.8 applyBoostFIDOffset(dev) + +5.- enableNbPState1(dev) + +6.- 2.4.1.7 + a) UpdateSinglePlaneNbVid() + b) setVSRamp(), called from prep_fid_change + c) prep_fid_change + d) improperly, for lack of voltage regulator details?, + F3xA0[PsiVidEn] in defaults.h + F3xA0[PsiVid] in init_cpus.c AMD_SetupPSIVID_d (before prep_fid_change) + +7.- TODO (Core Performance Boost is only available in revision E cpus, and we + don't seem to support those yet, at least they don't have any + constant in amddefs.h ) + +8.- FIXME ? Transition to min Pstate according to 2.4.2.15.3 is required + by 2.4.2.6 after warm reset. But 2.4.2.15 states that it is not required + if the warm reset is issued by coreboot to update NbFid. So it is required + or not ? How can I tell who issued warm reset ? + Coreboot transitions to P0 instead, which is not recommended, and does + not follow 2.4.2.15.2 to do so. + +9.- TODO Requires information on current delivery capability + (depends on mainboard and maybe power supply ?). One might use a config + option with the maximum number of Ampers that the board can deliver to CPU. + +10.- [Multiprocessor] TODO 2.4.2.12 + [Uniprocessor] FIXME ? We call setPStateMaxVal() in init_fidvid_stage2, + but not sure this is what is meant by "Determine the valid set of + P-states based on enabled P-states indicated + in MSRC001_00[68:64][PstateEn]" in 2.4.2.6-10 + +11.- finalPstateChange() from init_fidvid_Stage2 (BKDG says just "may", anyway) + +12.- generate ACPI for p-states. FIXME + Needs more assesment. There's some kind of fixed support that + does not seem to depend on CPU revision or actual MSRC001_00[68:64] + as BKDG apparently requires. + http://www.coreboot.org/ACPI#CPU_Power_Management + At least for Tilapia board: + src/mainboard///acpi_tables.c write_acpi_tables(...) calls + acpi_add_ssdt_pstates(...) + in /src/northbridge/amd/amdfam10/amdfam10_acpi.c + which apparently copies them from static info in + src/mainboard///acpi/cpstate.asl + +"must also be completed" + +a.- PllLockTime set in ruleset in defaults.h + BKDG says set it "If MSRC001_00[68:64][CpuFid] is different between + any two enabled P-states", but since it does not say "only if" + I guess it is safe to do it always. + +b.- prep_fid_change(...) + + */ + #if CONFIG_SET_FIDVID + #include static inline void print_debug_fv(const char *str, u32 val) @@ -62,10 +147,114 @@ static void enable_fid_change(u8 fid) dword |= 1 << 5; // enable pci_write_config32(dev, 0xd4, dword); printk(BIOS_DEBUG, "FID Change Node:%02x, F3xD4: %08x \n", i, - dword); + dword); } } +/* + * BKDG 2.4.2.6 point 5 + */ +static void enableNbPState1( device_t dev ) { + u32 cpuRev = mctGetLogicalCPUID(0xFF); + if (cpuRev & AMD_FAM10_C3) { + u32 nbPState = (pci_read_config32(dev, 0x1F0) & NB_PSTATE_MASK); + if ( nbPState){ + u32 nbVid1 = (pci_read_config32(dev, 0x1F4) & NB_VID1_MASK) >> NB_VID1_SHIFT; + u32 i; + for (i = nbPState; i < NM_PS_REG; i++) { + msr_t msr = rdmsr(PS_REG_BASE + i); + if (msr.hi & PS_EN_MASK ) { + msr.hi |= NB_DID_M_ON; + msr.lo &= NB_VID_MASK_OFF; + msr.lo |= ( nbVid1 << NB_VID_POS); + wrmsr(PS_REG_BASE + i, msr); + } + } + } + } +} + + +static u8 setPStateMaxVal( device_t dev ) { + u8 i,maxpstate=0; + for (i = 0; i < NM_PS_REG; i++) { + msr_t msr = rdmsr(PS_REG_BASE + i); + if (msr.hi & PS_IDD_VALUE_MASK) { + msr.hi |= PS_EN_MASK ; + wrmsr(PS_REG_BASE + i, msr); + } + if (msr.hi | PS_EN_MASK) { + maxpstate = i; + } + } + //FIXME: CPTC2 and HTC_REG should get max per node, not per core ? + u32 reg = pci_read_config32(dev, CPTC2); + reg &= PS_MAX_VAL_MASK; + reg |= (maxpstate << PS_MAX_VAL_POS); + pci_write_config32(dev, CPTC2,reg); + return maxpstate; +} + +static void dualPlaneOnly( device_t dev ) { + // BKDG 2.4.2.7 + + u32 cpuRev = mctGetLogicalCPUID(0xFF); + if ((mctGetProcessorPackageType() == AMD_PKGTYPE_AM3_2r2) + && (cpuRev & AMD_DR_Cx)) { // should be rev C or rev E but there's no constant for E + if ( (pci_read_config32(dev, 0x1FC) & DUAL_PLANE_ONLY_MASK) + && (pci_read_config32(dev, 0xA0) & PVI_MODE) ){ + if (cpuid_edx(0x80000007) & CPB_MASK) { + msr_t minPstate = rdmsr(0xC0010065); + wrmsr(0xC0010065, rdmsr(0xC0010068) ); + wrmsr(0xC0010068,minPstate); + } else { + msr_t msr; + msr.lo=0; msr.hi=0; + wrmsr(0xC0010064, rdmsr(0xC0010068) ); + wrmsr(0xC0010068, msr ); + } + + //FIXME: CPTC2 and HTC_REG should get max per node, not per core ? + u8 maxpstate = setPStateMaxVal(dev); + + u32 reg = pci_read_config32(dev, HTC_REG); + reg &= HTC_PS_LMT_MASK; + reg |= (maxpstate << PS_LIMIT_POS); + pci_write_config32(dev, HTC_REG,reg); + + } + } +} + +static void applyBoostFIDOffset( device_t dev ) { + // BKDG 2.4.2.8 + // revision E only, but E is apparently not supported yet, therefore untested + if ((cpuid_edx(0x80000007) & CPB_MASK) + && ((cpuid_ecx(0x80000008) & NC_MASK) ==5) ) { + u32 core = get_node_core_id_x().coreid; + u32 asymetricBoostThisCore = ((pci_read_config32(dev, 0x10C) >> (core*2))) & 3; + msr_t msr = rdmsr(PS_REG_BASE); + u32 cpuFid = msr.lo & PS_CPU_FID_MASK; + cpuFid = cpuFid + asymetricBoostThisCore; + msr.lo &= ~PS_CPU_FID_MASK; + msr.lo |= cpuFid ; + wrmsr(PS_REG_BASE , msr); + + } +} + +static int vidTo100uV(u8 vid) +{// returns voltage corresponding to vid in tenths of mV, i.e. hundreds of uV + // BKDG #31116 rev 3.48 2.4.1.6 + int voltage; + if (vid >= 0x7c) { + voltage = 0; + } else { + voltage = (15500 - (125*vid)); + } + return voltage; +} + static void recalculateVsSlamTimeSettingOnCorePre(device_t dev) { u8 pviModeFlag; @@ -77,12 +266,14 @@ static void recalculateVsSlamTimeSettingOnCorePre( /* This function calculates the VsSlamTime using the range of possible * voltages instead of a hardcoded 200us. - * Note:This function is called from setFidVidRegs and setUserPs after - * programming a custom Pstate. + * Note: his function is called only from prep_fid_change, + * and that from init_cpus.c finalize_node_setup() + * (after set AMD MSRs and init ht ) */ - + + /* BKDG r31116 2010-04-22 2.4.1.7 step b F3xD8[VSSlamTime] */ /* Calculate Slam Time - * Vslam = 0.4us/mV * Vp0 - (lowest out of Vpmin or Valt) + * Vslam = (mobileCPU?0.2:0.4)us/mV * (Vp0 - (lowest out of Vpmin or Valt)) mV * In our case, we will scale the values by 100 to avoid * decimals. */ @@ -95,10 +286,19 @@ static void recalculateVsSlamTimeSettingOnCorePre( else pviModeFlag = 0; - /* Get P0's voltage */ + /* Get P0's voltage */ + /* MSRC001_00[68:64] are not programmed yet when called from + prep_fid_change, one might use F4x1[F0:E0] instead, but + theoretically MSRC001_00[68:64] are equal to them after + reset. */ msr = rdmsr(0xC0010064); highVoltageVid = (u8) ((msr.lo >> PS_CPU_VID_SHFT) & 0x7F); - + printk(BIOS_DEBUG,"MSRC001_0064 = %08x,%08x \n",msr.hi,msr.lo); + if (!(msr.hi & 0x80000000)) { + printk(BIOS_ERR,"P-state info in MSRC001_0064 is invalid !!!\n"); + highVoltageVid = (u8) ((pci_read_config32(dev, 0x1E0) + >> PS_CPU_VID_SHFT) & 0x7F); + } /* If SVI, we only care about CPU VID. * If PVI, determine the higher voltage b/t NB and CPU */ @@ -108,16 +308,22 @@ static void recalculateVsSlamTimeSettingOnCorePre( highVoltageVid = bValue; } - /* Get Pmin's index */ + /* Get PSmax's index */ msr = rdmsr(0xC0010061); - bValue = (u8) ((msr.lo >> PS_CUR_LIM_SHFT) & BIT_MASK_3); - - /* Get Pmin's VID */ + bValue = (u8) ((msr.lo >> PS_MAX_VAL_SHFT) & BIT_MASK_3); + + /* Get PSmax's VID */ msr = rdmsr(0xC0010064 + bValue); lowVoltageVid = (u8) ((msr.lo >> PS_CPU_VID_SHFT) & 0x7F); + if (!(msr.hi & 0x80000000)) { + printk(BIOS_ERR,"P-state info in MSR%8x is invalid !!!\n",0xC0010064 + bValue); + lowVoltageVid = (u8) ((pci_read_config32(dev, 0x1E0+(bValue*4)) + >> PS_CPU_VID_SHFT) & 0x7F); + } /* If SVI, we only care about CPU VID. * If PVI, determine the higher voltage b/t NB and CPU + * BKDG 2.4.1.7 (a) */ if (pviModeFlag) { bValue = (u8) ((msr.lo >> PS_NB_VID_SHFT) & 0x7F); @@ -133,21 +339,10 @@ static void recalculateVsSlamTimeSettingOnCorePre( if (lowVoltageVid < bValue) lowVoltageVid = bValue; - /* If Vids are 7Dh - 7Fh, force 7Ch to keep calculations linear */ - if (lowVoltageVid > 0x7C) { - lowVoltageVid = 0x7C; - if (highVoltageVid > 0x7C) - highVoltageVid = 0x7C; - } - bValue = (u8) (lowVoltageVid - highVoltageVid); + u8 mobileFlag = get_platform_type() & AMD_PTYPE_MOB; + minimumSlamTime = (mobileFlag?2:4) * (vidTo100uV(highVoltageVid) - vidTo100uV(lowVoltageVid)); /* * 0.01 us */ - /* Each Vid increment is 12.5 mV. The minimum slam time is: - * vidCodeDelta * 12.5mV * 0.4us/mV - * Scale by 100 to avoid decimals. - */ - minimumSlamTime = bValue * (125 * 4); - /* Now round up to nearest register setting. * Note that if we don't find a value, we * will fall through to a value of 7 @@ -164,58 +359,73 @@ static void recalculateVsSlamTimeSettingOnCorePre( pci_write_config32(dev, 0xd8, dtemp); } -static void prep_fid_change(void) -{ - u32 dword, dtemp; - u32 nodes; - device_t dev; - int i; - - /* This needs to be run before any Pstate changes are requested */ - - nodes = get_nodes(); - - for (i = 0; i < nodes; i++) { - printk(BIOS_DEBUG, "Prep FID/VID Node:%02x \n", i); - dev = NODE_PCI(i, 3); - +static void setVSRamp(device_t dev) { + /* BKDG r31116 2010-04-22 2.4.1.7 step b F3xD8[VSRampTime] + * If this field accepts 8 values between 10 and 500 us why + * does page 324 say "BIOS should set this field to 001b." + * (20 us) ? + * Shouldn't it depend on the voltage regulators, mainboard + * or something ? + */ + u32 dword; dword = pci_read_config32(dev, 0xd8); dword &= VSRAMP_MASK; dword |= VSRAMP_VALUE; pci_write_config32(dev, 0xd8, dword); +} - /* Figure out the value for VsSlamTime and program it */ - recalculateVsSlamTimeSettingOnCorePre(dev); +static u32 nb_clk_did(int node, u32 cpuRev,u8 procPkg) { + u8 link0isGen3 = 0; + u8 offset; + if (AMD_CpuFindCapability(node, 0, &offset)) { + link0isGen3 = (AMD_checkLinkType(node, 0, offset) & HTPHY_LINKTYPE_HT3 ); + } + /* FIXME: NB_CLKDID should be 101b for AMD_DA_C2 in package + S1g3 in link Gen3 mode, but I don't know how to tell + package S1g3 from S1g4 */ + if ((cpuRev & AMD_DA_C2) && (procPkg & AMD_PKGTYPE_S1gX) + && link0isGen3) { + return 5 ; /* divide clk by 128*/ + } else { + return 4 ; /* divide clk by 16 */ + } +} - /* Program fields in Clock Power/Control register0 (F3xD4) */ - /* set F3xD4 Clock Power/Timing Control 0 Register - * NbClkDidApplyAll=1b - * NbClkDid=100b - * PowerStepUp= "platform dependent" - * PowerStepDown= "platform dependent" - * LinkPllLink=01b - * ClkRampHystSel=HW default - */ - /* check platform type */ - if (!(get_platform_type() & AMD_PTYPE_SVR)) { - /* For non-server platform +static u32 power_up_down(int node, u8 procPkg) { + u32 dword=0; + /* from CPU rev guide #41322 rev 3.74 June 2010 Table 26 */ + u8 singleLinkFlag = ((procPkg == AMD_PKGTYPE_AM3_2r2) + || (procPkg == AMD_PKGTYPE_S1gX) + || (procPkg == AMD_PKGTYPE_ASB2)); + + if (singleLinkFlag) { + /* * PowerStepUp=01000b - 50nS * PowerStepDown=01000b - 50ns */ - dword = pci_read_config32(dev, 0xd4); - dword &= CPTC0_MASK; - dword |= NB_CLKDID_ALL | NB_CLKDID | PW_STP_UP50 | PW_STP_DN50 | LNK_PLL_LOCK; /* per BKDG */ - pci_write_config32(dev, 0xd4, dword); + dword |= PW_STP_UP50 | PW_STP_DN50; } else { - dword = pci_read_config32(dev, 0xd4); - dword &= CPTC0_MASK; + u32 dispRefModeEn = (pci_read_config32(NODE_PCI(node,0),0x68) >> 24) & 1; + u32 isocEn = 0; + int j; + for(j=0 ; (j<4) && (!isocEn) ; j++ ) { + u8 offset; + if (AMD_CpuFindCapability(node, j, &offset)) { + isocEn = (pci_read_config32(NODE_PCI(node,0),offset+4) >>12) & 1; + } + + } + + if (dispRefModeEn || isocEn) { + dword |= PW_STP_UP50 | PW_STP_DN50; + } else { /* get number of cores for PowerStepUp & PowerStepDown in server 1 core - 400nS - 0000b 2 cores - 200nS - 0010b 3 cores - 133nS -> 100nS - 0011b 4 cores - 100nS - 0011b */ - switch (get_core_num_in_bsp(i)) { + switch (get_core_num_in_bsp(node)) { case 0: dword |= PW_STP_UP400 | PW_STP_DN400; break; @@ -230,61 +440,194 @@ static void recalculateVsSlamTimeSettingOnCorePre( dword |= PW_STP_UP100 | PW_STP_DN100; break; } - dword |= NB_CLKDID_ALL | NB_CLKDID | LNK_PLL_LOCK; - pci_write_config32(dev, 0xd4, dword); + } + } + return dword; +} - /* check PVI/SVI */ - dword = pci_read_config32(dev, 0xA0); - if (dword & PVI_MODE) { /* PVI */ +static void config_clk_power_ctrl_reg0(int node, u32 cpuRev, u8 procPkg) { + + device_t dev = NODE_PCI(node, 3); + + /* Program fields in Clock Power/Control register0 (F3xD4) */ + /* set F3xD4 Clock Power/Timing Control 0 Register + * NbClkDidApplyAll=1b + * NbClkDid=100b or 101b + * PowerStepUp= "platform dependent" + * PowerStepDown= "platform dependent" + * LinkPllLink=01b + * ClkRampHystCtl=HW default + * ClkRampHystSel=1111b + */ + /* check platform type */ + u32 dword = pci_read_config32(dev, 0xd4); + dword &= CPTC0_MASK; + + dword |= NB_CLKDID_ALL | LNK_PLL_LOCK | CLK_RAMP_HYST_SEL_VAL; + dword |= (nb_clk_did(node,cpuRev,procPkg) << NB_CLKDID_SHIFT); + + dword |= power_up_down(node,procPkg); + + pci_write_config32(dev, 0xd4, dword); +} + +static void config_power_ctrl_misc_reg(device_t dev,u32 cpuRev, u8 procPkg) { /* check PVI/SVI */ + u32 dword = pci_read_config32(dev, 0xA0); + int pviFlag = (dword & PVI_MODE) ; + + /* BKDG r31116 2010-04-22 2.4.1.7 step b F3xA0[VSSlamVidMod] */ + if (pviFlag) { /* PVI */ /* set slamVidMode to 0 for PVI */ - dword &= VID_SLAM_OFF | PLLLOCK_OFF; - dword |= PLLLOCK_DFT_L; - pci_write_config32(dev, 0xA0, dword); + dword &= VID_SLAM_OFF ; } else { /* SVI */ /* set slamVidMode to 1 for SVI */ - dword &= PLLLOCK_OFF; - dword |= PLLLOCK_DFT_L | VID_SLAM_ON; - pci_write_config32(dev, 0xA0, dword); + dword |= VID_SLAM_ON; + } + /* set the rest of A0 since we're at it... */ + + if (cpuRev & (AMD_DA_Cx | AMD_RB_C3 )) { + dword |= NB_PSTATE_FORCE_ON; + } // else should we clear it ? - dtemp = dword; - /* Program F3xD8[PwrPlanes] according F3xA0[DulaVdd] */ - dword = pci_read_config32(dev, 0xD8); + if ((procPkg == AMD_PKGTYPE_G34) || (procPkg == AMD_PKGTYPE_C32) ) { + dword |= BP_INS_TRI_EN_ON ; + } - if (dtemp & DUAL_VDD_BIT) - dword |= PWR_PLN_ON; - else - dword &= PWR_PLN_OFF; - pci_write_config32(dev, 0xD8, dword); + // PllLockTime and PsiVidEn set in ruleset in defaults.h + + /* TODO: look into C1E state and F3xA0[IdleExitEn]*/ + #if CONFIG_SVI_HIGH_FREQ + if (cpuRev & AMD_FAM10_C3) { + dword |= SVI_HIGH_FREQ_ON; } + #endif + pci_write_config32(dev, 0xA0, dword); +} +static void config_nb_syn_ptr_adj(device_t dev,u32 cpuRev) { /* Note the following settings are additional from the ported * function setFidVidRegs() */ - dword = pci_read_config32(dev, 0xDc); - dword |= 0x5 << 12; /* NbsynPtrAdj set to 0x5 per BKDG (needs reset) */ + /* adjust FIFO between nb and core clocks to max allowed + values (min latency) */ + u32 nbPstate = pci_read_config32(dev,0x1f0) & NB_PSTATE_MASK; + u8 nbSynPtrAdj; + if ((cpuRev & (AMD_DR_Bx|AMD_DA_Cx) ) + || ( (cpuRev & AMD_RB_C3) && (nbPstate!=0))) { + nbSynPtrAdj = 5; + } else { + nbSynPtrAdj = 6; + } + + u32 dword = pci_read_config32(dev, 0xDc); + dword &= ~ NB_SYN_PTR_ADJ_MASK; + dword |= nbSynPtrAdj << NB_SYN_PTR_ADJ_POS; /* NbsynPtrAdj set to 5 or 6 per BKDG (needs reset) */ pci_write_config32(dev, 0xdc, dword); +} - /* Rev B settings - FIXME: support other revs. */ - dword = 0xA0E641E6; +static void config_acpi_pwr_state_ctrl_regs(device_t dev, u32 cpuRev, u8 procPkg) { + /* step 1, chapter 2.4.2.6 of AMD Fam 10 BKDG #31116 Rev 3.48 22.4.2010 */ + u32 dword; + u32 c1= 1; + if (cpuRev & (AMD_DR_Bx)) { + // will coreboot ever enable cache scrubbing ? + // if it does, will it be enough to check the current state + // or should we configure for what we'll set up later ? + dword = pci_read_config32(dev, 0x58); + u32 scrubbingCache = dword & + ( (0x1F << 16) // DCacheScrub + | (0x1F << 8) ); // L2Scrub + if (scrubbingCache) { + c1 = 0x80; + } else { + c1 = 0xA0; + } + } else { // rev C or later + // same doubt as cache scrubbing: ok to check current state ? + dword = pci_read_config32(dev, 0xDC); + u32 cacheFlushOnHalt = dword & (7 << 16); + if (!cacheFlushOnHalt) { + c1 = 0x80; + } + } + dword = (c1 << 24) | (0xE641E6); pci_write_config32(dev, 0x84, dword); - dword = 0xE600A681; + + /* FIXME: BKDG Table 100 says if the link is at a Gen1 +frequency and the chipset does not support a 10us minimum LDTSTOP +assertion time, then { If ASB2 && SVI then smaf001 = F6h else +smaf001=87h. } else ... I hardly know what it means or how to check +it from here, so I bluntly assume it is false and code here the else, +which is easier */ + + u32 smaf001 = 0xE6; + if (cpuRev & AMD_DR_Bx ) { + smaf001 = 0xA6; + } else { + #if CONFIG_SVI_HIGH_FREQ + if (cpuRev & (AMD_RB_C3 | AMD_DA_C3)) { + smaf001 = 0xF6; + } + #endif + } + u32 fidvidChange = 0; + if (((cpuRev & AMD_DA_Cx) && (procPkg & AMD_PKGTYPE_S1gX)) + || (cpuRev & AMD_RB_C3) ) { + fidvidChange=0x0B; + } + dword = (0xE6 << 24) | (fidvidChange << 16) + | (smaf001 << 8) | 0x81; pci_write_config32(dev, 0x80, dword); +} - dword = pci_read_config32(dev, 0x80); - printk(BIOS_DEBUG, " F3x80: %08x \n", dword); - dword = pci_read_config32(dev, 0x84); - printk(BIOS_DEBUG, " F3x84: %08x \n", dword); - dword = pci_read_config32(dev, 0xD4); - printk(BIOS_DEBUG, " F3xD4: %08x \n", dword); +static void prep_fid_change(void) +{ + u32 nodes; + device_t dev; + int i; + + /* This needs to be run before any Pstate changes are requested */ + + nodes = get_nodes(); + + for (i = 0; i < nodes; i++) { + printk(BIOS_DEBUG, "Prep FID/VID Node:%02x \n", i); + + dev = NODE_PCI(i, 3); + + setVSRamp(dev); + /* BKDG r31116 2010-04-22 2.4.1.7 step b F3xD8[VSSlamTime] */ + /* Figure out the value for VsSlamTime and program it */ + recalculateVsSlamTimeSettingOnCorePre(dev); + + u32 cpuRev = mctGetLogicalCPUID(0xFF) ; + u8 procPkg = mctGetProcessorPackageType(); + + config_clk_power_ctrl_reg0(i,cpuRev,procPkg); + config_power_ctrl_misc_reg(dev,cpuRev,procPkg); + + #if 0 + // I don't understand what this is doing nor find docs for these regs + u32 dtemp = dword; + + /* Program F3xD8[PwrPlanes] according F3xA0[DulaVdd] */ dword = pci_read_config32(dev, 0xD8); - printk(BIOS_DEBUG, " F3xD8: %08x \n", dword); - dword = pci_read_config32(dev, 0xDC); - printk(BIOS_DEBUG, " F3xDC: %08x \n", dword); + + if (dtemp & DUAL_VDD_BIT) + dword |= PWR_PLN_ON; + else + dword &= PWR_PLN_OFF; + pci_write_config32(dev, 0xD8, dword); + #endif + config_nb_syn_ptr_adj(dev,cpuRev); + config_acpi_pwr_state_ctrl_regs(dev,cpuRev,procPkg); + + } } @@ -296,8 +639,9 @@ static void UpdateSinglePlaneNbVid(void) msr_t msr; /* copy higher voltage (lower VID) of NBVID & CPUVID to both */ - for (i = 0; i < 5; i++) { + for (i = 0; i < NM_PS_REG; i++) { msr = rdmsr(PS_REG_BASE + i); + nbVid = (msr.lo & PS_CPU_VID_M_ON) >> PS_CPU_VID_SHFT; cpuVid = (msr.lo & PS_NB_VID_M_ON) >> PS_NB_VID_SHFT; @@ -309,23 +653,75 @@ static void UpdateSinglePlaneNbVid(void) msr.lo = msr.lo | (u32) ((nbVid) << PS_NB_VID_SHFT); msr.lo = msr.lo | (u32) ((nbVid) << PS_CPU_VID_SHFT); wrmsr(PS_REG_BASE + i, msr); + } } } -static void fixPsNbVidBeforeWR(u32 newNbVid, u32 coreid) + +static void waitCurrentPstate(u32 target_pstate){ + msr_t initial_msr = rdmsr(TSC_MSR); + msr_t pstate_msr = rdmsr(CUR_PSTATE_MSR); + msr_t tsc_msr; + u8 timedout ; + /* paranoia ? I fear when we run fixPsNbVidBeforeWR we can enter a P1 + * that is a copy of P0, therefore has the same NB DID but the TSC will + * count twice per tick, so we have to wait for twice the count to achieve + * the desired timeout. But I'm likely to misunderstand this... + */ + u32 corrected_timeout = ((pstate_msr.lo==1) && (!(rdmsr(0xC0010065).lo & NB_DID_M_ON)))? WAIT_PSTATE_TIMEOUT*2 : WAIT_PSTATE_TIMEOUT ; + msr_t timeout; + + timeout.lo = initial_msr.lo + corrected_timeout ; + timeout.hi = initial_msr.hi; + if ( (((u32)0xffffffff) - initial_msr.lo) < corrected_timeout ) { + timeout.hi++; + } + // assuming TSC ticks at 1.25 ns per tick (800 MHz) + do { + pstate_msr = rdmsr(CUR_PSTATE_MSR); + tsc_msr = rdmsr(TSC_MSR); + timedout = (tsc_msr.hi > timeout.hi) + || ((tsc_msr.hi == timeout.hi) && (tsc_msr.lo > timeout.lo )); + } while ( (pstate_msr.lo != target_pstate) && (! timedout) ) ; + if (pstate_msr.lo != target_pstate) { + msr_t limit_msr = rdmsr(0xc0010061); + printk(BIOS_ERR, "*** Time out waiting for P-state %01x. Current P-state %01x P-state current limit MSRC001_0061=%02x\n", target_pstate, pstate_msr.lo, limit_msr.lo); + do { // should we just go on instead ? + pstate_msr = rdmsr(CUR_PSTATE_MSR); + } while ( pstate_msr.lo != target_pstate ) ; + } +} + +static void set_pstate(u32 nonBoostedPState) { + msr_t msr; + + // Transition P0 for calling core. + msr = rdmsr(0xC0010062); + + msr.lo = nonBoostedPState; + wrmsr(0xC0010062, msr); + + /* Wait for P0 to set. */ + waitCurrentPstate(nonBoostedPState); +} + + +static void fixPsNbVidBeforeWR(u32 newNbVid, u32 coreid, u32 dev, u8 pviMode) { msr_t msr; u8 startup_pstate; /* This function sets NbVid before the warm reset. * Get StartupPstate from MSRC001_0071. - * Read Pstate register pionted by [StartupPstate]. + * Read Pstate register pointed by [StartupPstate]. * and copy its content to P0 and P1 registers. * Copy newNbVid to P0[NbVid]. * transition to P1 on all cores, * then transition to P0 on core 0. * Wait for MSRC001_0063[CurPstate] = 000b on core 0. + * see BKDG rev 3.48 2.4.2.9.1 BIOS NB COF and VID Configuration + * for SVI and Single-Plane PVI Systems */ msr = rdmsr(0xc0010071); @@ -338,36 +734,38 @@ static void UpdateSinglePlaneNbVid(void) msr = rdmsr(0xC0010064 + startup_pstate); wrmsr(0xC0010065, msr); wrmsr(0xC0010064, msr); + + // missing step 2 from BDKG , F3xDC[PstateMaxVal] = max(1,F3xDC[PstateMaxVal] ) + // because it would take synchronization between cores and we + // don't think PstatMaxVal is going to be 0 on cold reset anyway ? + if ( ! (pci_read_config32(dev, 0xDC) & (~ PS_MAX_VAL_MASK)) ) { + printk(BIOS_ERR,"F3xDC[PstateMaxVal] is zero. Northbridge voltage setting will fail. fixPsNbVidBeforeWR in fidvid.c needs fixing. See AMD # 31116 rev 3.48 BKDG 2.4.2.9.1 \n"); + }; msr.lo &= ~0xFE000000; // clear nbvid - msr.lo |= newNbVid << 25; + msr.lo |= (newNbVid << 25); wrmsr(0xC0010064, msr); - + + if (pviMode) { /* single plane*/ UpdateSinglePlaneNbVid(); - + } // Transition to P1 for all APs and P0 for core0. - msr = rdmsr(0xC0010062); - msr.lo = (msr.lo & ~0x07) | 1; - wrmsr(0xC0010062, msr); - // Wait for P1 to set. - do { - msr = rdmsr(0xC0010063); - } while (msr.lo != 1); + set_pstate(1); if (coreid == 0) { - msr.lo = msr.lo & ~0x07; - wrmsr(0xC0010062, msr); - // Wait for P0 to set. - do { - msr = rdmsr(0xC0010063); - } while (msr.lo != 0); + set_pstate(0); } + + // missing step 7 (restore PstateMax to 0 if needed) because we skipped step 2 } -static void coreDelay(void) +static void coreDelay(u32 microseconds) { u32 saved; + u32 saved_hi; + u32 end; + u32 end_hi; u32 hi, lo, msr; u32 cycles; @@ -375,18 +773,34 @@ static void UpdateSinglePlaneNbVid(void) This seems like a hack to me... It would be nice to have a central delay function. */ - cycles = 8000 << 3; /* x8 (number of 1.25ns ticks) */ + cycles = (microseconds * 100) << 3; /* x8 (number of 1.25ns ticks) */ + if (!(rdmsr(HWCR).lo & TSC_FREQ_SEL_MASK)) { + msr_t pstate_msr = rdmsr(CUR_PSTATE_MSR); + if (!(rdmsr(0xC0010064+pstate_msr.lo).lo & NB_DID_M_ON)) { + cycles = cycles <<1; // half freq, double cycles + } + } // else should we keep p0 freq at the time of setting TSC_FREQ_SEL_MASK somewhere and check it here ? + msr = 0x10; /* TSC */ _RDMSR(msr, &lo, &hi); saved = lo; + saved_hi = hi; + // avoid overflow when called near 2^32 ticks ~ 5.3 s boundaries + if (0xffffffff - cycles >= saved ) { + end_hi = saved_hi; + end = saved + cycles; + } else { + end_hi = saved_hi +1; // + end = cycles - (1+(0xffffffff - saved)); + } do { _RDMSR(msr, &lo, &hi); - } while (lo - saved < cycles); + } while ((hi < end_hi) || ((hi == end_hi) && (lo < end))); } - +#if 0 static void transitionVid(u32 targetVid, u8 dev, u8 isNb) -{ +{ //called from init_fidvid_bsp, init_fidvid_ap when SVI u32 currentVid, dtemp; msr_t msr; u8 vsTimecode; @@ -397,7 +811,7 @@ static void transitionVid(u32 targetVid, u8 dev, u * It uses VSRampTime for [SlamVidMode]=0 ([PviMode]=1) * or VSSlamTime for [SlamVidMode]=1 ([PviMode]=0)to time period. */ - + printk(BIOS_DEBUG,"transitionVid(targetVid=%d,dev,isNb=%d)\n",targetVid,isNb); /* get the current VID */ msr = rdmsr(0xC0010071); if (isNb) @@ -407,34 +821,32 @@ static void transitionVid(u32 targetVid, u8 dev, u /* Read MSRC001_0070 COFVID Control Register */ msr = rdmsr(0xC0010070); - + /* check PVI/SPI */ dtemp = pci_read_config32(dev, 0xA0); + printk(BIOS_DEBUG,"transitionVid current=%d target=%d\n",currentVid,targetVid); if (dtemp & PVI_MODE) { /* PVI, step VID */ + /* not called in PVI mode, shouldn't work if called */ + printk(BIOS_ERR,"Software initiated votage transitions not implemented for PVI\n"); + #if 0 + /* BKDG 2.4.1.9 : If F3xA0[PviMode]=1b only changes + to NbVid are driven on the PVI inter- face as + defined in Section 2.4.1 [Processor Power Planes + And Voltage Control]. + */ + if (!isNb) { + printk(BIOS_DEBUG,"useless software initiated Voltage transition for cpu vid in PVI mode. Should change NB Vid instead. \n"); + } + int step =-1; if (currentVid < targetVid) { - while (currentVid < targetVid) { - currentVid++; - if (isNb) - msr.lo = (msr.lo & NB_VID_MASK_OFF) | (currentVid << NB_VID_POS); - else - msr.lo = (msr.lo & CPU_VID_MASK_OFF) | (currentVid << CPU_VID_POS); - wrmsr(0xC0010070, msr); - - /* read F3xD8[VSRampTime] */ - dtemp = pci_read_config32(dev, 0xD8); - vsTimecode = (u8) ((dtemp >> VS_RAMP_T) & 0x7); - vsTime = (int)timeTable[vsTimecode]; - do { - coreDelay(); - vsTime -= 40; - } while (vsTime > 0); + step=1; } - } else if (currentVid > targetVid) { - while (currentVid > targetVid) { - currentVid--; + while (currentVid != targetVid) { + /* according to BKDG 2.4.1.9.1 shouldn't we synchronize cores at each step ? It says write to all copies of MSRC001_0070 and then wait VS_RAMP_T */ + currentVid+=step; if (isNb) msr.lo = (msr.lo & NB_VID_MASK_OFF) | (currentVid << NB_VID_POS); - else + else /* useless, BKDG 2.4.1.9.2 says to change NB vid since we're single plane. I can't test so I don't change it... */ msr.lo = (msr.lo & CPU_VID_MASK_OFF) | (currentVid << CPU_VID_POS); wrmsr(0xC0010070, msr); @@ -442,12 +854,9 @@ static void transitionVid(u32 targetVid, u8 dev, u dtemp = pci_read_config32(dev, 0xD8); vsTimecode = (u8) ((dtemp >> VS_RAMP_T) & 0x7); vsTime = (int)timeTable[vsTimecode]; - do { - coreDelay(); - vsTime -= 40; - } while (vsTime > 0); + coreDelay((u32) vsTime); } - } + #endif } else { /* SVI, slam VID */ if (isNb) msr.lo = (msr.lo & NB_VID_MASK_OFF) | (targetVid << NB_VID_POS); @@ -457,60 +866,62 @@ static void transitionVid(u32 targetVid, u8 dev, u /* read F3xD8[VSRampTime] */ dtemp = pci_read_config32(dev, 0xD8); - vsTimecode = (u8) ((dtemp >> VS_RAMP_T) & 0x7); + vsTimecode = (u8) ((dtemp >> VS_SLAM_T) & ~VSSLAM_MASK); vsTime = (int)timeTable[vsTimecode]; - do { - coreDelay(); - vsTime -= 40; - } while (vsTime > 0); + coreDelay((u32) vsTime); } } +#endif - -static void init_fidvid_ap(u32 bsp_apicid, u32 apicid, u32 nodeid, u32 coreid) +static u32 needs_NB_COF_VID_update(void) { - device_t dev; - u32 vid_max; - u32 fid_max; u8 nb_cof_vid_update; - u8 pvimode; - u32 reg1fc; - u32 send; u8 nodes; u8 i; - printk(BIOS_DEBUG, "FIDVID on AP: %02x\n", apicid); - - /* Steps 1-6 of BIOS NB COF and VID Configuration - * for SVI and Single-Plane PVI Systems. - */ - /* If any node has nb_cof_vid_update set all nodes need an update. */ nodes = get_nodes(); nb_cof_vid_update = 0; for (i = 0; i < nodes; i++) { - if (pci_read_config32(NODE_PCI(i, 3), 0x1FC) & 1) { + u32 cpuRev = mctGetLogicalCPUID(i) ; + u32 nbCofVidUpdateDefined = (cpuRev & (AMD_FAM10_LT_D)); + if (nbCofVidUpdateDefined + && (pci_read_config32(NODE_PCI(i, 3), 0x1FC) + & NB_COF_VID_UPDATE_MASK)) { nb_cof_vid_update = 1; break; } } + return nb_cof_vid_update; +} +static u32 init_fidvid_core(u32 nodeid, u32 coreid) +{ + device_t dev; + u32 vid_max; + u32 fid_max = 0; + u8 nb_cof_vid_update = needs_NB_COF_VID_update(); + u8 pvimode; + u32 reg1fc; + + /* Steps 1-6 of BIOS NB COF and VID Configuration + * for SVI and Single-Plane PVI Systems. BKDG 2.4.2.9 #31116 rev 3.48 + */ + dev = NODE_PCI(nodeid, 3); - pvimode = (pci_read_config32(dev, 0xA0) >> 8) & 1; + pvimode = pci_read_config32(dev, PW_CTL_MISC) & PVI_MODE; reg1fc = pci_read_config32(dev, 0x1FC); if (nb_cof_vid_update) { - if (pvimode) { - vid_max = (reg1fc >> 7) & 0x7F; - fid_max = (reg1fc >> 2) & 0x1F; + vid_max = (reg1fc & SINGLE_PLANE_NB_VID_MASK ) >> SINGLE_PLANE_NB_VID_SHIFT ; + fid_max = (reg1fc & SINGLE_PLANE_NB_FID_MASK ) >> SINGLE_PLANE_NB_FID_SHIFT ; + if (!pvimode) { /* SVI, dual power plane */ + vid_max = vid_max - ((reg1fc & DUAL_PLANE_NB_VID_OFF_MASK ) >> DUAL_PLANE_NB_VID_SHIFT ); + fid_max = fid_max + ((reg1fc & DUAL_PLANE_NB_FID_OFF_MASK ) >> DUAL_PLANE_NB_FID_SHIFT ); + } /* write newNbVid to P-state Reg's NbVid always if NbVidUpdatedAll=1 */ - fixPsNbVidBeforeWR(vid_max, coreid); - } else { /* SVI */ - vid_max = ((reg1fc >> 7) & 0x7F) - ((reg1fc >> 17) & 0x1F); - fid_max = ((reg1fc >> 2) & 0x1F) + ((reg1fc >> 14) & 0x7); - transitionVid(vid_max, dev, IS_NB); - } + fixPsNbVidBeforeWR(vid_max, coreid,dev,pvimode); /* fid setup is handled by the BSP at the end. */ @@ -520,7 +931,16 @@ static void transitionVid(u32 targetVid, u8 dev, u UpdateSinglePlaneNbVid(); } - send = (nb_cof_vid_update << 16) | (fid_max << 8); + return ((nb_cof_vid_update << 16) | (fid_max << 8)); + +} + + +static void init_fidvid_ap(u32 apicid, u32 nodeid, u32 coreid) +{ + u32 send; + + send = init_fidvid_core(nodeid,coreid); send |= (apicid << 24); // ap apicid // Send signal to BSP about this AP max fid @@ -528,6 +948,7 @@ static void transitionVid(u32 targetVid, u8 dev, u lapic_write(LAPIC_MSG_REG, send | F10_APSTATE_RESET); } + static u32 calc_common_fid(u32 fid_packed, u32 fid_packed_new) { u32 fidmax; @@ -569,7 +990,7 @@ static void init_fidvid_bsp_stage1(u32 ap_apicid, } if (timeout) { - printk(BIOS_DEBUG, "%s: timed out reading from ap %02x\n", + printk(BIOS_ERR, "%s: timed out reading from ap %02x\n", __func__, ap_apicid); return; } @@ -582,80 +1003,49 @@ static void init_fidvid_bsp_stage1(u32 ap_apicid, } -static void updateSviPsNbVidAfterWR(u32 newNbVid) -{ - msr_t msr; - u8 i; - /* This function copies newNbVid to NbVid bits in P-state Registers[4:0] - * for SVI mode. - */ - - for (i = 0; i < 5; i++) { - msr = rdmsr(0xC0010064 + i); - if ((msr.hi >> 31) & 1) { /* PstateEn? */ - msr.lo &= ~(0x7F << 25); - msr.lo |= (newNbVid & 0x7F) << 25; - wrmsr(0xC0010064 + i, msr); - } - } -} - - -static void fixPsNbVidAfterWR(u32 newNbVid, u8 NbVidUpdatedAll) +static void fixPsNbVidAfterWR(u32 newNbVid, u8 NbVidUpdatedAll,u8 pviMode) { msr_t msr; u8 i; u8 StartupPstate; - /* This function copies newNbVid to NbVid bits in P-state - * Registers[4:0] if its NbDid bit=0 and PstateEn bit =1 in case of - * NbVidUpdatedAll =0 or copies copies newNbVid to NbVid bits in - * P-state Registers[4:0] if its and PstateEn bit =1 in case of + /* BKDG 2.4.2.9.1 11-12 + * This function copies newNbVid to NbVid bits in P-state + * Registers[4:0] if its NbDid bit=0, and IddValue!=0 in case of + * NbVidUpdatedAll =0 or copies newNbVid to NbVid bits in + * P-state Registers[4:0] if its IddValue!=0 in case of * NbVidUpdatedAll=1. Then transition to StartPstate. */ /* write newNbVid to P-state Reg's NbVid if its NbDid=0 */ for (i = 0; i < 5; i++) { msr = rdmsr(0xC0010064 + i); + /* NbDid (bit 22 of P-state Reg) == 0 or NbVidUpdatedAll = 1 */ - if ((((msr.lo >> 22) & 1) == 0) || NbVidUpdatedAll) { - msr.lo &= ~(0x7F << 25); - msr.lo |= (newNbVid & 0x7F) << 25; + if ( (msr.hi & PS_IDD_VALUE_MASK) + && (msr.hi & PS_EN_MASK) + &&(((msr.lo & PS_NB_DID_MASK) == 0) || NbVidUpdatedAll)) { + msr.lo &= PS_NB_VID_M_OFF; + msr.lo |= (newNbVid & 0x7F) << PS_NB_VID_SHFT; wrmsr(0xC0010064 + i, msr); } } + // Not documented. Would overwrite Nb_Vids just copied + // should we just update cpu_vid or nothing at all ? + if (pviMode) { //single plane UpdateSinglePlaneNbVid(); - + } /* For each core in the system, transition all cores to StartupPstate */ msr = rdmsr(0xC0010071); StartupPstate = msr.hi & 0x07; - msr = rdmsr(0xC0010062); - msr.lo = StartupPstate; - wrmsr(0xC0010062, msr); - - /* Wait for StartupPstate to set. */ - do { - msr = rdmsr(0xC0010063); - } while (msr.lo != StartupPstate); + + /* Set and wait for StartupPstate to set. */ + set_pstate(StartupPstate); } -static void set_p0(void) -{ - msr_t msr; - // Transition P0 for calling core. - msr = rdmsr(0xC0010062); - msr.lo = (msr.lo & ~0x07); - wrmsr(0xC0010062, msr); - - /* Wait for P0 to set. */ - do { - msr = rdmsr(0xC0010063); - } while (msr.lo != 0); -} - static void finalPstateChange(void) { /* Enble P0 on all cores for best performance. @@ -663,49 +1053,35 @@ static void finalPstateChange(void) * It is safe since they will be in C1 halt * most of the time anyway. */ - set_p0(); + set_pstate(0); } static void init_fidvid_stage2(u32 apicid, u32 nodeid) { + msr_t msr; device_t dev; u32 reg1fc; u32 dtemp; u32 nbvid; - u8 nb_cof_vid_update; - u8 nodes; + u8 nb_cof_vid_update = needs_NB_COF_VID_update(); u8 NbVidUpdateAll; - u8 i; u8 pvimode; /* After warm reset finish the fid/vid setup for all cores. */ - /* If any node has nb_cof_vid_update set all nodes need an update. */ - nodes = get_nodes(); - nb_cof_vid_update = 0; - for (i = 0; i < nodes; i++) { - if (pci_read_config32(NODE_PCI(i, 3), 0x1FC) & 1) { - nb_cof_vid_update = 1; - break; - } - } - + dev = NODE_PCI(nodeid, 3); pvimode = (pci_read_config32(dev, 0xA0) >> 8) & 1; reg1fc = pci_read_config32(dev, 0x1FC); nbvid = (reg1fc >> 7) & 0x7F; NbVidUpdateAll = (reg1fc >> 1) & 1; - + if (nb_cof_vid_update) { - if (pvimode) { - nbvid = (reg1fc >> 7) & 0x7F; - /* write newNbVid to P-state Reg's NbVid if its NbDid=0 */ - fixPsNbVidAfterWR(nbvid, NbVidUpdateAll); - } else { /* SVI */ - nbvid = ((reg1fc >> 7) & 0x7F) - ((reg1fc >> 17) & 0x1F); - updateSviPsNbVidAfterWR(nbvid); + if (!pvimode) { /* SVI */ + nbvid = nbvid - ((reg1fc >> 17) & 0x1F); } + /* write newNbVid to P-state Reg's NbVid if its NbDid=0 */ fixPsNbVidAfterWR(nbvid, NbVidUpdateAll,pvimode); } else { /* !nb_cof_vid_update */ if (pvimode) UpdateSinglePlaneNbVid(); @@ -715,6 +1091,11 @@ static void init_fidvid_stage2(u32 apicid, u32 nod dtemp |= PLLLOCK_DFT_L; pci_write_config32(dev, 0xA0, dtemp); + dualPlaneOnly(dev); + applyBoostFIDOffset(dev); + enableNbPState1(dev); + setPStateMaxVal(dev); + finalPstateChange(); /* Set TSC to tick at the P0 ndfid rate */ @@ -739,8 +1120,6 @@ static void store_ap_apicid(unsigned ap_apicid, vo } #endif - - static int init_fidvid_bsp(u32 bsp_apicid, u32 nodes) { #if CONFIG_SET_FIDVID_STORE_AP_APICID_AT_FIRST @@ -748,57 +1127,13 @@ static int init_fidvid_bsp(u32 bsp_apicid, u32 nod u32 i; #endif struct fidvid_st fv; - device_t dev; - u32 vid_max; - u32 fid_max=0; - u8 nb_cof_vid_update; - u32 reg1fc; - u8 pvimode; - printk(BIOS_DEBUG, "FIDVID on BSP, APIC_id: %02x\n", bsp_apicid); - /* FIXME: The first half of this function is nearly the same as - * init_fidvid_bsp() and the code could be combined. - */ /* Steps 1-6 of BIOS NB COF and VID Configuration * for SVI and Single-Plane PVI Systems. */ + fv.common_fid = init_fidvid_core(0,0); - /* If any node has nb_cof_vid_update set all nodes need an update. */ - nb_cof_vid_update = 0; - for (i = 0; i < nodes; i++) { - if (pci_read_config32(NODE_PCI(i, 3), 0x1FC) & 1) { - nb_cof_vid_update = 1; - break; - } - } - - dev = NODE_PCI(0, 3); - pvimode = (pci_read_config32(dev, 0xA0) >> 8) & 1; - reg1fc = pci_read_config32(dev, 0x1FC); - - if (nb_cof_vid_update) { - if (pvimode) { - vid_max = (reg1fc >> 7) & 0x7F; - fid_max = (reg1fc >> 2) & 0x1F; - - /* write newNbVid to P-state Reg's NbVid always if NbVidUpdatedAll=1 */ - fixPsNbVidBeforeWR(vid_max, 0); - } else { /* SVI */ - vid_max = ((reg1fc >> 7) & 0x7F) - ((reg1fc >> 17) & 0x1F); - fid_max = ((reg1fc >> 2) & 0x1F) + ((reg1fc >> 14) & 0x7); - transitionVid(vid_max, dev, IS_NB); - } - - /* fid setup is handled by the BSP at the end. */ - - } else { /* ! nb_cof_vid_update */ - /* Use max values */ - if (pvimode) - UpdateSinglePlaneNbVid(); - } - - fv.common_fid = (nb_cof_vid_update << 16) | (fid_max << 8); print_debug_fv("BSP fid = ", fv.common_fid); #if CONFIG_SET_FIDVID_STORE_AP_APICID_AT_FIRST && !CONFIG_SET_FIDVID_CORE0_ONLY Index: src/cpu/amd/model_10xxx/defaults.h =================================================================== --- src/cpu/amd/model_10xxx/defaults.h (revision 6323) +++ src/cpu/amd/model_10xxx/defaults.h (working copy) @@ -68,7 +68,7 @@ static const struct { 1 << 24, 0x00000000, 1 << 24, 0x00000000 }, /* Erratum #261 [DIS_PIGGY_BACK_SCRUB]=1 */ - { LS_CFG, AMD_FAM10_GT_B0, AMD_PTYPE_ALL, + { LS_CFG, AMD_DR_GT_B0, AMD_PTYPE_ALL, 0 << 1, 0x00000000, 1 << 1, 0x00000000 }, /* IDX_MATCH_ALL=0 */ @@ -261,9 +261,12 @@ static const struct { { 3, 0xA0, AMD_FAM10_ALL, AMD_PTYPE_MOB | AMD_PTYPE_DSK, 0x00000080, 0x00000080 }, /* [7] PSIVidEnable */ - { 3, 0xA0, AMD_FAM10_ALL, AMD_PTYPE_ALL, - 0x00001800, 0x000003800 }, /* [13:11] PllLockTime = 3 */ + { 3, 0xA0, AMD_DR_Bx, AMD_PTYPE_ALL, + 0x00002800, 0x000003800 }, /* [13:11] PllLockTime = 5 */ + { 3, 0xA0, (AMD_FAM10_ALL & ~(AMD_DR_Bx)), AMD_PTYPE_ALL, + 0x00000800, 0x000003800 }, /* [13:11] PllLockTime = 1 */ + /* Reported Temp Control Register */ { 3, 0xA4, AMD_FAM10_ALL, AMD_PTYPE_ALL, 0x00000080, 0x00000080 }, /* [7] TempSlewDnEn = 1 */ Index: src/cpu/amd/model_10xxx/init_cpus.c =================================================================== --- src/cpu/amd/model_10xxx/init_cpus.c (revision 6323) +++ src/cpu/amd/model_10xxx/init_cpus.c (working copy) @@ -157,7 +157,7 @@ static inline int lapic_remote_read(int apicid, in } #if CONFIG_SET_FIDVID -static void init_fidvid_ap(u32 bsp_apicid, u32 apicid, u32 nodeid, u32 coreid); +static void init_fidvid_ap(u32 apicid, u32 nodeid, u32 coreid); #endif static inline __attribute__ ((always_inline)) @@ -325,7 +325,7 @@ static u32 init_cpus(u32 cpu_init_detectedx) * This happens after HTinit. * The BSP runs this code in it's own path. */ - update_microcode(cpuid_eax(1)); + //update_microcode(cpuid_eax(1)); cpuSetAMDMSR(); #if CONFIG_SET_FIDVID @@ -344,8 +344,7 @@ static u32 init_cpus(u32 cpu_init_detectedx) printk(BIOS_DEBUG, "init_fidvid_ap(stage1) apicid: %02x\n", apicid); - init_fidvid_ap(bsp_apicid, apicid, id.nodeid, - id.coreid); + init_fidvid_ap(apicid, id.nodeid, id.coreid); } } #endif Index: src/northbridge/amd/amdmct/wrappers/mcti_d.c =================================================================== --- src/northbridge/amd/amdmct/wrappers/mcti_d.c (revision 6323) +++ src/northbridge/amd/amdmct/wrappers/mcti_d.c (working copy) @@ -339,7 +339,7 @@ static void mctHookAfterDramInit(void) { } -static void coreDelay (void); +static void coreDelay (u32 microseconds); #if (CONFIG_DIMM_SUPPORT & 0x000F)==0x0005 /* AMD_FAM10_DDR3 */ @@ -388,7 +388,7 @@ static void vErrata350(struct MCTStatStruc *pMCTst print_t("vErrata350: step 3\n"); /* 3. Wait at least 300 nanoseconds. */ - coreDelay(); + coreDelay(1); print_t("vErrata350: step 4\n"); /* 4. Write 0000_0000h to register F2x[1, 0]9C_xD080F0C. */ @@ -401,7 +401,7 @@ static void vErrata350(struct MCTStatStruc *pMCTst print_t("vErrata350: step 5\n"); /* 5. Wait at least 2 microseconds. */ - coreDelay(); + coreDelay(3); } Index: src/northbridge/amd/amdmct/amddefs.h =================================================================== --- src/northbridge/amd/amdmct/amddefs.h (revision 6323) +++ src/northbridge/amd/amdmct/amddefs.h (working copy) @@ -63,8 +63,13 @@ #define AMD_DR_GT_B0 (AMD_DR_ALL & ~(AMD_DR_B0)) #define AMD_DR_ALL (AMD_DR_Bx) #define AMD_FAM10_ALL (AMD_DR_ALL | AMD_RB_C2 | AMD_HY_D0 | AMD_DA_C3 | AMD_DA_C2 | AMD_RB_C3 ) +/* #define AMD_FAM10_GT_B0 (AMD_FAM10_ALL & ~(AMD_DR_B0)) -#define AMD_DR_Cx (AMD_RB_C2 | AMD_DA_C2 | AMD_RB_C3 | AMD_DA_C3) +*/ +#define AMD_FAM10_LT_D (AMD_FAM10_ALL & ~(AMD_HY_D0)) +#define AMD_FAM10_C3 (AMD_RB_C3 | AMD_DA_C3) +#define AMD_DA_Cx (AMD_DA_C2 | AMD_DA_C3) +#define AMD_DR_Cx (AMD_RB_C2 | AMD_RB_C3 | AMD_DA_Cx) #define AMD_DR_Dx (AMD_HY_D0) #define AMD_DRBH_Cx (AMD_DR_Cx | AMD_HY_D0 ) #define AMD_DRBA23_RBC2 (AMD_DR_BA | AMD_DR_B2 | AMD_DR_B3 | AMD_RB_C2 ) @@ -134,3 +139,13 @@ #define DC_CFG 0xC0011022 #define BU_CFG 0xC0011023 #define BU_CFG2 0xC001102A + +/* + * Processor package types + */ +#define AMD_PKGTYPE_FrX_1207 0 +#define AMD_PKGTYPE_AM3_2r2 1 +#define AMD_PKGTYPE_S1gX 2 +#define AMD_PKGTYPE_G34 3 +#define AMD_PKGTYPE_ASB2 4 +#define AMD_PKGTYPE_C32 5 Index: src/northbridge/amd/amdfam10/Kconfig =================================================================== --- src/northbridge/amd/amdfam10/Kconfig (revision 6323) +++ src/northbridge/amd/amdfam10/Kconfig (working copy) @@ -112,4 +112,12 @@ if DIMM_DDR3 endif endif +config SVI_HIGH_FREQ + bool + default n + depends on NORTHBRIDGE_AMD_AMDFAM10 + help + Select this for boards with a Voltage Regulator able to operate + at 3.4 MHz in SVI mode. Ignored unless the AMD CPU is rev C3. + source src/northbridge/amd/amdfam10/root_complex/Kconfig Index: src/northbridge/amd/amdfam10/raminit_amdmct.c =================================================================== --- src/northbridge/amd/amdfam10/raminit_amdmct.c (revision 6323) +++ src/northbridge/amd/amdfam10/raminit_amdmct.c (working copy) @@ -214,6 +214,11 @@ u32 mctGetLogicalCPUID(u32 Node) return ret; } +static u8 mctGetProcessorPackageType(void) { + /* FIXME: I guess this belongs wherever mctGetLogicalCPUID ends up ? */ + u32 BrandId = cpuid_ebx(0x80000001); + return (u8)((BrandId >> 28) & 0x0F); +} static void raminit_amdmct(struct sys_info *sysinfo) { Index: src/northbridge/amd/amdht/AsPsDefs.h =================================================================== --- src/northbridge/amd/amdht/AsPsDefs.h (revision 6323) +++ src/northbridge/amd/amdht/AsPsDefs.h (working copy) @@ -25,7 +25,7 @@ #define APIC_BAR_BP 0x100 /* APIC_BAR BSP bit */ #define PS_LIM_REG 0xC0010061 /* P-state Current Limit Register */ -#define PS_CUR_LIM_SHFT 4 /* P-state Current Limit shift position */ +#define PS_MAX_VAL_SHFT 4 /* P-state Maximum Value shift position */ #define PS_CTL_REG 0xC0010062 /* P-state Control Register */ #define PS_CMD_MASK_OFF 0xfffffff8 /* P-state Control Register CMD Mask OFF */ @@ -44,9 +44,11 @@ #define PS_REG3 3 /* offset for P3 */ #define PS_REG4 4 /* offset for P4 */ +#define PS_IDD_VALUE_SHFT 0 /* IddValue: current value field offset for msr.hi */ +#define PS_IDD_VALUE_MASK 0xFF /* IddValue: current value field mask for msr.hi */ #define PS_PSDIS_MASK 0x7fffffff /* disable P-state register */ #define PS_EN_MASK 0x80000000 /* P-state register enable mask */ -#define PS_NB_DID_MASK 0x400000 /* P-state Reg[NbDid] Mask */ +#define PS_NB_DID_MASK 0x00400000 /* P-state Reg[NbDid] Mask */ #define PS_NB_VID_M_OFF 0x01ffffff /* P-state Reg[NbVid] Mask OFF */ #define PS_CPU_VID_M_ON 0x0fe00 /* P-state Reg[CpuVid] Mask On */ #define PS_NB_VID_M_ON 0x0fe000000 /* P-state Reg[NbVid] Mask On */ @@ -54,9 +56,9 @@ #define PS_NB_VID_SHFT 25 /* P-state bit shift for NbVid */ #define PS_BOTH_VID_OFF 0x01ff01ff /* Mask NbVid & CpuVid */ #define PS_CPU_NB_VID_SHFT 16 /* P-state bit shift from CpuVid to NbVid */ -#define PS_NB_VID_SHFT 25 /* P-state NBVID shift */ #define PS_DIS 0x7fffffff /* disable P-state reg */ #define PS_EN 0x80000000 /* enable P-state reg */ +#define PS_CPU_FID_MASK 0x03f /* MSRC001_00[68:64][CpuFid] Core Frequency Id */ #define PS_CURDIV_SHFT 8 /* P-state Current Divisor shift position */ #define PS_CPUDID_SHIFT 6 /* P-state CPU DID shift position */ @@ -105,12 +107,13 @@ #define STC_PS_LMT_MASK 0x8fffffff /* StcPstateLimit mask off */ #define CPTC0 0x0d4 /* Clock Power/Timing Control0 Register*/ -#define CPTC0_MASK 0x000c0fff /* Reset mask for this register */ +#define CPTC0_MASK 0x000cffff /* Reset mask for this register */ #define CPTC0_NBFID_MASK 0xffffffe0 /* NbFid mask off for this register */ #define CPTC0_NBFID_MON 0x1f /* NbFid mask on for this register */ #define NB_FID_EN 0x20 /* NbFidEn bit ON */ #define NB_CLKDID_ALL 0x80000000 /* NbClkDidApplyAll bit ON */ #define NB_CLKDID 0x40000000 /* NbClkDid value set by BIOS */ +#define NB_CLKDID_SHIFT 28 /* NbClkDid bit shift */ #define PW_STP_UP50 0x08000000 /* PowerStepUp 50nS(1000b) */ #define PW_STP_DN50 0x00800000 /* PowerStepDown 50nS (1000b)*/ #define PW_STP_UP100 0x03000000 /* PowerStepUp 100nS(0011b) */ @@ -119,8 +122,8 @@ #define PW_STP_DN200 0x00200000 /* PowerStepDown 200nS (0010b)*/ #define PW_STP_UP400 0x00000000 /* PowerStepUp 400nS(0000b) */ #define PW_STP_DN400 0x00000000 /* PowerStepDown 400nS (0000b)*/ +#define CLK_RAMP_HYST_SEL_VAL 0x00000f00 /* value mask for clock ramp hysteresis select. BIOS should program F3xC4[ClkRampHystSel] to 1111b */ - #define LNK_PLL_LOCK 0x00010000 /* LnkPllLock value set (01b) by BIOS */ @@ -143,9 +146,9 @@ #define PS_2 0x00020000 /* P-state 2 */ #define PS_CPU_DID_1 0x40 /* Cpu Did 1 */ +#define NB_VID1_MASK 0x00003f80 /* F3x1F4[NbVid1]*/ +#define NB_VID1_SHIFT 7 /* F3x1F4[NbVid1] */ - - #define PSTATE_STS 0xC0010071 /* P-state Status Register */ #define STARTUP_PS_MASK 0x7 /* StartupPstate Mask */ @@ -160,6 +163,7 @@ #define VSRAMP_MASK 0xffffff8f /* MaskOff [VSRampTime] */ #define VSRAMP_VALUE 0x10 /* [VSRampTime]=001b */ #define VS_RAMP_T 4 /* VSRampTime bit position */ +#define VS_SLAM_T 4 /* VSSlamTime bit position */ #define VSSLAM_MASK 0xfffffff8 /* MaskOff [VSSlamTime] */ #define PWR_PLN_SHIFT 28 /* PwrPlanes bit shift */ #define PWR_PLN_ON 0x10000000 /* PwrPlanes bit ON */ @@ -175,8 +179,10 @@ #define CPTC2 0xdc /* Clock Power/Timing Control2 Register*/ #define PS_MAX_VAL_POS 8 /* PstateMaxValue bit shift */ #define PS_MAX_VAL_MASK 0xfffff8ff /* PstateMaxValue Mask off */ - +#define NB_SYN_PTR_ADJ_POS 12 /* NbsynPtrAdj bit shift */ +#define NB_SYN_PTR_ADJ_MASK (0x7 << NB_SYN_PTR_ADJ_POS) /* NbsynPtrAdj bit mask */ #define PRCT_INFO 0x1fc /* Product Info Register */ +#define DUAL_PLANE_ONLY_MASK 0x80000000 /* F3x1FC[DualPlaneOnly] */ #define UNI_NB_FID_BIT 2 /* UniNbFid bit position */ #define UNI_NB_VID_BIT 7 /* UniNbVid bit position */ #define SPLT_NB_FID_OFFSET 14 /* SpltNbFidOffset value bit position */ @@ -185,6 +191,9 @@ #define NB_VID_UPDATE_ALL 0x02 /* F3x1FC[NbVidUpdatedAll] bit mask */ #define C_FID_DID_M_OFF 0xfffffe00 /* mask off Core FID & DID */ +#define CPB_MASK 0x00000020 /* core performance boost. CPUID Fn8000 0007 edx */ +#define NC_MASK 0x000000FF /* number of cores - 1. CPUID Fn8000 0008 ecx */ + #define PW_CTL_MISC 0x0a0 /* Power Control Miscellaneous Register */ #define COF_VID_PROG_BIT 0x80000000 /* CofVidProg bit. 0= unfused part */ #define DUAL_VDD_BIT 0x40000000 /* DualVdd bit. */ @@ -192,14 +201,16 @@ #define PVI_MODE 0x100 /* PviMode bit mask */ #define VID_SLAM_OFF 0x0dfffffff /* set VidSlamMode OFF */ #define VID_SLAM_ON 0x020000000 /* set VidSlamMode ON */ +#define NB_PSTATE_FORCE_ON 0x010000000 /* set Northbridge P-state force on next LDTSTOP assertion on, in F3xA0 */ +#define BP_INS_TRI_EN_ON 0x00004000 /* breakpoint pins tristate enable in F3xA0 */ #define PLLLOCK_OFF 0x0ffffc7ff /* PllLockTime Mask OFF */ #define PLLLOCK_DFT 0x00001800 /* PllLockTime default value = 011b */ #define PLLLOCK_DFT_L 0x00002800 /* PllLockTime long value = 101b */ - -/* P-state Specification register base in PCI sapce */ +#define SVI_HIGH_FREQ_ON 0x00000200 /* F3xA0[SviHighFreqSel] for 3.4 MHz SVI in rev. C3 */ +/* P-state Specification register base in PCI space */ #define PS_SPEC_REG 0x1e0 /* PS Spec register base address */ #define PCI_REG_LEN 4 /* PCI register length */ -#define NB_DID_MASK 0x10000 /* NbDid bit mask */ +#define NB_DID_MASK 0x10000 /* F4x1[F0:e0][NbDid] bit mask */ #define NB_DID_2 2 /* NbDid = 2 */ #define NB_DID_1 1 /* NbDid = 1 */ #define SPEC_PWRDIV_M_ON 0x06000000 /* PwrDiv mask on */ @@ -210,6 +221,22 @@ /* F4x1F4 Northbridge P-state spec register */ #define NB_PS_SPEC_REG 0x1f4 /* Nb PS spec reg */ +/* F3x1F0 Product Information Register */ +#define NB_PSTATE_MASK 0x00070000 /* NbPstate for CPU rev C3 */ + +/* F3x1FC Product Information Register */ +#define NB_COF_VID_UPDATE_MASK 1 /* for CPU rev <= C */ +#define SINGLE_PLANE_NB_FID_MASK 0x007c/* for CPU rev <= C */ +#define SINGLE_PLANE_NB_FID_SHIFT 2/* for CPU rev <= C */ +#define SINGLE_PLANE_NB_VID_MASK 0x3f80/* for CPU rev <= C */ +#define SINGLE_PLANE_NB_VID_SHIFT 7/* for CPU rev <= C */ + +#define DUAL_PLANE_NB_FID_OFF_MASK 0x001c000/* for CPU rev <= C */ +#define DUAL_PLANE_NB_FID_SHIFT 14/* for CPU rev <= C */ +#define DUAL_PLANE_NB_VID_OFF_MASK 0x3e0000/* for CPU rev <= C */ +#define DUAL_PLANE_NB_VID_SHIFT 17/* for CPU rev <= C */ + + #define NM_PS_REG 5 /* number of P-state MSR registers */ /* sFidVidInit.outFlags defines */ @@ -243,5 +270,13 @@ #define GH_REV_A2 0x4 /* GH Rev A2 logical ID, Upper half */ +#define TSC_MSR 0x10 +#define CUR_PSTATE_MSR 0xc0010063 +/* Hardware Configuration Register HWCR : MSRC0010015 */ +#define TSC_FREQ_SEL_SHIFT 24 +#define TSC_FREQ_SEL_MASK (1 << TSC_FREQ_SEL_SHIFT) +#define WAIT_PSTATE_TIMEOUT 80000000 /* 0.1 s , unit 1.25 ns */ + + #endif