/* 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 #endif #include #include #include #include #include #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; }