root/arch/i386/i386/powernow-k8.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. k8pnow_read_pending_wait
  2. k8_powernow_setperf
  3. k8pnow_decode_pst
  4. k8pnow_states
  5. k8pnow_acpi_states
  6. k8pnow_acpi_pss_changed
  7. k8pnow_acpi_init
  8. k8_powernow_init

    1 /*      $OpenBSD: powernow-k8.c,v 1.23 2007/05/31 17:49:16 gwk Exp $ */
    2 
    3 /*
    4  * Copyright (c) 2004 Martin Végiard.
    5  * Copyright (c) 2004-2005 Bruno Ducrot
    6  * Copyright (c) 2004 FUKUDA Nobuhiko <nfukuda@spa.is.uec.ac.jp>
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   27  */
   28 /* AMD POWERNOW K8 driver */
   29 
   30 #include <sys/types.h>
   31 #include <sys/param.h>
   32 #include <sys/systm.h>
   33 #include <sys/malloc.h>
   34 #include <sys/sysctl.h>
   35 
   36 #include <dev/isa/isareg.h>
   37 #include <i386/isa/isa_machdep.h>
   38 
   39 #include <machine/cpu.h>
   40 #include <machine/cpufunc.h>
   41 #include <machine/bus.h>
   42 
   43 #include "acpicpu.h"
   44 
   45 #if NACPICPU > 0
   46 #include <dev/acpi/acpidev.h>
   47 #include <dev/acpi/acpivar.h>
   48 #endif
   49 
   50 #define BIOS_START                      0xe0000
   51 #define BIOS_LEN                        0x20000
   52 #define BIOS_STEP                       16
   53 
   54 /*
   55  * MSRs and bits used by PowerNow! technology
   56  */
   57 #define MSR_AMDK7_FIDVID_CTL            0xc0010041
   58 #define MSR_AMDK7_FIDVID_STATUS         0xc0010042
   59 #define AMD_PN_FID_VID                  0x06
   60 
   61 /* Bitfields used by K8 */
   62 
   63 #define PN8_CTR_FID(x)                  ((x) & 0x3f)
   64 #define PN8_CTR_VID(x)                  (((x) & 0x1f) << 8)
   65 #define PN8_CTR_PENDING(x)              (((x) & 1) << 32)
   66 
   67 #define PN8_STA_CFID(x)                 ((x) & 0x3f)
   68 #define PN8_STA_SFID(x)                 (((x) >> 8) & 0x3f)
   69 #define PN8_STA_MFID(x)                 (((x) >> 16) & 0x3f)
   70 #define PN8_STA_PENDING(x)              (((x) >> 31) & 0x01)
   71 #define PN8_STA_CVID(x)                 (((x) >> 32) & 0x1f)
   72 #define PN8_STA_SVID(x)                 (((x) >> 40) & 0x1f)
   73 #define PN8_STA_MVID(x)                 (((x) >> 48) & 0x1f)
   74 
   75 /* Reserved1 to powernow k8 configuration */
   76 #define PN8_PSB_VERSION                 0x14
   77 #define PN8_PSB_TO_RVO(x)               ((x) & 0x03)
   78 #define PN8_PSB_TO_IRT(x)               (((x) >> 2) & 0x03)
   79 #define PN8_PSB_TO_MVS(x)               (((x) >> 4) & 0x03)
   80 #define PN8_PSB_TO_BATT(x)              (((x) >> 6) & 0x03)
   81 
   82 /* ACPI ctr_val status register to powernow k8 configuration */
   83 #define PN8_ACPI_CTRL_TO_FID(x)         ((x) & 0x3f)
   84 #define PN8_ACPI_CTRL_TO_VID(x)         (((x) >> 6) & 0x1f)
   85 #define PN8_ACPI_CTRL_TO_VST(x)         (((x) >> 11) & 0x1f)
   86 #define PN8_ACPI_CTRL_TO_MVS(x)         (((x) >> 18) & 0x03)
   87 #define PN8_ACPI_CTRL_TO_PLL(x)         (((x) >> 20) & 0x7f)
   88 #define PN8_ACPI_CTRL_TO_RVO(x)         (((x) >> 28) & 0x03)
   89 #define PN8_ACPI_CTRL_TO_IRT(x)         (((x) >> 30) & 0x03)
   90 
   91 #define PN8_PLL_LOCK(x)                 ((x) * 1000/5)
   92 #define WRITE_FIDVID(fid, vid, ctrl)    \
   93         wrmsr(MSR_AMDK7_FIDVID_CTL,     \
   94             (((ctrl) << 32) | (1ULL << 16) | ((vid) << 8) | (fid)))
   95 
   96 #define COUNT_OFF_IRT(irt)              DELAY(10 * (1 << (irt)))
   97 #define COUNT_OFF_VST(vst)              DELAY(20 * (vst))
   98 
   99 #define FID_TO_VCO_FID(fid)             \
  100         (((fid) < 8) ? (8 + ((fid) << 1)) : (fid))
  101 
  102 #define POWERNOW_MAX_STATES             16
  103 
  104 struct k8pnow_state {
  105         int freq;
  106         uint8_t fid;
  107         uint8_t vid;
  108 };
  109 
  110 struct k8pnow_cpu_state {
  111         struct k8pnow_state state_table[POWERNOW_MAX_STATES];
  112         unsigned int n_states;
  113         unsigned int sgtc;
  114         unsigned int vst;
  115         unsigned int mvs;
  116         unsigned int pll;
  117         unsigned int rvo;
  118         unsigned int irt;
  119         int low;
  120 };
  121 
  122 struct psb_s {
  123         char signature[10];     /* AMDK7PNOW! */
  124         uint8_t version;
  125         uint8_t flags;
  126         uint16_t ttime;         /* Min Settling time */
  127         uint8_t reserved;
  128         uint8_t n_pst;
  129 };
  130 
  131 struct pst_s {
  132         uint32_t cpuid;
  133         uint8_t pll;
  134         uint8_t fid;
  135         uint8_t vid;
  136         uint8_t n_states;
  137 };
  138 
  139 struct k8pnow_cpu_state *k8pnow_current_state = NULL;
  140 extern int setperf_prio;
  141 
  142 int k8pnow_read_pending_wait(uint64_t *);
  143 int k8pnow_decode_pst(struct k8pnow_cpu_state *, uint8_t *);
  144 int k8pnow_states(struct k8pnow_cpu_state *, uint32_t, unsigned int,
  145     unsigned int);
  146 
  147 #if NACPICPU > 0
  148 int k8pnow_acpi_init(struct k8pnow_cpu_state *, uint64_t);
  149 void k8pnow_acpi_pss_changed(struct acpicpu_pss *, int);
  150 int k8pnow_acpi_states(struct k8pnow_cpu_state *, struct acpicpu_pss *, int,
  151     uint64_t);
  152 #endif
  153 
  154 int
  155 k8pnow_read_pending_wait(uint64_t *status)
  156 {
  157         unsigned int i = 100000;
  158 
  159         while (i--) {
  160                 *status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
  161                 if (!PN8_STA_PENDING(*status))
  162                         return 0;
  163 
  164         }
  165         printf("k8pnow_read_pending_wait: change pending stuck.\n");
  166         return 1;
  167 }
  168 
  169 void
  170 k8_powernow_setperf(int level)
  171 {
  172         unsigned int i;
  173         uint64_t status;
  174         int cfid, cvid, fid = 0, vid = 0, rvo;
  175         u_int val;
  176         struct k8pnow_cpu_state *cstate;
  177 
  178         /*
  179          * We dont do a k8pnow_read_pending_wait here, need to ensure that the
  180          * change pending bit isn't stuck,
  181          */
  182         status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
  183         if (PN8_STA_PENDING(status))
  184                 return;
  185         cfid = PN8_STA_CFID(status);
  186         cvid = PN8_STA_CVID(status);
  187 
  188         cstate = k8pnow_current_state;
  189 
  190         i = ((level * cstate->n_states) + 1) / 101;
  191         if (i >= cstate->n_states)
  192                 i = cstate->n_states - 1;
  193         fid = cstate->state_table[i].fid;
  194         vid = cstate->state_table[i].vid;
  195 
  196         if (fid == cfid && vid == cvid)
  197                 return;
  198 
  199         /*
  200          * Phase 1: Raise core voltage to requested VID if frequency is
  201          * going up.
  202          */
  203         while (cvid > vid) {
  204                 val = cvid - (1 << cstate->mvs);
  205                 WRITE_FIDVID(cfid, (val > 0) ? val : 0, 1ULL);
  206                 if (k8pnow_read_pending_wait(&status))
  207                         return;
  208                 cvid = PN8_STA_CVID(status);
  209                 COUNT_OFF_VST(cstate->vst);
  210         }
  211 
  212         /* ... then raise to voltage + RVO (if required) */
  213         for (rvo = cstate->rvo; rvo > 0 && cvid > 0; --rvo) {
  214                 /* XXX It's not clear from spec if we have to do that
  215                  * in 0.25 step or in MVS.  Therefore do it as it's done
  216                  * under Linux */
  217                 WRITE_FIDVID(cfid, cvid - 1, 1ULL);
  218                 if (k8pnow_read_pending_wait(&status))
  219                         return;
  220                 cvid = PN8_STA_CVID(status);
  221                 COUNT_OFF_VST(cstate->vst);
  222         }
  223 
  224         /* Phase 2: change to requested core frequency */
  225         if (cfid != fid) {
  226                 u_int vco_fid, vco_cfid;
  227 
  228                 vco_fid = FID_TO_VCO_FID(fid);
  229                 vco_cfid = FID_TO_VCO_FID(cfid);
  230 
  231                 while (abs(vco_fid - vco_cfid) > 2) {
  232                         if (fid > cfid) {
  233                                 if (cfid > 6)
  234                                         val = cfid + 2;
  235                                 else
  236                                         val = FID_TO_VCO_FID(cfid) + 2;
  237                         } else
  238                                 val = cfid - 2;
  239                         WRITE_FIDVID(val, cvid, (uint64_t)
  240                             PN8_PLL_LOCK(cstate->pll));
  241 
  242                         if (k8pnow_read_pending_wait(&status))
  243                                 return;
  244                         cfid = PN8_STA_CFID(status);
  245                         COUNT_OFF_IRT(cstate->irt);
  246 
  247                         vco_cfid = FID_TO_VCO_FID(cfid);
  248                 }
  249 
  250                 WRITE_FIDVID(fid, cvid, (uint64_t) PN8_PLL_LOCK(cstate->pll));
  251                 if (k8pnow_read_pending_wait(&status))
  252                         return;
  253                 cfid = PN8_STA_CFID(status);
  254                 COUNT_OFF_IRT(cstate->irt);
  255         }
  256 
  257         /* Phase 3: change to requested voltage */
  258         if (cvid != vid) {
  259                 WRITE_FIDVID(cfid, vid, 1ULL);
  260                 if (k8pnow_read_pending_wait(&status))
  261                         return;
  262                 cvid = PN8_STA_CVID(status);
  263                 COUNT_OFF_VST(cstate->vst);
  264         }
  265 
  266         if (cfid == fid || cvid == vid)
  267                 cpuspeed = cstate->state_table[i].freq;
  268 }
  269 
  270 /*
  271  * Given a set of pair of fid/vid, and number of performance states,
  272  * compute state_table via an insertion sort.
  273  */
  274 int
  275 k8pnow_decode_pst(struct k8pnow_cpu_state *cstate, uint8_t *p)
  276 {
  277         int i, j, n;
  278         struct k8pnow_state state;
  279 
  280         for (n = 0, i = 0; i < cstate->n_states; i++) {
  281                 state.fid = *p++;
  282                 state.vid = *p++;
  283 
  284                 /*
  285                  * The minimum supported frequency per the data sheet is 800MHz
  286                  * The maximum supported frequency is 5000MHz.
  287                  */
  288                 state.freq = 800 + state.fid * 100;
  289                 j = n;
  290                 while (j > 0 && cstate->state_table[j - 1].freq > state.freq) {
  291                         memcpy(&cstate->state_table[j],
  292                             &cstate->state_table[j - 1],
  293                             sizeof(struct k8pnow_state));
  294                         --j;
  295                 }
  296                 memcpy(&cstate->state_table[j], &state,
  297                     sizeof(struct k8pnow_state));
  298                 n++;
  299         }
  300         return 1;
  301 }
  302 
  303 int
  304 k8pnow_states(struct k8pnow_cpu_state *cstate, uint32_t cpusig,
  305     unsigned int fid, unsigned int vid)
  306 {
  307         struct psb_s *psb;
  308         struct pst_s *pst;
  309         uint8_t *p;
  310         int i;
  311 
  312         for (p = (u_int8_t *)ISA_HOLE_VADDR(BIOS_START);
  313             p < (u_int8_t *)ISA_HOLE_VADDR(BIOS_START + BIOS_LEN); p +=
  314             BIOS_STEP) {
  315                 if (memcmp(p, "AMDK7PNOW!", 10) == 0) {
  316                         psb = (struct psb_s *)p;
  317                         if (psb->version != PN8_PSB_VERSION)
  318                                 return 0;
  319 
  320                         cstate->vst = psb->ttime;
  321                         cstate->rvo = PN8_PSB_TO_RVO(psb->reserved);
  322                         cstate->irt = PN8_PSB_TO_IRT(psb->reserved);
  323                         cstate->mvs = PN8_PSB_TO_MVS(psb->reserved);
  324                         cstate->low = PN8_PSB_TO_BATT(psb->reserved);
  325                         p+= sizeof(struct psb_s);
  326 
  327                         for (i = 0; i < psb->n_pst; ++i) {
  328                                 pst = (struct pst_s *) p;
  329 
  330                                 cstate->pll = pst->pll;
  331                                 cstate->n_states = pst->n_states;
  332                                 if (cpusig == pst->cpuid &&
  333                                     pst->fid == fid && pst->vid == vid) {
  334                                         return (k8pnow_decode_pst(cstate,
  335                                             p+= sizeof (struct pst_s)));
  336                                 }
  337                                 p += sizeof(struct pst_s) + 2
  338                                      * cstate->n_states;
  339                         }
  340                 }
  341         }
  342 
  343         return 0;
  344 
  345 }
  346 
  347 #if NACPICPU > 0
  348 
  349 int
  350 k8pnow_acpi_states(struct k8pnow_cpu_state * cstate, struct acpicpu_pss * pss,
  351     int nstates, uint64_t status)
  352 {
  353         struct k8pnow_state state;
  354         int j, k, n;
  355         uint32_t ctrl;
  356 
  357         k = -1;
  358 
  359         for (n = 0; n < cstate->n_states; n++) {
  360                 if (status == pss[n].pss_status)
  361                         k = n;
  362                 ctrl = pss[n].pss_ctrl;
  363                 state.fid = PN8_ACPI_CTRL_TO_FID(ctrl);
  364                 state.vid = PN8_ACPI_CTRL_TO_VID(ctrl);
  365 
  366                 state.freq = pss[n].pss_core_freq;
  367                 j = n;
  368                 while (j > 0 && cstate->state_table[j - 1].freq > state.freq) {
  369                         memcpy(&cstate->state_table[j],
  370                             &cstate->state_table[j - 1],
  371                             sizeof(struct k8pnow_state));
  372                         --j;
  373                 }
  374                 memcpy(&cstate->state_table[j], &state,
  375                     sizeof(struct k8pnow_state));
  376         }
  377 
  378         return k;
  379 }
  380 
  381 void
  382 k8pnow_acpi_pss_changed(struct acpicpu_pss * pss, int npss)
  383 {
  384         int curs;
  385         struct k8pnow_cpu_state * cstate;
  386         uint32_t ctrl;
  387         uint64_t status;
  388 
  389         status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
  390         cstate = k8pnow_current_state;
  391 
  392         curs = k8pnow_acpi_states(cstate, pss, npss, status);
  393         ctrl = pss[curs].pss_ctrl;
  394         cstate->vst = PN8_ACPI_CTRL_TO_VST(ctrl);
  395         cstate->mvs = PN8_ACPI_CTRL_TO_MVS(ctrl);
  396         cstate->pll = PN8_ACPI_CTRL_TO_PLL(ctrl);
  397         cstate->irt = PN8_ACPI_CTRL_TO_IRT(ctrl);
  398         cstate->low = 0;
  399         cstate->n_states = npss;
  400 }
  401 
  402 int
  403 k8pnow_acpi_init(struct k8pnow_cpu_state * cstate, uint64_t status)
  404 {
  405         int curs;
  406         uint32_t ctrl;
  407         struct acpicpu_pss *pss;
  408 
  409         cstate->n_states = acpicpu_fetch_pss(&pss);
  410         if (cstate->n_states == 0)
  411                 return 0;
  412         acpicpu_set_notify(k8pnow_acpi_pss_changed);
  413 
  414         curs = k8pnow_acpi_states(cstate, pss, cstate->n_states, status);
  415         ctrl = pss[curs].pss_ctrl;
  416 
  417         cstate->vst = PN8_ACPI_CTRL_TO_VST(ctrl);
  418         cstate->mvs = PN8_ACPI_CTRL_TO_MVS(ctrl);
  419         cstate->pll = PN8_ACPI_CTRL_TO_PLL(ctrl);
  420         cstate->irt = PN8_ACPI_CTRL_TO_IRT(ctrl);
  421         cstate->low = 0;
  422 
  423         return 1;
  424 }
  425 
  426 #endif /* NACPICPU */
  427 
  428 void
  429 k8_powernow_init(void)
  430 {
  431         uint64_t status;
  432         u_int maxfid, maxvid, i;
  433         struct k8pnow_cpu_state *cstate;
  434         struct k8pnow_state *state;
  435         struct cpu_info * ci;
  436         char * techname = NULL;
  437         u_int32_t regs[4];
  438 
  439         ci = curcpu();
  440 
  441         if (setperf_prio > 1)
  442                 return;
  443 
  444         if (k8pnow_current_state)
  445                 return;
  446 
  447         cpuid(0x80000000, regs);
  448         if (regs[0] < 0x80000007)
  449                 return;
  450 
  451         cpuid(0x80000007, regs);
  452         if (!(regs[3] & AMD_PN_FID_VID))
  453                 return;
  454 
  455         /* Extended CPUID signature value */
  456         cpuid(0x80000001, regs);
  457 
  458         cstate = malloc(sizeof(struct k8pnow_cpu_state), M_DEVBUF, M_NOWAIT);
  459         if (!cstate)
  460                 return;
  461 
  462         cstate->n_states = 0;
  463         status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
  464         maxfid = PN8_STA_MFID(status);
  465         maxvid = PN8_STA_MVID(status);
  466 
  467         /*
  468         * If start FID is different to max FID, then it is a
  469         * mobile processor.  If not, it is a low powered desktop
  470         * processor.
  471         */
  472         if (PN8_STA_SFID(status) != PN8_STA_MFID(status))
  473                 techname = "PowerNow! K8";
  474         else
  475                 techname = "Cool'n'Quiet K8";
  476 
  477 #if NACPICPU > 0
  478         /* If we have acpi check acpi first */
  479         if (!k8pnow_acpi_init(cstate, status))
  480 #endif
  481         {
  482                 if (!k8pnow_states(cstate, ci->ci_signature, maxfid, maxvid))
  483                         k8pnow_states(cstate, regs[0], maxfid, maxvid);
  484         }
  485         if (cstate->n_states) {
  486                 printf("%s: %s %d MHz: speeds:",
  487                     ci->ci_dev.dv_xname, techname, cpuspeed);
  488                 for (i = cstate->n_states; i > 0; i--) {
  489                         state = &cstate->state_table[i-1];
  490                         printf(" %d", state->freq);
  491                 }
  492                 printf(" MHz\n");
  493                 k8pnow_current_state = cstate;
  494                 cpu_setperf = k8_powernow_setperf;
  495                 setperf_prio = 1;
  496                 return;
  497         }
  498         free(cstate, M_DEVBUF);
  499 }

/* [<][>][^][v][top][bottom][index][help] */