Patchwork RFC AMD powernow generation for pre fam 0fh

login
register
about
Submitter Rudolf Marek
Date 2010-12-25 19:08:39
Message ID <4D164137.9080304@assembler.cz>
Download mbox | patch
Permalink /patch/2451/
State New
Headers show

Comments

Rudolf Marek - 2010-12-25 19:08:39
Hi all,

This is RFC patch. It adds support for automatic PSS object generation for AMD 
pre fam Fh CPU. Those CPUs require a hardcoded table, which I managed to rewrite 
during one particularly boring flight. Too pity it is only for Opteron CPUs. 
Someone needs to finish the second PDF for All others Athlons and Semprons.

It just adds the table to same place where is the fam0fh generator. To make the 
powernow work on my Asrock 939 board I had to enable undocumented bit1 in 
PM_Misc 67h of SB710. It looks like this bit is documented in SB600 and it is 
doing LDT_STOP toggle for C states (and for FID/VID). I remember I had to fix 
this toggle for VIA chipset too. It took me some time to figure it out. It 
helped that it started to work if the orig bios was booted and halted to S5.
All search was to find out what register was not  updated by coreboot).

Whom to ask to fix the AMD documentation?

It is unknown if the bit is necessary for fam 0fh or fam10h, question is if the 
second bit CC_en which says: "C State enable. This bit must be set in order to 
exercise the C state" should be enabled (it is for me with orig BIOS).

Thanks,
Rudolf
Marc Jones - 2010-12-27 20:36:02
2010/12/25 Rudolf Marek <r.marek@assembler.cz>:
> Hi all,
>
> This is RFC patch. It adds support for automatic PSS object generation for
> AMD pre fam Fh CPU. Those CPUs require a hardcoded table, which I managed to
> rewrite during one particularly boring flight. Too pity it is only for
> Opteron CPUs. Someone needs to finish the second PDF for All others Athlons
> and Semprons.
>
> It just adds the table to same place where is the fam0fh generator. To make
> the powernow work on my Asrock 939 board I had to enable undocumented bit1
> in PM_Misc 67h of SB710. It looks like this bit is documented in SB600 and
> it is doing LDT_STOP toggle for C states (and for FID/VID). I remember I had
> to fix this toggle for VIA chipset too. It took me some time to figure it
> out. It helped that it started to work if the orig bios was booted and
> halted to S5.
> All search was to find out what register was not  updated by coreboot).
>
> Whom to ask to fix the AMD documentation?

Hi Rudolf,

I don't know if this is the case for this bit, but some registers are
only documented in the register programming requirements document
(rpr) and not in the register reference guide (rrg). This is
intentional by AMD and they probably won't be changed.

Frank Vibrans is on this list and should be able to relay the request
back to the document gatekeepers next week, when they get back from
the holiday shutdown.

Marc

Patch

Index: src/cpu/amd/model_fxx/powernow_acpi.c
===================================================================
--- src/cpu/amd/model_fxx/powernow_acpi.c.orig	2010-10-16 09:09:24.000000000 +0200
+++ src/cpu/amd/model_fxx/powernow_acpi.c	2010-12-25 18:13:19.000000000 +0100
@@ -30,10 +30,9 @@ 
 #include <cpu/amd/amdk8_sysconf.h>
 #include <arch/cpu.h>
 
-#if CONFIG_K8_REV_F_SUPPORT
 static int write_pstates_for_core(u8 pstate_num, u16 *pstate_feq, u8 *pstate_vid,
 				u8 *pstate_fid, u32 *pstate_power, int coreID,
-				u32 pcontrol_blk, u8 plen, u8 onlyBSP)
+				u32 pcontrol_blk, u8 plen, u8 onlyBSP, u32 control)
 {
 	int lenp, lenpr, i;
 
@@ -50,16 +49,8 @@ 
 	lenp = acpigen_write_package(pstate_num);
 
 	for (i = 0;i < pstate_num;i++) {
-		u32 control, status;
-
-		control =
-			    (0x3 << 30) | /* IRT */
-			    (0x2 << 28) | /* RVO */
-			    (0x1 << 27) | /* ExtType */
-			    (0x2 << 20) | /* PLL_LOCK_TIME */
-			    (0x0 << 18) | /* MVS */
-			    (0x5 << 11) | /* VST */
-			    (pstate_vid[i] << 6) |
+		u32 status, c2;
+		c2 = control | (pstate_vid[i] << 6) |
 			    pstate_fid[i];
 		status =
 			    (pstate_vid[i] << 6) |
@@ -69,7 +60,7 @@ 
 						pstate_power[i],
 						0x64,
 						0x7,
-						control,
+						c2,
 						status);
 	}
 	/* update the package  size */
