It adds support for automatic PSS object generation for AMD pre fam Fh CPU. Those...
[coreboot.git] / src / cpu / amd / model_fxx / powernow_acpi.c
index 6ad1686dadc28a07c3e12bca8b72caf0968e3d6c..09f6ae56d71fed9157edde35a7eb1b541492a7be 100644 (file)
@@ -5,8 +5,8 @@
  * Copyright (C) 2009 Rudolf Marek <r.marek@assembler.cz>
  *
  * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License v2 as published by
- * the Free Software Foundation.
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -32,7 +32,8 @@
 
 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;
 
        if ((onlyBSP) && (coreID != 0)) {
@@ -48,16 +49,8 @@ static int write_pstates_for_core(u8 pstate_num, u16 *pstate_feq, u8 *pstate_vid
        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) |
@@ -67,7 +60,7 @@ static int write_pstates_for_core(u8 pstate_num, u16 *pstate_feq, u8 *pstate_vid
                                                pstate_power[i],
                                                0x64,
                                                0x7,
-                                               control,
+                                               c2,
                                                status);
        }
        /* update the package  size */
@@ -79,6 +72,8 @@ static int write_pstates_for_core(u8 pstate_num, u16 *pstate_feq, u8 *pstate_vid
        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
@@ -88,7 +83,7 @@ static int pstates_algorithm(u32 pcontrol_blk, u8 plen, u8 onlyBSP)
 {
        int len;
        u8 processor_brand[49];
-       u32 *v;
+       u32 *v, control;
        struct cpuid_result cpuid1;
 
        struct power_limit_encoding {
@@ -155,21 +150,21 @@ static int pstates_algorithm(u32 pcontrol_blk, u8 plen, u8 onlyBSP)
        v[10] = cpuid1.ecx;
        v[11] = cpuid1.edx;
        processor_brand[48] = 0;
-       printk_info("processor_brand=%s\n", processor_brand);
+       printk(BIOS_INFO, "processor_brand=%s\n", processor_brand);
 
        /*
         * Based on the CPU socket type,cmp_cap and pwr_lmt , get the power limit.
         * socket_type : 0x10 SocketF; 0x11 AM2/ASB1 ; 0x12 S1G1
         * cmp_cap : 0x0 SingleCore ; 0x1 DualCore
         */
-       printk_info("Pstates Algorithm ...\n");
+       printk(BIOS_INFO, "Pstates Algorithm ...\n");
        cmp_cap =
            (pci_read_config16(dev_find_slot(0, PCI_DEVFN(0x18, 3)), 0xE8) &
             0x3000) >> 12;
        cpuid1 = cpuid(0x80000001);
        pwr_lmt = ((cpuid1.ebx & 0x1C0) >> 5) | ((cpuid1.ebx & 0x4000) >> 14);
        for (index = 0; index <= sizeof(TDP) / sizeof(TDP[0]); index++)
-               if (TDP[index].socket_type == CPU_SOCKET_TYPE &&
+               if (TDP[index].socket_type == CONFIG_CPU_SOCKET_TYPE &&
                    TDP[index].cmp_cap == cmp_cap &&
                    TDP[index].pwr_lmt == pwr_lmt) {
                        power_limit = TDP[index].power_limit;
@@ -180,7 +175,7 @@ static int pstates_algorithm(u32 pcontrol_blk, u8 plen, u8 onlyBSP)
        /* See if the CPUID(0x80000007) returned EDX[2:1]==11b */
        cpuid1 = cpuid(0x80000007);
        if ((cpuid1.edx & 0x6) != 0x6) {
-               printk_info("No valid set of P-states\n");
+               printk(BIOS_INFO, "No valid set of P-states\n");
                goto write_pstates;
        }
 
@@ -203,7 +198,7 @@ static int pstates_algorithm(u32 pcontrol_blk, u8 plen, u8 onlyBSP)
                PstateStep_coef = 2;
 
        if (IntPstateSup == 0) {
-               printk_info("No intermediate P-states are supported\n");
+               printk(BIOS_INFO, "No intermediate P-states are supported\n");
                goto write_pstates;
        }
 
@@ -351,12 +346,12 @@ static int pstates_algorithm(u32 pcontrol_blk, u8 plen, u8 onlyBSP)
        /* Print Pstate freq,vid,volt,power */
 
        for (index = 0; index < Pstate_num; index++) {
-               printk_info("Pstate_freq[%d] = %dMHz\t", index,
+               printk(BIOS_INFO, "Pstate_freq[%d] = %dMHz\t", index,
                            Pstate_feq[index]);
-               printk_info("Pstate_vid[%d] = %d\t", index, Pstate_vid[index]);
-               printk_info("Pstate_volt[%d] = %dmv\t", index,
+               printk(BIOS_INFO, "Pstate_vid[%d] = %d\t", index, Pstate_vid[index]);
+               printk(BIOS_INFO, "Pstate_volt[%d] = %dmv\t", index,
                            Pstate_volt[index]);
-               printk_info("Pstate_power[%d] = %dmw\n", index,
+               printk(BIOS_INFO, "Pstate_power[%d] = %dmw\n", index,
                            Pstate_power[index]);
        }
 
@@ -365,16 +360,290 @@ write_pstates:
 
        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, 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;
+}
+/* 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; /* in MHz */
+       uint16_t voltage; /* in mV */
+       uint16_t tdp; /* in W * 10 */
+};
+
+struct cpuentry {
+       uint16_t modelnr; /* numeric model value, unused in code */
+       uint8_t brandID; /* CPUID 8000_0001h EBX [11:6] (BrandID) */
+       uint32_t cpuid; /* CPUID 8000_0001h EAX [31:0] (CPUID) */
+       uint8_t maxFID; /* FID/VID Status MaxFID Field */
+       uint8_t startFID; /* FID/VID Status StartFID Field */
+       uint16_t pwr:12; /* Thermal Design Power of Max P-State  *10 (fixed point) */
+       /* Other MAX P state are read from CPU, other P states in following table */
+       struct pstate pstates[MAXP];
+};
+
+struct cpuentry entr[] = {
+       /* rev E single core, check OSA152FAA5BK */
+       {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);
+                               pcontrol_blk, plen, onlyBSP, control);
        }
 
        return len;
 }
 
-int amd_model_fxx_generate_powernow(u32 pcontrol_blk, u8 plen, u8 onlyBSP) {
+#endif
+
+
+int amd_model_fxx_generate_powernow(u32 pcontrol_blk, u8 plen, u8 onlyBSP)
+{
        int lens;
        char pscope[] = "\\_PR";
 
@@ -384,3 +653,4 @@ int amd_model_fxx_generate_powernow(u32 pcontrol_blk, u8 plen, u8 onlyBSP) {
        acpigen_patch_len(lens - 1);
        return lens;
 }
+