/*
FVCool version 1.04
VCool for FreeBSD (and possibly Liunx):
CPU cooling software for AMD's Athlon/Duron motherboard.
*/
/* Original is VCool of Marin Peters in the following */
/***************************************************************************
LVCool.cpp
Sets the "enable Bus disconnect on STPGNT" bit on the northbridge
and runs and idle loop that puts the CPU into STPGNT mode.
Since I'm not a Linux guy just the minimum approach here *g*
--------------------------------
begin : Fri Jul 6 10:13:24 CEST 2001
copyright : (C) 2001 by Martin Peters
email : mpet@bigfoot.de
URL : http://vcool.occludo.net/
***************************************************************************/
/* Data for Athlon/Duron Cooling information by Hidemi Oya */
/***************************************************************************
CoolON
URL : http://homepage2.nifty.com/coolon/ (Japanese)
***************************************************************************/
/*
<<< BASIC DATASHEETS >>>
disconnect CPU bus at HLT or STPGNT state: bit in Northbridge
AMD 751/761
PCI conf. register 0x62 bit 1 and bit 2 i.e. |= 0x06
(PCI conf. register 0x60 bit 17 and bit 18 i.e. |= 0x060000)
AMD 762
PCI conf. register 0x62 bit 1 i.e. |= 0x02
(PCI conf. register 0x60 bit 17 i.e. |= 0x020000)
PCI conf. register 0x6A bit 1 i.e. |= 0x02
(PCI conf. register 0x68 bit 17 i.e. |= 0x020000)
VIA KT133/A/KM133/KL133/KN133, KX133, KLE133
PCI conf. register 0x52 bit 7 i.e. |= 0x80 < --- STPGNT
(PCI conf. register 0x50 bit 23 i.e. |= 0x800000)
PCI conf. register 0x70 bit 3 i.e. |= 0x08
(PCI conf. register 0x70 bit 3 i.e. |= 0x08)
with additional ACPI operation: set STPGNT state in idle-loop.
This is done by reading ACPI Processor Level 2 register.
VIA KT266/A/KT333, KM266/KL266/KM333, KN266
PCI conf. register 0x92 bit 7 i.e. |= 0x80 < --- STPGNT
(PCI conf. register 0x90 bit 23 i.e. |= 0x800000)
PCI conf. register 0x95 bit 1 i.e. |= 0x02 < --- HLT
(PCI conf. register 0x94 bit 9 i.e. |= 0x0200)
PCI conf. register 0x70 bit 3 i.e. |= 0x08
(PCI conf. register 0x70 bit 3 i.e. |= 0x08)
VIA KT400/A/KT600, KM400
PCI conf. register 0xD2 bit 7 i.e. |= 0x80 < --- STPGNT
(PCI conf. register 0xD0 bit 23 i.e. |= 0x800000)
PCI conf. register 0xD5 bit 1 i.e. |= 0x02 < --- HLT
(PCI conf. register 0xD4 bit 9 i.e. |= 0x0200)
PCI conf. register 0x70 bit 3 i.e. |= 0x08
(PCI conf. register 0x70 bit 3 i.e. |= 0x08)
VIA KT880
PCI conf. register 0x82 bit 7 i.e. |= 0x80 < --- STPGNT
(PCI conf. register 0x80 bit 23 i.e. |= 0x800000)
PCI conf. register 0x85 bit 1 i.e. |= 0x02 < --- HLT
(PCI conf. register 0x84 bit 9 i.e. |= 0x0200)
Sis 730, 733
PCI conf. register 0x6B bit 0 i.e. |= 0x01
(PCI conf. register 0x68 bit 24 i.e. |= 0x01000000)
Sis 735, 741, 740, 745
PCI conf. register 0x6A bit 0&1 i.e. |= 0x03
(PCI conf. register 0x68 bit 16&17 i.e. |= 0x030000)
Sis 746, 748
PCI conf. register 0x6C bit 0 i.e. |= 0x01
(PCI conf. register 0x6C bit 0 i.e. |= 0x00000001)
NVidia nForce
PCI conf. register 0x6D bit 7 i.e. |= 0x80
(PCI conf. register 0x6C bit 15 i.e. |= 0x8000)
PCI conf. register 0xE7 bit 1 and bit 2 i.e. |= 0x06
(PCI conf. register 0xE4 bit 25 and bit 26 i.e. |= 0x06000000)
NVidia nForce2
PCI conf. register 0x6F bit 4 i.e. |= 0x10
(PCI conf. register 0x6C bit 28 i.e. |= 0x10000000)
for some of C1 revisions, further need
PCI conf. register 0x6F bit 7-5 be 0, i.e. &= 0x1F
(PCI conf. register 0x6C bit 31-29 be 0, i.e. &= 0x1FFFFFFF)
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include "io_static.c"
#define DWORD unsigned int
#define PCI_CFIO 0x0CF8
#define PCI_CWRV 0x0CFC
#define PCI_BUSM 0x03
#define PCI_DEVM 0x32
#define PCI_FUNM 0x08
/* supported chipsets */
#define ID_AMD751 0x70061022
#define ID_AMD751S 0x70041022
#define ID_AMD761 0x700E1022
#define ID_AMD762 0x700C1022
#define AMD_751 0x01
#define AMD_762 0x02
#define ID_VIA8363 0x03051106
#define ID_VIA8371 0x03911106
#define ID_VIA8371A 0x06911106
#define ID_VIA8361 0x31121106
#define ID_VIA8366 0x30991106
#define ID_VIA8375 0x31161106
#define ID_VIA8372 0x31561106
#define ID_VIA8377 0x31891106
#define ID_VIA8378 0x32051106
#define ID_VIAKT880 0x22691106
#define ID_VIA686 0x30571106
#define VIA_KT133 0x11
#define VIA_KT266 0x12
#define VIA_KT400 0x13
#define VIA_KT880 0x14
#define ID_SIS730 0x07301039
#define ID_SIS733 0x07331039
#define ID_SIS735 0x07351039
#define ID_SIS740 0x07401039
#define ID_SIS741 0x07411039
#define ID_SIS745 0x07451039
#define ID_SIS746 0x07461039
#define ID_SIS748 0x07481039
#define SIS_730 0x21
#define SIS_735 0x22
#define SIS_746 0x23
#define ID_NFORCE 0x01A410DE
#define ID_NFORCE2 0x01E010DE
#define NFORCE 0x31
#define NFORCE2 0x32
/* global variables */
int Reg_PL2;
int North_Chip = 0;
int idle_flag = 0, debug_flag = 0, enable_flag = 0;
int iofl;
int iopl_counter;
DWORD PCIRead(int reg, int fun, int dev, int bus)
{
DWORD r = 0x80000000, ret, org;
r |= (( bus & 0xff) <<16);
r |= (( dev & 0x1f) <<11);
r |= (( fun & 0x07) << 8);
r |= (( reg & 0xfc) );
org = INl(PCI_CFIO); WAIT;
OUTl(PCI_CFIO, r); WAIT;
ret = INl(PCI_CWRV); WAIT;
org &= 0x7FFFFFFF;
OUTl(PCI_CFIO, org); WAIT;
return ret;
}
void PCIWrite(DWORD val, int reg, int fun, int dev, int bus)
{
DWORD r = 0x80000000, org;
r |= (( bus & 0xff) <<16);
r |= (( dev & 0x1f) <<11);
r |= (( fun & 0x07) << 8);
r |= (( reg & 0xfc) );
org = INl(PCI_CFIO); WAIT;
OUTl(PCI_CFIO, r); WAIT;
OUTl(PCI_CWRV, val); WAIT;
org &= 0x7FFFFFFF;
OUTl(PCI_CFIO, org); WAIT;
}
/* scan PCI bus for north and south (VIA82C686 only) bridge */
int search_PCI(int *chip, int *nb, int *nd, int *nf, int *sb, int *sd, int *sf)
{
int bus, dev, fun, res, ret = 0;
*chip = 0;
for (bus = 0; bus < PCI_BUSM; bus++) {
for (dev = 0; dev < PCI_DEVM; dev++) {
for (fun = 0; fun < PCI_FUNM; fun++) {
res = PCIRead(0, fun, dev, bus);
if (res == 0xffffffff)
continue;
switch (res) {
case ID_AMD751:
case ID_AMD751S:
case ID_AMD761:
*chip = AMD_751;
break;
case ID_AMD762:
*chip = AMD_762;
break;
case ID_VIA8363:
case ID_VIA8371:
case ID_VIA8371A:
case ID_VIA8361:
*chip = VIA_KT133;
break;
case ID_VIA8366:
case ID_VIA8375:
case ID_VIA8372:
*chip = VIA_KT266;
break;
case ID_VIA8377:
case ID_VIA8378:
*chip = VIA_KT400;
break;
case ID_VIAKT880:
*chip = VIA_KT880;
break;
case ID_SIS730:
case ID_SIS733:
*chip = SIS_730;
break;
case ID_SIS735:
case ID_SIS740:
case ID_SIS741:
case ID_SIS745:
*chip = SIS_735;
break;
case ID_SIS746:
case ID_SIS748:
*chip = SIS_746;
break;
case ID_NFORCE:
*chip = NFORCE;
break;
case ID_NFORCE2:
*chip = NFORCE2;
break;
case ID_VIA686:
*sb = bus;
*sd = dev;
*sf = fun;
ret |= 0x02;
break;
}
if (!(ret & 0x01) && *chip) {
*nb = bus;
*nd = dev;
*nf = fun;
ret |= 0x01;
}
if (ret >= 3) break;
}
if (ret >= 3) break;
}
if (ret >= 3) break;
}
return ret;
}
int maskbits(int value, int mask)
{
int ret;
if (enable_flag > 0)
ret = value | mask;
else if (enable_flag < 0)
ret = value & ~mask;
else
ret = value;
return ret;
}
void chip_info(int value, char *comment, int reg, int mask)
{
int val1, val2, shiftbits;
shiftbits = (reg % 4) * 8;
val1 = (0xFF & (value >> shiftbits));
val2 = maskbits(val1, mask);
fprintf(stderr, "%s", comment);
fprintf(stderr, " Change Reg0x%02X 0x%02X --> 0x%02X\n", reg, val1, val2);
}
int InitPCI(debug_flag)
{
DWORD res;
int ret;
int nb_b = 0, nb_d = 0, nb_f = 0;
int sb_b = 0, sb_d = 7, sb_f = 4;
ret = search_PCI(&North_Chip, &nb_b, &nb_d, &nb_f, &sb_b, &sb_d, &sb_f);
if (!(ret & 0x01)) {
perror("Supported Athlon/Duron chipset (north bridge) not found.\n");
exit(1);
}
/* now set enable bus Diconnect when HLT/STPGNT detected */
switch (North_Chip) {
case AMD_751:
res = PCIRead(0x60, nb_f, nb_d, nb_b);
PCIWrite(maskbits(res, 0x060000), 0x60, nb_f, nb_d, nb_b);
if (debug_flag)
chip_info(res, "AMD751/761 found.\n", 0x62, 0x02);
break;
case AMD_762:
res = PCIRead(0x60, nb_f, nb_d, nb_b);
PCIWrite(maskbits(res, 0x020000), 0x60, nb_f, nb_d, nb_b);
if (debug_flag)
chip_info(res, "AMD762 found.\n", 0x62, 0x02);
res = PCIRead(0x68, nb_f, nb_d, nb_b);
PCIWrite(maskbits(res, 0x020000), 0x68, nb_f, nb_d, nb_b);
if (debug_flag)
chip_info(res, "", 0x6A, 0x02);
break;
case VIA_KT133:
res = PCIRead(0x50, nb_f, nb_d, nb_b);
PCIWrite(maskbits(res, 0x800000), 0x50, nb_f, nb_d, nb_b);
if (debug_flag)
chip_info(res, "VIA KT133/A/KX133/KM133 found.\n", 0x52, 0x80);
res = PCIRead(0x70, nb_f, nb_d, nb_b);
PCIWrite(maskbits(res, 0x08), 0x70, nb_f, nb_d, nb_b);
if (debug_flag)
chip_info(res, "", 0x70, 0x08);
break;
case VIA_KT266:
res = PCIRead(0x90, nb_f, nb_d, nb_b);
PCIWrite(maskbits(res, 0x800000), 0x90, nb_f, nb_d, nb_b);
if (debug_flag)
chip_info(res, "VIA KT266/A/KT333 found.\n", 0x92, 0x80);
res = PCIRead(0x94, nb_f, nb_d, nb_b);
PCIWrite(maskbits(res, 0x0200), 0x94, nb_f, nb_d, nb_b);
if (debug_flag)
chip_info(res, "", 0x95, 0x02);
res = PCIRead(0x70, nb_f, nb_d, nb_b);
PCIWrite(maskbits(res, 0x08), 0x70, nb_f, nb_d, nb_b);
if (debug_flag)
chip_info(res, "", 0x70, 0x08);
break;
case VIA_KT400:
res = PCIRead(0xD0, nb_f, nb_d, nb_b);
PCIWrite(maskbits(res, 0x800000), 0xD0, nb_f, nb_d, nb_b);
if (debug_flag)
chip_info(res, "VIA KT400/A/KT600 found.\n", 0xD2, 0x80);
res = PCIRead(0xD4, nb_f, nb_d, nb_b);
PCIWrite(maskbits(res, 0x0200), 0xD4, nb_f, nb_d, nb_b);
if (debug_flag)
chip_info(res, "", 0xD5, 0x02);
res = PCIRead(0x70, nb_f, nb_d, nb_b);
PCIWrite(maskbits(res, 0x08), 0x70, nb_f, nb_d, nb_b);
if (debug_flag)
chip_info(res, "", 0x70, 0x08);
break;
case VIA_KT880:
res = PCIRead(0x80, nb_f, nb_d, nb_b);
PCIWrite(maskbits(res, 0x800000), 0x80, nb_f, nb_d, nb_b);
if (debug_flag)
chip_info(res, "VIA KT880 found.\n", 0x82, 0x80);
res = PCIRead(0x84, nb_f, nb_d, nb_b);
PCIWrite(maskbits(res, 0x0200), 0x84, nb_f, nb_d, nb_b);
if (debug_flag)
chip_info(res, "", 0x85, 0x02);
break;
case SIS_730:
res = PCIRead(0x68, nb_f, nb_d, nb_b);
PCIWrite(maskbits(res, 0x01000000), 0x68, nb_f, nb_d, nb_b);
if (debug_flag)
chip_info(res, "SiS730/733 found.\n", 0x6B, 0x01);
break;
case SIS_735:
res = PCIRead(0x68, nb_f, nb_d, nb_b);
PCIWrite(maskbits(res, 0x030000), 0x68, nb_f, nb_d, nb_b);
if (debug_flag)
chip_info(res, "SiS735/740/745 found.\n", 0x6A, 0x03);
break;
case SIS_746:
res = PCIRead(0x6C, nb_f, nb_d, nb_b);
PCIWrite(maskbits(res, 0x00000001), 0x6C, nb_f, nb_d, nb_b);
if (debug_flag)
chip_info(res, "SiS746 found.\n", 0x6C, 0x01);
break;
case NFORCE:
res = PCIRead(0x6C, nb_f, nb_d, nb_b);
PCIWrite(maskbits(res, 0x8000), 0x6C, nb_f, nb_d, nb_b);
if (debug_flag)
chip_info(res, "NVidia nForce found.\n", 0x6D, 0x80);
res = PCIRead(0xE4, nb_f, nb_d, nb_b);
PCIWrite(maskbits(res, 0x06000000), 0xE4, nb_f, nb_d, nb_b);
if (debug_flag)
chip_info(res, "", 0xE7, 0x06);
break;
case NFORCE2:
res = PCIRead(0x6C, nb_f, nb_d, nb_b);
res &= 0x1FFFFFFF; /* clear 0x6F bits 7-5 */
PCIWrite(res, 0x6C, nb_f, nb_d, nb_b);
PCIWrite(maskbits(res, 0x10000000), 0x6C, nb_f, nb_d, nb_b);
if (debug_flag)
chip_info(res, "NVidia nForce2 found.\n", 0x6F, 0x10);
break;
}
/* enable ACPI and find I/O-Space for VT82C686(KT133/A south) */
if ((ret & 0x02) && (enable_flag > 0)) {
res = PCIRead(0x41,sb_f,sb_d,sb_b);
if ((res & 0x8000) == 0) {
res |= 0x8000;
PCIWrite(res, 0x41, sb_f, sb_d, sb_b);
}
res = PCIRead(0x48, sb_f, sb_d, sb_b);
res &= 0xff80;
Reg_PL2 = res + 0x14;
if (debug_flag) {
fprintf(stderr, "VT82C686/A/B(ACPI) found.\n");
fprintf(stderr, " PLVL_2 Reg Address:0x%0X\n", Reg_PL2);
}
}
return ret;
}
void Idleloop()
{
if(nice(20) == -1) {
perror("nice does not work!\n");
exit(1);
}
while(1) {
INb(Reg_PL2);
/* usleep(30); */
}
}
void usage() {
fprintf(stderr, "Usage: [-v (verbose)] "
"[ -e (enable) [ -i (idle loop)]] [ -d (disable)]\n");
exit(1);
}
int main(int argc, char *argv[])
{
int n, ch;
int arguments_processed = 0;
while ((ch = getopt(argc, argv, "vidhe")) != -1) {
switch (ch) {
case 'v':
debug_flag = 1;
break;
case 'i':
idle_flag = 1;
break;
case 'd':
enable_flag = -1;
break;
case 'e':
enable_flag = 1;
break;
case 'h':
default:
usage();
}
arguments_processed++;
}
if (arguments_processed == 0)
usage();
if (enable_flag <= 0)
idle_flag = 0;
if (OpenIO() < 0) {
perror("cannot open IO-port, must run as root!\n");
exit(1);
}
if (idle_flag & !enable_flag) {
fprintf(stderr, "cannot idle without enabling!\n");
usage();
}
n = InitPCI(debug_flag);
if (idle_flag && (n & 0x02)) {
fprintf(stderr, "Now going into idle-loop!\n");
Idleloop();
}
CloseIO();
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1