@@ -81,6 +72,8 @@ 
 	acpigen_patch_len(lenpr - 2);
 	return lenpr;
 }
+
+#if CONFIG_K8_REV_F_SUPPORT
 /*
 * Details about this algorithm , refert to BDKG 10.5.1
 * Two parts are included, the another is the DSDT reconstruction process
@@ -90,7 +83,7 @@ 
 {
 	int len;
 	u8 processor_brand[49];
-	u32 *v;
+	u32 *v, control;
 	struct cpuid_result cpuid1;
 
 	struct power_limit_encoding {
@@ -367,15 +360,289 @@ 
 
 	len = 0;
 
+	control = (0x3 << 30) | /* IRT */
+		  (0x2 << 28) | /* RVO */
+		  (0x1 << 27) | /* ExtType */
+		  (0x2 << 20) | /* PLL_LOCK_TIME */
+		  (0x0 << 18) | /* MVS */
+		  (0x5 << 11); /* VST */
+
 	for (index = 0; index < (cmp_cap + 1); index++) {
 		len += write_pstates_for_core(Pstate_num, Pstate_feq, Pstate_vid,
 				Pstate_fid, Pstate_power, index,
-				pcontrol_blk, plen, onlyBSP);
+				pcontrol_blk, plen, onlyBSP, control);
 	}
 
 	return len;
 }
 
