root/arch/i386/i386/powernow.c

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

DEFINITIONS

This source file includes following definitions.
  1. k6_powernow_init
  2. k6_powernow_setperf

    1 /*      $OpenBSD: powernow.c,v 1.3 2006/12/12 23:14:27 dim Exp $        */
    2 /*
    3  * Copyright (c) 2004 Ted Unangst
    4  * All rights reserved.
    5  *
    6  * Permission to use, copy, modify, and distribute this software for any
    7  * purpose with or without fee is hereby granted, provided that the above
    8  * copyright notice and this permission notice appear in all copies.
    9  *
   10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   17  */
   18 
   19 /*
   20  * AMD K6 PowerNow driver, see AMD tech doc #23525
   21  * Numerous hints from Linux cpufreq driver
   22  */
   23 
   24 #include <sys/param.h>
   25 #include <sys/sysctl.h>
   26 
   27 #include <machine/cpu.h>
   28 #include <machine/cpufunc.h>
   29 #include <machine/specialreg.h>
   30 #include <machine/pio.h>
   31 
   32 /* table 27 in amd 23535.  entries after 45 taken from linux cpufreq */
   33 struct {
   34         int mult;       /* not actually used, maybe for cpuspeed */
   35         int magic;
   36 } k6_multipliers[] = {
   37         { 20, 4 },
   38         { 30, 5 },
   39         { 35, 7 },
   40         { 40, 2 },
   41         { 45, 0 },
   42         { 55, 3 },
   43         { 50, 1 },
   44         { 60, 6 },
   45 };
   46 #define NUM_K6_ENTRIES (sizeof k6_multipliers / sizeof k6_multipliers[0])
   47 
   48 int     k6_maxindex;    /* no setting higher than this */
   49 
   50 /* linux says: "it doesn't matter where, as long as it is unused */
   51 #define K6PORT 0xfff0
   52 
   53 void
   54 k6_powernow_init(void)
   55 {
   56         uint64_t msrval;
   57         uint32_t portval;
   58         int i;
   59 
   60         /* on */
   61         msrval = K6PORT | 0x1;
   62         wrmsr(MSR_K6_EPMR, msrval);
   63         /* read */
   64         portval = inl(K6PORT + 8);
   65         /* off */
   66         wrmsr(MSR_K6_EPMR, 0LL);
   67 
   68         portval = (portval >> 5) & 7;
   69 
   70         for (i = 0; i < NUM_K6_ENTRIES; i++)
   71                 if (portval == k6_multipliers[i].magic) {
   72                         k6_maxindex = i;
   73                         break;
   74                 }
   75         if (i == NUM_K6_ENTRIES) {
   76                 printf("bad value for current multiplier\n");
   77                 return;
   78         }
   79 
   80         cpu_setperf = k6_powernow_setperf;
   81 }
   82 
   83 void
   84 k6_powernow_setperf(int level)
   85 {
   86         uint64_t msrval;
   87         uint32_t portval;
   88         int index;
   89 
   90         index = level * k6_maxindex / 100;
   91 
   92         /* on */
   93         msrval = K6PORT | 0x1;
   94         wrmsr(MSR_K6_EPMR, msrval);
   95         /* read and update */
   96         portval = inl(K6PORT + 8);
   97         portval &= 0xf;
   98         portval |= 1 << 12 | 1 << 10 | 1 << 9 |
   99             k6_multipliers[index].magic << 5;
  100         outl(K6PORT + 8, portval);
  101         /* off */
  102         wrmsr(MSR_K6_EPMR, 0LL);
  103 }

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