+#else
+
+
+static uint8_t vid_to_reg(uint32_t vid)
+{
+	return (1550 - vid) / 25;
+}
+
+static uint32_t vid_from_reg(uint8_t val)
+{
+	return (val == 0x1f ? 0 : 1550 - val * 25);
+}
+
+static uint8_t freq_to_fid(uint32_t freq)
+{
+	return (freq - 800) / 100;
+}
+//from kernel
+/* Return a frequency in MHz, given an input fid */
+static uint32_t fid_to_freq(uint32_t fid)
+{
+	return 800 + (fid * 100);
+}
+
+
+#define MAXP 7
+
+struct pstate {
+	uint16_t freqMhz;
+	uint16_t voltage;
+	uint16_t tdp;
+};
+
+struct cpuentry {
+	uint16_t modelnr;
+	uint8_t brandID;
+	uint32_t cpuid;
+	uint8_t maxFID;
+	uint8_t startFID;
+	uint16_t pwr:12;
+	struct pstate pstates[MAXP];
+};
+
+struct cpuentry entr[] = {
+	/*rev E single core */
+	{152, 0xc, 0x20f51, 0x12, 0x12, 926,
+	 {{2400, 1350, 900}, {2200, 1300, 766},
+	  {2000, 1250, 651}, {1800, 1200, 522},
+	  {1000, 1100, 320}}},
+	{252, 0x10, 0x20f51, 0x12, 0x12, 926,
+	 {{2400, 1350, 900}, {2200, 1300, 766},
+	  {2000, 1250, 651}, {1800, 1200, 522},
+	  {1000, 1100, 320}}},
+	{852, 0x14, 0x20f51, 0x12, 0x12, 926,
+	 {{2400, 1350, 900}, {2200, 1300, 766},
+	  {2000, 1250, 651}, {1800, 1200, 522},
+	  {1000, 1100, 320}}},
+	{254, 0x10, 0x20f51, 0x14, 0x14, 926,
+	 {{2600, 1350, 902}, {2400, 1300, 770},
+	  {2200, 1250, 657}, {2000, 1200, 559},
+	  {1800, 1150, 476}, {1000, 1100, 361}}},
+	{854, 0x14, 0x20f51, 0x14, 0x14, 926,
+	 {{2600, 1350, 902}, {2400, 1300, 770},
+	  {2200, 1250, 657}, {2000, 1200, 559},
+	  {1800, 1150, 476}, {1000, 1100, 361}}},
+	{242, 0x10, 0x20f51, 0x8, 0x8, 853,
+	 {}},
+	{842, 0x10, 0x20f51, 0x8, 0x8, 853,
+	 {}},
+	{244, 0x10, 0x20f51, 0xa, 0xa, 853,
+	 {{1000, 1100, 378}}},
+	{844, 0x14, 0x20f51, 0xa, 0xa, 853,
+	 {{1000, 1100, 378}}},
+	{246, 0x10, 0x20f51, 0xc, 0xc, 853,
+	 {{1800, 1350, 853}, 
+	 {1000, 1100, 378}}},
+	{846, 0x14, 0x20f51, 0xc, 0xc, 853,
+	 {{1800, 1350, 853},
+	 {1000, 1100, 378}}},
+	{242, 0x10, 0x20f51, 0x8, 0x8, 853,
+	 {}},
+	{842, 0x14, 0x20f51, 0x8, 0x8, 853,
+	 {}},
+	{244, 0x10, 0x20f51, 0xa, 0xa, 853,
+	 {{1000, 1100, 378}}},
+	{844, 0x14, 0x20f51, 0xa, 0xa, 853,
+	 {{1000, 1100, 378}}},
+	{246, 0x10, 0x20f51, 0xc, 0xc, 853,
+	 {{1800, 1350, 827}, {1000, 1100, 366}}},
+	{846, 0x14, 0x20f51, 0xc, 0xc, 853,
+	 {{1800, 1350, 827}, {1000, 1100, 366}}},
+	{248, 0x10, 0x20f51, 0xe, 0xe, 853,
+	 {{2000, 1350, 827}, {1800, 1300, 700},
+	  {1000, 1100, 366}}},
+	{848, 0x14, 0x20f51, 0xe, 0xe, 853,
+	 {{2000, 1350, 827}, {1800, 1300, 700},
+	  {1000, 1100, 366}}},
+	{250, 0x10, 0x20f51, 0x10, 0x10, 853,
+	 {{2200, 1350, 853}, {2000, 1300, 827},
+	  {1800, 1250, 702}, {1000, 1100, 301}}},
+	{850, 0x14, 0x20f51, 0x10, 0x10, 853,
+	 {{2200, 1350, 853}, {2000, 1300, 827},
+	  {1800, 1250, 702}, {1000, 1100, 301}}},
+/* begin OSK246FAA5BL */
+	{246, 0x12, 0x20f51, 0xc, 0xc, 547,
+	 {{1800, 1350, 461}, {1000, 1100, 223}}},
+	{846, 0x16, 0x20f51, 0xc, 0xc, 547,
+	 {{1800, 1350, 461}, {1000, 1100, 223}}},
+	{148, 0xe, 0x20f51, 0xe, 0xe, 547,
+	 {{2000, 1350, 521}, {1800, 1300, 459},
+	  {1000, 1100, 211}}},
+	{248, 0x12, 0x20f51, 0xe, 0xe, 547,
+	 {{2000, 1350, 521}, {1800, 1300, 459},
+	  {1000, 1100, 211}}},
+	{848, 0x16, 0x20f51, 0xe, 0xe, 547,
+	 {{2000, 1350, 521}, {1800, 1300, 459},
+	  {1000, 1100, 211}}},
+	{250, 0x12, 0x20f51, 0x10, 0x10, 547,
+	 {{2200, 1350, 521}, {2000, 1300, 440},
+	  {1800, 1250, 379}, {1000, 1100, 199}}},
+	{850, 0x16, 0x20f51, 0x10, 0x10, 547,
+	 {{2200, 1350, 521}, {2000, 1300, 440},
+	  {1800, 1250, 379}, {1000, 1100, 199}}},
+	{144, 0xc, 0x20f71, 0xa, 0xa, 670,
+	 {{1000, 1100, 296}}},
+	{148, 0xc, 0x20f71, 0xe, 0xe, 853,
+	 {{2000, 1350, 830}, {1800, 1300, 704},
+	 {1000, 1100, 296}}},
+	{152, 0xc, 0x20f71, 0x12, 0x12, 104,
+	 {{2400, 1350, 1016}, {2200, 1300, 863},
+	 {2000, 1250, 732}, {1800, 1200, 621},
+	  {1000, 1100, 419}}},
+	{146, 0xc, 0x20f71, 0xc, 0xc, 670,
+	 {{1800, 1350, 647}, {1000, 1100, 286}}},
+	{150, 0xc, 0x20f71, 0x10, 0x10, 853,
+	{{2200, 1350, 830}, {2000, 1300, 706},
+	{1800, 1250, 596}, {1000, 1100, 350}}},
+	{154, 0xc, 0x20f71, 0x14, 0x14, 1040,
+	{{2600, 1350, 1017}, {2400, 1300, 868},
+	{2200, 1250, 740}, {2000, 1200, 630},
+	{1800, 1150, 537}, {1000, 1100, 416}}},
+	/* rev E dualcore */
+	{165, 0x2c, 0x20f12, 0xa, 0xa, 950,
+	 {{1000, 1100, 406}}},
+	{265, 0x30, 0x20f12, 0xa, 0xa, 950,
+	 {{1000, 1100, 406}}},
+	{865, 0x34, 0x20f12, 0xa, 0xa, 950,
+	 {{1000, 1100, 406}}},
+	{270, 0x30, 0x20f12, 0xc, 0xc, 950,
+	 {{1800, 1300, 903}, {1000, 1100, 383}}},
+	{870, 0x34, 0x20f12, 0xc, 0xc, 950,
+	 {{1800, 1300, 903}, {1000, 1100, 383}}},
+	{275, 0x30, 0x20f12, 0xe, 0xe, 950,
+	 {{2000, 1300, 903}, {1800, 1250, 759},
+	 {1000, 1100, 361}}},
+	{875, 0x34, 0x20f12, 0xe, 0xe, 950,
+	 {{2000, 1300, 903}, {1800, 1250, 759},
+	 {1000, 1100, 361}}},
+	{280, 0x30, 0x20f12, 0x10, 0x10, 926,
+	 {{2400, 1350, 900}, {2200, 1300, 766},
+	 {1800, 1200, 552}, {1000, 1100, 320}}},
+	{880, 0x34, 0x20f12, 0x10, 0x10, 926,
+	 {{2400, 1350, 900}, {2200, 1300, 766},
+	 {1800, 1200, 552}, {1000, 1100, 320}}},
+	{170, 0x2c, 0x20f32, 0xc, 0xc, 1100,
+	 {{1800, 1300, 1056}, {1000, 1100, 514}}},
+	{175, 0x2c, 0x20f32, 0xe, 0xe, 1100,
+	 {{2000, 1300, 1056}, {1800, 1250, 891},
+	  {1000, 1100, 490}}},
+	{260, 0x32, 0x20f32, 0x8, 0x8, 550,
+	 {}},
+	{860, 0x36, 0x20f32, 0x8, 0x8, 550,
+	 {}},
+	{165, 0x2e, 0x20f32, 0xa, 0xa, 550,
+	 {{1000, 1100, 365}}},
+	{265, 0x32, 0x20f32, 0xa, 0xa, 550,
+	 {{1000, 1100, 365}}},
+	{865, 0x36, 0x20f32, 0xa, 0xa, 550,
+	 {{1000, 1100, 365}}},
+	{270, 0x32, 0x20f12, 0xc, 0xc, 550,
+	 {{1800, 1150, 520}, {1000, 1100, 335}}},
+	{870, 0x36, 0x20f12, 0xc, 0xc, 550,
+	 {{1800, 1150, 520}, {1000, 1100, 335}}},
+	{180, 0x2c, 0x20f32, 0x10, 0x10, 1100,
+	 {{2200, 1300, 1056}, {2000, 1250, 891},
+	  {1800, 1200, 748}, {1000, 1100, 466}}},
+	{3000, 0x4, 0x10ff0, 0xa, 0xa, 670,
+	 {{1000, 1100, 210}}},
+};
+
+static int pstates_algorithm(u32 pcontrol_blk, u8 plen, u8 onlyBSP)
+{
+
+	u8 cmp_cap;
+	struct cpuentry *data = NULL;
+	uint32_t control;
+	int i = 0, index, len = 0, Pstate_num = 0;
+	msr_t msr;
+	u8 Pstate_fid[10];
+	u16 Pstate_feq[10];
+	u8 Pstate_vid[10];
+	u32 Pstate_power[10];
+	u8 Max_fid, Start_fid, Start_vid, Max_vid;
+	struct cpuid_result cpuid1 = cpuid(0x80000001);
+
+	msr = rdmsr(0xc0010042);
+	Max_fid = (msr.lo & 0x3F0000) >> 16;
+	Max_vid = (msr.hi & 0x3F0000) >> 16;
+	Start_fid = (msr.lo & 0x3F00) >> 8;
+	Start_vid = (msr.hi & 0x3F00) >> 8;
+
+	cmp_cap =
+	    (pci_read_config16(dev_find_slot(0, PCI_DEVFN(0x18, 3)), 0xE8) &
+	     0x3000) >> 12;
+
+	for (i = 0; i < ARRAY_SIZE(entr); i++) {
+		if ((entr[i].cpuid == cpuid1.eax)
+		    && (entr[i].startFID == Start_fid)
+		    && (entr[i].maxFID == Max_fid)
+		    && (entr[i].brandID == ((u8 )((cpuid1.ebx >> 6) & 0xff)))) {
+			data = &entr[i];
+			break;
+		}
+	}
+
+	if (data == NULL) {
+		printk(BIOS_WARNING, "Unknown CPU, please update the powernow_acpi.c\n");
+		return 0;
+	}
+
+	/* IRT 80us, PLL_LOCK_TIME 2us, MVS 25mv, VST 100us */
+	control = (3 << 30) | (2 << 20) | (0 << 18) | (5 << 11) | (1 << 29);
+	len = 0;
+	Pstate_num = 0;
+
+	Pstate_fid[Pstate_num] = Max_fid;
+	Pstate_feq[Pstate_num] = fid_to_freq(Max_fid);
+	Pstate_vid[Pstate_num] = Max_vid;
+	Pstate_power[Pstate_num] = data->pwr * 100;
+	Pstate_num++;
+
+	do {
+		Pstate_fid[Pstate_num] = freq_to_fid(data->pstates[Pstate_num - 1].freqMhz) & 0x3f;
+		Pstate_feq[Pstate_num] = data->pstates[Pstate_num - 1].freqMhz;
+		Pstate_vid[Pstate_num] = vid_to_reg(data->pstates[Pstate_num - 1].voltage);
+		Pstate_power[Pstate_num] = data->pstates[Pstate_num - 1].tdp * 100;
+		Pstate_num++;
+	} while ((Pstate_num < MAXP) && (data->pstates[Pstate_num].freqMhz != 0));
+
+	for (i=0;i<Pstate_num;i++)
+		printk(BIOS_DEBUG, "P#%d freq %d [MHz] voltage %d [mV] TDP %d [mW]\n", i,
+		       Pstate_feq[i],
+		       vid_from_reg(Pstate_vid[i]),
+		       Pstate_power[i]);
+
+	for (index = 0; index < (cmp_cap + 1); index++) {
+		len += write_pstates_for_core(Pstate_num, Pstate_feq, Pstate_vid,
+				Pstate_fid, Pstate_power, index,
+				pcontrol_blk, plen, onlyBSP, control);
+	}
+
+	return len;
+}
+
+#endif
+
+
 int amd_model_fxx_generate_powernow(u32 pcontrol_blk, u8 plen, u8 onlyBSP)
 {
 	int lens;
@@ -388,11 +655,3 @@ 
 	return lens;
 }
 
-#else
-
-int amd_model_fxx_generate_powernow(u32 pcontrol_blk, u8 plen, u8 onlyBSP)
-{
-	return 0;
-}
-
-#endif
Index: src/southbridge/amd/sb700/early_setup.c
===================================================================
--- src/southbridge/amd/sb700/early_setup.c.orig	2010-12-25 17:10:23.000000000 +0100
+++ src/southbridge/amd/sb700/early_setup.c	2010-12-25 17:12:23.000000000 +0100
@@ -231,6 +231,11 @@ 
 	pmio_write(0x42, byte);
 
 	pmio_write(0x89, 0x10);
+
+	/* Toggle the LDT_STOP# during FID/VID Change, this bit is documented
+	   only in SB600!
+	*/
+	pmio_write(0x67, 0x2);
 }
 
 void hard_reset(void)